[Public] Hi, While working on the implementation of DW_FORM_strx forms, addr2line tool could not print file names even after the implementation of strx forms. I found an issue with adding the file names to the file table with dwarf5 and clang. With dwarf5 debug line version, the file index is starting with zero, but the code is expecting it to be 1 which is the case with other dwarf versions. From the contents of .debug_line compiled with clang and dwarf5, the file names array index is starting with zero. standard_opcode_lengths[DW_LNS_set_isa] = 1 include_directories[ 0] = "/home/rupesh/addr2line" file_names[ 0]: name: "prog1.c" dir_index: 0 md5_checksum: da4ea4c312af96d39b13557acdf23f05 Address Line Column File ISA Discriminator Flags ------------------ ------ ------ ------ --- ------------- ------------- The below line skipping zero entry was added as part of commit 19d80e5fec548e681c453d15b4ae5b49bc080acc is ignoring the file names in the zeroth index. I have no idea why this line was added. Removing the line is working for programs compiled with clang using dwarf5. With my fix, I am not seeing any issues with GCC and dwarf5 because currently GCC's debug_line version is 3 even when compiled with dwarf5. /* Skip the first "zero entry", which is the compilation dir/file. */ if (datai != 0) if (!callback (table, fe.name, fe.dir, fe.time, fe.size)) return false; Made code changes to fix this issue. Added a new test case for addr2line to test the changes. And fixed a minor bug in read_indexed_address where in offset_size is used instead of addr_size. Can you review the code changes and send in your comments/suggestions? Regards, Rupesh P Patch Inline: Fixed an issue with the file index for dwarf5. Added addr2line test case. read_indexed_address is using offset_size instead of addr_size while reading addrx forms, fixed that as well. --- bfd/dwarf2.c | 21 ++++--- binutils/testsuite/binutils-all/addr2line.exp | 59 +++++++++++++++++++ binutils/testsuite/config/default.exp | 6 ++ 3 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 binutils/testsuite/binutils-all/addr2line.exp diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c index aaa2d84887f..2a992d67bc7 100644 --- a/bfd/dwarf2.c +++ b/bfd/dwarf2.c @@ -1369,7 +1369,7 @@ read_indexed_address (uint64_t idx, struct comp_unit *unit) &file->dwarf_addr_buffer, &file->dwarf_addr_size)) return 0; - if (_bfd_mul_overflow (idx, unit->offset_size, &offset)) + if (_bfd_mul_overflow (idx, unit->addr_size, &offset)) return 0; offset += unit->dwarf_addr_offset; @@ -1380,9 +1380,9 @@ read_indexed_address (uint64_t idx, struct comp_unit *unit) info_ptr = file->dwarf_addr_buffer + offset; - if (unit->offset_size == 4) + if (unit->addr_size == 4) return bfd_get_32 (unit->abfd, info_ptr); - else if (unit->offset_size == 8) + else if (unit->addr_size == 8) return bfd_get_64 (unit->abfd, info_ptr); else return 0; @@ -1731,6 +1731,7 @@ struct line_info_table unsigned int num_files; unsigned int num_dirs; unsigned int num_sequences; + unsigned int version; char * comp_dir; char ** dirs; struct fileinfo* files; @@ -1951,6 +1952,8 @@ concat_filename (struct line_info_table *table, unsigned int file) { char *filename; + if (table->version >= 5) + file = file + 1; if (table == NULL || file - 1 >= table->num_files) { /* FILE == 0 means unknown. */ @@ -2579,10 +2582,8 @@ read_formatted_entries (struct comp_unit *unit, bfd_byte **bufp, } } - /* Skip the first "zero entry", which is the compilation dir/file. */ - if (datai != 0) - if (!callback (table, fe.name, fe.dir, fe.time, fe.size)) - return false; + if (!callback (table, fe.name, fe.dir, fe.time, fe.size)) + return false; } *bufp = buf; @@ -2747,6 +2748,7 @@ decode_line_info (struct comp_unit *unit) table->sequences = NULL; table->lcl_head = NULL; + table->version = lh.version; if (lh.version >= 5) { @@ -2789,13 +2791,16 @@ decode_line_info (struct comp_unit *unit) /* State machine registers. */ bfd_vma address = 0; unsigned char op_index = 0; - char * filename = table->num_files ? concat_filename (table, 1) : NULL; + char *filename; + int index = table->version >= 5 ? 0 : 1; unsigned int line = 1; unsigned int column = 0; unsigned int discriminator = 0; int is_stmt = lh.default_is_stmt; int end_sequence = 0; unsigned int dir, xtime, size; + + filename = table->num_files ? concat_filename (table, index) : NULL; /* eraxxon@alumni.rice.edu: Against the DWARF2 specs, some compilers generate address sequences that are wildly out of order using DW_LNE_set_address (e.g. Intel C++ 6.0 compiler diff --git a/binutils/testsuite/binutils-all/addr2line.exp b/binutils/testsuite/binutils-all/addr2line.exp new file mode 100644 index 00000000000..153e83c2ace --- /dev/null +++ b/binutils/testsuite/binutils-all/addr2line.exp @@ -0,0 +1,59 @@ +# Copyright (C) 2018-2022 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + + global $NM + global $ADDR2LINE + + set testname "addr2line" + if { [target_compile $srcdir/$subdir/testprog.c tmpdir/testprog executable debug] != "" } { + verbose "Unable to compile test file." + untested "addr2line" + return + } + + #testcase for default option. + set output [binutils_run $NM "tmpdir/testprog"] + regexp -line {^[0-9]+\s+[A-Z]\s+main} $output contents + set list [regexp -inline -all -- {\S+} $contents] + + set got [binutils_run $ADDR2LINE "-e tmpdir/testprog [lindex $list 0]"] + set want "$srcdir/$subdir/testprog.c:\[0-9\]+" + if ![regexp $want $got] then { + fail "$testname $got\n" + } else { + pass "$testname" + } + + #testcase for -f option. + regexp -line {^[0-9]+\s+[A-Z]\s+fn} $output contents + set list [regexp -inline -all -- {\S+} $contents] + + set got [binutils_run $ADDR2LINE "-f -e tmpdir/testprog [lindex $list 0]"] + set want "fn\n$srcdir/$subdir/testprog.c:\[0-9\]+" + if ![regexp $want $got] then { + fail "$testname -f option $got\n" + } else { + pass "$testname -f option" + } + + #testcase for -s option. + set got [binutils_run $ADDR2LINE "-s -e tmpdir/testprog [lindex $list 0]"] + set want "testprog.c:\[0-9\]+" + if ![regexp $want $got] then { + fail "$testname -s option $got\n" + } else { + pass "$testname -s option" + } diff --git a/binutils/testsuite/config/default.exp b/binutils/testsuite/config/default.exp index c654bd4081c..7192c929a83 100644 --- a/binutils/testsuite/config/default.exp +++ b/binutils/testsuite/config/default.exp @@ -40,6 +40,12 @@ if ![info exists NM] then { if ![info exists NMFLAGS] then { set NMFLAGS "" } +if ![info exists ADDR2LINE] then { + set ADDR2LINE [findfile $base_dir/addr2line $base_dir/addr2line [transform nm]] +} +if ![info exists ADDR2LINEFLAGS] then { + set ADDR2LINEFLAGS "" +} if ![info exists SIZE] then { set SIZE [findfile $base_dir/size] } -- 2.17.1