readelf: print split CUs when given --debug-dump=info+
authorMark Wielaard <mark@klomp.org>
Fri, 19 Jan 2018 14:45:16 +0000 (15:45 +0100)
committerMark Wielaard <mark@klomp.org>
Thu, 24 May 2018 15:37:00 +0000 (17:37 +0200)
To show the difference between "regular" CUs and split CUs print
offsets and references between { and } instead of [ and ].

When --debug-dump=info+ is given (implied by -w) instead of
--debug-dump=info any skeleton unit will be immediately followed
by the corresponding split compile unit (from the .dwo file).

DWARF section [27] '.debug_info' at offset 0x1075:
 [Offset]
 Compilation unit at offset 0:
 Version: 4, Abbreviation section offset: 0, Address size: 8, Offset size: 4
 Unit type: skeleton (4), Unit id: 0xc152129eb4b99599
 [     b]  compile_unit         abbrev: 1
           ranges               (sec_offset) range list [     0]
           low_pc               (addr) +000000000000000000
           stmt_list            (sec_offset) 0
           GNU_dwo_name         (strp) "foo.dwo"
           comp_dir             (strp) "/tmp"
           GNU_pubnames         (flag_present) yes
           GNU_addr_base        (sec_offset) 0
           GNU_dwo_id           (data8) 0xc152129eb4b99599
           GNU_ranges_base      (sec_offset) 0
 Split compilation unit at offset 0:
 Version: 4, Abbreviation section offset: 0, Address size: 8, Offset size: 4
 Unit type: skeleton (4), Unit id: 0xc152129eb4b99599
 {     b}  compile_unit         abbrev: 1
           producer             (GNU_str_index) "GNU C11 7.3.0 -gsplit-dwarf -g"
           language             (data1) C99 (12)
           name                 (GNU_str_index) "foo.c"
           comp_dir             (GNU_str_index) "/tmp"
           GNU_dwo_id           (data8) 0xc152129eb4b99599
 {    18}    subprogram           abbrev: 2
             external             (flag_present) yes
             name                 (GNU_str_index) "main"
             decl_file            (data1) foo.c (1)
             decl_line            (data1) 1
             type                 (ref4) {    2b}
             high_pc              (data8) 3
             frame_base           (exprloc)
              [ 0] call_frame_cfa
             GNU_all_call_sites   (flag_present) yes
 {    2b}    base_type            abbrev: 3
             byte_size            (data1) 4
             encoding             (data1) signed (5)
             name                 (string) "int"

Signed-off-by: Mark Wielaard <mark@klomp.org>
src/ChangeLog
src/readelf.c

index 9a6adab..e187277 100644 (file)
@@ -1,3 +1,15 @@
+2018-01-19  Mark Wielaard  <mark@klomp.org>
+
+       * readelf.c (options): Add info+.
+       (show_split_units): New static boolean defaulting to false.
+       (parse_opt): For all (no arg) --debug-dump set show_split_units
+       to yes. For "info+" enable section_info and show_split_units.
+       (attrcb_args): Add is_split field.
+       (attr_callback): Use is_split to format DIE offsets differently.
+       (print_debug_units): Likewise. Get subdie (type or split) only
+       when needed. When not silent reiterate over split DIEs when
+       found.
+
 2018-05-15  Mark Wielaard  <mark@klomp.org>
 
        * readelf.c (print_debug_units): Print unit type and id for any
index bb03d2c..466d941 100644 (file)
@@ -112,7 +112,7 @@ static const struct argp_option options[] =
   { NULL, 0, NULL, 0, N_("Additional output selection:"), 0 },
   { "debug-dump", 'w', "SECTION", OPTION_ARG_OPTIONAL,
     N_("Display DWARF section content.  SECTION can be one of abbrev, "
-       "aranges, decodedaranges, frame, gdb_index, info, loc, line, "
+       "aranges, decodedaranges, frame, gdb_index, info, info+, loc, line, "
        "decodedline, ranges, pubnames, str, macinfo, macro or exception"), 0 },
   { "hex-dump", 'x', "SECTION", 0,
     N_("Dump the uninterpreted contents of SECTION, by number or name"), 0 },
@@ -215,6 +215,9 @@ static bool decodedline = false;
 /* True if we want to show more information about compressed sections.  */
 static bool print_decompress = false;
 
+/* True if we want to show split compile units for debug_info skeletons.  */
+static bool show_split_units = false;
+
 /* Select printing of debugging sections.  */
 static enum section_e
 {
@@ -422,6 +425,7 @@ parse_opt (int key, char *arg,
        {
          print_debug_sections = section_all;
          implicit_debug_sections = section_info;
+         show_split_units = true;
        }
       else if (strcmp (arg, "abbrev") == 0)
        print_debug_sections |= section_abbrev;
@@ -441,6 +445,11 @@ parse_opt (int key, char *arg,
        print_debug_sections |= section_frame;
       else if (strcmp (arg, "info") == 0)
        print_debug_sections |= section_info;
+      else if (strcmp (arg, "info+") == 0)
+       {
+         print_debug_sections |= section_info;
+         show_split_units = true;
+       }
       else if (strcmp (arg, "loc") == 0)
        {
          print_debug_sections |= section_loc;
@@ -6075,6 +6084,7 @@ struct attrcb_args
   Dwarf_Die *die;
   int level;
   bool silent;
+  bool is_split;
   unsigned int version;
   unsigned int addrsize;
   unsigned int offset_size;
@@ -6088,6 +6098,7 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
   struct attrcb_args *cbargs = (struct attrcb_args *) arg;
   const int level = cbargs->level;
   Dwarf_Die *die = cbargs->die;
+  bool is_split = cbargs->is_split;
 
   unsigned int attr = dwarf_whatattr (attrp);
   if (unlikely (attr == 0))
@@ -6180,9 +6191,13 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
       if (unlikely (dwarf_formref_die (attrp, &ref) == NULL))
        goto attrval_out;
 
-      printf ("           %*s%-20s (%s) [%6" PRIxMAX "]\n",
+      printf ("           %*s%-20s (%s) ",
              (int) (level * 2), "", dwarf_attr_name (attr),
-             dwarf_form_name (form), (uintmax_t) dwarf_dieoffset (&ref));
+             dwarf_form_name (form));
+      if (is_split)
+       printf ("{%6" PRIxMAX "}\n", (uintmax_t) dwarf_dieoffset (&ref));
+      else
+       printf ("[%6" PRIxMAX "]\n", (uintmax_t) dwarf_dieoffset (&ref));
       break;
 
     case DW_FORM_ref_sig8:
@@ -6521,7 +6536,6 @@ print_debug_units (Dwfl_Module *dwflmod,
   Dwarf_CU cu_mem;
   uint8_t unit_type;
   Dwarf_Die cudie;
-  Dwarf_Die subdie;
 
   /* We cheat a little because we want to see only the CUs from .debug_info
      or .debug_types.  We know the Dwarf_CU struct layout.  Set it up at
@@ -6539,7 +6553,7 @@ print_debug_units (Dwfl_Module *dwflmod,
 
  next_cu:
   unit_res = dwarf_get_units (dbg, cu, &cu, &version, &unit_type,
-                             &cudie, &subdie);
+                             &cudie, NULL);
   if (unit_res == 1)
     goto do_return;
 
@@ -6560,14 +6574,21 @@ print_debug_units (Dwfl_Module *dwflmod,
     {
       Dwarf_Off offset = cu->start;
       if (debug_types && version < 5)
-       printf (gettext (" Type unit at offset %" PRIu64 ":\n"
-                        " Version: %" PRIu16 ", Abbreviation section offset: %"
-                        PRIu64 ", Address size: %" PRIu8
-                        ", Offset size: %" PRIu8
-                        "\n Type signature: %#" PRIx64
-                        ", Type offset: %#" PRIx64 " [%" PRIx64 "]\n"),
-               (uint64_t) offset, version, abbroffset, addrsize, offsize,
-               unit_id, (uint64_t) subdie_off, dwarf_dieoffset (&subdie));
+       {
+         Dwarf_Die typedie;
+         Dwarf_Off dieoffset;
+         dieoffset = dwarf_dieoffset (dwarf_offdie_types (dbg, subdie_off,
+                                                          &typedie));
+         printf (gettext (" Type unit at offset %" PRIu64 ":\n"
+                          " Version: %" PRIu16
+                          ", Abbreviation section offset: %" PRIu64
+                          ", Address size: %" PRIu8
+                          ", Offset size: %" PRIu8
+                          "\n Type signature: %#" PRIx64
+                          ", Type offset: %#" PRIx64 " [%" PRIx64 "]\n"),
+                 (uint64_t) offset, version, abbroffset, addrsize, offsize,
+                 unit_id, (uint64_t) subdie_off, dieoffset);
+       }
       else
        {
          printf (gettext (" Compilation unit at offset %" PRIu64 ":\n"
@@ -6589,8 +6610,15 @@ print_debug_units (Dwfl_Module *dwflmod,
                printf (", Unit id: 0x%.16" PRIx64 "", unit_id);
              if (unit_type == DW_UT_type
                  || unit_type == DW_UT_split_type)
-               printf (", Unit DIE off: %#" PRIx64 " [%" PRIx64 "]",
-                       subdie_off, dwarf_dieoffset (&subdie));
+               {
+                 Dwarf_Die typedie;
+                 Dwarf_Off dieoffset;
+                 dwarf_cu_info (cu, NULL, NULL, NULL, &typedie,
+                                NULL, NULL, NULL);
+                 dieoffset = dwarf_dieoffset (&typedie);
+                 printf (", Unit DIE off: %#" PRIx64 " [%" PRIx64 "]",
+                         subdie_off, dieoffset);
+               }
              printf ("\n");
            }
        }
@@ -6608,17 +6636,21 @@ print_debug_units (Dwfl_Module *dwflmod,
   struct attrcb_args args =
     {
       .dwflmod = dwflmod,
-      .dbg = dbg,
       .silent = silent,
       .version = version,
       .addrsize = addrsize,
       .offset_size = offsize
     };
 
+  bool is_split = false;
   int level = 0;
   dies[0] = cudie;
   args.cu = dies[0].cu;
+  args.dbg = dbg;
+  args.is_split = is_split;
 
+  /* We might return here again for the split CU subdie.  */
+  do_cu:
   do
     {
       Dwarf_Off offset = dwarf_dieoffset (&dies[level]);
@@ -6643,8 +6675,11 @@ print_debug_units (Dwfl_Module *dwflmod,
       if (!silent)
        {
          unsigned int code = dwarf_getabbrevcode (dies[level].abbrev);
-         printf (" [%6" PRIx64 "]  %*s%-20s abbrev: %u\n",
-                 (uint64_t) offset, (int) (level * 2), "",
+         if (is_split)
+           printf (" {%6" PRIx64 "}  ", (uint64_t) offset);
+         else
+           printf (" [%6" PRIx64 "]  ", (uint64_t) offset);
+         printf ("%*s%-20s abbrev: %u\n", (int) (level * 2), "",
                  dwarf_tag_name (tag), code);
        }
 
@@ -6686,6 +6721,42 @@ print_debug_units (Dwfl_Module *dwflmod,
     }
   while (level >= 0);
 
+  /* We might want to show the split compile unit if this was a skeleton.  */
+  if (!silent && show_split_units && unit_type == DW_UT_skeleton)
+    {
+      Dwarf_Die subdie;
+      if (dwarf_cu_info (cu, NULL, NULL, NULL, &subdie, NULL, NULL, NULL) != 0
+         || dwarf_tag (&subdie) == DW_TAG_invalid)
+       error (0, 0, gettext ("Could not find split compile unit"));
+      else
+       {
+         Dwarf_CU *split_cu = subdie.cu;
+         dwarf_cu_die (split_cu, &result, NULL, &abbroffset,
+                       &addrsize, &offsize, &unit_id, &subdie_off);
+         Dwarf_Off offset = cu->start;
+
+         printf (gettext (" Split compilation unit at offset %" PRIu64 ":\n"
+                          " Version: %" PRIu16
+                          ", Abbreviation section offset: %" PRIu64
+                          ", Address size: %" PRIu8
+                          ", Offset size: %" PRIu8 "\n"),
+                 (uint64_t) offset, version, abbroffset, addrsize, offsize);
+         printf (gettext (" Unit type: %s (%" PRIu8 ")"),
+                 dwarf_unit_name (unit_type), unit_type);
+         printf (", Unit id: 0x%.16" PRIx64 "", unit_id);
+         printf ("\n");
+
+         unit_type = DW_UT_split_compile;
+         is_split = true;
+         level = 0;
+         dies[0] = subdie;
+         args.cu = dies[0].cu;
+         args.dbg = split_cu->dbg;
+         args.is_split = is_split;
+         goto do_cu;
+       }
+    }
+
   /* And again... */
   goto next_cu;