/* objdump.c -- dump information about an object file.
- Copyright (C) 1990-2016 Free Software Foundation, Inc.
+ Copyright (C) 1990-2017 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
--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[]=
{"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
\f
static void
-dump_section_header (bfd *abfd, asection *section,
- void *ignored ATTRIBUTE_UNUSED)
+dump_section_header (bfd *abfd, asection *section, void *data)
{
char *comma = "";
unsigned int opb = bfd_octets_per_byte (abfd);
+ int longest_section_name = *((int *) data);
/* Ignore linker created section. See elfNN_ia64_object_p in
bfd/elfxx-ia64.c. */
if (! process_section_p (section))
return;
- printf ("%3d %-13s %08lx ", section->index,
+ printf ("%3d %-*s %08lx ", section->index, longest_section_name,
bfd_get_section_name (abfd, section),
(unsigned long) bfd_section_size (abfd, section) / opb);
bfd_printf_vma (abfd, bfd_get_section_vma (abfd, section));
#undef PF
}
+/* Called on each SECTION in ABFD, update the int variable pointed to by
+ DATA which contains the string length of the longest section name. */
+
+static void
+find_longest_section_name (bfd *abfd, asection *section, void *data)
+{
+ int *longest_so_far = (int *) data;
+ const char *name;
+ int len;
+
+ /* Ignore linker created section. */
+ if (section->flags & SEC_LINKER_CREATED)
+ return;
+
+ /* Skip sections that we are ignoring. */
+ if (! process_section_p (section))
+ return;
+
+ name = bfd_get_section_name (abfd, section);
+ len = (int) strlen (name);
+ if (len > *longest_so_far)
+ *longest_so_far = len;
+}
+
static void
dump_headers (bfd *abfd)
{
- printf (_("Sections:\n"));
+ /* The default width of 13 is just an arbitrary choice. */
+ int max_section_name_length = 13;
+ int bfd_vma_width;
#ifndef BFD64
- printf (_("Idx Name Size VMA LMA File off Algn"));
+ bfd_vma_width = 10;
#else
/* With BFD64, non-ELF returns -1 and wants always 64 bit addresses. */
if (bfd_get_arch_size (abfd) == 32)
- printf (_("Idx Name Size VMA LMA File off Algn"));
+ bfd_vma_width = 10;
else
- printf (_("Idx Name Size VMA LMA File off Algn"));
+ bfd_vma_width = 18;
#endif
+ printf (_("Sections:\n"));
+
+ if (wide_output)
+ bfd_map_over_sections (abfd, find_longest_section_name,
+ &max_section_name_length);
+
+ printf (_("Idx %-*s Size %-*s%-*sFile off Algn"),
+ max_section_name_length, "Name",
+ bfd_vma_width, "VMA",
+ bfd_vma_width, "LMA");
+
if (wide_output)
printf (_(" Flags"));
printf ("\n");
- bfd_map_over_sections (abfd, dump_section_header, NULL);
+ bfd_map_over_sections (abfd, dump_section_header,
+ &max_section_name_length);
}
\f
static asymbol **
return sy;
}
+/* Some symbol names are significant and should be kept in the
+ table of sorted symbol names, even if they are marked as
+ debugging/section symbols. */
+
+static bfd_boolean
+is_significant_symbol_name (const char * name)
+{
+ return strcmp (name, ".plt") == 0
+ || strcmp (name, ".got") == 0
+ || strcmp (name, ".plt.got") == 0;
+}
+
/* Filter out (in place) symbols that are useless for disassembly.
COUNT is the number of elements in SYMBOLS.
Return the number of useful symbols. */
if (sym->name == NULL || sym->name[0] == '\0')
continue;
- if (sym->flags & (BSF_DEBUGGING | BSF_SECTION_SYM))
+ if ((sym->flags & (BSF_DEBUGGING | BSF_SECTION_SYM))
+ && ! is_significant_symbol_name (sym->name))
continue;
if (bfd_is_und_section (sym->section)
|| bfd_is_com_section (sym->section))
/* The symbol we want is now in min, the low end of the range we
were searching. If there are several symbols with the same
- value, we want the first one. */
+ value, we want the first (non-section/non-debugging) one. */
thisplace = min;
while (thisplace > 0
&& (bfd_asymbol_value (sorted_syms[thisplace])
- == bfd_asymbol_value (sorted_syms[thisplace - 1])))
+ == bfd_asymbol_value (sorted_syms[thisplace - 1]))
+ && ((sorted_syms[thisplace - 1]->flags
+ & (BSF_SECTION_SYM | BSF_DEBUGGING)) == 0)
+ )
--thisplace;
/* Prefer a symbol in the current section if we have multple symbols
return NULL;
}
+ /* If we have not found an exact match for the specified address
+ 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. */
+ if (!want_section
+ && aux->dynrelbuf != NULL
+ && sorted_syms[thisplace]->value != 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;
+
+ for (rel_count = aux->dynrelcount, rel_pp = aux->dynrelbuf;
+ rel_count--;)
+ {
+ arelent * rel = rel_pp[rel_count];
+
+ 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 (place != NULL)
+ * place = thisplace;
+ return * rel->sym_ptr_ptr;
+ }
+
+ /* We are scanning backwards, so if we go below the target address
+ we have failed. */
+ if (rel_pp[rel_count]->address < vma)
+ break;
+ }
+ }
+
if (place != NULL)
*place = thisplace;
else
{
(*inf->fprintf_func) (inf->stream, " <");
+
objdump_print_symname (abfd, inf, sym);
- if (bfd_asymbol_value (sym) > vma)
+
+ if (bfd_asymbol_value (sym) == vma)
+ ;
+ /* Undefined symbols in an executables and dynamic objects do not have
+ a value associated with them, so it does not make sense to display
+ an offset relative to them. Normally we would not be provided with
+ this kind of symbol, but the target backend might choose to do so,
+ and the code in find_symbol_for_address might return an as yet
+ unresolved symbol associated with a dynamic reloc. */
+ else if ((bfd_get_file_flags (abfd) & (EXEC_P | DYNAMIC))
+ && bfd_is_und_section (sym->section))
+ ;
+ else if (bfd_asymbol_value (sym) > vma)
{
(*inf->fprintf_func) (inf->stream, "-0x");
objdump_print_value (bfd_asymbol_value (sym) - vma, inf, TRUE);
(*inf->fprintf_func) (inf->stream, "+0x");
objdump_print_value (vma - bfd_asymbol_value (sym), inf, TRUE);
}
+
(*inf->fprintf_func) (inf->stream, ">");
}
/* 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. */
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)
+ /* PR 21580: 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 (' ');
}
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 (' ');
}
}
}
/* Decide which set of relocs to use. Load them if necessary. */
paux = (struct objdump_disasm_info *) pinfo->application_data;
- if (paux->dynrelbuf)
+ if (paux->dynrelbuf && dump_dynamic_reloc_info)
{
rel_pp = paux->dynrelbuf;
rel_count = paux->dynrelcount;
data = (bfd_byte *) xmalloc (datasize);
- bfd_get_section_contents (abfd, section, data, 0, datasize);
+ if (!bfd_get_section_contents (abfd, section, data, 0, datasize))
+ {
+ 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"),
/* Allow the target to customize the info structure. */
disassemble_init_for_target (& disasm_info);
- /* Pre-load the dynamic relocs if we are going
- to be dumping them along with the disassembly. */
- if (dump_dynamic_reloc_info)
+ /* Pre-load the dynamic relocs as we may need them during the disassembly. */
{
long relsize = bfd_get_dynamic_reloc_upper_bound (abfd);
- if (relsize < 0)
+ if (relsize < 0 && dump_dynamic_reloc_info)
bfd_fatal (bfd_get_filename (abfd));
if (relsize > 0)
return;
}
+ if ((bfd_get_file_flags (abfd) & (BFD_IN_MEMORY | BFD_LINKER_CREATED)) == 0
+ && relsize > 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);
}
static void
-display_file (char *filename, char *target)
+display_file (char *filename, char *target, bfd_boolean last_file)
{
bfd *file;
display_any_bfd (file, 0);
- bfd_close (file);
+ /* This is an optimization to improve the speed of objdump, especially when
+ dumping a file with lots of associated debug informatiom. Calling
+ bfd_close on such a file can take a non-trivial amount of time as there
+ are lots of lists to walk and buffers to free. This is only really
+ necessary however if we are about to load another file and we need the
+ memory back. Otherwise, if we are about to exit, then we can save (a lot
+ of) time by only doing a quick close, and allowing the OS to reclaim the
+ memory for us. */
+ if (! last_file)
+ bfd_close (file);
+ else
+ bfd_close_all_done (file);
}
\f
int
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;
else
{
if (optind == argc)
- display_file ("a.out", target);
+ display_file ("a.out", target, TRUE);
else
for (; optind < argc;)
- display_file (argv[optind++], target);
+ {
+ display_file (argv[optind], target, optind == argc - 1);
+ optind++;
+ }
}
free_only_list ();