Skip to content

Instantly share code, notes, and snippets.

@jmontleon
Created January 13, 2026 16:56
Show Gist options
  • Select an option

  • Save jmontleon/f57b7a2d282d64a4479cff094a94306c to your computer and use it in GitHub Desktop.

Select an option

Save jmontleon/f57b7a2d282d64a4479cff094a94306c to your computer and use it in GitHub Desktop.
diff --git a/tools/debugedit.c b/tools/debugedit.c
index c7cd778..96dc96d 100644
--- a/tools/debugedit.c
+++ b/tools/debugedit.c
@@ -2846,6 +2846,77 @@ edit_dwarf2_any_str (DSO *dso, struct strings *strings, debug_section *secp)
elf_flagdata (strdata, ELF_C_SET, ELF_F_DIRTY);
}
+/* Update symbol table entries that reference modified debug string sections.
+ When we modify .debug_str or .debug_line_str sections, symbols that point
+ into these sections need their st_value updated to reflect the new offsets.
+ This is particularly important for RISC-V and other architectures that use
+ local symbols to reference string section offsets. Without this update,
+ symbols can point beyond the end of the section after it has been shrunk,
+ causing linker errors and corrupt DWARF information. */
+static void
+update_symtab_for_debug_str_changes (DSO *dso)
+{
+ /* Find the symbol table section(s) */
+ for (int i = 1; i < dso->ehdr.e_shnum; ++i)
+ {
+ if (dso->shdr[i].sh_type == SHT_SYMTAB)
+ {
+ Elf_Scn *scn = dso->scn[i];
+ Elf_Data *symdata = elf_getdata (scn, NULL);
+ if (symdata == NULL)
+ continue;
+
+ int symcount = dso->shdr[i].sh_size / dso->shdr[i].sh_entsize;
+ bool modified = false;
+
+ for (int j = 0; j < symcount; j++)
+ {
+ GElf_Sym sym;
+ if (gelf_getsym (symdata, j, &sym) == NULL)
+ continue;
+
+ /* Check if this symbol references a modified debug string section */
+ struct strings *strings = NULL;
+ if (need_strp_update
+ && sym.st_shndx == debug_sections[DEBUG_STR].sec)
+ strings = &dso->debug_str;
+ else if (need_line_strp_update
+ && sym.st_shndx == debug_sections[DEBUG_LINE_STR].sec)
+ strings = &dso->debug_line_str;
+
+ if (strings != NULL)
+ {
+ /* Look up the old offset to find the new one */
+ size_t old_offset = sym.st_value;
+ struct stridxentry *entry = string_find_entry (strings,
+ old_offset,
+ true);
+
+ /* If we found the entry, update the symbol */
+ if (entry != &debugedit_stridxentry)
+ {
+ size_t new_offset = strent_offset (entry->entry);
+ if (new_offset != old_offset)
+ {
+ sym.st_value = new_offset;
+ if (gelf_update_sym (symdata, j, &sym) == 0)
+ error (1, 0, "Failed to update symbol: %s",
+ elf_errmsg (-1));
+ modified = true;
+ }
+ }
+ }
+ }
+
+ if (modified)
+ elf_flagdata (symdata, ELF_C_SET, ELF_F_DIRTY);
+
+ /* There's typically only one symbol table, but we'll continue
+ checking in case there are multiple */
+ }
+ }
+}
+
/* Rebuild .debug_str_offsets. */
static void
update_str_offsets (DSO *dso)
@@ -3358,6 +3429,12 @@ edit_dwarf2 (DSO *dso)
if (phase == 0 && need_line_strp_update)
edit_dwarf2_any_str (dso, &dso->debug_line_str,
&debug_sections[DEBUG_LINE_STR]);
+
+ /* After modifying string sections, update any symbols that reference them.
+ This is critical for RISC-V and other architectures that use local
+ symbols to reference offsets within mergeable string sections. */
+ if (phase == 0 && (need_strp_update || need_line_strp_update))
+ update_symtab_for_debug_str_changes (dso);
}
/* After phase 1 we might have rewritten the debug_info with
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment