From d9947f2dc0c2cd812f8e64380d5f6f53705a5280 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Tue, 19 Jan 2021 04:12:33 +0100 Subject: [PATCH 6/6] debugedit: Handle DWARF-5 debug_line and debug_line_str. Handle the new DWARF5 .debug_line tables and the new DW_FORM_line_strp. DWARF5 tables are handled separately from the earlier tables. They will never change size, but they do need updates to the .debug_str or .debug_line_str references. Based on a patch from Jan Kratochvil --- tools/debugedit.c | 471 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 410 insertions(+), 61 deletions(-) diff --git a/tools/debugedit.c b/tools/debugedit.c index be5fee85b..d6a0058e9 100644 --- a/tools/debugedit.c +++ b/tools/debugedit.c @@ -103,6 +103,8 @@ static bool need_string_replacement = false; /* Whether we need to do any updates of the string indexes (DW_FORM_strp) in debug_info for string indexes. */ static bool need_strp_update = false; +/* Likewise for DW_FORM_line_strp. */ +static bool need_line_strp_update = false; /* If the debug_line changes size we will need to update the DW_AT_stmt_list attributes indexes in the debug_info. */ static bool need_stmt_update = false; @@ -192,7 +194,7 @@ typedef struct const char *filename; int lastscn; size_t phnum; - struct strings strings; + struct strings debug_str, debug_line_str; struct debug_lines lines; GElf_Shdr shdr[0]; } DSO; @@ -553,10 +555,11 @@ setup_relbuf (DSO *dso, debug_section *sec, int *reltype) /* Relocations against section symbols are uninteresting in REL. */ if (dso->shdr[i].sh_type == SHT_REL && sym.st_value == 0) continue; - /* Only consider relocations against .debug_str, .debug_line - and .debug_abbrev. */ + /* Only consider relocations against .debug_str, .debug_line, + .debug_line_str, and .debug_abbrev. */ if (sym.st_shndx != debug_sections[DEBUG_STR].sec && sym.st_shndx != debug_sections[DEBUG_LINE].sec + && sym.st_shndx != debug_sections[DEBUG_LINE_STR].sec && sym.st_shndx != debug_sections[DEBUG_ABBREV].sec) continue; rela.r_addend += sym.st_value; @@ -768,6 +771,7 @@ no_memory: || (form > DW_FORM_flag_present && !(form == DW_FORM_ref_sig8 || form == DW_FORM_data16 + || form == DW_FORM_line_strp || form == DW_FORM_implicit_const || form == DW_FORM_addrx || form == DW_FORM_loclistx @@ -1049,17 +1053,20 @@ string_find_entry (struct strings *strings, size_t old_idx) a replacement file string has been recorded for it, otherwise returns false. */ static bool -record_file_string_entry_idx (struct strings *strings, size_t old_idx) +record_file_string_entry_idx (bool line_strp, DSO *dso, size_t old_idx) { + struct strings *strings = line_strp ? &dso->debug_line_str : &dso->debug_str; bool ret = false; struct stridxentry *entry = string_find_new_entry (strings, old_idx); if (entry != NULL) { - if (old_idx >= debug_sections[DEBUG_STR].size) - error (1, 0, "Bad string pointer index %zd", old_idx); + debug_section *sec = &debug_sections[line_strp + ? DEBUG_LINE_STR : DEBUG_STR]; + if (old_idx >= sec->size) + error (1, 0, "Bad string pointer index %zd (%s)", old_idx, sec->name); Strent *strent; - const char *old_str = (char *)debug_sections[DEBUG_STR].data + old_idx; + const char *old_str = (char *)sec->data + old_idx; const char *file = skip_dir_prefix (old_str, base_dir); if (file == NULL) { @@ -1103,15 +1110,18 @@ record_file_string_entry_idx (struct strings *strings, size_t old_idx) base_dir with dest_dir, just records the existing string associated with the index. */ static void -record_existing_string_entry_idx (struct strings *strings, size_t old_idx) +record_existing_string_entry_idx (bool line_strp, DSO *dso, size_t old_idx) { + struct strings *strings = line_strp ? &dso->debug_line_str : &dso->debug_str; struct stridxentry *entry = string_find_new_entry (strings, old_idx); if (entry != NULL) { - if (old_idx >= debug_sections[DEBUG_STR].size) - error (1, 0, "Bad string pointer index %zd", old_idx); + debug_section *sec = &debug_sections[line_strp + ? DEBUG_LINE_STR : DEBUG_STR]; + if (old_idx >= sec->size) + error (1, 0, "Bad string pointer index %zd (%s)", old_idx, sec->name); - const char *str = (char *)debug_sections[DEBUG_STR].data + old_idx; + const char *str = (char *)sec->data + old_idx; Strent *strent = strtab_add_len (strings->str_tab, str, strlen (str) + 1); if (strent == NULL) @@ -1244,13 +1254,28 @@ get_line_table (DSO *dso, size_t off, struct line_table **table) /* version */ t->version = read_16 (ptr); - if (t->version != 2 && t->version != 3 && t->version != 4) + if (t->version != 2 && t->version != 3 && t->version != 4 && t->version != 5) { error (0, 0, "%s: DWARF version %d unhandled", dso->filename, t->version); return false; } + if (t->version >= 5) + { + /* address_size */ + assert (ptr_size != 0); + if (ptr_size != read_8 (ptr)) + { + error (0, 0, "%s: .debug_line address size differs from .debug_info", + dso->filename); + return false; + } + + /* segment_selector_size */ + (void) read_8 (ptr); + } + /* header_length */ unsigned char *endprol = ptr + 4; t->header_length = read_32 (ptr); @@ -1343,7 +1368,9 @@ edit_dwarf2_line (DSO *dso) linedata->d_size = dso->lines.debug_lines_len; linedata->d_buf = dso->lines.line_buf; + debug_sections[DEBUG_LINE].data = linedata->d_buf; debug_sections[DEBUG_LINE].size = linedata->d_size; + debug_sections[DEBUG_LINE].elf_data = linedata; /* Make sure the line tables are sorted on the old index. */ qsort (dso->lines.table, dso->lines.used, sizeof (struct line_table), @@ -1483,9 +1510,10 @@ edit_dwarf2_line (DSO *dso) } } -/* Record or adjust (according to phase) DW_FORM_strp. */ +/* Record or adjust (according to phase) DW_FORM_strp or DW_FORM_line_strp. */ static void -edit_strp (DSO *dso, unsigned char *ptr, int phase, bool handled_strp) +edit_strp (DSO *dso, bool line_strp, unsigned char *ptr, int phase, + bool handled_strp) { unsigned char *ptr_orig = ptr; @@ -1500,15 +1528,18 @@ edit_strp (DSO *dso, unsigned char *ptr, int phase, bool handled_strp) if (! handled_strp) { size_t idx = do_read_32_relocated (ptr); - record_existing_string_entry_idx (&dso->strings, idx); + record_existing_string_entry_idx (line_strp, dso, idx); } } - else if (need_strp_update) /* && phase == 1 */ + else if (line_strp + ? need_line_strp_update : need_strp_update) /* && phase == 1 */ { struct stridxentry *entry; size_t idx, new_idx; + struct strings *strings = (line_strp + ? &dso->debug_line_str : &dso->debug_str); idx = do_read_32_relocated (ptr); - entry = string_find_entry (&dso->strings, idx); + entry = string_find_entry (strings, idx); new_idx = strent_offset (entry->entry); do_write_32_relocated (ptr, new_idx); } @@ -1759,6 +1790,254 @@ read_dwarf4_line (DSO *dso, unsigned char *ptr, char *comp_dir, return true; } +/* Called by read_dwarf5_line first for directories and then file + names as they both have the same format. */ +static bool +read_dwarf5_line_entries (DSO *dso, unsigned char **ptrp, + struct line_table *table, int phase, + char ***dirs, int *ndir, + const char *entry_name) +{ + /* directory_entry_format_count */ + /* file_name_entry_format_count */ + unsigned format_count = read_8 (*ptrp); + + unsigned char *formats = *ptrp; + + /* directory_entry_format */ + /* file_name_entry_format */ + for (unsigned formati = 0; formati < format_count; ++formati) + { + read_uleb128 (*ptrp); + read_uleb128 (*ptrp); + } + + /* directories_count */ + /* file_names_count */ + unsigned entry_count = read_uleb128 (*ptrp); + + bool collecting_dirs = dest_dir && phase == 0 && *dirs == NULL; + bool writing_files = dest_dir && phase == 0 && *dirs != NULL; + if (collecting_dirs) + { + *ndir = entry_count; + *dirs = malloc (entry_count * sizeof (char *)); + if (*dirs == NULL) + error (1, errno, "%s: Could not allocate debug_line dirs", + dso->filename); + } + + /* directories */ + /* file_names */ + for (unsigned entryi = 0; entryi < entry_count; ++entryi) + { + char *dir = NULL; + char *file = NULL;; + unsigned char *format_ptr = formats; + for (unsigned formati = 0; formati < format_count; ++formati) + { + unsigned lnct = read_uleb128 (format_ptr); + unsigned form = read_uleb128 (format_ptr); + bool handled_form = false; + bool handled_strp = false; + bool line_strp = form == DW_FORM_line_strp; + if (lnct == DW_LNCT_path) + { + switch (form) + { + case DW_FORM_strp: + case DW_FORM_line_strp: + if (dest_dir && phase == 0) + { + size_t idx = do_read_32_relocated (*ptrp); + if (record_file_string_entry_idx (line_strp, dso, idx)) + { + if (line_strp) + need_line_strp_update = true; + else + need_strp_update = true; + } + handled_strp = true; + if (collecting_dirs || writing_files) + { + debug_section *sec = &debug_sections[line_strp + ? DEBUG_LINE_STR : DEBUG_STR]; + if (collecting_dirs) + dir = (char *)sec->data + idx; + if (writing_files) + file = (char *)sec->data + idx; + } + } + break; + default: + error (0, 0, "%s: Unsupported " + ".debug_line %s %u path DW_FORM_0x%x", + dso->filename, entry_name, entryi, form); + return false; + } + } + if (writing_files && lnct == DW_LNCT_directory_index) + { + int dirndx; + switch (form) + { + case DW_FORM_udata: + handled_form = true; + dirndx = read_uleb128 (*ptrp); + break; + case DW_FORM_data1: + dirndx = **ptrp; + break; + case DW_FORM_data2: + dirndx = do_read_16 (*ptrp); + break; + case DW_FORM_data4: + dirndx = do_read_32 (*ptrp); + break; + default: + error (0, 0, "%s: Unsupported " + ".debug_line %s %u dirndx DW_FORM_0x%x", + dso->filename, entry_name, entryi, form); + return false; + } + + if (dirndx > *ndir) + { + error (0, 0, "%s: Bad dir number %u in .debug_line %s", + dso->filename, entryi, entry_name); + return false; + } + dir = (*dirs)[dirndx]; + } + + switch (form) + { + case DW_FORM_strp: + case DW_FORM_line_strp: + edit_strp (dso, line_strp, *ptrp, phase, handled_strp); + break; + } + + if (!handled_form) + { + switch (skip_form (dso, &form, ptrp)) + { + case FORM_OK: + break; + case FORM_ERROR: + return false; + case FORM_INDIRECT: + error (0, 0, "%s: Unsupported " + ".debug_line %s %u DW_FORM_indirect", + dso->filename, entry_name, entryi); + return false; + } + } + } + + if (collecting_dirs) + (*dirs)[entryi] = dir; + + if (writing_files) + { + char *comp_dir = (*dirs)[0]; + size_t comp_dir_len = strlen(comp_dir); + size_t file_len = strlen (file); + size_t dir_len = strlen (dir); + + char *s = malloc (comp_dir_len + 1 + file_len + 1 + dir_len + 1); + if (s == NULL) + { + error (0, ENOMEM, "%s: Reading file table", dso->filename); + return false; + } + if (file[0] == '/') + { + memcpy (s, file, file_len + 1); + } + else if (dir[0] == '/') + { + memcpy (s, dir, dir_len); + s[dir_len] = '/'; + memcpy (s + dir_len + 1, file, file_len + 1); + } + else + { + char *p = s; + if (comp_dir_len != 0) + { + memcpy (s, comp_dir, comp_dir_len); + s[comp_dir_len] = '/'; + p += comp_dir_len + 1; + } + memcpy (p, dir, dir_len); + p[dir_len] = '/'; + memcpy (p + dir_len + 1, file, file_len + 1); + } + canonicalize_path (s, s); + if (list_file_fd != -1) + { + const char *p = NULL; + if (base_dir == NULL) + p = s; + else + { + p = skip_dir_prefix (s, base_dir); + if (p == NULL && dest_dir != NULL) + p = skip_dir_prefix (s, dest_dir); + } + + if (p) + { + size_t size = strlen (p) + 1; + while (size > 0) + { + ssize_t ret = write (list_file_fd, p, size); + if (ret == -1) + break; + size -= ret; + p += ret; + } + } + } + + free (s); + } + } + + return true; +} + +/* Part of read_dwarf2_line processing DWARF-5. */ +static bool +read_dwarf5_line (DSO *dso, unsigned char *ptr, struct line_table *table, + int phase) +{ + char **dirs = NULL; + int ndir; + /* Skip header. */ + ptr += (4 /* unit len */ + + 2 /* version */ + + (table->version < 5 ? 0 : 0 + + 1 /* address_size */ + + 1 /* segment_selector*/) + + 4 /* header len */ + + 1 /* min instr len */ + + (table->version >= 4) /* max op per instr, if version >= 4 */ + + 1 /* default is stmt */ + + 1 /* line base */ + + 1 /* line range */ + + 1 /* opcode base */ + + table->opcode_base - 1); /* opcode len table */ + + bool retval = (read_dwarf5_line_entries (dso, &ptr, table, phase, + &dirs, &ndir, "directory") + && read_dwarf5_line_entries (dso, &ptr, table, phase, + &dirs, &ndir, "file name")); + free (dirs); + return retval; +} + /* Called during phase zero for each debug_line table referenced from .debug_info. Outputs all source files seen and records any adjustments needed in the debug_list data structures. Returns true @@ -1778,6 +2057,9 @@ read_dwarf2_line (DSO *dso, uint32_t off, char *comp_dir) ptr = debug_sections[DEBUG_LINE].data + off; ptr += (4 /* unit len */ + 2 /* version */ + + (table->version < 5 ? 0 : 0 + + 1 /* address_size */ + + 1 /* segment_selector*/) + 4 /* header len */ + 1 /* min instr len */ + (table->version >= 4) /* max op per instr, if version >= 4 */ @@ -1787,8 +2069,13 @@ read_dwarf2_line (DSO *dso, uint32_t off, char *comp_dir) + 1 /* opcode base */ + table->opcode_base - 1); /* opcode len table */ - if (! read_dwarf4_line (dso, ptr, comp_dir, table)) - return false; + /* DWARF version 5 line tables won't change size. But they might need + [line]strp recording/updates. Handle that part later. */ + if (table->version < 5) + { + if (! read_dwarf4_line (dso, ptr, comp_dir, table)) + return false; + } dso->lines.debug_lines_len += 4 + table->unit_length + table->size_diff; return table->replace_dirs || table->replace_files; @@ -1807,20 +2094,22 @@ find_new_list_offs (struct debug_lines *lines, size_t idx) return table->new_idx; } -/* Read DW_FORM_strp collecting compilation directory. */ +/* Read DW_FORM_strp or DW_FORM_line_strp collecting compilation directory. */ static void -edit_attributes_str_comp_dir (DSO *dso, unsigned char **ptrp, int phase, - char **comp_dirp, bool *handled_strpp) +edit_attributes_str_comp_dir (bool line_strp, DSO *dso, unsigned char **ptrp, + int phase, char **comp_dirp, bool *handled_strpp) { const char *dir; size_t idx = do_read_32_relocated (*ptrp); /* In phase zero we collect the comp_dir. */ if (phase == 0) { - if (idx >= debug_sections[DEBUG_STR].size) - error (1, 0, "%s: Bad string pointer index %zd for comp_dir", - dso->filename, idx); - dir = (char *) debug_sections[DEBUG_STR].data + idx; + debug_section *sec = &debug_sections[line_strp + ? DEBUG_LINE_STR : DEBUG_STR]; + if (sec->data == NULL || idx >= sec->size) + error (1, 0, "%s: Bad string pointer index %zd for comp_dir (%s)", + dso->filename, idx, sec->name); + dir = (char *) sec->data + idx; free (*comp_dirp); *comp_dirp = strdup (dir); @@ -1828,8 +2117,13 @@ edit_attributes_str_comp_dir (DSO *dso, unsigned char **ptrp, int phase, if (dest_dir != NULL && phase == 0) { - if (record_file_string_entry_idx (&dso->strings, idx)) - need_strp_update = true; + if (record_file_string_entry_idx (line_strp, dso, idx)) + { + if (line_strp) + need_line_strp_update = true; + else + need_strp_update = true; + } *handled_strpp = true; } } @@ -1937,17 +2231,24 @@ edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase) } } } - else if (form == DW_FORM_strp && - debug_sections[DEBUG_STR].data) - edit_attributes_str_comp_dir (dso, &ptr, phase, &comp_dir, + else if (form == DW_FORM_strp) + edit_attributes_str_comp_dir (false /* line_strp */, dso, + &ptr, phase, &comp_dir, &handled_strp); + else if (form == DW_FORM_line_strp) + edit_attributes_str_comp_dir (true /* line_strp */, dso, &ptr, + phase, &comp_dir, &handled_strp); } else if ((t->tag == DW_TAG_compile_unit || t->tag == DW_TAG_partial_unit) - && t->attr[i].attr == DW_AT_name - && form == DW_FORM_strp - && debug_sections[DEBUG_STR].data) + && ((form == DW_FORM_strp + && debug_sections[DEBUG_STR].data) + || (form == DW_FORM_line_strp + && debug_sections[DEBUG_LINE_STR].data)) + && t->attr[i].attr == DW_AT_name) { + bool line_strp = form == DW_FORM_line_strp; + /* DW_AT_name is the primary file for this compile unit. If starting with / it is a full path name. Note that we don't handle DW_FORM_string in this @@ -1957,11 +2258,14 @@ edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase) /* In phase zero we will look for a comp_dir to use. */ if (phase == 0) { - if (idx >= debug_sections[DEBUG_STR].size) + debug_section *sec = &debug_sections[line_strp + ? DEBUG_LINE_STR + : DEBUG_STR]; + if (idx >= sec->size) error (1, 0, - "%s: Bad string pointer index %zd for unit name", - dso->filename, idx); - char *name = (char *) debug_sections[DEBUG_STR].data + idx; + "%s: Bad string pointer index %zd for unit name (%s)", + dso->filename, idx, sec->name); + char *name = (char *) sec->data + idx; if (*name == '/' && comp_dir == NULL) { char *enddir = strrchr (name, '/'); @@ -1982,8 +2286,13 @@ edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase) pass (1) stores it (the new index). */ if (dest_dir && phase == 0) { - if (record_file_string_entry_idx (&dso->strings, idx)) - need_strp_update = true; + if (record_file_string_entry_idx (line_strp, dso, idx)) + { + if (line_strp) + need_line_strp_update = true; + else + need_strp_update = true; + } handled_strp = true; } } @@ -1991,7 +2300,10 @@ edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase) switch (form) { case DW_FORM_strp: - edit_strp (dso, ptr, phase, handled_strp); + edit_strp (dso, false /* line_strp */, ptr, phase, handled_strp); + break; + case DW_FORM_line_strp: + edit_strp (dso, true /* line_strp */, ptr, phase, handled_strp); break; } @@ -2196,11 +2508,11 @@ edit_info (DSO *dso, int phase, struct debug_section *sec) /* Rebuild .debug_str. */ static void -edit_dwarf2_any_str (DSO *dso) +edit_dwarf2_any_str (DSO *dso, struct strings *strings, debug_section *secp) { - Strtab *strtab = dso->strings.str_tab; - Elf_Data *strdata = debug_sections[DEBUG_STR].elf_data; - int strndx = debug_sections[DEBUG_STR].sec; + Strtab *strtab = strings->str_tab; + Elf_Data *strdata = secp->elf_data; + int strndx = secp->sec; Elf_Scn *strscn = dso->scn[strndx]; /* Out with the old. */ @@ -2212,8 +2524,8 @@ edit_dwarf2_any_str (DSO *dso) but the old ebl version will just abort on out of memory... */ strtab_finalize (strtab, strdata); - debug_sections[DEBUG_STR].size = strdata->d_size; - dso->strings.str_buf = strdata->d_buf; + secp->size = strdata->d_size; + strings->str_buf = strdata->d_buf; } static int @@ -2359,12 +2671,14 @@ edit_dwarf2 (DSO *dso) bool info_rel_updated = false; bool types_rel_updated = false; bool macro_rel_updated = false; + bool line_rel_updated = false; for (phase = 0; phase < 2; phase++) { /* If we don't need to update anyhing, skip phase 1. */ if (phase == 1 && !need_strp_update + && !need_line_strp_update && !need_string_replacement && !need_stmt_update) break; @@ -2582,15 +2896,14 @@ edit_dwarf2 (DSO *dso) if (phase == 0) { size_t idx = read_32_relocated (ptr); - record_existing_string_entry_idx (&dso->strings, - idx); + record_existing_string_entry_idx (false, dso, idx); } else { struct stridxentry *entry; size_t idx, new_idx; idx = do_read_32_relocated (ptr); - entry = string_find_entry (&dso->strings, idx); + entry = string_find_entry (&dso->debug_str, idx); new_idx = strent_offset (entry->entry); write_32_relocated (ptr, new_idx); } @@ -2610,24 +2923,50 @@ edit_dwarf2 (DSO *dso) } } - /* Same for the debug_str section. Make sure everything is - in place for phase 1 updating of debug_info + + /* Now handle all the DWARF5 line tables, they contain strp + and/or line_strp entries that need to be registered/rewritten. */ + setup_relbuf(dso, &debug_sections[DEBUG_LINE], &reltype); + rel_updated = false; + + /* edit_dwarf2_line will have set this up, unless there are no + moved/resized (DWARF4) lines. In which case we can just use + the original section data. new_idx will have been setup + correctly, even if it is the same as old_idx. */ + unsigned char *line_buf = (unsigned char *)dso->lines.line_buf; + if (line_buf == NULL) + line_buf = debug_sections[DEBUG_LINE].data; + for (int ldx = 0; ldx < dso->lines.used; ldx++) + { + struct line_table *t = &dso->lines.table[ldx]; + if (t->version >= 5) + read_dwarf5_line (dso, line_buf + t->new_idx, t, phase); + } + if (rel_updated) + line_rel_updated = true; + + /* Same for the debug_str and debug_line_str sections. + Make sure everything is in place for phase 1 updating of debug_info references. */ if (phase == 0 && need_strp_update) - edit_dwarf2_any_str (dso); - + edit_dwarf2_any_str (dso, &dso->debug_str, + &debug_sections[DEBUG_STR]); + if (phase == 0 && need_line_strp_update) + edit_dwarf2_any_str (dso, &dso->debug_line_str, + &debug_sections[DEBUG_LINE_STR]); } /* After phase 1 we might have rewritten the debug_info with new strp, strings and/or linep offsets. */ - if (need_strp_update || need_string_replacement || need_stmt_update) { + if (need_strp_update || need_line_strp_update + || need_string_replacement || need_stmt_update) { dirty_section (DEBUG_INFO); if (debug_sections[DEBUG_TYPES].data != NULL) dirty_section (DEBUG_TYPES); } if (need_strp_update || need_stmt_update) dirty_section (DEBUG_MACRO); - if (need_stmt_update) + if (need_stmt_update || need_line_strp_update) dirty_section (DEBUG_LINE); /* Update any relocations addends we might have touched. */ @@ -2653,6 +2992,9 @@ edit_dwarf2 (DSO *dso) } } + if (line_rel_updated) + update_rela_data (dso, &debug_sections[DEBUG_LINE]); + return 0; } @@ -2745,7 +3087,8 @@ fdopen_dso (int fd, const char *name) } dso->filename = (const char *) strdup (name); - setup_strings (&dso->strings); + setup_strings (&dso->debug_str); + setup_strings (&dso->debug_line_str); setup_lines (&dso->lines); return dso; @@ -2753,7 +3096,8 @@ error_out: if (dso) { free ((char *) dso->filename); - destroy_strings (&dso->strings); + destroy_strings (&dso->debug_str); + destroy_strings (&dso->debug_line_str); destroy_lines (&dso->lines); free (dso); } @@ -3034,7 +3378,9 @@ main (int argc, char *argv[]) in elfutils before 0.169 we will have to update and write out all section data if any data has changed (when ELF_F_LAYOUT was set). https://sourceware.org/bugzilla/show_bug.cgi?id=21199 */ - bool need_update = need_strp_update || need_stmt_update; + bool need_update = (need_strp_update + || need_line_strp_update + || need_stmt_update); #if !_ELFUTILS_PREREQ (0, 169) /* string replacements or build_id updates don't change section size. */ @@ -3106,10 +3452,12 @@ main (int argc, char *argv[]) GElf_Xword sec_size = shdr->sh_size; /* We might have changed the size (and content) of the - debug_str or debug_line section. */ + debug_str, debug_line_str or debug_line section. */ size_t secnum = elf_ndxscn (scn); if (secnum == debug_sections[DEBUG_STR].sec) sec_size = debug_sections[DEBUG_STR].size; + if (secnum == debug_sections[DEBUG_LINE_STR].sec) + sec_size = debug_sections[DEBUG_LINE_STR].size; if (secnum == debug_sections[DEBUG_LINE].sec) sec_size = debug_sections[DEBUG_LINE].size; @@ -3179,7 +3527,8 @@ main (int argc, char *argv[]) chmod (file, stat_buf.st_mode); free ((char *) dso->filename); - destroy_strings (&dso->strings); + destroy_strings (&dso->debug_str); + destroy_strings (&dso->debug_line_str); destroy_lines (&dso->lines); free (dso); -- 2.18.4