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

Jan Kratochvil
2007-11-24T15:43:56Z

[-- Attachment #1: Type: text/plain, Size: 219 bytes --]

On Tue, 09 Oct 2007 20:59:31 +0200, Daniel Jacobowitz wrote:
...
> Does that work with the default linker script and without -nostdlib?

Attached the patch with the testcase no longer using its own .lds.

Regards,
Jan

[-- Attachment #2: gdb-6.6-cu-ranges3.patch --]
[-- Type: text/plain, Size: 12123 bytes --]

2007-11-24 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-11-24 Jan Kratochvil <jan.kratochvil@redhat.com>

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

Index: gdb/dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.236
diff -u -p -r1.236 dwarf2read.c
--- gdb/dwarf2read.c 25 Oct 2007 20:54:27 -0000 1.236
+++ gdb/dwarf2read.c 24 Nov 2007 15:41:32 -0000
@@ -3077,6 +3077,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. */
@@ -3084,10 +3202,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;
@@ -3111,108 +3226,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;
}
}
@@ -5569,6 +5587,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))
Index: gdb/testsuite/gdb.dwarf2/dw2-ranges.S
===================================================================
RCS file: gdb/testsuite/gdb.dwarf2/dw2-ranges.S
diff -N gdb/testsuite/gdb.dwarf2/dw2-ranges.S
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.dwarf2/dw2-ranges.S 24 Nov 2007 15:41:33 -0000
@@ -0,0 +1,40 @@
+/*
+ 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/>.
+ */
+
+/* Despite the sections below will be adjacent the assembler has to produce
+ DW_AT_ranges as the linker could place both sections at arbitrary locations.
+ */
+
+ /* Without this directive GAS will not emit DWARF2 unless we provide an
+ instruction to assemble. We want to avoid any instructions to
+ remain architecture independent. */
+ .loc_mark_labels 1
+
+ .text
+
+ .globl main
+ .func main
+main: .int 0
+ .endfunc
+ .size main, . - main
+
+ .section .text.func, "ax", @progbits
+ .globl func
+ .func func
+func: .int 0
+ .endfunc
+ .size func, . - func
Index: gdb/testsuite/gdb.dwarf2/dw2-ranges.exp
===================================================================
RCS file: gdb/testsuite/gdb.dwarf2/dw2-ranges.exp
diff -N gdb/testsuite/gdb.dwarf2/dw2-ranges.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.dwarf2/dw2-ranges.exp 24 Nov 2007 15:41:33 -0000
@@ -0,0 +1,49 @@
+# 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.
+
+# 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 DW_AT_ranges test."
+ return 0
+}
+
+set testfile "dw2-ranges"
+set srcfile ${testfile}.S
+set binfile ${objdir}/${subdir}/${testfile}.o
+
+if {[gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" object debug] != "" } {
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# Correct output:
+# Line 39 of "../.././gdb/testsuite/gdb.dwarf2/dw2-ranges.S" starts at address 0x4 and ends at 0x8.
+# Wrong output:
+# No line number information available for address 0x4
+
+gdb_test "info line func" "Line \[0-9\]* of .* starts at address .* and ends at .*"