X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=binutils%2Fobjdump.c;h=a5ab114903eccb00cdd098c292824de4d318688e;hb=37cc8ec1be0959c1878e79fd2baed888da4a2775;hp=469bfbde7c465f27e58ae8ef0bc7f37030b7246a;hpb=334d6e7603c5ba4cec9b17613757c96e00763bba;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/objdump.c b/binutils/objdump.c index 469bfbde7c..a5ab114903 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -1,5 +1,6 @@ /* objdump.c -- dump information about an object file. - Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000 + Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -15,65 +16,118 @@ 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 */ - +/* Exit status. */ +static int exit_status = 0; + +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 */ +static int file_start_context = 0; /* --file-start-context */ + +/* Extra info to pass to the disassembler address printing function. */ struct objdump_disasm_info { bfd *abfd; asection *sec; + boolean require_sec; }; -/* Architecture to disassemble for. */ -char *machine = (char *) NULL; +/* Architecture to disassemble for, or default if NULL. */ +static char *machine = (char *) NULL; -/* The symbol table. */ -asymbol **syms; +/* Target specific options to the disassembler. */ +static char *disassembler_options = (char *) NULL; + +/* Endianness to disassemble for, or default if BFD_ENDIAN_UNKNOWN. */ +static enum bfd_endian endian = BFD_ENDIAN_UNKNOWN; -/* Number of bytes allocated for `syms'. */ -unsigned int storage; +/* The symbol table. */ +static asymbol **syms; /* Number of symbols in `syms'. */ -unsigned int symcount = 0; +static long symcount = 0; + +/* The sorted symbol table. */ +static asymbol **sorted_syms; + +/* 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)); -/* Forward declarations. */ +static void +nonfatal PARAMS ((const char *)); 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)); @@ -81,69 +135,229 @@ 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 *, bfd_vma, bfd_vma, + 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", - program_name); + fprintf (stream, _("Usage: %s file(s)\n"), program_name); + fprintf (stream, _(" At least one of the following switches must be given:\n")); + fprintf (stream, _("\ + -a --archive-headers Display archive header information\n\ + -f --file-headers Display the contents of the overall file header\n\ + -p --private-headers Display object format specific file header contents\n\ + -h --[section-]headers Display the contents of the section headers\n\ + -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\ + -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\ + -G --stabs Display the STABS contents of an ELF format file\n\ + -t --syms Display the contents of the symbol table(s)\n\ + -T --dynamic-syms Display the contents of the dynamic symbol table\n\ + -r --reloc Display the relocation entries in the file\n\ + -R --dynamic-reloc Display the dynamic relocation entries in the file\n\ + -V --version Display this program's version number\n\ + -i --info List object formats and architectures supported\n\ + -H --help Display this information\n\ +")); + if (status != 2) + { + fprintf (stream, _("\n The following switches are optional:\n")); + fprintf (stream, _("\ + -b --target Specify the target object format as \n\ + -m --architecture Specify the target architecture as \n\ + -j --section Only display information for section \n\ + -M --disassembler-options Pass text on to the disassembler\n\ + -EB --endian=big Assume big endian format when disassembling\n\ + -EL --endian=little Assume little endian format when disassembling\n\ + --file-start-context Include context from start of file (with -S)\n\ + -l --line-numbers Include line numbers and filenames in output\n\ + -C --demangle Decode mangled/processed symbol names\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 Only process data whoes address is >= \n\ + --stop-address Only process data whoes address is <= \n\ + --prefix-addresses Print complete address alongside disassembly\n\ + --[no-]show-raw-insn Display hex alongside symbolic disassembly\n\ + --adjust-vma Add to all displayed section addresses\n\ +\n")); + list_supported_targets (program_name, stream); + + disassembler_usage (stream); + } + if (status == 0) + fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); 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, NULL, 'g'}, + {"demangle", no_argument, NULL, 'C'}, {"disassemble", no_argument, NULL, 'd'}, + {"disassemble-all", no_argument, NULL, 'D'}, + {"disassembler-options", required_argument, NULL, 'M'}, + {"disassemble-zeroes", no_argument, NULL, 'z'}, + {"dynamic-reloc", no_argument, NULL, 'R'}, + {"dynamic-syms", no_argument, NULL, 'T'}, + {"endian", required_argument, NULL, OPTION_ENDIAN}, {"file-headers", no_argument, NULL, 'f'}, + {"file-start-context", no_argument, &file_start_context, 1}, {"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'}, - {"stabs", no_argument, &dump_stab_section_info, 1}, + {"show-raw-insn", no_argument, &show_raw_insn, 1}, + {"source", no_argument, NULL, 'S'}, + {"stabs", no_argument, NULL, 'G'}, + {"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, NULL, 'V'}, + {"wide", no_argument, NULL, 'w'}, {0, no_argument, 0, 0} }; static void +nonfatal (msg) + const char *msg; +{ + bfd_nonfatal (msg); + exit_status = 1; +} + +static void dump_section_header (abfd, section, ignored) - bfd *abfd; + bfd *abfd ATTRIBUTE_UNUSED; asection *section; - PTR ignored; + PTR ignored ATTRIBUTE_UNUSED; { 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); + unsigned int opb = bfd_octets_per_byte (abfd); + + printf ("%3d %-13s %08lx ", section->index, + bfd_get_section_name (abfd, section), + (unsigned long) bfd_section_size (abfd, section) / opb); + 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"); @@ -159,6 +373,44 @@ dump_section_header (abfd, section, ignored) 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"); + PF (SEC_BLOCK, "BLOCK"); + PF (SEC_CLINK, "CLINK"); + PF (SEC_SMALL_DATA, "SMALL_DATA"); + PF (SEC_SHARED, "SHARED"); + + 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); + + if (section->comdat != NULL) + printf (" (COMDAT %s %ld)", section->comdat->name, + section->comdat->symbol); + + comma = ", "; + } + printf ("\n"); #undef PF } @@ -167,6 +419,18 @@ static void dump_headers (abfd) bfd *abfd; { + printf (_("Sections:\n")); + +#ifndef BFD64 + printf (_("Idx Name Size VMA LMA File off Algn")); +#else + printf (_("Idx Name Size VMA LMA File off Algn")); +#endif + + if (wide_output) + printf (_(" Flags")); + printf ("\n"); + bfd_map_over_sections (abfd, dump_section_header, (PTR) NULL); } @@ -175,25 +439,62 @@ slurp_symtab (abfd) bfd *abfd; { asymbol **sy = (asymbol **) NULL; + long storage; if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) { - printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd)); + non_fatal (_("%s: no symbols"), 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) + non_fatal (_("%s: no symbols"), 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)) + { + non_fatal (_("%s: not a dynamic object"), bfd_get_filename (abfd)); + dynsymcount = 0; + return NULL; + } + + bfd_fatal (bfd_get_filename (abfd)); + } + + if (storage) { - fprintf (stderr, "%s: %s: Invalid symbol table\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) + non_fatal (_("%s: No dynamic symbols"), bfd_get_filename (abfd)); return sy; } @@ -201,10 +502,10 @@ slurp_symtab (abfd) COUNT is the number of elements in SYMBOLS. Return the number of useful symbols. */ -int +static long remove_useless_symbols (symbols, count) asymbol **symbols; - int count; + long count; { register asymbol **in_ptr = symbols, **out_ptr = symbols; @@ -216,7 +517,7 @@ remove_useless_symbols (symbols, 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; @@ -225,620 +526,1483 @@ remove_useless_symbols (symbols, count) return out_ptr - symbols; } -/* Sort symbols into value order. */ +/* Sort symbols into value order. */ static int compare_symbols (ap, bp) - PTR ap; - PTR 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 VMA symbolically to INFO if possible. */ +/* Sort relocs into address order. */ -void -objdump_print_address (vma, info) +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; { - /* @@ 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. */ - /* Indices in `syms'. */ - unsigned int min = 0; - unsigned int max = symcount; - unsigned int thisplace = 1; - unsigned int oldthisplace; + /* Indices in `sorted_syms'. */ + long min = 0; + long max = sorted_symcount; + long thisplace; + unsigned int opb = bfd_octets_per_byte (abfd); - int vardiff; + if (sorted_symcount < 1) + return NULL; - fprintf_vma (info->stream, vma); - - if (symcount < 1) - return; - - /* Perform a binary search looking for the closest symbol to - the required value. */ - while (true) + /* 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; -#if 0 - asection *sym_sec; -#endif - oldthisplace = thisplace; + thisplace = (max + min) / 2; - if (thisplace == oldthisplace) - break; - sym = syms[thisplace]; - vardiff = sym->value - vma; -#if 0 - sym_sec = sym->section; -#endif + sym = sorted_syms[thisplace]; - if (vardiff > 0) + if (bfd_asymbol_value (sym) > vma) max = thisplace; - else if (vardiff < 0) + else if (bfd_asymbol_value (sym) < vma) min = thisplace; else - goto found; + { + min = thisplace; + break; + } } - /* We've run out of places to look; see whether this or the - symbol before this describes this location the best. */ - if (thisplace != 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) / opb)))) { - if (syms[thisplace - 1]->value - vma < syms[thisplace]->value - vma) + long i; + + for (i = thisplace + 1; i < sorted_symcount; i++) { - /* Previous symbol is in correct section and is closer. */ - thisplace--; + if (bfd_asymbol_value (sorted_syms[i]) + != bfd_asymbol_value (sorted_syms[thisplace])) + break; } - } - - found: - { - /* If this symbol isn't global, search for one with the same value - that is. */ - bfd_vma val = syms[thisplace]->value; - int i; - if (syms[thisplace]->flags & (BSF_LOCAL|BSF_DEBUGGING)) - for (i = thisplace - 1; i >= 0; i--) + --i; + for (; 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)))) + 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])))) { thisplace = i; break; } } - if (syms[thisplace]->flags & (BSF_LOCAL|BSF_DEBUGGING)) - for (i = thisplace + 1; i < symcount; i++) + + if (sorted_syms[thisplace]->section != sec) { - if (syms[i]->value == val - && (!(syms[i]->flags & (BSF_LOCAL|BSF_DEBUGGING)) - || ((syms[thisplace]->flags & BSF_DEBUGGING) - && !(syms[i]->flags & BSF_DEBUGGING)))) + /* 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++) { - thisplace = i; - break; + 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) - { - char buf[30], *p = buf; - sprintf_vma (buf, vma - syms[thisplace]->value); - while (*p == '0') - p++; - fprintf (info->stream, "+%s", p); + + 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))))) + { + /* 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; - - int prevline; - CONST char *prev_function = ""; - - asection *section; - - /* Replace symbol section relative values with abs values */ - boolean done_dot = false; - - INIT_DISASSEMBLE_INFO(disasm_info, stdout); - disasm_info.application_data = (PTR) &aux; - aux.abfd = abfd; - disasm_info.print_address_func = objdump_print_address; + objdump_print_value (vma, info, skip_zeroes); - for (i = 0; i < symcount; i++) + if (sym == NULL) { - syms[i]->value += syms[i]->section->vma; - } + bfd_vma secaddr; - symcount = remove_useless_symbols (syms, symcount); - - /* Sort the symbols into section and symbol order */ - qsort (syms, symcount, sizeof (asymbol *), compare_symbols); - - if (machine != (char *) NULL) - { - info = bfd_scan_arch (machine); - if (info == 0) + (*info->fprintf_func) (info->stream, " <%s", + bfd_get_section_name (abfd, sec)); + secaddr = bfd_get_section_vma (abfd, sec); + if (vma < secaddr) { - fprintf (stderr, "%s: Can't use supplied machine %s\n", - program_name, - machine); - exit (1); + (*info->fprintf_func) (info->stream, "-0x"); + objdump_print_value (secaddr - vma, info, true); } - abfd->arch_info = info; - } - - /* See if we can disassemble using bfd */ - - if (abfd->arch_info->disassemble) - { - print = abfd->arch_info->disassemble; + else if (vma > secaddr) + { + (*info->fprintf_func) (info->stream, "+0x"); + objdump_print_value (vma - secaddr, info, true); + } + (*info->fprintf_func) (info->stream, ">"); } else { - a = bfd_get_arch (abfd); - switch (a) + (*info->fprintf_func) (info->stream, " <"); + objdump_print_symname (abfd, info, sym); + if (bfd_asymbol_value (sym) > vma) { - /* 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; + (*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, ">"); + } +} + +/* Print VMA to INFO, symbolically if possible. If SKIP_ZEROES is + true, don't output leading zeroes. */ + +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; + + if (sorted_symcount < 1) + { + (*info->fprintf_func) (info->stream, "0x"); + objdump_print_value (vma, info, skip_zeroes); + return; + } + + 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); +} + +/* Print VMA to INFO. This function is passed to the disassembler + routine. */ + +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) + { + char buf[100]; + + if (fgets (buf, sizeof buf, p->f) == NULL) + { + fclose (p->f); + p->f = NULL; break; -#endif -#ifdef ARCH_sh - case bfd_arch_sh: - disassemble = print_insn_sh; + } + + if (show) + printf ("%s", buf); + + if (strchr (buf, '\n') != NULL) + ++p->line; + } +} + +/* Show the line number, or the source line, in a dissassembly + listing. */ + +static void +show_line (abfd, section, addr_offset) + bfd *abfd; + asection *section; + bfd_vma addr_offset; +{ + 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, addr_offset, &filename, + &functionname, &line)) + return; + + if (filename != NULL && *filename == '\0') + filename = NULL; + if (functionname != NULL && *functionname == '\0') + functionname = NULL; + + if (with_line_numbers) + { + 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); + } + + if (with_source_code + && filename != NULL + && line > 0) + { + struct print_file_list **pp, *p; + + for (pp = &print_files; *pp != NULL; pp = &(*pp)->next) + if (strcmp ((*pp)->filename, filename) == 0) break; + 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 = 0; + } + + 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; + + if (file_start_context) + l = 0; + else + l = line - SHOW_PRECEDING_CONTEXT_LINES; + if (l < 0) + l = 0; + skip_to_line (p, l, false); + if (p->f != NULL) + skip_to_line (p, line, true); + } + } + } + + if (functionname != NULL + && (prev_functionname == NULL + || strcmp (functionname, prev_functionname) != 0)) + { + 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; + size_t size; + char *current; +} SFILE; + +/* sprintf to a "stream" */ + +static int +#ifdef ANSI_PROTOTYPES +objdump_sprintf (SFILE *f, const char *format, ...) +#else +objdump_sprintf (va_alist) + va_dcl #endif -#ifdef ARCH_sparc - case bfd_arch_sparc: - disassemble = print_insn_sparc; - break; +{ +#ifndef ANSI_PROTOTYPES + SFILE *f; + const char *format; #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; - break; + char *buf; + va_list args; + size_t n; + +#ifdef ANSI_PROTOTYPES + va_start (args, format); +#else + va_start (args); + f = va_arg (args, SFILE *); + format = va_arg (args, const char *); #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); - } + vasprintf (&buf, format, args); + + va_end (args); + + if (buf == NULL) + { + fatal (_("Out of virtual memory")); } - for (section = abfd->sections; - section != (asection *) NULL; - section = section->next) + n = strlen (buf); + + while ((size_t) ((f->buffer + f->size) - f->current) < n + 1) { - aux.sec = section; + size_t curroff; + + curroff = f->current - f->buffer; + f->size *= 2; + f->buffer = xrealloc (f->buffer, f->size); + f->current = f->buffer + curroff; + } + + memcpy (f->current, buf, n); + f->current += n; + f->current[0] = '\0'; + + free (buf); + + return n; +} + +/* The number of zeroes we want to see before we start skipping them. + The number is arbitrarily chosen. */ + +#define SKIP_ZEROES (8) + +/* 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_offset, stop_offset, relppp, + relppend) + struct disassemble_info *info; + disassembler_ftype disassemble_fn; + boolean insns; + bfd_byte *data; + bfd_vma start_offset; + bfd_vma stop_offset; + arelent ***relppp; + arelent **relppend; +{ + struct objdump_disasm_info *aux; + asection *section; + int octets_per_line; + boolean done_dot; + int skip_addr_chars; + bfd_vma addr_offset; + int opb = info->octets_per_byte; - if ((section->flags & SEC_LOAD) - && (only == (char *) NULL || strcmp (only, section->name) == 0)) + aux = (struct objdump_disasm_info *) info->application_data; + section = aux->sec; + + if (insns) + octets_per_line = 4; + else + octets_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) / opb); + 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; + addr_offset = start_offset; + while (addr_offset < stop_offset) + { + bfd_vma z; + int octets = 0; + boolean need_nl = false; + + /* If we see more than SKIP_ZEROES octets of zeroes, we just + print `...'. */ + for (z = addr_offset * opb; z < stop_offset * opb; z++) + if (data[z] != 0) + break; + if (! disassemble_zeroes + && (info->insn_info_valid == 0 + || info->branch_delay_insns == 0) + && (z - addr_offset * opb >= SKIP_ZEROES + || (z == stop_offset * opb && + z - addr_offset * opb < SKIP_ZEROES_AT_END))) + { + printf ("\t...\n"); + + /* If there are more nonzero octets 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_offset * opb) + z = addr_offset * opb + ((z - addr_offset * opb) &~ 3); + + octets = z - addr_offset * opb; + } + else + { + char buf[50]; + SFILE sfile; + int bpc = 0; + int pb = 0; + + done_dot = false; + + if (with_line_numbers || with_source_code) + show_line (aux->abfd, section, addr_offset); + + if (! prefix_addresses) + { + char *s; + + sprintf_vma (buf, section->vma + addr_offset); + 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 + addr_offset, info); + aux->require_sec = false; + putchar (' '); + } - data = (bfd_byte *) xmalloc ((size_t) bfd_get_section_size_before_reloc (section)); + if (insns) + { + sfile.size = 120; + sfile.buffer = xmalloc (sfile.size); + sfile.current = sfile.buffer; + info->fprintf_func = (fprintf_ftype) objdump_sprintf; + info->stream = (FILE *) &sfile; + info->bytes_per_line = 0; + info->bytes_per_chunk = 0; + + /* FIXME: This is wrong. It tests the number of octets + in the last instruction, not the current one. */ + if (*relppp < relppend + && (**relppp)->address >= addr_offset + && (**relppp)->address < addr_offset + octets / opb) + info->flags = INSN_HAS_RELOC; + else + info->flags = 0; + + octets = (*disassemble_fn) (section->vma + addr_offset, info); + info->fprintf_func = (fprintf_ftype) fprintf; + info->stream = stdout; + if (info->bytes_per_line != 0) + octets_per_line = info->bytes_per_line; + if (octets < 0) + { + if (sfile.current != sfile.buffer) + printf ("%s\n", sfile.buffer); + free (sfile.buffer); + break; + } + } + else + { + bfd_vma j; - datasize = bfd_get_section_size_before_reloc (section); + octets = octets_per_line; + if (addr_offset + octets / opb > stop_offset) + octets = (stop_offset - addr_offset) * opb; - bfd_get_section_contents (abfd, section, data, 0, bfd_get_section_size_before_reloc (section)); + for (j = addr_offset * opb; j < addr_offset * opb + octets; ++j) + { + if (isprint (data[j])) + buf[j - addr_offset * opb] = data[j]; + else + buf[j - addr_offset * opb] = '.'; + } + buf[j - addr_offset * opb] = '\0'; + } - 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 (prefix_addresses + ? show_raw_insn > 0 + : show_raw_insn >= 0) { - if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 && - data[i + 3] == 0) + bfd_vma j; + + /* If ! prefix_addresses and ! wide_output, we print + octets_per_line octets per line. */ + pb = octets; + if (pb > octets_per_line && ! prefix_addresses && ! wide_output) + pb = octets_per_line; + + if (info->bytes_per_chunk) + bpc = info->bytes_per_chunk; + else + bpc = 1; + + for (j = addr_offset * opb; j < addr_offset * opb + pb; j += bpc) { - if (done_dot == false) + 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 < octets_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 (" "); + } + + if (! insns) + printf ("%s", buf); + else + { + printf ("%s", sfile.buffer); + free (sfile.buffer); + } + + if (prefix_addresses + ? show_raw_insn > 0 + : show_raw_insn >= 0) + { + while (pb < octets) { - done_dot = false; - if (with_line_numbers) + bfd_vma j; + char *s; + + putchar ('\n'); + j = addr_offset * opb + pb; + + sprintf_vma (buf, section->vma + j / opb); + for (s = buf + skip_addr_chars; *s == '0'; s++) + *s = ' '; + if (*s == '\0') + *--s = '0'; + printf ("%s:\t", buf + skip_addr_chars); + + pb += octets_per_line; + if (pb > octets) + pb = octets; + for (; j < addr_offset * opb + 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) addr_offset + && (**relppp)->address < (bfd_vma) addr_offset + octets / opb)) + { + 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); -void dump_stabs_1 (); + printf (": %s\t", q->howto->name); -/* 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. */ + if (q->sym_ptr_ptr == NULL || *q->sym_ptr_ptr == NULL) + printf ("*unknown*"); + else + { + const char *sym_name; -void -dump_stabs (abfd) - bfd *abfd; -{ - int i; + 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; - /* 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; - } + 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); + } + } + + if (q->addend) + { + printf ("+0x"); + objdump_print_value (q->addend, info, true); + } + + printf ("\n"); + need_nl = false; + ++(*relppp); + } + } - 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$"); + if (need_nl) + printf ("\n"); + + addr_offset += octets / opb; + } } -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)); + unsigned long addr_offset; + disassembler_ftype disassemble_fn; + struct disassemble_info disasm_info; + struct objdump_disasm_info aux; + asection *section; + unsigned int opb = bfd_octets_per_byte (abfd); - if (is_elf) - { - stab_hdr = bfd_elf_find_section (abfd, name1); - } - else - { - stabsect = bfd_get_section_by_name (abfd, name1); - } + print_files = NULL; + prev_functionname = NULL; + prev_line = -1; - if (is_elf ? (0 == stab_hdr) : (0 == stabsect)) - { - printf ("No %s section present.\n\n", name1); - return; - } + /* 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); + + /* 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; + disasm_info.octets_per_byte = opb; - if (is_elf) + if (machine != (char *) NULL) { - stabstr_hdr = bfd_elf_find_section (abfd, name2); + const bfd_arch_info_type *info = bfd_scan_arch (machine); + if (info == NULL) + { + fatal (_("Can't use supplied machine %s"), machine); + } + abfd->arch_info = info; } - else + + if (endian != BFD_ENDIAN_UNKNOWN) { - stabstrsect = bfd_get_section_by_name (abfd, name2); + 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 == stabstr_hdr) : (0 == stabstrsect)) + disassemble_fn = disassembler (abfd); + if (!disassemble_fn) { - fprintf (stderr, "%s: %s has no %s section\n", program_name, - abfd->filename, name2); + non_fatal (_("Can't disassemble for architecture %s\n"), + bfd_printable_arch_mach (bfd_get_arch (abfd), 0)); + exit_status = 1; 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)); - stabs = (struct internal_nlist *) xmalloc (stab_size); - strtab = (char *) xmalloc (stabstr_size); - stabs_end = (struct internal_nlist *) (stab_size + (char *) stabs); + disasm_info.flavour = bfd_get_flavour (abfd); + disasm_info.arch = bfd_get_arch (abfd); + disasm_info.mach = bfd_get_mach (abfd); + disasm_info.disassembler_options = disassembler_options; - if (is_elf) + if (bfd_big_endian (abfd)) + disasm_info.display_endian = disasm_info.endian = BFD_ENDIAN_BIG; + else if (bfd_little_endian (abfd)) + disasm_info.display_endian = disasm_info.endian = BFD_ENDIAN_LITTLE; + else + /* ??? Aborting here seems too drastic. We could default to big or little + instead. */ + disasm_info.endian = BFD_ENDIAN_UNKNOWN; + + for (section = abfd->sections; + section != (asection *) NULL; + section = section->next) { - if (bfd_seek (abfd, stab_hdr->sh_offset, SEEK_SET) < 0 || - stab_size != bfd_read ((PTR) stabs, stab_size, 1, abfd)) + bfd_byte *data = NULL; + bfd_size_type datasize = 0; + arelent **relbuf = NULL; + arelent **relpp = NULL; + arelent **relppend = NULL; + unsigned long stop_offset; + 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; + + if (dump_reloc_info + && (section->flags & SEC_RELOC) != 0) { - fprintf (stderr, "%s: Reading %s section of %s failed\n", - program_name, name1, - abfd->filename); - return; + 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; + + /* Skip over the relocs belonging to addresses below the + start address. */ + if (start_address != (bfd_vma) -1) + { + while (relpp < relppend + && (*relpp)->address < start_address) + ++relpp; + } + } } + + 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) + addr_offset = 0; + else + addr_offset = start_address - disasm_info.buffer_vma; + if (stop_address == (bfd_vma) -1) + stop_offset = datasize / opb; + else + { + if (stop_address < disasm_info.buffer_vma) + stop_offset = 0; + else + stop_offset = stop_address - disasm_info.buffer_vma; + if (stop_offset > disasm_info.buffer_length / opb) + stop_offset = disasm_info.buffer_length / opb; + } + + sym = find_symbol_for_address (abfd, section, section->vma + addr_offset, + true, &place); + + while (addr_offset < stop_offset) + { + asymbol *nextsym; + unsigned long nextstop_offset; + boolean insns; + + if (sym != NULL && bfd_asymbol_value (sym) <= section->vma + addr_offset) + { + int x; + + for (x = place; + (x < sorted_symcount + && bfd_asymbol_value (sorted_syms[x]) <= section->vma + addr_offset); + ++x) + continue; + disasm_info.symbols = & sorted_syms[place]; + disasm_info.num_symbols = x - place; + } + else + disasm_info.symbols = NULL; + + if (! prefix_addresses) + { + printf ("\n"); + objdump_print_addr_with_sym (abfd, section, sym, + section->vma + addr_offset, + &disasm_info, + false); + printf (":\n"); + } + + if (sym != NULL && bfd_asymbol_value (sym) > section->vma + addr_offset) + nextsym = sym; + else if (sym == NULL) + nextsym = NULL; + else + { + /* Search forward for the next appropriate symbol in + SECTION. Note that all the symbols are sorted + together into one big array, and that some sections + may have overlapping addresses. */ + 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 + addr_offset) + { + nextstop_offset = bfd_asymbol_value (sym) - section->vma; + if (nextstop_offset > stop_offset) + nextstop_offset = stop_offset; + } + else if (nextsym == NULL) + nextstop_offset = stop_offset; + else + { + nextstop_offset = bfd_asymbol_value (nextsym) - section->vma; + if (nextstop_offset > stop_offset) + nextstop_offset = stop_offset; + } + + /* 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 + addr_offset + || ((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, + addr_offset, nextstop_offset, &relpp, relppend); + + addr_offset = nextstop_offset; + sym = nextsym; + } + + free (data); + if (relbuf != NULL) + free (relbuf); } - else + 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; + } + + stabstrsect = bfd_get_section_by_name (abfd, strsect_name); + if (0 == stabstrsect) { - bfd_get_section_contents (abfd, stabsect, (PTR) stabs, 0, stab_size); + non_fatal (_("%s has no %s section"), + bfd_get_filename (abfd), strsect_name); + exit_status = 1; + 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; - } + non_fatal (_("Reading %s section of %s failed: %s"), + stabsect_name, bfd_get_filename (abfd), + bfd_errmsg (bfd_get_error ())); + free (stabs); + free (strtab); + exit_status = 1; + 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); + non_fatal (_("Reading %s section of %s failed: %s\n"), + strsect_name, bfd_get_filename (abfd), + bfd_errmsg (bfd_get_error ())); + free (stabs); + free (strtab); + exit_status = 1; + 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 ATTRIBUTE_UNUSED; +{ + 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 (" *"); } @@ -846,16 +2010,51 @@ 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. I.e., we want either an exact + match or a section followed by a number. */ + if (strncmp (stabsect_name, s->name, len) == 0 + && (s->name[len] == '\000' + || isdigit ((unsigned char) 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, ", + printf (_("architecture: %s, "), bfd_printable_arch_mach (bfd_get_arch (abfd), bfd_get_mach (abfd))); - printf ("flags 0x%08x:\n", abfd->flags); + 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"); @@ -868,62 +2067,137 @@ dump_bfd_header (abfd) PF (WP_TEXT, "WP_TEXT"); PF (D_PAGED, "D_PAGED"); PF (BFD_IS_RELAXABLE, "BFD_IS_RELAXABLE"); - printf ("\nstart address 0x"); + printf (_("\nstart address 0x")); printf_vma (abfd->start_address); + printf ("\n"); } - + static void -list_matching_formats (p) - char **p; +dump_bfd_private_header (abfd) +bfd *abfd; { - fprintf(stderr, "%s: Matching formats:", program_name); - while (*p) - fprintf(stderr, " %s", *p++); - fprintf(stderr, "\n"); + bfd_print_private_bfd_data (abfd, stdout); } +/* Dump selected contents of ABFD */ + static void -display_bfd (abfd) +dump_bfd (abfd) bfd *abfd; { - char **matching; - - if (!bfd_check_format_matches (abfd, bfd_object, &matching)) + /* 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) { - fprintf (stderr, "%s: %s: %s\n", program_name, abfd->filename, - bfd_errmsg (bfd_error)); - if (bfd_error == file_ambiguously_recognized) + asection *s; + + for (s = abfd->sections; s != NULL; s = s->next) { - list_matching_formats (matching); - free (matching); + s->vma += adjust_section_vma; + s->lma += adjust_section_vma; } - return; } - printf ("\n%s: file format %s\n", abfd->filename, abfd->xvec->name); + 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)) + { + non_fatal (_("%s: printing debugging information failed"), + bfd_get_filename (abfd)); + exit_status = 1; + } + } + } + if (syms) + { + free (syms); + syms = NULL; + } + if (dynsyms) + { + free (dynsyms); + dynsyms = NULL; + } +} + +static void +display_bfd (abfd) + bfd *abfd; +{ + char **matching; + + if (bfd_check_format_matches (abfd, bfd_object, &matching)) + { + dump_bfd (abfd); + return; + } + + if (bfd_get_error () == bfd_error_file_ambiguously_recognized) + { + nonfatal (bfd_get_filename (abfd)); + list_matching_formats (matching); + free (matching); + return; + } + + if (bfd_get_error () != bfd_error_file_not_recognized) + { + nonfatal (bfd_get_filename (abfd)); + return; + } + + if (bfd_check_format_matches (abfd, bfd_core, &matching)) + { + dump_bfd (abfd); + return; + } + + nonfatal (bfd_get_filename (abfd)); + + if (bfd_get_error () == bfd_error_file_ambiguously_recognized) + { + list_matching_formats (matching); + free (matching); + } } static void @@ -936,32 +2210,36 @@ display_file (filename, target) file = bfd_openr (filename, target); if (file == NULL) { - fprintf (stderr, "%s: ", program_name); - bfd_perror (filename); + nonfatal (filename); return; } if (bfd_check_format (file, bfd_archive) == true) { - printf ("In archive %s:\n", bfd_get_filename (file)); + 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) - { - fprintf (stderr, "%s: ", program_name); - bfd_perror (bfd_get_filename (file)); - } - return; + if (bfd_get_error () != bfd_error_no_more_archived_files) + nonfatal (bfd_get_filename (file)); + 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); @@ -978,7 +2256,9 @@ dump_data (abfd) asection *section; bfd_byte *data = 0; bfd_size_type datasize = 0; - bfd_size_type i; + bfd_size_type addr_offset; + bfd_size_type start_offset, stop_offset; + unsigned int opb = bfd_octets_per_byte (abfd); for (section = abfd->sections; section != NULL; section = section->next) @@ -990,7 +2270,7 @@ dump_data (abfd) { if (section->flags & SEC_HAS_CONTENTS) { - printf ("Contents of section %s:\n", section->name); + printf (_("Contents of section %s:\n"), section->name); if (bfd_section_size (abfd, section) == 0) continue; @@ -1000,14 +2280,33 @@ 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_offset = 0; + else + start_offset = start_address - section->vma; + if (stop_address == (bfd_vma) -1) + stop_offset = bfd_section_size (abfd, section) / opb; + else + { + if (stop_address < section->vma) + stop_offset = 0; + else + stop_offset = stop_address - section->vma; + if (stop_offset > bfd_section_size (abfd, section) / opb) + stop_offset = bfd_section_size (abfd, section) / opb; + } + for (addr_offset = start_offset; + addr_offset < stop_offset; addr_offset += onaline) { bfd_size_type j; - printf (" %04lx ", (unsigned long int) (i + section->vma)); - for (j = i; j < i + onaline; j++) + printf (" %04lx ", (unsigned long int) + (addr_offset + section->vma)); + for (j = addr_offset * opb; + j < addr_offset * opb + onaline; j++) { - if (j < bfd_section_size (abfd, section)) + if (j < stop_offset * opb) printf ("%02x", (unsigned) (data[j])); else printf (" "); @@ -1016,9 +2315,9 @@ dump_data (abfd) } printf (" "); - for (j = i; j < i + onaline; j++) + for (j = addr_offset; j < addr_offset * opb + onaline; j++) { - if (j >= bfd_section_size (abfd, section)) + if (j >= stop_offset * opb) printf (" "); else printf ("%c", isprint (data[j]) ? data[j] : '.'); @@ -1033,29 +2332,71 @@ dump_data (abfd) /* Should perhaps share code and display with nm? */ static void -dump_symbols (abfd) - bfd *abfd; +dump_symbols (abfd, dynamic) + bfd *abfd ATTRIBUTE_UNUSED; + 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++; } @@ -1068,14 +2409,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; @@ -1088,96 +2431,201 @@ 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); + if (q->howto->name) + printf (" %-16s ", q->howto->name); + else + printf (" %-16d ", q->howto->type); + 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"); } } -/* A file to open each BFD on. It will never actually be written to. */ -#ifdef unix -#define _DUMMY_NAME_ "/dev/null" -#else -#define _DUMMY_NAME_ "##dummy" -#endif - /* 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. */ @@ -1185,31 +2633,40 @@ static void display_target_list () { extern bfd_target *bfd_target_vector[]; + char *dummy_name; int t; + dummy_name = choose_temp_base (); for (t = 0; bfd_target_vector[t]; t++) { - int a; bfd_target *p = bfd_target_vector[t]; - bfd *abfd = bfd_openw (_DUMMY_NAME_, p->name); + 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)); - /* It *is* possible that bfd_openw might fail; avoid the - tragic consequences that would otherwise ensue. */ if (abfd == NULL) { - fprintf (stderr, "%s: ", program_name); - bfd_perror (_DUMMY_NAME_); - return; + nonfatal (dummy_name); + continue; } - 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"); + + if (! bfd_set_format (abfd, bfd_object)) + { + if (bfd_get_error () != bfd_error_invalid_operation) + 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 @@ -1221,33 +2678,51 @@ display_info_table (first, last) int first; int last; { - int t, a; extern bfd_target *bfd_target_vector[]; + int t, a; + char *dummy_name; /* Print heading of target names. */ - printf ("\n%*s", LONGEST_ARCH, " "); - for (t = first; t++ < last && bfd_target_vector[t];) + 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 ("%*s ", LONGEST_ARCH - 1, bfd_printable_arch_mach (a, 0)); - for (t = first; t++ < last && bfd_target_vector[t];) + 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 = bfd_target_vector[t]; - bfd *abfd = bfd_openw (_DUMMY_NAME_, p->name); + boolean ok = true; + bfd *abfd = bfd_openw (dummy_name, p->name); - /* Just in case the open failed somehow. */ if (abfd == NULL) { - fprintf (stderr, "%s: ", program_name); - bfd_perror (_DUMMY_NAME_); - return; + nonfatal (p->name); + ok = false; + } + + if (ok) + { + if (! bfd_set_format (abfd, bfd_object)) + { + if (bfd_get_error () != bfd_error_invalid_operation) + nonfatal (p->name); + ok = false; + } + } + + if (ok) + { + if (! bfd_set_arch_mach (abfd, a, 0)) + ok = false; } - bfd_set_format (abfd, bfd_object); - if (bfd_set_arch_mach (abfd, a, 0)) + + if (ok) printf ("%s ", p->name); else { @@ -1259,6 +2734,8 @@ display_info_table (first, last) } putchar ('\n'); } + unlink (dummy_name); + free (dummy_name); } /* Print tables of all the target-architecture combinations that @@ -1270,7 +2747,6 @@ display_target_tables () int t, columns; extern bfd_target *bfd_target_vector[]; char *colum; - extern char *getenv (); columns = 0; colum = getenv ("COLUMNS"); @@ -1279,15 +2755,23 @@ display_target_tables () if (columns == 0) columns = 80; - for (t = 0; bfd_target_vector[t];) + t = 0; + while (bfd_target_vector[t] != NULL) { int oldt = t, wid; - for (wid = LONGEST_ARCH; bfd_target_vector[t] && wid < columns; t++) - wid += strlen (bfd_target_vector[t]->name) + 1; - t--; - if (oldt == t) - break; + 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); } } @@ -1295,7 +2779,7 @@ display_target_tables () static void display_info () { - printf ("BFD header file version %s\n", BFD_VERSION); + printf (_("BFD header file version %s\n"), BFD_VERSION); display_target_list (); display_target_tables (); } @@ -1309,14 +2793,24 @@ main (argc, argv) char *target = default_target; boolean seenflag = false; - bfd_init (); +#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) + setlocale (LC_MESSAGES, ""); +#endif + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + program_name = *argv; + xmalloc_set_program_name (program_name); + + START_PROGRESS (program_name, 0); - while ((c = getopt_long (argc, argv, "ib:m:Vdlfahrtxsj:", long_options, - (int *) 0)) + bfd_init (); + set_default_bfd_target (); + + while ((c = getopt_long (argc, argv, "pib:m:M:VCdDlfahHrRtTxsSj:wE:zgG", + long_options, (int *) 0)) != EOF) { - seenflag = true; switch (c) { case 0: @@ -1324,69 +2818,151 @@ main (argc, argv) case 'm': machine = optarg; break; + case 'M': + disassembler_options = optarg; + break; case 'j': only = optarg; break; case 'l': - with_line_numbers = 1; + with_line_numbers = true; break; case 'b': target = optarg; break; + case 'C': + do_demangle = true; + break; + case 'w': + wide_output = true; + 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 + { + non_fatal (_("unrecognized -E option")); + 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 + { + non_fatal (_("unrecognized --endian type `%s'"), optarg); + usage (stderr, 1); + } + break; + case 'f': dump_file_header = true; + seenflag = true; break; case 'i': formats_info = true; + seenflag = true; + break; + case 'p': + dump_private_headers = true; + seenflag = true; break; case 'x': - dump_symtab = 1; - dump_reloc_info = 1; + dump_private_headers = true; + dump_symtab = true; + dump_reloc_info = true; dump_file_header = true; - dump_ar_hdrs = 1; - dump_section_headers = 1; + dump_ar_hdrs = true; + dump_section_headers = true; + seenflag = true; break; case 't': - dump_symtab = 1; + dump_symtab = true; + seenflag = true; + break; + case 'T': + dump_dynamic_symtab = true; + seenflag = true; break; case 'd': disassemble = true; + seenflag = true; + break; + case 'z': + disassemble_zeroes = true; + break; + case 'D': + disassemble = true; + disassemble_all = true; + seenflag = true; + break; + case 'S': + disassemble = true; + with_source_code = true; + seenflag = true; + break; + case 'g': + dump_debugging = 1; + seenflag = true; + break; + case 'G': + dump_stab_section_info = true; + seenflag = true; break; case 's': - dump_section_contents = 1; + dump_section_contents = true; + seenflag = true; break; case 'r': - dump_reloc_info = 1; + dump_reloc_info = true; + seenflag = true; + break; + case 'R': + dump_dynamic_reloc_info = true; + seenflag = true; break; case 'a': - dump_ar_hdrs = 1; + dump_ar_hdrs = true; + seenflag = true; break; case 'h': - dump_section_headers = 1; + dump_section_headers = true; + seenflag = true; break; case 'H': usage (stdout, 0); + seenflag = true; case 'V': - show_version = 1; + show_version = true; + seenflag = true; 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); + usage (stderr, 2); if (formats_info) - { - display_info (); - } + display_info (); else { if (optind == argc) @@ -1395,5 +2971,8 @@ main (argc, argv) for (; optind < argc;) display_file (argv[optind++], target); } - return 0; + + END_PROGRESS (program_name); + + return exit_status; }