/* objdump.c -- dump information about an object file.
- Copyright (C) 1990-2018 Free Software Foundation, Inc.
+ Copyright (C) 1990-2019 Free Software Foundation, Inc.
This file is part of GNU Binutils.
static int prefix_strip; /* --prefix-strip */
static size_t prefix_length;
static bfd_boolean unwind_inlines; /* --inlines. */
+static const char * disasm_sym; /* Disassembly start symbol. */
+
+static int demangle_flags = DMGL_ANSI | DMGL_PARAMS;
/* A structure to record the sections mentioned in -j switches. */
struct only
long dynrelcount;
disassembler_ftype disassemble_fn;
arelent * reloc;
+ const char * symbol;
};
/* Architecture to disassemble for, or default if NULL. */
-x, --all-headers Display the contents of all headers\n\
-d, --disassemble Display assembler contents of executable sections\n\
-D, --disassemble-all Display assembler contents of all sections\n\
+ --disassemble=<sym> Display assembler contents from <sym>\n\
-S, --source Intermix source code with disassembly\n\
-s, --full-contents Display the full contents of all sections requested\n\
-g, --debugging Display debug information in object file\n\
The STYLE, if specified, can be `auto', `gnu',\n\
`lucid', `arm', `hp', `edg', `gnu-v3', `java'\n\
or `gnat'\n\
+ --recurse-limit Enable a limit on recursion whilst demangling. [Default]\n\
+ --no-recurse-limit Disable a limit on recursion whilst demangling\n\
-w, --wide Format output for more than 80 columns\n\
-z, --disassemble-zeroes Do not skip blocks of zeroes when disassembling\n\
--start-address=ADDR Only process data whose address is >= ADDR\n\
OPTION_DWARF_DEPTH,
OPTION_DWARF_CHECK,
OPTION_DWARF_START,
+ OPTION_RECURSE_LIMIT,
+ OPTION_NO_RECURSE_LIMIT,
OPTION_INLINES
};
{"debugging", no_argument, NULL, 'g'},
{"debugging-tags", no_argument, NULL, 'e'},
{"demangle", optional_argument, NULL, 'C'},
- {"disassemble", no_argument, NULL, 'd'},
+ {"disassemble", optional_argument, NULL, 'd'},
{"disassemble-all", no_argument, NULL, 'D'},
{"disassembler-options", required_argument, NULL, 'M'},
{"disassemble-zeroes", no_argument, NULL, 'z'},
{"line-numbers", no_argument, NULL, 'l'},
{"no-show-raw-insn", no_argument, &show_raw_insn, -1},
{"prefix-addresses", no_argument, &prefix_addresses, 1},
+ {"recurse-limit", no_argument, NULL, OPTION_RECURSE_LIMIT},
+ {"recursion-limit", no_argument, NULL, OPTION_RECURSE_LIMIT},
+ {"no-recurse-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT},
+ {"no-recursion-limit", no_argument, NULL, OPTION_NO_RECURSE_LIMIT},
{"reloc", no_argument, NULL, 'r'},
{"section", required_argument, NULL, 'j'},
{"section-headers", no_argument, NULL, 'h'},
bfd_nonfatal (msg);
exit_status = 1;
}
+
+/* Returns a version of IN with any control characters
+ replaced by escape sequences. Uses a static buffer
+ if necessary. */
+
+static const char *
+sanitize_string (const char * in)
+{
+ static char * buffer = NULL;
+ static unsigned int buffer_len = 0;
+ const char * original = in;
+ char * out;
+
+ /* Paranoia. */
+ if (in == NULL)
+ return "";
+
+ /* See if any conversion is necessary. In the majority
+ of cases it will not be needed. */
+ do
+ {
+ char c = *in++;
+
+ if (c == 0)
+ return original;
+
+ if (ISCNTRL (c))
+ break;
+ }
+ while (1);
+
+ /* Copy the input, translating as needed. */
+ in = original;
+ if (buffer_len < (strlen (in) * 2))
+ {
+ free ((void *) buffer);
+ buffer_len = strlen (in) * 2;
+ buffer = xmalloc (buffer_len + 1);
+ }
+
+ out = buffer;
+ do
+ {
+ char c = *in++;
+
+ if (c == 0)
+ break;
+
+ if (!ISCNTRL (c))
+ *out++ = c;
+ else
+ {
+ *out++ = '^';
+ *out++ = c + 0x40;
+ }
+ }
+ while (1);
+
+ *out = 0;
+ return buffer;
+}
+
\f
/* Returns TRUE if the specified section should be dumped. */
return;
printf ("%3d %-*s %08lx ", section->index, longest_section_name,
- bfd_get_section_name (abfd, section),
+ sanitize_string (bfd_get_section_name (abfd, section)),
(unsigned long) bfd_section_size (abfd, section) / opb);
bfd_printf_vma (abfd, bfd_get_section_vma (abfd, section));
printf (" ");
if (do_demangle && name[0] != '\0')
{
/* Demangle the name. */
- alloc = bfd_demangle (abfd, name, DMGL_ANSI | DMGL_PARAMS);
+ alloc = bfd_demangle (abfd, name, demangle_flags);
if (alloc != NULL)
name = alloc;
}
if (bfd_is_und_section (bfd_get_section (sym)))
hidden = TRUE;
+ name = sanitize_string (name);
+
if (inf != NULL)
{
(*inf->fprintf_func) (inf->stream, "%s", name);
bfd_vma secaddr;
(*inf->fprintf_func) (inf->stream, " <%s",
- bfd_get_section_name (abfd, sec));
+ sanitize_string (bfd_get_section_name (abfd, sec)));
secaddr = bfd_get_section_vma (abfd, sec);
if (vma < secaddr)
{
&& (prev_functionname == NULL
|| strcmp (functionname, prev_functionname) != 0))
{
- printf ("%s():\n", functionname);
+ printf ("%s():\n", sanitize_string (functionname));
prev_line = -1;
}
if (linenumber > 0
{
if (discriminator > 0)
printf ("%s:%u (discriminator %u)\n",
- filename == NULL ? "???" : filename,
+ filename == NULL ? "???" : sanitize_string (filename),
linenumber, discriminator);
else
- printf ("%s:%u\n", filename == NULL ? "???" : filename,
+ printf ("%s:%u\n", filename == NULL
+ ? "???" : sanitize_string (filename),
linenumber);
}
if (unwind_inlines)
while (bfd_find_inliner_info (abfd, &filename2, &functionname2,
&line2))
- printf ("inlined by %s:%u (%s)\n", filename2, line2,
- functionname2);
+ {
+ printf ("inlined by %s:%u",
+ sanitize_string (filename2), line2);
+ printf (" (%s)\n", sanitize_string (functionname2));
+ }
}
}
sym_name = bfd_get_section_name (aux->abfd, sym_sec);
if (sym_name == NULL || *sym_name == '\0')
sym_name = "*unknown*";
- printf ("%s", sym_name);
+ printf ("%s", sanitize_string (sym_name));
}
}
long rel_count;
bfd_vma rel_offset;
unsigned long addr_offset;
+ bfd_boolean do_print;
+ enum loop_control
+ {
+ stop_offset_reached,
+ function_sym,
+ next_sym
+ } loop_until;
/* Sections that do not contain machine
code are not normally disassembled. */
&& (*rel_pp)->address < rel_offset + addr_offset)
++rel_pp;
- printf (_("\nDisassembly of section %s:\n"), section->name);
+ printf (_("\nDisassembly of section %s:\n"), sanitize_string (section->name));
/* Find the nearest symbol forwards from our current position. */
paux->require_sec = TRUE;
the symbol we have just found. Then print the symbol and find the
next symbol on. Repeat until we have disassembled the entire section
or we have reached the end of the address range we are interested in. */
+ do_print = paux->symbol == NULL;
+ loop_until = stop_offset_reached;
+
while (addr_offset < stop_offset)
{
bfd_vma addr;
pinfo->symtab_pos = -1;
}
- if (! prefix_addresses)
+ /* If we are only disassembling from a specific symbol,
+ check to see if we should start or stop displaying. */
+ if (sym && paux->symbol)
+ {
+ if (do_print)
+ {
+ /* See if we should stop printing. */
+ switch (loop_until)
+ {
+ case function_sym:
+ if (sym->flags & BSF_FUNCTION)
+ do_print = FALSE;
+ break;
+
+ case stop_offset_reached:
+ /* Handled by the while loop. */
+ break;
+
+ case next_sym:
+ /* FIXME: There is an implicit assumption here
+ that the name of sym is different from
+ paux->symbol. */
+ if (! bfd_is_local_label (abfd, sym))
+ do_print = FALSE;
+ break;
+ }
+ }
+ else
+ {
+ const char * name = bfd_asymbol_name (sym);
+ char * alloc = NULL;
+
+ if (do_demangle && name[0] != '\0')
+ {
+ /* Demangle the name. */
+ alloc = bfd_demangle (abfd, name, demangle_flags);
+ if (alloc != NULL)
+ name = alloc;
+ }
+
+ /* We are not currently printing. Check to see
+ if the current symbol matches the requested symbol. */
+ if (streq (name, paux->symbol))
+ {
+ do_print = TRUE;
+
+ if (sym->flags & BSF_FUNCTION)
+ {
+ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && ((elf_symbol_type *) sym)->internal_elf_sym.st_size > 0)
+ {
+ /* Sym is a function symbol with a size associated
+ with it. Turn on automatic disassembly for the
+ next VALUE bytes. */
+ stop_offset = addr_offset
+ + ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
+ loop_until = stop_offset_reached;
+ }
+ else
+ {
+ /* Otherwise we need to tell the loop heuristic to
+ loop until the next function symbol is encountered. */
+ loop_until = function_sym;
+ }
+ }
+ else
+ {
+ /* Otherwise loop until the next symbol is encountered. */
+ loop_until = next_sym;
+ }
+ }
+
+ free (alloc);
+ }
+ }
+
+ if (! prefix_addresses && do_print)
{
pinfo->fprintf_func (pinfo->stream, "\n");
objdump_print_addr_with_sym (abfd, section, sym, addr,
else
insns = FALSE;
- disassemble_bytes (pinfo, paux->disassemble_fn, insns, data,
- addr_offset, nextstop_offset,
- rel_offset, &rel_pp, rel_ppend);
+ if (do_print)
+ disassemble_bytes (pinfo, paux->disassemble_fn, insns, data,
+ addr_offset, nextstop_offset,
+ rel_offset, &rel_pp, rel_ppend);
addr_offset = nextstop_offset;
sym = nextsym;
aux.dynrelbuf = NULL;
aux.dynrelcount = 0;
aux.reloc = NULL;
+ aux.symbol = disasm_sym;
disasm_info.print_address_func = objdump_print_address;
disasm_info.symbol_at_address_func = objdump_symbol_at_address;
section->reloc_info = NULL;
section->num_relocs = 0;
section->address = bfd_get_section_vma (abfd, sec);
+ section->user_data = sec;
section->size = bfd_get_section_size (sec);
amt = section->size + 1;
+ if (amt == 0 || amt > bfd_get_file_size (abfd))
+ {
+ section->start = NULL;
+ free_debug_section (debug);
+ printf (_("\nSection '%s' has an invalid size: %#llx.\n"),
+ sanitize_string (section->name),
+ (unsigned long long) section->size);
+ return FALSE;
+ }
section->start = contents = malloc (amt);
- section->user_data = sec;
- if (amt == 0
- || section->start == NULL
+ if (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);
+ sanitize_string (section->name));
return FALSE;
}
/* Ensure any string section has a terminating NUL. */
{
free_debug_section (debug);
printf (_("\nCan't get contents for section '%s'.\n"),
- section->name);
+ sanitize_string (section->name));
return FALSE;
}
static void
dump_dwarf (bfd *abfd)
{
- bfd * separates;
+ bfd_boolean have_separates;
is_relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
break;
}
- separates = load_separate_debug_file (abfd, bfd_get_filename (abfd));
+ have_separates = load_separate_debug_files (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);
+ if (have_separates)
+ {
+ separate_info * i;
+
+ for (i = first_separate_info; i != NULL; i = i->next)
+ bfd_map_over_sections (i->handle, dump_dwarf_section, NULL);
+
+ /* The file handles are closed by the call to free_debug_memory() below. */
+ }
free_debug_memory ();
}
stabsect = bfd_get_section_by_name (abfd, sect_name);
if (stabsect == NULL)
{
- printf (_("No %s section present\n\n"), sect_name);
+ printf (_("No %s section present\n\n"),
+ sanitize_string (sect_name));
return FALSE;
}
stabp = stabs;
stabs_end = stabp + stab_size;
- printf (_("Contents of %s section:\n\n"), stabsect_name);
+ printf (_("Contents of %s section:\n\n"), sanitize_string (stabsect_name));
printf ("Symnum n_type n_othr n_desc n_value n_strx String\n");
/* Loop through all symbols and print them.
again (makes consistent formatting for tools like awk). */
name = bfd_get_stab_name (type);
if (name != NULL)
- printf ("%-6s", name);
+ printf ("%-6s", sanitize_string (name));
else if (type == N_UNDF)
printf ("HdrSym");
else
/* Using the (possibly updated) string table offset, print the
string (if any) associated with this symbol. */
if (amt < stabstr_size)
- /* PR 17512: file: 079-79389-0.001:0.1. */
+ /* PR 17512: file: 079-79389-0.001:0.1.
+ FIXME: May need to sanitize this string before displaying. */
printf (" %.*s", (int)(stabstr_size - amt), strtab + amt);
else
printf (" *");
static void
dump_bfd_private_header (bfd *abfd)
{
- bfd_print_private_bfd_data (abfd, stdout);
+ if (!bfd_print_private_bfd_data (abfd, stdout))
+ non_fatal (_("warning: private headers incomplete: %s"),
+ bfd_errmsg (bfd_get_error ()));
}
static void
if (start_offset >= stop_offset)
return;
- printf (_("Contents of section %s:"), section->name);
+ printf (_("Contents of section %s:"), sanitize_string (section->name));
if (display_file_offsets)
printf (_(" (Starting at file offset: 0x%lx)"),
(unsigned long) (section->filepos + start_offset));
/* If we want to demangle the name, we demangle it
here, and temporarily clobber it while calling
bfd_print_symbol. FIXME: This is a gross hack. */
- alloc = bfd_demangle (cur_bfd, name, DMGL_ANSI | DMGL_PARAMS);
+ alloc = bfd_demangle (cur_bfd, name, demangle_flags);
if (alloc != NULL)
(*current)->name = alloc;
bfd_print_symbol (cur_bfd, stdout, *current,
&& (last_functionname == NULL
|| strcmp (functionname, last_functionname) != 0))
{
- printf ("%s():\n", functionname);
+ printf ("%s():\n", sanitize_string (functionname));
if (last_functionname != NULL)
free (last_functionname);
last_functionname = xstrdup (functionname);
|| (discriminator != last_discriminator)))
{
if (discriminator > 0)
- printf ("%s:%u\n", filename == NULL ? "???" : filename, linenumber);
+ printf ("%s:%u\n", filename == NULL ? "???" :
+ sanitize_string (filename), linenumber);
else
- printf ("%s:%u (discriminator %u)\n", filename == NULL ? "???" : filename,
+ printf ("%s:%u (discriminator %u)\n",
+ filename == NULL ? "???" : sanitize_string (filename),
linenumber, discriminator);
last_line = linenumber;
last_discriminator = discriminator;
{
if (section_name == NULL)
section_name = "*unknown*";
- printf ("[%s]", section_name);
+ printf ("[%s]", sanitize_string (section_name));
}
if (q->addend)
if (relsize < 0)
bfd_fatal (bfd_get_filename (abfd));
- printf ("RELOCATION RECORDS FOR [%s]:", section->name);
+ printf ("RELOCATION RECORDS FOR [%s]:", sanitize_string (section->name));
if (relsize == 0)
{
}
if ((bfd_get_file_flags (abfd) & (BFD_IN_MEMORY | BFD_LINKER_CREATED)) == 0
- && (((ufile_ptr) relsize > bfd_get_file_size (abfd))
+ && (/* Check that the size of the relocs is reasonable. Note that some
+ file formats, eg aout, can have relocs whose internal size is
+ larger than their external size, thus we check the size divided
+ by four against the file size. See PR 23931 for an example of
+ this. */
+ ((ufile_ptr) (relsize / 4) > 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.
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);
+ printf (" (too many: %#x relocs)\n", section->reloc_count);
bfd_set_error (bfd_error_file_truncated);
bfd_fatal (bfd_get_filename (abfd));
}
if (relcount < 0)
{
printf ("\n");
- non_fatal (_("failed to read relocs in: %s"), bfd_get_filename (abfd));
+ non_fatal (_("failed to read relocs in: %s"), sanitize_string (bfd_get_filename (abfd)));
bfd_fatal (_("error message was"));
}
else if (relcount == 0)
}
if (! dump_debugging_tags && ! suppress_bfd_header)
- printf (_("\n%s: file format %s\n"), bfd_get_filename (abfd),
+ printf (_("\n%s: file format %s\n"),
+ sanitize_string (bfd_get_filename (abfd)),
abfd->xvec->name);
if (dump_ar_hdrs)
print_arelt_descr (stdout, abfd, TRUE, FALSE);
bfd_get_filename (abfd));
exit_status = 1;
}
+
+ free (dhandle);
}
/* PR 6483: If there was no STABS debug info in the file, try
DWARF instead. */
bfd *last_arfile = NULL;
if (level == 0)
- printf (_("In archive %s:\n"), bfd_get_filename (file));
+ printf (_("In archive %s:\n"), sanitize_string (bfd_get_filename (file)));
else if (level > 100)
{
/* Prevent corrupted files from spinning us into an
return;
}
else
- printf (_("In nested archive %s:\n"), bfd_get_filename (file));
+ printf (_("In nested archive %s:\n"),
+ sanitize_string (bfd_get_filename (file)));
for (;;)
{
expandargv (&argc, &argv);
- bfd_init ();
+ if (bfd_init () != BFD_INIT_MAGIC)
+ fatal (_("fatal error: libbfd ABI mismatch"));
set_default_bfd_target ();
while ((c = getopt_long (argc, argv,
cplus_demangle_set_style (style);
}
break;
+ case OPTION_RECURSE_LIMIT:
+ demangle_flags &= ~ DMGL_NO_RECURSE_LIMIT;
+ break;
+ case OPTION_NO_RECURSE_LIMIT:
+ demangle_flags |= DMGL_NO_RECURSE_LIMIT;
+ break;
case 'w':
do_wide = wide_output = TRUE;
break;
case 'd':
disassemble = TRUE;
seenflag = TRUE;
+ disasm_sym = optarg;
break;
case 'z':
disassemble_zeroes = TRUE;