[Rpm-maint] [PATCH 4/5] debugedit: Implement DWARF-5 .debug_types (in .debug_info).
Jan Kratochvil
jan.kratochvil at redhat.com
Tue Aug 18 20:13:15 UTC 2020
diff --git a/tests/debugedit.at b/tests/debugedit.at
index 49721a342..bcd86ac67 100644
--- a/tests/debugedit.at
+++ b/tests/debugedit.at
@@ -253,9 +253,8 @@ AT_CLEANUP
# ===
# Make sure -fdebug-types-section has updated strings in objects.
# ===
-AT_SETUP([debugedit .debug_types objects])
-AT_KEYWORDS([debugtypes] [debugedit])
-RPM_DEBUGEDIT_SETUP([-fdebug-types-section])
+m4_define([RPM_DEBUGEDIT_DEBUG_TYPES_OBJECTS],[
+RPM_DEBUGEDIT_SETUP($1)
AT_DATA([expout],
[st1
@@ -283,15 +282,13 @@ for i in ./foo.o ./subdir_bar/bar.o ./baz.o;do \
| sort;
done
]],[0],[expout])
-
-AT_CLEANUP
+])
# ===
# Make sure -fdebug-types-section has updated strings in partial linked object.
# ===
-AT_SETUP([debugedit .debug_types partial])
-AT_KEYWORDS([debugtypes] [debugedit])
-RPM_DEBUGEDIT_SETUP([-fdebug-types-section])
+m4_define([RPM_DEBUGEDIT_DEBUG_TYPES_PARTIAL],[
+RPM_DEBUGEDIT_SETUP($1)
AT_DATA([expout],
[st1
@@ -311,15 +308,13 @@ readelf --debug-dump=info ./foobarbaz.part.o \
| sed -n 's/^.*> *DW_AT_name *:.* \(stringp[^ ]*\|st.\)$/\1/p' \
| sort
]],[0],[expout])
-
-AT_CLEANUP
+])
# ===
# Make sure -fdebug-types-section has updated strings in executable.
# ===
-AT_SETUP([debugedit .debug_types exe])
-AT_KEYWORDS([debugtypes] [debugedit])
-RPM_DEBUGEDIT_SETUP([-fdebug-types-section])
+m4_define([RPM_DEBUGEDIT_DEBUG_TYPES_EXE],[
+RPM_DEBUGEDIT_SETUP($1)
AT_DATA([expout],
[st1
@@ -339,7 +334,36 @@ readelf --debug-dump=info ./foobarbaz.exe \
| sed -n 's/^.*> *DW_AT_name *:.* \(stringp[^ ]*\|st.\)$/\1/p' \
| sort
]],[0],[expout])
+])
+
+AT_SETUP([debugedit DWARF-4 .debug_types objects])
+AT_KEYWORDS([debugtypes] [debugedit])
+RPM_DEBUGEDIT_DEBUG_TYPES_OBJECTS([-gdwarf-4 -fdebug-types-section])
+AT_CLEANUP
+AT_SETUP([debugedit DWARF-4 .debug_types partial])
+AT_KEYWORDS([debugtypes] [debugedit])
+RPM_DEBUGEDIT_DEBUG_TYPES_PARTIAL([-gdwarf-4 -fdebug-types-section])
+AT_CLEANUP
+
+AT_SETUP([debugedit DWARF-4 .debug_types exe])
+AT_KEYWORDS([debugtypes] [debugedit])
+RPM_DEBUGEDIT_DEBUG_TYPES_EXE([-gdwarf-4 -fdebug-types-section])
+AT_CLEANUP
+
+AT_SETUP([debugedit DWARF-5 .debug_types objects])
+AT_KEYWORDS([debugtypes] [debugedit])
+RPM_DEBUGEDIT_DEBUG_TYPES_OBJECTS([-gdwarf-5 -fdebug-types-section])
+AT_CLEANUP
+
+AT_SETUP([debugedit DWARF-5 .debug_types partial])
+AT_KEYWORDS([debugtypes] [debugedit])
+RPM_DEBUGEDIT_DEBUG_TYPES_PARTIAL([-gdwarf-5 -fdebug-types-section])
+AT_CLEANUP
+
+AT_SETUP([debugedit DWARF-5 .debug_types exe])
+AT_KEYWORDS([debugtypes] [debugedit])
+RPM_DEBUGEDIT_DEBUG_TYPES_EXE([-gdwarf-5 -fdebug-types-section])
AT_CLEANUP
# foo.o and bar.o are build with relative paths and so will use the
diff --git a/tools/debugedit.c b/tools/debugedit.c
index 9f1dc2d3f..19f69e263 100644
--- a/tools/debugedit.c
+++ b/tools/debugedit.c
@@ -433,7 +433,8 @@ typedef struct debug_section
int sec, relsec;
REL *relbuf;
REL *relend;
- /* Only happens for COMDAT .debug_macro and .debug_types. */
+ /* Only happens for COMDAT .debug_macro, .debug_types and DWARF-5
+ .debug_info. */
struct debug_section *next;
} debug_section;
@@ -755,12 +756,19 @@ no_memory:
}
form = read_uleb128 (ptr);
if (form == 2
- || (form > DW_FORM_flag_present && form != DW_FORM_ref_sig8))
+ || (form > DW_FORM_flag_present && form != DW_FORM_ref_sig8
+ && form != DW_FORM_implicit_const))
{
- error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename, form);
+ error (0, 0, "%s: Unknown DWARF abbrev DW_FORM_0x%x",
+ dso->filename, form);
htab_delete (h);
return NULL;
}
+ if (form == DW_FORM_implicit_const)
+ {
+ /* It is SLEB128 but the value is dropped anyway. */
+ read_uleb128 (ptr);
+ }
t->attr[t->nattr].attr = attr;
t->attr[t->nattr++].form = form;
@@ -1505,6 +1513,7 @@ skip_form (DSO *dso, uint32_t *formp, unsigned char **ptrp)
*ptrp += 4;
break;
case DW_FORM_flag_present:
+ case DW_FORM_implicit_const:
break;
case DW_FORM_addr:
*ptrp += ptr_size;
@@ -2018,7 +2027,7 @@ line_rel_cmp (const void *a, const void *b)
}
static int
-edit_info (DSO *dso, int phase, struct debug_section *sec)
+edit_info (DSO *dso, int phase, struct debug_section *sec, bool is_types)
{
unsigned char *ptr, *endcu, *endsec;
uint32_t value;
@@ -2033,7 +2042,9 @@ edit_info (DSO *dso, int phase, struct debug_section *sec)
endsec = ptr + sec->size;
while (ptr < endsec)
{
- if (ptr + (sec == &debug_sections[DEBUG_INFO] ? 11 : 23) > endsec)
+ unsigned char *sec_start = ptr;
+
+ if (ptr + 4 + 2 + 1 + 1 > endsec)
{
error (0, 0, "%s: %s CU header too small",
dso->filename, sec->name);
@@ -2055,13 +2066,48 @@ edit_info (DSO *dso, int phase, struct debug_section *sec)
}
cu_version = read_16 (ptr);
- if (cu_version != 2 && cu_version != 3 && cu_version != 4)
+ if (cu_version != 2 && cu_version != 3 && cu_version != 4
+ && cu_version != 5)
{
error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
cu_version);
return 1;
}
+ int cu_ptr_size;
+ bool cu_is_types;
+
+ if (cu_version >= 5)
+ {
+ if (is_types)
+ {
+ error (0, 0, "%s: .debug_types are invalid for DWARF 5+",
+ dso->filename);
+ return 1;
+ }
+
+ uint8_t unit_type = read_8 (ptr);
+ if (unit_type != DW_UT_compile && unit_type != DW_UT_type)
+ {
+ error (0, 0, "%s: Unit type %u unhandled", dso->filename,
+ unit_type);
+ return 1;
+ }
+ cu_is_types = unit_type == DW_UT_type;
+
+ cu_ptr_size = read_8 (ptr);
+ }
+ else
+ cu_is_types = is_types;
+
+ unsigned char *header_end = (sec_start + (!cu_is_types ? 11 : 23)
+ + (cu_version < 5 ? 0 : 1));
+ if (header_end > endsec)
+ {
+ error (0, 0, "%s: %s CU header too small", dso->filename, sec->name);
+ return 1;
+ }
+
value = read_32_relocated (ptr);
if (value >= debug_sections[DEBUG_ABBREV].size)
{
@@ -2073,9 +2119,12 @@ edit_info (DSO *dso, int phase, struct debug_section *sec)
return 1;
}
+ if (cu_version < 5)
+ cu_ptr_size = read_8 (ptr);
+
if (ptr_size == 0)
{
- ptr_size = read_8 (ptr);
+ ptr_size = cu_ptr_size;
if (ptr_size != 4 && ptr_size != 8)
{
error (0, 0, "%s: Invalid DWARF pointer size %d",
@@ -2083,14 +2132,14 @@ edit_info (DSO *dso, int phase, struct debug_section *sec)
return 1;
}
}
- else if (read_8 (ptr) != ptr_size)
+ else if (cu_ptr_size != ptr_size)
{
error (0, 0, "%s: DWARF pointer size differs between CUs",
dso->filename);
return 1;
}
- if (sec != &debug_sections[DEBUG_INFO])
+ if (cu_is_types)
ptr += 12; /* Skip type_signature and type_offset. */
abbrev = read_abbrev (dso,
@@ -2179,7 +2228,8 @@ edit_dwarf2 (DSO *dso)
struct debug_section *debug_sec = &debug_sections[j];
if (debug_sections[j].data)
{
- if (j != DEBUG_MACRO && j != DEBUG_TYPES)
+ if (j != DEBUG_MACRO && j != DEBUG_TYPES
+ && j != DEBUG_INFO)
{
error (0, 0, "%s: Found two copies of %s section",
dso->filename, name);
@@ -2187,8 +2237,9 @@ edit_dwarf2 (DSO *dso)
}
else
{
- /* In relocatable files .debug_macro and .debug_types
- might appear multiple times as COMDAT section. */
+ /* In relocatable files .debug_macro, .debug_types
+ and DWARF-5 .debug_info might appear multiple
+ times as COMDAT section. */
struct debug_section *sec;
sec = calloc (sizeof (struct debug_section), 1);
if (sec == NULL)
@@ -2238,7 +2289,7 @@ edit_dwarf2 (DSO *dso)
+ (dso->shdr[i].sh_type == SHT_RELA),
debug_sections[j].name) == 0)
{
- if (j == DEBUG_MACRO || j == DEBUG_TYPES)
+ if (j == DEBUG_MACRO || j == DEBUG_TYPES || j == DEBUG_INFO)
{
/* Pick the correct one. */
int rel_target = dso->shdr[i].sh_info;
@@ -2302,8 +2353,13 @@ edit_dwarf2 (DSO *dso)
break;
rel_updated = false;
- if (edit_info (dso, phase, &debug_sections[DEBUG_INFO]))
- return 1;
+ struct debug_section *info_sec = &debug_sections[DEBUG_INFO];
+ while (info_sec != NULL)
+ {
+ if (edit_info (dso, phase, info_sec, false /* is_types */))
+ return 1;
+ info_sec = info_sec->next;
+ }
/* Remember whether any .debug_info relocations might need
to be updated. */
@@ -2313,7 +2369,7 @@ edit_dwarf2 (DSO *dso)
struct debug_section *types_sec = &debug_sections[DEBUG_TYPES];
while (types_sec != NULL)
{
- if (edit_info (dso, phase, types_sec))
+ if (edit_info (dso, phase, types_sec, true /* is_types */))
return 1;
types_sec = types_sec->next;
}
@@ -2564,7 +2620,14 @@ edit_dwarf2 (DSO *dso)
/* Update any relocations addends we might have touched. */
if (info_rel_updated)
- update_rela_data (dso, &debug_sections[DEBUG_INFO]);
+ {
+ struct debug_section *info_sec = &debug_sections[DEBUG_INFO];
+ while (info_sec != NULL)
+ {
+ update_rela_data (dso, info_sec);
+ info_sec = info_sec->next;
+ }
+ }
if (types_rel_updated)
{
struct debug_section *types_sec = &debug_sections[DEBUG_TYPES];
@@ -2914,6 +2977,7 @@ main (int argc, char *argv[])
if (dso == NULL)
exit (1);
+ bool have_info = false;
for (i = 1; i < dso->ehdr.e_shnum; i++)
{
const char *name;
@@ -2929,7 +2993,7 @@ main (int argc, char *argv[])
break;
}
if (strcmp (name, ".debug_info") == 0)
- edit_dwarf2 (dso);
+ have_info = true;
break;
case SHT_NOTE:
@@ -2960,6 +3024,9 @@ main (int argc, char *argv[])
}
}
+ if (have_info)
+ edit_dwarf2 (dso);
+
/* Normally we only need to explicitly update the section headers
and data when any section data changed size. But because of a bug
in elfutils before 0.169 we will have to update and write out all
@@ -3136,6 +3203,17 @@ main (int argc, char *argv[])
types_sec = next;
}
+ /* In case there were multiple (COMDAT) DWARF-5 .debug_info sections,
+ free them. */
+ struct debug_section *info_sec = &debug_sections[DEBUG_INFO];
+ info_sec = info_sec->next;
+ while (info_sec != NULL)
+ {
+ struct debug_section *next = info_sec->next;
+ free (info_sec);
+ info_sec = next;
+ }
+
poptFreeContext (optCon);
return 0;
More information about the Rpm-maint
mailing list