public inbox for elfutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] libdw: handle DW_FORM_indirect when reading attributes
@ 2021-04-23 23:36 Omar Sandoval
  2021-05-01 15:59 ` Mark Wielaard
  0 siblings, 1 reply; 6+ messages in thread
From: Omar Sandoval @ 2021-04-23 23:36 UTC (permalink / raw)
  To: elfutils-devel; +Cc: Jay Kamat

From: Omar Sandoval <osandov@fb.com>

Whenever we encounter an attribute with DW_FORM_indirect, we need to
read its true form from the DIE data. Then, we can continue normally.
This adds support to the most obvious places: __libdw_find_attr() and
dwarf_getattrs(). There may be more places that need to be updated.

I encountered this when inspecting a file that was processed by our BOLT
tool: https://github.com/facebookincubator/BOLT. This also adds a couple
of test cases using a file generated by that tool.

Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 libdw/ChangeLog                           |   5 +
 libdw/dwarf_child.c                       |  13 +
 libdw/dwarf_getattrs.c                    |  13 +
 tests/ChangeLog                           |  10 +
 tests/Makefile.am                         |   6 +-
 tests/run-low_high_pc-dw-form-indirect.sh |  23 +
 tests/run-readelf-dw-form-indirect.sh     | 678 ++++++++++++++++++++++
 tests/testfile-dw-form-indirect.bz2       | Bin 0 -> 7007 bytes
 8 files changed, 746 insertions(+), 2 deletions(-)
 create mode 100755 tests/run-low_high_pc-dw-form-indirect.sh
 create mode 100755 tests/run-readelf-dw-form-indirect.sh
 create mode 100755 tests/testfile-dw-form-indirect.bz2

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index f01bee39..e3e467ee 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,8 @@
+2021-04-23  Omar Sandoval  <osandov@fb.com>
+
+	* dwarf_child.c (__libdw_find_attr): Handle DW_FORM_indirect.
+	* dwarf_getattrs.c (dwarf_getattrs): Handle DW_FORM_indirect.
+
 2021-02-12  Mark Wielaard  <mark@klomp.org>
 
 	* dwarf_getlocation.c (attr_ok): For DWARF version 4 or higher
diff --git a/libdw/dwarf_child.c b/libdw/dwarf_child.c
index 2e39d834..c8c8bb61 100644
--- a/libdw/dwarf_child.c
+++ b/libdw/dwarf_child.c
@@ -53,6 +53,8 @@ __libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
       return NULL;
     }
 
+  const unsigned char *endp = die->cu->endp;
+
   /* Search the name attribute.  Attribute has been checked when
      Dwarf_Abbrev was created, we can read unchecked.  */
   const unsigned char *attrp = abbrevp->attrp;
@@ -69,6 +71,17 @@ __libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
       if (attr_name == 0 && attr_form == 0)
 	break;
 
+      if (attr_form == DW_FORM_indirect)
+	{
+	  get_uleb128 (attr_form, readp, endp);
+	  if (attr_form == DW_FORM_indirect ||
+	      attr_form == DW_FORM_implicit_const)
+	    {
+	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	      return NULL;
+	    }
+	}
+
       /* Is this the name attribute?  */
       if (attr_name == search_name && search_name != INVALID)
 	{
diff --git a/libdw/dwarf_getattrs.c b/libdw/dwarf_getattrs.c
index 4ac16b1a..770c32c9 100644
--- a/libdw/dwarf_getattrs.c
+++ b/libdw/dwarf_getattrs.c
@@ -55,6 +55,8 @@ dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *),
       return -1l;
     }
 
+  const unsigned char *endp = die->cu->endp;
+
   /* This is where the attributes start.  */
   const unsigned char *attrp = abbrevp->attrp;
   const unsigned char *const offset_attrp = abbrevp->attrp + offset;
@@ -78,6 +80,17 @@ dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *),
 	   offset of an attribute.  */
         return 1l;
 
+      if (attr.form == DW_FORM_indirect)
+	{
+	  get_uleb128 (attr.form, die_addr, endp);
+	  if (attr.form == DW_FORM_indirect ||
+	      attr.form == DW_FORM_implicit_const)
+	    {
+	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+	      return -1l;
+	    }
+	}
+
       /* If we are not to OFFSET_ATTRP yet, we just have to skip
 	 the values of the intervening attributes.  */
       if (remembered_attrp >= offset_attrp)
diff --git a/tests/ChangeLog b/tests/ChangeLog
index ea44d20c..cb22dfbb 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,13 @@
+2021-04-23  Omar Sandoval  <osandov@fb.com>
+
+	* run-low_high_pc-dw-form-indirect.sh: New file.
+	* run-readelf-dw-form-indirect.sh: New file.
+	* testfile-dw-form-indirect.bz2: New file.
+	* Makefile.am (TESTS): Add run-low_high_pc-dw-form-indirect.sh and
+	run-readelf-dw-form-indirect.sh.
+	(EXTRA_DIST): Add run-low_high_pc-dw-form-indirect.sh,
+	run-readelf-dw-form-indirect.sh, and testfile-dw-form-indirect.bz2.
+
 2021-03-30  Frank Ch. Eigler  <fche@redhat.com>
 
 	* run-debuginfod-find.sh: Add thread comm checks.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 852269a3..dc7517d9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -187,7 +187,8 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
 	run-getphdrnum.sh run-test-includes.sh \
 	leb128 read_unaligned \
 	msg_tst system-elf-libelf-test \
-	$(asm_TESTS) run-disasm-bpf.sh
+	$(asm_TESTS) run-disasm-bpf.sh run-low_high_pc-dw-form-indirect.sh \
+	run-readelf-dw-form-indirect.sh
 
 if !BIARCH
 export ELFUTILS_DISABLE_BIARCH = 1
@@ -507,7 +508,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
 	     run-pt_gnu_prop-tests.sh \
 	     testfile_pt_gnu_prop.bz2 testfile_pt_gnu_prop32.bz2 \
 	     run-getphdrnum.sh testfile-phdrs.elf.bz2 \
-	     run-test-includes.sh
+	     run-test-includes.sh run-low_high_pc-dw-form-indirect.sh \
+	     run-readelf-dw-form-indirect.sh testfile-dw-form-indirect.bz2
 
 
 if USE_VALGRIND
diff --git a/tests/run-low_high_pc-dw-form-indirect.sh b/tests/run-low_high_pc-dw-form-indirect.sh
new file mode 100755
index 00000000..6902982b
--- /dev/null
+++ b/tests/run-low_high_pc-dw-form-indirect.sh
@@ -0,0 +1,23 @@
+#! /bin/sh
+# Copyright (C) 2021 Facebook
+# This file is part of elfutils.
+#
+# This file 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.
+#
+# elfutils 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/>.
+
+. $srcdir/test-subr.sh
+
+# See run-readelf-dw-form-indirect
+testfiles testfile-dw-form-indirect
+
+testrun ${abs_builddir}/low_high_pc -e ./testfile-dw-form-indirect
diff --git a/tests/run-readelf-dw-form-indirect.sh b/tests/run-readelf-dw-form-indirect.sh
new file mode 100755
index 00000000..58838484
--- /dev/null
+++ b/tests/run-readelf-dw-form-indirect.sh
@@ -0,0 +1,678 @@
+#! /bin/sh
+# Copyright (C) 2021 Facebook
+# This file is part of elfutils.
+#
+# This file 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.
+#
+# elfutils 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/>.
+
+. $srcdir/test-subr.sh
+
+# // Program processed by https://github.com/facebookincubator/BOLT.
+# // gcc -g -O2 -fno-reorder-blocks-and-partition -Wl,--emit-relocs primes.c -o primes
+# // perf record -e cycles:u -j any,u -o perf.data -- ./primes 1000 > /dev/null
+# // perf2bolt -p perf.data -o perf.fdata ./primes
+# // llvm-bolt primes -o primes.bolt -data=perf.fdata -reorder-blocks=cache+ -reorder-functions=hfsort -split-functions=2 -split-all-cold -split-eh -dyno-stats -update-debug-sections
+#
+# #include <inttypes.h>
+# #include <stdbool.h>
+# #include <stdio.h>
+# #include <stdlib.h>
+# 
+# bool
+# is_prime (uint32_t n)
+# {
+#   if (n < 2)
+#     return false;
+#   if (n == 2)
+#     return true;
+#   if (n % 2 == 0)
+#     return false;
+#   for (uint32_t i = 3; i <= n / 2; i++)
+#     {
+#       if (n % i == 0)
+# 	return false;
+#     }
+#   return true;
+# }
+# 
+# int
+# main (int argc, char *argv[])
+# {
+#   if (argc != 2)
+#     return EXIT_FAILURE;
+#   int n = atoi (argv[1]);
+#   for (uint32_t i = 2; n > 0; i++)
+#     {
+#       if (is_prime (i))
+# 	{
+# 	  printf ("%" PRIu32 "\n", i);
+# 	  n--;
+# 	}
+#     }
+#   return EXIT_SUCCESS;
+# }
+testfiles testfile-dw-form-indirect
+
+testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=info testfile-dw-form-indirect << EOF
+
+DWARF section [33] '.debug_info' at offset 0x801db0:
+ [Offset]
+ Compilation unit at offset 0:
+ Version: 4, Abbreviation section offset: 0, Address size: 8, Offset size: 4
+ [     b]  compile_unit         abbrev: 1
+           producer             (strp) "GNU C17 8.4.1 20200928 (Red Hat 8.4.1-1) -mtune=generic -march=x86-64 -g -O2 -fno-reorder-blocks-and-partition"
+           language             (data1) C99 (12)
+           name                 (strp) "primes.c"
+           comp_dir             (strp) "/home/osandov/bolt"
+           ranges               (sec_offset) range list [    10]
+           low_pc               (addr) 000000000000000000
+           stmt_list            (sec_offset) 0
+ [    29]    base_type            abbrev: 2
+             byte_size            (data1) 1
+             encoding             (data1) unsigned_char (8)
+             name                 (strp) "unsigned char"
+ [    30]    base_type            abbrev: 2
+             byte_size            (data1) 2
+             encoding             (data1) unsigned (7)
+             name                 (strp) "short unsigned int"
+ [    37]    base_type            abbrev: 2
+             byte_size            (data1) 4
+             encoding             (data1) unsigned (7)
+             name                 (strp) "unsigned int"
+ [    3e]    base_type            abbrev: 2
+             byte_size            (data1) 8
+             encoding             (data1) unsigned (7)
+             name                 (strp) "long unsigned int"
+ [    45]    base_type            abbrev: 2
+             byte_size            (data1) 1
+             encoding             (data1) signed_char (6)
+             name                 (strp) "signed char"
+ [    4c]    base_type            abbrev: 2
+             byte_size            (data1) 2
+             encoding             (data1) signed (5)
+             name                 (strp) "short int"
+ [    53]    base_type            abbrev: 3
+             byte_size            (data1) 4
+             encoding             (data1) signed (5)
+             name                 (string) "int"
+ [    5a]    typedef              abbrev: 4
+             name                 (strp) "__uint32_t"
+             decl_file            (data1) types.h (3)
+             decl_line            (data1) 41
+             decl_column          (data1) 22
+             type                 (ref4) [    37]
+ [    66]    base_type            abbrev: 2
+             byte_size            (data1) 8
+             encoding             (data1) signed (5)
+             name                 (strp) "long int"
+ [    6d]    typedef              abbrev: 4
+             name                 (strp) "__off_t"
+             decl_file            (data1) types.h (3)
+             decl_line            (data1) 150
+             decl_column          (data1) 25
+             type                 (ref4) [    66]
+ [    79]    typedef              abbrev: 4
+             name                 (strp) "__off64_t"
+             decl_file            (data1) types.h (3)
+             decl_line            (data1) 151
+             decl_column          (data1) 27
+             type                 (ref4) [    66]
+ [    85]    pointer_type         abbrev: 5
+             byte_size            (data1) 8
+ [    87]    pointer_type         abbrev: 6
+             byte_size            (data1) 8
+             type                 (ref4) [    8d]
+ [    8d]    base_type            abbrev: 2
+             byte_size            (data1) 1
+             encoding             (data1) signed_char (6)
+             name                 (strp) "char"
+ [    94]    const_type           abbrev: 7
+             type                 (ref4) [    8d]
+ [    99]    typedef              abbrev: 4
+             name                 (strp) "uint32_t"
+             decl_file            (data1) stdint-uintn.h (4)
+             decl_line            (data1) 26
+             decl_column          (data1) 20
+             type                 (ref4) [    5a]
+ [    a5]    typedef              abbrev: 4
+             name                 (strp) "size_t"
+             decl_file            (data1) stddef.h (5)
+             decl_line            (data1) 216
+             decl_column          (data1) 23
+             type                 (ref4) [    3e]
+ [    b1]    structure_type       abbrev: 8
+             name                 (strp) "_IO_FILE"
+             byte_size            (data1) 216
+             decl_file            (data1) struct_FILE.h (6)
+             decl_line            (data1) 49
+             decl_column          (data1) 8
+             sibling              (ref4) [   238]
+ [    be]      member               abbrev: 9
+               name                 (strp) "_flags"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 51
+               decl_column          (data1) 7
+               type                 (ref4) [    53]
+               data_member_location (data1) 0
+ [    cb]      member               abbrev: 9
+               name                 (strp) "_IO_read_ptr"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 54
+               decl_column          (data1) 9
+               type                 (ref4) [    87]
+               data_member_location (data1) 8
+ [    d8]      member               abbrev: 9
+               name                 (strp) "_IO_read_end"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 55
+               decl_column          (data1) 9
+               type                 (ref4) [    87]
+               data_member_location (data1) 16
+ [    e5]      member               abbrev: 9
+               name                 (strp) "_IO_read_base"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 56
+               decl_column          (data1) 9
+               type                 (ref4) [    87]
+               data_member_location (data1) 24
+ [    f2]      member               abbrev: 9
+               name                 (strp) "_IO_write_base"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 57
+               decl_column          (data1) 9
+               type                 (ref4) [    87]
+               data_member_location (data1) 32
+ [    ff]      member               abbrev: 9
+               name                 (strp) "_IO_write_ptr"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 58
+               decl_column          (data1) 9
+               type                 (ref4) [    87]
+               data_member_location (data1) 40
+ [   10c]      member               abbrev: 9
+               name                 (strp) "_IO_write_end"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 59
+               decl_column          (data1) 9
+               type                 (ref4) [    87]
+               data_member_location (data1) 48
+ [   119]      member               abbrev: 9
+               name                 (strp) "_IO_buf_base"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 60
+               decl_column          (data1) 9
+               type                 (ref4) [    87]
+               data_member_location (data1) 56
+ [   126]      member               abbrev: 9
+               name                 (strp) "_IO_buf_end"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 61
+               decl_column          (data1) 9
+               type                 (ref4) [    87]
+               data_member_location (data1) 64
+ [   133]      member               abbrev: 9
+               name                 (strp) "_IO_save_base"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 64
+               decl_column          (data1) 9
+               type                 (ref4) [    87]
+               data_member_location (data1) 72
+ [   140]      member               abbrev: 9
+               name                 (strp) "_IO_backup_base"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 65
+               decl_column          (data1) 9
+               type                 (ref4) [    87]
+               data_member_location (data1) 80
+ [   14d]      member               abbrev: 9
+               name                 (strp) "_IO_save_end"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 66
+               decl_column          (data1) 9
+               type                 (ref4) [    87]
+               data_member_location (data1) 88
+ [   15a]      member               abbrev: 9
+               name                 (strp) "_markers"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 68
+               decl_column          (data1) 22
+               type                 (ref4) [   251]
+               data_member_location (data1) 96
+ [   167]      member               abbrev: 9
+               name                 (strp) "_chain"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 70
+               decl_column          (data1) 20
+               type                 (ref4) [   257]
+               data_member_location (data1) 104
+ [   174]      member               abbrev: 9
+               name                 (strp) "_fileno"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 72
+               decl_column          (data1) 7
+               type                 (ref4) [    53]
+               data_member_location (data1) 112
+ [   181]      member               abbrev: 9
+               name                 (strp) "_flags2"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 73
+               decl_column          (data1) 7
+               type                 (ref4) [    53]
+               data_member_location (data1) 116
+ [   18e]      member               abbrev: 9
+               name                 (strp) "_old_offset"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 74
+               decl_column          (data1) 11
+               type                 (ref4) [    6d]
+               data_member_location (data1) 120
+ [   19b]      member               abbrev: 9
+               name                 (strp) "_cur_column"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 77
+               decl_column          (data1) 18
+               type                 (ref4) [    30]
+               data_member_location (data1) 128
+ [   1a8]      member               abbrev: 9
+               name                 (strp) "_vtable_offset"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 78
+               decl_column          (data1) 15
+               type                 (ref4) [    45]
+               data_member_location (data1) 130
+ [   1b5]      member               abbrev: 9
+               name                 (strp) "_shortbuf"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 79
+               decl_column          (data1) 8
+               type                 (ref4) [   25d]
+               data_member_location (data1) 131
+ [   1c2]      member               abbrev: 9
+               name                 (strp) "_lock"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 81
+               decl_column          (data1) 15
+               type                 (ref4) [   26d]
+               data_member_location (data1) 136
+ [   1cf]      member               abbrev: 9
+               name                 (strp) "_offset"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 89
+               decl_column          (data1) 13
+               type                 (ref4) [    79]
+               data_member_location (data1) 144
+ [   1dc]      member               abbrev: 9
+               name                 (strp) "_codecvt"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 91
+               decl_column          (data1) 23
+               type                 (ref4) [   278]
+               data_member_location (data1) 152
+ [   1e9]      member               abbrev: 9
+               name                 (strp) "_wide_data"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 92
+               decl_column          (data1) 25
+               type                 (ref4) [   283]
+               data_member_location (data1) 160
+ [   1f6]      member               abbrev: 9
+               name                 (strp) "_freeres_list"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 93
+               decl_column          (data1) 20
+               type                 (ref4) [   257]
+               data_member_location (data1) 168
+ [   203]      member               abbrev: 9
+               name                 (strp) "_freeres_buf"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 94
+               decl_column          (data1) 9
+               type                 (ref4) [    85]
+               data_member_location (data1) 176
+ [   210]      member               abbrev: 9
+               name                 (strp) "__pad5"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 95
+               decl_column          (data1) 10
+               type                 (ref4) [    a5]
+               data_member_location (data1) 184
+ [   21d]      member               abbrev: 9
+               name                 (strp) "_mode"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 96
+               decl_column          (data1) 7
+               type                 (ref4) [    53]
+               data_member_location (data1) 192
+ [   22a]      member               abbrev: 9
+               name                 (strp) "_unused2"
+               decl_file            (data1) struct_FILE.h (6)
+               decl_line            (data1) 98
+               decl_column          (data1) 8
+               type                 (ref4) [   289]
+               data_member_location (data1) 196
+ [   238]    typedef              abbrev: 4
+             name                 (strp) "FILE"
+             decl_file            (data1) FILE.h (7)
+             decl_line            (data1) 7
+             decl_column          (data1) 25
+             type                 (ref4) [    b1]
+ [   244]    typedef              abbrev: 10
+             name                 (strp) "_IO_lock_t"
+             decl_file            (data1) struct_FILE.h (6)
+             decl_line            (data1) 43
+             decl_column          (data1) 14
+ [   24c]    structure_type       abbrev: 11
+             name                 (strp) "_IO_marker"
+             declaration          (flag_present) yes
+ [   251]    pointer_type         abbrev: 6
+             byte_size            (data1) 8
+             type                 (ref4) [   24c]
+ [   257]    pointer_type         abbrev: 6
+             byte_size            (data1) 8
+             type                 (ref4) [    b1]
+ [   25d]    array_type           abbrev: 12
+             type                 (ref4) [    8d]
+             sibling              (ref4) [   26d]
+ [   266]      subrange_type        abbrev: 13
+               type                 (ref4) [    3e]
+               upper_bound          (data1) 0
+ [   26d]    pointer_type         abbrev: 6
+             byte_size            (data1) 8
+             type                 (ref4) [   244]
+ [   273]    structure_type       abbrev: 11
+             name                 (strp) "_IO_codecvt"
+             declaration          (flag_present) yes
+ [   278]    pointer_type         abbrev: 6
+             byte_size            (data1) 8
+             type                 (ref4) [   273]
+ [   27e]    structure_type       abbrev: 11
+             name                 (strp) "_IO_wide_data"
+             declaration          (flag_present) yes
+ [   283]    pointer_type         abbrev: 6
+             byte_size            (data1) 8
+             type                 (ref4) [   27e]
+ [   289]    array_type           abbrev: 12
+             type                 (ref4) [    8d]
+             sibling              (ref4) [   299]
+ [   292]      subrange_type        abbrev: 13
+               type                 (ref4) [    3e]
+               upper_bound          (data1) 19
+ [   299]    variable             abbrev: 14
+             name                 (strp) "stdin"
+             decl_file            (data1) stdio.h (8)
+             decl_line            (data1) 137
+             decl_column          (data1) 14
+             type                 (ref4) [   2a5]
+             external             (flag_present) yes
+             declaration          (flag_present) yes
+ [   2a5]    pointer_type         abbrev: 6
+             byte_size            (data1) 8
+             type                 (ref4) [   238]
+ [   2ab]    variable             abbrev: 14
+             name                 (strp) "stdout"
+             decl_file            (data1) stdio.h (8)
+             decl_line            (data1) 138
+             decl_column          (data1) 14
+             type                 (ref4) [   2a5]
+             external             (flag_present) yes
+             declaration          (flag_present) yes
+ [   2b7]    variable             abbrev: 14
+             name                 (strp) "stderr"
+             decl_file            (data1) stdio.h (8)
+             decl_line            (data1) 139
+             decl_column          (data1) 14
+             type                 (ref4) [   2a5]
+             external             (flag_present) yes
+             declaration          (flag_present) yes
+ [   2c3]    variable             abbrev: 14
+             name                 (strp) "sys_nerr"
+             decl_file            (data1) sys_errlist.h (9)
+             decl_line            (data1) 26
+             decl_column          (data1) 12
+             type                 (ref4) [    53]
+             external             (flag_present) yes
+             declaration          (flag_present) yes
+ [   2cf]    array_type           abbrev: 12
+             type                 (ref4) [   2e5]
+             sibling              (ref4) [   2da]
+ [   2d8]      subrange_type        abbrev: 15
+ [   2da]    const_type           abbrev: 7
+             type                 (ref4) [   2cf]
+ [   2df]    pointer_type         abbrev: 6
+             byte_size            (data1) 8
+             type                 (ref4) [    94]
+ [   2e5]    const_type           abbrev: 7
+             type                 (ref4) [   2df]
+ [   2ea]    variable             abbrev: 14
+             name                 (strp) "sys_errlist"
+             decl_file            (data1) sys_errlist.h (9)
+             decl_line            (data1) 27
+             decl_column          (data1) 26
+             type                 (ref4) [   2da]
+             external             (flag_present) yes
+             declaration          (flag_present) yes
+ [   2f6]    base_type            abbrev: 2
+             byte_size            (data1) 8
+             encoding             (data1) signed (5)
+             name                 (strp) "long long int"
+ [   2fd]    base_type            abbrev: 2
+             byte_size            (data1) 8
+             encoding             (data1) unsigned (7)
+             name                 (strp) "long long unsigned int"
+ [   304]    subprogram           abbrev: 16
+             external             (flag_present) yes
+             name                 (strp) "main"
+             decl_file            (data1) primes.c (1)
+             decl_line            (data1) 24
+             decl_column          (data1) 1
+             prototyped           (flag_present) yes
+             type                 (ref4) [    53]
+             ranges               (sec_offset) range list [    50]
+             low_pc               (addr) 000000000000000000
+             frame_base           (exprloc) 
+              [ 0] call_frame_cfa
+             GNU_all_call_sites   (flag_present) yes
+             sibling              (ref4) [   429]
+ [   326]      formal_parameter     abbrev: 17
+               name                 (strp) "argc"
+               decl_file            (data1) primes.c (1)
+               decl_line            (data1) 24
+               decl_column          (data1) 11
+               type                 (ref4) [    53]
+               location             (sec_offset) location list [    10]
+               GNU_locviews         (sec_offset) location list [     0]
+ [   33a]      formal_parameter     abbrev: 17
+               name                 (strp) "argv"
+               decl_file            (data1) primes.c (1)
+               decl_line            (data1) 24
+               decl_column          (data1) 23
+               type                 (ref4) [   429]
+               location             (sec_offset) location list [    72]
+               GNU_locviews         (sec_offset) location list [    3d]
+ [   34e]      variable             abbrev: 18
+               name                 (string) "n"
+               decl_file            (data1) primes.c (1)
+               decl_line            (data1) 28
+               decl_column          (data1) 7
+               type                 (ref4) [    53]
+               location             (sec_offset) location list [    d4]
+               GNU_locviews         (sec_offset) location list [    7a]
+ [   360]      lexical_block        abbrev: 19
+               ranges               (sec_offset) range list [    80]
+               sibling              (ref4) [   3ed]
+ [   369]        variable             abbrev: 18
+                 name                 (string) "i"
+                 decl_file            (data1) primes.c (1)
+                 decl_line            (data1) 29
+                 decl_column          (data1) 17
+                 type                 (ref4) [    99]
+                 location             (sec_offset) location list [   158]
+                 GNU_locviews         (sec_offset) location list [    f5]
+ [   37b]        inlined_subroutine   abbrev: 20
+                 abstract_origin      (ref4) [   42f]
+                 entry_pc             (addr) 0x0000000000400520
+                 GNU_entry_view       (data1) 6
+                 ranges               (sec_offset) range list [    e0]
+                 call_file            (data1) primes.c (1)
+                 call_line            (data1) 31
+                 call_column          (data1) 11
+                 sibling              (ref4) [   3cb]
+ [   394]          formal_parameter     abbrev: 21
+                   abstract_origin      (ref4) [   440]
+                   location             (sec_offset) location list [   1dd]
+                   GNU_locviews         (sec_offset) location list [   186]
+ [   3a1]          inlined_subroutine   abbrev: 22
+                   abstract_origin      (ref4) [   42f]
+                   ranges               (sec_offset) range list [   120]
+                   call_file            (data1) primes.c (1)
+                   call_line            (data1) 7
+                   call_column          (data1) 1
+ [   3ad]            formal_parameter     abbrev: 23
+                     abstract_origin      (ref4) [   440]
+ [   3b2]            lexical_block        abbrev: 24
+                     abstract_origin      (ref4) [   44a]
+                     ranges               (sec_offset) range list [   120]
+ [   3bb]              variable             abbrev: 25
+                       abstract_origin      (ref4) [   44b]
+                       location             (sec_offset) location list [   250]
+                       GNU_locviews         (sec_offset) location list [   203]
+ [   3cb]        GNU_call_site        abbrev: 26
+                 low_pc               (addr) 0x0000000000a000c7 <.annobin_init.c.unlikely.cold.0+0x47>
+                 abstract_origin      (ref4) [   4e2]
+ [   3d8]          GNU_call_site_parameter abbrev: 27
+                   location             (exprloc) 
+                    [ 0] reg5
+                   GNU_call_site_value  (exprloc) 
+                    [ 0] addr 0x400788 <__dso_handle+0x8>
+ [   3e5]          GNU_call_site_parameter abbrev: 27
+                   location             (exprloc) 
+                    [ 0] reg4
+                   GNU_call_site_value  (exprloc) 
+                    [ 0] breg3 -1
+ [   3ed]      inlined_subroutine   abbrev: 28
+               abstract_origin      (ref4) [   45e]
+               entry_pc             (addr) 0x00000000004004fb
+               GNU_entry_view       (data1) 1
+               ranges               (sec_offset) range list [   150]
+               call_file            (data1) primes.c (1)
+               call_line            (data1) 28
+               call_column          (data1) 11
+ [   402]        formal_parameter     abbrev: 21
+                 abstract_origin      (ref4) [   470]
+                 location             (sec_offset) location list [   2ad]
+                 GNU_locviews         (sec_offset) location list [   268]
+ [   40f]        GNU_call_site        abbrev: 26
+                 low_pc               (addr) 0x0000000000a000a4 <.annobin_init.c.unlikely.cold.0+0x24>
+                 abstract_origin      (ref4) [   4ef]
+ [   41c]          GNU_call_site_parameter abbrev: 27
+                   location             (exprloc) 
+                    [ 0] reg4
+                   GNU_call_site_value  (exprloc) 
+                    [ 0] lit0
+ [   421]          GNU_call_site_parameter abbrev: 27
+                   location             (exprloc) 
+                    [ 0] reg1
+                   GNU_call_site_value  (exprloc) 
+                    [ 0] lit10
+ [   429]    pointer_type         abbrev: 6
+             byte_size            (data1) 8
+             type                 (ref4) [    87]
+ [   42f]    subprogram           abbrev: 29
+             external             (flag_present) yes
+             name                 (strp) "is_prime"
+             decl_file            (data1) primes.c (1)
+             decl_line            (data1) 7
+             decl_column          (data1) 1
+             prototyped           (flag_present) yes
+             type                 (ref4) [   457]
+             inline               (data1) inlined (1)
+             sibling              (ref4) [   457]
+ [   440]      formal_parameter     abbrev: 30
+               name                 (string) "n"
+               decl_file            (data1) primes.c (1)
+               decl_line            (data1) 7
+               decl_column          (data1) 20
+               type                 (ref4) [    99]
+ [   44a]      lexical_block        abbrev: 31
+ [   44b]        variable             abbrev: 32
+                 name                 (string) "i"
+                 decl_file            (data1) primes.c (1)
+                 decl_line            (data1) 15
+                 decl_column          (data1) 17
+                 type                 (ref4) [    99]
+ [   457]    base_type            abbrev: 2
+             byte_size            (data1) 1
+             encoding             (data1) boolean (2)
+             name                 (strp) "_Bool"
+ [   45e]    subprogram           abbrev: 33
+             external             (flag_present) yes
+             name                 (strp) "atoi"
+             decl_file            (data1) stdlib.h (2)
+             decl_line            (data2) 361
+             decl_column          (data1) 1
+             prototyped           (flag_present) yes
+             type                 (ref4) [    53]
+             inline               (data1) declared_inlined (3)
+             sibling              (ref4) [   47e]
+ [   470]      formal_parameter     abbrev: 34
+               name                 (strp) "__nptr"
+               decl_file            (data1) stdlib.h (2)
+               decl_line            (data2) 361
+               decl_column          (data1) 1
+               type                 (ref4) [   2df]
+ [   47e]    subprogram           abbrev: 35
+             abstract_origin      (ref4) [   42f]
+             low_pc               (addr) 0x0000000000400680 <is_prime>
+             high_pc              (data8) 101 (0x00000000004006e5)
+             frame_base           (exprloc) 
+              [ 0] call_frame_cfa
+             GNU_all_call_sites   (flag_present) yes
+             sibling              (ref4) [   4e2]
+ [   499]      formal_parameter     abbrev: 36
+               abstract_origin      (ref4) [   440]
+               location             (exprloc) 
+                [ 0] reg5
+ [   4a0]      inlined_subroutine   abbrev: 37
+               abstract_origin      (ref4) [   42f]
+               ranges               (sec_offset) range list [   1a0]
+               low_pc               (addr) 000000000000000000
+               call_file            (data1) primes.c (1)
+               call_line            (data1) 7
+               call_column          (data1) 1
+ [   4b8]        formal_parameter     abbrev: 23
+                 abstract_origin      (ref4) [   440]
+ [   4bd]        lexical_block        abbrev: 38
+                 abstract_origin      (ref4) [   44a]
+                 ranges               (sec_offset) range list [   1a0]
+                 low_pc               (addr) 000000000000000000
+ [   4d2]          variable             abbrev: 25
+                   abstract_origin      (ref4) [   44b]
+                   location             (sec_offset) location list [   2d1]
+                   GNU_locviews         (sec_offset) location list [   28e]
+ [   4e2]    subprogram           abbrev: 39
+             external             (flag_present) yes
+             declaration          (flag_present) yes
+             linkage_name         (strp) "printf"
+             name                 (strp) "printf"
+             decl_file            (data1) stdio.h (8)
+             decl_line            (data2) 332
+             decl_column          (data1) 12
+ [   4ef]    subprogram           abbrev: 40
+             external             (flag_present) yes
+             declaration          (flag_present) yes
+             linkage_name         (strp) "strtol"
+             name                 (strp) "strtol"
+             decl_file            (data1) stdlib.h (2)
+             decl_line            (data1) 176
+             decl_column          (data1) 17
+EOF
diff --git a/tests/testfile-dw-form-indirect.bz2 b/tests/testfile-dw-form-indirect.bz2
new file mode 100755
index 0000000000000000000000000000000000000000..e531c11d812bec9b246132e587e34607aa749ead
GIT binary patch
literal 7007
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

literal 0
HcmV?d00001

-- 
2.31.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] libdw: handle DW_FORM_indirect when reading attributes
  2021-04-23 23:36 [PATCH] libdw: handle DW_FORM_indirect when reading attributes Omar Sandoval
@ 2021-05-01 15:59 ` Mark Wielaard
  2021-05-01 16:03   ` Mark Wielaard
  2021-05-04 21:17   ` Omar Sandoval
  0 siblings, 2 replies; 6+ messages in thread
From: Mark Wielaard @ 2021-05-01 15:59 UTC (permalink / raw)
  To: Omar Sandoval, elfutils-devel; +Cc: Jay Kamat

Hi Omar,

On Fri, 2021-04-23 at 16:36 -0700, Omar Sandoval wrote:
> Whenever we encounter an attribute with DW_FORM_indirect, we need to
> read its true form from the DIE data. Then, we can continue normally.
> This adds support to the most obvious places: __libdw_find_attr() and
> dwarf_getattrs().

Very nice. I wasn't aware anybody actually used DW_FORM_indirect.

In your patch you only handle one indirection. I think that in theory a
DW_FORM_indirect could be an DW_FORM_indirect itself (but now in the
DIE instead of the Abbrev). But this is probably silly, so not
supporting that seems correct. Same for an indirect
DW_FORM_implicit_const. It doesn't really make sense to do that because
if you wanted to put the value in the DIE instead of an Abbrev you
would have used an actual FORM that did that.

> There may be more places that need to be updated.

There is __libdw_form_val_compute_len which already handles
DW_FORM_indirect:

    case DW_FORM_indirect:
      get_uleb128 (u128, valp, endp);
      // XXX Is this really correct?
      result = __libdw_form_val_len (cu, u128, valp);
      if (result != (size_t) -1)
        result += valp - startp;
      else
        return (size_t) -1;
      break;

I believe the XXX question can be answered with: Yes, the result is the
size of the actual FORM data plus the size of the uleb128 encoding that
FORM (which is valp - startp). And it probably should check like your
code does that valp != DW_FORM_indirect && valp !=
DW_FORM_implicit_const. I'll sent a patch to do that.

But, now that dwarf_child and dwarf_getattrs handle DW_FORM_indirectly
directly (haha, pun intended) I think __libdw_form_val_compute_len is
never called for DW_FORM_indirect anymore.

There is dwarf_hasattr, but that doesn't care about the value, just the
attribute name, so it doesn't have to follow any DW_FORM_indirect.

And there are the "raw" dwarf_getabbrev functions, but those aren't
associated with any DIE/.debug_info data, so leaving DW_FORM_indirect
as is in the Dwarf_Abbrev for those seems correct.

> I encountered this when inspecting a file that was processed by our BOLT
> tool: https://github.com/facebookincubator/BOLT. This also adds a couple
> of test cases using a file generated by that tool.

Thanks for that test case. It really helps seeing an actual example of
indirection. I note that all Abbrevs/DIEs using DW_FORM_indirect are
for DW_AT_low_pc and that the indirect DW_AT_addr are all the zero
address. Is that intended?

Pushed you patch.

Thanks,

Mark

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] libdw: handle DW_FORM_indirect when reading attributes
  2021-05-01 15:59 ` Mark Wielaard
@ 2021-05-01 16:03   ` Mark Wielaard
  2021-05-04 21:18     ` Omar Sandoval
  2021-05-04 21:17   ` Omar Sandoval
  1 sibling, 1 reply; 6+ messages in thread
From: Mark Wielaard @ 2021-05-01 16:03 UTC (permalink / raw)
  To: Omar Sandoval, elfutils-devel; +Cc: Jay Kamat

[-- Attachment #1: Type: text/plain, Size: 829 bytes --]

Hi,

On Sat, 2021-05-01 at 17:59 +0200, Mark Wielaard wrote:
> There is __libdw_form_val_compute_len which already handles
> DW_FORM_indirect:
> 
>     case DW_FORM_indirect:
>       get_uleb128 (u128, valp, endp);
>       // XXX Is this really correct?
>       result = __libdw_form_val_len (cu, u128, valp);
>       if (result != (size_t) -1)
>         result += valp - startp;
>       else
>         return (size_t) -1;
>       break;
> 
> I believe the XXX question can be answered with: Yes, the result is the
> size of the actual FORM data plus the size of the uleb128 encoding that
> FORM (which is valp - startp). And it probably should check like your
> code does that valp != DW_FORM_indirect && valp !=
> DW_FORM_implicit_const. I'll sent a patch to do that.

Patch attached.

Cheers,

Mark

[-- Attachment #2: 0001-libdw-Document-and-handle-DW_FORM_indirect-in-__libd.patch --]
[-- Type: text/x-patch, Size: 1770 bytes --]

From 73d0a32b44aa9bc641f0d5f0d79ee626d1ad2e4a Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mark@klomp.org>
Date: Sat, 1 May 2021 18:00:49 +0200
Subject: [PATCH] libdw: Document and handle DW_FORM_indirect in
 __libdw_form_val_compute_len

Update the documentation in __libdw_form_val_compute_len for handling
DW_FORM_indirect and make sure the indirect form isn't DW_FORM_indirect
itself or DW_FORM_implicit_const.

Signed-off-by: Mark Wielaard <mark@klomp.org>
---
 libdw/ChangeLog    | 5 +++++
 libdw/libdw_form.c | 6 +++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index e3e467ee..aa3e5ee2 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,8 @@
+2021-05-01  Mark Wielaard  <mark@klomp.org>
+
+	* libdw_form.c (__libdw_form_val_compute_len): Check indirect
+	form is not DW_FORM_indirect or DW_FORM_implicit_const.
+
 2021-04-23  Omar Sandoval  <osandov@fb.com>
 
 	* dwarf_child.c (__libdw_find_attr): Handle DW_FORM_indirect.
diff --git a/libdw/libdw_form.c b/libdw/libdw_form.c
index 584c8467..c83dfb39 100644
--- a/libdw/libdw_form.c
+++ b/libdw/libdw_form.c
@@ -116,8 +116,12 @@ __libdw_form_val_compute_len (struct Dwarf_CU *cu, unsigned int form,
       break;
 
     case DW_FORM_indirect:
+      /* The amount of data to skip in the DIE is the size of the actual
+	 FORM data (which is __libdw_form_val_len) plus the size of the
+	 uleb128 encoding that FORM (which is valp - startp).  */
       get_uleb128 (u128, valp, endp);
-      // XXX Is this really correct?
+      if (*valp == DW_FORM_indirect || *valp == DW_FORM_implicit_const)
+	return (size_t) -1;
       result = __libdw_form_val_len (cu, u128, valp);
       if (result != (size_t) -1)
 	result += valp - startp;
-- 
2.18.4


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] libdw: handle DW_FORM_indirect when reading attributes
  2021-05-01 15:59 ` Mark Wielaard
  2021-05-01 16:03   ` Mark Wielaard
@ 2021-05-04 21:17   ` Omar Sandoval
  1 sibling, 0 replies; 6+ messages in thread
From: Omar Sandoval @ 2021-05-04 21:17 UTC (permalink / raw)
  To: Mark Wielaard; +Cc: elfutils-devel, Jay Kamat

On Sat, May 01, 2021 at 05:59:31PM +0200, Mark Wielaard wrote:
> Hi Omar,
> 
> On Fri, 2021-04-23 at 16:36 -0700, Omar Sandoval wrote:
> > Whenever we encounter an attribute with DW_FORM_indirect, we need to
> > read its true form from the DIE data. Then, we can continue normally.
> > This adds support to the most obvious places: __libdw_find_attr() and
> > dwarf_getattrs().
> 
> Very nice. I wasn't aware anybody actually used DW_FORM_indirect.
> 
> In your patch you only handle one indirection. I think that in theory a
> DW_FORM_indirect could be an DW_FORM_indirect itself (but now in the
> DIE instead of the Abbrev). But this is probably silly, so not
> supporting that seems correct. Same for an indirect
> DW_FORM_implicit_const. It doesn't really make sense to do that because
> if you wanted to put the value in the DIE instead of an Abbrev you
> would have used an actual FORM that did that.
> 
> > There may be more places that need to be updated.
> 
> There is __libdw_form_val_compute_len which already handles
> DW_FORM_indirect:
> 
>     case DW_FORM_indirect:
>       get_uleb128 (u128, valp, endp);
>       // XXX Is this really correct?
>       result = __libdw_form_val_len (cu, u128, valp);
>       if (result != (size_t) -1)
>         result += valp - startp;
>       else
>         return (size_t) -1;
>       break;
> 
> I believe the XXX question can be answered with: Yes, the result is the
> size of the actual FORM data plus the size of the uleb128 encoding that
> FORM (which is valp - startp). And it probably should check like your
> code does that valp != DW_FORM_indirect && valp !=
> DW_FORM_implicit_const. I'll sent a patch to do that.
> 
> But, now that dwarf_child and dwarf_getattrs handle DW_FORM_indirectly
> directly (haha, pun intended) I think __libdw_form_val_compute_len is
> never called for DW_FORM_indirect anymore.
> 
> There is dwarf_hasattr, but that doesn't care about the value, just the
> attribute name, so it doesn't have to follow any DW_FORM_indirect.
> 
> And there are the "raw" dwarf_getabbrev functions, but those aren't
> associated with any DIE/.debug_info data, so leaving DW_FORM_indirect
> as is in the Dwarf_Abbrev for those seems correct.
> 
> > I encountered this when inspecting a file that was processed by our BOLT
> > tool: https://github.com/facebookincubator/BOLT. This also adds a couple
> > of test cases using a file generated by that tool.
> 
> Thanks for that test case. It really helps seeing an actual example of
> indirection. I note that all Abbrevs/DIEs using DW_FORM_indirect are
> for DW_AT_low_pc and that the indirect DW_AT_addr are all the zero
> address. Is that intended?

From manually inspecting the debug information, I believe this is
correct. Looking into it more, BOLT uses DW_FORM_indirect for silly
reasons. Something to do with using it to pad out values in place so
that .debug_abbrev and .debug_info don't need to be rewritten entirely
in the patched binary.

> Pushed you patch.

Thank you!

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] libdw: handle DW_FORM_indirect when reading attributes
  2021-05-01 16:03   ` Mark Wielaard
@ 2021-05-04 21:18     ` Omar Sandoval
  2021-05-06 21:16       ` Mark Wielaard
  0 siblings, 1 reply; 6+ messages in thread
From: Omar Sandoval @ 2021-05-04 21:18 UTC (permalink / raw)
  To: Mark Wielaard; +Cc: elfutils-devel, Jay Kamat

On Sat, May 01, 2021 at 06:03:37PM +0200, Mark Wielaard wrote:
> Hi,
> 
> On Sat, 2021-05-01 at 17:59 +0200, Mark Wielaard wrote:
> > There is __libdw_form_val_compute_len which already handles
> > DW_FORM_indirect:
> > 
> >     case DW_FORM_indirect:
> >       get_uleb128 (u128, valp, endp);
> >       // XXX Is this really correct?
> >       result = __libdw_form_val_len (cu, u128, valp);
> >       if (result != (size_t) -1)
> >         result += valp - startp;
> >       else
> >         return (size_t) -1;
> >       break;
> > 
> > I believe the XXX question can be answered with: Yes, the result is the
> > size of the actual FORM data plus the size of the uleb128 encoding that
> > FORM (which is valp - startp). And it probably should check like your
> > code does that valp != DW_FORM_indirect && valp !=
> > DW_FORM_implicit_const. I'll sent a patch to do that.
> 
> Patch attached.

The patch looks reasonable to me, Mark, thanks.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] libdw: handle DW_FORM_indirect when reading attributes
  2021-05-04 21:18     ` Omar Sandoval
@ 2021-05-06 21:16       ` Mark Wielaard
  0 siblings, 0 replies; 6+ messages in thread
From: Mark Wielaard @ 2021-05-06 21:16 UTC (permalink / raw)
  To: Omar Sandoval; +Cc: Jay Kamat, elfutils-devel

Hi Omar,

On Tue, May 04, 2021 at 02:18:45PM -0700, Omar Sandoval wrote:
> On Sat, May 01, 2021 at 06:03:37PM +0200, Mark Wielaard wrote:
> > On Sat, 2021-05-01 at 17:59 +0200, Mark Wielaard wrote:
> > > There is __libdw_form_val_compute_len which already handles
> > > DW_FORM_indirect:
> > > 
> > >     case DW_FORM_indirect:
> > >       get_uleb128 (u128, valp, endp);
> > >       // XXX Is this really correct?
> > >       result = __libdw_form_val_len (cu, u128, valp);
> > >       if (result != (size_t) -1)
> > >         result += valp - startp;
> > >       else
> > >         return (size_t) -1;
> > >       break;
> > > 
> > > I believe the XXX question can be answered with: Yes, the result is the
> > > size of the actual FORM data plus the size of the uleb128 encoding that
> > > FORM (which is valp - startp). And it probably should check like your
> > > code does that valp != DW_FORM_indirect && valp !=
> > > DW_FORM_implicit_const. I'll sent a patch to do that.
> > 
> > Patch attached.
> 
> The patch looks reasonable to me, Mark, thanks.

Thanks, pushed.

Cheers,

Mark

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-05-06 21:18 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-23 23:36 [PATCH] libdw: handle DW_FORM_indirect when reading attributes Omar Sandoval
2021-05-01 15:59 ` Mark Wielaard
2021-05-01 16:03   ` Mark Wielaard
2021-05-04 21:18     ` Omar Sandoval
2021-05-06 21:16       ` Mark Wielaard
2021-05-04 21:17   ` Omar Sandoval

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).