From e38332c286bb96026fadc128170303cc4e935225 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 25 Feb 2021 17:50:44 +0000 Subject: [PATCH] Add initial support for .debug_sup sections. * dwarf.c (get_type_abbrev_from_form): Accept but ignore sup forms. (read_and_display_attr_value): Handle sup forms. (display_debug_sup): New function. Displays the contents of a .debug_sup section. (load_debug_sup_file): New function. Loads the contents of a file referenced by a .debug_sup section. (check_for_and_load_links): Call load_debug_sup_file. (debug_displays): Add entry for .debug_sup. * dwarf.h (enum dwarf_section_display_enum): Add debug_sup. * readelf.c (process_section_headers): Add support for debug_sup. * doc/debug.options.texi: Note that the =links option will display the contents of .debug_sup sections. * NEWS: Mention the new support. --- binutils/ChangeLog | 17 ++++ binutils/NEWS | 3 + binutils/doc/debug.options.texi | 10 +-- binutils/dwarf.c | 150 +++++++++++++++++++++++++++++++- binutils/dwarf.h | 1 + binutils/readelf.c | 4 +- 6 files changed, 176 insertions(+), 9 deletions(-) diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 7d47631f28f..332bf8f426b 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,20 @@ +2021-02-25 Nick Clifton + + * dwarf.c (get_type_abbrev_from_form): Accept but ignore sup + forms. + (read_and_display_attr_value): Handle sup forms. + (display_debug_sup): New function. Displays the contents of a + .debug_sup section. + (load_debug_sup_file): New function. Loads the contents of a file + referenced by a .debug_sup section. + (check_for_and_load_links): Call load_debug_sup_file. + (debug_displays): Add entry for .debug_sup. + * dwarf.h (enum dwarf_section_display_enum): Add debug_sup. + * readelf.c (process_section_headers): Add support for debug_sup. + * doc/debug.options.texi: Note that the =links option will display + the contents of .debug_sup sections. + * NEWS: Mention the new support. + 2021-02-25 Alan Modra PR 27456 diff --git a/binutils/NEWS b/binutils/NEWS index b0d55623738..61aca952f2d 100644 --- a/binutils/NEWS +++ b/binutils/NEWS @@ -1,5 +1,8 @@ -*- text -*- +* Readelf and objdump can now display and use the contents of .debug_sup + sections. + * Readelf and objdump will now follow links to separate debug info files by default. This behaviour can be stopped via the use of the new -wN or --debug-dump=no-follow-links options for readelf and the -WN or diff --git a/binutils/doc/debug.options.texi b/binutils/doc/debug.options.texi index 2ad8f03626d..3f0234ab0cc 100644 --- a/binutils/doc/debug.options.texi +++ b/binutils/doc/debug.options.texi @@ -44,11 +44,11 @@ output from this option can also be restricted by the use of the @item k @itemx =links -Displays the contents of the @samp{.gnu_debuglink} and/or -@samp{.gnu_debugaltlink} sections. Also displays any links to -separate dwarf object files (dwo), if they are specified by the -DW_AT_GNU_dwo_name or DW_AT_dwo_name attributes in the -@samp{.debug_info} section. +Displays the contents of the @samp{.gnu_debuglink}, +@samp{.gnu_debugaltlink} and @samp{.debug_sup} sections, if any of +them are present. Also displays any links to separate dwarf object +files (dwo), if they are specified by the DW_AT_GNU_dwo_name or +DW_AT_dwo_name attributes in the @samp{.debug_info} section. @item K @itemx =follow-links diff --git a/binutils/dwarf.c b/binutils/dwarf.c index ce2602b6cb0..3d279079380 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -2131,6 +2131,10 @@ get_type_abbrev_from_form (unsigned long form, } break; + case DW_FORM_ref_sup4: + case DW_FORM_ref_sup8: + break; + case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: @@ -2387,7 +2391,7 @@ display_discr_list (unsigned long form, default: printf ("\n"); - warn (_("corrupt discr_list - unrecognised discriminant byte %#x\n"), + warn (_("corrupt discr_list - unrecognized discriminant byte %#x\n"), discriminant); return; } @@ -2460,6 +2464,7 @@ read_and_display_attr_value (unsigned long attribute, SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end); break; + case DW_FORM_strp_sup: case DW_FORM_strp: case DW_FORM_line_strp: case DW_FORM_sec_offset: @@ -2483,6 +2488,7 @@ read_and_display_attr_value (unsigned long attribute, SAFE_BYTE_GET_AND_INC (uvalue, data, 2, end); break; + case DW_FORM_ref_sup4: case DW_FORM_ref4: case DW_FORM_data4: SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end); @@ -2536,6 +2542,7 @@ read_and_display_attr_value (unsigned long attribute, case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: + case DW_FORM_ref_sup4: case DW_FORM_ref_udata: if (!do_loc) printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x", uvalue + cu_offset)); @@ -2563,6 +2570,7 @@ read_and_display_attr_value (unsigned long attribute, printf ("%c%s", delimiter, dwarf_vmatoa ("d", implicit_const)); break; + case DW_FORM_ref_sup8: case DW_FORM_ref8: case DW_FORM_data8: if (!do_loc) @@ -2755,8 +2763,13 @@ read_and_display_attr_value (unsigned long attribute, } break; + case DW_FORM_strp_sup: + if (!do_loc) + printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x", uvalue + cu_offset)); + break; + default: - warn (_("Unrecognized form: %lu\n"), form); + warn (_("Unrecognized form: 0x%lx\n"), form); break; } @@ -4334,6 +4347,81 @@ display_formatted_table (unsigned char * data, return data; } +static int +display_debug_sup (struct dwarf_section * section, + void * file ATTRIBUTE_UNUSED) +{ + unsigned char * start = section->start; + unsigned char * end = section->start + section->size; + unsigned int version; + char is_supplementary; + const unsigned char * sup_filename; + size_t sup_filename_len; + unsigned int num_read; + int status; + dwarf_vma checksum_len; + + + introduce (section, TRUE); + if (section->size < 4) + { + error (_("corrupt .debug_sup section: size is too small\n")); + return 0; + } + + /* Read the data. */ + SAFE_BYTE_GET_AND_INC (version, start, 2, end); + if (version < 5) + warn (_("corrupt .debug_sup section: version < 5")); + + SAFE_BYTE_GET_AND_INC (is_supplementary, start, 1, end); + if (is_supplementary != 0 && is_supplementary != 1) + warn (_("corrupt .debug_sup section: is_supplementary not 0 or 1\n")); + + sup_filename = start; + if (is_supplementary && sup_filename[0] != 0) + warn (_("corrupt .debug_sup section: filename not empty in supplementary section\n")); + + sup_filename_len = strnlen ((const char *) start, end - start); + if (sup_filename_len == (size_t) (end - start)) + { + error (_("corrupt .debug_sup section: filename is not NUL terminated\n")); + return 0; + } + start += sup_filename_len + 1; + + checksum_len = read_leb128 (start, end, FALSE /* unsigned */, & num_read, & status); + if (status) + { + error (_("corrupt .debug_sup section: bad LEB128 field for checksum length\n")); + checksum_len = 0; + } + start += num_read; + if (checksum_len > (dwarf_vma) (end - start)) + { + error (_("corrupt .debug_sup section: checksum length is longer than the remaining section length\n")); + checksum_len = end - start; + } + else if (checksum_len < (dwarf_vma) (end - start)) + { + warn (_("corrupt .debug_sup section: there are 0x%lx extra, unused bytes at the end of the section\n"), + (long) ((end - start) - checksum_len)); + } + + printf (_(" Version: %u\n"), version); + printf (_(" Is Supp: %u\n"), is_supplementary); + printf (_(" Filename: %s\n"), sup_filename); + printf (_(" Checksum Len: %lu\n"), (long) checksum_len); + if (checksum_len > 0) + { + printf (_(" Checksum: ")); + while (checksum_len--) + printf ("0x%x ", * start++ ); + printf ("\n"); + } + return 1; +} + static int display_debug_lines_raw (struct dwarf_section * section, unsigned char * data, @@ -11131,9 +11219,62 @@ load_dwo_file (const char * main_filename, const char * name, const char * dir, return separate_handle; } +static void +load_debug_sup_file (const char * main_filename, void * file) +{ + if (! load_debug_section (debug_sup, file)) + return; /* No .debug_sup section. */ + + struct dwarf_section * section; + section = & debug_displays [debug_sup].section; + assert (section != NULL); + + if (section->start == NULL || section->size < 5) + { + warn (_(".debug_sup section is corrupt/empty\n")); + return; + } + + if (section->start[2] != 0) + return; /* This is a supplementary file. */ + + const char * filename = (const char *) section->start + 3; + if (strnlen (filename, section->size - 3) == section->size - 3) + { + warn (_("filename in .debug_sup section is corrupt\n")); + return; + } + + if (filename[0] != '/' && strchr (main_filename, '/')) + { + char * new_name; + if (asprintf (& new_name, "%.*s/%s", + (int) (strrchr (main_filename, '/') - main_filename), + main_filename, + filename) < 3) + warn (_("unable to construct path for supplementary debug file")); + else + filename = new_name; + } + + void * handle; + handle = open_debug_file (filename); + if (handle == NULL) + { + warn (_("unable to open file '%s' referenced from .debug_sup section\n"), filename); + return; + } + + printf (_("%s: Found supplementary debug file: %s\n\n"), main_filename, filename); + + /* FIXME: Compare the checksums, if present. */ + add_separate_debug_file (filename, 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. */ + Also follow any links in .debug_sup sections. + FIXME: Should also check for DWO_* entries in the newly loaded files. */ static void check_for_and_load_links (void * file, const char * filename) @@ -11175,6 +11316,8 @@ check_for_and_load_links (void * file, const char * filename) first_separate_info->filename); } } + + load_debug_sup_file (filename, file); } /* Load the separate debug info file(s) attached to FILE, if any exist. @@ -11541,6 +11684,7 @@ struct dwarf_section_display debug_displays[] = { { ".debug_tu_index", "", NO_ABBREVS }, display_cu_index, &do_debug_cu_index, FALSE }, { { ".gnu_debuglink", "", NO_ABBREVS }, display_debug_links, &do_debug_links, FALSE }, { { ".gnu_debugaltlink", "", NO_ABBREVS }, display_debug_links, &do_debug_links, FALSE }, + { { ".debug_sup", "", NO_ABBREVS }, display_debug_sup, &do_debug_links, FALSE }, /* Separate debug info files can containt their own .debug_str section, and this might be in *addition* to a .debug_str section already present in the main file. Hence we need to have two entries for .debug_str. */ diff --git a/binutils/dwarf.h b/binutils/dwarf.h index 98fbef8183d..043d3f9c9d0 100644 --- a/binutils/dwarf.h +++ b/binutils/dwarf.h @@ -120,6 +120,7 @@ enum dwarf_section_display_enum dwp_tu_index, gnu_debuglink, gnu_debugaltlink, + debug_sup, separate_debug_str, max }; diff --git a/binutils/readelf.c b/binutils/readelf.c index 811c529986a..7c8496c17ae 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -6556,7 +6556,8 @@ process_section_headers (Filedata * filedata) if ((do_debugging || do_debug_info || do_debug_abbrevs || do_debug_lines || do_debug_pubnames || do_debug_pubtypes || do_debug_aranges || do_debug_frames || do_debug_macinfo - || do_debug_str || do_debug_str_offsets || do_debug_loc || do_debug_ranges + || do_debug_str || do_debug_str_offsets || do_debug_loc + || do_debug_ranges || do_debug_addr || do_debug_cu_index || do_debug_links) && (const_strneq (name, ".debug_") || const_strneq (name, ".zdebug_"))) @@ -6583,6 +6584,7 @@ process_section_headers (Filedata * filedata) || (do_debug_macinfo && const_strneq (name, "macinfo")) || (do_debug_macinfo && const_strneq (name, "macro")) || (do_debug_str && const_strneq (name, "str")) + || (do_debug_links && const_strneq (name, "sup")) || (do_debug_str_offsets && const_strneq (name, "str_offsets")) || (do_debug_loc && const_strneq (name, "loc")) || (do_debug_loc && const_strneq (name, "loclists")) -- 2.30.2