X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=binutils%2Fobjdump.c;h=ecfce4253d0499b32bdd529348ba5ec19b312f96;hb=80ae9dea4b85fc8306d20fdf37c428d6ba072ac6;hp=c6dddc8eaa56bdbd0cf6fd7e8198d151f99301e6;hpb=722087ec13ed0df5f70fa40ed0c196a3d874600f;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/objdump.c b/binutils/objdump.c index c6dddc8eaa..ecfce4253d 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -1,5 +1,5 @@ /* objdump.c -- dump information about an object file. - Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Copyright 1990, 91, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -15,60 +15,108 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software -Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bfd.h" -#include "sysdep.h" #include "getopt.h" +#include "progress.h" #include "bucomm.h" -#include #include #include "dis-asm.h" +#include "libiberty.h" +#include "demangle.h" +#include "debug.h" +#include "budbg.h" + +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif /* Internal headers for the ELF .stab-dump code - sorry. */ #define BYTES_IN_WORD 32 #include "aout/aout64.h" -#include "elf/internal.h" -extern Elf_Internal_Shdr *bfd_elf_find_section(); -#ifndef FPRINTF_ALREADY_DECLARED -extern int fprintf PARAMS ((FILE *, CONST char *, ...)); +#ifdef NEED_DECLARATION_FPRINTF +/* This is needed by INIT_DISASSEMBLE_INFO. */ +extern int fprintf PARAMS ((FILE *, const char *, ...)); #endif -char *default_target = NULL; /* default at runtime */ - -extern char *program_version; - -int show_version = 0; /* show the version number */ -int dump_section_contents; /* -s */ -int dump_section_headers; /* -h */ -boolean dump_file_header; /* -f */ -int dump_symtab; /* -t */ -int dump_reloc_info; /* -r */ -int dump_ar_hdrs; /* -a */ -int with_line_numbers; /* -l */ -int dump_stab_section_info; /* --stabs */ -boolean disassemble; /* -d */ -boolean formats_info; /* -i */ -char *only; /* -j secname */ - +static char *default_target = NULL; /* default at runtime */ + +static int show_version = 0; /* show the version number */ +static int dump_section_contents; /* -s */ +static int dump_section_headers; /* -h */ +static boolean dump_file_header; /* -f */ +static int dump_symtab; /* -t */ +static int dump_dynamic_symtab; /* -T */ +static int dump_reloc_info; /* -r */ +static int dump_dynamic_reloc_info; /* -R */ +static int dump_ar_hdrs; /* -a */ +static int dump_private_headers; /* -p */ +static int prefix_addresses; /* --prefix-addresses */ +static int with_line_numbers; /* -l */ +static boolean with_source_code; /* -S */ +static int show_raw_insn; /* --show-raw-insn */ +static int dump_stab_section_info; /* --stabs */ +static int do_demangle; /* -C, --demangle */ +static boolean disassemble; /* -d */ +static boolean disassemble_all; /* -D */ +static int disassemble_zeroes; /* --disassemble-zeroes */ +static boolean formats_info; /* -i */ +static char *only; /* -j secname */ +static int wide_output; /* -w */ +static bfd_vma start_address = (bfd_vma) -1; /* --start-address */ +static bfd_vma stop_address = (bfd_vma) -1; /* --stop-address */ +static int dump_debugging; /* --debugging */ +static bfd_vma adjust_section_vma = 0; /* --adjust-vma */ + +/* Extra info to pass to the disassembler address printing function. */ struct objdump_disasm_info { bfd *abfd; asection *sec; + boolean require_sec; }; -char *machine = (char *) NULL; -asymbol **syms; +/* Architecture to disassemble for, or default if NULL. */ +static char *machine = (char *) NULL; + +/* Endianness to disassemble for, or default if BFD_ENDIAN_UNKNOWN. */ +static enum bfd_endian endian = BFD_ENDIAN_UNKNOWN; + +/* The symbol table. */ +static asymbol **syms; -unsigned int storage; +/* Number of symbols in `syms'. */ +static long symcount = 0; -unsigned int symcount = 0; +/* The sorted symbol table. */ +static asymbol **sorted_syms; -/* Forward declarations. */ +/* Number of symbols in `sorted_syms'. */ +static long sorted_symcount = 0; + +/* The dynamic symbol table. */ +static asymbol **dynsyms; + +/* Number of symbols in `dynsyms'. */ +static long dynsymcount = 0; + +/* Static declarations. */ + +static void +usage PARAMS ((FILE *, int)); static void display_file PARAMS ((char *filename, char *target)); +static void +dump_section_header PARAMS ((bfd *, asection *, PTR)); + +static void +dump_headers PARAMS ((bfd *)); + static void dump_data PARAMS ((bfd *abfd)); @@ -76,132 +124,327 @@ static void dump_relocs PARAMS ((bfd *abfd)); static void -dump_symbols PARAMS ((bfd *abfd)); +dump_dynamic_relocs PARAMS ((bfd * abfd)); + +static void +dump_reloc_set PARAMS ((bfd *, asection *, arelent **, long)); + +static void +dump_symbols PARAMS ((bfd *abfd, boolean dynamic)); + +static void +dump_bfd_header PARAMS ((bfd *)); + +static void +dump_bfd_private_header PARAMS ((bfd *)); static void display_bfd PARAMS ((bfd *abfd)); + +static void +display_target_list PARAMS ((void)); + +static void +display_info_table PARAMS ((int, int)); + +static void +display_target_tables PARAMS ((void)); + +static void +display_info PARAMS ((void)); + +static void +objdump_print_value PARAMS ((bfd_vma, struct disassemble_info *, boolean)); + +static void +objdump_print_symname PARAMS ((bfd *, struct disassemble_info *, asymbol *)); + +static asymbol * +find_symbol_for_address PARAMS ((bfd *, asection *, bfd_vma, boolean, long *)); + +static void +objdump_print_addr_with_sym PARAMS ((bfd *, asection *, asymbol *, bfd_vma, + struct disassemble_info *, boolean)); + +static void +objdump_print_addr PARAMS ((bfd_vma, struct disassemble_info *, boolean)); + +static void +objdump_print_address PARAMS ((bfd_vma, struct disassemble_info *)); + +static void +show_line PARAMS ((bfd *, asection *, bfd_vma)); + +static void +disassemble_bytes PARAMS ((struct disassemble_info *, disassembler_ftype, + boolean, bfd_byte *, long, long, arelent ***, + arelent **)); + +static void +disassemble_data PARAMS ((bfd *)); + +static const char * +endian_string PARAMS ((enum bfd_endian)); + +static asymbol ** +slurp_symtab PARAMS ((bfd *)); + +static asymbol ** +slurp_dynamic_symtab PARAMS ((bfd *)); + +static long +remove_useless_symbols PARAMS ((asymbol **, long)); + +static int +compare_symbols PARAMS ((const PTR, const PTR)); + +static int +compare_relocs PARAMS ((const PTR, const PTR)); + +static void +dump_stabs PARAMS ((bfd *)); + +static boolean +read_section_stabs PARAMS ((bfd *, const char *, const char *)); + +static void +print_section_stabs PARAMS ((bfd *, const char *, const char *)); -void +static void usage (stream, status) FILE *stream; int status; { fprintf (stream, "\ -Usage: %s [-ahifdrtxsl] [-b bfdname] [-m machine] [-j section-name]\n\ - [--archive-headers] [--target=bfdname] [--disassemble] [--file-headers]\n\ - [--section-headers] [--headers] [--info] [--section=section-name]\n\ - [--line-numbers] [--architecture=machine] [--reloc] [--full-contents]\n\ - [--stabs] [--syms] [--all-headers] [--version] [--help] objfile...\n\ -at least one option besides -l (--line-numbers) must be given\n", +Usage: %s [-ahifCdDprRtTxsSlw] [-b bfdname] [-m machine] [-j section-name]\n\ + [--archive-headers] [--target=bfdname] [--debugging] [--disassemble]\n\ + [--disassemble-all] [--disassemble-zeroes] [--file-headers]\n\ + [--section-headers] [--headers]\n\ + [--info] [--section=section-name] [--line-numbers] [--source]\n", program_name); + fprintf (stream, "\ + [--architecture=machine] [--reloc] [--full-contents] [--stabs]\n\ + [--syms] [--all-headers] [--dynamic-syms] [--dynamic-reloc]\n\ + [--wide] [--version] [--help] [--private-headers]\n\ + [--start-address=addr] [--stop-address=addr]\n\ + [--prefix-addresses] [--[no-]show-raw-insn] [--demangle]\n\ + [--adjust-vma=offset] [-EB|-EL] [--endian={big|little}] objfile...\n\ +at least one option besides -l (--line-numbers) must be given\n"); + list_supported_targets (program_name, stream); + if (status == 0) + fprintf (stream, "Report bugs to bug-gnu-utils@prep.ai.mit.edu\n"); exit (status); } +/* 150 isn't special; it's just an arbitrary non-ASCII char value. */ + +#define OPTION_ENDIAN (150) +#define OPTION_START_ADDRESS (OPTION_ENDIAN + 1) +#define OPTION_STOP_ADDRESS (OPTION_START_ADDRESS + 1) +#define OPTION_ADJUST_VMA (OPTION_STOP_ADDRESS + 1) + static struct option long_options[]= { + {"adjust-vma", required_argument, NULL, OPTION_ADJUST_VMA}, {"all-headers", no_argument, NULL, 'x'}, + {"private-headers", no_argument, NULL, 'p'}, {"architecture", required_argument, NULL, 'm'}, {"archive-headers", no_argument, NULL, 'a'}, + {"debugging", no_argument, &dump_debugging, 1}, + {"demangle", no_argument, &do_demangle, 1}, {"disassemble", no_argument, NULL, 'd'}, + {"disassemble-all", no_argument, NULL, 'D'}, + {"disassemble-zeroes", no_argument, &disassemble_zeroes, 1}, + {"dynamic-reloc", no_argument, NULL, 'R'}, + {"dynamic-syms", no_argument, NULL, 'T'}, + {"endian", required_argument, NULL, OPTION_ENDIAN}, {"file-headers", no_argument, NULL, 'f'}, {"full-contents", no_argument, NULL, 's'}, {"headers", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'H'}, {"info", no_argument, NULL, 'i'}, {"line-numbers", no_argument, NULL, 'l'}, + {"no-show-raw-insn", no_argument, &show_raw_insn, -1}, + {"prefix-addresses", no_argument, &prefix_addresses, 1}, {"reloc", no_argument, NULL, 'r'}, {"section", required_argument, NULL, 'j'}, {"section-headers", no_argument, NULL, 'h'}, + {"show-raw-insn", no_argument, &show_raw_insn, 1}, + {"source", no_argument, NULL, 'S'}, {"stabs", no_argument, &dump_stab_section_info, 1}, + {"start-address", required_argument, NULL, OPTION_START_ADDRESS}, + {"stop-address", required_argument, NULL, OPTION_STOP_ADDRESS}, {"syms", no_argument, NULL, 't'}, {"target", required_argument, NULL, 'b'}, - {"version", no_argument, &show_version, 1}, + {"version", no_argument, &show_version, 1}, + {"wide", no_argument, &wide_output, 'w'}, {0, no_argument, 0, 0} }; - - + static void -dump_headers (abfd) +dump_section_header (abfd, section, ignored) bfd *abfd; + asection *section; + PTR ignored; { - asection *section; - - for (section = abfd->sections; - section != (asection *) NULL; - section = section->next) - { - char *comma = ""; - -#define PF(x,y) \ - if (section->flags & x) { printf("%s%s",comma,y); comma = ", "; } - - - printf ("SECTION %d [%s]\t: size %08x", - section->index, - section->name, - (unsigned) bfd_get_section_size_before_reloc (section)); - printf (" vma "); - printf_vma (section->vma); - printf (" align 2**%u\n ", - section->alignment_power); - PF (SEC_ALLOC, "ALLOC"); - PF (SEC_CONSTRUCTOR, "CONSTRUCTOR"); - PF (SEC_CONSTRUCTOR_TEXT, "CONSTRUCTOR TEXT"); - PF (SEC_CONSTRUCTOR_DATA, "CONSTRUCTOR DATA"); - PF (SEC_CONSTRUCTOR_BSS, "CONSTRUCTOR BSS"); - PF (SEC_LOAD, "LOAD"); - PF (SEC_RELOC, "RELOC"); + char *comma = ""; + + printf ("%3d %-13s %08lx ", section->index, + bfd_get_section_name (abfd, section), + (unsigned long) bfd_section_size (abfd, section)); + printf_vma (bfd_get_section_vma (abfd, section)); + printf (" "); + printf_vma (section->lma); + printf (" %08lx 2**%u", section->filepos, + bfd_get_section_alignment (abfd, section)); + if (! wide_output) + printf ("\n "); + printf (" "); + +#define PF(x, y) \ + if (section->flags & x) { printf ("%s%s", comma, y); comma = ", "; } + + PF (SEC_HAS_CONTENTS, "CONTENTS"); + PF (SEC_ALLOC, "ALLOC"); + PF (SEC_CONSTRUCTOR, "CONSTRUCTOR"); + PF (SEC_CONSTRUCTOR_TEXT, "CONSTRUCTOR TEXT"); + PF (SEC_CONSTRUCTOR_DATA, "CONSTRUCTOR DATA"); + PF (SEC_CONSTRUCTOR_BSS, "CONSTRUCTOR BSS"); + PF (SEC_LOAD, "LOAD"); + PF (SEC_RELOC, "RELOC"); #ifdef SEC_BALIGN - PF (SEC_BALIGN, "BALIGN"); + PF (SEC_BALIGN, "BALIGN"); #endif - PF (SEC_READONLY, "READONLY"); - PF (SEC_CODE, "CODE"); - PF (SEC_DATA, "DATA"); - PF (SEC_ROM, "ROM"); - PF (SEC_DEBUGGING, "DEBUGGING"); - printf ("\n"); -#undef PF + PF (SEC_READONLY, "READONLY"); + PF (SEC_CODE, "CODE"); + PF (SEC_DATA, "DATA"); + PF (SEC_ROM, "ROM"); + PF (SEC_DEBUGGING, "DEBUGGING"); + PF (SEC_NEVER_LOAD, "NEVER_LOAD"); + PF (SEC_EXCLUDE, "EXCLUDE"); + PF (SEC_SORT_ENTRIES, "SORT_ENTRIES"); + + if ((section->flags & SEC_LINK_ONCE) != 0) + { + const char *ls; + + switch (section->flags & SEC_LINK_DUPLICATES) + { + default: + abort (); + case SEC_LINK_DUPLICATES_DISCARD: + ls = "LINK_ONCE_DISCARD"; + break; + case SEC_LINK_DUPLICATES_ONE_ONLY: + ls = "LINK_ONCE_ONE_ONLY"; + break; + case SEC_LINK_DUPLICATES_SAME_SIZE: + ls = "LINK_ONCE_SAME_SIZE"; + break; + case SEC_LINK_DUPLICATES_SAME_CONTENTS: + ls = "LINK_ONCE_SAME_CONTENTS"; + break; + } + printf ("%s%s", comma, ls); + comma = ", "; } + + printf ("\n"); +#undef PF } +static void +dump_headers (abfd) + bfd *abfd; +{ + printf ("Sections:\n"); +#ifndef BFD64 + printf ("Idx Name Size VMA LMA File off Algn\n"); +#else + printf ("Idx Name Size VMA LMA File off Algn\n"); +#endif + bfd_map_over_sections (abfd, dump_section_header, (PTR) NULL); +} + static asymbol ** -DEFUN (slurp_symtab, (abfd), - bfd * abfd) +slurp_symtab (abfd) + bfd *abfd; { asymbol **sy = (asymbol **) NULL; + long storage; if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) { - (void) printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd)); - return (NULL); + printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd)); + symcount = 0; + return NULL; } - storage = get_symtab_upper_bound (abfd); + storage = bfd_get_symtab_upper_bound (abfd); + if (storage < 0) + bfd_fatal (bfd_get_filename (abfd)); + if (storage) { sy = (asymbol **) xmalloc (storage); } symcount = bfd_canonicalize_symtab (abfd, sy); - if (symcount <= 0) + if (symcount < 0) + bfd_fatal (bfd_get_filename (abfd)); + if (symcount == 0) + fprintf (stderr, "%s: %s: No symbols\n", + program_name, bfd_get_filename (abfd)); + return sy; +} + +/* Read in the dynamic symbols. */ + +static asymbol ** +slurp_dynamic_symtab (abfd) + bfd *abfd; +{ + asymbol **sy = (asymbol **) NULL; + long storage; + + storage = bfd_get_dynamic_symtab_upper_bound (abfd); + if (storage < 0) + { + if (!(bfd_get_file_flags (abfd) & DYNAMIC)) + { + fprintf (stderr, "%s: %s: not a dynamic object\n", + program_name, bfd_get_filename (abfd)); + dynsymcount = 0; + return NULL; + } + + bfd_fatal (bfd_get_filename (abfd)); + } + + if (storage) { - fprintf (stderr, "%s: Bad symbol table in \"%s\".\n", - program_name, bfd_get_filename (abfd)); - exit (1); + sy = (asymbol **) xmalloc (storage); } + dynsymcount = bfd_canonicalize_dynamic_symtab (abfd, sy); + if (dynsymcount < 0) + bfd_fatal (bfd_get_filename (abfd)); + if (dynsymcount == 0) + fprintf (stderr, "%s: %s: No dynamic symbols\n", + program_name, bfd_get_filename (abfd)); return sy; } -/* Filter out (in place) symbols that are useless for dis-assemble. - Return count of useful symbols. */ +/* Filter out (in place) symbols that are useless for disassembly. + COUNT is the number of elements in SYMBOLS. + Return the number of useful symbols. */ -int remove_useless_symbols (syms, count) - asymbol **syms; - int count; +static long +remove_useless_symbols (symbols, count) + asymbol **symbols; + long count; { - register asymbol **in_ptr = syms; - register asymbol **out_ptr = syms; + register asymbol **in_ptr = symbols, **out_ptr = symbols; - while ( --count >= 0 ) + while (--count >= 0) { asymbol *sym = *in_ptr++; @@ -209,622 +452,1414 @@ int remove_useless_symbols (syms, count) continue; if (sym->flags & (BSF_DEBUGGING)) continue; - if (sym->section == &bfd_und_section + if (bfd_is_und_section (sym->section) || bfd_is_com_section (sym->section)) continue; *out_ptr++ = sym; } - return out_ptr - syms; + return out_ptr - symbols; } +/* Sort symbols into value order. */ -/* Sort symbols into value order */ static int -comp (ap, bp) - PTR ap; - PTR bp; +compare_symbols (ap, bp) + const PTR ap; + const PTR bp; { - asymbol *a = *(asymbol **)ap; - asymbol *b = *(asymbol **)bp; - - if (a->value > b->value) + const asymbol *a = *(const asymbol **)ap; + const asymbol *b = *(const asymbol **)bp; + const char *an, *bn; + size_t anl, bnl; + boolean af, bf; + flagword aflags, bflags; + + if (bfd_asymbol_value (a) > bfd_asymbol_value (b)) return 1; - else if (a->value < b->value) + else if (bfd_asymbol_value (a) < bfd_asymbol_value (b)) return -1; if (a->section > b->section) return 1; else if (a->section < b->section) return -1; - return 0; + + an = bfd_asymbol_name (a); + bn = bfd_asymbol_name (b); + anl = strlen (an); + bnl = strlen (bn); + + /* The symbols gnu_compiled and gcc2_compiled convey no real + information, so put them after other symbols with the same value. */ + + af = (strstr (an, "gnu_compiled") != NULL + || strstr (an, "gcc2_compiled") != NULL); + bf = (strstr (bn, "gnu_compiled") != NULL + || strstr (bn, "gcc2_compiled") != NULL); + + if (af && ! bf) + return 1; + if (! af && bf) + return -1; + + /* We use a heuristic for the file name, to try to sort it after + more useful symbols. It may not work on non Unix systems, but it + doesn't really matter; the only difference is precisely which + symbol names get printed. */ + +#define file_symbol(s, sn, snl) \ + (((s)->flags & BSF_FILE) != 0 \ + || ((sn)[(snl) - 2] == '.' \ + && ((sn)[(snl) - 1] == 'o' \ + || (sn)[(snl) - 1] == 'a'))) + + af = file_symbol (a, an, anl); + bf = file_symbol (b, bn, bnl); + + if (af && ! bf) + return 1; + if (! af && bf) + return -1; + + /* Try to sort global symbols before local symbols before function + symbols before debugging symbols. */ + + aflags = a->flags; + bflags = b->flags; + + if ((aflags & BSF_DEBUGGING) != (bflags & BSF_DEBUGGING)) + { + if ((aflags & BSF_DEBUGGING) != 0) + return 1; + else + return -1; + } + if ((aflags & BSF_FUNCTION) != (bflags & BSF_FUNCTION)) + { + if ((aflags & BSF_FUNCTION) != 0) + return -1; + else + return 1; + } + if ((aflags & BSF_LOCAL) != (bflags & BSF_LOCAL)) + { + if ((aflags & BSF_LOCAL) != 0) + return 1; + else + return -1; + } + if ((aflags & BSF_GLOBAL) != (bflags & BSF_GLOBAL)) + { + if ((aflags & BSF_GLOBAL) != 0) + return -1; + else + return 1; + } + + /* Symbols that start with '.' might be section names, so sort them + after symbols that don't start with '.'. */ + if (an[0] == '.' && bn[0] != '.') + return 1; + if (an[0] != '.' && bn[0] == '.') + return -1; + + /* Finally, if we can't distinguish them in any other way, try to + get consistent results by sorting the symbols by name. */ + return strcmp (an, bn); } -/* Print the supplied address symbolically if possible */ -void -objdump_print_address (vma, info) +/* Sort relocs into address order. */ + +static int +compare_relocs (ap, bp) + const PTR ap; + const PTR bp; +{ + const arelent *a = *(const arelent **)ap; + const arelent *b = *(const arelent **)bp; + + if (a->address > b->address) + return 1; + else if (a->address < b->address) + return -1; + + /* So that associated relocations tied to the same address show up + in the correct order, we don't do any further sorting. */ + if (a > b) + return 1; + else if (a < b) + return -1; + else + return 0; +} + +/* Print VMA to STREAM. If SKIP_ZEROES is true, omit leading zeroes. */ + +static void +objdump_print_value (vma, info, skip_zeroes) bfd_vma vma; struct disassemble_info *info; + boolean skip_zeroes; +{ + char buf[30]; + char *p; + + sprintf_vma (buf, vma); + if (! skip_zeroes) + p = buf; + else + { + for (p = buf; *p == '0'; ++p) + ; + if (*p == '\0') + --p; + } + (*info->fprintf_func) (info->stream, "%s", p); +} + +/* Print the name of a symbol. */ + +static void +objdump_print_symname (abfd, info, sym) + bfd *abfd; + struct disassemble_info *info; + asymbol *sym; +{ + char *alloc; + const char *name; + const char *print; + + alloc = NULL; + name = bfd_asymbol_name (sym); + if (! do_demangle || name[0] == '\0') + print = name; + else + { + /* Demangle the name. */ + if (bfd_get_symbol_leading_char (abfd) == name[0]) + ++name; + + alloc = cplus_demangle (name, DMGL_ANSI | DMGL_PARAMS); + if (alloc == NULL) + print = name; + else + print = alloc; + } + + if (info != NULL) + (*info->fprintf_func) (info->stream, "%s", print); + else + printf ("%s", print); + + if (alloc != NULL) + free (alloc); +} + +/* Locate a symbol given a bfd, a section, and a VMA. If REQUIRE_SEC + is true, then always require the symbol to be in the section. This + returns NULL if there is no suitable symbol. If PLACE is not NULL, + then *PLACE is set to the index of the symbol in sorted_syms. */ + +static asymbol * +find_symbol_for_address (abfd, sec, vma, require_sec, place) + bfd *abfd; + asection *sec; + bfd_vma vma; + boolean require_sec; + long *place; { - /* Perform a binary search looking for the closest symbol to - the required value. */ - /* @@ For relocateable files, should filter out symbols belonging to - the wrong section. Unfortunately, not enough information is supplied - to this routine to determine the correct section in all cases. */ /* @@ Would it speed things up to cache the last two symbols returned, and maybe their address ranges? For many processors, only one memory operand can be present at a time, so the 2-entry cache wouldn't be constantly churned by code doing heavy memory accesses. */ - unsigned int min = 0; - unsigned int max = symcount; + /* Indices in `sorted_syms'. */ + long min = 0; + long max = sorted_symcount; + long thisplace; - unsigned int thisplace = 1; - unsigned int oldthisplace; + if (sorted_symcount < 1) + return NULL; + + /* Perform a binary search looking for the closest symbol to the + required value. We are searching the range (min, max]. */ + while (min + 1 < max) + { + asymbol *sym; - int vardiff; + thisplace = (max + min) / 2; + sym = sorted_syms[thisplace]; - fprintf_vma (info->stream, vma); + if (bfd_asymbol_value (sym) > vma) + max = thisplace; + else if (bfd_asymbol_value (sym) < vma) + min = thisplace; + else + { + min = thisplace; + break; + } + } - if (symcount > 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. */ + thisplace = min; + while (thisplace > 0 + && (bfd_asymbol_value (sorted_syms[thisplace]) + == bfd_asymbol_value (sorted_syms[thisplace - 1]))) + --thisplace; + + /* If the file is relocateable, and the symbol could be from this + section, prefer a symbol from this section over symbols from + others, even if the other symbol's value might be closer. + + Note that this may be wrong for some symbol references if the + sections have overlapping memory ranges, but in that case there's + no way to tell what's desired without looking at the relocation + table. */ + + if (sorted_syms[thisplace]->section != sec + && (require_sec + || ((abfd->flags & HAS_RELOC) != 0 + && vma >= bfd_get_section_vma (abfd, sec) + && vma < (bfd_get_section_vma (abfd, sec) + + bfd_section_size (abfd, sec))))) { - while (true) + long i; + + for (i = thisplace + 1; i < sorted_symcount; i++) { - asymbol *sym; asection *sym_sec; - oldthisplace = thisplace; - thisplace = (max + min) / 2; - if (thisplace == oldthisplace) + if (bfd_asymbol_value (sorted_syms[i]) + != bfd_asymbol_value (sorted_syms[thisplace])) break; - sym = syms[thisplace]; - vardiff = sym->value - vma; - sym_sec = sym->section; - - if (vardiff > 0) - max = thisplace; - else if (vardiff < 0) - min = thisplace; - else - goto found; } - /* We've run out of places to look, print the symbol before this one - see if this or the symbol before describes this location the best */ - - if (thisplace != 0) + --i; + for (; i >= 0; i--) { - if (syms[thisplace - 1]->value - vma > - syms[thisplace]->value - vma) + if (sorted_syms[i]->section == sec + && (i == 0 + || sorted_syms[i - 1]->section != sec + || (bfd_asymbol_value (sorted_syms[i]) + != bfd_asymbol_value (sorted_syms[i - 1])))) { - /* Previous symbol is in correct section and is closer */ - thisplace--; + thisplace = i; + break; } } - found: - { - bfd_vma val = syms[thisplace]->value; - int i; - if (syms[thisplace]->flags & (BSF_LOCAL|BSF_DEBUGGING)) - for (i = thisplace - 1; i >= 0; i--) - { - if (syms[i]->value == val - && (!(syms[i]->flags & (BSF_LOCAL|BSF_DEBUGGING)) - || ((syms[thisplace]->flags & BSF_DEBUGGING) - && !(syms[i]->flags & BSF_DEBUGGING)))) - { - thisplace = i; - break; - } - } - if (syms[thisplace]->flags & (BSF_LOCAL|BSF_DEBUGGING)) - for (i = thisplace + 1; i < symcount; i++) + if (sorted_syms[thisplace]->section != sec) + { + /* We didn't find a good symbol with a smaller value. + Look for one with a larger value. */ + for (i = thisplace + 1; i < sorted_symcount; i++) { - if (syms[i]->value == val - && (!(syms[i]->flags & (BSF_LOCAL|BSF_DEBUGGING)) - || ((syms[thisplace]->flags & BSF_DEBUGGING) - && !(syms[i]->flags & BSF_DEBUGGING)))) + if (sorted_syms[i]->section == sec) { thisplace = i; break; } } - } - { - /* If the file is relocateable, and the symbol could be from this - section, prefer a symbol from this section over symbols from - others, even if the other symbol's value might be closer. - - Note that this may be wrong for some symbol references if the - sections have overlapping memory ranges, but in that case there's - no way to tell what's desired without looking at the relocation - table. */ - struct objdump_disasm_info *aux; - int i; - - aux = (struct objdump_disasm_info *) info->application_data; - if (aux->abfd->flags & HAS_RELOC - && vma >= bfd_get_section_vma (aux->abfd, aux->sec) - && vma < (bfd_get_section_vma (aux->abfd, aux->sec) - + bfd_get_section_size_before_reloc (aux->sec)) - && syms[thisplace]->section != aux->sec) - { - for (i = thisplace + 1; i < symcount; i++) - if (syms[i]->value != syms[thisplace]->value) - break; - while (--i >= 0) - if (syms[i]->section == aux->sec) - { - thisplace = i; - break; - } - } - } - fprintf (info->stream, " <%s", syms[thisplace]->name); - if (syms[thisplace]->value > vma) - { - char buf[30], *p = buf; - sprintf_vma (buf, syms[thisplace]->value - vma); - while (*p == '0') - p++; - fprintf (info->stream, "-%s", p); } - else if (vma > syms[thisplace]->value) + + if (sorted_syms[thisplace]->section != sec + && (require_sec + || ((abfd->flags & HAS_RELOC) != 0 + && vma >= bfd_get_section_vma (abfd, sec) + && vma < (bfd_get_section_vma (abfd, sec) + + bfd_section_size (abfd, sec))))) { - char buf[30], *p = buf; - sprintf_vma (buf, vma - syms[thisplace]->value); - while (*p == '0') - p++; - fprintf (info->stream, "+%s", p); + /* There is no suitable symbol. */ + return NULL; } - fprintf (info->stream, ">"); } + + if (place != NULL) + *place = thisplace; + + return sorted_syms[thisplace]; } -#ifdef ARCH_all -#define ARCH_a29k -#define ARCH_alpha -#define ARCH_h8300 -#define ARCH_h8500 -#define ARCH_hppa -#define ARCH_i386 -#define ARCH_i960 -#define ARCH_m68k -#define ARCH_m88k -#define ARCH_mips -#define ARCH_rs6000 -#define ARCH_sh -#define ARCH_sparc -#define ARCH_z8k -#endif +/* Print an address to INFO symbolically. */ -void -disassemble_data (abfd) +static void +objdump_print_addr_with_sym (abfd, sec, sym, vma, info, skip_zeroes) bfd *abfd; + asection *sec; + asymbol *sym; + bfd_vma vma; + struct disassemble_info *info; + boolean skip_zeroes; { - bfd_byte *data = NULL; - bfd_arch_info_type *info; - bfd_size_type datasize = 0; - bfd_size_type i; - unsigned int (*print) ()= 0; /* Old style */ - disassembler_ftype disassemble = 0; /* New style */ - enum bfd_architecture a; - struct disassemble_info disasm_info; - struct objdump_disasm_info aux; + objdump_print_value (vma, info, skip_zeroes); - int prevline; - CONST char *prev_function = ""; + if (sym == NULL) + { + bfd_vma secaddr; - asection *section; + (*info->fprintf_func) (info->stream, " <%s", + bfd_get_section_name (abfd, sec)); + secaddr = bfd_get_section_vma (abfd, sec); + if (vma < secaddr) + { + (*info->fprintf_func) (info->stream, "-0x"); + objdump_print_value (secaddr - vma, info, true); + } + else if (vma > secaddr) + { + (*info->fprintf_func) (info->stream, "+0x"); + objdump_print_value (vma - secaddr, info, true); + } + (*info->fprintf_func) (info->stream, ">"); + } + else + { + (*info->fprintf_func) (info->stream, " <"); + objdump_print_symname (abfd, info, sym); + if (bfd_asymbol_value (sym) > vma) + { + (*info->fprintf_func) (info->stream, "-0x"); + objdump_print_value (bfd_asymbol_value (sym) - vma, info, true); + } + else if (vma > bfd_asymbol_value (sym)) + { + (*info->fprintf_func) (info->stream, "+0x"); + objdump_print_value (vma - bfd_asymbol_value (sym), info, true); + } + (*info->fprintf_func) (info->stream, ">"); + + /* Notify the disassembler of the symbol being used: */ + disasm_symaddr (sym, info); + } +} - /* Replace symbol section relative values with abs values */ - boolean done_dot = false; +/* Print VMA to INFO, symbolically if possible. If SKIP_ZEROES is + true, don't output leading zeroes. */ - INIT_DISASSEMBLE_INFO(disasm_info, stdout); - disasm_info.application_data = (PTR) &aux; - aux.abfd = abfd; - disasm_info.print_address_func = objdump_print_address; +static void +objdump_print_addr (vma, info, skip_zeroes) + bfd_vma vma; + struct disassemble_info *info; + boolean skip_zeroes; +{ + struct objdump_disasm_info *aux; + asymbol *sym; - for (i = 0; i < symcount; i++) + if (sorted_symcount < 1) { - syms[i]->value += syms[i]->section->vma; + (*info->fprintf_func) (info->stream, "0x"); + objdump_print_value (vma, info, skip_zeroes); + return; } - symcount = remove_useless_symbols (syms, symcount); + aux = (struct objdump_disasm_info *) info->application_data; + sym = find_symbol_for_address (aux->abfd, aux->sec, vma, aux->require_sec, + (long *) NULL); + objdump_print_addr_with_sym (aux->abfd, aux->sec, sym, vma, info, + skip_zeroes); +} - /* Sort the symbols into section and symbol order */ - (void) qsort (syms, symcount, sizeof (asymbol *), comp); +/* Print VMA to INFO. This function is passed to the disassembler + routine. */ - if (machine != (char *) NULL) +static void +objdump_print_address (vma, info) + bfd_vma vma; + struct disassemble_info *info; +{ + objdump_print_addr (vma, info, ! prefix_addresses); +} + +/* Determine of the given address has a symbol associated with it. */ + +static int +objdump_symbol_at_address (vma, info) + bfd_vma vma; + struct disassemble_info * info; +{ + struct objdump_disasm_info * aux; + asymbol * sym; + + /* No symbols - do not bother checking. */ + if (sorted_symcount < 1) + return 0; + + aux = (struct objdump_disasm_info *) info->application_data; + sym = find_symbol_for_address (aux->abfd, aux->sec, vma, aux->require_sec, + (long *) NULL); + + return (sym != NULL && (bfd_asymbol_value (sym) == vma)); +} + +/* Hold the last function name and the last line number we displayed + in a disassembly. */ + +static char *prev_functionname; +static unsigned int prev_line; + +/* We keep a list of all files that we have seen when doing a + dissassembly with source, so that we know how much of the file to + display. This can be important for inlined functions. */ + +struct print_file_list +{ + struct print_file_list *next; + char *filename; + unsigned int line; + FILE *f; +}; + +static struct print_file_list *print_files; + +/* The number of preceding context lines to show when we start + displaying a file for the first time. */ + +#define SHOW_PRECEDING_CONTEXT_LINES (5) + +/* Skip ahead to a given line in a file, optionally printing each + line. */ + +static void +skip_to_line PARAMS ((struct print_file_list *, unsigned int, boolean)); + +static void +skip_to_line (p, line, show) + struct print_file_list *p; + unsigned int line; + boolean show; +{ + while (p->line < line) { - info = bfd_scan_arch (machine); - if (info == 0) + char buf[100]; + + if (fgets (buf, sizeof buf, p->f) == NULL) { - fprintf (stderr, "%s: Can't use supplied machine %s\n", - program_name, - machine); - exit (1); + fclose (p->f); + p->f = NULL; + break; } - abfd->arch_info = info; + + if (show) + printf ("%s", buf); + + if (strchr (buf, '\n') != NULL) + ++p->line; } +} - /* See if we can disassemble using bfd */ +/* Show the line number, or the source line, in a dissassembly + listing. */ - if (abfd->arch_info->disassemble) +static void +show_line (abfd, section, off) + bfd *abfd; + asection *section; + bfd_vma off; +{ + CONST char *filename; + CONST char *functionname; + unsigned int line; + + if (! with_line_numbers && ! with_source_code) + return; + + if (! bfd_find_nearest_line (abfd, section, syms, off, &filename, + &functionname, &line)) + return; + + if (filename != NULL && *filename == '\0') + filename = NULL; + if (functionname != NULL && *functionname == '\0') + functionname = NULL; + + if (with_line_numbers) { - print = abfd->arch_info->disassemble; + if (functionname != NULL + && (prev_functionname == NULL + || strcmp (functionname, prev_functionname) != 0)) + printf ("%s():\n", functionname); + if (line > 0 && line != prev_line) + printf ("%s:%u\n", filename == NULL ? "???" : filename, line); } - else + + if (with_source_code + && filename != NULL + && line > 0) { - a = bfd_get_arch (abfd); - switch (a) - { - /* If you add a case to this table, also add it to the - ARCH_all definition right above this function. */ -#ifdef ARCH_a29k - case bfd_arch_a29k: - /* As far as I know we only handle big-endian 29k objects. */ - disassemble = print_insn_big_a29k; - break; -#endif -#ifdef ARCH_alpha - case bfd_arch_alpha: - disassemble = print_insn_alpha; - break; -#endif -#ifdef ARCH_h8300 - case bfd_arch_h8300: - if (bfd_get_mach(abfd) == bfd_mach_h8300h) - disassemble = print_insn_h8300h; - else - disassemble = print_insn_h8300; - break; -#endif -#ifdef ARCH_h8500 - case bfd_arch_h8500: - disassemble = print_insn_h8500; - break; -#endif -#ifdef ARCH_hppa - case bfd_arch_hppa: - disassemble = print_insn_hppa; - break; -#endif -#ifdef ARCH_i386 - case bfd_arch_i386: - disassemble = print_insn_i386; - break; -#endif -#ifdef ARCH_i960 - case bfd_arch_i960: - disassemble = print_insn_i960; - break; -#endif -#ifdef ARCH_m68k - case bfd_arch_m68k: - disassemble = print_insn_m68k; - break; -#endif -#ifdef ARCH_m88k - case bfd_arch_m88k: - disassemble = print_insn_m88k; - break; -#endif -#ifdef ARCH_mips - case bfd_arch_mips: - if (abfd->xvec->byteorder_big_p) - disassemble = print_insn_big_mips; - else - disassemble = print_insn_little_mips; - break; -#endif -#ifdef ARCH_rs6000: - case bfd_arch_rs6000: - disassemble = print_insn_rs6000; - break; -#endif -#ifdef ARCH_sh - case bfd_arch_sh: - disassemble = print_insn_sh; - break; -#endif -#ifdef ARCH_sparc - case bfd_arch_sparc: - disassemble = print_insn_sparc; - break; -#endif -#ifdef ARCH_z8k - case bfd_arch_z8k: - if (bfd_get_mach(abfd) == bfd_mach_z8001) - disassemble = print_insn_z8001; - else - disassemble = print_insn_z8002; + struct print_file_list **pp, *p; + + for (pp = &print_files; *pp != NULL; pp = &(*pp)->next) + if (strcmp ((*pp)->filename, filename) == 0) break; -#endif - default: - fprintf (stderr, "%s: Can't disassemble for architecture %s\n", - program_name, - bfd_printable_arch_mach (bfd_get_arch (abfd), 0)); - exit (1); + p = *pp; + + if (p != NULL) + { + if (p != print_files) + { + int l; + + /* We have reencountered a file name which we saw + earlier. This implies that either we are dumping out + code from an included file, or the same file was + linked in more than once. There are two common cases + of an included file: inline functions in a header + file, and a bison or flex skeleton file. In the + former case we want to just start printing (but we + back up a few lines to give context); in the latter + case we want to continue from where we left off. I + can't think of a good way to distinguish the cases, + so I used a heuristic based on the file name. */ + if (strcmp (p->filename + strlen (p->filename) - 2, ".h") != 0) + l = p->line; + else + { + l = line - SHOW_PRECEDING_CONTEXT_LINES; + if (l <= 0) + l = 1; + } + + if (p->f == NULL) + { + p->f = fopen (p->filename, "r"); + p->line = 0; + } + if (p->f != NULL) + skip_to_line (p, l, false); + + if (print_files->f != NULL) + { + fclose (print_files->f); + print_files->f = NULL; + } + } + + if (p->f != NULL) + { + skip_to_line (p, line, true); + *pp = p->next; + p->next = print_files; + print_files = p; + } } + else + { + FILE *f; + f = fopen (filename, "r"); + if (f != NULL) + { + int l; + + p = ((struct print_file_list *) + xmalloc (sizeof (struct print_file_list))); + p->filename = xmalloc (strlen (filename) + 1); + strcpy (p->filename, filename); + p->line = 0; + p->f = f; + + if (print_files != NULL && print_files->f != NULL) + { + fclose (print_files->f); + print_files->f = NULL; + } + p->next = print_files; + print_files = p; + + l = line - SHOW_PRECEDING_CONTEXT_LINES; + if (l <= 0) + l = 1; + skip_to_line (p, l, false); + if (p->f != NULL) + skip_to_line (p, line, true); + } + } } - for (section = abfd->sections; - section != (asection *) NULL; - section = section->next) + if (functionname != NULL + && (prev_functionname == NULL + || strcmp (functionname, prev_functionname) != 0)) { - aux.sec = section; + if (prev_functionname != NULL) + free (prev_functionname); + prev_functionname = xmalloc (strlen (functionname) + 1); + strcpy (prev_functionname, functionname); + } + + if (line > 0 && line != prev_line) + prev_line = line; +} + +/* Pseudo FILE object for strings. */ +typedef struct { + char *buffer; + char *current; +} SFILE; + +/* sprintf to a "stream" */ + +#ifdef ANSI_PROTOTYPES +static int +objdump_sprintf (SFILE *f, const char *format, ...) +{ + int n; + va_list args; + + va_start (args, format); + vsprintf (f->current, format, args); + f->current += n = strlen (f->current); + va_end (args); + return n; +} +#else +static int +objdump_sprintf (va_alist) + va_dcl +{ + int n; + SFILE *f; + const char *format; + va_list args; + + va_start (args); + f = va_arg (args, SFILE *); + format = va_arg (args, const char *); + vsprintf (f->current, format, args); + f->current += n = strlen (f->current); + va_end (args); + return n; +} +#endif + +/* The number of zeroes we want to see before we start skipping them. + The number is arbitrarily chosen. */ + +#define SKIP_ZEROES (8) - if ((section->flags & SEC_LOAD) - && (only == (char *) NULL || strcmp (only, section->name) == 0)) +/* The number of zeroes to skip at the end of a section. If the + number of zeroes at the end is between SKIP_ZEROES_AT_END and + SKIP_ZEROES, they will be disassembled. If there are fewer than + SKIP_ZEROES_AT_END, they will be skipped. This is a heuristic + attempt to avoid disassembling zeroes inserted by section + alignment. */ + +#define SKIP_ZEROES_AT_END (3) + +/* Disassemble some data in memory between given values. */ + +static void +disassemble_bytes (info, disassemble_fn, insns, data, start, stop, relppp, + relppend) + struct disassemble_info *info; + disassembler_ftype disassemble_fn; + boolean insns; + bfd_byte *data; + long start; + long stop; + arelent ***relppp; + arelent **relppend; +{ + struct objdump_disasm_info *aux; + asection *section; + int bytes_per_line; + boolean done_dot; + int skip_addr_chars; + long i; + + aux = (struct objdump_disasm_info *) info->application_data; + section = aux->sec; + + if (insns) + bytes_per_line = 4; + else + bytes_per_line = 16; + + /* Figure out how many characters to skip at the start of an + address, to make the disassembly look nicer. We discard leading + zeroes in chunks of 4, ensuring that there is always a leading + zero remaining. */ + skip_addr_chars = 0; + if (! prefix_addresses) + { + char buf[30]; + char *s; + + sprintf_vma (buf, + section->vma + bfd_section_size (section->owner, section)); + s = buf; + while (s[0] == '0' && s[1] == '0' && s[2] == '0' && s[3] == '0' + && s[4] == '0') { - printf ("Disassembly of section %s:\n", section->name); + skip_addr_chars += 4; + s += 4; + } + } - if (bfd_get_section_size_before_reloc (section) == 0) - continue; + info->insn_info_valid = 0; + + done_dot = false; + i = start; + while (i < stop) + { + long z; + int bytes; + boolean need_nl = false; + + /* If we see more than SKIP_ZEROES bytes of zeroes, we just + print `...'. */ + for (z = i; z < stop; z++) + if (data[z] != 0) + break; + if (! disassemble_zeroes + && (info->insn_info_valid == 0 + || info->branch_delay_insns == 0) + && (z - i >= SKIP_ZEROES + || (z == stop && z - i < SKIP_ZEROES_AT_END))) + { + printf ("\t...\n"); - data = (bfd_byte *) xmalloc ((size_t) bfd_get_section_size_before_reloc (section)); + /* If there are more nonzero bytes to follow, we only skip + zeroes in multiples of 4, to try to avoid running over + the start of an instruction which happens to start with + zero. */ + if (z != stop) + z = i + ((z - i) &~ 3); - datasize = bfd_get_section_size_before_reloc (section); + bytes = z - i; + } + else + { + char buf[1000]; + SFILE sfile; + int bpc, pb = 0; - bfd_get_section_contents (abfd, section, data, 0, bfd_get_section_size_before_reloc (section)); + done_dot = false; - disasm_info.buffer = data; - disasm_info.buffer_vma = section->vma; - disasm_info.buffer_length = - bfd_get_section_size_before_reloc (section); - i = 0; - while (i < disasm_info.buffer_length) + if (with_line_numbers || with_source_code) + show_line (aux->abfd, section, i); + + if (! prefix_addresses) + { + char *s; + + sprintf_vma (buf, section->vma + i); + for (s = buf + skip_addr_chars; *s == '0'; s++) + *s = ' '; + if (*s == '\0') + *--s = '0'; + printf ("%s:\t", buf + skip_addr_chars); + } + else + { + aux->require_sec = true; + objdump_print_address (section->vma + i, info); + aux->require_sec = false; + putchar (' '); + } + + if (insns) + { + sfile.buffer = sfile.current = buf; + info->fprintf_func = (fprintf_ftype) objdump_sprintf; + info->stream = (FILE *) &sfile; + info->bytes_per_line = 0; + info->bytes_per_chunk = 0; + bytes = (*disassemble_fn) (section->vma + i, info); + info->fprintf_func = (fprintf_ftype) fprintf; + info->stream = stdout; + if (info->bytes_per_line != 0) + bytes_per_line = info->bytes_per_line; + if (bytes < 0) + break; + } + else { - if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 && - data[i + 3] == 0) + long j; + + bytes = bytes_per_line; + if (i + bytes > stop) + bytes = stop - i; + + for (j = i; j < i + bytes; ++j) { - if (done_dot == false) + if (isprint (data[j])) + buf[j - i] = data[j]; + else + buf[j - i] = '.'; + } + buf[j - i] = '\0'; + } + + if (prefix_addresses + ? show_raw_insn > 0 + : show_raw_insn >= 0) + { + long j; + + /* If ! prefix_addresses and ! wide_output, we print + bytes_per_line bytes per line. */ + pb = bytes; + if (pb > bytes_per_line && ! prefix_addresses && ! wide_output) + pb = bytes_per_line; + + if (info->bytes_per_chunk) + bpc = info->bytes_per_chunk; + else + bpc = 1; + + for (j = i; j < i + pb; j += bpc) + { + int k; + if (bpc > 1 && info->display_endian == BFD_ENDIAN_LITTLE) + { + for (k = bpc - 1; k >= 0; k--) + printf ("%02x", (unsigned) data[j + k]); + putchar (' '); + } + else { - printf ("...\n"); - done_dot = true; + for (k = 0; k < bpc; k++) + printf ("%02x", (unsigned) data[j + k]); + putchar (' '); } - i += 4; } + + for (; pb < bytes_per_line; pb += bpc) + { + int k; + + for (k = 0; k < bpc; k++) + printf (" "); + putchar (' '); + } + + /* Separate raw data from instruction by extra space. */ + if (insns) + putchar ('\t'); else + printf (" "); + } + + printf ("%s", buf); + + if (prefix_addresses + ? show_raw_insn > 0 + : show_raw_insn >= 0) + { + while (pb < bytes) { - done_dot = false; - if (with_line_numbers) + long j; + char *s; + + putchar ('\n'); + j = i + pb; + + sprintf_vma (buf, section->vma + j); + for (s = buf + skip_addr_chars; *s == '0'; s++) + *s = ' '; + if (*s == '\0') + *--s = '0'; + printf ("%s:\t", buf + skip_addr_chars); + + pb += bytes_per_line; + if (pb > bytes) + pb = bytes; + for (; j < i + pb; j += bpc) { - CONST char *filename; - CONST char *functionname; - unsigned int line; - - if (bfd_find_nearest_line (abfd, - section, - syms, - section->vma + i, - &filename, - &functionname, - &line)) + int k; + + if (bpc > 1 && info->display_endian == BFD_ENDIAN_LITTLE) { - if (functionname && *functionname - && strcmp(functionname, prev_function)) - { - printf ("%s():\n", functionname); - prev_function = functionname; - } - if (!filename) - filename = "???"; - if (line && line != prevline) - { - printf ("%s:%u\n", filename, line); - prevline = line; - } + 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 (' '); } } - objdump_print_address (section->vma + i, &disasm_info); - printf (" "); - - if (disassemble) /* New style */ - { - int bytes = (*disassemble)(section->vma + i, - &disasm_info); - if (bytes < 0) - break; - i += bytes; - } - else /* Old style */ - i += print (section->vma + i, - data + i, - stdout); - putchar ('\n'); } } - free (data); + + if (!wide_output) + putchar ('\n'); + else + need_nl = true; } - } -} - -/* Define a table of stab values and print-strings. We wish the initializer - could be a direct-mapped table, but instead we build one the first - time we need it. */ + if (dump_reloc_info + && (section->flags & SEC_RELOC) != 0) + { + while ((*relppp) < relppend + && ((**relppp)->address >= (bfd_vma) i + && (**relppp)->address < (bfd_vma) i + bytes)) + { + arelent *q; -char **stab_name; + q = **relppp; -struct stab_print { - int value; - char *string; -}; + if (wide_output) + putchar ('\t'); + else + printf ("\t\t\t"); -struct stab_print stab_print[] = { -#define __define_stab(NAME, CODE, STRING) {CODE, STRING}, -#include "aout/stab.def" -#undef __define_stab - {0, ""} -}; + objdump_print_value (section->vma + q->address, info, true); + + printf (": %s\t", q->howto->name); + + if (q->sym_ptr_ptr == NULL || *q->sym_ptr_ptr == NULL) + printf ("*unknown*"); + else + { + const char *sym_name; -void dump_stabs_1 (); + sym_name = bfd_asymbol_name (*q->sym_ptr_ptr); + if (sym_name != NULL && *sym_name != '\0') + objdump_print_symname (aux->abfd, info, *q->sym_ptr_ptr); + else + { + asection *sym_sec; -/* This dumps the stabs section from object files that have a section that - uses Sun stabs encoding. It has to use some hooks into BFD because - string table sections are not normally visible to BFD callers. */ + sym_sec = bfd_get_section (*q->sym_ptr_ptr); + sym_name = bfd_get_section_name (aux->abfd, sym_sec); + if (sym_name == NULL || *sym_name == '\0') + sym_name = "*unknown*"; + printf ("%s", sym_name); + } + } -void -dump_stabs (abfd) - bfd *abfd; -{ - int i; + if (q->addend) + { + printf ("+0x"); + objdump_print_value (q->addend, info, true); + } - /* Allocate and initialize stab name array if first time. */ - if (stab_name == NULL) - { - stab_name = (char **) xmalloc (256 * sizeof(char *)); - /* Clear the array. */ - for (i = 0; i < 256; i++) - stab_name[i] = NULL; - /* Fill in the defined stabs. */ - for (i = 0; *stab_print[i].string; i++) - stab_name[stab_print[i].value] = stab_print[i].string; - } + printf ("\n"); + need_nl = false; + ++(*relppp); + } + } + + if (need_nl) + printf ("\n"); - dump_stabs_1 (abfd, ".stab", ".stabstr"); - dump_stabs_1 (abfd, ".stab.excl", ".stab.exclstr"); - dump_stabs_1 (abfd, ".stab.index", ".stab.indexstr"); - dump_stabs_1 (abfd, "$GDB_SYMBOLS$", "$GDB_STRINGS$"); + i += bytes; + } } -void -dump_stabs_1 (abfd, name1, name2) +/* Disassemble the contents of an object file. */ + +static void +disassemble_data (abfd) bfd *abfd; - char *name1; /* Section name of .stab */ - char *name2; /* Section name of its string section */ { - Elf_Internal_Shdr *stab_hdr, *stabstr_hdr; - asection *stabsect, *stabstrsect; - char *strtab; - struct internal_nlist *stabs, *stabs_end; - int i; - int stab_size, stabstr_size; - unsigned file_string_table_offset, next_file_string_table_offset; - int is_elf = (0 == strncmp ("elf", abfd->xvec->name, 3)); + long i; + disassembler_ftype disassemble_fn; + struct disassemble_info disasm_info; + struct objdump_disasm_info aux; + asection *section; + + print_files = NULL; + prev_functionname = NULL; + prev_line = -1; + + /* We make a copy of syms to sort. We don't want to sort syms + because that will screw up the relocs. */ + sorted_syms = (asymbol **) xmalloc (symcount * sizeof (asymbol *)); + memcpy (sorted_syms, syms, symcount * sizeof (asymbol *)); + + sorted_symcount = remove_useless_symbols (sorted_syms, symcount); - if (is_elf) + /* Sort the symbols into section and symbol order */ + qsort (sorted_syms, sorted_symcount, sizeof (asymbol *), compare_symbols); + + INIT_DISASSEMBLE_INFO(disasm_info, stdout, fprintf); + disasm_info.application_data = (PTR) &aux; + aux.abfd = abfd; + aux.require_sec = false; + disasm_info.print_address_func = objdump_print_address; + disasm_info.symbol_at_address_func = objdump_symbol_at_address; + + if (machine != (char *) NULL) { - stab_hdr = bfd_elf_find_section (abfd, name1); + const bfd_arch_info_type *info = bfd_scan_arch (machine); + if (info == NULL) + { + fprintf (stderr, "%s: Can't use supplied machine %s\n", + program_name, + machine); + exit (1); + } + abfd->arch_info = info; } - else + + if (endian != BFD_ENDIAN_UNKNOWN) { - stabsect = bfd_get_section_by_name (abfd, name1); + struct bfd_target *xvec; + + xvec = (struct bfd_target *) xmalloc (sizeof (struct bfd_target)); + memcpy (xvec, abfd->xvec, sizeof (struct bfd_target)); + xvec->byteorder = endian; + abfd->xvec = xvec; } - if (is_elf ? (0 == stab_hdr) : (0 == stabsect)) + disassemble_fn = disassembler (abfd); + if (!disassemble_fn) { - printf ("No %s section present.\n\n", name1); + fprintf (stderr, "%s: Can't disassemble for architecture %s\n", + program_name, + bfd_printable_arch_mach (bfd_get_arch (abfd), 0)); return; } - if (is_elf) - { - stabstr_hdr = bfd_elf_find_section (abfd, name2); - } + disasm_info.flavour = bfd_get_flavour (abfd); + disasm_info.arch = bfd_get_arch (abfd); + disasm_info.mach = bfd_get_mach (abfd); + if (bfd_big_endian (abfd)) + disasm_info.endian = BFD_ENDIAN_BIG; + else if (bfd_little_endian (abfd)) + disasm_info.endian = BFD_ENDIAN_LITTLE; else - { - stabstrsect = bfd_get_section_by_name (abfd, name2); - } + /* ??? Aborting here seems too drastic. We could default to big or little + instead. */ + disasm_info.endian = BFD_ENDIAN_UNKNOWN; - if (is_elf ? (0 == stabstr_hdr) : (0 == stabstrsect)) + for (section = abfd->sections; + section != (asection *) NULL; + section = section->next) { - fprintf (stderr, "%s: %s has no %s section.\n", program_name, - abfd->filename, name2); - return; - } - - stab_size = (is_elf ? stab_hdr ->sh_size : bfd_section_size (abfd, stabsect)); - stabstr_size = (is_elf ? stabstr_hdr->sh_size : bfd_section_size (abfd, stabstrsect)); + bfd_byte *data = NULL; + bfd_size_type datasize = 0; + arelent **relbuf = NULL; + arelent **relpp = NULL; + arelent **relppend = NULL; + long stop; + asymbol *sym = NULL; + long place = 0; + + if ((section->flags & SEC_LOAD) == 0 + || (! disassemble_all + && only == NULL + && (section->flags & SEC_CODE) == 0)) + continue; + if (only != (char *) NULL && strcmp (only, section->name) != 0) + continue; - stabs = (struct internal_nlist *) xmalloc (stab_size); - strtab = (char *) xmalloc (stabstr_size); - stabs_end = (struct internal_nlist *) (stab_size + (char *) stabs); - - if (is_elf) - { - if (bfd_seek (abfd, stab_hdr->sh_offset, SEEK_SET) < 0 || - stab_size != bfd_read ((PTR) stabs, stab_size, 1, abfd)) + if (dump_reloc_info + && (section->flags & SEC_RELOC) != 0) + { + long relsize; + + relsize = bfd_get_reloc_upper_bound (abfd, section); + if (relsize < 0) + bfd_fatal (bfd_get_filename (abfd)); + + if (relsize > 0) + { + long relcount; + + relbuf = (arelent **) xmalloc (relsize); + relcount = bfd_canonicalize_reloc (abfd, section, relbuf, syms); + if (relcount < 0) + bfd_fatal (bfd_get_filename (abfd)); + + /* Sort the relocs by address. */ + qsort (relbuf, relcount, sizeof (arelent *), compare_relocs); + + relpp = relbuf; + relppend = relpp + relcount; + } + } + + printf ("Disassembly of section %s:\n", section->name); + + datasize = bfd_get_section_size_before_reloc (section); + if (datasize == 0) + continue; + + data = (bfd_byte *) xmalloc ((size_t) datasize); + + bfd_get_section_contents (abfd, section, data, 0, datasize); + + aux.sec = section; + disasm_info.buffer = data; + disasm_info.buffer_vma = section->vma; + disasm_info.buffer_length = datasize; + if (start_address == (bfd_vma) -1 + || start_address < disasm_info.buffer_vma) + i = 0; + else + i = start_address - disasm_info.buffer_vma; + if (stop_address == (bfd_vma) -1) + stop = datasize; + else + { + if (stop_address < disasm_info.buffer_vma) + stop = 0; + else + stop = stop_address - disasm_info.buffer_vma; + if (stop > disasm_info.buffer_length) + stop = disasm_info.buffer_length; + } + + sym = find_symbol_for_address (abfd, section, section->vma + i, + true, &place); + ++place; + while (i < stop) { - fprintf (stderr, "%s: reading %s section of %s failed.\n", - program_name, name1, - abfd->filename); - return; + asymbol *nextsym; + long nextstop; + boolean insns; + + if (sym != NULL && bfd_asymbol_value (sym) <= section->vma + i) + disasm_info.symbol = sym; + else + disasm_info.symbol = NULL; + + if (! prefix_addresses) + { + printf ("\n"); + objdump_print_addr_with_sym (abfd, section, sym, + section->vma + i, + &disasm_info, + false); + printf (":\n"); + } + + if (sym != NULL && bfd_asymbol_value (sym) > section->vma + i) + nextsym = sym; + else if (sym == NULL) + nextsym = NULL; + else + { + while (place < sorted_symcount + && (sorted_syms[place]->section != section + || (bfd_asymbol_value (sorted_syms[place]) + <= bfd_asymbol_value (sym)))) + ++place; + if (place >= sorted_symcount) + nextsym = NULL; + else + nextsym = sorted_syms[place]; + } + + if (sym != NULL && bfd_asymbol_value (sym) > section->vma + i) + { + nextstop = bfd_asymbol_value (sym) - section->vma; + if (nextstop > stop) + nextstop = stop; + } + else if (nextsym == NULL) + nextstop = stop; + else + { + nextstop = bfd_asymbol_value (nextsym) - section->vma; + if (nextstop > stop) + nextstop = stop; + } + + /* If a symbol is explicitly marked as being an object + rather than a function, just dump the bytes without + disassembling them. */ + if (disassemble_all + || sym == NULL + || bfd_asymbol_value (sym) > section->vma + i + || ((sym->flags & BSF_OBJECT) == 0 + && (strstr (bfd_asymbol_name (sym), "gnu_compiled") + == NULL) + && (strstr (bfd_asymbol_name (sym), "gcc2_compiled") + == NULL)) + || (sym->flags & BSF_FUNCTION) != 0) + insns = true; + else + insns = false; + + disassemble_bytes (&disasm_info, disassemble_fn, insns, data, i, + nextstop, &relpp, relppend); + + i = nextstop; + sym = nextsym; } + + free (data); + if (relbuf != NULL) + free (relbuf); + } + free (sorted_syms); +} + + +/* Define a table of stab values and print-strings. We wish the initializer + could be a direct-mapped table, but instead we build one the first + time we need it. */ + +static void dump_section_stabs PARAMS ((bfd *abfd, char *stabsect_name, + char *strsect_name)); + +/* Dump the stabs sections from an object file that has a section that + uses Sun stabs encoding. */ + +static void +dump_stabs (abfd) + bfd *abfd; +{ + dump_section_stabs (abfd, ".stab", ".stabstr"); + dump_section_stabs (abfd, ".stab.excl", ".stab.exclstr"); + dump_section_stabs (abfd, ".stab.index", ".stab.indexstr"); + dump_section_stabs (abfd, "$GDB_SYMBOLS$", "$GDB_STRINGS$"); +} + +static bfd_byte *stabs; +static bfd_size_type stab_size; + +static char *strtab; +static bfd_size_type stabstr_size; + +/* Read ABFD's stabs section STABSECT_NAME into `stabs' + and string table section STRSECT_NAME into `strtab'. + If the section exists and was read, allocate the space and return true. + Otherwise return false. */ + +static boolean +read_section_stabs (abfd, stabsect_name, strsect_name) + bfd *abfd; + const char *stabsect_name; + const char *strsect_name; +{ + asection *stabsect, *stabstrsect; + + stabsect = bfd_get_section_by_name (abfd, stabsect_name); + if (0 == stabsect) + { + printf ("No %s section present\n\n", stabsect_name); + return false; } - else + + stabstrsect = bfd_get_section_by_name (abfd, strsect_name); + if (0 == stabstrsect) { - bfd_get_section_contents (abfd, stabsect, (PTR) stabs, 0, stab_size); + fprintf (stderr, "%s: %s has no %s section\n", program_name, + bfd_get_filename (abfd), strsect_name); + return false; } + + stab_size = bfd_section_size (abfd, stabsect); + stabstr_size = bfd_section_size (abfd, stabstrsect); - if (is_elf) + stabs = (bfd_byte *) xmalloc (stab_size); + strtab = (char *) xmalloc (stabstr_size); + + if (! bfd_get_section_contents (abfd, stabsect, (PTR) stabs, 0, stab_size)) { - if (bfd_seek (abfd, stabstr_hdr->sh_offset, SEEK_SET) < 0 || - stabstr_size != bfd_read ((PTR) strtab, stabstr_size, 1, abfd)) - { - fprintf (stderr, "%s: reading %s section of %s failed.\n", - program_name, name2, - abfd->filename); - return; - } + fprintf (stderr, "%s: Reading %s section of %s failed: %s\n", + program_name, stabsect_name, bfd_get_filename (abfd), + bfd_errmsg (bfd_get_error ())); + free (stabs); + free (strtab); + return false; } - else + + if (! bfd_get_section_contents (abfd, stabstrsect, (PTR) strtab, 0, + stabstr_size)) { - bfd_get_section_contents (abfd, stabstrsect, (PTR) strtab, 0, stabstr_size); + fprintf (stderr, "%s: Reading %s section of %s failed: %s\n", + program_name, strsect_name, bfd_get_filename (abfd), + bfd_errmsg (bfd_get_error ())); + free (stabs); + free (strtab); + return false; } -#define SWAP_SYMBOL(symp, abfd) \ - { \ - (symp)->n_strx = bfd_h_get_32(abfd, \ - (unsigned char *)&(symp)->n_strx); \ - (symp)->n_desc = bfd_h_get_16 (abfd, \ - (unsigned char *)&(symp)->n_desc); \ - (symp)->n_value = bfd_h_get_32 (abfd, \ - (unsigned char *)&(symp)->n_value); \ - } + return true; +} - printf ("Contents of %s section:\n\n", name1); - printf ("Symnum n_type n_othr n_desc n_value n_strx String\n"); +/* Stabs entries use a 12 byte format: + 4 byte string table index + 1 byte stab type + 1 byte stab other field + 2 byte stab desc field + 4 byte stab value + FIXME: This will have to change for a 64 bit object format. */ + +#define STRDXOFF (0) +#define TYPEOFF (4) +#define OTHEROFF (5) +#define DESCOFF (6) +#define VALOFF (8) +#define STABSIZE (12) + +/* Print ABFD's stabs section STABSECT_NAME (in `stabs'), + using string table section STRSECT_NAME (in `strtab'). */ + +static void +print_section_stabs (abfd, stabsect_name, strsect_name) + bfd *abfd; + const char *stabsect_name; + const char *strsect_name; +{ + int i; + unsigned file_string_table_offset = 0, next_file_string_table_offset = 0; + bfd_byte *stabp, *stabs_end; + + stabp = stabs; + stabs_end = stabp + stab_size; - file_string_table_offset = 0; - next_file_string_table_offset = 0; + printf ("Contents of %s section:\n\n", stabsect_name); + printf ("Symnum n_type n_othr n_desc n_value n_strx String\n"); /* Loop through all symbols and print them. We start the index at -1 because there is a dummy symbol on - the front of stabs-in-{coff,elf} sections that supplies sizes. */ + the front of stabs-in-{coff,elf} sections that supplies sizes. */ - for (i = -1; stabs < stabs_end; stabs++, i++) + for (i = -1; stabp < stabs_end; stabp += STABSIZE, i++) { - SWAP_SYMBOL (stabs, abfd); + const char *name; + unsigned long strx; + unsigned char type, other; + unsigned short desc; + bfd_vma value; + + strx = bfd_h_get_32 (abfd, stabp + STRDXOFF); + type = bfd_h_get_8 (abfd, stabp + TYPEOFF); + other = bfd_h_get_8 (abfd, stabp + OTHEROFF); + desc = bfd_h_get_16 (abfd, stabp + DESCOFF); + value = bfd_h_get_32 (abfd, stabp + VALOFF); + printf ("\n%-6d ", i); - /* Print either the stab name, or, if unnamed, print its number + /* Either print the stab name, or, if unnamed, print its number again (makes consistent formatting for tools like awk). */ - if (stab_name[stabs->n_type]) - printf ("%-6s", stab_name[stabs->n_type]); + name = bfd_get_stab_name (type); + if (name != NULL) + printf ("%-6s", name); + else if (type == N_UNDF) + printf ("HdrSym"); else - printf ("%-6d", i); - printf (" %-6d %-6d ", stabs->n_other, stabs->n_desc); - printf_vma (stabs->n_value); - printf (" %-6lu", stabs->n_strx); + printf ("%-6d", type); + printf (" %-6d %-6d ", other, desc); + printf_vma (value); + printf (" %-6lu", strx); /* Symbols with type == 0 (N_UNDF) specify the length of the string table associated with this file. We use that info to know how to relocate the *next* file's string table indices. */ - if (stabs->n_type == N_UNDF) + if (type == N_UNDF) { file_string_table_offset = next_file_string_table_offset; - next_file_string_table_offset += stabs->n_value; + next_file_string_table_offset += value; } else { - /* Now, using the possibly updated string table offset, print the + /* Using the (possibly updated) string table offset, print the string (if any) associated with this symbol. */ - if ((stabs->n_strx + file_string_table_offset) < stabstr_size) - printf (" %s", &strtab[stabs->n_strx + file_string_table_offset]); + if ((strx + file_string_table_offset) < stabstr_size) + printf (" %s", &strtab[strx + file_string_table_offset]); else printf (" *"); } @@ -832,64 +1867,160 @@ dump_stabs_1 (abfd, name1, name2) printf ("\n\n"); } +static void +dump_section_stabs (abfd, stabsect_name, strsect_name) + bfd *abfd; + char *stabsect_name; + char *strsect_name; +{ + asection *s; + + /* Check for section names for which stabsect_name is a prefix, to + handle .stab0, etc. */ + for (s = abfd->sections; + s != NULL; + s = s->next) + { + int len; + + len = strlen (stabsect_name); + +/* If the prefix matches, and the files section name ends with a nul or a digit, + then we match. Ie: we want either an exact match or a a section followed by + a number. */ + if (strncmp (stabsect_name, s->name, len) == 0 + && (s->name[len] == '\000' || isdigit (s->name[len]))) + { + if (read_section_stabs (abfd, s->name, strsect_name)) + { + print_section_stabs (abfd, s->name, strsect_name); + free (stabs); + free (strtab); + } + } + } +} + +static void +dump_bfd_header (abfd) + bfd *abfd; +{ + char *comma = ""; + + printf ("architecture: %s, ", + bfd_printable_arch_mach (bfd_get_arch (abfd), + bfd_get_mach (abfd))); + printf ("flags 0x%08x:\n", abfd->flags); + +#define PF(x, y) if (abfd->flags & x) {printf("%s%s", comma, y); comma=", ";} + PF (HAS_RELOC, "HAS_RELOC"); + PF (EXEC_P, "EXEC_P"); + PF (HAS_LINENO, "HAS_LINENO"); + PF (HAS_DEBUG, "HAS_DEBUG"); + PF (HAS_SYMS, "HAS_SYMS"); + PF (HAS_LOCALS, "HAS_LOCALS"); + PF (DYNAMIC, "DYNAMIC"); + PF (WP_TEXT, "WP_TEXT"); + PF (D_PAGED, "D_PAGED"); + PF (BFD_IS_RELAXABLE, "BFD_IS_RELAXABLE"); + printf ("\nstart address 0x"); + printf_vma (abfd->start_address); + printf ("\n"); +} + +static void +dump_bfd_private_header (abfd) +bfd *abfd; +{ + bfd_print_private_bfd_data (abfd, stdout); +} + static void display_bfd (abfd) bfd *abfd; { + char **matching; - if (!bfd_check_format (abfd, bfd_object)) + if (!bfd_check_format_matches (abfd, bfd_object, &matching)) { - fprintf (stderr, "%s:%s: %s\n", program_name, abfd->filename, - bfd_errmsg (bfd_error)); + bfd_nonfatal (bfd_get_filename (abfd)); + if (bfd_get_error () == bfd_error_file_ambiguously_recognized) + { + list_matching_formats (matching); + free (matching); + } return; } - printf ("\n%s: file format %s\n", abfd->filename, abfd->xvec->name); - if (dump_ar_hdrs) - print_arelt_descr (stdout, abfd, true); - if (dump_file_header) + /* If we are adjusting section VMA's, change them all now. Changing + the BFD information is a hack. However, we must do it, or + bfd_find_nearest_line will not do the right thing. */ + if (adjust_section_vma != 0) { - char *comma = ""; + asection *s; - printf ("architecture: %s, ", - bfd_printable_arch_mach (bfd_get_arch (abfd), - bfd_get_mach (abfd))); - printf ("flags 0x%08x:\n", abfd->flags); - -#define PF(x, y) if (abfd->flags & x) {printf("%s%s", comma, y); comma=", ";} - PF (HAS_RELOC, "HAS_RELOC"); - PF (EXEC_P, "EXEC_P"); - PF (HAS_LINENO, "HAS_LINENO"); - PF (HAS_DEBUG, "HAS_DEBUG"); - PF (HAS_SYMS, "HAS_SYMS"); - PF (HAS_LOCALS, "HAS_LOCALS"); - PF (DYNAMIC, "DYNAMIC"); - PF (WP_TEXT, "WP_TEXT"); - PF (D_PAGED, "D_PAGED"); - PF (BFD_IS_RELAXABLE, "BFD_IS_RELAXABLE"); - printf ("\nstart address 0x"); - printf_vma (abfd->start_address); + for (s = abfd->sections; s != NULL; s = s->next) + { + s->vma += adjust_section_vma; + s->lma += adjust_section_vma; + } } - printf ("\n"); + printf ("\n%s: file format %s\n", bfd_get_filename (abfd), + abfd->xvec->name); + if (dump_ar_hdrs) + print_arelt_descr (stdout, abfd, true); + if (dump_file_header) + dump_bfd_header (abfd); + if (dump_private_headers) + dump_bfd_private_header (abfd); + putchar ('\n'); if (dump_section_headers) dump_headers (abfd); - if (dump_symtab || dump_reloc_info || disassemble) + if (dump_symtab || dump_reloc_info || disassemble || dump_debugging) { syms = slurp_symtab (abfd); } + if (dump_dynamic_symtab || dump_dynamic_reloc_info) + { + dynsyms = slurp_dynamic_symtab (abfd); + } if (dump_symtab) - dump_symbols (abfd); + dump_symbols (abfd, false); + if (dump_dynamic_symtab) + dump_symbols (abfd, true); if (dump_stab_section_info) dump_stabs (abfd); - if (dump_reloc_info) + if (dump_reloc_info && ! disassemble) dump_relocs (abfd); + if (dump_dynamic_reloc_info) + dump_dynamic_relocs (abfd); if (dump_section_contents) dump_data (abfd); - /* Note that disassemble_data re-orders the syms table, but that is - safe - as long as it is done last! */ if (disassemble) disassemble_data (abfd); + if (dump_debugging) + { + PTR dhandle; + + dhandle = read_debugging_info (abfd, syms, symcount); + if (dhandle != NULL) + { + if (! print_debugging_info (stdout, dhandle)) + fprintf (stderr, "%s: printing debugging information failed\n", + bfd_get_filename (abfd)); + } + } + if (syms) + { + free (syms); + syms = NULL; + } + if (dynsyms) + { + free (dynsyms); + dynsyms = NULL; + } } static void @@ -902,32 +2033,38 @@ display_file (filename, target) file = bfd_openr (filename, target); if (file == NULL) { - fprintf (stderr, "%s: ", program_name); - bfd_perror (filename); + bfd_nonfatal (filename); return; } if (bfd_check_format (file, bfd_archive) == true) { + bfd *last_arfile = NULL; + printf ("In archive %s:\n", bfd_get_filename (file)); for (;;) { - bfd_error = no_error; + bfd_set_error (bfd_error_no_error); arfile = bfd_openr_next_archived_file (file, arfile); if (arfile == NULL) { - if (bfd_error != no_more_archived_files) + if (bfd_get_error () != bfd_error_no_more_archived_files) { - fprintf (stderr, "%s: ", program_name); - bfd_perror (bfd_get_filename (file)); + bfd_nonfatal (bfd_get_filename (file)); } - return; + break; } display_bfd (arfile); - /* Don't close the archive elements; we need them for next_archive */ + + if (last_arfile != NULL) + bfd_close (last_arfile); + last_arfile = arfile; } + + if (last_arfile != NULL) + bfd_close (last_arfile); } else display_bfd (file); @@ -945,6 +2082,7 @@ dump_data (abfd) bfd_byte *data = 0; bfd_size_type datasize = 0; bfd_size_type i; + bfd_size_type start, stop; for (section = abfd->sections; section != NULL; section = section->next) @@ -966,14 +2104,30 @@ dump_data (abfd) bfd_get_section_contents (abfd, section, (PTR) data, 0, bfd_section_size (abfd, section)); - for (i = 0; i < bfd_section_size (abfd, section); i += onaline) + if (start_address == (bfd_vma) -1 + || start_address < section->vma) + start = 0; + else + start = start_address - section->vma; + if (stop_address == (bfd_vma) -1) + stop = bfd_section_size (abfd, section); + else + { + if (stop_address < section->vma) + stop = 0; + else + stop = stop_address - section->vma; + if (stop > bfd_section_size (abfd, section)) + stop = bfd_section_size (abfd, section); + } + for (i = start; i < stop; i += onaline) { bfd_size_type j; printf (" %04lx ", (unsigned long int) (i + section->vma)); for (j = i; j < i + onaline; j++) { - if (j < bfd_section_size (abfd, section)) + if (j < stop) printf ("%02x", (unsigned) (data[j])); else printf (" "); @@ -984,7 +2138,7 @@ dump_data (abfd) printf (" "); for (j = i; j < i + onaline; j++) { - if (j >= bfd_section_size (abfd, section)) + if (j >= stop) printf (" "); else printf ("%c", isprint (data[j]) ? data[j] : '.'); @@ -999,29 +2153,71 @@ dump_data (abfd) /* Should perhaps share code and display with nm? */ static void -dump_symbols (abfd) +dump_symbols (abfd, dynamic) bfd *abfd; + boolean dynamic; { + asymbol **current; + long max; + long count; - unsigned int count; - asymbol **current = syms; - - printf ("SYMBOL TABLE:\n"); - - for (count = 0; count < symcount; count++) + if (dynamic) + { + current = dynsyms; + max = dynsymcount; + if (max == 0) + return; + printf ("DYNAMIC SYMBOL TABLE:\n"); + } + else { + current = syms; + max = symcount; + if (max == 0) + return; + printf ("SYMBOL TABLE:\n"); + } + for (count = 0; count < max; count++) + { if (*current) { - bfd *cur_bfd = bfd_asymbol_bfd(*current); - if (cur_bfd) + bfd *cur_bfd = bfd_asymbol_bfd (*current); + + if (cur_bfd != NULL) { - bfd_print_symbol (cur_bfd, - stdout, - *current, bfd_print_symbol_all); + const char *name; + char *alloc; + + name = bfd_asymbol_name (*current); + alloc = NULL; + if (do_demangle && name != NULL && *name != '\0') + { + const char *n; + + /* 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. */ + + n = name; + if (bfd_get_symbol_leading_char (cur_bfd) == *n) + ++n; + alloc = cplus_demangle (n, DMGL_ANSI | DMGL_PARAMS); + if (alloc != NULL) + (*current)->name = alloc; + else + (*current)->name = n; + } + + bfd_print_symbol (cur_bfd, stdout, *current, + bfd_print_symbol_all); + + (*current)->name = name; + if (alloc != NULL) + free (alloc); + printf ("\n"); } - } current++; } @@ -1034,14 +2230,16 @@ dump_relocs (abfd) bfd *abfd; { arelent **relpp; - unsigned int relcount; + long relcount; asection *a; for (a = abfd->sections; a != (asection *) NULL; a = a->next) { - if (a == &bfd_abs_section) + long relsize; + + if (bfd_is_abs_section (a)) continue; - if (a == &bfd_und_section) + if (bfd_is_und_section (a)) continue; if (bfd_is_com_section (a)) continue; @@ -1054,189 +2252,379 @@ dump_relocs (abfd) else if ((a->flags & SEC_RELOC) == 0) continue; + relsize = bfd_get_reloc_upper_bound (abfd, a); + if (relsize < 0) + bfd_fatal (bfd_get_filename (abfd)); + printf ("RELOCATION RECORDS FOR [%s]:", a->name); - if (bfd_get_reloc_upper_bound (abfd, a) == 0) + if (relsize == 0) { printf (" (none)\n\n"); } else { - arelent **p; - - relpp = (arelent **) xmalloc (bfd_get_reloc_upper_bound (abfd, a)); - /* Note that this must be done *before* we sort the syms table. */ + relpp = (arelent **) xmalloc (relsize); relcount = bfd_canonicalize_reloc (abfd, a, relpp, syms); - if (relcount == 0) + if (relcount < 0) + bfd_fatal (bfd_get_filename (abfd)); + else if (relcount == 0) { printf (" (none)\n\n"); } else { printf ("\n"); - /* Get column headers lined up reasonably. */ - { - static int width; - if (width == 0) - { - char buf[30]; - sprintf_vma (buf, (bfd_vma) -1); - width = strlen (buf) - 7; - } - printf ("OFFSET %*s TYPE %*s VALUE \n", width, "", 12, ""); - } + dump_reloc_set (abfd, a, relpp, relcount); + printf ("\n\n"); + } + free (relpp); + } + } +} - for (p = relpp; relcount && *p != (arelent *) NULL; p++, - relcount--) - { - arelent *q = *p; - CONST char *sym_name; - CONST char *section_name; +static void +dump_dynamic_relocs (abfd) + bfd *abfd; +{ + long relsize; + arelent **relpp; + long relcount; - if (q->sym_ptr_ptr && *q->sym_ptr_ptr) - { - sym_name = (*(q->sym_ptr_ptr))->name; - section_name = (*(q->sym_ptr_ptr))->section->name; - } - else - { - sym_name = NULL; - section_name = NULL; - } - if (sym_name) - { - printf_vma (q->address); - printf (" %-16s %s", - q->howto->name, - sym_name); - } - else - { - if (section_name == (CONST char *) NULL) - section_name = "*unknown*"; - printf_vma (q->address); - printf (" %-16s [%s]", - q->howto->name, - section_name); - } - if (q->addend) - { - printf ("+0x"); - printf_vma (q->addend); - } - printf ("\n"); - } - printf ("\n\n"); - free (relpp); + relsize = bfd_get_dynamic_reloc_upper_bound (abfd); + if (relsize < 0) + bfd_fatal (bfd_get_filename (abfd)); + + printf ("DYNAMIC RELOCATION RECORDS"); + + if (relsize == 0) + { + printf (" (none)\n\n"); + } + else + { + relpp = (arelent **) xmalloc (relsize); + relcount = bfd_canonicalize_dynamic_reloc (abfd, relpp, dynsyms); + if (relcount < 0) + bfd_fatal (bfd_get_filename (abfd)); + else if (relcount == 0) + { + printf (" (none)\n\n"); + } + else + { + printf ("\n"); + dump_reloc_set (abfd, (asection *) NULL, relpp, relcount); + printf ("\n\n"); + } + free (relpp); + } +} + +static void +dump_reloc_set (abfd, sec, relpp, relcount) + bfd *abfd; + asection *sec; + arelent **relpp; + long relcount; +{ + arelent **p; + char *last_filename, *last_functionname; + unsigned int last_line; + + /* Get column headers lined up reasonably. */ + { + static int width; + if (width == 0) + { + char buf[30]; + sprintf_vma (buf, (bfd_vma) -1); + width = strlen (buf) - 7; + } + printf ("OFFSET %*s TYPE %*s VALUE \n", width, "", 12, ""); + } + + last_filename = NULL; + last_functionname = NULL; + last_line = 0; + + for (p = relpp; relcount && *p != (arelent *) NULL; p++, relcount--) + { + arelent *q = *p; + const char *filename, *functionname; + unsigned int line; + const char *sym_name; + const char *section_name; + + if (start_address != (bfd_vma) -1 + && q->address < start_address) + continue; + if (stop_address != (bfd_vma) -1 + && q->address > stop_address) + continue; + + if (with_line_numbers + && sec != NULL + && bfd_find_nearest_line (abfd, sec, syms, q->address, + &filename, &functionname, &line)) + { + if (functionname != NULL + && (last_functionname == NULL + || strcmp (functionname, last_functionname) != 0)) + { + printf ("%s():\n", functionname); + if (last_functionname != NULL) + free (last_functionname); + last_functionname = xstrdup (functionname); + } + if (line > 0 + && (line != last_line + || (filename != NULL + && last_filename != NULL + && strcmp (filename, last_filename) != 0))) + { + printf ("%s:%u\n", filename == NULL ? "???" : filename, line); + last_line = line; + if (last_filename != NULL) + free (last_filename); + if (filename == NULL) + last_filename = NULL; + else + last_filename = xstrdup (filename); } } + if (q->sym_ptr_ptr && *q->sym_ptr_ptr) + { + sym_name = (*(q->sym_ptr_ptr))->name; + section_name = (*(q->sym_ptr_ptr))->section->name; + } + else + { + sym_name = NULL; + section_name = NULL; + } + if (sym_name) + { + printf_vma (q->address); + printf (" %-16s ", q->howto->name); + objdump_print_symname (abfd, (struct disassemble_info *) NULL, + *q->sym_ptr_ptr); + } + else + { + if (section_name == (CONST char *) NULL) + section_name = "*unknown*"; + printf_vma (q->address); + printf (" %-16s [%s]", + q->howto->name, + section_name); + } + if (q->addend) + { + printf ("+0x"); + printf_vma (q->addend); + } + printf ("\n"); } } + +/* The length of the longest architecture name + 1. */ +#define LONGEST_ARCH sizeof("rs6000:6000") + +static const char * +endian_string (endian) + enum bfd_endian endian; +{ + if (endian == BFD_ENDIAN_BIG) + return "big endian"; + else if (endian == BFD_ENDIAN_LITTLE) + return "little endian"; + else + return "endianness unknown"; +} + +/* List the targets that BFD is configured to support, each followed + by its endianness and the architectures it supports. */ -#ifdef unix -#define _DUMMY_NAME_ "/dev/null" -#else -#define _DUMMY_NAME_ "##dummy" -#endif static void -DEFUN (display_info_table, (first, last), - int first AND int last) +display_target_list () { - unsigned int i, j; - extern bfd_target *target_vector[]; + extern bfd_target *bfd_target_vector[]; + char *dummy_name; + int t; - printf ("\n%12s", " "); - for (i = first; i++ < last && target_vector[i];) - printf ("%s ", target_vector[i]->name); - printf ("\n"); + dummy_name = choose_temp_base (); + for (t = 0; bfd_target_vector[t]; t++) + { + bfd_target *p = bfd_target_vector[t]; + bfd *abfd = bfd_openw (dummy_name, p->name); + int a; + + printf ("%s\n (header %s, data %s)\n", p->name, + endian_string (p->header_byteorder), + endian_string (p->byteorder)); + + if (abfd == NULL) + { + bfd_nonfatal (dummy_name); + continue; + } + + if (! bfd_set_format (abfd, bfd_object)) + { + if (bfd_get_error () != bfd_error_invalid_operation) + bfd_nonfatal (p->name); + continue; + } + + for (a = (int) bfd_arch_obscure + 1; a < (int) bfd_arch_last; a++) + if (bfd_set_arch_mach (abfd, (enum bfd_architecture) a, 0)) + printf (" %s\n", + bfd_printable_arch_mach ((enum bfd_architecture) a, 0)); + } + unlink (dummy_name); + free (dummy_name); +} + +/* Print a table showing which architectures are supported for entries + FIRST through LAST-1 of bfd_target_vector (targets across, + architectures down). */ - for (j = (int) bfd_arch_obscure + 1; (int) j < (int) bfd_arch_last; j++) - if (strcmp (bfd_printable_arch_mach (j, 0), "UNKNOWN!") != 0) +static void +display_info_table (first, last) + int first; + int last; +{ + extern bfd_target *bfd_target_vector[]; + int t, a; + char *dummy_name; + + /* Print heading of target names. */ + printf ("\n%*s", (int) LONGEST_ARCH, " "); + for (t = first; t < last && bfd_target_vector[t]; t++) + printf ("%s ", bfd_target_vector[t]->name); + putchar ('\n'); + + dummy_name = choose_temp_base (); + for (a = (int) bfd_arch_obscure + 1; a < (int) bfd_arch_last; a++) + if (strcmp (bfd_printable_arch_mach (a, 0), "UNKNOWN!") != 0) { - printf ("%11s ", bfd_printable_arch_mach (j, 0)); - for (i = first; i++ < last && target_vector[i];) + printf ("%*s ", (int) LONGEST_ARCH - 1, + bfd_printable_arch_mach (a, 0)); + for (t = first; t < last && bfd_target_vector[t]; t++) { - bfd_target *p = target_vector[i]; - bfd *abfd = bfd_openw (_DUMMY_NAME_, p->name); - int l = strlen (p->name); - int ok; - bfd_set_format (abfd, bfd_object); - ok = bfd_set_arch_mach (abfd, j, 0); + bfd_target *p = bfd_target_vector[t]; + boolean ok = true; + bfd *abfd = bfd_openw (dummy_name, p->name); + + if (abfd == NULL) + { + bfd_nonfatal (p->name); + ok = false; + } + + if (ok) + { + if (! bfd_set_format (abfd, bfd_object)) + { + if (bfd_get_error () != bfd_error_invalid_operation) + bfd_nonfatal (p->name); + ok = false; + } + } + + if (ok) + { + if (! bfd_set_arch_mach (abfd, a, 0)) + ok = false; + } if (ok) printf ("%s ", p->name); else { + int l = strlen (p->name); while (l--) - printf ("%c", ok ? '*' : '-'); - printf (" "); + putchar ('-'); + putchar (' '); } } - printf ("\n"); + putchar ('\n'); } + unlink (dummy_name); + free (dummy_name); } +/* Print tables of all the target-architecture combinations that + BFD has been configured to support. */ + static void -DEFUN_VOID (display_info) +display_target_tables () { + int t, columns; + extern bfd_target *bfd_target_vector[]; char *colum; - unsigned int i, j, columns; - extern bfd_target *target_vector[]; - extern char *getenv (); - printf ("BFD header file version %s\n", BFD_VERSION); - for (i = 0; target_vector[i]; i++) - { - bfd_target *p = target_vector[i]; - bfd *abfd = bfd_openw (_DUMMY_NAME_, p->name); - bfd_set_format (abfd, bfd_object); - printf ("%s\n (header %s, data %s)\n", p->name, - p->header_byteorder_big_p ? "big endian" : "little endian", - p->byteorder_big_p ? "big endian" : "little endian"); - for (j = (int) bfd_arch_obscure + 1; j < (int) bfd_arch_last; j++) - if (bfd_set_arch_mach (abfd, (enum bfd_architecture) j, 0)) - printf (" %s\n", - bfd_printable_arch_mach ((enum bfd_architecture) j, 0)); - } columns = 0; - if ((colum = getenv ("COLUMNS")) != (char *) NULL) + colum = getenv ("COLUMNS"); + if (colum != NULL) columns = atoi (colum); - if (!columns) + if (columns == 0) columns = 80; - for (i = 0; target_vector[i];) + + t = 0; + while (bfd_target_vector[t] != NULL) { - int old; - old = i; - for (j = 12; target_vector[i] && j < columns; i++) - j += strlen (target_vector[i]->name) + 1; - i--; - if (old == i) - break; - display_info_table (old, i); + int oldt = t, wid; + + wid = LONGEST_ARCH + strlen (bfd_target_vector[t]->name) + 1; + ++t; + while (wid < columns && bfd_target_vector[t] != NULL) + { + int newwid; + + newwid = wid + strlen (bfd_target_vector[t]->name) + 1; + if (newwid >= columns) + break; + wid = newwid; + ++t; + } + display_info_table (oldt, t); } } -/** main and like trivia */ +static void +display_info () +{ + printf ("BFD header file version %s\n", BFD_VERSION); + display_target_list (); + display_target_tables (); +} + int main (argc, argv) int argc; char **argv; { int c; - extern int optind; - extern char *optarg; char *target = default_target; boolean seenflag = false; - bfd_init (); program_name = *argv; + xmalloc_set_program_name (program_name); + + START_PROGRESS (program_name, 0); + + bfd_init (); + set_default_bfd_target (); - while ((c = getopt_long (argc, argv, "ib:m:Vdlfahrtxsj:", long_options, - (int *) 0)) + while ((c = getopt_long (argc, argv, "pib:m:VCdDlfahrRtTxsSj:wE:", + long_options, (int *) 0)) != EOF) { - seenflag = true; + if (c != 'l' && c != OPTION_START_ADDRESS && c != OPTION_STOP_ADDRESS) + seenflag = true; switch (c) { case 0: @@ -1259,7 +2647,11 @@ main (argc, argv) case 'i': formats_info = true; break; + case 'p': + dump_private_headers = 1; + break; case 'x': + dump_private_headers = 1; dump_symtab = 1; dump_reloc_info = 1; dump_file_header = true; @@ -1269,15 +2661,31 @@ main (argc, argv) case 't': dump_symtab = 1; break; + case 'T': + dump_dynamic_symtab = 1; + break; + case 'C': + do_demangle = 1; + break; case 'd': disassemble = true; break; + case 'D': + disassemble = disassemble_all = true; + break; + case 'S': + disassemble = true; + with_source_code = true; + break; case 's': dump_section_contents = 1; break; case 'r': dump_reloc_info = 1; break; + case 'R': + dump_dynamic_reloc_info = 1; + break; case 'a': dump_ar_hdrs = 1; break; @@ -1289,16 +2697,48 @@ main (argc, argv) case 'V': show_version = 1; break; + case 'w': + wide_output = 1; + break; + case OPTION_ADJUST_VMA: + adjust_section_vma = parse_vma (optarg, "--adjust-vma"); + break; + case OPTION_START_ADDRESS: + start_address = parse_vma (optarg, "--start-address"); + break; + case OPTION_STOP_ADDRESS: + stop_address = parse_vma (optarg, "--stop-address"); + break; + case 'E': + if (strcmp (optarg, "B") == 0) + endian = BFD_ENDIAN_BIG; + else if (strcmp (optarg, "L") == 0) + endian = BFD_ENDIAN_LITTLE; + else + { + fprintf (stderr, "%s: unrecognized -E option\n", program_name); + usage (stderr, 1); + } + break; + case OPTION_ENDIAN: + if (strncmp (optarg, "big", strlen (optarg)) == 0) + endian = BFD_ENDIAN_BIG; + else if (strncmp (optarg, "little", strlen (optarg)) == 0) + endian = BFD_ENDIAN_LITTLE; + else + { + fprintf (stderr, "%s: unrecognized --endian type `%s'\n", + program_name, optarg); + usage (stderr, 1); + } + break; default: usage (stderr, 1); } } if (show_version) - { - printf ("GNU %s version %s\n", program_name, program_version); - exit (0); - } + print_version ("objdump"); if (seenflag == false) usage (stderr, 1); @@ -1315,5 +2755,8 @@ main (argc, argv) for (; optind < argc;) display_file (argv[optind++], target); } + + END_PROGRESS (program_name); + return 0; }