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.
This commit is contained in:
Nick Clifton 2021-02-25 17:50:44 +00:00
parent d4ff3cbfdb
commit e38332c286
6 changed files with 176 additions and 9 deletions

View File

@ -1,3 +1,20 @@
2021-02-25 Nick Clifton <nickc@redhat.com>
* 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 <amodra@gmail.com> 2021-02-25 Alan Modra <amodra@gmail.com>
PR 27456 PR 27456

View File

@ -1,5 +1,8 @@
-*- text -*- -*- 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 * 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 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 --debug-dump=no-follow-links options for readelf and the -WN or

View File

@ -44,11 +44,11 @@ output from this option can also be restricted by the use of the
@item k @item k
@itemx =links @itemx =links
Displays the contents of the @samp{.gnu_debuglink} and/or Displays the contents of the @samp{.gnu_debuglink},
@samp{.gnu_debugaltlink} sections. Also displays any links to @samp{.gnu_debugaltlink} and @samp{.debug_sup} sections, if any of
separate dwarf object files (dwo), if they are specified by the them are present. Also displays any links to separate dwarf object
DW_AT_GNU_dwo_name or DW_AT_dwo_name attributes in the files (dwo), if they are specified by the DW_AT_GNU_dwo_name or
@samp{.debug_info} section. DW_AT_dwo_name attributes in the @samp{.debug_info} section.
@item K @item K
@itemx =follow-links @itemx =follow-links

View File

@ -2131,6 +2131,10 @@ get_type_abbrev_from_form (unsigned long form,
} }
break; break;
case DW_FORM_ref_sup4:
case DW_FORM_ref_sup8:
break;
case DW_FORM_ref1: case DW_FORM_ref1:
case DW_FORM_ref2: case DW_FORM_ref2:
case DW_FORM_ref4: case DW_FORM_ref4:
@ -2387,7 +2391,7 @@ display_discr_list (unsigned long form,
default: default:
printf ("<corrupt>\n"); printf ("<corrupt>\n");
warn (_("corrupt discr_list - unrecognised discriminant byte %#x\n"), warn (_("corrupt discr_list - unrecognized discriminant byte %#x\n"),
discriminant); discriminant);
return; return;
} }
@ -2460,6 +2464,7 @@ read_and_display_attr_value (unsigned long attribute,
SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end); SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
break; break;
case DW_FORM_strp_sup:
case DW_FORM_strp: case DW_FORM_strp:
case DW_FORM_line_strp: case DW_FORM_line_strp:
case DW_FORM_sec_offset: 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); SAFE_BYTE_GET_AND_INC (uvalue, data, 2, end);
break; break;
case DW_FORM_ref_sup4:
case DW_FORM_ref4: case DW_FORM_ref4:
case DW_FORM_data4: case DW_FORM_data4:
SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end); 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_ref1:
case DW_FORM_ref2: case DW_FORM_ref2:
case DW_FORM_ref4: case DW_FORM_ref4:
case DW_FORM_ref_sup4:
case DW_FORM_ref_udata: case DW_FORM_ref_udata:
if (!do_loc) if (!do_loc)
printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x", uvalue + cu_offset)); 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)); printf ("%c%s", delimiter, dwarf_vmatoa ("d", implicit_const));
break; break;
case DW_FORM_ref_sup8:
case DW_FORM_ref8: case DW_FORM_ref8:
case DW_FORM_data8: case DW_FORM_data8:
if (!do_loc) if (!do_loc)
@ -2755,8 +2763,13 @@ read_and_display_attr_value (unsigned long attribute,
} }
break; break;
case DW_FORM_strp_sup:
if (!do_loc)
printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x", uvalue + cu_offset));
break;
default: default:
warn (_("Unrecognized form: %lu\n"), form); warn (_("Unrecognized form: 0x%lx\n"), form);
break; break;
} }
@ -4334,6 +4347,81 @@ display_formatted_table (unsigned char * data,
return 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 static int
display_debug_lines_raw (struct dwarf_section * section, display_debug_lines_raw (struct dwarf_section * section,
unsigned char * data, unsigned char * data,
@ -11131,9 +11219,62 @@ load_dwo_file (const char * main_filename, const char * name, const char * dir,
return separate_handle; 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. /* Load a debuglink section and/or a debugaltlink section, if either are present.
Recursively check the loaded files for more of these sections. 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 static void
check_for_and_load_links (void * file, const char * filename) 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); first_separate_info->filename);
} }
} }
load_debug_sup_file (filename, file);
} }
/* Load the separate debug info file(s) attached to FILE, if any exist. /* 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 }, { { ".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_debuglink", "", NO_ABBREVS }, display_debug_links, &do_debug_links, FALSE },
{ { ".gnu_debugaltlink", "", 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, /* Separate debug info files can containt their own .debug_str section,
and this might be in *addition* to a .debug_str section already present 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. */ in the main file. Hence we need to have two entries for .debug_str. */

View File

@ -120,6 +120,7 @@ enum dwarf_section_display_enum
dwp_tu_index, dwp_tu_index,
gnu_debuglink, gnu_debuglink,
gnu_debugaltlink, gnu_debugaltlink,
debug_sup,
separate_debug_str, separate_debug_str,
max max
}; };

View File

@ -6556,7 +6556,8 @@ process_section_headers (Filedata * filedata)
if ((do_debugging || do_debug_info || do_debug_abbrevs if ((do_debugging || do_debug_info || do_debug_abbrevs
|| do_debug_lines || do_debug_pubnames || do_debug_pubtypes || do_debug_lines || do_debug_pubnames || do_debug_pubtypes
|| do_debug_aranges || do_debug_frames || do_debug_macinfo || 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) || do_debug_addr || do_debug_cu_index || do_debug_links)
&& (const_strneq (name, ".debug_") && (const_strneq (name, ".debug_")
|| const_strneq (name, ".zdebug_"))) || 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, "macinfo"))
|| (do_debug_macinfo && const_strneq (name, "macro")) || (do_debug_macinfo && const_strneq (name, "macro"))
|| (do_debug_str && const_strneq (name, "str")) || (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_str_offsets && const_strneq (name, "str_offsets"))
|| (do_debug_loc && const_strneq (name, "loc")) || (do_debug_loc && const_strneq (name, "loc"))
|| (do_debug_loc && const_strneq (name, "loclists")) || (do_debug_loc && const_strneq (name, "loclists"))