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

Doug Evans
2008-04-23T21:18:31Z

Hi. What's the status of this work? I ask because I'm tripping over
a problem here that is fixed by this.

On Sun, Dec 9, 2007 at 1:31 PM, Jan Kratochvil
<jan.kratochvil@redhat.com> wrote:
> On Fri, 30 Nov 2007 15:56:13 +0100, Daniel Jacobowitz wrote:
> > On Fri, Nov 30, 2007 at 12:10:21PM +0100, Jan Kratochvil wrote:
> > > It was not reproducible for me but the problem is Vladimir's i386 crti.S has
> > > DW_AT_ranges which overlap the main code (due to its .fini part). The main
> > > code full-symbols get ignored now due to it.
> ...
> > Jim, can we get your addrmap changes in as they are,
> ...
> > After that, it's simple to solve this problem more accurately by using
> > addrmaps for symtabs too, not just blocks.
>
> Attaching the fix for discontiguous psymtabs based on the addrmap framework.
>
> This one is a conservative one - it tries to just fix it with minimal changes.
> It is bidirectionally compatible:
> * Producer (dwarf2read.c) still tries to set the bounds TEXTLOW and TEXTHIGH.
> * Consumer (symtab.c) deals with both set and unset PSYMTABS_ADDRMAP.
>
> #1 With the new OBJFILE->PSYMTABS_ADDRMAP I believe the whole
> PARTIAL_SYMTAB->{TEXTLOW,TEXTHIGH} can be removed. It requires updating of all
> the producers and consumers. Dumb producers may even just set contiguous
> ranges in PSYMTABS_ADDRMAP.
>
> #2 My folowup mail will offer a future removal of FIND_PC_SECT_PSYMTAB_IS_VALID.
>
>
> The included testcase (FAIL->PASS by this patch) is the one posted here as:
> http://sources.redhat.com/ml/gdb-patches/2007-11/msg00565.html
>
> Testsuite has been run on x86_64 Fedora 8.
>
>
> Regards,
> Jan
>
> 2007-12-09 Jan Kratochvil <jan.kratochvil@redhat.com>
>
> * Makefile.in: Update dependencies.
> * dwarf2read.c: Include "addrmap.h"
> (struct dwarf2_cu): New fields RANGES_OFFSET and HAS_RANGES_OFFSET.
> (dwarf2_ranges_read): New prototype.
> (dwarf2_build_psymtabs_hard): Initialize and prepare PSYMTABS_ADDRMAP.
> Add discontiguous range to PSYMTABS_ADDRMAP by DWARF2_RANGES_READ on
> HAS_RANGES_OFFSET, otherwise add there the contiguous range.
> (dwarf2_ranges_read): New parameter RANGES_PST, update the function
> comment for it. Add the found ranges to RANGES_PST. New variable
> BASEADDR, initialize it the common way.
> (dwarf2_get_pc_bounds): Update the caller for the new parameter.
> (read_partial_die): `DW_AT_ranges' now only sets RANGES_OFFSET and
> HAS_RANGES_OFFSET for the later processing.
> * objfiles.h (struct objfile): New field PSYMTABS_ADDRMAP.
> * symtab.c: Include "addrmap.h"
> (find_pc_sect_psymtab): Support reading the field PSYMTABS_ADDRMAP.
> Move the psymtab locator into ...
> (find_pc_sect_psymtab_is_valid): ... a new function.
>
> 2007-11-30 Jan Kratochvil <jan.kratochvil@redhat.com>
>
> * gdb.dwarf2/dw2-ranges2.S: New file.
> * gdb.dwarf2/dw2-ranges.S: Merge the secondary section with `.fini'.
> * gdb.dwarf2/dw2-ranges.exp: Compile also "dw2-ranges2.S" and test also
> its MAIN2 and FUNC2 symbols.
>
> --- ./gdb/Makefile.in 6 Dec 2007 11:17:03 -0000 1.965
> +++ ./gdb/Makefile.in 9 Dec 2007 19:45:11 -0000
> @@ -2057,7 +2057,8 @@ dwarf2-frame.o: dwarf2-frame.c $(defs_h)
> dwarf2loc.o: dwarf2loc.c $(defs_h) $(ui_out_h) $(value_h) $(frame_h) \
> $(gdbcore_h) $(target_h) $(inferior_h) $(ax_h) $(ax_gdb_h) \
> $(regcache_h) $(objfiles_h) $(exceptions_h) $(elf_dwarf2_h) \
> - $(dwarf2expr_h) $(dwarf2loc_h) $(gdb_string_h) $(gdb_assert_h)
> + $(dwarf2expr_h) $(dwarf2loc_h) $(gdb_string_h) $(gdb_assert_h) \
> + $(addrmap_h)
> dwarf2read.o: dwarf2read.c $(defs_h) $(bfd_h) $(symtab_h) $(gdbtypes_h) \
> $(objfiles_h) $(elf_dwarf2_h) $(buildsym_h) $(demangle_h) \
> $(expression_h) $(filenames_h) $(macrotab_h) $(language_h) \
> @@ -2856,7 +2857,7 @@ symtab.o: symtab.c $(defs_h) $(symtab_h)
> $(filenames_h) $(objc_lang_h) $(ada_lang_h) $(hashtab_h) \
> $(gdb_obstack_h) $(block_h) $(dictionary_h) $(gdb_string_h) \
> $(gdb_stat_h) $(cp_abi_h) $(observer_h) $(gdb_assert_h) \
> - $(solist_h) $(p_lang_h)
> + $(solist_h) $(p_lang_h) $(addrmap_h)
> target.o: target.c $(defs_h) $(gdb_string_h) $(target_h) $(gdbcmd_h) \
> $(symtab_h) $(inferior_h) $(bfd_h) $(symfile_h) $(objfiles_h) \
> $(gdb_wait_h) $(dcache_h) $(regcache_h) $(gdb_assert_h) $(gdbcore_h) \
> --- ./gdb/dwarf2read.c 4 Dec 2007 23:43:57 -0000 1.239
> +++ ./gdb/dwarf2read.c 9 Dec 2007 19:45:23 -0000
> @@ -45,6 +45,7 @@
> #include "hashtab.h"
> #include "command.h"
> #include "gdbcmd.h"
> +#include "addrmap.h"
>
> #include <fcntl.h>
> #include "gdb_string.h"
> @@ -297,6 +298,9 @@ struct dwarf2_cu
> /* Hash table holding all the loaded partial DIEs. */
> htab_t partial_dies;
>
> + /* `.debug_ranges' offset for this `DW_TAG_compile_unit' DIE. */
> + unsigned long ranges_offset;
> +
> /* Storage for things with the same lifetime as this read-in compilation
> unit, including partial DIEs. */
> struct obstack comp_unit_obstack;
> @@ -339,6 +343,9 @@ struct dwarf2_cu
> DIEs for namespaces, we don't need to try to infer them
> from mangled names. */
> unsigned int has_namespace_info : 1;
> +
> + /* Field `ranges_offset' is filled in; flag as the value may be zero. */
> + unsigned int has_ranges_offset : 1;
> };
>
> /* Persistent data held for a compilation unit, even when not
> @@ -888,6 +895,9 @@ static void read_func_scope (struct die_
>
> static void read_lexical_block_scope (struct die_info *, struct dwarf2_cu *);
>
> +static int dwarf2_ranges_read (unsigned, CORE_ADDR *, CORE_ADDR *,
> + struct dwarf2_cu *, struct partial_symtab *);
> +
> static int dwarf2_get_pc_bounds (struct die_info *,
> CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *);
>
> @@ -1416,6 +1426,9 @@ dwarf2_build_psymtabs_hard (struct objfi
>
> create_all_comp_units (objfile);
>
> + objfile->psymtabs_addrmap = addrmap_create_mutable
> + (&objfile->objfile_obstack);
> +
> /* Since the objects we're extracting from .debug_info vary in
> length, only the individual functions to extract them (like
> read_comp_unit_head and load_partial_die) can really know whether
> @@ -1481,7 +1494,8 @@ dwarf2_build_psymtabs_hard (struct objfi
> /* Allocate a new partial symbol table structure */
> pst = start_psymtab_common (objfile, objfile->section_offsets,
> comp_unit_die.name ? comp_unit_die.name : "",
> - comp_unit_die.lowpc,
> + /* TEXTLOW and TEXTHIGH are set below. */
> + 0,
> objfile->global_psymbols.next,
> objfile->static_psymbols.next);
>
> @@ -1514,6 +1528,15 @@ dwarf2_build_psymtabs_hard (struct objfi
>
> this_cu->psymtab = pst;
>
> + /* Possibly set the default values of LOWPC and HIGHPC from
> + `DW_AT_ranges'. */
> + if (cu.has_ranges_offset)
> + {
> + if (dwarf2_ranges_read (cu.ranges_offset, &comp_unit_die.lowpc,
> + &comp_unit_die.highpc, &cu, pst))
> + comp_unit_die.has_pc_info = 1;
> + }
> +
> /* Check if comp unit has_children.
> If so, read the rest of the partial symbols from this comp unit.
> If not, there's no more debug_info for this comp unit. */
> @@ -1544,6 +1567,11 @@ dwarf2_build_psymtabs_hard (struct objfi
> pst->textlow = comp_unit_die.lowpc + baseaddr;
> pst->texthigh = comp_unit_die.highpc + baseaddr;
>
> + /* Store the contiguous range; `DW_AT_ranges' range is stored above. */
> + if (!cu.has_ranges_offset)
> + addrmap_set_empty (objfile->psymtabs_addrmap, pst->textlow,
> + pst->texthigh - 1, pst);
> +
> pst->n_global_syms = objfile->global_psymbols.next -
> (objfile->global_psymbols.list + pst->globals_offset);
> pst->n_static_syms = objfile->static_psymbols.next -
> @@ -1567,6 +1595,10 @@ dwarf2_build_psymtabs_hard (struct objfi
>
> do_cleanups (back_to_inner);
> }
> +
> + objfile->psymtabs_addrmap = addrmap_create_fixed (objfile->psymtabs_addrmap,
> + &objfile->objfile_obstack);
> +
> do_cleanups (back_to);
> }
>
> @@ -3078,11 +3110,13 @@ read_lexical_block_scope (struct die_inf
> }
>
> /* 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. */
> + Return 1 if the attributes are present and valid, otherwise, return 0.
> + If RANGES_PST is not NULL we should setup `objfile->psymtabs_addrmap'. */
>
> static int
> dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return,
> - CORE_ADDR *high_return, struct dwarf2_cu *cu)
> + CORE_ADDR *high_return, struct dwarf2_cu *cu,
> + struct partial_symtab *ranges_pst)
> {
> struct objfile *objfile = cu->objfile;
> struct comp_unit_head *cu_header = &cu->header;
> @@ -3098,6 +3132,7 @@ dwarf2_ranges_read (unsigned offset, COR
> int low_set;
> CORE_ADDR low = 0;
> CORE_ADDR high = 0;
> + CORE_ADDR baseaddr;
>
> found_base = cu_header->base_known;
> base = cu_header->base_address;
> @@ -3125,6 +3160,9 @@ dwarf2_ranges_read (unsigned offset, COR
>
> low_set = 0;
>
> + if (ranges_pst != NULL)
> + baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
> +
> while (1)
> {
> CORE_ADDR range_beginning, range_end;
> @@ -3164,6 +3202,11 @@ dwarf2_ranges_read (unsigned offset, COR
> range_beginning += base;
> range_end += base;
>
> + if (ranges_pst != NULL)
> + addrmap_set_empty (objfile->psymtabs_addrmap,
> + range_beginning + baseaddr, range_end - 1 + baseaddr,
> + ranges_pst);
> +
> /* FIXME: This is recording everything as a low-high
> segment of consecutive addresses. We should have a
> data structure for discontiguous block ranges
> @@ -3228,7 +3271,7 @@ dwarf2_get_pc_bounds (struct die_info *d
> {
> /* Value of the DW_AT_ranges attribute is the offset in the
> .debug_ranges section. */
> - if (!dwarf2_ranges_read (DW_UNSND (attr), &low, &high, cu))
> + if (!dwarf2_ranges_read (DW_UNSND (attr), &low, &high, cu, NULL))
> return 0;
> /* Found discontinuous range of addresses. */
> ret = -1;
> @@ -5663,9 +5706,11 @@ read_partial_die (struct partial_die_inf
> 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;
> + if (part_die->tag == DW_TAG_compile_unit)
> + {
> + cu->ranges_offset = DW_UNSND (&attr);
> + cu->has_ranges_offset = 1;
> + }
> break;
> case DW_AT_location:
> /* Support the .debug_loc offsets */
> --- ./gdb/objfiles.h 4 Dec 2007 23:33:00 -0000 1.47
> +++ ./gdb/objfiles.h 9 Dec 2007 19:45:27 -0000
> @@ -220,6 +220,12 @@ struct objfile
>
> struct partial_symtab *psymtabs;
>
> + /* Map addresses to the entries of PSYMTABS. It would be more efficient to
> + have a map per the whole process but ADDRMAP cannot selectively remove
> + its items during FREE_OBJFILE. */
> +
> + struct addrmap *psymtabs_addrmap;
> +
> /* List of freed partial symtabs, available for re-use */
>
> struct partial_symtab *free_psymtabs;
> --- ./gdb/symtab.c 24 Oct 2007 13:25:16 -0000 1.167
> +++ ./gdb/symtab.c 9 Dec 2007 19:45:38 -0000
> @@ -41,6 +41,7 @@
> #include "objc-lang.h"
> #include "ada-lang.h"
> #include "p-lang.h"
> +#include "addrmap.h"
>
> #include "hashtab.h"
>
> @@ -759,6 +760,83 @@ matching_bfd_sections (asection *first,
> return 0;
> }
>
> +/* Find which partial symtab contains PC and SECTION starting at psymtab PST.
> + We may find a different psymtab than PST. See FIND_PC_SECT_PSYMTAB. */
> +
> +struct partial_symtab *
> +find_pc_sect_psymtab_is_valid (CORE_ADDR pc, asection *section,
> + struct partial_symtab *pst,
> + struct minimal_symbol *msymbol)
> +{
> + struct objfile *objfile = pst->objfile;
> + struct partial_symtab *tpst;
> + struct partial_symtab *best_pst = pst;
> + CORE_ADDR best_addr = pst->textlow;
> +
> + /* An objfile that has its functions reordered might have
> + many partial symbol tables containing the PC, but
> + we want the partial symbol table that contains the
> + function containing the PC. */
> + if (!(objfile->flags & OBJF_REORDERED) &&
> + section == 0) /* can't validate section this way */
> + return pst;
> +
> + if (msymbol == NULL)
> + return (pst);
> +
> + /* The code range of partial symtabs sometimes overlap, so, in
> + the loop below, we need to check all partial symtabs and
> + find the one that fits better for the given PC address. We
> + select the partial symtab that contains a symbol whose
> + address is closest to the PC address. By closest we mean
> + that find_pc_sect_symbol returns the symbol with address
> + that is closest and still less than the given PC. */
> + for (tpst = pst; tpst != NULL; tpst = tpst->next)
> + {
> + if (pc >= tpst->textlow && pc < tpst->texthigh)
> + {
> + struct partial_symbol *p;
> + CORE_ADDR this_addr;
> +
> + /* NOTE: This assumes that every psymbol has a
> + corresponding msymbol, which is not necessarily
> + true; the debug info might be much richer than the
> + object's symbol table. */
> + p = find_pc_sect_psymbol (tpst, pc, section);
> + if (p != NULL
> + && SYMBOL_VALUE_ADDRESS (p)
> + == SYMBOL_VALUE_ADDRESS (msymbol))
> + return tpst;
> +
> + /* Also accept the textlow value of a psymtab as a
> + "symbol", to provide some support for partial
> + symbol tables with line information but no debug
> + symbols (e.g. those produced by an assembler). */
> + if (p != NULL)
> + this_addr = SYMBOL_VALUE_ADDRESS (p);
> + else
> + this_addr = tpst->textlow;
> +
> + /* Check whether it is closer than our current
> + BEST_ADDR. Since this symbol address is
> + necessarily lower or equal to PC, the symbol closer
> + to PC is the symbol which address is the highest.
> + This way we return the psymtab which contains such
> + best match symbol. This can help in cases where the
> + symbol information/debuginfo is not complete, like
> + for instance on IRIX6 with gcc, where no debug info
> + is emitted for statics. (See also the nodebug.exp
> + testcase.) */
> + if (this_addr > best_addr)
> + {
> + best_addr = this_addr;
> + best_pst = tpst;
> + }
> + }
> + }
> + return best_pst;
> +}
> +
> /* Find which partial symtab contains PC and SECTION. Return 0 if
> none. We return the psymtab that contains a symbol whose address
> exactly matches PC, or, if we cannot find an exact match, the
> @@ -766,7 +844,6 @@ matching_bfd_sections (asection *first,
> struct partial_symtab *
> find_pc_sect_psymtab (CORE_ADDR pc, asection *section)
> {
> - struct partial_symtab *pst;
> struct objfile *objfile;
> struct minimal_symbol *msymbol;
>
> @@ -782,79 +859,43 @@ find_pc_sect_psymtab (CORE_ADDR pc, asec
> || msymbol->type == mst_file_bss))
> return NULL;
>
> - ALL_PSYMTABS (objfile, pst)
> - {
> - if (pc >= pst->textlow && pc < pst->texthigh)
> - {
> - struct partial_symtab *tpst;
> - struct partial_symtab *best_pst = pst;
> - CORE_ADDR best_addr = pst->textlow;
> -
> - /* An objfile that has its functions reordered might have
> - many partial symbol tables containing the PC, but
> - we want the partial symbol table that contains the
> - function containing the PC. */
> - if (!(objfile->flags & OBJF_REORDERED) &&
> - section == 0) /* can't validate section this way */
> - return (pst);
> -
> - if (msymbol == NULL)
> - return (pst);
> -
> - /* The code range of partial symtabs sometimes overlap, so, in
> - the loop below, we need to check all partial symtabs and
> - find the one that fits better for the given PC address. We
> - select the partial symtab that contains a symbol whose
> - address is closest to the PC address. By closest we mean
> - that find_pc_sect_symbol returns the symbol with address
> - that is closest and still less than the given PC. */
> - for (tpst = pst; tpst != NULL; tpst = tpst->next)
> - {
> - if (pc >= tpst->textlow && pc < tpst->texthigh)
> + ALL_OBJFILES (objfile)
> + {
> + if (objfile->psymtabs_addrmap != NULL)
> + {
> + struct partial_symtab *pst;
> +
> + pst = addrmap_find (objfile->psymtabs_addrmap, pc);
> + if (pst != NULL)
> + {
> + struct partial_symtab *best_pst;
> +
> + best_pst = find_pc_sect_psymtab_is_valid (pc, section, pst,
> + msymbol);
> + if (best_pst != NULL)
> + return best_pst;
> + }
> + /* Existing PSYMTABS_ADDRMAP should cover all the PSYMTABS of
> + OBJFILE, there is no need to scan the remaining ones by hand. */
> + }
> + else
> + {
> + struct partial_symtab *pst;
> +
> + ALL_OBJFILE_PSYMTABS (objfile, pst)
> + if (pc >= pst->textlow && pc < pst->texthigh)
> {
> - struct partial_symbol *p;
> - CORE_ADDR this_addr;
> + struct partial_symtab *best_pst;
>
> - /* NOTE: This assumes that every psymbol has a
> - corresponding msymbol, which is not necessarily
> - true; the debug info might be much richer than the
> - object's symbol table. */
> - p = find_pc_sect_psymbol (tpst, pc, section);
> - if (p != NULL
> - && SYMBOL_VALUE_ADDRESS (p)
> - == SYMBOL_VALUE_ADDRESS (msymbol))
> - return (tpst);
> -
> - /* Also accept the textlow value of a psymtab as a
> - "symbol", to provide some support for partial
> - symbol tables with line information but no debug
> - symbols (e.g. those produced by an assembler). */
> - if (p != NULL)
> - this_addr = SYMBOL_VALUE_ADDRESS (p);
> - else
> - this_addr = tpst->textlow;
> -
> - /* Check whether it is closer than our current
> - BEST_ADDR. Since this symbol address is
> - necessarily lower or equal to PC, the symbol closer
> - to PC is the symbol which address is the highest.
> - This way we return the psymtab which contains such
> - best match symbol. This can help in cases where the
> - symbol information/debuginfo is not complete, like
> - for instance on IRIX6 with gcc, where no debug info
> - is emitted for statics. (See also the nodebug.exp
> - testcase.) */
> - if (this_addr > best_addr)
> - {
> - best_addr = this_addr;
> - best_pst = tpst;
> - }
> + best_pst = find_pc_sect_psymtab_is_valid (pc, section, pst,
> + msymbol);
> + if (best_pst != NULL)
> + return best_pst;
> }
> - }
> - return (best_pst);
> - }
> - }
> - return (NULL);
> + }
> + }
> +
> + return NULL;
> }
>
> /* Find which partial symtab contains PC. Return 0 if none.
> --- ./gdb/testsuite/gdb.dwarf2/dw2-ranges.S 25 Nov 2007 21:40:39 -0000 1.1
> +++ ./gdb/testsuite/gdb.dwarf2/dw2-ranges.S 30 Nov 2007 15:01:49 -0000
> @@ -32,7 +32,10 @@ main: .int 0
> .endfunc
> .size main, . - main
>
> - .section .text.func, "ax", @progbits
> + /* `.fini' section is here to make sure `dw2-ranges.S'
> + vs. `dw2-ranges2.S' overlap their DW_AT_ranges with eac other. */
> + .section .fini, "ax", @progbits
> +
> .globl func
> .func func
> func: .int 0
> --- ./gdb/testsuite/gdb.dwarf2/dw2-ranges.exp 25 Nov 2007 21:40:39 -0000 1.1
> +++ ./gdb/testsuite/gdb.dwarf2/dw2-ranges.exp 30 Nov 2007 15:01:49 -0000
> @@ -30,9 +30,10 @@ if {![istarget *-*-linux*]
>
> set testfile "dw2-ranges"
> set srcfile ${testfile}.S
> -set binfile ${objdir}/${subdir}/${testfile}.o
> +set srcfile2 ${testfile}2.S
> +set binfile ${objdir}/${subdir}/${testfile}
>
> -if {[gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" object debug] != "" } {
> +if {[gdb_compile "${srcdir}/${subdir}/${srcfile} ${srcdir}/${subdir}/${srcfile2}" "${binfile}" executable debug] != "" } {
> return -1
> }
>
> @@ -46,4 +47,7 @@ gdb_load ${binfile}
> # Wrong output:
> # No line number information available for address 0x4
>
> +gdb_test "info line main" "Line \[0-9\]* of .* starts at address .* and ends at .*"
> gdb_test "info line func" "Line \[0-9\]* of .* starts at address .* and ends at .*"
> +gdb_test "info line main2" "Line \[0-9\]* of .* starts at address .* and ends at .*"
> +gdb_test "info line func2" "Line \[0-9\]* of .* starts at address .* and ends at .*"
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ ./gdb/testsuite/gdb.dwarf2/dw2-ranges2.S 30 Nov 2007 15:01:49 -0000
> @@ -0,0 +1,43 @@
> +/*
> + 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 main2
> + .func main2
> +main2: .int 0
> + .endfunc
> + .size main2, . - main2
> +
> + /* `.fini' section is here to make sure `dw2-ranges.S'
> + vs. `dw2-ranges2.S' overlap their DW_AT_ranges with eac other. */
> + .section .fini, "ax", @progbits
> +
> + .globl func2
> + .func func2
> +func2: .int 0
> + .endfunc
> + .size func2, . - func2
>
>