* 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'.

gdb/testsuite/
	* gdb.dwarf2/dw2-ranges.S, gdb.dwarf2/dw2-ranges.exp: New files.
This commit is contained in:
Jan Kratochvil 2007-11-25 21:40:39 +00:00
parent a67d13cf51
commit 4303944388
5 changed files with 225 additions and 102 deletions

View File

@ -1,3 +1,10 @@
2007-11-25 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 Pedro Alves <pedro_alves@portugalmail.pt>
* win32-nat.c (DR6_CLEAR_VALUE): New define.

View File

@ -3077,6 +3077,124 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu)
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 *die, CORE_ADDR *lowpc,
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_info *part_die,
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))

View File

@ -1,3 +1,7 @@
2007-11-25 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.dwarf2/dw2-ranges.S, gdb.dwarf2/dw2-ranges.exp: New files.
2007-11-22 Maciej W. Rozycki <macro@mips.com>
* gdb.trace/backtrace.exp: Fix a typo.

View File

@ -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

View File

@ -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 .*"