423 lines
13 KiB
Diff
423 lines
13 KiB
Diff
|
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)
|