From 4303944388ea72f96de9b1b662e45ac8f86cc741 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Sun, 25 Nov 2007 21:40:39 +0000 Subject: [PATCH] gdb/ * 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. --- gdb/ChangeLog | 7 + gdb/dwarf2read.c | 227 ++++++++++++++++++-------------- gdb/testsuite/ChangeLog | 4 + gdb/testsuite/gdb.dwarf2/dw2-ranges.S | 40 ++++++ gdb/testsuite/gdb.dwarf2/dw2-ranges.exp | 49 +++++++ 5 files changed, 225 insertions(+), 102 deletions(-) create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-ranges.S create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-ranges.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 2e3fc01..3cb6fb6 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2007-11-25 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-11-24 Pedro Alves * win32-nat.c (DR6_CLEAR_VALUE): New define. diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 1498d1f..d6178a7 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -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)) diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index e58ac5c..6385c74 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2007-11-25 Jan Kratochvil + + * gdb.dwarf2/dw2-ranges.S, gdb.dwarf2/dw2-ranges.exp: New files. + 2007-11-22 Maciej W. Rozycki * gdb.trace/backtrace.exp: Fix a typo. diff --git a/gdb/testsuite/gdb.dwarf2/dw2-ranges.S b/gdb/testsuite/gdb.dwarf2/dw2-ranges.S new file mode 100644 index 0000000..87dc019 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-ranges.S @@ -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 . + */ + +/* 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 diff --git a/gdb/testsuite/gdb.dwarf2/dw2-ranges.exp b/gdb/testsuite/gdb.dwarf2/dw2-ranges.exp new file mode 100644 index 0000000..4921551 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-ranges.exp @@ -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 . + +# 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 .*" -- 2.7.4