diff --git a/binutils-dwarf-type-sign.patch b/binutils-dwarf-type-sign.patch new file mode 100644 index 0000000..0c81b92 --- /dev/null +++ b/binutils-dwarf-type-sign.patch @@ -0,0 +1,931 @@ +--- binutils.orig/binutils/dwarf.c 2020-10-21 14:15:47.101351869 +0100 ++++ binutils-2.35.1/binutils/dwarf.c 2020-10-21 14:17:44.608585923 +0100 +@@ -1868,7 +1868,7 @@ skip_attr_bytes (unsigned long + case DW_FORM_ref_addr: + if (dwarf_version == 2) + SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end); +- else if (dwarf_version == 3 || dwarf_version == 4) ++ else if (dwarf_version > 2) + SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end); + else + return NULL; +@@ -1920,6 +1920,7 @@ skip_attr_bytes (unsigned long + + case DW_FORM_ref8: + case DW_FORM_data8: ++ case DW_FORM_ref_sig8: + data += 8; + break; + +@@ -1934,6 +1935,7 @@ skip_attr_bytes (unsigned long + case DW_FORM_block: + case DW_FORM_exprloc: + READ_ULEB (uvalue, data, end); ++ data += uvalue; + break; + + case DW_FORM_block1: +@@ -1951,12 +1953,12 @@ skip_attr_bytes (unsigned long + data += 4 + uvalue; + break; + +- case DW_FORM_ref_sig8: +- data += 8; +- break; +- + case DW_FORM_indirect: +- /* FIXME: Handle this form. */ ++ READ_ULEB (form, data, end); ++ if (form == DW_FORM_implicit_const) ++ SKIP_ULEB (data, end); ++ return skip_attr_bytes (form, data, end, pointer_size, offset_size, dwarf_version, value_return); ++ + default: + return NULL; + } +@@ -1978,7 +1980,7 @@ get_type_signedness (unsigned char * + dwarf_vma offset_size, + int dwarf_version, + bfd_boolean * is_signed, +- bfd_boolean is_nested) ++ unsigned int nesting) + { + unsigned long abbrev_number; + abbrev_entry * entry; +@@ -1997,6 +1999,14 @@ get_type_signedness (unsigned char * + /* FIXME: Issue a warning ? */ + return; + ++#define MAX_NESTING 20 ++ if (nesting > MAX_NESTING) ++ { ++ /* FIXME: Warn - or is this expected ? ++ NB/ We need to avoid infinite recursion. */ ++ return; ++ } ++ + for (attr = entry->first_attr; + attr != NULL && attr->attribute; + attr = attr->next) +@@ -2019,16 +2029,12 @@ get_type_signedness (unsigned char * + #endif + case DW_AT_type: + /* Recurse. */ +- if (is_nested) +- { +- /* FIXME: Warn - or is this expected ? +- NB/ We need to avoid infinite recursion. */ +- return; +- } + if (uvalue >= (size_t) (end - start)) + return; +- get_type_signedness (start, start + uvalue, end, pointer_size, +- offset_size, dwarf_version, is_signed, TRUE); ++ /* We cannot correctly process DW_FORM_ref_addr at the moment. */ ++ if (attr->form != DW_FORM_ref_addr) ++ get_type_signedness (start, start + uvalue, end, pointer_size, ++ offset_size, dwarf_version, is_signed, nesting + 1); + break; + + case DW_AT_encoding: +@@ -2206,7 +2212,6 @@ read_and_display_attr_value (unsigned lo + SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end); + else + error (_("Internal error: DWARF version is not 2, 3 or 4.\n")); +- + break; + + case DW_FORM_addr: +@@ -2246,8 +2251,8 @@ read_and_display_attr_value (unsigned lo + uvalue = svalue; + break; + +- case DW_FORM_GNU_str_index: + case DW_FORM_ref_udata: ++ case DW_FORM_GNU_str_index: + case DW_FORM_udata: + case DW_FORM_GNU_addr_index: + READ_ULEB (uvalue, data, end); +@@ -2663,8 +2668,10 @@ read_and_display_attr_value (unsigned lo + { + bfd_boolean is_signed = FALSE; + +- get_type_signedness (start, start + uvalue, end, pointer_size, +- offset_size, dwarf_version, & is_signed, FALSE); ++ /* We cannot correctly process DW_FORM_ref_addr at the moment. */ ++ if (form != DW_FORM_ref_addr) ++ get_type_signedness (start, start + uvalue, end, pointer_size, ++ offset_size, dwarf_version, & is_signed, 0); + level_type_signed[level] = is_signed; + } + break; +diff -rup binutils.orig/binutils/dwarf.c binutils-2.35.1/binutils/dwarf.c +--- binutils.orig/binutils/dwarf.c 2020-10-27 16:24:29.489636820 +0000 ++++ binutils-2.35.1/binutils/dwarf.c 2020-10-27 16:24:44.507568083 +0000 +@@ -849,101 +849,204 @@ fetch_indexed_value (dwarf_vma offset, d + /* FIXME: There are better and more efficient ways to handle + these structures. For now though, I just want something that + is simple to implement. */ ++/* Records a single attribute in an abbrev. */ + typedef struct abbrev_attr + { +- unsigned long attribute; +- unsigned long form; +- bfd_signed_vma implicit_const; +- struct abbrev_attr *next; ++ unsigned long attribute; ++ unsigned long form; ++ bfd_signed_vma implicit_const; ++ struct abbrev_attr * next; + } + abbrev_attr; + ++/* Records a single abbrev. */ + typedef struct abbrev_entry + { +- unsigned long entry; +- unsigned long tag; +- int children; +- struct abbrev_attr *first_attr; +- struct abbrev_attr *last_attr; +- struct abbrev_entry *next; ++ unsigned long number; ++ unsigned long tag; ++ int children; ++ struct abbrev_attr * first_attr; ++ struct abbrev_attr * last_attr; ++ struct abbrev_entry * next; + } + abbrev_entry; + +-static abbrev_entry *first_abbrev = NULL; +-static abbrev_entry *last_abbrev = NULL; ++/* Records a set of abbreviations. */ ++typedef struct abbrev_list ++{ ++ abbrev_entry * first_abbrev; ++ abbrev_entry * last_abbrev; ++ dwarf_vma abbrev_offset; ++ struct abbrev_list * next; ++ unsigned char * start_of_next_abbrevs; ++} ++abbrev_list; ++ ++/* Records all the abbrevs found so far. */ ++static struct abbrev_list * abbrev_lists = NULL; ++ ++typedef struct abbrev_map ++{ ++ dwarf_vma start; ++ dwarf_vma end; ++ abbrev_list * list; ++} abbrev_map; ++ ++/* Maps between CU offsets and abbrev sets. */ ++static abbrev_map * cu_abbrev_map = NULL; ++static unsigned long num_abbrev_map_entries = 0; ++static unsigned long next_free_abbrev_map_entry = 0; ++ ++#define INITIAL_NUM_ABBREV_MAP_ENTRIES 8 ++#define ABBREV_MAP_ENTRIES_INCREMENT 8 ++ ++static void ++record_abbrev_list_for_cu (dwarf_vma start, dwarf_vma end, abbrev_list * list) ++{ ++ if (cu_abbrev_map == NULL) ++ { ++ num_abbrev_map_entries = INITIAL_NUM_ABBREV_MAP_ENTRIES; ++ cu_abbrev_map = xmalloc (num_abbrev_map_entries * sizeof (* cu_abbrev_map)); ++ } ++ else if (next_free_abbrev_map_entry == num_abbrev_map_entries) ++ { ++ num_abbrev_map_entries += ABBREV_MAP_ENTRIES_INCREMENT; ++ cu_abbrev_map = xrealloc (cu_abbrev_map, num_abbrev_map_entries * sizeof (* cu_abbrev_map)); ++ } ++ ++ cu_abbrev_map[next_free_abbrev_map_entry].start = start; ++ cu_abbrev_map[next_free_abbrev_map_entry].end = end; ++ cu_abbrev_map[next_free_abbrev_map_entry].list = list; ++ next_free_abbrev_map_entry ++; ++} + + static void +-free_abbrevs (void) ++free_all_abbrevs (void) + { +- abbrev_entry *abbrv; ++ abbrev_list * list; + +- for (abbrv = first_abbrev; abbrv;) ++ for (list = abbrev_lists; list != NULL;) + { +- abbrev_entry *next_abbrev = abbrv->next; +- abbrev_attr *attr; ++ abbrev_list * next = list->next; ++ abbrev_entry * abbrv; + +- for (attr = abbrv->first_attr; attr;) ++ for (abbrv = list->first_abbrev; abbrv != NULL;) + { +- abbrev_attr *next_attr = attr->next; ++ abbrev_entry * next_abbrev = abbrv->next; ++ abbrev_attr * attr; + +- free (attr); +- attr = next_attr; ++ for (attr = abbrv->first_attr; attr;) ++ { ++ abbrev_attr *next_attr = attr->next; ++ ++ free (attr); ++ attr = next_attr; ++ } ++ ++ free (abbrv); ++ abbrv = next_abbrev; + } + +- free (abbrv); +- abbrv = next_abbrev; ++ free (list); ++ list = next; + } + +- last_abbrev = first_abbrev = NULL; ++ abbrev_lists = NULL; ++} ++ ++static abbrev_list * ++new_abbrev_list (dwarf_vma abbrev_offset) ++{ ++ abbrev_list * list = (abbrev_list *) xcalloc (sizeof * list, 1); ++ ++ list->abbrev_offset = abbrev_offset; ++ ++ list->next = abbrev_lists; ++ abbrev_lists = list; ++ ++ return list; ++} ++ ++static abbrev_list * ++find_abbrev_list_by_abbrev_offset (dwarf_vma abbrev_offset) ++{ ++ abbrev_list * list; ++ ++ for (list = abbrev_lists; list != NULL; list = list->next) ++ if (list->abbrev_offset == abbrev_offset) ++ return list; ++ ++ return NULL; ++} ++ ++/* Find the abbreviation map for the CU that includes OFFSET. ++ OFFSET is an absolute offset from the start of the .debug_info section. */ ++/* FIXME: This function is going to slow down readelf & objdump. ++ Consider using a better algorithm to mitigate this effect. */ ++ ++static abbrev_map * ++find_abbrev_map_by_offset (dwarf_vma offset) ++{ ++ unsigned long i; ++ ++ for (i = 0; i < next_free_abbrev_map_entry; i++) ++ if (cu_abbrev_map[i].start <= offset ++ && cu_abbrev_map[i].end > offset) ++ return cu_abbrev_map + i; ++ ++ return NULL; + } + + static void +-add_abbrev (unsigned long number, unsigned long tag, int children) ++add_abbrev (unsigned long number, ++ unsigned long tag, ++ int children, ++ abbrev_list * list) + { +- abbrev_entry *entry; ++ abbrev_entry * entry; + +- entry = (abbrev_entry *) malloc (sizeof (*entry)); +- if (entry == NULL) +- /* ugg */ +- return; ++ entry = (abbrev_entry *) xmalloc (sizeof (*entry)); + +- entry->entry = number; ++ entry->number = number; + entry->tag = tag; + entry->children = children; + entry->first_attr = NULL; + entry->last_attr = NULL; + entry->next = NULL; + +- if (first_abbrev == NULL) +- first_abbrev = entry; ++ assert (list != NULL); ++ ++ if (list->first_abbrev == NULL) ++ list->first_abbrev = entry; + else +- last_abbrev->next = entry; ++ list->last_abbrev->next = entry; + +- last_abbrev = entry; ++ list->last_abbrev = entry; + } + + static void +-add_abbrev_attr (unsigned long attribute, unsigned long form, +- bfd_signed_vma implicit_const) ++add_abbrev_attr (unsigned long attribute, ++ unsigned long form, ++ bfd_signed_vma implicit_const, ++ abbrev_list * list) + { + abbrev_attr *attr; + +- attr = (abbrev_attr *) malloc (sizeof (*attr)); +- if (attr == NULL) +- /* ugg */ +- return; ++ attr = (abbrev_attr *) xmalloc (sizeof (*attr)); + + attr->attribute = attribute; + attr->form = form; + attr->implicit_const = implicit_const; + attr->next = NULL; + +- if (last_abbrev->first_attr == NULL) +- last_abbrev->first_attr = attr; ++ assert (list != NULL && list->last_abbrev != NULL); ++ ++ if (list->last_abbrev->first_attr == NULL) ++ list->last_abbrev->first_attr = attr; + else +- last_abbrev->last_attr->next = attr; ++ list->last_abbrev->last_attr->next = attr; + +- last_abbrev->last_attr = attr; ++ list->last_abbrev->last_attr = attr; + } + + /* Processes the (partial) contents of a .debug_abbrev section. +@@ -952,11 +1055,10 @@ add_abbrev_attr (unsigned long attribute + an abbreviation set was found. */ + + static unsigned char * +-process_abbrev_section (unsigned char *start, unsigned char *end) ++process_abbrev_set (unsigned char * start, ++ const unsigned char * end, ++ abbrev_list * list) + { +- if (first_abbrev != NULL) +- return NULL; +- + while (start < end) + { + unsigned long entry; +@@ -966,7 +1068,7 @@ process_abbrev_section (unsigned char *s + + READ_ULEB (entry, start, end); + +- /* A single zero is supposed to end the section according ++ /* A single zero is supposed to end the set according + to the standard. If there's more, then signal that to + the caller. */ + if (start == end) +@@ -980,7 +1082,7 @@ process_abbrev_section (unsigned char *s + + children = *start++; + +- add_abbrev (entry, tag, children); ++ add_abbrev (entry, tag, children, list); + + do + { +@@ -1003,7 +1105,7 @@ process_abbrev_section (unsigned char *s + break; + } + +- add_abbrev_attr (attribute, form, implicit_const); ++ add_abbrev_attr (attribute, form, implicit_const, list); + } + while (attribute != 0); + } +@@ -1969,36 +2071,123 @@ skip_attr_bytes (unsigned long + return data; + } + +-/* Return IS_SIGNED set to TRUE if the type at +- DATA can be determined to be a signed type. */ ++/* Given form FORM with value UVALUE, locate and return the abbreviation ++ associated with it. */ ++ ++static abbrev_entry * ++get_type_abbrev_from_form (unsigned long form, ++ unsigned long uvalue, ++ dwarf_vma cu_offset, ++ const struct dwarf_section * section, ++ unsigned long * abbrev_num_return, ++ unsigned char ** data_return, ++ unsigned long * cu_offset_return) ++{ ++ unsigned long abbrev_number; ++ abbrev_map * map; ++ abbrev_entry * entry; ++ unsigned char * data; ++ ++ if (abbrev_num_return != NULL) ++ * abbrev_num_return = 0; ++ if (data_return != NULL) ++ * data_return = NULL; ++ ++ switch (form) ++ { ++ case DW_FORM_GNU_ref_alt: ++ /* FIXME: We are unable to handle this form at the moment. */ ++ return NULL; ++ ++ case DW_FORM_ref_addr: ++ if (uvalue >= section->size) ++ { ++ warn (_("Unable to resolve ref_addr form: uvalue %lx > section size %lx (%s)\n"), ++ uvalue, (long) section->size, section->name); ++ return NULL; ++ } ++ break; ++ ++ case DW_FORM_ref1: ++ case DW_FORM_ref2: ++ case DW_FORM_ref4: ++ case DW_FORM_ref_udata: ++ if (uvalue + cu_offset > section->size) ++ { ++ warn (_("Unable to resolve ref form: uvalue %lx + cu_offset %lx > section size %lx\n"), ++ uvalue, (long) cu_offset, (long) section->size); ++ return NULL; ++ } ++ uvalue += cu_offset; ++ break; ++ ++ /* FIXME: Are there other DW_FORMs that can be used by types ? */ ++ ++ default: ++ warn (_("Unexpected form %lx encountered whilst finding abbreviation for type\n"), form); ++ return NULL; ++ } ++ ++ data = (unsigned char *) section->start + uvalue; ++ map = find_abbrev_map_by_offset (uvalue); ++ ++ if (map == NULL) ++ { ++ warn (_("Unable to find abbreviations for CU offset %#lx\n"), uvalue); ++ return NULL; ++ } ++ if (map->list == NULL) ++ { ++ warn (_("Empty abbreviation list encountered for CU offset %lx\n"), uvalue); ++ return NULL; ++ } ++ ++ if (cu_offset_return != NULL) ++ { ++ if (form == DW_FORM_ref_addr) ++ * cu_offset_return = map->start; ++ else ++ * cu_offset_return = cu_offset; ++ } ++ ++ READ_ULEB (abbrev_number, data, section->start + section->size); ++ ++ for (entry = map->list->first_abbrev; entry != NULL; entry = entry->next) ++ if (entry->number == abbrev_number) ++ break; ++ ++ if (abbrev_num_return != NULL) ++ * abbrev_num_return = abbrev_number; ++ ++ if (data_return != NULL) ++ * data_return = data; ++ ++ if (entry == NULL) ++ warn (_("Unable to find entry for abbreviation %lu\n"), abbrev_number); ++ ++ return entry; ++} ++ ++/* Return IS_SIGNED set to TRUE if the type using abbreviation ENTRY ++ can be determined to be a signed type. The data for ENTRY can be ++ found starting at DATA. */ + + static void +-get_type_signedness (unsigned char * start, ++get_type_signedness (abbrev_entry * entry, ++ const struct dwarf_section * section, + unsigned char * data, + unsigned const char * end, ++ dwarf_vma cu_offset, + dwarf_vma pointer_size, + dwarf_vma offset_size, + int dwarf_version, + bfd_boolean * is_signed, + unsigned int nesting) + { +- unsigned long abbrev_number; +- abbrev_entry * entry; + abbrev_attr * attr; + + * is_signed = FALSE; + +- READ_ULEB (abbrev_number, data, end); +- +- for (entry = first_abbrev; +- entry != NULL && entry->entry != abbrev_number; +- entry = entry->next) +- continue; +- +- if (entry == NULL) +- /* FIXME: Issue a warning ? */ +- return; +- + #define MAX_NESTING 20 + if (nesting > MAX_NESTING) + { +@@ -2011,6 +2200,7 @@ get_type_signedness (unsigned char * + attr != NULL && attr->attribute; + attr = attr->next) + { ++ unsigned char * orig_data = data; + dwarf_vma uvalue = 0; + + data = skip_attr_bytes (attr->form, data, end, pointer_size, +@@ -2020,21 +2210,38 @@ get_type_signedness (unsigned char * + + switch (attr->attribute) + { +-#if 0 /* FIXME: It would be nice to print the name of the type, +- but this would mean updating a lot of binutils tests. */ ++ case DW_AT_linkage_name: + case DW_AT_name: +- if (attr->form == DW_FORM_strp) +- printf ("%s", fetch_indirect_string (uvalue)); ++ if (do_wide) ++ { ++ if (attr->form == DW_FORM_strp) ++ printf (", %s", fetch_indirect_string (uvalue)); ++ else if (attr->form == DW_FORM_string) ++ printf (", %s", orig_data); ++ } + break; +-#endif ++ + case DW_AT_type: + /* Recurse. */ +- if (uvalue >= (size_t) (end - start)) +- return; +- /* We cannot correctly process DW_FORM_ref_addr at the moment. */ +- if (attr->form != DW_FORM_ref_addr) +- get_type_signedness (start, start + uvalue, end, pointer_size, +- offset_size, dwarf_version, is_signed, nesting + 1); ++ { ++ abbrev_entry * type_abbrev; ++ unsigned char * type_data; ++ unsigned long type_cu_offset; ++ ++ type_abbrev = get_type_abbrev_from_form (attr->form, ++ uvalue, ++ cu_offset, ++ section, ++ NULL /* abbrev num return */, ++ & type_data, ++ & type_cu_offset); ++ if (type_abbrev == NULL) ++ break; ++ ++ get_type_signedness (type_abbrev, section, type_data, end, type_cu_offset, ++ pointer_size, offset_size, dwarf_version, ++ is_signed, nesting + 1); ++ } + break; + + case DW_AT_encoding: +@@ -2276,12 +2483,12 @@ read_and_display_attr_value (unsigned lo + { + case DW_FORM_ref_addr: + if (!do_loc) +- printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x",uvalue)); ++ printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x", uvalue)); + break; + + case DW_FORM_GNU_ref_alt: + if (!do_loc) +- printf ("%c", delimiter, dwarf_vmatoa ("x",uvalue)); ++ printf ("%c", delimiter, dwarf_vmatoa ("x", uvalue)); + /* FIXME: Follow the reference... */ + break; + +@@ -2667,11 +2874,18 @@ read_and_display_attr_value (unsigned lo + && uvalue < (size_t) (end - start)) + { + bfd_boolean is_signed = FALSE; +- +- /* We cannot correctly process DW_FORM_ref_addr at the moment. */ +- if (form != DW_FORM_ref_addr) +- get_type_signedness (start, start + uvalue, end, pointer_size, +- offset_size, dwarf_version, & is_signed, 0); ++ abbrev_entry * type_abbrev; ++ unsigned char * type_data; ++ unsigned long type_cu_offset; ++ ++ type_abbrev = get_type_abbrev_from_form (form, uvalue, cu_offset, ++ section, NULL, & type_data, & type_cu_offset); ++ if (type_abbrev != NULL) ++ { ++ get_type_signedness (type_abbrev, section, type_data, end, type_cu_offset, ++ pointer_size, offset_size, dwarf_version, ++ & is_signed, 0); ++ } + level_type_signed[level] = is_signed; + } + break; +@@ -2993,40 +3207,22 @@ read_and_display_attr_value (unsigned lo + + case DW_AT_import: + { +- if (form == DW_FORM_ref_sig8 +- || form == DW_FORM_GNU_ref_alt) +- break; +- +- if (form == DW_FORM_ref1 +- || form == DW_FORM_ref2 +- || form == DW_FORM_ref4 +- || form == DW_FORM_ref_udata) +- uvalue += cu_offset; ++ unsigned long abbrev_number; ++ abbrev_entry *entry; + +- if (uvalue >= section->size) +- warn (_("Offset %s used as value for DW_AT_import attribute of DIE at offset 0x%lx is too big.\n"), +- dwarf_vmatoa ("x", uvalue), +- (unsigned long) (orig_data - section->start)); ++ entry = get_type_abbrev_from_form (form, uvalue, cu_offset, ++ section, & abbrev_number, NULL, NULL); ++ if (entry == NULL) ++ { ++ if (form != DW_FORM_GNU_ref_alt) ++ warn (_("Offset %s used as value for DW_AT_import attribute of DIE at offset 0x%lx is too big.\n"), ++ dwarf_vmatoa ("x", uvalue), ++ (unsigned long) (orig_data - section->start)); ++ } + else + { +- unsigned long abbrev_number; +- abbrev_entry *entry; +- unsigned char *p = section->start + uvalue; +- +- READ_ULEB (abbrev_number, p, end); +- + printf (_("\t[Abbrev Number: %ld"), abbrev_number); +- /* Don't look up abbrev for DW_FORM_ref_addr, as it very often will +- use different abbrev table, and we don't track .debug_info chunks +- yet. */ +- if (form != DW_FORM_ref_addr) +- { +- for (entry = first_abbrev; entry != NULL; entry = entry->next) +- if (entry->entry == abbrev_number) +- break; +- if (entry != NULL) +- printf (" (%s)", get_TAG_name (entry->tag)); +- } ++ printf (" (%s)", get_TAG_name (entry->tag)); + printf ("]"); + } + } +@@ -3245,8 +3441,98 @@ process_debug_info (struct dwarf_section + + if (!do_loc && dwarf_start_die == 0) + introduce (section, FALSE); ++ ++ free_all_abbrevs (); ++ free (cu_abbrev_map); ++ cu_abbrev_map = NULL; ++ next_free_abbrev_map_entry = 0; + +- for (section_begin = start, unit = 0; start < end; unit++) ++ /* In order to be able to resolve DW_FORM_ref_attr forms we need ++ to load *all* of the abbrevs for all CUs in this .debug_info ++ section. This does effectively mean that we (partially) read ++ every CU header twice. */ ++ for (section_begin = start; start < end;) ++ { ++ DWARF2_Internal_CompUnit compunit; ++ unsigned char * hdrptr; ++ dwarf_vma cu_offset; ++ unsigned int offset_size; ++ unsigned int initial_length_size; ++ struct cu_tu_set * this_set; ++ abbrev_list * list; ++ ++ hdrptr = start; ++ ++ SAFE_BYTE_GET_AND_INC (compunit.cu_length, hdrptr, 4, end); ++ ++ if (compunit.cu_length == 0xffffffff) ++ { ++ SAFE_BYTE_GET_AND_INC (compunit.cu_length, hdrptr, 8, end); ++ offset_size = 8; ++ initial_length_size = 12; ++ } ++ else ++ { ++ offset_size = 4; ++ initial_length_size = 4; ++ } ++ ++ SAFE_BYTE_GET_AND_INC (compunit.cu_version, hdrptr, 2, end); ++ ++ cu_offset = start - section_begin; ++ ++ this_set = find_cu_tu_set_v2 (cu_offset, do_types); ++ ++ if (compunit.cu_version < 5) ++ { ++ compunit.cu_unit_type = DW_UT_compile; ++ /* Initialize it due to a false compiler warning. */ ++ compunit.cu_pointer_size = -1; ++ } ++ else ++ { ++ SAFE_BYTE_GET_AND_INC (compunit.cu_unit_type, hdrptr, 1, end); ++ do_types = (compunit.cu_unit_type == DW_UT_type); ++ ++ SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end); ++ } ++ ++ SAFE_BYTE_GET_AND_INC (compunit.cu_abbrev_offset, hdrptr, offset_size, end); ++ ++ list = find_abbrev_list_by_abbrev_offset (compunit.cu_abbrev_offset); ++ if (list == NULL) ++ { ++ dwarf_vma abbrev_base; ++ size_t abbrev_size; ++ unsigned char * next; ++ ++ if (this_set == NULL) ++ { ++ abbrev_base = 0; ++ abbrev_size = debug_displays [abbrev_sec].section.size; ++ } ++ else ++ { ++ abbrev_base = this_set->section_offsets [DW_SECT_ABBREV]; ++ abbrev_size = this_set->section_sizes [DW_SECT_ABBREV]; ++ } ++ ++ list = new_abbrev_list (compunit.cu_abbrev_offset); ++ next = process_abbrev_set ++ (((unsigned char *) debug_displays [abbrev_sec].section.start ++ + abbrev_base + compunit.cu_abbrev_offset), ++ ((unsigned char *) debug_displays [abbrev_sec].section.start ++ + abbrev_base + abbrev_size), ++ list); ++ list->start_of_next_abbrevs = next; ++ } ++ ++ start = section_begin + cu_offset + compunit.cu_length ++ + initial_length_size; ++ record_abbrev_list_for_cu (cu_offset, start - section_begin, list); ++ } ++ ++ for (start = section_begin, unit = 0; start < end; unit++) + { + DWARF2_Internal_CompUnit compunit; + unsigned char *hdrptr; +@@ -3262,6 +3548,7 @@ process_debug_info (struct dwarf_section + struct cu_tu_set *this_set; + dwarf_vma abbrev_base; + size_t abbrev_size; ++ abbrev_list * list = NULL; + + hdrptr = start; + +@@ -3434,8 +3721,6 @@ process_debug_info (struct dwarf_section + continue; + } + +- free_abbrevs (); +- + /* Process the abbrevs used by this compilation unit. */ + if (compunit.cu_abbrev_offset >= abbrev_size) + warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than abbrev section size (%lx)\n"), +@@ -3448,11 +3733,22 @@ process_debug_info (struct dwarf_section + (unsigned long) abbrev_base + abbrev_size, + (unsigned long) debug_displays [abbrev_sec].section.size); + else +- process_abbrev_section +- (((unsigned char *) debug_displays [abbrev_sec].section.start +- + abbrev_base + compunit.cu_abbrev_offset), +- ((unsigned char *) debug_displays [abbrev_sec].section.start +- + abbrev_base + abbrev_size)); ++ { ++ list = find_abbrev_list_by_abbrev_offset (compunit.cu_abbrev_offset); ++ if (list == NULL) ++ { ++ unsigned char * next; ++ ++ list = new_abbrev_list (compunit.cu_abbrev_offset); ++ next = process_abbrev_set ++ (((unsigned char *) debug_displays [abbrev_sec].section.start ++ + abbrev_base + compunit.cu_abbrev_offset), ++ ((unsigned char *) debug_displays [abbrev_sec].section.start ++ + abbrev_base + abbrev_size), ++ list); ++ list->start_of_next_abbrevs = next; ++ } ++ } + + level = 0; + last_level = level; +@@ -3532,11 +3828,13 @@ process_debug_info (struct dwarf_section + + /* Scan through the abbreviation list until we reach the + correct entry. */ +- for (entry = first_abbrev; +- entry && entry->entry != abbrev_number; +- entry = entry->next) ++ if (list == NULL) + continue; + ++ for (entry = list->first_abbrev; entry != NULL; entry = entry->next) ++ if (entry->number == abbrev_number) ++ break; ++ + if (entry == NULL) + { + if (!do_loc && do_printing) +@@ -5721,30 +6019,37 @@ display_debug_abbrev (struct dwarf_secti + { + abbrev_entry *entry; + unsigned char *start = section->start; +- unsigned char *end = start + section->size; ++ const unsigned char *end = start + section->size; + + introduce (section, FALSE); + + do + { +- unsigned char *last; +- +- free_abbrevs (); ++ abbrev_list * list; ++ dwarf_vma offset; + +- last = start; +- start = process_abbrev_section (start, end); ++ offset = start - section->start; ++ list = find_abbrev_list_by_abbrev_offset (offset); ++ if (list == NULL) ++ { ++ list = new_abbrev_list (offset); ++ start = process_abbrev_set (start, end, list); ++ list->start_of_next_abbrevs = start; ++ } ++ else ++ start = list->start_of_next_abbrevs; + +- if (first_abbrev == NULL) ++ if (list->first_abbrev == NULL) + continue; + +- printf (_(" Number TAG (0x%lx)\n"), (long) (last - section->start)); ++ printf (_(" Number TAG (0x%lx)\n"), (long) offset); + +- for (entry = first_abbrev; entry; entry = entry->next) ++ for (entry = list->first_abbrev; entry; entry = entry->next) + { + abbrev_attr *attr; + + printf (" %ld %s [%s]\n", +- entry->entry, ++ entry->number, + get_TAG_name (entry->tag), + entry->children ? _("has children") : _("no children")); + +@@ -10776,8 +11081,12 @@ free_debug_memory (void) + { + unsigned int i; + +- free_abbrevs (); ++ free_all_abbrevs (); + ++ free (cu_abbrev_map); ++ cu_abbrev_map = NULL; ++ next_free_abbrev_map_entry = 0; ++ + for (i = 0; i < max; i++) + free_debug_section ((enum dwarf_section_display_enum) i); + +Only in binutils-2.35.1/binutils: dwarf.c.orig diff --git a/binutils-recursive-debuglink-following.patch b/binutils-recursive-debuglink-following.patch new file mode 100644 index 0000000..b230bcf --- /dev/null +++ b/binutils-recursive-debuglink-following.patch @@ -0,0 +1,109 @@ +--- binutils.orig/binutils/dwarf.c 2020-10-15 12:13:21.960799738 +0100 ++++ binutils-2.35.1/binutils/dwarf.c 2020-10-15 13:02:39.454692627 +0100 +@@ -10427,7 +10427,7 @@ load_separate_debug_info (const char * + { + warn (_("Corrupt debuglink section: %s\n"), + xlink->name ? xlink->name : xlink->uncompressed_name); +- return FALSE; ++ return NULL; + } + + /* Attempt to locate the separate file. +@@ -10587,7 +10587,7 @@ load_separate_debug_info (const char * + { + warn (_("failed to open separate debug file: %s\n"), debug_filename); + free (debug_filename); +- return FALSE; ++ return NULL; + } + + /* FIXME: We do not check to see if there are any other separate debug info +@@ -10632,6 +10632,52 @@ load_dwo_file (const char * main_filenam + return separate_handle; + } + ++/* Load a debuglink section and/or a debugaltlink section, if either are present. ++ Recursively check the loaded files for more of these sections. ++ FIXME: Should also check for DWO_* entries in the newlu loaded files. */ ++ ++static void ++check_for_and_load_links (void * file, const char * filename) ++{ ++ void * handle = NULL; ++ ++ if (load_debug_section (gnu_debugaltlink, file)) ++ { ++ Build_id_data build_id_data; ++ ++ handle = load_separate_debug_info (filename, ++ & debug_displays[gnu_debugaltlink].section, ++ parse_gnu_debugaltlink, ++ check_gnu_debugaltlink, ++ & build_id_data, ++ file); ++ if (handle) ++ { ++ assert (handle == first_separate_info->handle); ++ check_for_and_load_links (first_separate_info->handle, ++ first_separate_info->filename); ++ } ++ } ++ ++ if (load_debug_section (gnu_debuglink, file)) ++ { ++ unsigned long crc32; ++ ++ handle = load_separate_debug_info (filename, ++ & debug_displays[gnu_debuglink].section, ++ parse_gnu_debuglink, ++ check_gnu_debuglink, ++ & crc32, ++ file); ++ if (handle) ++ { ++ assert (handle == first_separate_info->handle); ++ check_for_and_load_links (first_separate_info->handle, ++ first_separate_info->filename); ++ } ++ } ++} ++ + /* Load the separate debug info file(s) attached to FILE, if any exist. + Returns TRUE if any were found, FALSE otherwise. + If TRUE is returned then the linked list starting at first_separate_info +@@ -10707,34 +10753,10 @@ load_separate_debug_files (void * file, + return FALSE; + + /* FIXME: We do not check for the presence of both link sections in the same file. */ +- /* FIXME: We do not check the separate debug info file to see if it too contains debuglinks. */ + /* FIXME: We do not check for the presence of multiple, same-name debuglink sections. */ + /* FIXME: We do not check for the presence of a dwo link as well as a debuglink. */ + +- if (load_debug_section (gnu_debugaltlink, file)) +- { +- Build_id_data * build_id_data; +- +- load_separate_debug_info (filename, +- & debug_displays[gnu_debugaltlink].section, +- parse_gnu_debugaltlink, +- check_gnu_debugaltlink, +- & build_id_data, +- file); +- } +- +- if (load_debug_section (gnu_debuglink, file)) +- { +- unsigned long crc32; +- +- load_separate_debug_info (filename, +- & debug_displays[gnu_debuglink].section, +- parse_gnu_debuglink, +- check_gnu_debuglink, +- & crc32, +- file); +- } +- ++ check_for_and_load_links (file, filename); + if (first_separate_info != NULL) + return TRUE; + diff --git a/binutils.spec b/binutils.spec index 09b04bb..c53d3aa 100644 --- a/binutils.spec +++ b/binutils.spec @@ -2,7 +2,7 @@ Summary: A GNU collection of binary utilities Name: %{?cross}binutils%{?_with_debug:-debug} Version: 2.35.1 -Release: 5%{?dist} +Release: 8%{?dist} License: GPLv3+ URL: https://sourceware.org/binutils @@ -186,69 +186,78 @@ Patch10: binutils-attach-to-group.patch # Purpose: Allow OS specific sections in section groups. # Lifetime: Fixed in 2.36 (maybe) -Patch12: binutils-special-sections-in-groups.patch +Patch11: binutils-special-sections-in-groups.patch # Purpose: Fix linker testsuite failures. # Lifetime: Fixed in 2.36 (maybe) -Patch13: binutils-fix-testsuite-failures.patch +Patch12: binutils-fix-testsuite-failures.patch # Purpose: Stop gold from aborting when input sections with the same name # have different flags. # Lifetime: Fixed in 2.36 (maybe) -Patch14: binutils-gold-mismatched-section-flags.patch +Patch13: binutils-gold-mismatched-section-flags.patch # Purpose: Add a check to the GOLD linker for a corrupt input file # with a fuzzed section offset. # Lifetime: Fixed in 2.36 (maybe) -Patch15: binutils-CVE-2019-1010204.patch +Patch14: binutils-CVE-2019-1010204.patch # Purpose: Change the gold configuration script to only warn about # unsupported targets. This allows the binutils to be built with # BPF support enabled. # Lifetime: Permanent. -Patch17: binutils-gold-warn-unsupported.patch +Patch15: binutils-gold-warn-unsupported.patch # Purpose: Fix compile time warning messages building s390 target with gcc-10. # Lifetime: Should be fixed in 2.36. -Patch19: binutils-s390-build.patch +Patch16: binutils-s390-build.patch # Purpose: Fix LTO problems running config mini-builds. # Lifetime: Should be fixed in 2.36. -Patch20: binutils-config.patch +Patch17: binutils-config.patch # Purpose: Fix compile time warning messages building with gcc-10. # Lifetime: Should be fixed in 2.36. -Patch21: binutils-warnings.patch +Patch18: binutils-warnings.patch # Purpose: Fix compile time warning messages building with gcc-10. (part 2). # Lifetime: Should be fixed in 2.36. -Patch22: binutils-gcc-10-fixes.patch +Patch19: binutils-gcc-10-fixes.patch # Purpose: Fixes for linking LTO objects. # Lifetime: Fixed in 2.36 -Patch23: binutils-add-sym-cache-to-elf-link-hash.patch -Patch24: binutils-elf-add-objects.patch +Patch20: binutils-add-sym-cache-to-elf-link-hash.patch +Patch21: binutils-elf-add-objects.patch # Purpose: Fix handling of relocations for AArch64 conditional branches. # Lifetime: Fixed in 2.36 -Patch25: binutils-aarch64-condbranch-relocs.patch +Patch22: binutils-aarch64-condbranch-relocs.patch # Purpose: Fix the PowerPC disassembler so that it ignores annobin symbols. # Lifetime: Fixed in 2.36 -Patch26: binutils-ppc-annobin-disassembly.patch +Patch23: binutils-ppc-annobin-disassembly.patch # Purpose: Fix the strip program to cope when merging multiple same-named # sections. # Lifetime: Fixed in 2.36 -Patch27: binutils-strip-merge.patch +Patch24: binutils-strip-merge.patch # Purpose: Fix various problems with the PowerPC arch10 extensions. # Lifetime: Fixed in 2.36 -Patch28: binutils-Power10-fixes.patch +Patch25: binutils-Power10-fixes.patch # Purpose: Allow plugin syms to mark as-needed shared libs needed. # Lifetime: Fixed in 2.36 -Patch29: binutils-plugin-as-needed.patch +Patch26: binutils-plugin-as-needed.patch + +# Purpose: Recursively follow .gnu_debuglink and .gnu_debugaltlink sections. +# Lifetime: Fixed in 2.36 +Patch27: binutils-recursive-debuglink-following.patch + +# Purpose: Fix the DWARF parser to skip DW_FORM_ref_addr types +# when attempting to determine a type's signedness. +# Lifetime: Fixed in 2.36 +Patch28: binutils-dwarf-type-sign.patch #---------------------------------------------------------------------------- @@ -823,6 +832,15 @@ exit 0 #---------------------------------------------------------------------------- %changelog +* Tue Oct 27 2020 Nick Clifton - 2.35.1-8 +- Really fix erroneous decoding of LEB128 values. (#1891171) + +* Wed Oct 21 2020 Nick Clifton - 2.35.1-7 +- Fix erroneous decoding of LEB128 values. (#188716) + +* Thu Oct 15 2020 Nick Clifton - 2.35.1-6 +- Make readelf and objdump recursively follow debug links. (PR 26595) + * Fri Oct 09 2020 Nick Clifton - 2.35.1-5 - Allow plugin syms to mark as-needed shared libs needed