/* objdump.c -- dump information about an object file.
- Copyright (C) 1990-2017 Free Software Foundation, Inc.
+ Copyright (C) 1990-2018 Free Software Foundation, Inc.
This file is part of GNU Binutils.
static const char *prefix; /* --prefix */
static int prefix_strip; /* --prefix-strip */
static size_t prefix_length;
+static bfd_boolean unwind_inlines; /* --inlines. */
/* A structure to record the sections mentioned in -j switches. */
struct only
static bfd_byte *stabs;
static bfd_size_type stab_size;
-static char *strtab;
+static bfd_byte *strtab;
static bfd_size_type stabstr_size;
static bfd_boolean is_relocatable = FALSE;
-g, --debugging Display debug information in object file\n\
-e, --debugging-tags Display debug information using ctags style\n\
-G, --stabs Display (in raw form) any STABS info in the file\n\
- -W[lLiaprmfFsoRt] or\n\
+ -W[lLiaprmfFsoRtUuTgAckK] or\n\
--dwarf[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,\n\
=frames-interp,=str,=loc,=Ranges,=pubtypes,\n\
=gdb_index,=trace_info,=trace_abbrev,=trace_aranges,\n\
- =addr,=cu_index]\n\
+ =addr,=cu_index,=links,=follow-links]\n\
Display DWARF info in the file\n\
-t, --syms Display the contents of the symbol table(s)\n\
-T, --dynamic-syms Display the contents of the dynamic symbol table\n\
--insn-width=WIDTH Display WIDTH bytes on a single line for -d\n\
--adjust-vma=OFFSET Add OFFSET to all displayed section addresses\n\
--special-syms Include special symbols in symbol dumps\n\
+ --inlines Print all inlines for source line (with -l)\n\
--prefix=PREFIX Add PREFIX to absolute paths for -S\n\
--prefix-strip=LEVEL Strip initial directory names for -S\n"));
fprintf (stream, _("\
OPTION_ADJUST_VMA,
OPTION_DWARF_DEPTH,
OPTION_DWARF_CHECK,
- OPTION_DWARF_START
+ OPTION_DWARF_START,
+ OPTION_INLINES
};
static struct option long_options[]=
{"prefix", required_argument, NULL, OPTION_PREFIX},
{"prefix-strip", required_argument, NULL, OPTION_PREFIX_STRIP},
{"insn-width", required_argument, NULL, OPTION_INSN_WIDTH},
- {"dwarf-depth", required_argument, 0, OPTION_DWARF_DEPTH},
- {"dwarf-start", required_argument, 0, OPTION_DWARF_START},
- {"dwarf-check", no_argument, 0, OPTION_DWARF_CHECK},
+ {"dwarf-depth", required_argument, 0, OPTION_DWARF_DEPTH},
+ {"dwarf-start", required_argument, 0, OPTION_DWARF_START},
+ {"dwarf-check", no_argument, 0, OPTION_DWARF_CHECK},
+ {"inlines", no_argument, 0, OPTION_INLINES},
{0, no_argument, 0, 0}
};
\f
static bfd_boolean
is_significant_symbol_name (const char * name)
{
- return strcmp (name, ".plt") == 0
- || strcmp (name, ".got") == 0
- || strcmp (name, ".plt.got") == 0;
+ return strncmp (name, ".plt", 4) == 0 || strcmp (name, ".got") == 0;
}
/* Filter out (in place) symbols that are useless for disassembly.
bfd_vma asz, bsz;
asz = 0;
- if ((a->flags & BSF_SYNTHETIC) == 0)
+ if ((a->flags & (BSF_SECTION_SYM | BSF_SYNTHETIC)) == 0)
asz = ((elf_symbol_type *) a)->internal_elf_sym.st_size;
bsz = 0;
- if ((b->flags & BSF_SYNTHETIC) == 0)
+ if ((b->flags & (BSF_SECTION_SYM | BSF_SYNTHETIC)) == 0)
bsz = ((elf_symbol_type *) b)->internal_elf_sym.st_size;
if (asz != bsz)
return asz > bsz ? -1 : 1;
name = alloc;
}
- if ((sym->flags & BSF_SYNTHETIC) == 0)
+ if ((sym->flags & (BSF_SECTION_SYM | BSF_SYNTHETIC)) == 0)
version_string = bfd_get_symbol_version_string (abfd, sym, &hidden);
if (bfd_is_und_section (bfd_get_section (sym)))
asection *sec;
unsigned int opb;
bfd_boolean want_section;
+ long rel_count;
if (sorted_symcount < 1)
return NULL;
and we have dynamic relocations available, then we can produce
a better result by matching a relocation to the address and
using the symbol associated with that relocation. */
+ rel_count = aux->dynrelcount;
if (!want_section
- && aux->dynrelbuf != NULL
&& sorted_syms[thisplace]->value != vma
+ && rel_count > 0
+ && aux->dynrelbuf != NULL
+ && aux->dynrelbuf[0]->address <= vma
+ && aux->dynrelbuf[rel_count - 1]->address >= vma
/* If we have matched a synthetic symbol, then stick with that. */
&& (sorted_syms[thisplace]->flags & BSF_SYNTHETIC) == 0)
{
- long rel_count;
- arelent ** rel_pp;
+ arelent ** rel_low;
+ arelent ** rel_high;
- for (rel_count = aux->dynrelcount, rel_pp = aux->dynrelbuf;
- rel_count--;)
+ rel_low = aux->dynrelbuf;
+ rel_high = rel_low + rel_count - 1;
+ while (rel_low <= rel_high)
{
- arelent * rel = rel_pp[rel_count];
+ arelent **rel_mid = &rel_low[(rel_high - rel_low) / 2];
+ arelent * rel = *rel_mid;
- if (rel->address == vma
- && rel->sym_ptr_ptr != NULL
- /* Absolute relocations do not provide a more helpful symbolic address. */
- && ! bfd_is_abs_section ((* rel->sym_ptr_ptr)->section))
+ if (rel->address == vma)
{
- if (place != NULL)
- * place = thisplace;
- return * rel->sym_ptr_ptr;
+ /* Absolute relocations do not provide a more helpful
+ symbolic address. Find a non-absolute relocation
+ with the same address. */
+ arelent **rel_vma = rel_mid;
+ for (rel_mid--;
+ rel_mid >= rel_low && rel_mid[0]->address == vma;
+ rel_mid--)
+ rel_vma = rel_mid;
+
+ for (; rel_vma <= rel_high && rel_vma[0]->address == vma;
+ rel_vma++)
+ {
+ rel = *rel_vma;
+ if (rel->sym_ptr_ptr != NULL
+ && ! bfd_is_abs_section ((* rel->sym_ptr_ptr)->section))
+ {
+ if (place != NULL)
+ * place = thisplace;
+ return * rel->sym_ptr_ptr;
+ }
+ }
+ break;
}
- /* We are scanning backwards, so if we go below the target address
- we have failed. */
- if (rel_pp[rel_count]->address < vma)
+ if (vma < rel->address)
+ rel_high = rel_mid;
+ else if (vma >= rel_mid[1]->address)
+ rel_low = rel_mid + 1;
+ else
break;
}
}
/* Read a complete file into memory. */
static const char *
-slurp_file (const char *fn, size_t *size)
+slurp_file (const char *fn, size_t *size, struct stat *fst)
{
#ifdef HAVE_MMAP
int ps = getpagesize ();
size_t msize;
#endif
const char *map;
- struct stat st;
int fd = open (fn, O_RDONLY | O_BINARY);
if (fd < 0)
return NULL;
- if (fstat (fd, &st) < 0)
+ if (fstat (fd, fst) < 0)
{
close (fd);
return NULL;
}
- *size = st.st_size;
+ *size = fst->st_size;
#ifdef HAVE_MMAP
msize = (*size + ps - 1) & ~(ps - 1);
map = mmap (NULL, msize, PROT_READ, MAP_SHARED, fd, 0);
linked list and returns that node. Returns NULL on failure. */
static struct print_file_list *
-try_print_file_open (const char *origname, const char *modname)
+try_print_file_open (const char *origname, const char *modname, struct stat *fst)
{
struct print_file_list *p;
p = (struct print_file_list *) xmalloc (sizeof (struct print_file_list));
- p->map = slurp_file (modname, &p->mapsize);
+ p->map = slurp_file (modname, &p->mapsize, fst);
if (p->map == NULL)
{
free (p);
If found, add location to print_files linked list. */
static struct print_file_list *
-update_source_path (const char *filename)
+update_source_path (const char *filename, bfd *abfd)
{
struct print_file_list *p;
const char *fname;
+ struct stat fst;
int i;
- p = try_print_file_open (filename, filename);
- if (p != NULL)
- return p;
+ p = try_print_file_open (filename, filename, &fst);
+ if (p == NULL)
+ {
+ if (include_path_count == 0)
+ return NULL;
- if (include_path_count == 0)
- return NULL;
+ /* Get the name of the file. */
+ fname = lbasename (filename);
- /* Get the name of the file. */
- fname = lbasename (filename);
+ /* If file exists under a new path, we need to add it to the list
+ so that show_line knows about it. */
+ for (i = 0; i < include_path_count; i++)
+ {
+ char *modname = concat (include_paths[i], "/", fname,
+ (const char *) 0);
- /* If file exists under a new path, we need to add it to the list
- so that show_line knows about it. */
- for (i = 0; i < include_path_count; i++)
- {
- char *modname = concat (include_paths[i], "/", fname, (const char *) 0);
+ p = try_print_file_open (filename, modname, &fst);
+ if (p)
+ break;
- p = try_print_file_open (filename, modname);
- if (p)
- return p;
+ free (modname);
+ }
+ }
- free (modname);
+ if (p != NULL)
+ {
+ long mtime = bfd_get_mtime (abfd);
+
+ if (fst.st_mtime > mtime)
+ warn (_("source file %s is more recent than object file\n"),
+ filename);
}
- return NULL;
+ return p;
}
/* Print a source file line. */
return;
if (! bfd_find_nearest_line_discriminator (abfd, section, syms, addr_offset,
- &filename, &functionname,
- &linenumber, &discriminator))
+ &filename, &functionname,
+ &linenumber, &discriminator))
return;
if (filename != NULL && *filename == '\0')
if (functionname != NULL
&& (prev_functionname == NULL
|| strcmp (functionname, prev_functionname) != 0))
- printf ("%s():\n", functionname);
- if (linenumber > 0 && (linenumber != prev_line ||
- (discriminator != prev_discriminator)))
- {
- if (discriminator > 0)
- printf ("%s:%u (discriminator %u)\n", filename == NULL ? "???" : filename,
- linenumber, discriminator);
- else
- printf ("%s:%u\n", filename == NULL ? "???" : filename, linenumber);
- }
+ {
+ printf ("%s():\n", functionname);
+ prev_line = -1;
+ }
+ if (linenumber > 0
+ && (linenumber != prev_line
+ || discriminator != prev_discriminator))
+ {
+ if (discriminator > 0)
+ printf ("%s:%u (discriminator %u)\n",
+ filename == NULL ? "???" : filename,
+ linenumber, discriminator);
+ else
+ printf ("%s:%u\n", filename == NULL ? "???" : filename,
+ linenumber);
+ }
+ if (unwind_inlines)
+ {
+ const char *filename2;
+ const char *functionname2;
+ unsigned line2;
+
+ while (bfd_find_inliner_info (abfd, &filename2, &functionname2,
+ &line2))
+ printf ("inlined by %s:%u (%s)\n", filename2, line2,
+ functionname2);
+ }
}
if (with_source_code
{
if (reloc)
filename = xstrdup (filename);
- p = update_source_path (filename);
+ p = update_source_path (filename, abfd);
}
if (p != NULL && linenumber != p->last_line)
for (j = addr_offset * opb; j < addr_offset * opb + pb; j += bpc)
{
- int k;
-
- if (bpc > 1 && inf->display_endian == BFD_ENDIAN_LITTLE)
- {
- for (k = bpc - 1; k >= 0; k--)
- printf ("%02x", (unsigned) data[j + k]);
- putchar (' ');
- }
- else
+ /* PR 21580: Check for a buffer ending early. */
+ if (j + bpc <= stop_offset * opb)
{
- for (k = 0; k < bpc; k++)
- printf ("%02x", (unsigned) data[j + k]);
- putchar (' ');
+ int k;
+
+ if (inf->display_endian == BFD_ENDIAN_LITTLE)
+ {
+ for (k = bpc - 1; k >= 0; k--)
+ printf ("%02x", (unsigned) data[j + k]);
+ }
+ else
+ {
+ for (k = 0; k < bpc; k++)
+ printf ("%02x", (unsigned) data[j + k]);
+ }
}
+ putchar (' ');
}
for (; pb < octets_per_line; pb += bpc)
pb = octets;
for (; j < addr_offset * opb + pb; j += bpc)
{
- int k;
-
- if (bpc > 1 && inf->display_endian == BFD_ENDIAN_LITTLE)
+ /* PR 21619: Check for a buffer ending early. */
+ if (j + bpc <= stop_offset * opb)
{
- for (k = bpc - 1; k >= 0; k--)
- printf ("%02x", (unsigned) data[j + k]);
- putchar (' ');
- }
- else
- {
- for (k = 0; k < bpc; k++)
- printf ("%02x", (unsigned) data[j + k]);
- putchar (' ');
+ int k;
+
+ if (inf->display_endian == BFD_ENDIAN_LITTLE)
+ {
+ for (k = bpc - 1; k >= 0; k--)
+ printf ("%02x", (unsigned) data[j + k]);
+ }
+ else
+ {
+ for (k = 0; k < bpc; k++)
+ printf ("%02x", (unsigned) data[j + k]);
+ }
}
+ putchar (' ');
}
}
}
}
rel_ppend = rel_pp + rel_count;
- data = (bfd_byte *) xmalloc (datasize);
-
- bfd_get_section_contents (abfd, section, data, 0, datasize);
+ if (!bfd_malloc_and_get_section (abfd, section, &data))
+ {
+ non_fatal (_("Reading section %s failed because: %s"),
+ section->name, bfd_errmsg (bfd_get_error ()));
+ return;
+ }
paux->sec = section;
pinfo->buffer = data;
}
/* Use libopcodes to locate a suitable disassembler. */
- aux.disassemble_fn = disassembler (abfd);
+ aux.disassemble_fn = disassembler (bfd_get_arch (abfd),
+ bfd_big_endian (abfd),
+ bfd_get_mach (abfd), abfd);
if (!aux.disassemble_fn)
{
non_fatal (_("can't disassemble for architecture %s\n"),
free (sorted_syms);
}
\f
-static int
+static bfd_boolean
load_specific_debug_section (enum dwarf_section_display_enum debug,
asection *sec, void *file)
{
struct dwarf_section *section = &debug_displays [debug].section;
bfd *abfd = (bfd *) file;
- bfd_boolean ret;
+ bfd_byte *contents;
+ bfd_size_type amt;
- /* If it is already loaded, do nothing. */
if (section->start != NULL)
- return 1;
+ {
+ /* If it is already loaded, do nothing. */
+ if (streq (section->filename, bfd_get_filename (abfd)))
+ return TRUE;
+ free (section->start);
+ }
+ section->filename = bfd_get_filename (abfd);
section->reloc_info = NULL;
section->num_relocs = 0;
section->address = bfd_get_section_vma (abfd, sec);
section->size = bfd_get_section_size (sec);
- section->start = NULL;
+ amt = section->size + 1;
+ section->start = contents = malloc (amt);
section->user_data = sec;
- ret = bfd_get_full_section_contents (abfd, sec, §ion->start);
-
- if (! ret)
+ if (amt == 0
+ || section->start == NULL
+ || !bfd_get_full_section_contents (abfd, sec, &contents))
{
free_debug_section (debug);
printf (_("\nCan't get contents for section '%s'.\n"),
section->name);
- return 0;
+ return FALSE;
}
+ /* Ensure any string section has a terminating NUL. */
+ section->start[section->size] = 0;
if (is_relocatable && debug_displays [debug].relocate)
{
+ long reloc_size;
+ bfd_boolean ret;
+
bfd_cache_section_contents (sec, section->start);
ret = bfd_simple_get_relocated_section_contents (abfd,
free_debug_section (debug);
printf (_("\nCan't get contents for section '%s'.\n"),
section->name);
- return 0;
+ return FALSE;
}
- long reloc_size;
-
reloc_size = bfd_get_reloc_upper_bound (abfd, sec);
if (reloc_size > 0)
{
}
}
- return 1;
+ return TRUE;
}
bfd_boolean
return FALSE;
}
-int
+bfd_boolean
load_debug_section (enum dwarf_section_display_enum debug, void *file)
{
struct dwarf_section *section = &debug_displays [debug].section;
/* If it is already loaded, do nothing. */
if (section->start != NULL)
- return 1;
+ {
+ if (streq (section->filename, bfd_get_filename (abfd)))
+ return TRUE;
+ }
/* Locate the debug section. */
sec = bfd_get_section_by_name (abfd, section->uncompressed_name);
section->name = section->compressed_name;
}
if (sec == NULL)
- return 0;
+ return FALSE;
return load_specific_debug_section (debug, sec, file);
}
section->size = 0;
}
+void
+close_debug_file (void * file)
+{
+ bfd * abfd = (bfd *) file;
+
+ bfd_close (abfd);
+}
+
+void *
+open_debug_file (const char * pathname)
+{
+ bfd * data;
+
+ data = bfd_openr (pathname, NULL);
+ if (data == NULL)
+ return NULL;
+
+ if (! bfd_check_format (data, bfd_object))
+ return NULL;
+
+ return data;
+}
+
static void
dump_dwarf_section (bfd *abfd, asection *section,
void *arg ATTRIBUTE_UNUSED)
static void
dump_dwarf (bfd *abfd)
{
+ bfd * separates;
+
is_relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
eh_addr_size = bfd_arch_bits_per_address (abfd) / 8;
init_dwarf_regnames_s390 ();
break;
+ case bfd_arch_riscv:
+ init_dwarf_regnames_riscv ();
+ break;
+
default:
break;
}
+ separates = load_separate_debug_file (abfd, bfd_get_filename (abfd));
+
bfd_map_over_sections (abfd, dump_dwarf_section, NULL);
+ if (separates)
+ bfd_map_over_sections (separates, dump_dwarf_section, NULL);
+
free_debug_memory ();
}
\f
/* Read ABFD's stabs section STABSECT_NAME, and return a pointer to
it. Return NULL on failure. */
-static char *
+static bfd_byte *
read_section_stabs (bfd *abfd, const char *sect_name, bfd_size_type *size_ptr)
{
asection *stabsect;
- bfd_size_type size;
- char *contents;
+ bfd_byte *contents;
stabsect = bfd_get_section_by_name (abfd, sect_name);
if (stabsect == NULL)
return FALSE;
}
- size = bfd_section_size (abfd, stabsect);
- contents = (char *) xmalloc (size);
-
- if (! bfd_get_section_contents (abfd, stabsect, contents, 0, size))
+ if (!bfd_malloc_and_get_section (abfd, stabsect, &contents))
{
non_fatal (_("reading %s section of %s failed: %s"),
sect_name, bfd_get_filename (abfd),
return NULL;
}
- *size_ptr = size;
+ *size_ptr = bfd_section_size (abfd, stabsect);
return contents;
}
if (strtab)
{
- stabs = (bfd_byte *) read_section_stabs (abfd, section->name,
- &stab_size);
+ stabs = read_section_stabs (abfd, section->name, &stab_size);
if (stabs)
print_section_stabs (abfd, section->name, &sought->string_offset);
}
static void
dump_section (bfd *abfd, asection *section, void *dummy ATTRIBUTE_UNUSED)
{
- bfd_byte *data = 0;
+ bfd_byte *data = NULL;
bfd_size_type datasize;
bfd_vma addr_offset;
bfd_vma start_offset;
return;
}
+ if ((bfd_get_file_flags (abfd) & (BFD_IN_MEMORY | BFD_LINKER_CREATED)) == 0
+ && (((ufile_ptr) relsize > bfd_get_file_size (abfd))
+ /* Also check the section's reloc count since if this is negative
+ (or very large) the computation in bfd_get_reloc_upper_bound
+ may have resulted in returning a small, positive integer.
+ See PR 22508 for a reproducer.
+
+ Note - we check against file size rather than section size as
+ it is possible for there to be more relocs that apply to a
+ section than there are bytes in that section. */
+ || (section->reloc_count > bfd_get_file_size (abfd))))
+ {
+ printf (" (too many: 0x%x)\n", section->reloc_count);
+ bfd_set_error (bfd_error_file_truncated);
+ bfd_fatal (bfd_get_filename (abfd));
+ }
+
relpp = (arelent **) xmalloc (relsize);
relcount = bfd_canonicalize_reloc (abfd, section, relpp, syms);
printf (_("\n%s: file format %s\n"), bfd_get_filename (abfd),
abfd->xvec->name);
if (dump_ar_hdrs)
- print_arelt_descr (stdout, abfd, TRUE);
+ print_arelt_descr (stdout, abfd, TRUE, FALSE);
if (dump_file_header)
dump_bfd_header (abfd);
if (dump_private_headers)
exit_status = 1;
}
}
- /* PR 6483: If there was no STABS or IEEE debug
- info in the file, try DWARF instead. */
+ /* PR 6483: If there was no STABS debug info in the file, try
+ DWARF instead. */
else if (! dump_dwarf_section_info)
{
dwarf_select_sections_all ();
machine = optarg;
break;
case 'M':
- if (disassembler_options)
- /* Ignore potential memory leak for now. */
- disassembler_options = concat (disassembler_options, ",",
- optarg, (const char *) NULL);
- else
- disassembler_options = optarg;
+ {
+ char *options;
+ if (disassembler_options)
+ /* Ignore potential memory leak for now. */
+ options = concat (disassembler_options, ",",
+ optarg, (const char *) NULL);
+ else
+ options = optarg;
+ disassembler_options = remove_whitespace_and_extra_commas (options);
+ }
break;
case 'j':
add_only (optarg);
}
break;
case 'w':
- wide_output = TRUE;
+ do_wide = wide_output = TRUE;
break;
case OPTION_ADJUST_VMA:
adjust_section_vma = parse_vma (optarg, "--adjust-vma");
if (insn_width <= 0)
fatal (_("error: instruction width must be positive"));
break;
+ case OPTION_INLINES:
+ unwind_inlines = TRUE;
+ break;
case 'E':
if (strcmp (optarg, "B") == 0)
endian = BFD_ENDIAN_BIG;