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.
This commit is contained in:
Doug Evans 2014-08-22 17:25:59 -07:00
parent 9bda4a968f
commit a05a36a5fc
6 changed files with 471 additions and 12 deletions

View File

@ -1,3 +1,10 @@
2014-08-22 Doug Evans <dje@google.com>
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 <dje@google.com>
* buildsym.h (record_line_ftype): New typedef.

View File

@ -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);
}
}

View File

@ -1,3 +1,10 @@
2014-08-22 Doug Evans <dje@google.com>
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 <yao@codesourcery.com>
* gdb.python/py-finish-breakpoint.exp: Copy .py file to host.

View File

@ -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 <http://www.gnu.org/licenses/>. */
/* 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:

View File

@ -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 <http://www.gnu.org/licenses/>. */
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;
}

View File

@ -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 <http://www.gnu.org/licenses/>.
# 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\]+"