/* dwarf.c -- display DWARF contents of a BFD binary file
- Copyright (C) 2005-2019 Free Software Foundation, Inc.
+ Copyright (C) 2005-2020 Free Software Foundation, Inc.
This file is part of GNU Binutils.
#include "safe-ctype.h"
#include <assert.h>
+#ifdef HAVE_LIBDEBUGINFOD
+#include <elfutils/debuginfod.h>
+#endif
+
#undef MAX
#undef MIN
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int do_wide;
int do_debug_links;
int do_follow_links;
+bfd_boolean do_checks;
int dwarf_cutoff_level = -1;
unsigned long dwarf_start_die;
int status;
dwarf_vma val = read_leb128 (data, end, is_signed, bytes_read, &status);
if (status != 0)
- report_leb_status (status);
+ report_leb_status (status, __FILE__, __LINE__);
else
printf ("%s", dwarf_vmatoa (is_signed ? "d" : "u", val));
}
if ((do_loc || do_debug_loc || do_debug_ranges)
&& num_debug_info_entries == 0
+ && alloc_num_debug_info_entries > unit
&& ! do_types)
{
debug_information [unit].cu_offset = cu_offset;
{
unsigned char *hdrptr;
unsigned int initial_length_size;
- unsigned char address_size, segment_selector_size;
/* Extract information from the Line Number Program Header.
(section 6.2.4 in the Dwarf3 doc). */
if (linfo->li_version >= 5)
{
- SAFE_BYTE_GET_AND_INC (address_size, hdrptr, 1, end);
+ SAFE_BYTE_GET_AND_INC (linfo->li_address_size, hdrptr, 1, end);
- SAFE_BYTE_GET_AND_INC (segment_selector_size, hdrptr, 1, end);
- if (segment_selector_size != 0)
+ SAFE_BYTE_GET_AND_INC (linfo->li_segment_size, hdrptr, 1, end);
+ if (linfo->li_segment_size != 0)
{
warn (_("The %s section contains "
"unsupported segment selector size: %d.\n"),
- section->name, segment_selector_size);
- return 0;
+ section->name, linfo->li_segment_size);
+ return NULL;
}
}
unsigned char *format_start, format_count, *format, formati;
dwarf_vma data_count, datai;
unsigned int namepass, last_entry = 0;
-
+ const char * table_name = is_dir ? N_("Directory Table") : N_("File Name Table");
+
SAFE_BYTE_GET_AND_INC (format_count, data, 1, end);
+ if (do_checks && format_count > 5)
+ warn (_("Unexpectedly large number of columns in the %s (%u)\n"),
+ table_name, format_count);
+
format_start = data;
for (formati = 0; formati < format_count; formati++)
{
SKIP_ULEB (data, end);
if (data == end)
{
- if (is_dir)
- warn (_("Corrupt directory format table entry\n"));
- else
- warn (_("Corrupt file name format table entry\n"));
+ warn (_("%s: Corrupt format description entry\n"), table_name);
return data;
}
}
READ_ULEB (data_count, data, end);
- if (data == end)
+ if (data_count == 0)
{
- if (is_dir)
- warn (_("Corrupt directory list\n"));
- else
- warn (_("Corrupt file name list\n"));
+ printf (_("\n The %s is empty.\n"), table_name);
return data;
}
-
- if (data_count == 0)
+ else if (data == end)
{
- if (is_dir)
- printf (_("\n The Directory Table is empty.\n"));
- else
- printf (_("\n The File Name Table is empty.\n"));
+ warn (_("%s: Corrupt entry count - expected %s but none found\n"),
+ table_name, dwarf_vmatoa ("x", data_count));
return data;
}
- if (is_dir)
- printf (_("\n The Directory Table (offset 0x%lx):\n"),
- (long) (data - start));
- else
- printf (_("\n The File Name Table (offset 0x%lx):\n"),
- (long) (data - start));
+ else if (format_count == 0)
+ {
+ warn (_("%s: format count is zero, but the table is not empty\n"),
+ table_name);
+ return end;
+ }
+
+ printf (_("\n The %s (offset 0x%lx, lines %s, columns %u):\n"),
+ table_name, (long) (data - start), dwarf_vmatoa ("u", data_count),
+ format_count);
printf (_(" Entry"));
/* Delay displaying name as the last entry for better screen layout. */
printf (_("\tSize"));
break;
case DW_LNCT_MD5:
- printf (_("\tMD5"));
+ printf (_("\tMD5\t\t\t"));
break;
default:
printf (_("\t(Unknown format content type %s)"),
section, NULL, '\t', -1);
}
}
- if (data == end)
+
+ if (data == end && (datai < data_count - 1))
{
- if (is_dir)
- warn (_("Corrupt directory entries list\n"));
- else
- warn (_("Corrupt file name entries list\n"));
+ warn (_("\n%s: Corrupt entries list\n"), table_name);
return data;
}
putchar ('\n');
printf (_(" Offset: 0x%lx\n"), (long)(data - start));
printf (_(" Length: %ld\n"), (long) linfo.li_length);
printf (_(" DWARF Version: %d\n"), linfo.li_version);
+ if (linfo.li_version >= 5)
+ {
+ printf (_(" Address size (bytes): %d\n"), linfo.li_address_size);
+ printf (_(" Segment selector (bytes): %d\n"), linfo.li_segment_size);
+ }
printf (_(" Prologue Length: %d\n"), (int) linfo.li_prologue_length);
printf (_(" Minimum Instruction Length: %d\n"), linfo.li_min_insn_length);
if (linfo.li_version >= 4)
/* Skip directories format. */
SAFE_BYTE_GET_AND_INC (format_count, data, 1, end);
+ if (do_checks && format_count > 1)
+ warn (_("Unexpectedly large number of columns in the directory name table (%u)\n"),
+ format_count);
format_start = data;
for (formati = 0; formati < format_count; formati++)
{
break;
}
- directory_table = (unsigned char **)
- xmalloc (n_directories * sizeof (unsigned char *));
+ if (n_directories == 0)
+ directory_table = NULL;
+ else
+ directory_table = (unsigned char **)
+ xmalloc (n_directories * sizeof (unsigned char *));
for (entryi = 0; entryi < n_directories; entryi++)
{
/* Skip files format. */
SAFE_BYTE_GET_AND_INC (format_count, data, 1, end);
+ if (do_checks && format_count > 5)
+ warn (_("Unexpectedly large number of columns in the file name table (%u)\n"),
+ format_count);
format_start = data;
for (formati = 0; formati < format_count; formati++)
{
}
READ_ULEB (n_files, data, end);
- if (data == end)
+ if (data == end && n_files > 0)
{
warn (_("Corrupt file name list\n"));
break;
}
- file_table = (File_Entry *) xcalloc (1, n_files
- * sizeof (File_Entry));
+ if (n_files == 0)
+ file_table = NULL;
+ else
+ file_table = (File_Entry *) xcalloc (1, n_files
+ * sizeof (File_Entry));
for (entryi = 0; entryi < n_files; entryi++)
{
/* Print the Compilation Unit's name and a header. */
if (file_table == NULL)
- ;
+ printf (_("CU: No directory table\n"));
else if (directory_table == NULL)
printf (_("CU: %s:\n"), file_table[0].name);
else
printf ("%s:\n", file_table[0].name);
}
- printf (_("File name Line number Starting address View Stmt\n"));
+ if (n_files > 0)
+ printf (_("File name Line number Starting address View Stmt\n"));
+ else
+ printf (_("CU: Empty file name table\n"));
saved_linfo = linfo;
}
default:
printf (_("UNKNOWN (%u): length %ld\n"),
- ext_op_code, op_code_data - data);
+ ext_op_code, (long int) (op_code_data - data));
break;
}
data = op_code_end;
strncpy (newFileName,
fileName + fileNameLength - MAX_FILENAME_LENGTH,
MAX_FILENAME_LENGTH + 1);
+ /* FIXME: This is to pacify gcc-10 which can warn that the
+ strncpy above might leave a non-NUL terminated string
+ in newFileName. It won't, but gcc's analysis doesn't
+ quite go far enough to discover this. */
+ newFileName[MAX_FILENAME_LENGTH] = 0;
}
else
{
int is_rnglists = strstr (section->name, "debug_rnglists") != NULL;
/* Initialize it due to a false compiler warning. */
unsigned char address_size = 0;
+ dwarf_vma last_offset = 0;
if (bytes == 0)
{
continue;
}
+ /* If multiple DWARF entities reference the same range then we will
+ have multiple entries in the `range_entries' list for the same
+ offset. Thanks to the sort above these will all be consecutive in
+ the `range_entries' list, so we can easily ignore duplicates
+ here. */
+ if (i > 0 && last_offset == offset)
+ continue;
+ last_offset = offset;
+
if (dwarf_check != 0 && i > 0)
{
if (start < next)
document. */
switch (regno)
{
-#define DECLARE_CSR(NAME,VALUE) case VALUE + 4096: name = #NAME; break;
+#define DECLARE_CSR(NAME,VALUE,CLASS,DEFINE_VER,ABORT_VER) \
+ case VALUE + 4096: name = #NAME; break;
#include "opcode/riscv-opc.h"
#undef DECLARE_CSR
unsigned int offset_size;
unsigned int initial_length_size;
bfd_boolean all_nops;
+ static Frame_Chunk fde_fc;
saved_start = start;
else
{
unsigned char *look_for;
- static Frame_Chunk fde_fc;
unsigned long segment_selector;
if (is_eh)
if (do_debug_frames_interp && ! all_nops)
frame_display_row (fc, &need_col_headers, &max_regs);
+ if (fde_fc.col_type != NULL)
+ {
+ free (fde_fc.col_type);
+ fde_fc.col_type = NULL;
+ }
+ if (fde_fc.col_offset != NULL)
+ {
+ free (fde_fc.col_offset);
+ fde_fc.col_offset = NULL;
+ }
+
start = block_end;
eh_addr_size = saved_eh_addr_size;
}
first_separate_info = i;
}
+#if HAVE_LIBDEBUGINFOD
+/* Query debuginfod servers for the target debuglink or debugaltlink
+ file. If successful, store the path of the file in filename and
+ return TRUE, otherwise return FALSE. */
+
+static bfd_boolean
+debuginfod_fetch_separate_debug_info (struct dwarf_section * section,
+ char ** filename,
+ void * file)
+{
+ size_t build_id_len;
+ unsigned char * build_id;
+
+ if (strcmp (section->uncompressed_name, ".gnu_debuglink") == 0)
+ {
+ /* Get the build-id of file. */
+ build_id = get_build_id (file);
+ build_id_len = 0;
+ }
+ else if (strcmp (section->uncompressed_name, ".gnu_debugaltlink") == 0)
+ {
+ /* Get the build-id of the debugaltlink file. */
+ unsigned int filelen;
+
+ filelen = strnlen ((const char *)section->start, section->size);
+ if (filelen == section->size)
+ /* Corrupt debugaltlink. */
+ return FALSE;
+
+ build_id = section->start + filelen + 1;
+ build_id_len = section->size - (filelen + 1);
+
+ if (build_id_len == 0)
+ return FALSE;
+ }
+ else
+ return FALSE;
+
+ if (build_id)
+ {
+ int fd;
+ debuginfod_client * client;
+
+ client = debuginfod_begin ();
+ if (client == NULL)
+ return FALSE;
+
+ /* Query debuginfod servers for the target file. If found its path
+ will be stored in filename. */
+ fd = debuginfod_find_debuginfo (client, build_id, build_id_len, filename);
+ debuginfod_end (client);
+
+ /* Only free build_id if we allocated space for a hex string
+ in get_build_id (). */
+ if (build_id_len == 0)
+ free (build_id);
+
+ if (fd >= 0)
+ {
+ /* File successfully retrieved. Close fd since we want to
+ use open_debug_file () on filename instead. */
+ close (fd);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+#endif
+
static void *
load_separate_debug_info (const char * main_filename,
struct dwarf_section * xlink,
parse_func_type parse_func,
check_func_type check_func,
- void * func_data)
+ void * func_data,
+ void * file ATTRIBUTE_UNUSED)
{
const char * separate_filename;
char * debug_filename;
if (check_func (debug_filename, func_data))
goto found;
+#if HAVE_LIBDEBUGINFOD
+ {
+ char * tmp_filename;
+
+ if (debuginfod_fetch_separate_debug_info (xlink,
+ & tmp_filename,
+ file))
+ {
+ /* File successfully downloaded from server, replace
+ debug_filename with the file's path. */
+ free (debug_filename);
+ debug_filename = tmp_filename;
+ goto found;
+ }
+ }
+#endif
+
/* Failed to find the file. */
warn (_("could not find separate debug file '%s'\n"), separate_filename);
warn (_("tried: %s\n"), debug_filename);
sprintf (debug_filename, "%s", separate_filename);
warn (_("tried: %s\n"), debug_filename);
+#if HAVE_LIBDEBUGINFOD
+ {
+ char *urls = getenv (DEBUGINFOD_URLS_ENV_VAR);
+ if (urls == NULL)
+ urls = "";
+
+ warn (_("tried: DEBUGINFOD_URLS=%s\n"), urls);
+ }
+#endif
+
free (canon_dir);
free (debug_filename);
return NULL;
& debug_displays[gnu_debugaltlink].section,
parse_gnu_debugaltlink,
check_gnu_debugaltlink,
- & build_id_data);
+ & build_id_data,
+ file);
}
if (load_debug_section (gnu_debuglink, file))
& debug_displays[gnu_debuglink].section,
parse_gnu_debuglink,
check_gnu_debuglink,
- & crc32);
+ & crc32,
+ file);
}
if (first_separate_info != NULL)