You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
455 lines
13 KiB
455 lines
13 KiB
From bab443ab4f756ef80f814af0353143f41e90e6a6 Mon Sep 17 00:00:00 2001 |
|
From: Jan Kratochvil <jan.kratochvil@redhat.com> |
|
Date: Mon, 17 Aug 2020 21:58:19 +0200 |
|
Subject: [PATCH 4/6] [NFC] debugedit: Move code to separate functions. |
|
|
|
New functions edit_strp, skip_form and edit_attributes_str_comp_dir |
|
called by edit_attributes. |
|
Split part of read_dwarf2_line into a read_dwarf4_line function. |
|
New function edit_dwarf2_any_str called by edit_dwarf2 at the end of |
|
phase 0 to rebuild .debug_str. |
|
--- |
|
tools/debugedit.c | 367 ++++++++++++++++++++++++++-------------------- |
|
1 file changed, 212 insertions(+), 155 deletions(-) |
|
|
|
diff --git a/tools/debugedit.c b/tools/debugedit.c |
|
index 87c1cd622..7464883c5 100644 |
|
--- a/tools/debugedit.c |
|
+++ b/tools/debugedit.c |
|
@@ -1457,37 +1457,128 @@ edit_dwarf2_line (DSO *dso) |
|
} |
|
} |
|
|
|
-/* 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 |
|
- if line_table needs to be rewrite either the dir or file paths. */ |
|
+/* Record or adjust (according to phase) DW_FORM_strp. */ |
|
+static void |
|
+edit_strp (DSO *dso, unsigned char *ptr, int phase, bool handled_strp) |
|
+{ |
|
+ unsigned char *ptr_orig = ptr; |
|
+ |
|
+ /* In the first pass we collect all strings, in the |
|
+ second we put the new references back (if there are |
|
+ any changes). */ |
|
+ if (phase == 0) |
|
+ { |
|
+ /* handled_strp is set for attributes referring to |
|
+ files. If it is set the string is already |
|
+ recorded. */ |
|
+ if (! handled_strp) |
|
+ { |
|
+ size_t idx = do_read_32_relocated (ptr); |
|
+ record_existing_string_entry_idx (&dso->strings, idx); |
|
+ } |
|
+ } |
|
+ else if (need_strp_update) /* && phase == 1 */ |
|
+ { |
|
+ 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); |
|
+ do_write_32_relocated (ptr, new_idx); |
|
+ } |
|
+ |
|
+ assert (ptr == ptr_orig); |
|
+} |
|
+ |
|
+/* Adjust *PTRP after the current *FORMP, update *FORMP for FORM_INDIRECT. */ |
|
+static enum { FORM_OK, FORM_ERROR, FORM_INDIRECT } |
|
+skip_form (DSO *dso, uint32_t *formp, unsigned char **ptrp) |
|
+{ |
|
+ size_t len = 0; |
|
+ |
|
+ switch (*formp) |
|
+ { |
|
+ case DW_FORM_ref_addr: |
|
+ if (cu_version == 2) |
|
+ *ptrp += ptr_size; |
|
+ else |
|
+ *ptrp += 4; |
|
+ break; |
|
+ case DW_FORM_flag_present: |
|
+ break; |
|
+ case DW_FORM_addr: |
|
+ *ptrp += ptr_size; |
|
+ break; |
|
+ case DW_FORM_ref1: |
|
+ case DW_FORM_flag: |
|
+ case DW_FORM_data1: |
|
+ ++*ptrp; |
|
+ break; |
|
+ case DW_FORM_ref2: |
|
+ case DW_FORM_data2: |
|
+ *ptrp += 2; |
|
+ break; |
|
+ case DW_FORM_ref4: |
|
+ case DW_FORM_data4: |
|
+ case DW_FORM_sec_offset: |
|
+ *ptrp += 4; |
|
+ break; |
|
+ case DW_FORM_ref8: |
|
+ case DW_FORM_data8: |
|
+ case DW_FORM_ref_sig8: |
|
+ *ptrp += 8; |
|
+ break; |
|
+ case DW_FORM_sdata: |
|
+ case DW_FORM_ref_udata: |
|
+ case DW_FORM_udata: |
|
+ read_uleb128 (*ptrp); |
|
+ break; |
|
+ case DW_FORM_strp: |
|
+ *ptrp += 4; |
|
+ break; |
|
+ case DW_FORM_string: |
|
+ *ptrp = (unsigned char *) strchr ((char *)*ptrp, '\0') + 1; |
|
+ break; |
|
+ case DW_FORM_indirect: |
|
+ *formp = read_uleb128 (*ptrp); |
|
+ return FORM_INDIRECT; |
|
+ case DW_FORM_block1: |
|
+ len = *(*ptrp)++; |
|
+ break; |
|
+ case DW_FORM_block2: |
|
+ len = read_16 (*ptrp); |
|
+ *formp = DW_FORM_block1; |
|
+ break; |
|
+ case DW_FORM_block4: |
|
+ len = read_32 (*ptrp); |
|
+ *formp = DW_FORM_block1; |
|
+ break; |
|
+ case DW_FORM_block: |
|
+ case DW_FORM_exprloc: |
|
+ len = read_uleb128 (*ptrp); |
|
+ *formp = DW_FORM_block1; |
|
+ assert (len < UINT_MAX); |
|
+ break; |
|
+ default: |
|
+ error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename, *formp); |
|
+ return FORM_ERROR; |
|
+ } |
|
+ |
|
+ if (*formp == DW_FORM_block1) |
|
+ *ptrp += len; |
|
+ |
|
+ return FORM_OK; |
|
+} |
|
+ |
|
+/* Part of read_dwarf2_line processing DWARF-4. */ |
|
static bool |
|
-read_dwarf2_line (DSO *dso, uint32_t off, char *comp_dir) |
|
+read_dwarf4_line (DSO *dso, unsigned char *ptr, char *comp_dir, |
|
+ struct line_table *table) |
|
{ |
|
- unsigned char *ptr, *dir; |
|
unsigned char **dirt; |
|
uint32_t value, dirt_cnt; |
|
size_t comp_dir_len = !comp_dir ? 0 : strlen (comp_dir); |
|
- struct line_table *table; |
|
- |
|
- if (get_line_table (dso, off, &table) == false |
|
- || table == NULL) |
|
- return false; |
|
- |
|
- /* Skip to the directory table. The rest of the header has already |
|
- been read and checked by get_line_table. */ |
|
- ptr = debug_sections[DEBUG_LINE].data + off; |
|
- ptr += (4 /* unit len */ |
|
- + 2 /* version */ |
|
- + 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 */ |
|
- dir = ptr; |
|
+ unsigned char *dir = ptr; |
|
|
|
/* dir table: */ |
|
value = 1; |
|
@@ -1620,6 +1711,40 @@ read_dwarf2_line (DSO *dso, uint32_t off, char *comp_dir) |
|
read_uleb128 (ptr); |
|
} |
|
|
|
+ return true; |
|
+} |
|
+ |
|
+/* 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 |
|
+ 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) |
|
+{ |
|
+ unsigned char *ptr; |
|
+ struct line_table *table; |
|
+ |
|
+ if (get_line_table (dso, off, &table) == false |
|
+ || table == NULL) |
|
+ return false; |
|
+ |
|
+ /* Skip to the directory table. The rest of the header has already |
|
+ been read and checked by get_line_table. */ |
|
+ ptr = debug_sections[DEBUG_LINE].data + off; |
|
+ ptr += (4 /* unit len */ |
|
+ + 2 /* version */ |
|
+ + 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 */ |
|
+ |
|
+ 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; |
|
} |
|
@@ -1637,6 +1762,33 @@ find_new_list_offs (struct debug_lines *lines, size_t idx) |
|
return table->new_idx; |
|
} |
|
|
|
+/* Read DW_FORM_strp collecting compilation directory. */ |
|
+static void |
|
+edit_attributes_str_comp_dir (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; |
|
+ |
|
+ free (*comp_dirp); |
|
+ *comp_dirp = strdup (dir); |
|
+ } |
|
+ |
|
+ if (dest_dir != NULL && phase == 0) |
|
+ { |
|
+ if (record_file_string_entry_idx (&dso->strings, idx)) |
|
+ need_strp_update = true; |
|
+ *handled_strpp = true; |
|
+ } |
|
+} |
|
+ |
|
/* This scans the attributes of one DIE described by the given abbrev_tag. |
|
PTR points to the data in the debug_info. It will be advanced till all |
|
abbrev data is consumed. In phase zero data is collected, in phase one |
|
@@ -1655,7 +1807,6 @@ edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase) |
|
for (i = 0; i < t->nattr; ++i) |
|
{ |
|
uint32_t form = t->attr[i].form; |
|
- size_t len = 0; |
|
while (1) |
|
{ |
|
/* Whether we already handled a string as file for this |
|
@@ -1743,29 +1894,8 @@ edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase) |
|
} |
|
else if (form == DW_FORM_strp && |
|
debug_sections[DEBUG_STR].data) |
|
- { |
|
- const char *dir; |
|
- size_t idx = do_read_32_relocated (ptr); |
|
- /* 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; |
|
- |
|
- free (comp_dir); |
|
- comp_dir = strdup (dir); |
|
- } |
|
- |
|
- if (dest_dir != NULL && phase == 0) |
|
- { |
|
- if (record_file_string_entry_idx (&dso->strings, idx)) |
|
- need_strp_update = true; |
|
- handled_strp = true; |
|
- } |
|
- } |
|
+ edit_attributes_str_comp_dir (dso, &ptr, phase, &comp_dir, |
|
+ &handled_strp); |
|
} |
|
else if ((t->tag == DW_TAG_compile_unit |
|
|| t->tag == DW_TAG_partial_unit) |
|
@@ -1815,99 +1945,21 @@ edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase) |
|
|
|
switch (form) |
|
{ |
|
- case DW_FORM_ref_addr: |
|
- if (cu_version == 2) |
|
- ptr += ptr_size; |
|
- else |
|
- ptr += 4; |
|
- break; |
|
- case DW_FORM_flag_present: |
|
- break; |
|
- case DW_FORM_addr: |
|
- ptr += ptr_size; |
|
- break; |
|
- case DW_FORM_ref1: |
|
- case DW_FORM_flag: |
|
- case DW_FORM_data1: |
|
- ++ptr; |
|
- break; |
|
- case DW_FORM_ref2: |
|
- case DW_FORM_data2: |
|
- ptr += 2; |
|
- break; |
|
- case DW_FORM_ref4: |
|
- case DW_FORM_data4: |
|
- case DW_FORM_sec_offset: |
|
- ptr += 4; |
|
- break; |
|
- case DW_FORM_ref8: |
|
- case DW_FORM_data8: |
|
- case DW_FORM_ref_sig8: |
|
- ptr += 8; |
|
- break; |
|
- case DW_FORM_sdata: |
|
- case DW_FORM_ref_udata: |
|
- case DW_FORM_udata: |
|
- read_uleb128 (ptr); |
|
- break; |
|
case DW_FORM_strp: |
|
- /* In the first pass we collect all strings, in the |
|
- second we put the new references back (if there are |
|
- any changes). */ |
|
- if (phase == 0) |
|
- { |
|
- /* handled_strp is set for attributes referring to |
|
- files. If it is set the string is already |
|
- recorded. */ |
|
- if (! handled_strp) |
|
- { |
|
- size_t idx = do_read_32_relocated (ptr); |
|
- record_existing_string_entry_idx (&dso->strings, idx); |
|
- } |
|
- } |
|
- else if (need_strp_update) /* && phase == 1 */ |
|
- { |
|
- 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); |
|
- do_write_32_relocated (ptr, new_idx); |
|
- } |
|
- ptr += 4; |
|
- break; |
|
- case DW_FORM_string: |
|
- ptr = (unsigned char *) strchr ((char *)ptr, '\0') + 1; |
|
- break; |
|
- case DW_FORM_indirect: |
|
- form = read_uleb128 (ptr); |
|
- continue; |
|
- case DW_FORM_block1: |
|
- len = *ptr++; |
|
- break; |
|
- case DW_FORM_block2: |
|
- len = read_16 (ptr); |
|
- form = DW_FORM_block1; |
|
+ edit_strp (dso, ptr, phase, handled_strp); |
|
break; |
|
- case DW_FORM_block4: |
|
- len = read_32 (ptr); |
|
- form = DW_FORM_block1; |
|
- break; |
|
- case DW_FORM_block: |
|
- case DW_FORM_exprloc: |
|
- len = read_uleb128 (ptr); |
|
- form = DW_FORM_block1; |
|
- assert (len < UINT_MAX); |
|
+ } |
|
+ |
|
+ switch (skip_form (dso, &form, &ptr)) |
|
+ { |
|
+ case FORM_OK: |
|
break; |
|
- default: |
|
- error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename, |
|
- form); |
|
+ case FORM_ERROR: |
|
return NULL; |
|
+ case FORM_INDIRECT: |
|
+ continue; |
|
} |
|
|
|
- if (form == DW_FORM_block1) |
|
- ptr += len; |
|
- |
|
break; |
|
} |
|
} |
|
@@ -2068,6 +2120,28 @@ edit_info (DSO *dso, int phase, struct debug_section *sec) |
|
return 0; |
|
} |
|
|
|
+/* Rebuild .debug_str. */ |
|
+static void |
|
+edit_dwarf2_any_str (DSO *dso) |
|
+{ |
|
+ 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; |
|
+} |
|
+ |
|
static int |
|
edit_dwarf2 (DSO *dso) |
|
{ |
|
@@ -2466,24 +2540,7 @@ edit_dwarf2 (DSO *dso) |
|
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; |
|
- } |
|
+ edit_dwarf2_any_str (dso); |
|
|
|
} |
|
|
|
-- |
|
2.18.4 |
|
|
|
|