/* 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.
\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))
return 1;
}
+ if (bfd_get_flavour (bfd_asymbol_bfd (a)) == bfd_target_elf_flavour
+ && bfd_get_flavour (bfd_asymbol_bfd (b)) == bfd_target_elf_flavour)
+ {
+ bfd_vma asz, bsz;
+
+ asz = 0;
+ if ((a->flags & BSF_SYNTHETIC) == 0)
+ asz = ((elf_symbol_type *) a)->internal_elf_sym.st_size;
+ bsz = 0;
+ if ((b->flags & BSF_SYNTHETIC) == 0)
+ bsz = ((elf_symbol_type *) b)->internal_elf_sym.st_size;
+ if (asz != bsz)
+ return asz > bsz ? -1 : 1;
+ }
+
/* Symbols that start with '.' might be section names, so sort them
after symbols that don't start with '.'. */
if (an[0] == '.' && bn[0] != '.')
/* 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, ">");
}
/* 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;
/* 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)
}
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);
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 ();