readelf, libdw: Handle DWARF5 .debug_macro.
authorMark Wielaard <mark@klomp.org>
Wed, 6 Dec 2017 11:30:12 +0000 (12:30 +0100)
committerMark Wielaard <mark@klomp.org>
Tue, 15 May 2018 09:25:43 +0000 (11:25 +0200)
Almost identical to GNU .debug_macro extension. Just accept and use
DW_AT_macros where we accept or use DW_AT_GNU_macros. And be a little
stricter in which FORMs we accept (this could have caused problems
with the GNU variant too). Deals with DW_FORM_strx[1234], but not yet
with imported macros through DW_MACRO_import_sup.

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

index efdd927..e66a1ec 100644 (file)
@@ -1,3 +1,11 @@
+2018-05-11  Mark Wielaard  <mark@klomp.org>
+
+       * dwarf_formudata.c (dwarf_formudata): Handle DW_AT_macros as macptr.
+       * dwarf_getmacros.c (get_table_for_offset): Add DW_MACRO_define_sup,
+       DW_MACRO_undef_sup, DW_MACRO_import_sup, DW_MACRO_define_strx and
+       DW_MACRO_undef_strx. Add str_offsets_base_off to fake CU. Deal with
+       DW_AT_macros. Use libdw_valid_user_form.
+
 2018-05-09  Mark Wielaard  <mark@klomp.org>
 
        * dwarf_formstring.c (__libdw_cu_str_off_base): Moved to...
index 02c1694..62352ee 100644 (file)
@@ -158,6 +158,7 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
              break;
 
            case DW_AT_GNU_macros:
+           case DW_AT_macros:
              /* macptr into .debug_macro */
              if (__libdw_formptr (attr, IDX_debug_macro,
                                   DWARF_E_NO_ENTRY, NULL,
index c456051..fd92966 100644 (file)
@@ -1,7 +1,6 @@
 /* Get macro information.
-   Copyright (C) 2002-2009, 2014 Red Hat, Inc.
+   Copyright (C) 2002-2009, 2014, 2017, 2018 Red Hat, Inc.
    This file is part of elfutils.
-   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
 
    This file is free software; you can redistribute it and/or modify
    it under the terms of either
@@ -192,6 +191,8 @@ get_table_for_offset (Dwarf *dbg, Dwarf_Word macoff,
 
   MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
   MACRO_PROTO (p_udata_strp, DW_FORM_udata, DW_FORM_strp);
+  MACRO_PROTO (p_udata_strsup, DW_FORM_udata, DW_FORM_strp_sup);
+  MACRO_PROTO (p_udata_strx, DW_FORM_udata, DW_FORM_strx);
   MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
   MACRO_PROTO (p_secoffset, DW_FORM_sec_offset);
   MACRO_PROTO (p_none);
@@ -205,10 +206,11 @@ get_table_for_offset (Dwarf *dbg, Dwarf_Word macoff,
       [DW_MACRO_start_file - 1] = p_udata_udata,
       [DW_MACRO_end_file - 1] = p_none,
       [DW_MACRO_import - 1] = p_secoffset,
-      /* When adding support for DWARF5 supplementary object files and
-        indirect string tables also add support for DW_MACRO_define_sup,
-        DW_MACRO_undef_sup, DW_MACRO_import_sup, DW_MACRO_define_strx
-        and DW_MACRO_undef_strx.  */
+      [DW_MACRO_define_sup - 1] = p_udata_strsup,
+      [DW_MACRO_undef_sup - 1] = p_udata_strsup,
+      [DW_MACRO_import_sup - 1] = p_secoffset, /* XXX - but in sup!. */
+      [DW_MACRO_define_strx - 1] = p_udata_strx,
+      [DW_MACRO_undef_strx - 1] = p_udata_strx,
     };
 
   if ((flags & 0x4) != 0)
@@ -357,12 +359,18 @@ read_macros (Dwarf *dbg, int sec_index,
       /* A fake CU with bare minimum data to fool dwarf_formX into
         doing the right thing with the attributes that we put out.
         We pretend it is the same version as the actual table.
-        Version 4 for the old GNU extension, version 5 for DWARF5.  */
+        Version 4 for the old GNU extension, version 5 for DWARF5.
+        To handle DW_FORM_strx[1234] we set the .str_offsets_base
+        from the given CU.
+        XXX We will need to deal with DW_MACRO_import_sup and change
+        out the dbg somehow for the DW_FORM_sec_offset to make sense.  */
       Dwarf_CU fake_cu = {
        .dbg = dbg,
        .sec_idx = sec_index,
        .version = table->version,
        .offset_size = table->is_64bit ? 8 : 4,
+       .str_off_base = str_offsets_base_off (dbg, (cudie != NULL
+                                                   ? cudie->cu: NULL)),
        .startp = (void *) startp + offset,
        .endp = (void *) endp,
       };
@@ -385,14 +393,25 @@ read_macros (Dwarf *dbg, int sec_index,
 
       for (Dwarf_Word i = 0; i < proto->nforms; ++i)
        {
-         /* We pretend this is a DW_AT_GNU_macros attribute so that
+         /* We pretend this is a DW_AT[_GNU]_macros attribute so that
             DW_FORM_sec_offset forms get correctly interpreted as
-            offset into .debug_macro.  */
-         attributes[i].code = DW_AT_GNU_macros;
+            offset into .debug_macro.  XXX Deal with DW_MACRO_import_sup
+            (swap .dbg) for DW_FORM_sec_offset? */
+         attributes[i].code = (fake_cu.version == 4 ? DW_AT_GNU_macros
+                                                    : DW_AT_macros);
          attributes[i].form = proto->forms[i];
          attributes[i].valp = (void *) readp;
          attributes[i].cu = &fake_cu;
 
+         /* We don't want forms that aren't allowed because they could
+            read from the "abbrev" like DW_FORM_implicit_const.  */
+         if (! libdw_valid_user_form (attributes[i].form))
+           {
+             __libdw_seterrno (DWARF_E_INVALID_DWARF);
+             free (attributesp);
+             return -1;
+           }
+
          size_t len = __libdw_form_val_len (&fake_cu, proto->forms[i], readp);
          if (unlikely (len == (size_t) -1))
            {
@@ -562,7 +581,8 @@ dwarf_getmacros (Dwarf_Die *cudie, int (*callback) (Dwarf_Macro *, void *),
     {
       /* DW_AT_GNU_macros, DW_AT_macros */
       Dwarf_Word macoff;
-      if (get_offset_from (cudie, DW_AT_GNU_macros, &macoff) != 0)
+      if (get_offset_from (cudie, DW_AT_GNU_macros, &macoff) != 0
+         && get_offset_from (cudie, DW_AT_macros, &macoff) != 0)
        return -1;
       offset = gnu_macros_getmacros_off (cudie->cu->dbg, macoff,
                                         callback, arg, offset, accept_0xff,
index 3870508..4e6887e 100644 (file)
@@ -1,3 +1,8 @@
+2018-05-11  Mark Wielaard  <mark@klomp.org>
+
+       * readelf.c (print_debug_macro_section): Use libdw_valid_user_form.
+       Use print_form_data for strx and sup strings.
+
 2018-05-09  Mark Wielaard  <mark@klomp.org>
 
        * readelf.c (dwarf_line_content_description_string): New function.
index c3154ca..c1d89d3 100644 (file)
@@ -8205,20 +8205,7 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
                        goto invalid_data;
                      unsigned int form = *readp++;
                      printf (" %s", dwarf_form_name (form));
-                     if (form != DW_FORM_data1
-                         && form != DW_FORM_data2
-                         && form != DW_FORM_data4
-                         && form != DW_FORM_data8
-                         && form != DW_FORM_sdata
-                         && form != DW_FORM_udata
-                         && form != DW_FORM_block
-                         && form != DW_FORM_block1
-                         && form != DW_FORM_block2
-                         && form != DW_FORM_block4
-                         && form != DW_FORM_flag
-                         && form != DW_FORM_string
-                         && form != DW_FORM_strp
-                         && form != DW_FORM_sec_offset)
+                     if (! libdw_valid_user_form (form))
                        goto invalid_data;
                      args--;
                      if (args > 0)
@@ -8333,26 +8320,22 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
              get_uleb128 (u128, readp, readendp);
              if (readp + offset_len > readendp)
                goto invalid_data;
-             if (offset_len == 8)
-               off = read_8ubyte_unaligned_inc (dbg, readp);
-             else
-               off = read_4ubyte_unaligned_inc (dbg, readp);
-             // Needs support for reading from supplementary object file.
-             printf ("%*s#define <str-at-0x%" PRIx64 ">, line %u (sup)\n",
-                     level, "", off, u128);
+             printf ("%*s#define ", level, "");
+             readp =  print_form_data (dbg, DW_FORM_strp_sup,
+                                       readp, readendp, offset_len,
+                                       str_offsets_base);
+             printf (", line %u (sup)\n", u128);
              break;
 
            case DW_MACRO_undef_sup:
              get_uleb128 (u128, readp, readendp);
              if (readp + offset_len > readendp)
                goto invalid_data;
-             if (offset_len == 8)
-               off = read_8ubyte_unaligned_inc (dbg, readp);
-             else
-               off = read_4ubyte_unaligned_inc (dbg, readp);
-             // Needs support for reading from supplementary object file.
-             printf ("%*s#undef <str-at-0x%" PRIx64 ">, line %u (sup)\n",
-                     level, "", off, u128);
+             printf ("%*s#undef ", level, "");
+             readp =  print_form_data (dbg, DW_FORM_strp_sup,
+                                       readp, readendp, offset_len,
+                                       str_offsets_base);
+             printf (", line %u (sup)\n", u128);
              break;
 
            case DW_MACRO_import_sup:
@@ -8362,6 +8345,7 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
                off = read_8ubyte_unaligned_inc (dbg, readp);
              else
                off = read_4ubyte_unaligned_inc (dbg, readp);
+             // XXX Needs support for reading from supplementary object file.
              printf ("%*s#include offset 0x%" PRIx64 " (sup)\n",
                      level, "", off);
              break;
@@ -8370,26 +8354,22 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
              get_uleb128 (u128, readp, readendp);
              if (readp + offset_len > readendp)
                goto invalid_data;
-             if (offset_len == 8)
-               off = read_8ubyte_unaligned_inc (dbg, readp);
-             else
-               off = read_4ubyte_unaligned_inc (dbg, readp);
-             // Needs support for reading indirect string offset table
-             printf ("%*s#define <str-at-0x%" PRIx64 ">, line %u (strx)\n",
-                     level, "", off, u128);
+             printf ("%*s#define ", level, "");
+             readp =  print_form_data (dbg, DW_FORM_strx,
+                                       readp, readendp, offset_len,
+                                       str_offsets_base);
+             printf (", line %u (strx)\n", u128);
              break;
 
            case DW_MACRO_undef_strx:
              get_uleb128 (u128, readp, readendp);
              if (readp + offset_len > readendp)
                goto invalid_data;
-             if (offset_len == 8)
-               off = read_8ubyte_unaligned_inc (dbg, readp);
-             else
-               off = read_4ubyte_unaligned_inc (dbg, readp);
-             // Needs support for reading indirect string offset table.
-             printf ("%*s#undef <str-at-0x%" PRIx64 ">, line %u (strx)\n",
-                     level, "", off, u128);
+             printf ("%*s#undef ", level, "");
+             readp =  print_form_data (dbg, DW_FORM_strx,
+                                       readp, readendp, offset_len,
+                                       str_offsets_base);
+             printf (", line %u (strx)\n", u128);
              break;
 
            default:
@@ -8405,11 +8385,11 @@ print_debug_macro_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
              // Just skip the arguments, we cannot really interpret them,
              // but print as much as we can.
              unsigned int args = *op_desc++;
-             while (args > 0)
+             while (args > 0 && readp < readendp)
                {
                  unsigned int form = *op_desc++;
-                 print_form_data (dbg, form, readp, readendp, offset_len,
-                                  str_offsets_base);
+                 readp = print_form_data (dbg, form, readp, readendp,
+                                          offset_len, str_offsets_base);
                  args--;
                  if (args > 0)
                    printf (", ");