[Rpm-maint] [PATCH 4/5] Handle .debug_macro in debugedit.
Mark Wielaard
mark at klomp.org
Mon Jun 17 09:23:25 UTC 2019
When compiling with -g3 gcc will generate a .debug_macro section
which has pointers to the .debug_str section. Since we might rewrite
the .debug_str section, we also need to update any .debug_macro
pointers.
Updated the debugedit.at testcase by building everything with -g
and add various checks to see the .debug_macro section looks OK
after running debugedit. Added a new rpmbuild.at testcase to check
handing of .debug_macro in the whole rpmbuild debuginfo pipeline
to double check the separate .debug file also contains the macros.
Original patch by Michael Schroeder <mls at suse.de>. Extended by
Mark Wielaard <mark at klomp.org> to deal with relocations and possible
multiple COMDAT .debug_macro sections.
---
tests/Makefile.am | 1 +
tests/data/SPECS/hello-g3.spec | 60 +++++++++++++
tests/debugedit.at | 79 ++++++++++++++++-
tests/rpmbuild.at | 33 +++++++
tools/debugedit.c | 196 +++++++++++++++++++++++++++++++++++++++--
5 files changed, 356 insertions(+), 13 deletions(-)
create mode 100644 tests/data/SPECS/hello-g3.spec
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6f909d7..046c912 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -49,6 +49,7 @@ EXTRA_DIST += data/SPECS/hello2.spec
EXTRA_DIST += data/SPECS/hello2cp.spec
EXTRA_DIST += data/SPECS/hello2ln.spec
EXTRA_DIST += data/SPECS/hello2-suid.spec
+EXTRA_DIST += data/SPECS/hello-g3.spec
EXTRA_DIST += data/SPECS/foo.spec
EXTRA_DIST += data/SPECS/globtest.spec
EXTRA_DIST += data/SPECS/versiontest.spec
diff --git a/tests/data/SPECS/hello-g3.spec b/tests/data/SPECS/hello-g3.spec
new file mode 100644
index 0000000..55bbb4a
--- /dev/null
+++ b/tests/data/SPECS/hello-g3.spec
@@ -0,0 +1,60 @@
+Summary: hello-g3 -- double hello, world rpm, .debug_macro -g3
+Name: hello-g3
+Version: 1.0
+Release: 1
+Group: Utilities
+License: GPL
+Distribution: RPM test suite.
+Vendor: Red Hat Software
+Packager: Red Hat Software <bugs at redhat.com>
+URL: http://www.redhat.com
+Source0: hello-1.0.tar.gz
+Patch0: hello-1.0-modernize.patch
+Prefix: /usr
+
+%description
+Simple rpm demonstration.
+
+%prep
+%setup -q -n hello-1.0
+%patch0 -p1 -b .modernize
+
+%build
+make CFLAGS="-g3 -O1 -DDEBUG_DEFINE=1"
+mv hello hello-g3
+make CFLAGS="-g3 -O2 -D_FORTIFY_SOURCE=2"
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/usr/local/bin
+make DESTDIR=$RPM_BUILD_ROOT install
+cp hello-g3 $RPM_BUILD_ROOT/usr/local/bin/
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%pre
+
+%post
+
+%preun
+
+%postun
+
+%files
+%defattr(-,root,root)
+%doc FAQ
+#%readme README
+#%license COPYING
+%attr(0751,root,root) /usr/local/bin/hello
+%attr(0751,root,root) /usr/local/bin/hello-g3
+
+%changelog
+* Mon Jun 3 2019 Mark Wielaard <mjw at fedoraproject.org>
+- Create hello-g3 for -g3 .debug_macro testing.
+
+* Wed May 18 2016 Mark Wielaard <mjw at redhat.com>
+- Add hello2 for dwz testing support.
+
+* Tue Oct 20 1998 Jeff Johnson <jbj at redhat.com>
+- create.
diff --git a/tests/debugedit.at b/tests/debugedit.at
index 8b724d3..7e26085 100644
--- a/tests/debugedit.at
+++ b/tests/debugedit.at
@@ -35,11 +35,11 @@ cp "${abs_srcdir}"/data/SOURCES/foobar.h subdir_headers
cp "${abs_srcdir}"/data/SOURCES/baz.c .
# First three object files (foo.o subdir_bar/bar.o and baz.o)
-gcc -g -Isubdir_headers -c subdir_foo/foo.c
+gcc -g3 -Isubdir_headers -c subdir_foo/foo.c
cd subdir_bar
-gcc -g -I../subdir_headers -c bar.c
+gcc -g3 -I../subdir_headers -c bar.c
cd ..
-gcc -g -I$(pwd)/subdir_headers -c $(pwd)/baz.c
+gcc -g3 -I$(pwd)/subdir_headers -c $(pwd)/baz.c
# Then a partially linked object file (somewhat like a kernel module).
# This will still have relocations between the debug sections.
@@ -47,7 +47,7 @@ ld -r -o foobarbaz.part.o foo.o subdir_bar/bar.o baz.o
# Create an executable. Relocations between debug sections will
# have been resolved.
-gcc -g -o foobarbaz.exe foo.o subdir_bar/bar.o baz.o
+gcc -g3 -o foobarbaz.exe foo.o subdir_bar/bar.o baz.o
]])
# ===
@@ -320,3 +320,74 @@ readelf --debug-dump=line ./foobarbaz.exe \
]],[0],[expout])
AT_CLEANUP
+
+# ===
+# Make sure .debug_macro strings are still there
+# in objects.
+# ===
+AT_SETUP([debugedit .debug_macro objects])
+AT_KEYWORDS([debuginfo] [debugedit])
+RPM_DEBUGEDIT_SETUP
+
+# We expect 3 for each compile unit.
+AT_DATA([expout],
+[NUMBER 42
+NUMBER 42
+NUMBER 42
+])
+
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./foo.o]])
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./subdir_bar/bar.o]])
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./baz.o]])
+AT_CHECK([[
+readelf --debug-dump=macro foo.o subdir_bar/bar.o baz.o \
+ | grep NUMBER | rev | cut -d: -f1 | rev | cut -c2-
+]],[0],[expout])
+
+AT_CLEANUP
+
+# ===
+# Make sure .debug_macro strings are still there
+# in partial linked object.
+# ===
+AT_SETUP([debugedit .debug_macro partial])
+AT_KEYWORDS([debuginfo] [debugedit])
+RPM_DEBUGEDIT_SETUP
+
+# We expect 3 for each compile unit.
+AT_DATA([expout],
+[NUMBER 42
+NUMBER 42
+NUMBER 42
+])
+
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./foobarbaz.part.o]])
+AT_CHECK([[
+readelf --debug-dump=macro ./foobarbaz.part.o \
+ | grep NUMBER | rev | cut -d: -f1 | rev | cut -c2-
+]],[0],[expout])
+
+AT_CLEANUP
+
+# ===
+# Make sure .debug_macro strings are still there
+# in executable.
+# ===
+AT_SETUP([debugedit .debug_macro exe])
+AT_KEYWORDS([debuginfo] [debugedit])
+RPM_DEBUGEDIT_SETUP
+
+# We expect 3 for each compile unit.
+AT_DATA([expout],
+[NUMBER 42
+NUMBER 42
+NUMBER 42
+])
+
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./foobarbaz.exe]])
+AT_CHECK([[
+readelf --debug-dump=macro ./foobarbaz.exe \
+ | grep NUMBER | rev | cut -d: -f1 | rev | cut -c2-
+]],[0],[expout])
+
+AT_CLEANUP
diff --git a/tests/rpmbuild.at b/tests/rpmbuild.at
index ba45011..88ff5e5 100644
--- a/tests/rpmbuild.at
+++ b/tests/rpmbuild.at
@@ -834,6 +834,39 @@ readelf -S ./usr/lib/debug/usr/local/bin/hello2*.debug \
AT_CLEANUP
# ------------------------------
+# Check that a -g3 (macros) build creates a valid .debug file.
+AT_SETUP([rpmbuild debuginfo -g3 .debug_macro])
+AT_KEYWORDS([build] [debuginfo] [gdb])
+AT_CHECK([
+rm -rf ${TOPDIR}
+AS_MKDIR_P(${TOPDIR}/SOURCES)
+
+# Build a package that has some debuginfo generated with -g3.
+# Specifically it uses -DDEBUG_DEFINE=1, which we want to see back
+# in the .debug_macro section of the .debug file.
+cp "${abs_srcdir}"/data/SOURCES/hello-1.0.tar.gz "${abs_srcdir}"/data/SOURCES/hello-1.0-modernize.patch ${TOPDIR}/SOURCES
+
+rundebug rpmbuild --quiet \
+ --define "_include_gdb_index 1" \
+ -ba "${abs_srcdir}"/data/SPECS/hello-g3.spec
+
+# Unpack the debuginfo rpms so we can check the .debug files.
+rpm2cpio ${abs_builddir}/testing/build/RPMS/*/hello-g3-debuginfo-1.0-1.*.rpm \
+ | cpio -diu --quiet
+
+# We are looking for a line like:
+# DW_MACRO_define_strp - lineno : 0 macro : DEBUG_DEFINE 1
+readelf --debug-dump=macro ./usr/lib/debug/usr/local/bin/hello-g3*.debug \
+ | grep DEBUG_DEFINE | cut -f3 -d:
+],
+[0],
+[ DEBUG_DEFINE 1
+],
+[ignore])
+AT_CLEANUP
+
+# ------------------------------
+# ------------------------------
# Check that a debug source is in a "unique" directory when requested.
AT_SETUP([rpmbuild debuginfo unique debug src dir])
AT_KEYWORDS([build] [debuginfo])
diff --git a/tools/debugedit.c b/tools/debugedit.c
index cf9cc3c..84483ef 100644
--- a/tools/debugedit.c
+++ b/tools/debugedit.c
@@ -41,6 +41,7 @@
#include <gelf.h>
#include <dwarf.h>
+
/* Unfortunately strtab manipulation functions were only officially added
to elfutils libdw in 0.167. Before that there were internal unsupported
ebl variants. While libebl.h isn't supported we'll try to use it anyway
@@ -432,6 +433,7 @@ typedef struct debug_section
int sec, relsec;
REL *relbuf;
REL *relend;
+ struct debug_section *next; /* Only happens for COMDAT .debug_macro. */
} debug_section;
static debug_section debug_sections[] =
@@ -1989,11 +1991,35 @@ edit_dwarf2 (DSO *dso)
for (j = 0; debug_sections[j].name; ++j)
if (strcmp (name, debug_sections[j].name) == 0)
{
+ struct debug_section *debug_sec = &debug_sections[j];
if (debug_sections[j].data)
{
- error (0, 0, "%s: Found two copies of %s section",
- dso->filename, name);
- return 1;
+ if (j != DEBUG_MACRO)
+ {
+ error (0, 0, "%s: Found two copies of %s section",
+ dso->filename, name);
+ return 1;
+ }
+ else
+ {
+ /* In relocatable files .debug_macro might
+ appear multiple times as COMDAT
+ section. */
+ struct debug_section *sec;
+ sec = calloc (sizeof (struct debug_section), 1);
+ if (sec == NULL)
+ error (1, errno,
+ "%s: Could not allocate more macro sections",
+ dso->filename);
+ sec->name = ".debug_macro";
+
+ struct debug_section *macro_sec = debug_sec;
+ while (macro_sec->next != NULL)
+ macro_sec = macro_sec->next;
+
+ macro_sec->next = sec;
+ debug_sec = sec;
+ }
}
scn = dso->scn[i];
@@ -2002,10 +2028,10 @@ edit_dwarf2 (DSO *dso)
assert (elf_getdata (scn, data) == NULL);
assert (data->d_off == 0);
assert (data->d_size == dso->shdr[i].sh_size);
- debug_sections[j].data = data->d_buf;
- debug_sections[j].elf_data = data;
- debug_sections[j].size = data->d_size;
- debug_sections[j].sec = i;
+ debug_sec->data = data->d_buf;
+ debug_sec->elf_data = data;
+ debug_sec->size = data->d_size;
+ debug_sec->sec = i;
break;
}
@@ -2028,7 +2054,26 @@ edit_dwarf2 (DSO *dso)
+ (dso->shdr[i].sh_type == SHT_RELA),
debug_sections[j].name) == 0)
{
- debug_sections[j].relsec = i;
+ if (j == DEBUG_MACRO)
+ {
+ /* Pick the correct one. */
+ int rel_target = dso->shdr[i].sh_info;
+ struct debug_section *macro_sec = &debug_sections[j];
+ while (macro_sec != NULL)
+ {
+ if (macro_sec->sec == rel_target)
+ {
+ macro_sec->relsec = i;
+ break;
+ }
+ macro_sec = macro_sec->next;
+ }
+ if (macro_sec == NULL)
+ error (0, 1, "No .debug_macro reloc section: %s",
+ dso->filename);
+ }
+ else
+ debug_sections[j].relsec = i;
break;
}
}
@@ -2062,6 +2107,7 @@ edit_dwarf2 (DSO *dso)
struct abbrev_tag tag, *t;
int phase;
bool info_rel_updated = false;
+ bool macro_rel_updated = false;
for (phase = 0; phase < 2; phase++)
{
@@ -2279,6 +2325,113 @@ edit_dwarf2 (DSO *dso)
}
}
+ /* The .debug_macro section also contains offsets into the
+ .debug_str section and references to the .debug_line
+ tables, so we need to update those as well if we update
+ the strings or the stmts. */
+ if ((need_strp_update || need_stmt_update)
+ && debug_sections[DEBUG_MACRO].data)
+ {
+ /* There might be multiple (COMDAT) .debug_macro sections. */
+ struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO];
+ while (macro_sec != NULL)
+ {
+ setup_relbuf(dso, macro_sec, &reltype);
+ rel_updated = false;
+
+ ptr = macro_sec->data;
+ endsec = ptr + macro_sec->size;
+ int op = 0, macro_version, macro_flags;
+ int offset_len = 4, line_offset = 0;
+
+ while (ptr < endsec)
+ {
+ if (!op)
+ {
+ macro_version = read_16 (ptr);
+ macro_flags = read_8 (ptr);
+ if (macro_version < 4 || macro_version > 5)
+ error (1, 0, "unhandled .debug_macro version: %d",
+ macro_version);
+ if ((macro_flags & ~2) != 0)
+ error (1, 0, "unhandled .debug_macro flags: 0x%x",
+ macro_flags);
+
+ offset_len = (macro_flags & 0x01) ? 8 : 4;
+ line_offset = (macro_flags & 0x02) ? 1 : 0;
+
+ if (offset_len != 4)
+ error (0, 1,
+ "Cannot handle 8 byte macro offsets: %s",
+ dso->filename);
+
+ /* Update the line_offset if it is there. */
+ if (line_offset)
+ {
+ if (phase == 0)
+ ptr += offset_len;
+ else
+ {
+ size_t idx, new_idx;
+ idx = do_read_32_relocated (ptr);
+ new_idx = find_new_list_offs (&dso->lines,
+ idx);
+ write_32_relocated (ptr, new_idx);
+ }
+ }
+ }
+
+ op = read_8 (ptr);
+ if (!op)
+ continue;
+ switch(op)
+ {
+ case DW_MACRO_GNU_define:
+ case DW_MACRO_GNU_undef:
+ read_uleb128 (ptr);
+ ptr = ((unsigned char *) strchr ((char *) ptr, '\0')
+ + 1);
+ break;
+ case DW_MACRO_GNU_start_file:
+ read_uleb128 (ptr);
+ read_uleb128 (ptr);
+ break;
+ case DW_MACRO_GNU_end_file:
+ break;
+ case DW_MACRO_GNU_define_indirect:
+ case DW_MACRO_GNU_undef_indirect:
+ read_uleb128 (ptr);
+ if (phase == 0)
+ {
+ size_t idx = read_32_relocated (ptr);
+ record_existing_string_entry_idx (&dso->strings,
+ idx);
+ }
+ else
+ {
+ struct stridxentry *entry;
+ size_t idx, new_idx;
+ idx = do_read_32_relocated (ptr);
+ entry = string_find_entry (&dso->strings, idx);
+ new_idx = strent_offset (entry->entry);
+ write_32_relocated (ptr, new_idx);
+ }
+ break;
+ case DW_MACRO_GNU_transparent_include:
+ ptr += offset_len;
+ break;
+ default:
+ error (1, 0, "Unhandled DW_MACRO op 0x%x", op);
+ break;
+ }
+ }
+
+ if (rel_updated)
+ macro_rel_updated = true;
+ macro_sec = macro_sec->next;
+ }
+ }
+
/* Same for the debug_str section. Make sure everything is
in place for phase 1 updating of debug_info
references. */
@@ -2308,10 +2461,24 @@ edit_dwarf2 (DSO *dso)
new strp, strings and/or linep offsets. */
if (need_strp_update || need_string_replacement || need_stmt_update)
dirty_section (DEBUG_INFO);
+ if (need_strp_update || need_stmt_update)
+ dirty_section (DEBUG_MACRO);
+ if (need_stmt_update)
+ dirty_section (DEBUG_LINE);
- /* Update any debug_info relocations addends we might have touched. */
+ /* Update any relocations addends we might have touched. */
if (info_rel_updated)
update_rela_data (dso, &debug_sections[DEBUG_INFO]);
+
+ if (macro_rel_updated)
+ {
+ struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO];
+ while (macro_sec != NULL)
+ {
+ update_rela_data (dso, macro_sec);
+ macro_sec = macro_sec->next;
+ }
+ }
}
return 0;
@@ -2843,6 +3010,17 @@ main (int argc, char *argv[])
destroy_lines (&dso->lines);
free (dso);
+ /* In case there were multiple (COMDAT) .debug_macro sections,
+ free them. */
+ struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO];
+ macro_sec = macro_sec->next;
+ while (macro_sec != NULL)
+ {
+ struct debug_section *next = macro_sec->next;
+ free (macro_sec);
+ macro_sec = next;
+ }
+
poptFreeContext (optCon);
return 0;
--
1.8.3.1
More information about the Rpm-maint
mailing list