From a05a36a5fc98c816381b25c37e8aa971cc86c28d Mon Sep 17 00:00:00 2001 From: Doug Evans Date: Fri, 22 Aug 2014 17:25:59 -0700 Subject: [PATCH] Fix pr 17276. See the description here: https://sourceware.org/ml/gdb-patches/2014-08/msg00283.html This patch keeps track of whether the current line has seen a non-zero discriminator, and if so coalesces consecutive entries for the same line (by ignoring all entries after the first). gdb/ChangeLog: PR 17276 * dwarf2read.c (dwarf_record_line_p): New function. (dwarf_decode_lines_1): Ignore subsequent line number entries for the same line if any entry had a non-zero discriminator. gdb/testsuite/ChangeLog: * gdb.dwarf2/dw2-single-line-discriminators.S: New file. * gdb.dwarf2/dw2-single-line-discriminators.c: New file. * gdb.dwarf2/dw2-single-line-discriminators.exp: New file. --- gdb/ChangeLog | 7 + gdb/dwarf2read.c | 108 ++++++- gdb/testsuite/ChangeLog | 7 + .../dw2-single-line-discriminators.S | 281 ++++++++++++++++++ .../dw2-single-line-discriminators.c | 31 ++ .../dw2-single-line-discriminators.exp | 49 +++ 6 files changed, 471 insertions(+), 12 deletions(-) create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-single-line-discriminators.S create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-single-line-discriminators.c create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-single-line-discriminators.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 2ebc1e8fdcf..0978d63ff35 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2014-08-22 Doug Evans + + PR 17276 + * dwarf2read.c (dwarf_record_line_p): New function. + (dwarf_decode_lines_1): Ignore subsequent line number entries + for the same line if any entry had a non-zero discriminator. + 2014-08-22 Doug Evans * buildsym.h (record_line_ftype): New typedef. diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 57a2e652461..458977eabe6 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -17174,6 +17174,53 @@ noop_record_line (struct subfile *subfile, int line, CORE_ADDR pc) return; } +/* Return non-zero if we should add LINE to the line number table. + LINE is the line to add, LAST_LINE is the last line that was added, + LAST_SUBFILE is the subfile for LAST_LINE. + LINE_HAS_NON_ZERO_DISCRIMINATOR is non-zero if LINE has ever + had a non-zero discriminator. + + We have to be careful in the presence of discriminators. + E.g., for this line: + + for (i = 0; i < 100000; i++); + + clang can emit four line number entries for that one line, + each with a different discriminator. + See gdb.dwarf2/dw2-single-line-discriminators.exp for an example. + + However, we want gdb to coalesce all four entries into one. + Otherwise the user could stepi into the middle of the line and + gdb would get confused about whether the pc really was in the + middle of the line. + + Things are further complicated by the fact that two consecutive + line number entries for the same line is a heuristic used by gcc + to denote the end of the prologue. So we can't just discard duplicate + entries, we have to be selective about it. The heuristic we use is + that we only collapse consecutive entries for the same line if at least + one of those entries has a non-zero discriminator. PR 17276. + + Note: Addresses in the line number state machine can never go backwards + within one sequence, thus this coalescing is ok. */ + +static int +dwarf_record_line_p (unsigned int line, unsigned int last_line, + int line_has_non_zero_discriminator, + struct subfile *last_subfile) +{ + if (current_subfile != last_subfile) + return 1; + if (line != last_line) + return 1; + /* Same line for the same file that we've seen already. + As a last check, for pr 17276, only record the line if the line + has never had a non-zero discriminator. */ + if (!line_has_non_zero_discriminator) + return 1; + return 0; +} + /* Use P_RECORD_LINE to record line number LINE beginning at address ADDRESS in the line table of subfile SUBFILE. */ @@ -17234,6 +17281,12 @@ dwarf_decode_lines_1 (struct line_header *lh, const char *comp_dir, int is_stmt = lh->default_is_stmt; int end_sequence = 0; unsigned char op_index = 0; + unsigned int discriminator = 0; + /* The last line number that was recorded, used to coalesce + consecutive entries for the same line. This can happen, for + example, when discriminators are present. PR 17276. */ + unsigned int last_line = 0; + int line_has_non_zero_discriminator = 0; if (!decode_for_pst_p && lh->num_file_names >= file) { @@ -17265,6 +17318,7 @@ dwarf_decode_lines_1 (struct line_header *lh, const char *comp_dir, { /* Special opcode. */ unsigned char adj_opcode; + int line_delta; adj_opcode = op_code - lh->opcode_base; address += (((op_index + (adj_opcode / lh->line_range)) @@ -17272,7 +17326,10 @@ dwarf_decode_lines_1 (struct line_header *lh, const char *comp_dir, * lh->minimum_instruction_length); op_index = ((op_index + (adj_opcode / lh->line_range)) % lh->maximum_ops_per_instruction); - line += lh->line_base + (adj_opcode % lh->line_range); + line_delta = lh->line_base + (adj_opcode % lh->line_range); + line += line_delta; + if (line_delta != 0) + line_has_non_zero_discriminator = discriminator != 0; if (lh->num_file_names < file || file == 0) dwarf2_debug_line_missing_file_complaint (); /* For now we ignore lines not starting on an @@ -17286,13 +17343,19 @@ dwarf_decode_lines_1 (struct line_header *lh, const char *comp_dir, { dwarf_finish_line (gdbarch, last_subfile, address, p_record_line); - last_subfile = current_subfile; } - /* Append row to matrix using current values. */ - dwarf_record_line (gdbarch, current_subfile, - line, address, p_record_line); + if (dwarf_record_line_p (line, last_line, + line_has_non_zero_discriminator, + last_subfile)) + { + dwarf_record_line (gdbarch, current_subfile, + line, address, p_record_line); + } + last_subfile = current_subfile; + last_line = line; } } + discriminator = 0; } else switch (op_code) { @@ -17355,8 +17418,14 @@ dwarf_decode_lines_1 (struct line_header *lh, const char *comp_dir, break; case DW_LNE_set_discriminator: /* The discriminator is not interesting to the debugger; - just ignore it. */ - line_ptr = extended_end; + just ignore it. We still need to check its value though: + if there are consecutive entries for the same + (non-prologue) line we want to coalesce them. + PR 17276. */ + discriminator = read_unsigned_leb128 (abfd, line_ptr, + &bytes_read); + line_has_non_zero_discriminator |= discriminator != 0; + line_ptr += bytes_read; break; default: complaint (&symfile_complaints, @@ -17385,12 +17454,19 @@ dwarf_decode_lines_1 (struct line_header *lh, const char *comp_dir, { dwarf_finish_line (gdbarch, last_subfile, address, p_record_line); - last_subfile = current_subfile; } - dwarf_record_line (gdbarch, current_subfile, - line, address, p_record_line); + if (dwarf_record_line_p (line, last_line, + line_has_non_zero_discriminator, + last_subfile)) + { + dwarf_record_line (gdbarch, current_subfile, + line, address, p_record_line); + } + last_subfile = current_subfile; + last_line = line; } } + discriminator = 0; break; case DW_LNS_advance_pc: { @@ -17406,8 +17482,15 @@ dwarf_decode_lines_1 (struct line_header *lh, const char *comp_dir, } break; case DW_LNS_advance_line: - line += read_signed_leb128 (abfd, line_ptr, &bytes_read); - line_ptr += bytes_read; + { + int line_delta + = read_signed_leb128 (abfd, line_ptr, &bytes_read); + + line += line_delta; + if (line_delta != 0) + line_has_non_zero_discriminator = discriminator != 0; + line_ptr += bytes_read; + } break; case DW_LNS_set_file: { @@ -17429,6 +17512,7 @@ dwarf_decode_lines_1 (struct line_header *lh, const char *comp_dir, if (!decode_for_pst_p) { last_subfile = current_subfile; + line_has_non_zero_discriminator = discriminator != 0; dwarf2_start_subfile (fe->name, dir, comp_dir); } } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 08ee2b9c756..a006ed5c7d5 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2014-08-22 Doug Evans + + PR 17276 + * gdb.dwarf2/dw2-single-line-discriminators.S: New file. + * gdb.dwarf2/dw2-single-line-discriminators.c: New file. + * gdb.dwarf2/dw2-single-line-discriminators.exp: New file. + 2014-08-22 Yao Qi * gdb.python/py-finish-breakpoint.exp: Copy .py file to host. diff --git a/gdb/testsuite/gdb.dwarf2/dw2-single-line-discriminators.S b/gdb/testsuite/gdb.dwarf2/dw2-single-line-discriminators.S new file mode 100644 index 00000000000..a9fa63e0131 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-single-line-discriminators.S @@ -0,0 +1,281 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 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 . */ + +/* This was made from dw2-single-line-discriminators.c using + clang -dA -S -g + and then hand-editing the assembly a bit (simplify paths, + tweak so gas accepts it). */ + + .text + .file "dw2-single-line-discriminators.c" + .section .debug_info,"",@progbits +.Lsection_info: + .section .debug_abbrev,"",@progbits +.Lsection_abbrev: + .section .debug_line,"",@progbits +.Lsection_line: + .section .debug_pubnames,"",@progbits + .section .debug_pubtypes,"",@progbits + .section .debug_str,"MS",@progbits,1 +.Linfo_string: + .section .debug_loc,"",@progbits +.Lsection_debug_loc: + .section .debug_ranges,"",@progbits +.Ldebug_range: + .file 1 "gdb.dwarf2/dw2-single-line-discriminators.c" + .text + .globl main + .align 16, 0x90 + .type main,@function +main: # @main +.Lfunc_begin0: + .loc 1 22 0 # dw2-single-line-discriminators.c:22:0 + .cfi_startproc +# BB#0: + pushq %rbp +.Ltmp0: + .cfi_def_cfa_offset 16 +.Ltmp1: + .cfi_offset %rbp, -16 + movq %rsp, %rbp +.Ltmp2: + .cfi_def_cfa_register %rbp + movl $0, -4(%rbp) + .loc 1 26 3 prologue_end # dw2-single-line-discriminators.c:26:3 +.Ltmp3: + movl $0, x + .loc 1 28 8 # dw2-single-line-discriminators.c:28:8 +.Ltmp4: + movl $0, -8(%rbp) +.LBB0_1: # =>This Inner Loop Header: Depth=1 + .loc 1 28 8 discriminator 4 # dw2-single-line-discriminators.c:28:8 +.Ltmp5: + cmpl $10, -8(%rbp) + jge .LBB0_4 +.Ltmp6: +# BB#2: # in Loop: Header=BB0_1 Depth=1 + .loc 1 28 28 discriminator 2 # dw2-single-line-discriminators.c:28:28 + jmp .LBB0_3 +.Ltmp7: +.LBB0_3: # in Loop: Header=BB0_1 Depth=1 + .loc 1 28 23 discriminator 3 # dw2-single-line-discriminators.c:28:23 + movl -8(%rbp), %eax + addl $1, %eax + movl %eax, -8(%rbp) + jmp .LBB0_1 +.Ltmp8: +.LBB0_4: + movl $0, %eax + .loc 1 30 3 # dw2-single-line-discriminators.c:30:3 + popq %rbp + retq +.Ltmp9: +.Ltmp10: + .size main, .Ltmp10-main +.Lfunc_end0: + .cfi_endproc + + .type x,@object # @x + .comm x,4,4 +.Ldebug_end1: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version (trunk r215195)" +.Linfo_string1: + .asciz "dw2-single-line-discriminators.c" +.Linfo_string2: + .asciz "/tmp/obj/gdb/testsuite" +.Linfo_string3: + .asciz "x" +.Linfo_string4: + .asciz "int" +.Linfo_string5: + .asciz "main" +.Linfo_string6: + .asciz "i" + .section .debug_info,"",@progbits +.L.debug_info_begin0: + .long 108 # Length of Unit + .short 4 # DWARF version number + .long .Lsection_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x65 DW_TAG_compile_unit + .long .Linfo_string0 # DW_AT_producer + .short 12 # DW_AT_language + .long .Linfo_string1 # DW_AT_name + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Linfo_string2 # DW_AT_comp_dir + .quad .Lfunc_begin0 # DW_AT_low_pc +.Lset0 = .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .long .Lset0 + .byte 2 # Abbrev [2] 0x2a:0x15 DW_TAG_variable + .long .Linfo_string3 # DW_AT_name + .long 63 # DW_AT_type + # DW_AT_external + .byte 1 # DW_AT_decl_file + .byte 18 # DW_AT_decl_line + .byte 9 # DW_AT_location + .byte 3 + .quad x + .byte 3 # Abbrev [3] 0x3f:0x7 DW_TAG_base_type + .long .Linfo_string4 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 4 # Abbrev [4] 0x46:0x29 DW_TAG_subprogram + .quad .Lfunc_begin0 # DW_AT_low_pc +.Lset1 = .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .long .Lset1 + .byte 1 # DW_AT_frame_base + .byte 86 + .long .Linfo_string5 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 21 # DW_AT_decl_line + .long 63 # DW_AT_type + # DW_AT_external + .byte 1 # DW_AT_accessibility + # DW_ACCESS_public + .byte 5 # Abbrev [5] 0x60:0xe DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .long .Linfo_string6 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 23 # DW_AT_decl_line + .long 63 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark +.L.debug_info_end0: + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 14 # DW_FORM_strp + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 50 # DW_AT_accessibility + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_ranges,"",@progbits + .section .debug_loc,"",@progbits + .section .debug_pubnames,"",@progbits +.Lset2 = .LpubNames_end0-.LpubNames_begin0 # Length of Public Names Info + .long .Lset2 +.LpubNames_begin0: + .short 2 # DWARF Version + .long .L.debug_info_begin0 # Offset of Compilation Unit Info +.Lset3 = .L.debug_info_end0-.L.debug_info_begin0 # Compilation Unit Length + .long .Lset3 + .long 70 # DIE offset + .asciz "main" # External Name + .long 42 # DIE offset + .asciz "x" # External Name + .long 0 # End Mark +.LpubNames_end0: + .section .debug_pubtypes,"",@progbits +.Lset4 = .LpubTypes_end0-.LpubTypes_begin0 # Length of Public Types Info + .long .Lset4 +.LpubTypes_begin0: + .short 2 # DWARF Version + .long .L.debug_info_begin0 # Offset of Compilation Unit Info +.Lset5 = .L.debug_info_end0-.L.debug_info_begin0 # Compilation Unit Length + .long .Lset5 + .long 63 # DIE offset + .asciz "int" # External Name + .long 0 # End Mark +.LpubTypes_end0: + + .ident "clang version (trunk r215195)" + .section ".note.GNU-stack","",@progbits + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/gdb/testsuite/gdb.dwarf2/dw2-single-line-discriminators.c b/gdb/testsuite/gdb.dwarf2/dw2-single-line-discriminators.c new file mode 100644 index 00000000000..5e0f7fb0815 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-single-line-discriminators.c @@ -0,0 +1,31 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 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 . */ + +int x; + +int +main () +{ + int i; + + /* Ensure runto_main stops before the for loop. */ + x = 0; + + for (i = 0; i < 10; ++i) continue; /* stepi line */ + + return 0; +} diff --git a/gdb/testsuite/gdb.dwarf2/dw2-single-line-discriminators.exp b/gdb/testsuite/gdb.dwarf2/dw2-single-line-discriminators.exp new file mode 100644 index 00000000000..dbd9438a350 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-single-line-discriminators.exp @@ -0,0 +1,49 @@ +# Copyright 2012-2014 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 gdb's coalescing of multiple line number entries for the same line +# but with different discriminators. PR 17276. + +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if ![dwarf2_support] { + return 0 +} + +# This test can only be run on x86-64 targets. +if {![istarget x86_64-*] || ![is_lp64_target]} { + return 0 +} + +standard_testfile .S +set csrcfile ${testfile}.c + +if { [prepare_for_testing "${testfile}.exp" "${testfile}" $srcfile {nodebug}] } { + return -1 +} + +if ![runto_main] then { + fail "Cannot run to main." + continue +} + +set srcline [gdb_get_line_number "stepi line" $csrcfile] +gdb_breakpoint $srcline +gdb_continue_to_breakpoint "stepi line" + +# A stepi will land us in the middle of the line, and thus +# gdb should print the pc value. +gdb_test "stepi" "$hex\[ \t\]+$srcline\[ \t\]+\[^\r\n\]+" -- 2.30.2