Michael Schröder
c835eac6bb
OBS-URL: https://build.opensuse.org/package/show/Base:System/rpm?expand=0&rev=574
1952 lines
57 KiB
Diff
1952 lines
57 KiB
Diff
# Contains DWARF 5 support and includes the following upstream patches:
|
|
|
|
6b0019cd0c5ae18a59affa49a857b4d610d403e4
|
|
a834fccf3c94f78ad6a1b35ae352b1ede183dde4
|
|
86408cd826c32229817071bd008d9856cda4aca5
|
|
0d1003bc723ba30bfe325bb51aeafe7dbfed6a5c
|
|
|
|
--- ./tools/debugedit.c.orig 2021-03-30 09:34:25.206392109 +0000
|
|
+++ ./tools/debugedit.c 2021-03-30 09:34:40.186365656 +0000
|
|
@@ -103,6 +103,8 @@ static bool need_string_replacement = fa
|
|
/* 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;
|
|
@@ -233,7 +235,7 @@ typedef struct
|
|
int shift = 0; \
|
|
do \
|
|
{ \
|
|
- c = *ptr++; \
|
|
+ c = *(ptr)++; \
|
|
ret |= (c & 0x7f) << shift; \
|
|
shift += 7; \
|
|
} while (c & 0x80); \
|
|
@@ -251,7 +253,7 @@ typedef struct
|
|
valv >>= 7; \
|
|
if (valv) \
|
|
c |= 0x80; \
|
|
- *ptr++ = c; \
|
|
+ *(ptr)++ = c; \
|
|
} \
|
|
while (valv); \
|
|
})
|
|
@@ -311,7 +313,7 @@ strptr (DSO *dso, int sec, off_t offset)
|
|
}
|
|
|
|
|
|
-#define read_8(ptr) *ptr++
|
|
+#define read_8(ptr) *(ptr)++
|
|
|
|
#define read_16(ptr) ({ \
|
|
uint16_t ret = do_read_16 (ptr); \
|
|
@@ -328,13 +330,13 @@ strptr (DSO *dso, int sec, off_t offset)
|
|
REL *relptr, *relend;
|
|
int reltype;
|
|
|
|
-#define do_read_32_relocated(ptr) ({ \
|
|
- uint32_t dret = do_read_32 (ptr); \
|
|
+#define do_read_32_relocated(xptr) ({ \
|
|
+ uint32_t dret = do_read_32 (xptr); \
|
|
if (relptr) \
|
|
{ \
|
|
- while (relptr < relend && relptr->ptr < ptr) \
|
|
+ while (relptr < relend && relptr->ptr < (xptr)) \
|
|
++relptr; \
|
|
- if (relptr < relend && relptr->ptr == ptr) \
|
|
+ if (relptr < relend && relptr->ptr == (xptr)) \
|
|
{ \
|
|
if (reltype == SHT_REL) \
|
|
dret += relptr->addend; \
|
|
@@ -433,7 +435,8 @@ typedef struct debug_section
|
|
int sec, relsec;
|
|
REL *relbuf;
|
|
REL *relend;
|
|
- struct debug_section *next; /* Only happens for COMDAT .debug_macro. */
|
|
+ /* Only happens for COMDAT .debug_macro and .debug_types. */
|
|
+ struct debug_section *next;
|
|
} debug_section;
|
|
|
|
static debug_section debug_sections[] =
|
|
@@ -452,6 +455,11 @@ static debug_section debug_sections[] =
|
|
#define DEBUG_TYPES 11
|
|
#define DEBUG_MACRO 12
|
|
#define DEBUG_GDB_SCRIPT 13
|
|
+#define DEBUG_RNGLISTS 14
|
|
+#define DEBUG_LINE_STR 15
|
|
+#define DEBUG_ADDR 16
|
|
+#define DEBUG_STR_OFFSETS 17
|
|
+#define DEBUG_LOCLISTS 18
|
|
{ ".debug_info", NULL, NULL, 0, 0, 0 },
|
|
{ ".debug_abbrev", NULL, NULL, 0, 0, 0 },
|
|
{ ".debug_line", NULL, NULL, 0, 0, 0 },
|
|
@@ -466,6 +474,11 @@ static debug_section debug_sections[] =
|
|
{ ".debug_types", NULL, NULL, 0, 0, 0 },
|
|
{ ".debug_macro", NULL, NULL, 0, 0, 0 },
|
|
{ ".debug_gdb_scripts", NULL, NULL, 0, 0, 0 },
|
|
+ { ".debug_rnglists", NULL, NULL, 0, 0, 0 },
|
|
+ { ".debug_line_str", NULL, NULL, 0, 0, 0 },
|
|
+ { ".debug_addr", NULL, NULL, 0, 0, 0 },
|
|
+ { ".debug_str_offsets", NULL, NULL, 0, 0, 0 },
|
|
+ { ".debug_loclists", NULL, NULL, 0, 0, 0 },
|
|
{ NULL, NULL, NULL, 0, 0, 0 }
|
|
};
|
|
|
|
@@ -542,10 +555,11 @@ setup_relbuf (DSO *dso, debug_section *s
|
|
/* 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;
|
|
@@ -754,12 +768,29 @@ no_memory:
|
|
}
|
|
form = read_uleb128 (ptr);
|
|
if (form == 2
|
|
- || (form > DW_FORM_flag_present && form != DW_FORM_ref_sig8))
|
|
+ || (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
|
|
+ || form == DW_FORM_rnglistx
|
|
+ || form == DW_FORM_addrx1
|
|
+ || form == DW_FORM_addrx2
|
|
+ || form == DW_FORM_addrx3
|
|
+ || form == DW_FORM_addrx4)))
|
|
{
|
|
- error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename, form);
|
|
+ error (0, 0, "%s: Unknown DWARF DW_FORM_0x%x", dso->filename,
|
|
+ form);
|
|
htab_delete (h);
|
|
return NULL;
|
|
}
|
|
+ if (form == DW_FORM_implicit_const)
|
|
+ {
|
|
+ /* It is SLEB128 but the value is dropped anyway. */
|
|
+ read_uleb128 (ptr);
|
|
+ }
|
|
|
|
t->attr[t->nattr].attr = attr;
|
|
t->attr[t->nattr++].form = form;
|
|
@@ -1022,17 +1053,20 @@ string_find_entry (struct strings *strin
|
|
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)
|
|
{
|
|
@@ -1076,15 +1110,18 @@ record_file_string_entry_idx (struct str
|
|
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)
|
|
@@ -1217,13 +1254,28 @@ get_line_table (DSO *dso, size_t off, st
|
|
|
|
/* 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);
|
|
@@ -1269,7 +1321,9 @@ static int dirty_elf;
|
|
static void
|
|
dirty_section (unsigned int sec)
|
|
{
|
|
- elf_flagdata (debug_sections[sec].elf_data, ELF_C_SET, ELF_F_DIRTY);
|
|
+ for (struct debug_section *secp = &debug_sections[sec]; secp != NULL;
|
|
+ secp = secp->next)
|
|
+ elf_flagdata (secp->elf_data, ELF_C_SET, ELF_F_DIRTY);
|
|
dirty_elf = 1;
|
|
}
|
|
|
|
@@ -1314,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),
|
|
@@ -1454,42 +1510,151 @@ 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. */
|
|
-static bool
|
|
-read_dwarf2_line (DSO *dso, uint32_t off, char *comp_dir)
|
|
+/* Record or adjust (according to phase) DW_FORM_strp or DW_FORM_line_strp. */
|
|
+static void
|
|
+edit_strp (DSO *dso, bool line_strp, unsigned char *ptr, int phase,
|
|
+ bool handled_strp)
|
|
{
|
|
- 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;
|
|
+ unsigned char *ptr_orig = ptr;
|
|
|
|
- if (get_line_table (dso, off, &table) == false
|
|
- || table == NULL)
|
|
+ /* 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)
|
|
{
|
|
- if (table != NULL)
|
|
- error (0, 0, ".debug_line offset 0x%x referenced multiple times",
|
|
- off);
|
|
- return false;
|
|
+ /* 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 (line_strp, dso, idx);
|
|
+ }
|
|
+ }
|
|
+ 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 (strings, idx);
|
|
+ new_idx = strent_offset (entry->entry);
|
|
+ do_write_32_relocated (ptr, new_idx);
|
|
}
|
|
|
|
- /* 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;
|
|
+ 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:
|
|
+ case DW_FORM_implicit_const:
|
|
+ break;
|
|
+ case DW_FORM_addr:
|
|
+ *ptrp += ptr_size;
|
|
+ break;
|
|
+ case DW_FORM_ref1:
|
|
+ case DW_FORM_flag:
|
|
+ case DW_FORM_data1:
|
|
+ case DW_FORM_strx1:
|
|
+ case DW_FORM_addrx1:
|
|
+ ++*ptrp;
|
|
+ break;
|
|
+ case DW_FORM_ref2:
|
|
+ case DW_FORM_data2:
|
|
+ case DW_FORM_strx2:
|
|
+ case DW_FORM_addrx2:
|
|
+ *ptrp += 2;
|
|
+ break;
|
|
+ case DW_FORM_strx3:
|
|
+ case DW_FORM_addrx3:
|
|
+ *ptrp += 3;
|
|
+ break;
|
|
+ case DW_FORM_ref4:
|
|
+ case DW_FORM_data4:
|
|
+ case DW_FORM_strx4:
|
|
+ case DW_FORM_addrx4:
|
|
+ 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_data16:
|
|
+ *ptrp += 16;
|
|
+ break;
|
|
+ case DW_FORM_sdata:
|
|
+ case DW_FORM_ref_udata:
|
|
+ case DW_FORM_udata:
|
|
+ case DW_FORM_strx:
|
|
+ case DW_FORM_loclistx:
|
|
+ case DW_FORM_rnglistx:
|
|
+ case DW_FORM_addrx:
|
|
+ read_uleb128 (*ptrp);
|
|
+ break;
|
|
+ case DW_FORM_strp:
|
|
+ case DW_FORM_line_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_0x%x", 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_dwarf4_line (DSO *dso, unsigned char *ptr, char *comp_dir,
|
|
+ struct line_table *table)
|
|
+{
|
|
+ unsigned char **dirt;
|
|
+ uint32_t value, dirt_cnt;
|
|
+ size_t comp_dir_len = !comp_dir ? 0 : strlen (comp_dir);
|
|
+ unsigned char *dir = ptr;
|
|
|
|
/* dir table: */
|
|
value = 1;
|
|
@@ -1622,6 +1787,296 @@ read_dwarf2_line (DSO *dso, uint32_t off
|
|
read_uleb128 (ptr);
|
|
}
|
|
|
|
+ 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
|
|
+ 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 */
|
|
+ + (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 */
|
|
+
|
|
+ /* 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;
|
|
}
|
|
@@ -1639,6 +2094,40 @@ find_new_list_offs (struct debug_lines *
|
|
return table->new_idx;
|
|
}
|
|
|
|
+/* Read DW_FORM_strp or DW_FORM_line_strp collecting compilation directory. */
|
|
+static void
|
|
+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)
|
|
+ {
|
|
+ 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);
|
|
+ }
|
|
+
|
|
+ if (dest_dir != NULL && phase == 0)
|
|
+ {
|
|
+ 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;
|
|
+ }
|
|
+}
|
|
+
|
|
/* 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
|
|
@@ -1657,7 +2146,6 @@ edit_attributes (DSO *dso, unsigned char
|
|
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,38 +2231,24 @@ edit_attributes (DSO *dso, unsigned char
|
|
}
|
|
}
|
|
}
|
|
- 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;
|
|
- }
|
|
- }
|
|
+ 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
|
|
@@ -1784,11 +2258,14 @@ edit_attributes (DSO *dso, unsigned char
|
|
/* 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, '/');
|
|
@@ -1809,107 +2286,37 @@ edit_attributes (DSO *dso, unsigned char
|
|
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;
|
|
}
|
|
}
|
|
|
|
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, false /* line_strp */, ptr, phase, handled_strp);
|
|
break;
|
|
- case DW_FORM_block4:
|
|
- len = read_32 (ptr);
|
|
- form = DW_FORM_block1;
|
|
+ case DW_FORM_line_strp:
|
|
+ edit_strp (dso, true /* line_strp */, ptr, phase, handled_strp);
|
|
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;
|
|
}
|
|
}
|
|
@@ -1965,6 +2372,163 @@ line_rel_cmp (const void *a, const void
|
|
}
|
|
|
|
static int
|
|
+edit_info (DSO *dso, int phase, struct debug_section *sec)
|
|
+{
|
|
+ unsigned char *ptr, *endcu, *endsec;
|
|
+ uint32_t value;
|
|
+ htab_t abbrev;
|
|
+ struct abbrev_tag tag, *t;
|
|
+
|
|
+ ptr = sec->data;
|
|
+ if (ptr == NULL)
|
|
+ return 0;
|
|
+
|
|
+ setup_relbuf(dso, sec, &reltype);
|
|
+ endsec = ptr + sec->size;
|
|
+ while (ptr < endsec)
|
|
+ {
|
|
+ unsigned char *cu_start = ptr;
|
|
+
|
|
+ /* header size, version, unit_type, ptr_size. */
|
|
+ if (ptr + 4 + 2 + 1 + 1 > endsec)
|
|
+ {
|
|
+ error (0, 0, "%s: %s CU header too small",
|
|
+ dso->filename, sec->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, sec->name);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ cu_version = read_16 (ptr);
|
|
+ if (cu_version != 2 && cu_version != 3 && cu_version != 4
|
|
+ && cu_version != 5)
|
|
+ {
|
|
+ error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
|
|
+ cu_version);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ int cu_ptr_size = 0;
|
|
+
|
|
+ if (cu_version >= 5)
|
|
+ {
|
|
+ uint8_t unit_type = read_8 (ptr);
|
|
+ if (unit_type != DW_UT_compile && unit_type != DW_UT_partial)
|
|
+ {
|
|
+ error (0, 0, "%s: Unit type %u unhandled", dso->filename,
|
|
+ unit_type);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ cu_ptr_size = read_8 (ptr);
|
|
+ }
|
|
+
|
|
+ unsigned char *header_end = (cu_start + 23 + (cu_version < 5 ? 0 : 1));
|
|
+ if (header_end > endsec)
|
|
+ {
|
|
+ error (0, 0, "%s: %s CU header too small", dso->filename, sec->name);
|
|
+ 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 (cu_version < 5)
|
|
+ cu_ptr_size = read_8 (ptr);
|
|
+
|
|
+ if (ptr_size == 0)
|
|
+ {
|
|
+ ptr_size = cu_ptr_size;
|
|
+ if (ptr_size != 4 && ptr_size != 8)
|
|
+ {
|
|
+ error (0, 0, "%s: Invalid DWARF pointer size %d",
|
|
+ dso->filename, ptr_size);
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+ else if (cu_ptr_size != ptr_size)
|
|
+ {
|
|
+ error (0, 0, "%s: DWARF pointer size differs between CUs",
|
|
+ dso->filename);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ if (sec != &debug_sections[DEBUG_INFO])
|
|
+ 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, ptr, t, phase);
|
|
+ if (ptr == NULL)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ htab_delete (abbrev);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Rebuild .debug_str. */
|
|
+static void
|
|
+edit_dwarf2_any_str (DSO *dso, struct strings *strings, debug_section *secp)
|
|
+{
|
|
+ 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. */
|
|
+ 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);
|
|
+ secp->size = strdata->d_size;
|
|
+ strings->str_buf = strdata->d_buf;
|
|
+}
|
|
+
|
|
+static int
|
|
edit_dwarf2 (DSO *dso)
|
|
{
|
|
Elf_Data *data;
|
|
@@ -1995,7 +2559,7 @@ edit_dwarf2 (DSO *dso)
|
|
struct debug_section *debug_sec = &debug_sections[j];
|
|
if (debug_sections[j].data)
|
|
{
|
|
- if (j != DEBUG_MACRO)
|
|
+ if (j != DEBUG_MACRO && j != DEBUG_TYPES)
|
|
{
|
|
error (0, 0, "%s: Found two copies of %s section",
|
|
dso->filename, name);
|
|
@@ -2003,22 +2567,21 @@ edit_dwarf2 (DSO *dso)
|
|
}
|
|
else
|
|
{
|
|
- /* In relocatable files .debug_macro might
|
|
- appear multiple times as COMDAT
|
|
- section. */
|
|
+ /* In relocatable files .debug_macro and .debug_types
|
|
+ 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";
|
|
+ "%s: Could not allocate more %s sections",
|
|
+ dso->filename, name);
|
|
+ sec->name = name;
|
|
|
|
- struct debug_section *macro_sec = debug_sec;
|
|
- while (macro_sec->next != NULL)
|
|
- macro_sec = macro_sec->next;
|
|
+ struct debug_section *multi_sec = debug_sec;
|
|
+ while (multi_sec->next != NULL)
|
|
+ multi_sec = multi_sec->next;
|
|
|
|
- macro_sec->next = sec;
|
|
+ multi_sec->next = sec;
|
|
debug_sec = sec;
|
|
}
|
|
}
|
|
@@ -2055,23 +2618,23 @@ edit_dwarf2 (DSO *dso)
|
|
+ (dso->shdr[i].sh_type == SHT_RELA),
|
|
debug_sections[j].name) == 0)
|
|
{
|
|
- if (j == DEBUG_MACRO)
|
|
+ if (j == DEBUG_MACRO || j == DEBUG_TYPES)
|
|
{
|
|
/* Pick the correct one. */
|
|
int rel_target = dso->shdr[i].sh_info;
|
|
- struct debug_section *macro_sec = &debug_sections[j];
|
|
- while (macro_sec != NULL)
|
|
+ struct debug_section *multi_sec = &debug_sections[j];
|
|
+ while (multi_sec != NULL)
|
|
{
|
|
- if (macro_sec->sec == rel_target)
|
|
+ if (multi_sec->sec == rel_target)
|
|
{
|
|
- macro_sec->relsec = i;
|
|
+ multi_sec->relsec = i;
|
|
break;
|
|
}
|
|
- macro_sec = macro_sec->next;
|
|
+ multi_sec = multi_sec->next;
|
|
}
|
|
- if (macro_sec == NULL)
|
|
- error (0, 1, "No .debug_macro reloc section: %s",
|
|
- dso->filename);
|
|
+ if (multi_sec == NULL)
|
|
+ error (0, 1, "No %s reloc section: %s",
|
|
+ debug_sections[j].name, dso->filename);
|
|
}
|
|
else
|
|
debug_sections[j].relsec = i;
|
|
@@ -2100,388 +2663,338 @@ edit_dwarf2 (DSO *dso)
|
|
return 1;
|
|
}
|
|
|
|
- if (debug_sections[DEBUG_INFO].data != NULL)
|
|
+ if (debug_sections[DEBUG_INFO].data == NULL)
|
|
+ return 0;
|
|
+
|
|
+ unsigned char *ptr, *endsec;
|
|
+ int phase;
|
|
+ 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++)
|
|
{
|
|
- 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 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;
|
|
|
|
- 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;
|
|
+ rel_updated = false;
|
|
+ if (edit_info (dso, phase, &debug_sections[DEBUG_INFO]))
|
|
+ return 1;
|
|
|
|
- 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;
|
|
- }
|
|
+ /* Remember whether any .debug_info relocations might need
|
|
+ to be updated. */
|
|
+ info_rel_updated = rel_updated;
|
|
|
|
- endcu = ptr + 4;
|
|
- endcu += read_32 (ptr);
|
|
- if (endcu == ptr + 0xffffffff)
|
|
- {
|
|
- error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
|
|
- return 1;
|
|
- }
|
|
+ rel_updated = false;
|
|
+ struct debug_section *types_sec = &debug_sections[DEBUG_TYPES];
|
|
+ while (types_sec != NULL)
|
|
+ {
|
|
+ if (edit_info (dso, phase, types_sec))
|
|
+ return 1;
|
|
+ types_sec = types_sec->next;
|
|
+ }
|
|
|
|
- if (endcu > endsec)
|
|
- {
|
|
- error (0, 0, "%s: .debug_info too small", dso->filename);
|
|
- return 1;
|
|
- }
|
|
+ /* Remember whether any .debug_types relocations might need
|
|
+ to be updated. */
|
|
+ types_rel_updated = rel_updated;
|
|
|
|
- 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;
|
|
- }
|
|
+ /* 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);
|
|
|
|
- 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;
|
|
- }
|
|
+ /* 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);
|
|
|
|
- if (ptr_size == 0)
|
|
+ /* Sort them by offset into section. */
|
|
+ for (size_t i = 0; i < rels; i++)
|
|
{
|
|
- ptr_size = read_8 (ptr);
|
|
- if (ptr_size != 4 && ptr_size != 8)
|
|
+ if (rtype == SHT_RELA)
|
|
{
|
|
- error (0, 0, "%s: Invalid DWARF pointer size %d",
|
|
- dso->filename, ptr_size);
|
|
- return 1;
|
|
+ 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 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)
|
|
+ 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);
|
|
+ /* These relocations only happen in ET_REL files
|
|
+ and are section offsets. */
|
|
+ GElf_Addr r_offset;
|
|
+ size_t ndx = rbuf[i].ndx;
|
|
|
|
- /* Sort them by offset into section. */
|
|
- for (size_t i = 0; i < rels; i++)
|
|
+ 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;
|
|
+ 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);
|
|
|
|
- if (offset_len != 4)
|
|
- error (0, 1,
|
|
- "Cannot handle 8 byte macro offsets: %s",
|
|
- dso->filename);
|
|
+ offset_len = (macro_flags & 0x01) ? 8 : 4;
|
|
+ line_offset = (macro_flags & 0x02) ? 1 : 0;
|
|
|
|
- /* 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);
|
|
- }
|
|
- }
|
|
- }
|
|
+ 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 (false, dso, idx);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ struct stridxentry *entry;
|
|
+ size_t idx, new_idx;
|
|
+ idx = do_read_32_relocated (ptr);
|
|
+ entry = string_find_entry (&dso->debug_str, 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];
|
|
+ if (rel_updated)
|
|
+ macro_rel_updated = true;
|
|
+ macro_sec = macro_sec->next;
|
|
+ }
|
|
+ }
|
|
|
|
- /* 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;
|
|
- }
|
|
+ /* 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;
|
|
|
|
- /* 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);
|
|
+ /* 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, &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]);
|
|
+ }
|
|
|
|
- /* 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_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 || need_line_strp_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 (types_rel_updated)
|
|
+ {
|
|
+ struct debug_section *types_sec = &debug_sections[DEBUG_TYPES];
|
|
+ while (types_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, types_sec);
|
|
+ types_sec = types_sec->next;
|
|
}
|
|
}
|
|
|
|
+ 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;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (line_rel_updated)
|
|
+ update_rela_data (dso, &debug_sections[DEBUG_LINE]);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -2574,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;
|
|
|
|
@@ -2582,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);
|
|
}
|
|
@@ -2862,7 +3377,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. */
|
|
@@ -2934,10 +3451,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;
|
|
|
|
@@ -3007,7 +3526,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);
|
|
|
|
@@ -3022,6 +3542,17 @@ main (int argc, char *argv[])
|
|
macro_sec = next;
|
|
}
|
|
|
|
+ /* In case there were multiple (COMDAT) .debug_types sections,
|
|
+ free them. */
|
|
+ struct debug_section *types_sec = &debug_sections[DEBUG_TYPES];
|
|
+ types_sec = types_sec->next;
|
|
+ while (types_sec != NULL)
|
|
+ {
|
|
+ struct debug_section *next = types_sec->next;
|
|
+ free (types_sec);
|
|
+ types_sec = next;
|
|
+ }
|
|
+
|
|
poptFreeContext (optCon);
|
|
|
|
return 0;
|