2007-10-09 Jan Kratochvil * 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 * 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 . + */ + + .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 . + +# 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 . + */ + +SECTIONS +{ + .text._start : { *(.text._start) } + /* Create the hole. */ + . = . + 1; + .text.func : { *(.text.func) } +} +ENTRY(_start)