This is the mail archive of the gdb@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Smaller DWARF - .debug_loc masked by .debug_range (with [patch])


Hi,

this is a followup on:
	Re: [PATCH] Prune useless .debug_loc entries (PR debug/43442)
	http://gcc.gnu.org/ml/gcc-patches/2010-03/msg01004.html

the attached patch of GDB would do the same as does the GCC incremental patch
above.  The benefit of placing it in GDB would be smaller DWARF `.debug_loc'.
Disadvantage is a subtle difference in DWARF interpretation - thus making it
probably valid only after discussion on <dwarf-discuss@> since DWARF-5.

Currently if GDB holds `struct symbol' - for example by `watch varname' - it
fully follows its DW_AT_location - usually the .debug_loc list in more
complicated cases.  It follows it even when its name under which it has been
looked up is no longer valid in the current execution scope.

One cannot normally create a symbol which is out of the scope - as such symbol
cannot be looked up.  Watchpoint is the only way known to me how to exploit it.

If GDB exits a function containing the symbol program gets caught by
bp_watchpoint_scope in the caller automatically placed there by GDB.  But the
symbol can be also local only for example to DW_TAG_lexical_block where is no
breakpoint to catch its exit.

AFAIK with current DWARF (and its production by GCC) there is no difference
with this GDB patch as DW_AT_location is already undefined for PC ranges where
block containing the variable is not valid.

Exploiting the difference of this patch on real world code is IMO unreal even
with patched GCC.

Pretending DW_AT_location is undefined on addresses where DW_AT_range of the
variable's block is undefined would permit GCC to make the DWARF size smaller.

If there are no general objections it should be posted to <dwarf-discuss@>.

No regressions on {x86_64,x86_64-m32,i686}-fedora12-linux-gnu.
This patch is currently only illustrative with no intention to check it in now.


Thanks,
Jan


gdb/
	* findvar.c: Include dictionary.h
	(frame_can_access_var): New.
	(read_var_value): Move symbol_read_needs_frame earlier.  Extend the
	block by a check using frame_can_access_var.

gdb/testsuite/
	* gdb.dwarf2/dw2-loc-in-range.exp, gdb.dwarf2/dw2-loc-in-range-main.c,
	gdb.dwarf2/dw2-loc-in-range.S: New.

--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -35,6 +35,7 @@
 #include "user-regs.h"
 #include "block.h"
 #include "objfiles.h"
+#include "dictionary.h"
 
 /* Basic byte-swapping routines.  All 'extract' functions return a
    host-format integer from a target-format integer at ADDR which is
@@ -394,6 +395,43 @@ symbol_read_needs_frame (struct symbol *sym)
   return 1;
 }
 
+/* Return non-zero if VAR can be accessed from FRAME.  VAR can be located in
+   the block of FRAME or any parent block.  If you watch a variable which gets
+   out of scope return zero - still such variable may have otherwise valid
+   DW_AT_location.  But DW_AT_location is being discussed to be valid only if
+   DW_AT_range (or DW_AT_low_pc with DW_AT_high_pc) of its enclosing block is
+   defined.  */
+
+static int
+frame_can_access_var (struct symbol *var, struct frame_info *frame)
+{
+  CORE_ADDR pc;
+  struct block *block;
+
+  block = get_frame_block (frame, &pc);
+
+  /* Be optimistic - try to display VAR if we are absolutely not sure it has
+     gone out of scope.  */
+  if (block == NULL)
+    return 1;
+
+  while (block != NULL)
+    {
+      struct dict_iterator iter;
+      struct symbol *iter_sym;
+
+      /* There is no pointer back from VAR to its owning block.  */
+
+      ALL_BLOCK_SYMBOLS (block, iter, iter_sym)
+	if (iter_sym == var)
+	  return 1;
+
+      block = BLOCK_SUPERBLOCK (block);
+    }
+
+  return 0;
+}
+
 /* Given a struct symbol for a variable,
    and a stack frame id, read the value of the variable
    and return a (pointer to a) struct value containing the value. 
@@ -407,6 +445,20 @@ read_var_value (struct symbol *var, struct frame_info *frame)
   CORE_ADDR addr;
   int len;
 
+  if (symbol_read_needs_frame (var))
+    {
+      gdb_assert (frame);
+
+      /* Is SYMBOL at a block currently out of the range of its block?  */
+      if (!frame_can_access_var (var, frame))
+	{
+	  v = allocate_value (type);
+	  VALUE_LVAL (v) = not_lval;
+	  set_value_optimized_out (v, 1);
+	  return v;
+	}
+    }
+
   if (SYMBOL_CLASS (var) == LOC_COMPUTED
       || SYMBOL_CLASS (var) == LOC_REGISTER)
     /* These cases do not use V.  */
@@ -419,9 +471,6 @@ read_var_value (struct symbol *var, struct frame_info *frame)
 
   len = TYPE_LENGTH (type);
 
-  if (symbol_read_needs_frame (var))
-    gdb_assert (frame);
-
   switch (SYMBOL_CLASS (var))
     {
     case LOC_CONST:
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-loc-in-range-main.c
@@ -0,0 +1,38 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2010 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+
+asm (".globl cu_text_start");
+asm ("cu_text_start:");
+
+unsigned char var = 1;
+
+int
+main (void)
+{
+  if (var != 1)
+    abort ();
+
+asm (".globl range_end");
+asm ("range_end:");
+
+  return 0;
+}
+
+asm (".globl cu_text_end");
+asm ("cu_text_end:");
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-loc-in-range.S
@@ -0,0 +1,148 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2010 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Debug information */
+
+	.section .debug_info
+.Lcu1_begin:
+	/* CU header */
+	.4byte	.Lcu1_end - .Lcu1_start		/* Length of Compilation Unit */
+.Lcu1_start:
+	.2byte	2				/* DWARF Version */
+	.4byte	.Labbrev1_begin			/* Offset into abbrev section */
+	.byte	4				/* Pointer size */
+
+	/* CU die */
+	.uleb128 1				/* Abbrev: DW_TAG_compile_unit */
+	.4byte	cu_text_end			/* DW_AT_high_pc */
+	.4byte	cu_text_start			/* DW_AT_low_pc */
+	.ascii	"dw2-loc-in-range-main.c\0"	/* DW_AT_name */
+	.ascii	"GNU C 4.3.2\0"			/* DW_AT_producer */
+	.byte	1				/* DW_AT_language (C) */
+
+.Ltype_uchar:
+	.uleb128	2			/* Abbrev: DW_TAG_base_type */
+	.ascii		"unsigned char\0"	/* DW_AT_name */
+	.byte		1			/* DW_AT_byte_size */
+	.byte		7			/* DW_AT_encoding */
+
+	/* main */
+	.uleb128	3			/* Abbrev: DW_TAG_subprogram */
+	.byte		1			/* DW_AT_decl_file */
+	.byte		2			/* DW_AT_decl_line */
+	.ascii		"main\0"		/* DW_AT_name */
+	.4byte		.Ltype_uchar-.Lcu1_begin	/* DW_AT_type */
+	.4byte		cu_text_start		/* DW_AT_low_pc */
+	.4byte		cu_text_end		/* DW_AT_high_pc */
+
+	.uleb128	5			/* Abbrev: DW_TAG_lexical_block */
+	.4byte		cu_text_start		/* DW_AT_low_pc */
+	.4byte		range_end		/* DW_AT_high_pc */
+
+	.uleb128	4			/* Abbrev: DW_TAG_variable (location) */
+	.ascii		"var_by_dwarf\0"	/* DW_AT_name */
+	.byte		2f - 1f			/* DW_AT_location */
+1:	.byte		3			/*   DW_OP_addr */
+/* See VAR1 definition why this DIE is not correct.  */
+	.4byte		var			/*   <addr> */
+	/* Make the expression more complicated to pretend it needs a frame.  */
+	.byte		0x70			/* DW_OP_breg0 */
+	.uleb128	0			/*   0 */
+	.byte		0x13			/* DW_OP_drop */
+2:	.4byte		.Ltype_uchar-.Lcu1_begin	/* DW_AT_type */
+
+	.byte		0			/* End of children of the lexical block */
+
+	.byte		0			/* End of children of main */
+
+	.byte		0			/* End of children of CU */
+
+.Lcu1_end:
+
+/* Abbrev table */
+	.section .debug_abbrev
+.Labbrev1_begin:
+	.uleb128	1			/* Abbrev code */
+	.uleb128	0x11			/* DW_TAG_compile_unit */
+	.byte		1			/* has_children */
+	.uleb128	0x12			/* DW_AT_high_pc */
+	.uleb128	0x1			/* DW_FORM_addr */
+	.uleb128	0x11			/* DW_AT_low_pc */
+	.uleb128	0x1			/* DW_FORM_addr */
+	.uleb128	0x3			/* DW_AT_name */
+	.uleb128	0x8			/* DW_FORM_string */
+	.uleb128	0x25			/* DW_AT_producer */
+	.uleb128	0x8			/* DW_FORM_string */
+	.uleb128	0x13			/* DW_AT_language */
+	.uleb128	0xb			/* DW_FORM_data1 */
+	.byte		0x0			/* Terminator */
+	.byte		0x0			/* Terminator */
+
+	.uleb128	2			/* Abbrev code */
+	.uleb128	0x24			/* DW_TAG_base_type */
+	.byte		0			/* has_children */
+	.uleb128	0x3			/* DW_AT_name */
+	.uleb128	0x8			/* DW_FORM_string */
+	.uleb128	0xb			/* DW_AT_byte_size */
+	.uleb128	0xb			/* DW_FORM_data1 */
+	.uleb128	0x3e			/* DW_AT_encoding */
+	.uleb128	0xb			/* DW_FORM_data1 */
+	.byte		0x0			/* Terminator */
+	.byte		0x0			/* Terminator */
+
+	.uleb128	3			/* Abbrev code */
+	.uleb128	0x2e			/* DW_TAG_subprogram */
+	.byte		1			/* has_children */
+	.uleb128	0x3a			/* DW_AT_decl_file */
+	.uleb128	0xb			/* DW_FORM_data1 */
+	.uleb128	0x3b			/* DW_AT_decl_line */
+	.uleb128	0xb			/* DW_FORM_data1 */
+	.uleb128	0x3			/* DW_AT_name */
+	.uleb128	0x8			/* DW_FORM_string */
+	.uleb128	0x49			/* DW_AT_type */
+	.uleb128	0x13			/* DW_FORM_ref4 */
+	.uleb128	0x11			/* DW_AT_low_pc */
+	.uleb128	0x1			/* DW_FORM_addr */
+	.uleb128	0x12			/* DW_AT_high_pc */
+	.uleb128	0x1			/* DW_FORM_addr */
+	.byte		0x0			/* Terminator */
+	.byte		0x0			/* Terminator */
+
+	.uleb128	4			/* Abbrev code (location) */
+	.uleb128	0x34			/* DW_TAG_variable */
+	.byte		0			/* has_children */
+	.uleb128	0x3			/* DW_AT_name */
+	.uleb128	0x8			/* DW_FORM_string */
+	.uleb128	0x2			/* DW_AT_location */
+	.uleb128	0xa			/* DW_FORM_block1 */
+	.uleb128	0x49			/* DW_AT_type */
+	.uleb128	0x13			/* DW_FORM_ref4 */
+	.byte		0x0			/* Terminator */
+	.byte		0x0			/* Terminator */
+
+	.uleb128	5			/* Abbrev code */
+	.uleb128	0x0b			/* DW_TAG_lexical_block */
+	.byte		1			/* has_children */
+	.uleb128	0x11			/* DW_AT_low_pc */
+	.uleb128	0x1			/* DW_FORM_addr */
+	.uleb128	0x12			/* DW_AT_high_pc */
+	.uleb128	0x1			/* DW_FORM_addr */
+	.byte		0x0			/* Terminator */
+	.byte		0x0			/* Terminator */
+
+	.byte		0x0			/* Terminator */
+	.byte		0x0			/* Terminator */
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-loc-in-range.exp
@@ -0,0 +1,52 @@
+# Copyright 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+# For now pick a sampling of likely targets.
+if {![istarget *-*-linux*]
+    && ![istarget *-*-gnu*]
+    && ![istarget *-*-elf*]
+    && ![istarget *-*-openbsd*]
+    && ![istarget arm-*-eabi*]
+    && ![istarget powerpc-*-eabi*]} {
+    return 0  
+}
+
+if { [prepare_for_testing dw2-loc-in-range.exp "dw2-loc-in-range" {dw2-loc-in-range-main.c dw2-loc-in-range.S} {nodebug}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+# This testcase tests DW_AT_location is considered undefined if DW_AT_range of
+# its block is undefined.
+
+# Testing hardware watchpoints correctness is not a goal of this test.
+gdb_test "set can-use-hw-watchpoints 0"
+
+# Do not access VAR just by its name as it could get resolved through ELF
+# minimal symbol without restricted visibility.
+gdb_test "p (int) var_by_dwarf" " = 1" "var is visible"
+
+gdb_test "watch var_by_dwarf" "Watchpoint 2: var_by_dwarf" "setup watchpoint"
+
+gdb_test "continue" "Watchpoint 2: var_by_dwarf\r\n\r\nOld value = 1\[^\r\n\]*\r\nNew value = <value optimized out>\r\n.* in main .*"
+
+# Test we have stopped at the right point.
+gdb_test {p $pc == range_end} " = 1"
+
+gdb_test "p var_by_dwarf" {No symbol "var_by_dwarf" in current context.} "var is not visible"


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]