http://sourceware.org/ml/gdb-patches/2011-04/msg00229.html Subject: [rfc, 7.3?] -O2 -g breakpoints internal error + prologue skipping [ Backported. ] Hi, obsoletes my: [patch] Fix internal error on some -O2 -g breakpoints http://sourceware.org/ml/gdb-patches/2010-07/msg00533.html and IMO also Paul's: [patch] Fix for PR gdb/12573 http://sourceware.org/ml/gdb-patches/2011-03/msg00883.html it is an improvement of: [patch] Do not skip prologue for -O2 -g with GCC VTA Re: [patch] Fix for PR gdb/12573 http://sourceware.org/ml/gdb-patches/2011-03/msg01129.html Just the removal of gdb_assert may place the breakpoints on -O2 -g code too late. IMO on `(gdb) break Bar::Bar' no real inferior modification should happen while with the Paul's reproducer in the PR the `free(malloc(1));' line is already executed when GDB stops. This over-execution is tested in the attached artificial reproducer by the testcase "no statement got executed". There are several issues of this patch: #1 The two-pass complicated execution in skip_prologue_sal currently has no effect as the functionality depending on it does not work now. But that is a separate new Bug and the two passes will be needed after its fix: regression by physname: PE32 prologue skip vs. static initializers http://sourceware.org/bugzilla/show_bug.cgi?id=12680 #2 A conservative approach has been taken. The problematic prologue skipping is disabled only if .debug_loc reference is found which proves -O2 (with -g). This test is imperfect as there may exist optimized debug code not using any location list and still facing inlining issues if handled as unoptimized code. For a future better test see GCC PR other/32998. GCC PR other/32998 = -frecord-gcc-switches issues, Status: NEW The opposite option would be to keep the prologue skipping enabled only if there is any DW_AT_location(DW_OP_fbreg(x)). I haven't tested this way, it seems very intrusive to me. In practice I doubt there will be a real world case of -O2 -g CU not referencing .debug_loc - such as if all its code accesses only global variables and has no local variables. Just the testcase originally was such a countercase CU. :-/ The GDB internal error is kept in place as it still can happen in such case, this problem is not yet fully fixed. #3 Whether a .debug_loc reference may be present with still invalid DW_AT_location before prologue I do not know, it does not seem to happen for GCC. There is currently no DW_AT_producer check. Even before VTA (Variable Tracking Assignments, since FSF GCC 4.5, -O2 -g variables DW_AT_location improvement) it seems to me the validity at function entry point worked well enough. #4 This whole problems appears only with involvement of inlined code, either explicitly or implicitly. But GDB does not support inlined code breakpoints well (PR breakpoints/10738, RH BZ#149125). When one plays with testing this patch various suitable breakpoints are not placed but AFAIK all of them are in the scope of the PR 10738. #5 If function does not start is not on a line boundary the multi-location breakpoints are already not found properly and everything fails. I do not think it can ever happen in real world. Even for a singe-line code void f (void) {} void g (void) {} GCC places there multiple line markers - -O2 -g, duplicity is for prologues: File name Line number Starting address 1.c 1 0 1.c 1 0 1.c 1 0x10 1.c 1 0x10 Whether this should go for 7.3 I am not sure. The simple removal of gdb_assert looks nice, GDB does not crash. But GDB behaves wrong and `break func' may not stop before a crash there at all etc. No regressions on {x86_64,x86_64-m32,i686}-fedora15-linux-gnu. I will to commit it without any review/discussion. Thanks, Jan gdb/ 2011-04-15 Jan Kratochvil * dwarf2read.c (struct dwarf2_cu): New field has_loclist. (process_full_comp_unit): Set also symtab->locations_valid. Move the symtab->language code. (var_decode_location): Set cu->has_loclist. * symtab.c (skip_prologue_sal): New variables saved_pc, force_skip and skip. Intialize force_skip from locations_valid. Move the prologue skipping code into two passes. * symtab.h (struct symtab): Make the primary field a bitfield. New field locations_valid. gdb/testsuite/ 2011-04-15 Jan Kratochvil * gdb.dwarf2/dw2-skip-prologue.S: New file. * gdb.dwarf2/dw2-skip-prologue.c: New file. * gdb.dwarf2/dw2-skip-prologue.exp: New file. --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -396,6 +396,13 @@ struct dwarf2_cu DIEs for namespaces, we don't need to try to infer them from mangled names. */ unsigned int has_namespace_info : 1; + + /* This CU references .debug_loc. See the symtab->locations_valid field. + This test is imperfect as there may exist optimized debug code not using + any location list and still facing inlining issues if handled as + unoptimized code. For a future better test see GCC PR other/32998. */ + + unsigned int has_loclist : 1; }; /* Persistent data held for a compilation unit, even when not @@ -4654,13 +4661,15 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu) symtab = end_symtab (highpc + baseaddr, objfile, SECT_OFF_TEXT (objfile)); - /* Set symtab language to language from DW_AT_language. - If the compilation is from a C file generated by language preprocessors, - do not set the language if it was already deduced by start_subfile. */ - if (symtab != NULL - && !(cu->language == language_c && symtab->language != language_c)) + if (symtab != NULL) { - symtab->language = cu->language; + /* Set symtab language to language from DW_AT_language. If the + compilation is from a C file generated by language preprocessors, do + not set the language if it was already deduced by start_subfile. */ + if (!(cu->language == language_c && symtab->language != language_c)) + symtab->language = cu->language; + + symtab->locations_valid = cu->has_loclist; } if (dwarf2_per_objfile->using_index) @@ -11221,6 +11230,9 @@ var_decode_location (struct attribute *a SYMBOL_CLASS (sym) = LOC_COMPUTED; dwarf2_symbol_mark_computed (attr, sym, cu); + + if (SYMBOL_COMPUTED_OPS (sym) == &dwarf2_loclist_funcs) + cu->has_loclist = 1; } /* Given a pointer to a DWARF information entry, figure out if we need --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -2454,12 +2454,13 @@ skip_prologue_sal (struct symtab_and_line *sal) struct symbol *sym; struct symtab_and_line start_sal; struct cleanup *old_chain; - CORE_ADDR pc; + CORE_ADDR pc, saved_pc; struct obj_section *section; const char *name; struct objfile *objfile; struct gdbarch *gdbarch; struct block *b, *function_block; + int force_skip, skip; /* Do not change the SAL is PC was specified explicitly. */ if (sal->explicit_pc) @@ -2497,46 +2498,69 @@ skip_prologue_sal (struct symtab_and_line *sal) gdbarch = get_objfile_arch (objfile); - /* If the function is in an unmapped overlay, use its unmapped LMA address, - so that gdbarch_skip_prologue has something unique to work on. */ - if (section_is_overlay (section) && !section_is_mapped (section)) - pc = overlay_unmapped_address (pc, section); + /* Process the prologue in two passes. In the first pass try to skip the + prologue (SKIP is true) and verify there is a real need for it (indicated + by FORCE_SKIP). If no such reason was found run a second pass where the + prologue is not skipped (SKIP is false). */ - /* Skip "first line" of function (which is actually its prologue). */ - pc += gdbarch_deprecated_function_start_offset (gdbarch); - pc = gdbarch_skip_prologue (gdbarch, pc); + skip = 1; + force_skip = 1; - /* For overlays, map pc back into its mapped VMA range. */ - pc = overlay_mapped_address (pc, section); + /* Be conservative - allow direct PC (without skipping prologue) only if we + have proven the CU (Compilation Unit) supports it. sal->SYMTAB does not + have to be set by the caller so we use SYM instead. */ + if (sym && SYMBOL_SYMTAB (sym)->locations_valid) + force_skip = 0; - /* Calculate line number. */ - start_sal = find_pc_sect_line (pc, section, 0); - - /* Check if gdbarch_skip_prologue left us in mid-line, and the next - line is still part of the same function. */ - if (start_sal.pc != pc - && (sym? (BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) <= start_sal.end - && start_sal.end < BLOCK_END (SYMBOL_BLOCK_VALUE (sym))) - : (lookup_minimal_symbol_by_pc_section (start_sal.end, section) - == lookup_minimal_symbol_by_pc_section (pc, section)))) + saved_pc = pc; + do { - /* First pc of next line */ - pc = start_sal.end; - /* Recalculate the line number (might not be N+1). */ - start_sal = find_pc_sect_line (pc, section, 0); - } + pc = saved_pc; - /* On targets with executable formats that don't have a concept of - constructors (ELF with .init has, PE doesn't), gcc emits a call - to `__main' in `main' between the prologue and before user - code. */ - if (gdbarch_skip_main_prologue_p (gdbarch) - && name && strcmp (name, "main") == 0) - { - pc = gdbarch_skip_main_prologue (gdbarch, pc); - /* Recalculate the line number (might not be N+1). */ + /* If the function is in an unmapped overlay, use its unmapped LMA address, + so that gdbarch_skip_prologue has something unique to work on. */ + if (section_is_overlay (section) && !section_is_mapped (section)) + pc = overlay_unmapped_address (pc, section); + + /* Skip "first line" of function (which is actually its prologue). */ + pc += gdbarch_deprecated_function_start_offset (gdbarch); + if (skip) + pc = gdbarch_skip_prologue (gdbarch, pc); + + /* For overlays, map pc back into its mapped VMA range. */ + pc = overlay_mapped_address (pc, section); + + /* Calculate line number. */ start_sal = find_pc_sect_line (pc, section, 0); + + /* Check if gdbarch_skip_prologue left us in mid-line, and the next + line is still part of the same function. */ + if (skip && start_sal.pc != pc + && (sym? (BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) <= start_sal.end + && start_sal.end < BLOCK_END (SYMBOL_BLOCK_VALUE (sym))) + : (lookup_minimal_symbol_by_pc_section (start_sal.end, section) + == lookup_minimal_symbol_by_pc_section (pc, section)))) + { + /* First pc of next line */ + pc = start_sal.end; + /* Recalculate the line number (might not be N+1). */ + start_sal = find_pc_sect_line (pc, section, 0); + } + + /* On targets with executable formats that don't have a concept of + constructors (ELF with .init has, PE doesn't), gcc emits a call + to `__main' in `main' between the prologue and before user + code. */ + if (gdbarch_skip_main_prologue_p (gdbarch) + && name && strcmp (name, "main") == 0) + { + pc = gdbarch_skip_main_prologue (gdbarch, pc); + /* Recalculate the line number (might not be N+1). */ + start_sal = find_pc_sect_line (pc, section, 0); + force_skip = 1; + } } + while (!force_skip && skip--); /* If we still don't have a valid source line, try to find the first PC in the lineinfo table that belongs to the same function. This @@ -2546,7 +2570,7 @@ skip_prologue_sal (struct symtab_and_line *sal) the case with the DJGPP target using "gcc -gcoff" when the compiler inserted code after the prologue to make sure the stack is aligned. */ - if (sym && start_sal.symtab == NULL) + if (!force_skip && sym && start_sal.symtab == NULL) { pc = skip_prologue_using_lineinfo (pc, SYMBOL_SYMTAB (sym)); /* Recalculate the line number. */ --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -767,7 +767,13 @@ struct symtab should be designated the primary, so that the blockvector is relocated exactly once by objfile_relocate. */ - int primary; + unsigned int primary : 1; + + /* Symtab has been compiled with both optimizations and debug info so that + GDB may stop skipping prologues as variables locations are valid already + at function entry points. */ + + unsigned int locations_valid : 1; /* The macro table for this symtab. Like the blockvector, this may be shared between different symtabs --- and normally is for --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-skip-prologue.S @@ -0,0 +1,391 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2011 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 . */ + + .section .debug_info +.Lcu1_begin: + /* CU header */ + .4byte .Lcu1_end - .Lcu1_start /* Length of Compilation Unit */ +.Lcu1_start: + .2byte 2 /* DWARF Version */ + .4byte .Labbrev1_begin /* Offset into abbrev section */ + .byte 4 /* Pointer size */ + + /* CU die */ + .uleb128 1 /* Abbrev: DW_TAG_compile_unit */ + .4byte .Lline1_begin /* DW_AT_stmt_list */ + .4byte func_start /* DW_AT_low_pc */ + .4byte func_end /* DW_AT_high_pc */ + .ascii "main.c\0" /* DW_AT_name */ + .ascii "GNU C 3.3.3\0" /* DW_AT_producer */ + .byte 2 /* DW_AT_language (DW_LANG_C) */ + + .uleb128 2 /* Abbrev: DW_TAG_subprogram */ + .byte 1 /* DW_AT_external */ + .ascii "func\0" /* DW_AT_name */ + .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */ + .4byte func_start /* DW_AT_low_pc */ + .4byte func_end /* DW_AT_high_pc */ + +/* GDB `has_loclist' detection of -O2 -g code needs to see a DW_AT_location + location list. There may exist -O2 -g CUs still not needing/using any such + location list - exactly like this CU. Make one up. */ + + .uleb128 0x7 /* (DIE (0x42) DW_TAG_formal_parameter) */ + .ascii "param\0" /* DW_AT_name */ + .long .Ltype_int - .Lcu1_begin /* DW_AT_type */ + .long loclist /* DW_AT_location */ + + .uleb128 4 /* Abbrev: DW_TAG_inlined_subroutine */ + .ascii "inlined\0" /* DW_AT_name */ + .4byte func0 /* DW_AT_low_pc */ + .4byte func1 /* DW_AT_high_pc */ + .byte 3 /* DW_AT_inline (DW_INL_declared_inlined) */ + .byte 1 /* DW_AT_call_file */ + .byte 8 /* DW_AT_call_line */ + + .uleb128 4 /* Abbrev: DW_TAG_inlined_subroutine */ + .ascii "inlined2\0" /* DW_AT_name */ + .4byte func2 /* DW_AT_low_pc */ + .4byte func3 /* DW_AT_high_pc */ + .byte 3 /* DW_AT_inline (DW_INL_declared_inlined) */ + .byte 1 /* DW_AT_call_file */ + .byte 11 /* DW_AT_call_line */ + +#ifdef INLINED + .uleb128 4 /* Abbrev: DW_TAG_inlined_subroutine */ + .ascii "otherinline\0" /* DW_AT_name */ + .4byte func3 /* DW_AT_low_pc */ + .4byte func_end /* DW_AT_high_pc */ + .byte 3 /* DW_AT_inline (DW_INL_declared_inlined) */ + .byte 1 /* DW_AT_call_file */ + .byte 9 /* DW_AT_call_line */ +#endif + +#ifdef LEXICAL + .uleb128 5 /* Abbrev: DW_TAG_lexical_block */ + .4byte func3 /* DW_AT_low_pc */ + .4byte func_end /* DW_AT_high_pc */ + + /* GDB would otherwise ignore the DW_TAG_lexical_block. */ + .uleb128 6 /* Abbrev: DW_TAG_variable */ + .ascii "lexicalvar\0" /* DW_AT_name */ + .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */ + + .byte 0 /* End of children of DW_TAG_lexical_block */ +#endif + + .byte 0 /* End of children of DW_TAG_subprogram */ + +/* Simulate `fund' is also named `func' so that the function name matches and + fund's SAL is not discarded in expand_line_sal_maybe. */ + + .uleb128 2 /* Abbrev: DW_TAG_subprogram */ + .byte 1 /* DW_AT_external */ + .ascii "func\0" /* DW_AT_name */ + .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */ + .4byte fund_start /* DW_AT_low_pc */ + .4byte fund_end /* DW_AT_high_pc */ + + .byte 0 /* End of children of DW_TAG_subprogram */ + +.Ltype_int: + .uleb128 3 /* Abbrev: DW_TAG_base_type */ + .ascii "int\0" /* DW_AT_name */ + .byte 4 /* DW_AT_byte_size */ + .byte 5 /* DW_AT_encoding */ + + .byte 0 /* End of children of CU */ + +.Lcu1_end: + + .section .debug_loc +loclist: + /* Reset the location list base address first. */ + .long -1, 0 + + .long func_start, func_end + .2byte 2f-1f +1: .byte 0x50 /* DW_OP_reg0 */ +2: + /* Location list end. */ + .long 0, 0 + +/* Abbrev table */ + .section .debug_abbrev +.Labbrev1_begin: + .uleb128 1 /* Abbrev code */ + .uleb128 0x11 /* DW_TAG_compile_unit */ + .byte 1 /* has_children */ + .uleb128 0x10 /* DW_AT_stmt_list */ + .uleb128 0x6 /* DW_FORM_data4 */ + .uleb128 0x11 /* DW_AT_low_pc */ + .uleb128 0x1 /* DW_FORM_addr */ + .uleb128 0x12 /* DW_AT_high_pc */ + .uleb128 0x1 /* DW_FORM_addr */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0x25 /* DW_AT_producer */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0x13 /* DW_AT_language */ + .uleb128 0xb /* DW_FORM_data1 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 2 /* Abbrev code */ + .uleb128 0x2e /* DW_TAG_subprogram */ + .byte 1 /* has_children */ + .uleb128 0x3f /* DW_AT_external */ + .uleb128 0xc /* DW_FORM_flag */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x11 /* DW_AT_low_pc */ + .uleb128 0x1 /* DW_FORM_addr */ + .uleb128 0x12 /* DW_AT_high_pc */ + .uleb128 0x1 /* DW_FORM_addr */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 3 /* Abbrev code */ + .uleb128 0x24 /* DW_TAG_base_type */ + .byte 0 /* has_children */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0xb /* DW_AT_byte_size */ + .uleb128 0xb /* DW_FORM_data1 */ + .uleb128 0x3e /* DW_AT_encoding */ + .uleb128 0xb /* DW_FORM_data1 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 4 /* Abbrev code */ + .uleb128 0x1d /* DW_TAG_inlined_subroutine */ + .byte 0 /* has_children */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0x11 /* DW_AT_low_pc */ + .uleb128 0x1 /* DW_FORM_addr */ + .uleb128 0x12 /* DW_AT_high_pc */ + .uleb128 0x1 /* DW_FORM_addr */ + .uleb128 0x20 /* DW_AT_inline */ + .uleb128 0xb /* DW_FORM_data1 */ + .uleb128 0x58 /* DW_AT_call_file */ + .uleb128 0xb /* DW_FORM_data1 */ + .uleb128 0x59 /* DW_AT_call_line */ + .uleb128 0xb /* DW_FORM_data1 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 5 /* Abbrev code */ + .uleb128 0x0b /* DW_TAG_lexical_block */ + .byte 1 /* has_children */ + .uleb128 0x11 /* DW_AT_low_pc */ + .uleb128 0x1 /* DW_FORM_addr */ + .uleb128 0x12 /* DW_AT_high_pc */ + .uleb128 0x1 /* DW_FORM_addr */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 6 /* Abbrev code */ + .uleb128 0x34 /* DW_TAG_variable */ + .byte 0 /* has_children */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 0x7 /* (abbrev code) */ + .uleb128 0x5 /* (TAG: DW_TAG_formal_parameter) */ + .byte 0x0 /* DW_children_no */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0x49 /* (DW_AT_type) */ + .uleb128 0x13 /* (DW_FORM_ref4) */ + .uleb128 0x02 /* (DW_AT_location) */ + .uleb128 0x06 /* (DW_FORM_data4) */ + .byte 0x0 + .byte 0x0 + + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + +/* Line table */ + .section .debug_line +.Lline1_begin: + .4byte .Lline1_end - .Lline1_start /* Initial length */ +.Lline1_start: + .2byte 2 /* Version */ + .4byte .Lline1_lines - .Lline1_hdr /* header_length */ +.Lline1_hdr: + .byte 1 /* Minimum insn length */ + .byte 1 /* default_is_stmt */ + .byte 1 /* line_base */ + .byte 1 /* line_range */ + .byte 0x10 /* opcode_base */ + + /* Standard lengths */ + .byte 0 + .byte 1 + .byte 1 + .byte 1 + .byte 1 + .byte 0 + .byte 0 + .byte 0 + .byte 1 + .byte 0 + .byte 0 + .byte 1 + .byte 0 + .byte 0 + .byte 0 + + /* Include directories */ + .byte 0 + + /* File names */ + .ascii "main.c\0" + .uleb128 0 + .uleb128 0 + .uleb128 0 + + .ascii "other.c\0" + .uleb128 0 + .uleb128 0 + .uleb128 0 + + .byte 0 + +.Lline1_lines: + .byte 0 /* DW_LNE_set_address */ + .uleb128 5 + .byte 2 + .4byte func_start + .byte 3 /* DW_LNS_advance_line */ + .sleb128 4 /* ... to 5 */ + .byte 1 /* DW_LNS_copy */ + + .byte 0 /* DW_LNE_set_address */ + .uleb128 5 + .byte 2 + .4byte func0 + .byte 4 /* DW_LNS_set_file */ + .uleb128 2 + .byte 3 /* DW_LNS_advance_line */ + .sleb128 -4 /* ... to 1 */ + .byte 1 /* DW_LNS_copy */ + + .byte 0 /* DW_LNE_set_address */ + .uleb128 5 + .byte 2 + .4byte func1 + .byte 4 /* DW_LNS_set_file */ + .uleb128 1 + .byte 3 /* DW_LNS_advance_line */ + .sleb128 8 /* ... to 9 */ + .byte 1 /* DW_LNS_copy */ + + .byte 0 /* DW_LNE_set_address */ + .uleb128 5 + .byte 2 + .4byte func2 + .byte 4 /* DW_LNS_set_file */ + .uleb128 2 + .byte 3 /* DW_LNS_advance_line */ + .sleb128 -8 /* ... to 1 */ + .byte 1 /* DW_LNS_copy */ + + .byte 0 /* DW_LNE_set_address */ + .uleb128 5 + .byte 2 + .4byte func3 + .byte 4 /* DW_LNS_set_file */ + .uleb128 1 + .byte 3 /* DW_LNS_advance_line */ + .sleb128 8 /* ... to 9 */ + .byte 1 /* DW_LNS_copy */ + + .byte 0 /* DW_LNE_set_address */ + .uleb128 5 + .byte 2 + .4byte func_end + +/* Equivalent copy but renamed s/func/fund/. */ + + .byte 0 /* DW_LNE_set_address */ + .uleb128 5 + .byte 2 + .4byte fund_start + .byte 3 /* DW_LNS_advance_line */ + .sleb128 -4 /* ... to 5 */ + .byte 1 /* DW_LNS_copy */ + + .byte 0 /* DW_LNE_set_address */ + .uleb128 5 + .byte 2 + .4byte fund0 + .byte 4 /* DW_LNS_set_file */ + .uleb128 2 + .byte 3 /* DW_LNS_advance_line */ + .sleb128 -4 /* ... to 1 */ + .byte 1 /* DW_LNS_copy */ + + .byte 0 /* DW_LNE_set_address */ + .uleb128 5 + .byte 2 + .4byte fund1 + .byte 4 /* DW_LNS_set_file */ + .uleb128 1 + .byte 3 /* DW_LNS_advance_line */ + .sleb128 8 /* ... to 9 */ + .byte 1 /* DW_LNS_copy */ + + .byte 0 /* DW_LNE_set_address */ + .uleb128 5 + .byte 2 + .4byte fund2 + .byte 4 /* DW_LNS_set_file */ + .uleb128 2 + .byte 3 /* DW_LNS_advance_line */ + .sleb128 -8 /* ... to 1 */ + .byte 1 /* DW_LNS_copy */ + + .byte 0 /* DW_LNE_set_address */ + .uleb128 5 + .byte 2 + .4byte fund3 + .byte 4 /* DW_LNS_set_file */ + .uleb128 1 + .byte 3 /* DW_LNS_advance_line */ + .sleb128 8 /* ... to 9 */ + .byte 1 /* DW_LNS_copy */ + + .byte 0 /* DW_LNE_set_address */ + .uleb128 5 + .byte 2 + .4byte fund_end + +/* Line numbering end. */ + + .byte 0 /* DW_LNE_end_of_sequence */ + .uleb128 1 + .byte 1 + +.Lline1_end: --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-skip-prologue.c @@ -0,0 +1,58 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2011 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 . */ + +static volatile int v; + +asm ("func_start: .globl func_start\n"); +static int +func (void) +{ + v++; +asm ("func0: .globl func0\n"); + v++; +asm ("func1: .globl func1\n"); + v++; +asm ("func2: .globl func2\n"); + v++; +asm ("func3: .globl func3\n"); + return v; +} +asm ("func_end: .globl func_end\n"); + +/* Equivalent copy but renamed s/func/fund/. */ + +asm ("fund_start: .globl fund_start\n"); +static int +fund (void) +{ + v++; +asm ("fund0: .globl fund0\n"); + v++; +asm ("fund1: .globl fund1\n"); + v++; +asm ("fund2: .globl fund2\n"); + v++; +asm ("fund3: .globl fund3\n"); + return v; +} +asm ("fund_end: .globl fund_end\n"); + +int +main (void) +{ + return func () + fund (); +} --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-skip-prologue.exp @@ -0,0 +1,74 @@ +# Copyright 2011 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 . +load_lib dwarf.exp + +# Test multiple location breakpoints vs. prologue analysis on -O2 -g code. +# when the first statement of a function is an inlined function GDB could +# crash. Map of this testcase: +# +# File name Line number Starting address +# main.c 5 func_start +# other.c 1 func0 +# `inlined' called at main.c line 8 +# main.c 9 func1 +# func1 = Breakpoint location 1 +# other.c 1 func2 +# `inlined2' called at main.c line 11 +# main.c 9 func3 +# func3 = Breakpoint location 2 +# `otherinline' called at main.c line 9 +# end of main func_end + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +set testfile "dw2-skip-prologue" +set executable ${testfile} +set binfile ${objdir}/${subdir}/${executable} + +if {[build_executable ${testfile}.exp ${executable} "${testfile}.c ${testfile}.S" {additional_flags=-DINLINED}] == -1} { + return -1 +} + +# We need those symbols global to access them from the .S file. +set test "strip stub symbols" +set objcopy_program [transform objcopy] +set result [catch "exec $objcopy_program \ + -N func0 -N func1 -N func2 -N func3 -N func_start -N func_end \ + -N fund0 -N fund1 -N fund2 -N fund3 -N fund -N fund_start \ + ${binfile}" output] +verbose "result is $result" +verbose "output is $output" +if {$result != 0} { + fail $test + return +} +pass $test + +clean_restart $executable + +if ![runto_main] { + return -1 +} + +gdb_breakpoint "func" +gdb_continue_to_breakpoint "func" + +# Sanity check GDB has really found 2 locations +gdb_test {info break $bpnum} "\r\n2\\.1\[ \t\]\[^\n\]*\r\n2\\.2\[ \t\]\[^\n\]*" "2 locations found" + +gdb_test "p v" " = 0" "no statement got executed"