From 070683775b28a3d32427fcc6cd20ef1edea57047 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Wed, 29 Jul 2020 22:27:41 +0200 Subject: [PATCH 1/2] [NFC] debugedit: Reindent edit_dwarf2(). --- tools/debugedit.c | 642 +++++++++++++++++++++++----------------------- 1 file changed, 321 insertions(+), 321 deletions(-) diff --git a/tools/debugedit.c b/tools/debugedit.c index 9f8dcd0fb6..dcacb23b7a 100644 --- a/tools/debugedit.c +++ b/tools/debugedit.c @@ -2100,385 +2100,385 @@ edit_dwarf2 (DSO *dso) return 1; } - if (debug_sections[DEBUG_INFO].data != NULL) - { - unsigned char *ptr, *endcu, *endsec; - uint32_t value; - htab_t abbrev; - struct abbrev_tag tag, *t; - int phase; - bool info_rel_updated = false; - bool macro_rel_updated = false; + if (debug_sections[DEBUG_INFO].data == NULL) + return 0; + + unsigned char *ptr, *endcu, *endsec; + uint32_t value; + htab_t abbrev; + struct abbrev_tag tag, *t; + int phase; + bool info_rel_updated = false; + bool macro_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_string_replacement + && !need_stmt_update) + break; - for (phase = 0; phase < 2; phase++) + ptr = debug_sections[DEBUG_INFO].data; + setup_relbuf(dso, &debug_sections[DEBUG_INFO], &reltype); + rel_updated = false; + endsec = ptr + debug_sections[DEBUG_INFO].size; + while (ptr < endsec) { - /* If we don't need to update anyhing, skip phase 1. */ - if (phase == 1 - && !need_strp_update - && !need_string_replacement - && !need_stmt_update) - break; - - ptr = debug_sections[DEBUG_INFO].data; - setup_relbuf(dso, &debug_sections[DEBUG_INFO], &reltype); - rel_updated = false; - endsec = ptr + debug_sections[DEBUG_INFO].size; - while (ptr < endsec) + if (ptr + 11 > endsec) { - if (ptr + 11 > endsec) - { - error (0, 0, "%s: .debug_info CU header too small", - dso->filename); - return 1; - } + error (0, 0, "%s: .debug_info CU header too small", + dso->filename); + return 1; + } - endcu = ptr + 4; - endcu += read_32 (ptr); - if (endcu == ptr + 0xffffffff) - { - error (0, 0, "%s: 64-bit DWARF not supported", dso->filename); - return 1; - } + endcu = ptr + 4; + endcu += read_32 (ptr); + if (endcu == ptr + 0xffffffff) + { + error (0, 0, "%s: 64-bit DWARF not supported", dso->filename); + return 1; + } - if (endcu > endsec) - { - error (0, 0, "%s: .debug_info too small", dso->filename); - return 1; - } + if (endcu > endsec) + { + error (0, 0, "%s: .debug_info too small", dso->filename); + return 1; + } - cu_version = read_16 (ptr); - if (cu_version != 2 && cu_version != 3 && cu_version != 4) - { - error (0, 0, "%s: DWARF version %d unhandled", dso->filename, - cu_version); - return 1; - } + cu_version = read_16 (ptr); + if (cu_version != 2 && cu_version != 3 && cu_version != 4) + { + error (0, 0, "%s: DWARF version %d unhandled", dso->filename, + cu_version); + return 1; + } - value = read_32_relocated (ptr); - if (value >= debug_sections[DEBUG_ABBREV].size) + value = read_32_relocated (ptr); + if (value >= debug_sections[DEBUG_ABBREV].size) + { + if (debug_sections[DEBUG_ABBREV].data == NULL) + error (0, 0, "%s: .debug_abbrev not present", dso->filename); + else + error (0, 0, "%s: DWARF CU abbrev offset too large", + dso->filename); + return 1; + } + + if (ptr_size == 0) + { + ptr_size = read_8 (ptr); + if (ptr_size != 4 && ptr_size != 8) { - if (debug_sections[DEBUG_ABBREV].data == NULL) - error (0, 0, "%s: .debug_abbrev not present", dso->filename); - else - error (0, 0, "%s: DWARF CU abbrev offset too large", - dso->filename); + error (0, 0, "%s: Invalid DWARF pointer size %d", + dso->filename, ptr_size); return 1; } + } + else if (read_8 (ptr) != ptr_size) + { + error (0, 0, "%s: DWARF pointer size differs between CUs", + dso->filename); + return 1; + } - if (ptr_size == 0) - { - ptr_size = read_8 (ptr); - if (ptr_size != 4 && ptr_size != 8) - { - error (0, 0, "%s: Invalid DWARF pointer size %d", - dso->filename, ptr_size); - return 1; - } - } - else if (read_8 (ptr) != ptr_size) + abbrev = read_abbrev (dso, + debug_sections[DEBUG_ABBREV].data + value); + if (abbrev == NULL) + return 1; + + while (ptr < endcu) + { + tag.entry = read_uleb128 (ptr); + if (tag.entry == 0) + continue; + t = htab_find_with_hash (abbrev, &tag, tag.entry); + if (t == NULL) { - error (0, 0, "%s: DWARF pointer size differs between CUs", - dso->filename); + error (0, 0, "%s: Could not find DWARF abbreviation %d", + dso->filename, tag.entry); + htab_delete (abbrev); return 1; } - abbrev = read_abbrev (dso, - debug_sections[DEBUG_ABBREV].data + value); - if (abbrev == NULL) - return 1; + ptr = edit_attributes (dso, ptr, t, phase); + if (ptr == NULL) + break; + } - while (ptr < endcu) + htab_delete (abbrev); + } + + /* Remember whether any .debug_info relocations might need + to be updated. */ + info_rel_updated = rel_updated; + + /* We might have to recalculate/rewrite the debug_line + section. We need to do that before going into phase one + so we have all new offsets. We do this separately from + scanning the dirs/file names because the DW_AT_stmt_lists + might not be in order or skip some padding we might have + to (re)move. */ + if (phase == 0 && need_stmt_update) + { + edit_dwarf2_line (dso); + + /* The line table programs will be moved + forward/backwards a bit in the new data. Update the + debug_line relocations to the new offsets. */ + int rndx = debug_sections[DEBUG_LINE].relsec; + if (rndx != 0) + { + LINE_REL *rbuf; + size_t rels; + Elf_Data *rdata = elf_getdata (dso->scn[rndx], NULL); + int rtype = dso->shdr[rndx].sh_type; + rels = dso->shdr[rndx].sh_size / dso->shdr[rndx].sh_entsize; + rbuf = malloc (rels * sizeof (LINE_REL)); + if (rbuf == NULL) + error (1, errno, "%s: Could not allocate line relocations", + dso->filename); + + /* Sort them by offset into section. */ + for (size_t i = 0; i < rels; i++) { - tag.entry = read_uleb128 (ptr); - if (tag.entry == 0) - continue; - t = htab_find_with_hash (abbrev, &tag, tag.entry); - if (t == NULL) + if (rtype == SHT_RELA) + { + GElf_Rela rela; + if (gelf_getrela (rdata, i, &rela) == NULL) + error (1, 0, "Couldn't get relocation: %s", + elf_errmsg (-1)); + rbuf[i].r_offset = rela.r_offset; + rbuf[i].ndx = i; + } + else { - error (0, 0, "%s: Could not find DWARF abbreviation %d", - dso->filename, tag.entry); - htab_delete (abbrev); - return 1; + GElf_Rel rel; + if (gelf_getrel (rdata, i, &rel) == NULL) + error (1, 0, "Couldn't get relocation: %s", + elf_errmsg (-1)); + rbuf[i].r_offset = rel.r_offset; + rbuf[i].ndx = i; } - - ptr = edit_attributes (dso, ptr, t, phase); - if (ptr == NULL) - break; } + qsort (rbuf, rels, sizeof (LINE_REL), line_rel_cmp); - htab_delete (abbrev); - } - - /* Remember whether any .debug_info relocations might need - to be updated. */ - info_rel_updated = rel_updated; - - /* We might have to recalculate/rewrite the debug_line - section. We need to do that before going into phase one - so we have all new offsets. We do this separately from - scanning the dirs/file names because the DW_AT_stmt_lists - might not be in order or skip some padding we might have - to (re)move. */ - if (phase == 0 && need_stmt_update) - { - edit_dwarf2_line (dso); - - /* The line table programs will be moved - forward/backwards a bit in the new data. Update the - debug_line relocations to the new offsets. */ - int rndx = debug_sections[DEBUG_LINE].relsec; - if (rndx != 0) + size_t lndx = 0; + for (size_t i = 0; i < rels; i++) { - LINE_REL *rbuf; - size_t rels; - Elf_Data *rdata = elf_getdata (dso->scn[rndx], NULL); - int rtype = dso->shdr[rndx].sh_type; - rels = dso->shdr[rndx].sh_size / dso->shdr[rndx].sh_entsize; - rbuf = malloc (rels * sizeof (LINE_REL)); - if (rbuf == NULL) - error (1, errno, "%s: Could not allocate line relocations", - dso->filename); - - /* Sort them by offset into section. */ - for (size_t i = 0; i < rels; i++) + /* These relocations only happen in ET_REL files + and are section offsets. */ + GElf_Addr r_offset; + size_t ndx = rbuf[i].ndx; + + GElf_Rel rel; + GElf_Rela rela; + if (rtype == SHT_RELA) { - if (rtype == SHT_RELA) - { - GElf_Rela rela; - if (gelf_getrela (rdata, i, &rela) == NULL) - error (1, 0, "Couldn't get relocation: %s", - elf_errmsg (-1)); - rbuf[i].r_offset = rela.r_offset; - rbuf[i].ndx = i; - } - else - { - GElf_Rel rel; - if (gelf_getrel (rdata, i, &rel) == NULL) - error (1, 0, "Couldn't get relocation: %s", - elf_errmsg (-1)); - rbuf[i].r_offset = rel.r_offset; - rbuf[i].ndx = i; - } + if (gelf_getrela (rdata, ndx, &rela) == NULL) + error (1, 0, "Couldn't get relocation: %s", + elf_errmsg (-1)); + r_offset = rela.r_offset; } - qsort (rbuf, rels, sizeof (LINE_REL), line_rel_cmp); - - size_t lndx = 0; - for (size_t i = 0; i < rels; i++) + else { - /* These relocations only happen in ET_REL files - and are section offsets. */ - GElf_Addr r_offset; - size_t ndx = rbuf[i].ndx; - - GElf_Rel rel; - GElf_Rela rela; - if (rtype == SHT_RELA) - { - if (gelf_getrela (rdata, ndx, &rela) == NULL) - error (1, 0, "Couldn't get relocation: %s", - elf_errmsg (-1)); - r_offset = rela.r_offset; - } - else - { - if (gelf_getrel (rdata, ndx, &rel) == NULL) - error (1, 0, "Couldn't get relocation: %s", - elf_errmsg (-1)); - r_offset = rel.r_offset; - } + if (gelf_getrel (rdata, ndx, &rel) == NULL) + error (1, 0, "Couldn't get relocation: %s", + elf_errmsg (-1)); + r_offset = rel.r_offset; + } - while (lndx < dso->lines.used - && r_offset > (dso->lines.table[lndx].old_idx - + 4 - + dso->lines.table[lndx].unit_length)) - lndx++; + while (lndx < dso->lines.used + && r_offset > (dso->lines.table[lndx].old_idx + + 4 + + dso->lines.table[lndx].unit_length)) + lndx++; - if (lndx >= dso->lines.used) - error (1, 0, - ".debug_line relocation offset out of range"); + if (lndx >= dso->lines.used) + error (1, 0, + ".debug_line relocation offset out of range"); - /* Offset (pointing into the line program) moves - from old to new index including the header - size diff. */ - r_offset += (ssize_t)((dso->lines.table[lndx].new_idx - - dso->lines.table[lndx].old_idx) - + dso->lines.table[lndx].size_diff); + /* Offset (pointing into the line program) moves + from old to new index including the header + size diff. */ + r_offset += (ssize_t)((dso->lines.table[lndx].new_idx + - dso->lines.table[lndx].old_idx) + + dso->lines.table[lndx].size_diff); - if (rtype == SHT_RELA) - { - rela.r_offset = r_offset; - if (gelf_update_rela (rdata, ndx, &rela) == 0) - error (1, 0, "Couldn't update relocation: %s", - elf_errmsg (-1)); - } - else - { - rel.r_offset = r_offset; - if (gelf_update_rel (rdata, ndx, &rel) == 0) - error (1, 0, "Couldn't update relocation: %s", - elf_errmsg (-1)); - } + if (rtype == SHT_RELA) + { + rela.r_offset = r_offset; + if (gelf_update_rela (rdata, ndx, &rela) == 0) + error (1, 0, "Couldn't update relocation: %s", + elf_errmsg (-1)); + } + else + { + rel.r_offset = r_offset; + if (gelf_update_rel (rdata, ndx, &rel) == 0) + error (1, 0, "Couldn't update relocation: %s", + elf_errmsg (-1)); } - - elf_flagdata (rdata, ELF_C_SET, ELF_F_DIRTY); - free (rbuf); } + + elf_flagdata (rdata, ELF_C_SET, ELF_F_DIRTY); + free (rbuf); } + } - /* 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) + /* 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) { - /* 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; + 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; + 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) + while (ptr < endsec) + { + if (!op) { - 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); - } - } - } + 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); - op = read_8 (ptr); - if (!op) - continue; - switch(op) + /* Update the line_offset if it is there. */ + if (line_offset) { - 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); - } + ptr += offset_len; 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); + new_idx = find_new_list_offs (&dso->lines, + idx); 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; + 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; + } } - } - /* Same for the debug_str section. Make sure everything is - in place for phase 1 updating of debug_info - references. */ - if (phase == 0 && need_strp_update) - { - Strtab *strtab = dso->strings.str_tab; - Elf_Data *strdata = debug_sections[DEBUG_STR].elf_data; - int strndx = debug_sections[DEBUG_STR].sec; - Elf_Scn *strscn = dso->scn[strndx]; - - /* Out with the old. */ - strdata->d_size = 0; - /* In with the new. */ - strdata = elf_newdata (strscn); - - /* We really should check whether we had enough memory, - 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; + 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. */ + if (phase == 0 && need_strp_update) + { + Strtab *strtab = dso->strings.str_tab; + Elf_Data *strdata = debug_sections[DEBUG_STR].elf_data; + int strndx = debug_sections[DEBUG_STR].sec; + Elf_Scn *strscn = dso->scn[strndx]; + + /* Out with the old. */ + strdata->d_size = 0; + /* In with the new. */ + strdata = elf_newdata (strscn); + + /* We really should check whether we had enough memory, + 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; } - /* 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) - 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 relocations addends we might have touched. */ - if (info_rel_updated) - update_rela_data (dso, &debug_sections[DEBUG_INFO]); + /* 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) + dirty_section (DEBUG_INFO); + if (need_strp_update || need_stmt_update) + dirty_section (DEBUG_MACRO); + if (need_stmt_update) + dirty_section (DEBUG_LINE); - if (macro_rel_updated) + /* 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) { - struct debug_section *macro_sec = &debug_sections[DEBUG_MACRO]; - while (macro_sec != NULL) - { - update_rela_data (dso, macro_sec); - macro_sec = macro_sec->next; - } + update_rela_data (dso, macro_sec); + macro_sec = macro_sec->next; } } From 97b4e7a44c9c62d4f8072f3a9abb639f9e5ff9c4 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Wed, 29 Jul 2020 22:30:43 +0200 Subject: [PATCH 2/2] debugedit: Fix missing relocation of .debug_types section. --- tools/debugedit.c | 222 ++++++++++++++++++++++++++-------------------- 1 file changed, 126 insertions(+), 96 deletions(-) diff --git a/tools/debugedit.c b/tools/debugedit.c index dcacb23b7a..aaa0d06614 100644 --- a/tools/debugedit.c +++ b/tools/debugedit.c @@ -1459,7 +1459,7 @@ edit_dwarf2_line (DSO *dso) adjustments needed in the debug_list data structures. Returns true if line_table needs to be rewrite either the dir or file paths. */ static bool -read_dwarf2_line (DSO *dso, uint32_t off, char *comp_dir) +read_dwarf2_line (DSO *dso, int info_scn_ix, uint32_t off, char *comp_dir) { unsigned char *ptr, *dir; unsigned char **dirt; @@ -1470,7 +1470,7 @@ read_dwarf2_line (DSO *dso, uint32_t off, char *comp_dir) if (get_line_table (dso, off, &table) == false || table == NULL) { - if (table != NULL) + if (table != NULL && info_scn_ix == DEBUG_INFO) error (0, 0, ".debug_line offset 0x%x referenced multiple times", off); return false; @@ -1644,7 +1644,8 @@ find_new_list_offs (struct debug_lines *lines, size_t idx) abbrev data is consumed. In phase zero data is collected, in phase one data might be replaced/updated. */ static unsigned char * -edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase) +edit_attributes (DSO *dso, int info_scn_ix, unsigned char *ptr, + struct abbrev_tag *t, int phase) { int i; uint32_t list_offs; @@ -1942,7 +1943,7 @@ edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase) separately (at the end of phase zero after all CUs have been scanned in dwarf2_edit). */ if (phase == 0 && found_list_offs - && read_dwarf2_line (dso, list_offs, comp_dir)) + && read_dwarf2_line (dso, info_scn_ix, list_offs, comp_dir)) need_stmt_update = true; free (comp_dir); @@ -1964,6 +1965,114 @@ line_rel_cmp (const void *a, const void *b) return 0; } +static int +edit_info (DSO *dso, int phase, int scn_ix) +{ + unsigned char *ptr, *endcu, *endsec; + uint32_t value; + htab_t abbrev; + struct abbrev_tag tag, *t; + + assert (scn_ix == DEBUG_INFO || scn_ix == DEBUG_TYPES); + ptr = debug_sections[scn_ix].data; + if (ptr == NULL) + return 0; + + setup_relbuf(dso, &debug_sections[scn_ix], &reltype); + endsec = ptr + debug_sections[scn_ix].size; + while (ptr < endsec) + { + if (ptr + (scn_ix == DEBUG_INFO ? 11 : 23) > endsec) + { + error (0, 0, "%s: %s CU header too small", + dso->filename, debug_sections[scn_ix].name); + return 1; + } + + endcu = ptr + 4; + endcu += read_32 (ptr); + if (endcu == ptr + 0xffffffff) + { + error (0, 0, "%s: 64-bit DWARF not supported", dso->filename); + return 1; + } + + if (endcu > endsec) + { + error (0, 0, "%s: %s too small", dso->filename, + debug_sections[scn_ix].name); + return 1; + } + + cu_version = read_16 (ptr); + if (cu_version != 2 && cu_version != 3 && cu_version != 4) + { + error (0, 0, "%s: DWARF version %d unhandled", dso->filename, + cu_version); + return 1; + } + + value = read_32_relocated (ptr); + if (value >= debug_sections[DEBUG_ABBREV].size) + { + if (debug_sections[DEBUG_ABBREV].data == NULL) + error (0, 0, "%s: .debug_abbrev not present", dso->filename); + else + error (0, 0, "%s: DWARF CU abbrev offset too large", + dso->filename); + return 1; + } + + if (ptr_size == 0) + { + ptr_size = read_8 (ptr); + if (ptr_size != 4 && ptr_size != 8) + { + error (0, 0, "%s: Invalid DWARF pointer size %d", + dso->filename, ptr_size); + return 1; + } + } + else if (read_8 (ptr) != ptr_size) + { + error (0, 0, "%s: DWARF pointer size differs between CUs", + dso->filename); + return 1; + } + + if (scn_ix == DEBUG_TYPES) + ptr += 12; /* Skip type_signature and type_offset. */ + + abbrev = read_abbrev (dso, + debug_sections[DEBUG_ABBREV].data + value); + if (abbrev == NULL) + return 1; + + while (ptr < endcu) + { + tag.entry = read_uleb128 (ptr); + if (tag.entry == 0) + continue; + t = htab_find_with_hash (abbrev, &tag, tag.entry); + if (t == NULL) + { + error (0, 0, "%s: Could not find DWARF abbreviation %d", + dso->filename, tag.entry); + htab_delete (abbrev); + return 1; + } + + ptr = edit_attributes (dso, scn_ix, ptr, t, phase); + if (ptr == NULL) + break; + } + + htab_delete (abbrev); + } + + return 0; +} + static int edit_dwarf2 (DSO *dso) { @@ -2103,12 +2212,10 @@ edit_dwarf2 (DSO *dso) if (debug_sections[DEBUG_INFO].data == NULL) return 0; - unsigned char *ptr, *endcu, *endsec; - uint32_t value; - htab_t abbrev; - struct abbrev_tag tag, *t; + unsigned char *ptr, *endsec; int phase; bool info_rel_updated = false; + bool types_rel_updated = false; bool macro_rel_updated = false; for (phase = 0; phase < 2; phase++) @@ -2120,100 +2227,21 @@ edit_dwarf2 (DSO *dso) && !need_stmt_update) break; - ptr = debug_sections[DEBUG_INFO].data; - setup_relbuf(dso, &debug_sections[DEBUG_INFO], &reltype); rel_updated = false; - endsec = ptr + debug_sections[DEBUG_INFO].size; - while (ptr < endsec) - { - if (ptr + 11 > endsec) - { - error (0, 0, "%s: .debug_info CU header too small", - dso->filename); - return 1; - } - - endcu = ptr + 4; - endcu += read_32 (ptr); - if (endcu == ptr + 0xffffffff) - { - error (0, 0, "%s: 64-bit DWARF not supported", dso->filename); - return 1; - } - - if (endcu > endsec) - { - error (0, 0, "%s: .debug_info too small", dso->filename); - return 1; - } - - cu_version = read_16 (ptr); - if (cu_version != 2 && cu_version != 3 && cu_version != 4) - { - error (0, 0, "%s: DWARF version %d unhandled", dso->filename, - cu_version); - return 1; - } - - value = read_32_relocated (ptr); - if (value >= debug_sections[DEBUG_ABBREV].size) - { - if (debug_sections[DEBUG_ABBREV].data == NULL) - error (0, 0, "%s: .debug_abbrev not present", dso->filename); - else - error (0, 0, "%s: DWARF CU abbrev offset too large", - dso->filename); - return 1; - } - - if (ptr_size == 0) - { - ptr_size = read_8 (ptr); - if (ptr_size != 4 && ptr_size != 8) - { - error (0, 0, "%s: Invalid DWARF pointer size %d", - dso->filename, ptr_size); - return 1; - } - } - else if (read_8 (ptr) != ptr_size) - { - error (0, 0, "%s: DWARF pointer size differs between CUs", - dso->filename); - return 1; - } - - abbrev = read_abbrev (dso, - debug_sections[DEBUG_ABBREV].data + value); - if (abbrev == NULL) - return 1; - - while (ptr < endcu) - { - tag.entry = read_uleb128 (ptr); - if (tag.entry == 0) - continue; - t = htab_find_with_hash (abbrev, &tag, tag.entry); - if (t == NULL) - { - error (0, 0, "%s: Could not find DWARF abbreviation %d", - dso->filename, tag.entry); - htab_delete (abbrev); - return 1; - } - - ptr = edit_attributes (dso, ptr, t, phase); - if (ptr == NULL) - break; - } - - htab_delete (abbrev); - } + if (edit_info (dso, phase, DEBUG_INFO)) + return 1; /* Remember whether any .debug_info relocations might need to be updated. */ info_rel_updated = rel_updated; + if (edit_info (dso, phase, DEBUG_TYPES)) + return 1; + + /* Remember whether any .debug_types relocations might need + to be updated. */ + types_rel_updated = rel_updated; + /* We might have to recalculate/rewrite the debug_line section. We need to do that before going into phase one so we have all new offsets. We do this separately from @@ -2471,6 +2499,8 @@ edit_dwarf2 (DSO *dso) /* Update any relocations addends we might have touched. */ if (info_rel_updated) update_rela_data (dso, &debug_sections[DEBUG_INFO]); + if (types_rel_updated) + update_rela_data (dso, &debug_sections[DEBUG_TYPES]); if (macro_rel_updated) {