davea42 / libdwarf-code

Contains source for libdwarf, a library for reading DWARF2 and later DWARF. Contains source to create dwarfdump, a program which prints DWARF2 and later DWARF in readable format. Has a very limited DWARF writer set of functions in libdwarfp (producer library). Builds using GNU configure, meson, or cmake.
Other
170 stars 70 forks source link

dwarf_lowpc returns no entry on a die with a DW_AT_low_pc #245

Closed jeremy-rifkin closed 4 months ago

jeremy-rifkin commented 5 months ago

I'm running into an odd issue where dwarf_lowpc is returning DW_DLV_NO_ENTRY on a die that has a DW_AT_low_pc attribute:

0x00022223:   DW_TAG_subprogram
                DW_AT_specification (0x0001a3be "_ZN8cpptrace14generate_traceEmm")
                DW_AT_low_pc    (indexed (000001ba) address = <unresolved>)
                DW_AT_high_pc   (0x0000000000000235)
                DW_AT_frame_base    (DW_OP_call_frame_cfa)
                DW_AT_call_all_tail_calls   (true)
                DW_AT_sibling   (0x000222b4)

For additional context, I'm working with split dwarf objects and this die is located in a .dwo file but I have tied with the appropriate executable/.so debug. The .dwo is cpptrace.cpp.dwo and the .so is libcpptrace.so which references the .dwo as

0x0000013a: DW_TAG_skeleton_unit
              DW_AT_ranges      (0x000009b6
                        ...
              DW_AT_low_pc      (0x0000000000000000)
              DW_AT_stmt_list   (0x0000a98b)
              DW_AT_dwo_name    ("CMakeFiles/cpptrace-lib.dir/src/cpptrace.cpp.dwo")
              DW_AT_comp_dir    ("/path/to/cpptrace/build")
              DW_AT_GNU_pubnames        (true)
              DW_AT_addr_base   (0x00001f98)

I haven't had this issue for a couple other cases of working with dies in .dwo files. I can try to provide additional information as needed.

davea42 commented 5 months ago

Please redo the output with dwarfdump -i -M -G -vv --tied-file=<skelname> dwoname

(focusing on the two TAGs above as you show above). Lets see what dwarfdump says about those two DIEs.

jeremy-rifkin commented 5 months ago

Thanks Dave, I got 522 errors along the lines of NO ENTRY: DW_FORM_addrx is a DW_DLV_NO_ENTRY? something is wrong.:.

< 1><0x00022223 GOFF=0x00022223>    DW_TAG_subprogram <abbrev 25 ABGOFF = 0x00000175 count = 0x00000006>
                                      DW_AT_specification         <0x0001a3be GOFF=0x0001a3be> <form DW_FORM_ref4 19>

dwarfdump NO ENTRY:  DW_FORM_addrx is a DW_DLV_NO_ENTRY? something is wrong.:

CU Name = (indexed string: 0x000001bc)/path/to/src/cpptrace.cpp
CU Producer = (indexed string: 0x00000f1a)GNU C++17 13.2.0 -mtune=generic -march=x86-64 -gsplit-dwarf -gdwarf-5 -g -fPIC -fvisibility=hidden -fvisibility-inlines-hidden -fasynchronous-unwind-tables -fstack-protector-strong -fstack-clash-protection -fcf-protection
DIE OFF = 0x00022223 GOFF = 0x00022223, Low PC = unknown   , High PC = unknown
DW_AT_low_pc
                                      DW_AT_high_pc               <offset-from-lowpc> 565 <form DW_FORM_data8 7>
                                      DW_AT_frame_base            len 0x0001: 0x9c:  <form DW_FORM_exprloc 24>
                                          DW_OP_call_frame_cfa
                                      DW_AT_call_all_tail_calls   yes(1) <form DW_FORM_flag_present 25>
                                      DW_AT_sibling               <0x000222b4 GOFF=0x000222b4> <form DW_FORM_ref4 19>

Here is the .so and .dwo file in case it may be of help cpptrace-so-and-dwo.zip

davea42 commented 5 months ago

There was a recent bug in gcc that gdb folks are working around related to this, but I cannot find it just now.

Problem is in (print_die.c line 9098)

dwarfdump calls
    dwarf_formaddr() (print_die.c line 9098)
    _dwarf_look_in_local_and_tied()
       _dwarf_get_addr_index_itself()
       _dwarf_look_in_local_and_tied_by_index

So var I have not been able to figure out where DW_DLV_NO_ENTRY might be returned from libdwarf. in this sequence of calls.

Given you have the objects, try setting a breakpoint on _dwarf_look_in_local_and_tied() and step-over and check the result for DW_DLV_ERROR (1). In case of DW_DLV_NO_ENTRY there is no specific function to put a breakpoint on for that.

davea42 commented 5 months ago

Is this dWARF4 or 5?

Ah. _dwarf_get_addr_from_tied() in dwarf_query.c: if (!context->cc_addr_base_present) { / Does not exist. / return DW_DLV_NO_ENTRY; } might not be correct for DWARF4. Hmm.

But if not present the next call, _dwarf_search_for_signature() would work? or Not? and the latter too could return dW_DLV_NO_ENTRY.

Hmm Lots of related data needed and I would have to see what gcc did in Dwarf, both the object (dwo?) and the tied skeleton.

davea42 commented 5 months ago

So. Find the first failure.

From the dwarfdump output ( -i -M -G -vv) of the dwo show the CU-die of the failure. And for the skeleton CU that belongs to the dwo CU.

And the DIE (TAG Attrs) for the failure (dwo) and in the skeleton.

So four DIEswith attributes and FORMs from dwarfdump. Children DIEs of these are of no interest.

That will help me. It is possibly all I need to know. I see where the DW_DLV_NO_ENTRY is coming from. Your data will tell me what gcc is doing so I can fix libdwarf.

jeremy-rifkin commented 5 months ago

Thanks Dave, this one is dwarf 5.

I have built dwarfdump locally at commit a54dbb55b436978efc87f854560d2d2253d79e42. Debugging locally:

The CU-die of the failure (in the dwo):

Section Groups data
  Number of Elf-like sections:   10
  Number of groups           :    1
  Group to print             :    2
  Count of map entries       :    6
  [index]  group section
  [    0]    2     1 .debug_info.dwo
  [    1]    2     2 .debug_abbrev.dwo
  [    2]    2     3 .debug_rnglists.dwo
  [    3]    2     4 .debug_line.dwo
  [    4]    2     5 .debug_str_offsets.dwo
  [    5]    2     6 .debug_str.dwo

.debug_info.dwo

CU_HEADER:
  cu_header_length = 0x00023bd9 146393
  version_stamp    = 0x0005     5
  abbrev_offset    = 0x00000000 0
  address_size     = 0x08       8
  offset_size      = 0x04       4
  cu_type          = 0x05       DW_UT_split_compile
  signature        = 0x10ec1965cadc101e
  typeoffset       = 0x00000000 0

COMPILE_UNIT<header overall offset = 0x00000000>:
< 0><0x00000014 GOFF=0x00000014>  DW_TAG_compile_unit <abbrev 208 ABGOFF = 0x00000f5d count = 0x00000004>
                                    DW_AT_producer              (indexed string: 0x00000f1a)GNU C++17 13.2.0 -mtune=generic -march=x86-64 -gsplit-dwarf -gdwarf-5 -g -fPIC -fvisibility=hidden -fvisibility-inlines-hidden -fasynchronous-unwind-tables -fstack-protector-strong -fstack-clash-protection -fcf-protection <form DW_FORM_strx 26>
                                    DW_AT_language              DW_LANG_C_plus_plus_14 <form DW_FORM_data1 11>
                                    DW_AT_name                  (indexed string: 0x000001bc)/mnt/c/Users/rifkin/home/projects/cpptrace/src/cpptrace.cpp <form DW_FORM_strx 26>
                                    DW_AT_comp_dir              (indexed string: 0x00000771)/mnt/c/Users/rifkin/home/projects/cpptrace/build <form DW_FORM_strx 26>

The skeleton CU:

CU_HEADER:
  cu_header_length = 0x0000002d 45
  version_stamp    = 0x0005     5
  abbrev_offset    = 0x0000007e 126
  address_size     = 0x08       8
  offset_size      = 0x04       4
  cu_type          = 0x04       DW_UT_skeleton
  signature        = 0x10ec1965cadc101e
  typeoffset       = 0x00000000 0

COMPILE_UNIT<header overall offset = 0x00000126>:
< 0><0x00000014 GOFF=0x0000013a>  DW_TAG_skeleton_unit <abbrev 1 ABGOFF = 0x0000007e count = 0x00000007>
                                    DW_AT_ranges                0x000009b6 <form DW_FORM_sec_offset 23>

      Offset of rnglists entries: 0x000009b6
      Index of rnglist head     : 6
      rnglist head version      : 5
      Record count rnglist set  : 293
      Bytes this rnglist set    : 1153
      offset size               : 4
      address size              : 8
      CU DW_AT_low_pc (baseaddr): 0x00000000
      CU DW_AT_addr_base        : 0x00001f98
      section offset CU rnglists: 0x000009aa
      section length CU rnglists: 0x0000048d (1165)
                                                       secoff
      [ 0] DW_RLE_startx_length  0x0000010c 0x00003511 0x000009b6
      [ 0] start,end             0x00028d56 0x0002c267 0x000009b6
      [ 1] DW_RLE_startx_length  0x000001de 0x0000000f 0x000009bb
      [ 1] start,end             0x0001d463 0x0001d472 0x000009bb
...
      [291] DW_RLE_startx_length  0x00000152 0x0000002f 0x00000e32
      [291] start,end             0x000310aa 0x000310d9 0x00000e32
      [292] DW_RLE_end_of_list                          0x00000e36
      [292] end of list                                 0x00000e36
                                    DW_AT_low_pc                0x00000000 <form DW_FORM_addr 1>
                                    DW_AT_stmt_list             0x0000a98b <form DW_FORM_sec_offset 23>
                                    DW_AT_dwo_name              CMakeFiles/cpptrace-lib.dir/src/cpptrace.cpp.dwo <form DW_FORM_strp 14>
                                    DW_AT_comp_dir              /mnt/c/Users/rifkin/home/projects/cpptrace/build <form DW_FORM_strp 14>
                                    DW_AT_GNU_pubnames          yes(1) <form DW_FORM_flag_present 25>
                                    DW_AT_addr_base             0x00001f98 <form DW_FORM_sec_offset 23>

The subprogram DIE that lead to the first failure:

< 1><0x0001bdbf GOFF=0x0001bdbf>    DW_TAG_subprogram <abbrev 263 ABGOFF = 0x00001350 count = 0x00000006>
                                      DW_AT_name                  (indexed string: 0x0000048c)_GLOBAL__sub_I_cpptrace.cpp <form DW_FORM_strx 26>
                                      DW_AT_artificial            yes(1) <form DW_FORM_flag_present 25>

/mnt/c/Users/rifkin/home/projects/open-source/libdwarf-code/build/src/bin/dwarfdump/dwarfdump NO ENTRY:  DW_FORM_addrx is a DW_DLV_NO_ENTRY? something is wrong.: 

CU Name = (indexed string: 0x000001bc)/mnt/c/Users/rifkin/home/projects/cpptrace/src/cpptrace.cpp
CU Producer = (indexed string: 0x00000f1a)GNU C++17 13.2.0 -mtune=generic -march=x86-64 -gsplit-dwarf -gdwarf-5 -g -fPIC -fvisibility=hidden -fvisibility-inlines-hidden -fasynchronous-unwind-tables -fstack-protector-strong -fstack-clash-protection -fcf-protection
DIE OFF = 0x0001bdbf GOFF = 0x0001bdbf, Low PC = unknown   , High PC = unknown   
DW_AT_low_pc                
                                      DW_AT_high_pc               <offset-from-lowpc> 15 <form DW_FORM_data8 7>
                                      DW_AT_frame_base            len 0x0001: 0x9c:  <form DW_FORM_exprloc 24>
                                          DW_OP_call_frame_cfa
                                      DW_AT_call_all_tail_calls   yes(1) <form DW_FORM_flag_present 25>

I also included a zip of the objects in my earlier comment if it would be helpful to look at them directly.

davea42 commented 5 months ago

OK. Found the latest attachment, downloaded. Problem reproduced. Thanks. Looking now.

davea42 commented 5 months ago

Picking up signatures in dwarf_tied.c: the stopping condition of the loop accessing CU signatures was coded incorrectly. Stopped too soon. A problem with RNGLISTS remains.

davea42 commented 5 months ago

Here is the change to dwarf_tied.c. Not yet committed .

diff --git a/src/lib/libdwarf/dwarf_tied.c b/src/lib/libdwarf/dwarf_tied.c
index 074623ea..e9921b2e 100644
--- a/src/lib/libdwarf/dwarf_tied.c
+++ b/src/lib/libdwarf/dwarf_tied.c
@@ -49,6 +49,7 @@
 #include "dwarf_tsearch.h"
 #include "dwarf_tied_decls.h"

+#if 0
 void
 _dwarf_dumpsig(const char *msg, Dwarf_Sig8 *sig,int lineno)
 {
@@ -62,6 +63,7 @@ _dwarf_dumpsig(const char *msg, Dwarf_Sig8 *sig,int lineno)
     }
     printf(" line %d\n",lineno);
 }
+#endif

 void *
 _dwarf_tied_make_entry(Dwarf_Sig8 *key, Dwarf_CU_Context val)
@@ -129,6 +131,7 @@ _dwarf_tied_destroy_free_node(void*nodep)
 static int
 _dwarf_loop_reading_debug_info_for_cu(
     Dwarf_Debug tieddbg,
+    struct Dwarf_Tied_Entry_s *targsig,
     Dwarf_Error *error)
 {
     /*  We will not find tied signatures
@@ -207,11 +210,17 @@ _dwarf_loop_reading_debug_info_for_cu(
                     *(struct Dwarf_Tied_Data_s**) retval;
                 if (retent == entry) {
                     /*  we added a record. */
-                    return DW_DLV_OK;
+                    int res = _dwarf_tied_compare_function(
+                        targsig,entry);
+                    if (!res) {
+                         /* Found match,  stop looping */
+                         return DW_DLV_OK;
+                    }
+                    continue;
                 } else {
                     /*  found existing, no add */
                     free(entry);
-                    return DW_DLV_OK;
+                    continue;
                 }
             }
         }
@@ -253,14 +262,14 @@ _dwarf_search_for_signature(Dwarf_Debug tieddbg,
         *context_out = e2->dt_context;
         return DW_DLV_OK;
     }
-
     /*  We now ensure all tieddbg CUs signatures
         are in the td_tied_search,
         The caller is NOT doing
         info section read operations
         on the tieddbg in this (tied)dbg, so it
         cannot goof up their _dwarf_next_cu_header*().  */
-    res  = _dwarf_loop_reading_debug_info_for_cu(tieddbg,error);
+    res  = _dwarf_loop_reading_debug_info_for_cu(tieddbg,&entry,
+        error);
     if (res == DW_DLV_ERROR) {
         return res;
     }
davea42 commented 5 months ago

DWARF 5 in Table F.1 omitted mentions where to put DW_AT_rnglists_base and/or DW_AT_loclists_base in a CU DIE. And that attribute is missing from the skeleton data. However, there is sufficient data (already being read in) to calculate what the value of such a base would be. dwarfdump -i -vv prints it all out!

regression tests pass with the update posted above, committed and pushed to github. the rnglists/loclists issue remains, and will be dealt with next (not today, sorry).

jeremy-rifkin commented 5 months ago

Thanks so much for all the help with supporting this! I appreciate it immensely.

davea42 commented 4 months ago

Pushed these and other fixes to .debug_rnglists and .debug_loclists. Dwarfdump does a more useful job of reporting those sections now.

davea42 commented 4 months ago

This is fixed. Closing.

jeremy-rifkin commented 4 months ago

Thank you so much!