This is the mail archive of the gdb-patches@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]

[patch] Parse DW_AT_ranges into PSYMTABS (for childless CU, for vDSO32)


Hi,

currently on GNU/Linux running i386 inferior on x86_64 host you do not see some
of the debug info for the vDSO32 provided by the kernel.

Unpatched:
------------------------------------------------------------------------------
0xffffe410 in __kernel_vsyscall ()
(gdb) bt
#0  0xffffe410 in __kernel_vsyscall ()
#1  0x00c7a853 in __read_nocancel () from /lib/libc.so.6
#2  0x0804b263 in ?? ()
#3  0x0804941f in ?? ()
#4  0x00bcd3a0 in __libc_start_main () from /lib/libc.so.6
#5  0x08048c61 in ?? ()
(gdb) info line *0xffffe410
No line number information available for address 0xffffe410 <__kernel_vsyscall+16>
------------------------------------------------------------------------------

Patched:
------------------------------------------------------------------------------
__kernel_vsyscall () at arch/x86_64/ia32/vsyscall-sysenter.S:26
26              pop     %ebp
Current language:  auto; currently asm
(gdb) bt
#0  __kernel_vsyscall () at arch/x86_64/ia32/vsyscall-sysenter.S:26
#1  0x00c7a853 in __read_nocancel () from /lib/libc.so.6
#2  0x0804b263 in ?? ()
#3  0x0804941f in ?? ()
#4  0x00bcd3a0 in __libc_start_main () from /lib/libc.so.6
#5  0x08048c61 in ?? ()
(gdb) info line $eip
Convenience variables used in line specs must have integer values.
(gdb) info line $rip
Convenience variables used in line specs must have integer values.
(gdb) p/x $eip
$1 = 0xffffe410
(gdb) info line *0xffffe410
Line 26 of "arch/x86_64/ia32/vsyscall-sysenter.S" starts at address 0xffffe410 <__kernel_vsyscall+16>
   and ends at 0xffffe411 <__kernel_vsyscall+17>.
------------------------------------------------------------------------------

The problem is this vDSO is in assembly language, therefore its
 <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
  < c>     DW_AT_stmt_list   : 0
  <10>     DW_AT_ranges      : 0
  <14>     DW_AT_name        : arch/x86_64/ia32/vsyscall-sysenter.S
  <39>     DW_AT_comp_dir    : /usr/src/debug////////kernel-2.6.22/linux-2.6.22.x86_64
  <71>     DW_AT_producer    : GNU AS 2.17.50.0.18
  <85>     DW_AT_language    : 32769    (MIPS assembler)

Contents of the .debug_ranges section:

    Offset   Begin    End
    00000000 ffffffff 00000000 (start > end)
    00000000 ffffe400 ffffe414
    00000000 ffffe500 ffffe508
    00000000 ffffe600 ffffe607
    00000000 <End of list>

DW_TAG_compile_unit has no children and it has neither DW_AT_low_pc nor
DW_AT_high_pc but it has DW_AT_ranges instead.  So far DW_AT_ranges was not
parsed into PSYMTABS and so this file was ignored during the debug info search
later.  Reasons for the discontinuous vDSO32 layout/hack are in the Linux
kernel sources.

Thanks to Roland McGrath for pointing out this .debug_info is not broken for
`.S'.


Regards,
Jan
2007-10-09  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* dwarf2read.c (dwarf2_get_pc_bounds): Moved the `DW_AT_ranges' parsing
	code with its variables OBJFILE, CU_HEADER and OBFD into ...
	(dwarf2_ranges_read): ... a new function.
	(read_partial_die): Implemented the parsing of `DW_AT_ranges'.

2007-10-09  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdb.dwarf2/dw2-ranges.S, gdb.dwarf2/dw2-ranges.exp,
	gdb.dwarf2/dw2-ranges.lds: New files.

--- ./gdb/dwarf2read.c	26 Sep 2007 13:59:54 -0000	1.232
+++ ./gdb/dwarf2read.c	9 Oct 2007 15:03:09 -0000
@@ -3075,6 +3075,124 @@ read_lexical_block_scope (struct die_inf
   local_symbols = new->locals;
 }
 
+/* Get low and high pc attributes from DW_AT_ranges attribute value OFFSET.
+   Return 1 if the attributes are present and valid, otherwise, return 0.  */
+
+static int
+dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return,
+		    CORE_ADDR *high_return, struct dwarf2_cu *cu)
+{
+  struct objfile *objfile = cu->objfile;
+  struct comp_unit_head *cu_header = &cu->header;
+  bfd *obfd = objfile->obfd;
+  unsigned int addr_size = cu_header->addr_size;
+  CORE_ADDR mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
+  /* Base address selection entry.  */
+  CORE_ADDR base;
+  int found_base;
+  unsigned int dummy;
+  gdb_byte *buffer;
+  CORE_ADDR marker;
+  int low_set;
+  CORE_ADDR low = 0;
+  CORE_ADDR high = 0;
+
+  found_base = cu_header->base_known;
+  base = cu_header->base_address;
+
+  if (offset >= dwarf2_per_objfile->ranges_size)
+    {
+      complaint (&symfile_complaints,
+		 _("Offset %d out of bounds for DW_AT_ranges attribute"),
+		 offset);
+      return 0;
+    }
+  buffer = dwarf2_per_objfile->ranges_buffer + offset;
+
+  /* Read in the largest possible address.  */
+  marker = read_address (obfd, buffer, cu, &dummy);
+  if ((marker & mask) == mask)
+    {
+      /* If we found the largest possible address, then
+	 read the base address.  */
+      base = read_address (obfd, buffer + addr_size, cu, &dummy);
+      buffer += 2 * addr_size;
+      offset += 2 * addr_size;
+      found_base = 1;
+    }
+
+  low_set = 0;
+
+  while (1)
+    {
+      CORE_ADDR range_beginning, range_end;
+
+      range_beginning = read_address (obfd, buffer, cu, &dummy);
+      buffer += addr_size;
+      range_end = read_address (obfd, buffer, cu, &dummy);
+      buffer += addr_size;
+      offset += 2 * addr_size;
+
+      /* An end of list marker is a pair of zero addresses.  */
+      if (range_beginning == 0 && range_end == 0)
+	/* Found the end of list entry.  */
+	break;
+
+      /* Each base address selection entry is a pair of 2 values.
+	 The first is the largest possible address, the second is
+	 the base address.  Check for a base address here.  */
+      if ((range_beginning & mask) == mask)
+	{
+	  /* If we found the largest possible address, then
+	     read the base address.  */
+	  base = read_address (obfd, buffer + addr_size, cu, &dummy);
+	  found_base = 1;
+	  continue;
+	}
+
+      if (!found_base)
+	{
+	  /* We have no valid base address for the ranges
+	     data.  */
+	  complaint (&symfile_complaints,
+		     _("Invalid .debug_ranges data (no base address)"));
+	  return 0;
+	}
+
+      range_beginning += base;
+      range_end += base;
+
+      /* FIXME: This is recording everything as a low-high
+	 segment of consecutive addresses.  We should have a
+	 data structure for discontiguous block ranges
+	 instead.  */
+      if (! low_set)
+	{
+	  low = range_beginning;
+	  high = range_end;
+	  low_set = 1;
+	}
+      else
+	{
+	  if (range_beginning < low)
+	    low = range_beginning;
+	  if (range_end > high)
+	    high = range_end;
+	}
+    }
+
+  if (! low_set)
+    /* If the first entry is an end-of-list marker, the range
+       describes an empty scope, i.e. no instructions.  */
+    return 0;
+
+  if (low_return)
+    *low_return = low;
+  if (high_return)
+    *high_return = high;
+  return 1;
+}
+
 /* Get low and high pc attributes from a die.  Return 1 if the attributes
    are present and valid, otherwise, return 0.  Return -1 if the range is
    discontinuous, i.e. derived from DW_AT_ranges information.  */
@@ -3082,10 +3200,7 @@ static int
 dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
 		      CORE_ADDR *highpc, struct dwarf2_cu *cu)
 {
-  struct objfile *objfile = cu->objfile;
-  struct comp_unit_head *cu_header = &cu->header;
   struct attribute *attr;
-  bfd *obfd = objfile->obfd;
   CORE_ADDR low = 0;
   CORE_ADDR high = 0;
   int ret = 0;
@@ -3109,108 +3224,11 @@ dwarf2_get_pc_bounds (struct die_info *d
       attr = dwarf2_attr (die, DW_AT_ranges, cu);
       if (attr != NULL)
 	{
-	  unsigned int addr_size = cu_header->addr_size;
-	  CORE_ADDR mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
 	  /* Value of the DW_AT_ranges attribute is the offset in the
 	     .debug_ranges section.  */
-	  unsigned int offset = DW_UNSND (attr);
-	  /* Base address selection entry.  */
-	  CORE_ADDR base;
-	  int found_base;
-	  unsigned int dummy;
-	  gdb_byte *buffer;
-	  CORE_ADDR marker;
-	  int low_set;
- 
-	  found_base = cu_header->base_known;
-	  base = cu_header->base_address;
-
-	  if (offset >= dwarf2_per_objfile->ranges_size)
-	    {
-	      complaint (&symfile_complaints,
-	                 _("Offset %d out of bounds for DW_AT_ranges attribute"),
-			 offset);
-	      return 0;
-	    }
-	  buffer = dwarf2_per_objfile->ranges_buffer + offset;
-
-	  /* Read in the largest possible address.  */
-	  marker = read_address (obfd, buffer, cu, &dummy);
-	  if ((marker & mask) == mask)
-	    {
-	      /* If we found the largest possible address, then
-		 read the base address.  */
-	      base = read_address (obfd, buffer + addr_size, cu, &dummy);
-	      buffer += 2 * addr_size;
-	      offset += 2 * addr_size;
-	      found_base = 1;
-	    }
-
-	  low_set = 0;
-
-	  while (1)
-	    {
-	      CORE_ADDR range_beginning, range_end;
-
-	      range_beginning = read_address (obfd, buffer, cu, &dummy);
-	      buffer += addr_size;
-	      range_end = read_address (obfd, buffer, cu, &dummy);
-	      buffer += addr_size;
-	      offset += 2 * addr_size;
-
-	      /* An end of list marker is a pair of zero addresses.  */
-	      if (range_beginning == 0 && range_end == 0)
-		/* Found the end of list entry.  */
-		break;
-
-	      /* Each base address selection entry is a pair of 2 values.
-		 The first is the largest possible address, the second is
-		 the base address.  Check for a base address here.  */
-	      if ((range_beginning & mask) == mask)
-		{
-		  /* If we found the largest possible address, then
-		     read the base address.  */
-		  base = read_address (obfd, buffer + addr_size, cu, &dummy);
-		  found_base = 1;
-		  continue;
-		}
-
-	      if (!found_base)
-		{
-		  /* We have no valid base address for the ranges
-		     data.  */
-		  complaint (&symfile_complaints,
-			     _("Invalid .debug_ranges data (no base address)"));
-		  return 0;
-		}
-
-	      range_beginning += base;
-	      range_end += base;
-
-	      /* FIXME: This is recording everything as a low-high
-		 segment of consecutive addresses.  We should have a
-		 data structure for discontiguous block ranges
-		 instead.  */
-	      if (! low_set)
-		{
-		  low = range_beginning;
-		  high = range_end;
-		  low_set = 1;
-		}
-	      else
-		{
-		  if (range_beginning < low)
-		    low = range_beginning;
-		  if (range_end > high)
-		    high = range_end;
-		}
-	    }
-
-	  if (! low_set)
-	    /* If the first entry is an end-of-list marker, the range
-	       describes an empty scope, i.e. no instructions.  */
+	  if (!dwarf2_ranges_read (DW_UNSND (attr), &low, &high, cu))
 	    return 0;
-
+	  /* Found discontinuous range of addresses.  */
 	  ret = -1;
 	}
     }
@@ -5571,6 +5589,11 @@ read_partial_die (struct partial_die_inf
 	  has_high_pc_attr = 1;
 	  part_die->highpc = DW_ADDR (&attr);
 	  break;
+	case DW_AT_ranges:
+	  if (dwarf2_ranges_read (DW_UNSND (&attr), &part_die->lowpc,
+				  &part_die->highpc, cu))
+	    has_low_pc_attr = has_high_pc_attr = 1;
+	  break;
 	case DW_AT_location:
           /* Support the .debug_loc offsets */
           if (attr_form_is_block (&attr))
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ./gdb/testsuite/gdb.dwarf2/dw2-ranges.S	9 Oct 2007 15:03:10 -0000
@@ -0,0 +1,33 @@
+/*
+   Copyright 2007 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/>.
+ */
+
+	.text
+
+	.section	.text._start, "ax", @progbits
+	.globl	_start
+	.func	_start
+_start:	call	func
+	.endfunc
+	.size	_start, . - _start
+
+	.section	.text.func, "ax", @progbits
+	.globl	func
+	.func	func
+func:	int3
+	nop
+	.endfunc
+	.size	func, . - func
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ./gdb/testsuite/gdb.dwarf2/dw2-ranges.exp	9 Oct 2007 15:03:10 -0000
@@ -0,0 +1,82 @@
+# Copyright 2007 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/>.
+
+# Test DW_TAG_compile_unit with no children and with neither DW_AT_low_pc nor
+# DW_AT_high_pc but with DW_AT_ranges instead.  We created the hole there for
+# DW_AT_ranges by the linker script.
+
+# 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*]} {
+    verbose "Skipping i386/amd64 DW_AT_ranges test."
+    return 0  
+}
+if { ![istarget "i?86-*-*"] && ![istarget "x86_64-*-*"] } then {
+    verbose "Skipping i386/amd64 DW_AT_ranges test."
+    return 0
+}
+
+set testfile "dw2-ranges"
+set srcfile ${testfile}.S
+set ldsfile ${testfile}.lds
+set binfile ${objdir}/${subdir}/${testfile}
+
+# Avoid `-lm' from `lib/ada.exp' as it would fail with out `-nostdlib'.
+# Provide BOARD for SET_BOARD_INFO.
+set board [target_info name]
+set_board_info mathlib ""
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "additional_flags=-Wl,--script=${srcdir}/${subdir}/${ldsfile} -nostdlib"]] != "" } {
+    return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# Former wrong output:
+# 	Program received signal SIGTRAP, Trace/breakpoint trap.
+# 	0x000000000000002b in func ()
+# 	(gdb) bt
+# 	#0  0x000000000000002b in func ()
+# 	#1  0x0000000000000029 in _start ()
+# 	(gdb) _
+# Correct output:
+# 	Program received signal SIGTRAP, Trace/breakpoint trap.
+# 	func () at dw2-ranges.S:14
+# 	14              nop
+# 	Current language:  auto; currently asm
+# 	(gdb) bt
+# 	#0  func () at dw2-ranges.S:14
+# 	#1  0x0000000000000029 in _start () at dw2-ranges.S:6
+# 	(gdb) _
+# The entry #1 is missing on i386.
+# 	"#0 +func \\(\\) at .*dw2-ranges.S:\[0-9\]+\r\n#1 .*in _start \\(\\) at .*dw2-ranges.S:\[0-9\]+"
+
+gdb_run_cmd
+set test "run"
+gdb_test_multiple "" "$test" {
+    -re "Program received signal SIGTRAP,.*$gdb_prompt $" {
+	pass $test
+    }
+}
+
+gdb_test "backtrace" "#0 +func \\(\\) at .*dw2-ranges.S:\[0-9\]+"
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ./gdb/testsuite/gdb.dwarf2/dw2-ranges.lds	9 Oct 2007 15:03:10 -0000
@@ -0,0 +1,25 @@
+/*
+   Copyright 2007 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/>.
+ */
+
+SECTIONS
+{
+	.text._start : { *(.text._start) }
+	/* Create the hole.  */
+	. = . + 1;
+	.text.func : { *(.text.func) }
+}
+ENTRY(_start)

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