X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=binutils%2Fobjdump.c;h=a273f511f15b1c9e9ad6ab05d57229fbe2342154;hb=92f01d6100e9f8bf2c4178dc34c1084119d6292d;hp=b641fde80383095261b7ea7a71d60646c7257305;hpb=06d86cf78eeb35897934df3c12e1024f305b2540;p=thirdparty%2Fbinutils-gdb.git diff --git a/binutils/objdump.c b/binutils/objdump.c index b641fde8038..a273f511f15 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -1,6 +1,6 @@ /* objdump.c -- dump information about an object file. Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003 + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -17,12 +17,42 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Objdump overview. + + Objdump displays information about one or more object files, either on + their own, or inside libraries. It is commonly used as a disassembler, + but it can also display information about file headers, symbol tables, + relocations, debugging directives and more. + + The flow of execution is as follows: + + 1. Command line arguments are checked for control switches and the + information to be displayed is selected. + + 2. Any remaining arguments are assumed to be object files, and they are + processed in order by display_bfd(). If the file is an archive each + of its elements is processed in turn. + + 3. The file's target architecture and binary file format are determined + by bfd_check_format(). If they are recognised, then dump_bfd() is + called. + + 4. dump_bfd() in turn calls separate functions to display the requested + item(s) of information(s). For example disassemble_data() is called if + a disassembly has been requested. + + When disassembling the code loops through blocks of instructions bounded + by symbols, calling disassemble_bytes() on each block. The actual + disassembling is done by the libopcodes library, via a function pointer + supplied by the disassembler() function. */ #include "bfd.h" #include "bfdver.h" #include "progress.h" #include "bucomm.h" +#include "dwarf.h" #include "budemang.h" #include "getopt.h" #include "safe-ctype.h" @@ -36,17 +66,13 @@ #define BYTES_IN_WORD 32 #include "aout/aout64.h" -#ifdef NEED_DECLARATION_FPRINTF -/* This is needed by INIT_DISASSEMBLE_INFO. */ -extern int fprintf - PARAMS ((FILE *, const char *, ...)); -#endif - /* Exit status. */ static int exit_status = 0; static char *default_target = NULL; /* Default at runtime. */ +/* The following variables are set based on arguments passed on the + command line. */ static int show_version = 0; /* Show the version number. */ static int dump_section_contents; /* -s */ static int dump_section_headers; /* -h */ @@ -61,33 +87,52 @@ static int prefix_addresses; /* --prefix-addresses */ static int with_line_numbers; /* -l */ static bfd_boolean with_source_code; /* -S */ static int show_raw_insn; /* --show-raw-insn */ +static int dump_dwarf_section_info; /* --dwarf */ static int dump_stab_section_info; /* --stabs */ static int do_demangle; /* -C, --demangle */ static bfd_boolean disassemble; /* -d */ static bfd_boolean disassemble_all; /* -D */ static int disassemble_zeroes; /* --disassemble-zeroes */ static bfd_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 int dump_debugging_tags; /* --debugging-tags */ +static int dump_special_syms = 0; /* --special-syms */ 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. */ +/* Pointer to an array of section names provided by + one or more "-j secname" command line options. */ +static char **only; +/* The total number of slots in the only[] array. */ +static size_t only_size = 0; +/* The number of occupied slots in the only[] array. */ +static size_t only_used = 0; + +/* Variables for handling include file path table. */ +static const char **include_paths; +static int include_path_count; + +/* Extra info to pass to the section disassembler and address printing + function. */ struct objdump_disasm_info { - bfd *abfd; - asection *sec; - bfd_boolean require_sec; + bfd * abfd; + asection * sec; + bfd_boolean require_sec; + arelent ** dynrelbuf; + long dynrelcount; + disassembler_ftype disassemble_fn; + arelent * reloc; }; /* Architecture to disassemble for, or default if NULL. */ -static char *machine = (char *) NULL; +static char *machine = NULL; /* Target specific options to the disassembler. */ -static char *disassembler_options = (char *) NULL; +static char *disassembler_options = NULL; /* Endianness to disassemble for, or default if BFD_ENDIAN_UNKNOWN. */ static enum bfd_endian endian = BFD_ENDIAN_UNKNOWN; @@ -107,6 +152,10 @@ static long sorted_symcount = 0; /* The dynamic symbol table. */ static asymbol **dynsyms; +/* The synthetic symbol table. */ +static asymbol *synthsyms; +static long synthcount = 0; + /* Number of symbols in `dynsyms'. */ static long dynsymcount = 0; @@ -115,82 +164,9 @@ static bfd_size_type stab_size; static char *strtab; static bfd_size_type stabstr_size; - -/* Static declarations. */ - -static void usage - PARAMS ((FILE *, int)); -static void nonfatal - PARAMS ((const char *)); -static void display_file - PARAMS ((char *, char *)); -static void dump_section_header - PARAMS ((bfd *, asection *, PTR)); -static void dump_headers - PARAMS ((bfd *)); -static void dump_data - PARAMS ((bfd *)); -static void dump_relocs - PARAMS ((bfd *)); -static void dump_dynamic_relocs - PARAMS ((bfd *)); -static void dump_reloc_set - PARAMS ((bfd *, asection *, arelent **, long)); -static void dump_symbols - PARAMS ((bfd *, bfd_boolean)); -static void dump_bfd_header - PARAMS ((bfd *)); -static void dump_bfd_private_header - PARAMS ((bfd *)); -static void dump_bfd - PARAMS ((bfd *)); -static void display_bfd - PARAMS ((bfd *)); -static void objdump_print_value - PARAMS ((bfd_vma, struct disassemble_info *, bfd_boolean)); -static void objdump_print_symname - PARAMS ((bfd *, struct disassemble_info *, asymbol *)); -static asymbol *find_symbol_for_address - PARAMS ((bfd *, asection *, bfd_vma, bfd_boolean, long *)); -static void objdump_print_addr_with_sym - PARAMS ((bfd *, asection *, asymbol *, bfd_vma, - struct disassemble_info *, bfd_boolean)); -static void objdump_print_addr - PARAMS ((bfd_vma, struct disassemble_info *, bfd_boolean)); -static void objdump_print_address - PARAMS ((bfd_vma, struct disassemble_info *)); -static int objdump_symbol_at_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, bfd_boolean, - bfd_byte *, bfd_vma, bfd_vma, arelent ***, arelent **)); -static void disassemble_data - PARAMS ((bfd *)); -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 bfd_boolean read_section_stabs - PARAMS ((bfd *, const char *, const char *)); -static void print_section_stabs - PARAMS ((bfd *, const char *, const char *)); -static void dump_section_stabs - PARAMS ((bfd *, char *, char *)); static void -usage (stream, status) - FILE *stream; - int status; +usage (FILE *stream, int status) { fprintf (stream, _("Usage: %s \n"), program_name); fprintf (stream, _(" Display information from object .\n")); @@ -206,11 +182,14 @@ usage (stream, status) -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\ + -e, --debugging-tags Display debug information using ctags style\n\ -G, --stabs Display (in raw form) any STABS info in the file\n\ + -W, --dwarf Display DWARF info in the 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\ + @ Read options from \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\ @@ -226,6 +205,7 @@ usage (stream, status) -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\ + -I, --include=DIR Add DIR to search list for source files\n\ -l, --line-numbers Include line numbers and filenames in output\n\ -C, --demangle[=STYLE] Decode mangled/processed symbol names\n\ The STYLE, if specified, can be `auto', `gnu',\n\ @@ -238,23 +218,26 @@ usage (stream, status) --prefix-addresses Print complete address alongside disassembly\n\ --[no-]show-raw-insn Display hex alongside symbolic disassembly\n\ --adjust-vma=OFFSET Add OFFSET to all displayed section addresses\n\ + --special-syms Include special symbols in symbol dumps\n\ \n")); list_supported_targets (program_name, stream); list_supported_architectures (program_name, stream); disassembler_usage (stream); } - if (status == 0) + if (REPORT_BUGS_TO[0] && 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) +enum option_values + { + OPTION_ENDIAN=150, + OPTION_START_ADDRESS, + OPTION_STOP_ADDRESS, + OPTION_ADJUST_VMA + }; static struct option long_options[]= { @@ -264,6 +247,7 @@ static struct option long_options[]= {"architecture", required_argument, NULL, 'm'}, {"archive-headers", no_argument, NULL, 'a'}, {"debugging", no_argument, NULL, 'g'}, + {"debugging-tags", no_argument, NULL, 'e'}, {"demangle", optional_argument, NULL, 'C'}, {"disassemble", no_argument, NULL, 'd'}, {"disassemble-all", no_argument, NULL, 'D'}, @@ -286,6 +270,9 @@ static struct option long_options[]= {"section-headers", no_argument, NULL, 'h'}, {"show-raw-insn", no_argument, &show_raw_insn, 1}, {"source", no_argument, NULL, 'S'}, + {"special-syms", no_argument, &dump_special_syms, 1}, + {"include", required_argument, NULL, 'I'}, + {"dwarf", no_argument, NULL, 'W'}, {"stabs", no_argument, NULL, 'G'}, {"start-address", required_argument, NULL, OPTION_START_ADDRESS}, {"stop-address", required_argument, NULL, OPTION_STOP_ADDRESS}, @@ -297,22 +284,24 @@ static struct option long_options[]= }; static void -nonfatal (msg) - const char *msg; +nonfatal (const char *msg) { bfd_nonfatal (msg); exit_status = 1; } static void -dump_section_header (abfd, section, ignored) - bfd *abfd ATTRIBUTE_UNUSED; - asection *section; - PTR ignored ATTRIBUTE_UNUSED; +dump_section_header (bfd *abfd, asection *section, + void *ignored ATTRIBUTE_UNUSED) { char *comma = ""; unsigned int opb = bfd_octets_per_byte (abfd); + /* Ignore linker created section. See elfNN_ia64_object_p in + bfd/elfxx-ia64.c. */ + if (section->flags & SEC_LINKER_CREATED) + return; + printf ("%3d %-13s %08lx ", section->index, bfd_get_section_name (abfd, section), (unsigned long) bfd_section_size (abfd, section) / opb); @@ -341,16 +330,21 @@ dump_section_header (abfd, section, ignored) PF (SEC_NEVER_LOAD, "NEVER_LOAD"); PF (SEC_EXCLUDE, "EXCLUDE"); PF (SEC_SORT_ENTRIES, "SORT_ENTRIES"); - PF (SEC_BLOCK, "BLOCK"); - PF (SEC_CLINK, "CLINK"); + if (bfd_get_arch (abfd) == bfd_arch_tic54x) + { + PF (SEC_TIC54X_BLOCK, "BLOCK"); + PF (SEC_TIC54X_CLINK, "CLINK"); + } PF (SEC_SMALL_DATA, "SMALL_DATA"); - PF (SEC_SHARED, "SHARED"); - PF (SEC_ARCH_BIT_0, "ARCH_BIT_0"); + if (bfd_get_flavour (abfd) == bfd_target_coff_flavour) + PF (SEC_COFF_SHARED, "SHARED"); PF (SEC_THREAD_LOCAL, "THREAD_LOCAL"); + PF (SEC_GROUP, "GROUP"); if ((section->flags & SEC_LINK_ONCE) != 0) { const char *ls; + struct coff_comdat_info *comdat; switch (section->flags & SEC_LINK_DUPLICATES) { @@ -371,9 +365,9 @@ dump_section_header (abfd, section, ignored) } printf ("%s%s", comma, ls); - if (section->comdat != NULL) - printf (" (COMDAT %s %ld)", section->comdat->name, - section->comdat->symbol); + comdat = bfd_coff_get_comdat_section (abfd, section); + if (comdat != NULL) + printf (" (COMDAT %s %ld)", comdat->name, comdat->symbol); comma = ", "; } @@ -383,8 +377,7 @@ dump_section_header (abfd, section, ignored) } static void -dump_headers (abfd) - bfd *abfd; +dump_headers (bfd *abfd) { printf (_("Sections:\n")); @@ -404,14 +397,13 @@ dump_headers (abfd) printf (_(" Pg")); printf ("\n"); - bfd_map_over_sections (abfd, dump_section_header, (PTR) NULL); + bfd_map_over_sections (abfd, dump_section_header, NULL); } static asymbol ** -slurp_symtab (abfd) - bfd *abfd; +slurp_symtab (bfd *abfd) { - asymbol **sy = (asymbol **) NULL; + asymbol **sy = NULL; long storage; if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) @@ -424,7 +416,7 @@ slurp_symtab (abfd) if (storage < 0) bfd_fatal (bfd_get_filename (abfd)); if (storage) - sy = (asymbol **) xmalloc (storage); + sy = xmalloc (storage); symcount = bfd_canonicalize_symtab (abfd, sy); if (symcount < 0) @@ -435,10 +427,9 @@ slurp_symtab (abfd) /* Read in the dynamic symbols. */ static asymbol ** -slurp_dynamic_symtab (abfd) - bfd *abfd; +slurp_dynamic_symtab (bfd *abfd) { - asymbol **sy = (asymbol **) NULL; + asymbol **sy = NULL; long storage; storage = bfd_get_dynamic_symtab_upper_bound (abfd); @@ -454,7 +445,7 @@ slurp_dynamic_symtab (abfd) bfd_fatal (bfd_get_filename (abfd)); } if (storage) - sy = (asymbol **) xmalloc (storage); + sy = xmalloc (storage); dynsymcount = bfd_canonicalize_dynamic_symtab (abfd, sy); if (dynsymcount < 0) @@ -467,11 +458,9 @@ slurp_dynamic_symtab (abfd) Return the number of useful symbols. */ static long -remove_useless_symbols (symbols, count) - asymbol **symbols; - long count; +remove_useless_symbols (asymbol **symbols, long count) { - register asymbol **in_ptr = symbols, **out_ptr = symbols; + asymbol **in_ptr = symbols, **out_ptr = symbols; while (--count >= 0) { @@ -479,7 +468,7 @@ remove_useless_symbols (symbols, count) if (sym->name == NULL || sym->name[0] == '\0') continue; - if (sym->flags & (BSF_DEBUGGING)) + if (sym->flags & (BSF_DEBUGGING | BSF_SECTION_SYM)) continue; if (bfd_is_und_section (sym->section) || bfd_is_com_section (sym->section)) @@ -493,16 +482,18 @@ remove_useless_symbols (symbols, count) /* Sort symbols into value order. */ static int -compare_symbols (ap, bp) - const PTR ap; - const PTR bp; +compare_symbols (const void *ap, const void *bp) { - const asymbol *a = *(const asymbol **)ap; - const asymbol *b = *(const asymbol **)bp; - const char *an, *bn; - size_t anl, bnl; - bfd_boolean af, bf; - flagword aflags, bflags; + const asymbol *a = * (const asymbol **) ap; + const asymbol *b = * (const asymbol **) bp; + const char *an; + const char *bn; + size_t anl; + size_t bnl; + bfd_boolean af; + bfd_boolean bf; + flagword aflags; + flagword bflags; if (bfd_asymbol_value (a) > bfd_asymbol_value (b)) return 1; @@ -600,12 +591,10 @@ compare_symbols (ap, bp) /* Sort relocs into address order. */ static int -compare_relocs (ap, bp) - const PTR ap; - const PTR bp; +compare_relocs (const void *ap, const void *bp) { - const arelent *a = *(const arelent **)ap; - const arelent *b = *(const arelent **)bp; + const arelent *a = * (const arelent **) ap; + const arelent *b = * (const arelent **) bp; if (a->address > b->address) return 1; @@ -622,19 +611,18 @@ compare_relocs (ap, bp) return 0; } -/* Print VMA to STREAM. If SKIP_ZEROES is TRUE, omit leading zeroes. */ +/* Print an address (VMA) to the output stream in INFO. + If SKIP_ZEROES is TRUE, omit leading zeroes. */ static void -objdump_print_value (vma, info, skip_zeroes) - bfd_vma vma; - struct disassemble_info *info; - bfd_boolean skip_zeroes; +objdump_print_value (bfd_vma vma, struct disassemble_info *info, + bfd_boolean skip_zeroes) { char buf[30]; char *p; - struct objdump_disasm_info *aux - = (struct objdump_disasm_info *) info->application_data; + struct objdump_disasm_info *aux; + aux = (struct objdump_disasm_info *) info->application_data; bfd_sprintf_vma (aux->abfd, buf, vma); if (! skip_zeroes) p = buf; @@ -651,10 +639,8 @@ objdump_print_value (vma, info, skip_zeroes) /* Print the name of a symbol. */ static void -objdump_print_symname (abfd, info, sym) - bfd *abfd; - struct disassemble_info *info; - asymbol *sym; +objdump_print_symname (bfd *abfd, struct disassemble_info *info, + asymbol *sym) { char *alloc; const char *name; @@ -677,18 +663,16 @@ objdump_print_symname (abfd, info, sym) 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. */ +/* Locate a symbol given a bfd and a section (from INFO->application_data), + and a VMA. If INFO->application_data->require_sec is TRUE, then always + require the symbol to be in the section. 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; - bfd_boolean require_sec; - long *place; +find_symbol_for_address (bfd_vma vma, + struct disassemble_info *info, + long *place) { /* @@ Would it speed things up to cache the last two symbols returned, and maybe their address ranges? For many processors, only one memory @@ -699,11 +683,19 @@ find_symbol_for_address (abfd, sec, vma, require_sec, place) long min = 0; long max = sorted_symcount; long thisplace; - unsigned int opb = bfd_octets_per_byte (abfd); + struct objdump_disasm_info *aux; + bfd *abfd; + asection *sec; + unsigned int opb; if (sorted_symcount < 1) return NULL; + aux = (struct objdump_disasm_info *) info->application_data; + abfd = aux->abfd; + sec = aux->sec; + opb = bfd_octets_per_byte (abfd); + /* Perform a binary search looking for the closest symbol to the required value. We are searching the range (min, max]. */ while (min + 1 < max) @@ -733,7 +725,7 @@ find_symbol_for_address (abfd, sec, vma, require_sec, place) == bfd_asymbol_value (sorted_syms[thisplace - 1]))) --thisplace; - /* If the file is relocateable, and the symbol could be from this + /* If the file is relocatable, 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. @@ -742,7 +734,7 @@ find_symbol_for_address (abfd, sec, vma, require_sec, place) no way to tell what's desired without looking at the relocation table. */ if (sorted_syms[thisplace]->section != sec - && (require_sec + && (aux->require_sec || ((abfd->flags & HAS_RELOC) != 0 && vma >= bfd_get_section_vma (abfd, sec) && vma < (bfd_get_section_vma (abfd, sec) @@ -787,15 +779,22 @@ find_symbol_for_address (abfd, sec, vma, require_sec, place) } if (sorted_syms[thisplace]->section != sec - && (require_sec + && (aux->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; - } + /* There is no suitable symbol. */ + return NULL; + } + + /* Give the target a chance to reject the symbol. */ + while (! info->symbol_is_valid (sorted_syms [thisplace], info)) + { + ++ thisplace; + if (thisplace >= sorted_symcount + || bfd_asymbol_value (sorted_syms [thisplace]) > vma) + return NULL; } if (place != NULL) @@ -804,16 +803,12 @@ find_symbol_for_address (abfd, sec, vma, require_sec, place) return sorted_syms[thisplace]; } -/* Print an address to INFO symbolically. */ +/* Print an address and the offset to the nearest symbol. */ 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; - bfd_boolean skip_zeroes; +objdump_print_addr_with_sym (bfd *abfd, asection *sec, asymbol *sym, + bfd_vma vma, struct disassemble_info *info, + bfd_boolean skip_zeroes) { objdump_print_value (vma, info, skip_zeroes); @@ -854,17 +849,17 @@ objdump_print_addr_with_sym (abfd, sec, sym, vma, info, skip_zeroes) } } -/* Print VMA to INFO, symbolically if possible. If SKIP_ZEROES is - TRUE, don't output leading zeroes. */ +/* Print an address (VMA), 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; - bfd_boolean skip_zeroes; +objdump_print_addr (bfd_vma vma, + struct disassemble_info *info, + bfd_boolean skip_zeroes) { struct objdump_disasm_info *aux; - asymbol *sym; + asymbol *sym = NULL; /* Initialize to avoid compiler warning. */ + bfd_boolean skip_find = FALSE; if (sorted_symcount < 1) { @@ -874,8 +869,23 @@ objdump_print_addr (vma, info, skip_zeroes) } aux = (struct objdump_disasm_info *) info->application_data; - sym = find_symbol_for_address (aux->abfd, aux->sec, vma, aux->require_sec, - (long *) NULL); + + if (aux->reloc != NULL + && aux->reloc->sym_ptr_ptr != NULL + && * aux->reloc->sym_ptr_ptr != NULL) + { + sym = * aux->reloc->sym_ptr_ptr; + + /* Adjust the vma to the reloc. */ + vma += bfd_asymbol_value (sym); + + if (bfd_is_und_section (bfd_get_section (sym))) + skip_find = TRUE; + } + + if (!skip_find) + sym = find_symbol_for_address (vma, info, NULL); + objdump_print_addr_with_sym (aux->abfd, aux->sec, sym, vma, info, skip_zeroes); } @@ -884,30 +894,19 @@ objdump_print_addr (vma, info, skip_zeroes) routine. */ static void -objdump_print_address (vma, info) - bfd_vma vma; - struct disassemble_info *info; +objdump_print_address (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. */ +/* Determine if the given address has a symbol associated with it. */ static int -objdump_symbol_at_address (vma, info) - bfd_vma vma; - struct disassemble_info * info; +objdump_symbol_at_address (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); + sym = find_symbol_for_address (vma, info, NULL); return (sym != NULL && (bfd_asymbol_value (sym) == vma)); } @@ -919,13 +918,14 @@ 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 + disassembly 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; + const char *filename; + const char *modname; unsigned int line; FILE *f; }; @@ -937,17 +937,95 @@ static struct print_file_list *print_files; #define SHOW_PRECEDING_CONTEXT_LINES (5) +/* Tries to open MODNAME, and if successful adds a node to print_files + linked list and returns that node. Returns NULL on failure. */ + +static struct print_file_list * +try_print_file_open (const char *origname, const char *modname) +{ + struct print_file_list *p; + FILE *f; + + f = fopen (modname, "r"); + if (f == NULL) + return NULL; + + if (print_files != NULL && print_files->f != NULL) + { + fclose (print_files->f); + print_files->f = NULL; + } + + p = xmalloc (sizeof (struct print_file_list)); + p->filename = origname; + p->modname = modname; + p->line = 0; + p->f = f; + p->next = print_files; + print_files = p; + return p; +} + +/* If the the source file, as described in the symtab, is not found + try to locate it in one of the paths specified with -I + If found, add location to print_files linked list. */ + +static struct print_file_list * +update_source_path (const char *filename) +{ + struct print_file_list *p; + const char *fname; + int i; + + if (filename == NULL) + return NULL; + + p = try_print_file_open (filename, filename); + if (p != NULL) + return p; + + if (include_path_count == 0) + return NULL; + + /* Get the name of the file. */ + fname = strrchr (filename, '/'); +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + { + /* We could have a mixed forward/back slash case. */ + char *backslash = strrchr (filename, '\\'); + if (fname == NULL || (backslash != NULL && backslash > fname)) + fname = backslash; + if (fname == NULL && filename[0] != '\0' && filename[1] == ':') + fname = filename + 1; + } +#endif + if (fname == NULL) + fname = filename; + else + ++fname; + + /* If file exists under a new path, we need to add it to the list + so that show_line knows about it. */ + for (i = 0; i < include_path_count; i++) + { + char *modname = concat (include_paths[i], "/", fname, (const char *) 0); + + p = try_print_file_open (filename, modname); + if (p) + return p; + + free (modname); + } + + return NULL; +} + /* 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, bfd_boolean)); - static void -skip_to_line (p, line, show) - struct print_file_list *p; - unsigned int line; - bfd_boolean show; +skip_to_line (struct print_file_list *p, unsigned int line, + bfd_boolean show) { while (p->line < line) { @@ -968,14 +1046,11 @@ skip_to_line (p, line, show) } } -/* Show the line number, or the source line, in a dissassembly +/* Show the line number, or the source line, in a disassembly listing. */ static void -show_line (abfd, section, addr_offset) - bfd *abfd; - asection *section; - bfd_vma addr_offset; +show_line (bfd *abfd, asection *section, bfd_vma addr_offset) { const char *filename; const char *functionname; @@ -1042,7 +1117,7 @@ show_line (abfd, section, addr_offset) if (p->f == NULL) { - p->f = fopen (p->filename, "r"); + p->f = fopen (p->modname, "r"); p->line = 0; } if (p->f != NULL) @@ -1065,28 +1140,12 @@ show_line (abfd, section, addr_offset) } else { - FILE *f; + p = update_source_path (filename); - f = fopen (filename, "r"); - if (f != NULL) + if (p != 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 @@ -1118,58 +1177,59 @@ show_line (abfd, section, addr_offset) typedef struct { char *buffer; - size_t size; - char *current; + size_t pos; + size_t alloc; } SFILE; -/* sprintf to a "stream" */ +/* sprintf to a "stream". */ -static int -objdump_sprintf VPARAMS ((SFILE *f, const char *format, ...)) +static int ATTRIBUTE_PRINTF_2 +objdump_sprintf (SFILE *f, const char *format, ...) { - char *buf; size_t n; + va_list args; - VA_OPEN (args, format); - VA_FIXEDARG (args, SFILE *, f); - VA_FIXEDARG (args, const char *, format); - - vasprintf (&buf, format, args); - - if (buf == NULL) + while (1) { + size_t space = f->alloc - f->pos; + + va_start (args, format); + n = vsnprintf (f->buffer + f->pos, space, format, args); va_end (args); - fatal (_("Out of virtual memory")); - } - n = strlen (buf); + if (space > n) + break; + + f->alloc = (f->alloc + n) * 2; + f->buffer = xrealloc (f->buffer, f->alloc); + } + f->pos += n; + + return n; +} - while ((size_t) ((f->buffer + f->size) - f->current) < n + 1) - { - size_t curroff; +/* Returns TRUE if the specified section should be dumped. */ - curroff = f->current - f->buffer; - f->size *= 2; - f->buffer = xrealloc (f->buffer, f->size); - f->current = f->buffer + curroff; - } +static bfd_boolean +process_section_p (asection * section) +{ + size_t i; - memcpy (f->current, buf, n); - f->current += n; - f->current[0] = '\0'; + if (only == NULL) + return TRUE; - free (buf); + for (i = 0; i < only_used; i++) + if (strcmp (only [i], section->name) == 0) + return TRUE; - VA_CLOSE (args); - return n; + return FALSE; } + /* The number of zeroes we want to see before we start skipping them. The number is arbitrarily chosen. */ -#ifndef SKIP_ZEROES -#define SKIP_ZEROES (8) -#endif +#define DEFAULT_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 @@ -1178,24 +1238,20 @@ objdump_sprintf VPARAMS ((SFILE *f, const char *format, ...)) attempt to avoid disassembling zeroes inserted by section alignment. */ -#ifndef SKIP_ZEROES_AT_END -#define SKIP_ZEROES_AT_END (3) -#endif +#define DEFAULT_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; - bfd_boolean insns; - bfd_byte *data; - bfd_vma start_offset; - bfd_vma stop_offset; - arelent ***relppp; - arelent **relppend; +disassemble_bytes (struct disassemble_info * info, + disassembler_ftype disassemble_fn, + bfd_boolean insns, + bfd_byte * data, + bfd_vma start_offset, + bfd_vma stop_offset, + bfd_vma rel_offset, + arelent *** relppp, + arelent ** relppend) { struct objdump_disasm_info *aux; asection *section; @@ -1203,11 +1259,19 @@ disassemble_bytes (info, disassemble_fn, insns, data, bfd_boolean done_dot; int skip_addr_chars; bfd_vma addr_offset; - int opb = info->octets_per_byte; + unsigned int opb = info->octets_per_byte; + unsigned int skip_zeroes = info->skip_zeroes; + unsigned int skip_zeroes_at_end = info->skip_zeroes_at_end; + int octets = opb; + SFILE sfile; aux = (struct objdump_disasm_info *) info->application_data; section = aux->sec; + sfile.alloc = 120; + sfile.buffer = xmalloc (sfile.alloc); + sfile.pos = 0; + if (insns) octets_per_line = 4; else @@ -1243,27 +1307,31 @@ disassemble_bytes (info, disassemble_fn, insns, data, while (addr_offset < stop_offset) { bfd_vma z; - int octets = 0; bfd_boolean need_nl = FALSE; + int previous_octets; + + /* Remember the length of the previous instruction. */ + previous_octets = octets; + octets = 0; /* If we see more than SKIP_ZEROES octets of zeroes, we just - print `...'. */ + 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 - addr_offset * opb >= skip_zeroes || (z == stop_offset * opb && - z - addr_offset * opb < SKIP_ZEROES_AT_END))) + 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. */ + 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); @@ -1272,17 +1340,13 @@ disassemble_bytes (info, disassemble_fn, insns, data, else { char buf[50]; - SFILE sfile; int bpc = 0; int pb = 0; done_dot = FALSE; if (with_line_numbers || with_source_code) - /* The line number tables will refer to unadjusted - section VMAs, so we must undo any VMA modifications - when calling show_line. */ - show_line (aux->abfd, section, addr_offset - adjust_section_vma); + show_line (aux->abfd, section, addr_offset); if (! prefix_addresses) { @@ -1305,24 +1369,44 @@ disassemble_bytes (info, disassemble_fn, insns, data, if (insns) { - sfile.size = 120; - sfile.buffer = xmalloc (sfile.size); - sfile.current = sfile.buffer; + sfile.pos = 0; info->fprintf_func = (fprintf_ftype) objdump_sprintf; - info->stream = (FILE *) &sfile; + info->stream = &sfile; info->bytes_per_line = 0; info->bytes_per_chunk = 0; + info->flags = 0; -#ifdef DISASSEMBLER_NEEDS_RELOCS - /* 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 -#endif - info->flags = 0; + if (info->disassembler_needs_relocs + && *relppp < relppend) + { + bfd_signed_vma distance_to_rel; + + distance_to_rel = (**relppp)->address + - (rel_offset + addr_offset); + + /* Check to see if the current reloc is associated with + the instruction that we are about to disassemble. */ + if (distance_to_rel == 0 + /* FIXME: This is wrong. We are trying to catch + relocs that are addressed part way through the + current instruction, as might happen with a packed + VLIW instruction. Unfortunately we do not know the + length of the current instruction since we have not + disassembled it yet. Instead we take a guess based + upon the length of the previous instruction. The + proper solution is to have a new target-specific + disassembler function which just returns the length + of an instruction at a given address without trying + to display its disassembly. */ + || (distance_to_rel > 0 + && distance_to_rel < (bfd_signed_vma) (previous_octets/ opb))) + { + info->flags = INSN_HAS_RELOC; + aux->reloc = **relppp; + } + else + aux->reloc = NULL; + } octets = (*disassemble_fn) (section->vma + addr_offset, info); info->fprintf_func = (fprintf_ftype) fprintf; @@ -1331,9 +1415,8 @@ disassemble_bytes (info, disassemble_fn, insns, data, octets_per_line = info->bytes_per_line; if (octets < 0) { - if (sfile.current != sfile.buffer) + if (sfile.pos) printf ("%s\n", sfile.buffer); - free (sfile.buffer); break; } } @@ -1362,7 +1445,7 @@ disassemble_bytes (info, disassemble_fn, insns, data, bfd_vma j; /* If ! prefix_addresses and ! wide_output, we print - octets_per_line octets per line. */ + octets_per_line octets per line. */ pb = octets; if (pb > octets_per_line && ! prefix_addresses && ! wide_output) pb = octets_per_line; @@ -1375,6 +1458,7 @@ disassemble_bytes (info, disassemble_fn, insns, data, for (j = addr_offset * opb; j < addr_offset * opb + pb; j += bpc) { int k; + if (bpc > 1 && info->display_endian == BFD_ENDIAN_LITTLE) { for (k = bpc - 1; k >= 0; k--) @@ -1407,11 +1491,8 @@ disassemble_bytes (info, disassemble_fn, insns, data, if (! insns) printf ("%s", buf); - else - { - printf ("%s", sfile.buffer); - free (sfile.buffer); - } + else if (sfile.pos) + printf ("%s", sfile.buffer); if (prefix_addresses ? show_raw_insn > 0 @@ -1461,20 +1542,10 @@ disassemble_bytes (info, disassemble_fn, insns, data, need_nl = TRUE; } - if ((section->flags & SEC_RELOC) != 0 -#ifndef DISASSEMBLER_NEEDS_RELOCS - && dump_reloc_info -#endif - ) + while ((*relppp) < relppend + && (**relppp)->address < rel_offset + addr_offset + octets / opb) { - while ((*relppp) < relppend - && ((**relppp)->address >= (bfd_vma) addr_offset - && (**relppp)->address < (bfd_vma) addr_offset + octets / opb)) -#ifdef DISASSEMBLER_NEEDS_RELOCS - if (! dump_reloc_info) - ++(*relppp); - else -#endif + if (dump_reloc_info || dump_dynamic_reloc_info) { arelent *q; @@ -1485,9 +1556,15 @@ disassemble_bytes (info, disassemble_fn, insns, data, else printf ("\t\t\t"); - objdump_print_value (section->vma + q->address, info, TRUE); + objdump_print_value (section->vma - rel_offset + q->address, + info, TRUE); - printf (": %s\t", q->howto->name); + if (q->howto == NULL) + printf (": *unknown*\t"); + else if (q->howto->name) + printf (": %s\t", q->howto->name); + else + printf (": %d\t", q->howto->type); if (q->sym_ptr_ptr == NULL || *q->sym_ptr_ptr == NULL) printf ("*unknown*"); @@ -1518,8 +1595,8 @@ disassemble_bytes (info, disassemble_fn, insns, data, printf ("\n"); need_nl = FALSE; - ++(*relppp); } + ++(*relppp); } if (need_nl) @@ -1527,20 +1604,240 @@ disassemble_bytes (info, disassemble_fn, insns, data, addr_offset += octets / opb; } + + free (sfile.buffer); +} + +static void +disassemble_section (bfd *abfd, asection *section, void *info) +{ + struct disassemble_info * pinfo = (struct disassemble_info *) info; + struct objdump_disasm_info * paux; + unsigned int opb = pinfo->octets_per_byte; + bfd_byte * data = NULL; + bfd_size_type datasize = 0; + arelent ** rel_pp = NULL; + arelent ** rel_ppstart = NULL; + arelent ** rel_ppend; + unsigned long stop_offset; + asymbol * sym = NULL; + long place = 0; + long rel_count; + bfd_vma rel_offset; + unsigned long addr_offset; + + /* Sections that do not contain machine + code are not normally disassembled. */ + if (! disassemble_all + && only == NULL + && ((section->flags & (SEC_CODE | SEC_HAS_CONTENTS)) + != (SEC_CODE | SEC_HAS_CONTENTS))) + return; + + if (! process_section_p (section)) + return; + + datasize = bfd_get_section_size (section); + if (datasize == 0) + return; + + /* Decide which set of relocs to use. Load them if necessary. */ + paux = (struct objdump_disasm_info *) pinfo->application_data; + if (paux->dynrelbuf) + { + rel_pp = paux->dynrelbuf; + rel_count = paux->dynrelcount; + /* Dynamic reloc addresses are absolute, non-dynamic are section + relative. REL_OFFSET specifies the reloc address corresponding + to the start of this section. */ + rel_offset = section->vma; + } + else + { + rel_count = 0; + rel_pp = NULL; + rel_offset = 0; + + if ((section->flags & SEC_RELOC) != 0 + && (dump_reloc_info || pinfo->disassembler_needs_relocs)) + { + long relsize; + + relsize = bfd_get_reloc_upper_bound (abfd, section); + if (relsize < 0) + bfd_fatal (bfd_get_filename (abfd)); + + if (relsize > 0) + { + rel_ppstart = rel_pp = xmalloc (relsize); + rel_count = bfd_canonicalize_reloc (abfd, section, rel_pp, syms); + if (rel_count < 0) + bfd_fatal (bfd_get_filename (abfd)); + + /* Sort the relocs by address. */ + qsort (rel_pp, rel_count, sizeof (arelent *), compare_relocs); + } + } + + } + rel_ppend = rel_pp + rel_count; + + data = xmalloc (datasize); + + bfd_get_section_contents (abfd, section, data, 0, datasize); + + paux->sec = section; + pinfo->buffer = data; + pinfo->buffer_vma = section->vma; + pinfo->buffer_length = datasize; + pinfo->section = section; + + if (start_address == (bfd_vma) -1 + || start_address < pinfo->buffer_vma) + addr_offset = 0; + else + addr_offset = start_address - pinfo->buffer_vma; + + if (stop_address == (bfd_vma) -1) + stop_offset = datasize / opb; + else + { + if (stop_address < pinfo->buffer_vma) + stop_offset = 0; + else + stop_offset = stop_address - pinfo->buffer_vma; + if (stop_offset > pinfo->buffer_length / opb) + stop_offset = pinfo->buffer_length / opb; + } + + /* Skip over the relocs belonging to addresses below the + start address. */ + while (rel_pp < rel_ppend + && (*rel_pp)->address < rel_offset + addr_offset) + ++rel_pp; + + printf (_("Disassembly of section %s:\n"), section->name); + + /* Find the nearest symbol forwards from our current position. */ + paux->require_sec = TRUE; + sym = find_symbol_for_address (section->vma + addr_offset, info, &place); + paux->require_sec = FALSE; + + /* Disassemble a block of instructions up to the address associated with + the symbol we have just found. Then print the symbol and find the + next symbol on. Repeat until we have disassembled the entire section + or we have reached the end of the address range we are interested in. */ + while (addr_offset < stop_offset) + { + bfd_vma addr; + asymbol *nextsym; + unsigned long nextstop_offset; + bfd_boolean insns; + + addr = section->vma + addr_offset; + + if (sym != NULL && bfd_asymbol_value (sym) <= addr) + { + int x; + + for (x = place; + (x < sorted_symcount + && (bfd_asymbol_value (sorted_syms[x]) <= addr)); + ++x) + continue; + + pinfo->symbols = sorted_syms + place; + pinfo->num_symbols = x - place; + pinfo->symtab_pos = place; + } + else + { + pinfo->symbols = NULL; + pinfo->num_symbols = 0; + pinfo->symtab_pos = -1; + } + + if (! prefix_addresses) + { + pinfo->fprintf_func (pinfo->stream, "\n"); + objdump_print_addr_with_sym (abfd, section, sym, addr, + pinfo, FALSE); + pinfo->fprintf_func (pinfo->stream, ":\n"); + } + + if (sym != NULL && bfd_asymbol_value (sym) > addr) + nextsym = sym; + else if (sym == NULL) + nextsym = NULL; + else + { +#define is_valid_next_sym(SYM) \ + ((SYM)->section == section \ + && (bfd_asymbol_value (SYM) > bfd_asymbol_value (sym)) \ + && pinfo->symbol_is_valid (SYM, pinfo)) + + /* 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 + && ! is_valid_next_sym (sorted_syms [place])) + ++place; + + if (place >= sorted_symcount) + nextsym = NULL; + else + nextsym = sorted_syms[place]; + } + + if (sym != NULL && bfd_asymbol_value (sym) > addr) + nextstop_offset = bfd_asymbol_value (sym) - section->vma; + 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) > addr + || ((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 (pinfo, paux->disassemble_fn, insns, data, + addr_offset, nextstop_offset, + rel_offset, &rel_pp, rel_ppend); + + addr_offset = nextstop_offset; + sym = nextsym; + } + + free (data); + + if (rel_ppstart != NULL) + free (rel_ppstart); } /* Disassemble the contents of an object file. */ static void -disassemble_data (abfd) - bfd *abfd; +disassemble_data (bfd *abfd) { - unsigned long addr_offset; - disassembler_ftype disassemble_fn; struct disassemble_info disasm_info; struct objdump_disasm_info aux; - asection *section; - unsigned int opb; + long i; print_files = NULL; prev_functionname = NULL; @@ -1548,23 +1845,35 @@ disassemble_data (abfd) /* 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 = symcount ? symcount : dynsymcount; + sorted_syms = xmalloc ((sorted_symcount + synthcount) * sizeof (asymbol *)); + memcpy (sorted_syms, symcount ? syms : dynsyms, + sorted_symcount * sizeof (asymbol *)); - sorted_symcount = remove_useless_symbols (sorted_syms, symcount); + sorted_symcount = remove_useless_symbols (sorted_syms, sorted_symcount); + + for (i = 0; i < synthcount; ++i) + { + sorted_syms[sorted_symcount] = synthsyms + i; + ++sorted_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); + init_disassemble_info (&disasm_info, stdout, (fprintf_ftype) fprintf); - disasm_info.application_data = (PTR) &aux; + disasm_info.application_data = (void *) &aux; aux.abfd = abfd; aux.require_sec = FALSE; + aux.dynrelbuf = NULL; + aux.dynrelcount = 0; + aux.reloc = NULL; + disasm_info.print_address_func = objdump_print_address; disasm_info.symbol_at_address_func = objdump_symbol_at_address; - if (machine != (char *) NULL) + if (machine != NULL) { const bfd_arch_info_type *info = bfd_scan_arch (machine); @@ -1578,14 +1887,15 @@ disassemble_data (abfd) { struct bfd_target *xvec; - xvec = (struct bfd_target *) xmalloc (sizeof (struct bfd_target)); + xvec = xmalloc (sizeof (struct bfd_target)); memcpy (xvec, abfd->xvec, sizeof (struct bfd_target)); xvec->byteorder = endian; abfd->xvec = xvec; } - disassemble_fn = disassembler (abfd); - if (!disassemble_fn) + /* Use libopcodes to locate a suitable disassembler. */ + aux.disassemble_fn = disassembler (abfd); + if (!aux.disassemble_fn) { non_fatal (_("Can't disassemble for architecture %s\n"), bfd_printable_arch_mach (bfd_get_arch (abfd), 0)); @@ -1593,13 +1903,14 @@ disassemble_data (abfd) return; } - opb = bfd_octets_per_byte (abfd); - 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; - disasm_info.octets_per_byte = opb; + disasm_info.octets_per_byte = bfd_octets_per_byte (abfd); + disasm_info.skip_zeroes = DEFAULT_SKIP_ZEROES; + disasm_info.skip_zeroes_at_end = DEFAULT_SKIP_ZEROES_AT_END; + disasm_info.disassembler_needs_relocs = FALSE; if (bfd_big_endian (abfd)) disasm_info.display_endian = disasm_info.endian = BFD_ENDIAN_BIG; @@ -1610,271 +1921,232 @@ disassemble_data (abfd) instead. */ disasm_info.endian = BFD_ENDIAN_UNKNOWN; - for (section = abfd->sections; - section != (asection *) NULL; - section = section->next) - { - 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; + /* Allow the target to customize the info structure. */ + disassemble_init_for_target (& disasm_info); - if ((section->flags & SEC_RELOC) != 0 -#ifndef DISASSEMBLER_NEEDS_RELOCS - && dump_reloc_info -#endif - ) - { - long relsize; + /* Pre-load the dynamic relocs if we are going + to be dumping them along with the disassembly. */ + if (dump_dynamic_reloc_info) + { + long relsize = bfd_get_dynamic_reloc_upper_bound (abfd); + + if (relsize < 0) + bfd_fatal (bfd_get_filename (abfd)); - relsize = bfd_get_reloc_upper_bound (abfd, section); - if (relsize < 0) + if (relsize > 0) + { + aux.dynrelbuf = xmalloc (relsize); + aux.dynrelcount = bfd_canonicalize_dynamic_reloc (abfd, + aux.dynrelbuf, + dynsyms); + if (aux.dynrelcount < 0) bfd_fatal (bfd_get_filename (abfd)); - if (relsize > 0) - { - long relcount; + /* Sort the relocs by address. */ + qsort (aux.dynrelbuf, aux.dynrelcount, sizeof (arelent *), + compare_relocs); + } + } + disasm_info.symtab = sorted_syms; + disasm_info.symtab_size = sorted_symcount; - relbuf = (arelent **) xmalloc (relsize); - relcount = bfd_canonicalize_reloc (abfd, section, relbuf, syms); - if (relcount < 0) - bfd_fatal (bfd_get_filename (abfd)); + bfd_map_over_sections (abfd, disassemble_section, & disasm_info); - /* Sort the relocs by address. */ - qsort (relbuf, relcount, sizeof (arelent *), compare_relocs); + if (aux.dynrelbuf != NULL) + free (aux.dynrelbuf); + free (sorted_syms); +} + +int +load_debug_section (enum dwarf_section_display_enum debug, void *file) +{ + struct dwarf_section *section = &debug_displays [debug].section; + bfd *abfd = file; + asection *sec; + bfd_boolean ret; - relpp = relbuf; - relppend = relpp + relcount; + /* If it is already loaded, do nothing. */ + if (section->start != NULL) + return 1; - /* 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; - } - } + /* Locate the debug section. */ + sec = bfd_get_section_by_name (abfd, section->name); + if (sec == NULL) + return 0; - printf (_("Disassembly of section %s:\n"), section->name); + section->address = bfd_get_section_vma (abfd, sec); + section->size = bfd_get_section_size (sec); + section->start = xmalloc (section->size); - datasize = bfd_get_section_size_before_reloc (section); - if (datasize == 0) - continue; + if (is_relocatable && debug_displays [debug].relocate) + ret = bfd_simple_get_relocated_section_contents (abfd, + sec, + section->start, + syms) != NULL; + else + ret = bfd_get_section_contents (abfd, sec, section->start, 0, + section->size); - data = (bfd_byte *) xmalloc ((size_t) datasize); + if (!ret) + { + free_debug_section (debug); + printf (_("\nCan't get contents for section '%s'.\n"), + section->name); + } - bfd_get_section_contents (abfd, section, data, 0, datasize); + return ret; +} - aux.sec = section; - disasm_info.buffer = data; - disasm_info.buffer_vma = section->vma; - disasm_info.buffer_length = datasize; - disasm_info.section = section; +void +free_debug_section (enum dwarf_section_display_enum debug) +{ + struct dwarf_section *section = &debug_displays [debug].section; - 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 (section->start == NULL) + return; - 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; - } + free ((char *) section->start); + section->start = NULL; + section->address = 0; + section->size = 0; +} - sym = find_symbol_for_address (abfd, section, section->vma + addr_offset, - TRUE, &place); +static void +dump_dwarf_section (bfd *abfd, asection *section, + void *arg ATTRIBUTE_UNUSED) +{ + const char *name = bfd_get_section_name (abfd, section); + const char *match; + enum dwarf_section_display_enum i; - while (addr_offset < stop_offset) - { - asymbol *nextsym; - unsigned long nextstop_offset; - bfd_boolean insns; + if (CONST_STRNEQ (name, ".gnu.linkonce.wi.")) + match = ".debug_info"; + else + match = name; - if (sym != NULL && bfd_asymbol_value (sym) <= section->vma + addr_offset) - { - int x; + for (i = 0; i < max; i++) + if (strcmp (debug_displays[i].section.name, match) == 0) + { + if (!debug_displays[i].eh_frame) + { + struct dwarf_section *sec = &debug_displays [i].section; + + if (load_debug_section (i, abfd)) + { + debug_displays[i].display (sec, abfd); + + if (i != info && i != abbrev) + free_debug_section (i); + } + } + break; + } +} - for (x = place; - (x < sorted_symcount - && bfd_asymbol_value (sorted_syms[x]) <= section->vma + addr_offset); - ++x) - continue; +static const char *mach_o_dwarf_sections [] = { + "LC_SEGMENT.__DWARFA.__debug_abbrev", /* .debug_abbrev */ + "LC_SEGMENT.__DWARFA.__debug_aranges", /* .debug_aranges */ + "LC_SEGMENT.__DWARFA.__debug_frame", /* .debug_frame */ + "LC_SEGMENT.__DWARFA.__debug_info", /* .debug_info */ + "LC_SEGMENT.__DWARFA.__debug_line", /* .debug_line */ + "LC_SEGMENT.__DWARFA.__debug_pubnames", /* .debug_pubnames */ + ".eh_frame", /* .eh_frame */ + "LC_SEGMENT.__DWARFA.__debug_macinfo", /* .debug_macinfo */ + "LC_SEGMENT.__DWARFA.__debug_str", /* .debug_str */ + "LC_SEGMENT.__DWARFA.__debug_loc", /* .debug_loc */ + "LC_SEGMENT.__DWARFA.__debug_pubtypes", /* .debug_pubtypes */ + "LC_SEGMENT.__DWARFA.__debug_ranges", /* .debug_ranges */ + "LC_SEGMENT.__DWARFA.__debug_static_func", /* .debug_static_func */ + "LC_SEGMENT.__DWARFA.__debug_static_vars", /* .debug_static_vars */ + "LC_SEGMENT.__DWARFA.__debug_types", /* .debug_types */ + "LC_SEGMENT.__DWARFA.__debug_weaknames" /* .debug_weaknames */ +}; - disasm_info.symbols = & sorted_syms[place]; - disasm_info.num_symbols = x - place; - } - else - disasm_info.symbols = NULL; +static const char *generic_dwarf_sections [max]; - if (! prefix_addresses) - { - (* disasm_info.fprintf_func) (disasm_info.stream, "\n"); - objdump_print_addr_with_sym (abfd, section, sym, - section->vma + addr_offset, - &disasm_info, - FALSE); - (* disasm_info.fprintf_func) (disasm_info.stream, ":\n"); - } +static void +check_mach_o_dwarf (bfd *abfd) +{ + static enum bfd_flavour old_flavour = bfd_target_unknown_flavour; + enum bfd_flavour current_flavour = bfd_get_flavour (abfd); + enum dwarf_section_display_enum i; - 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 (generic_dwarf_sections [0] == NULL) + for (i = 0; i < max; i++) + generic_dwarf_sections [i] = debug_displays[i].section.name; - 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 (old_flavour != current_flavour) + { + if (current_flavour == bfd_target_mach_o_flavour) + for (i = 0; i < max; i++) + debug_displays[i].section.name = mach_o_dwarf_sections [i]; + else if (old_flavour == bfd_target_mach_o_flavour) + for (i = 0; i < max; i++) + debug_displays[i].section.name = generic_dwarf_sections [i]; + + old_flavour = current_flavour; + } +} - /* 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; +/* Dump the dwarf debugging information. */ - disassemble_bytes (&disasm_info, disassemble_fn, insns, data, - addr_offset, nextstop_offset, &relpp, relppend); +static void +dump_dwarf (bfd *abfd) +{ + is_relocatable = ((abfd->flags & (HAS_RELOC | EXEC_P | DYNAMIC)) + == HAS_RELOC); - addr_offset = nextstop_offset; - sym = nextsym; - } + /* FIXME: bfd_get_arch_size may return -1. We assume that 64bit + targets will return 64. */ + eh_addr_size = bfd_get_arch_size (abfd) == 64 ? 8 : 4; - free (data); + if (bfd_big_endian (abfd)) + byte_get = byte_get_big_endian; + else if (bfd_little_endian (abfd)) + byte_get = byte_get_little_endian; + else + abort (); - if (relbuf != NULL) - free (relbuf); - } - free (sorted_syms); -} - -/* Dump the stabs sections from an object file that has a section that - uses Sun stabs encoding. */ + check_mach_o_dwarf (abfd); -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$"); -} + bfd_map_over_sections (abfd, dump_dwarf_section, NULL); -/* 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. */ + free_debug_memory (); +} + +/* Read ABFD's stabs section STABSECT_NAME, and return a pointer to + it. Return NULL on failure. */ -static bfd_boolean -read_section_stabs (abfd, stabsect_name, strsect_name) - bfd *abfd; - const char *stabsect_name; - const char *strsect_name; +static char * +read_section_stabs (bfd *abfd, const char *sect_name, bfd_size_type *size_ptr) { - asection *stabsect, *stabstrsect; + asection *stabsect; + bfd_size_type size; + char *contents; - stabsect = bfd_get_section_by_name (abfd, stabsect_name); - if (0 == stabsect) + stabsect = bfd_get_section_by_name (abfd, sect_name); + if (stabsect == NULL) { - printf (_("No %s section present\n\n"), stabsect_name); + printf (_("No %s section present\n\n"), sect_name); return FALSE; } - stabstrsect = bfd_get_section_by_name (abfd, strsect_name); - if (0 == stabstrsect) - { - 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); - - stabs = (bfd_byte *) xmalloc (stab_size); - strtab = (char *) xmalloc (stabstr_size); + size = bfd_section_size (abfd, stabsect); + contents = xmalloc (size); - if (! bfd_get_section_contents (abfd, stabsect, (PTR) stabs, 0, stab_size)) + if (! bfd_get_section_contents (abfd, stabsect, contents, 0, size)) { non_fatal (_("Reading %s section of %s failed: %s"), - stabsect_name, bfd_get_filename (abfd), + sect_name, bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ())); - free (stabs); - free (strtab); + free (contents); exit_status = 1; - return FALSE; + return NULL; } - if (! 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; - } + *size_ptr = size; - return TRUE; + return contents; } /* Stabs entries use a 12 byte format: @@ -1885,24 +2157,24 @@ read_section_stabs (abfd, stabsect_name, strsect_name) 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 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; +print_section_stabs (bfd *abfd, + const char *stabsect_name, + unsigned *string_offset_ptr) { int i; - unsigned file_string_table_offset = 0, next_file_string_table_offset = 0; + unsigned file_string_table_offset = 0; + unsigned next_file_string_table_offset = *string_offset_ptr; bfd_byte *stabp, *stabs_end; stabp = stabs; @@ -1962,47 +2234,76 @@ print_section_stabs (abfd, stabsect_name, strsect_name) } } printf ("\n\n"); + *string_offset_ptr = next_file_string_table_offset; +} + +typedef struct +{ + const char * section_name; + const char * string_section_name; + unsigned string_offset; } +stab_section_names; static void -dump_section_stabs (abfd, stabsect_name, strsect_name) - bfd *abfd; - char *stabsect_name; - char *strsect_name; +find_stabs_section (bfd *abfd, asection *section, void *names) { - asection *s; + int len; + stab_section_names * sought = (stab_section_names *) names; /* Check for section names for which stabsect_name is a prefix, to - handle .stab0, etc. */ - for (s = abfd->sections; - s != NULL; - s = s->next) + handle .stab.N, etc. */ + len = strlen (sought->section_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 (sought->section_name, section->name, len) == 0 + && (section->name[len] == 0 + || (section->name[len] == '.' && ISDIGIT (section->name[len + 1])))) { - 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 (s->name[len]))) + if (strtab == NULL) + strtab = read_section_stabs (abfd, sought->string_section_name, + &stabstr_size); + + if (strtab) { - if (read_section_stabs (abfd, s->name, strsect_name)) - { - print_section_stabs (abfd, s->name, strsect_name); - free (stabs); - free (strtab); - } + stabs = (bfd_byte *) read_section_stabs (abfd, section->name, + &stab_size); + if (stabs) + print_section_stabs (abfd, section->name, &sought->string_offset); } } } +static void +dump_stabs_section (bfd *abfd, char *stabsect_name, char *strsect_name) +{ + stab_section_names s; + + s.section_name = stabsect_name; + s.string_section_name = strsect_name; + s.string_offset = 0; + + bfd_map_over_sections (abfd, find_stabs_section, & s); + + free (strtab); + strtab = NULL; +} + +/* Dump the any sections containing stabs debugging information. */ + +static void +dump_stabs (bfd *abfd) +{ + dump_stabs_section (abfd, ".stab", ".stabstr"); + dump_stabs_section (abfd, ".stab.excl", ".stab.exclstr"); + dump_stabs_section (abfd, ".stab.index", ".stab.indexstr"); + dump_stabs_section (abfd, "$GDB_SYMBOLS$", "$GDB_STRINGS$"); +} static void -dump_bfd_header (abfd) - bfd *abfd; +dump_bfd_header (bfd *abfd) { char *comma = ""; @@ -2030,270 +2331,145 @@ dump_bfd_header (abfd) static void -dump_bfd_private_header (abfd) -bfd *abfd; +dump_bfd_private_header (bfd *abfd) { bfd_print_private_bfd_data (abfd, stdout); } -/* Dump selected contents of ABFD. */ + +/* Display a section in hexadecimal format with associated characters. + Each line prefixed by the zero padded address. */ static void -dump_bfd (abfd) - bfd *abfd; +dump_section (bfd *abfd, asection *section, void *dummy ATTRIBUTE_UNUSED) { - /* 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) - { - asection *s; - - for (s = abfd->sections; s != NULL; s = s->next) - { - s->vma += adjust_section_vma; - s->lma += adjust_section_vma; - } - } - - 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); + bfd_byte *data = 0; + bfd_size_type datasize; + bfd_size_type addr_offset; + bfd_size_type start_offset; + bfd_size_type stop_offset; + unsigned int opb = bfd_octets_per_byte (abfd); + /* Bytes per line. */ + const int onaline = 16; + char buf[64]; + int count; + int width; - 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 ((section->flags & SEC_HAS_CONTENTS) == 0) + return; - if (dump_symtab) - dump_symbols (abfd, FALSE); - if (dump_dynamic_symtab) - dump_symbols (abfd, TRUE); - if (dump_stab_section_info) - dump_stabs (abfd); - if (dump_reloc_info && ! disassemble) - dump_relocs (abfd); - if (dump_dynamic_reloc_info) - dump_dynamic_relocs (abfd); - if (dump_section_contents) - dump_data (abfd); - if (disassemble) - disassemble_data (abfd); - if (dump_debugging) - { - PTR dhandle; + if (! process_section_p (section)) + return; + + if ((datasize = bfd_section_size (abfd, section)) == 0) + return; - 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; - } - } - } + printf (_("Contents of section %s:\n"), section->name); - if (syms) - { - free (syms); - syms = NULL; - } + data = xmalloc (datasize); - if (dynsyms) - { - free (dynsyms); - dynsyms = NULL; - } -} + bfd_get_section_contents (abfd, section, data, 0, datasize); -static void -display_bfd (abfd) - bfd *abfd; -{ - char **matching; + /* Compute the address range to display. */ + if (start_address == (bfd_vma) -1 + || start_address < section->vma) + start_offset = 0; + else + start_offset = start_address - section->vma; - if (bfd_check_format_matches (abfd, bfd_object, &matching)) + if (stop_address == (bfd_vma) -1) + stop_offset = datasize / opb; + else { - dump_bfd (abfd); - return; - } + if (stop_address < section->vma) + stop_offset = 0; + else + stop_offset = stop_address - section->vma; - if (bfd_get_error () == bfd_error_file_ambiguously_recognized) - { - nonfatal (bfd_get_filename (abfd)); - list_matching_formats (matching); - free (matching); - return; + if (stop_offset > datasize / opb) + stop_offset = datasize / opb; } - if (bfd_get_error () != bfd_error_file_not_recognized) - { - nonfatal (bfd_get_filename (abfd)); - return; - } + width = 4; - if (bfd_check_format_matches (abfd, bfd_core, &matching)) - { - dump_bfd (abfd); - return; - } + bfd_sprintf_vma (abfd, buf, start_offset + section->vma); + if (strlen (buf) >= sizeof (buf)) + abort (); - nonfatal (bfd_get_filename (abfd)); + count = 0; + while (buf[count] == '0' && buf[count+1] != '\0') + count++; + count = strlen (buf) - count; + if (count > width) + width = count; - if (bfd_get_error () == bfd_error_file_ambiguously_recognized) - { - list_matching_formats (matching); - free (matching); - } -} + bfd_sprintf_vma (abfd, buf, stop_offset + section->vma - 1); + if (strlen (buf) >= sizeof (buf)) + abort (); -static void -display_file (filename, target) - char *filename; - char *target; -{ - bfd *file, *arfile = (bfd *) NULL; + count = 0; + while (buf[count] == '0' && buf[count+1] != '\0') + count++; + count = strlen (buf) - count; + if (count > width) + width = count; - file = bfd_openr (filename, target); - if (file == NULL) + for (addr_offset = start_offset; + addr_offset < stop_offset; addr_offset += onaline / opb) { - nonfatal (filename); - return; - } + bfd_size_type j; - if (bfd_check_format (file, bfd_archive)) - { - bfd *last_arfile = NULL; + bfd_sprintf_vma (abfd, buf, (addr_offset + section->vma)); + count = strlen (buf); + if ((size_t) count >= sizeof (buf)) + abort (); - printf (_("In archive %s:\n"), bfd_get_filename (file)); - for (;;) + putchar (' '); + while (count < width) { - bfd_set_error (bfd_error_no_error); - - arfile = bfd_openr_next_archived_file (file, arfile); - if (arfile == NULL) - { - if (bfd_get_error () != bfd_error_no_more_archived_files) - nonfatal (bfd_get_filename (file)); - break; - } - - display_bfd (arfile); + putchar ('0'); + count++; + } + fputs (buf + count - width, stdout); + putchar (' '); - if (last_arfile != NULL) - bfd_close (last_arfile); - last_arfile = arfile; + for (j = addr_offset * opb; + j < addr_offset * opb + onaline; j++) + { + if (j < stop_offset * opb) + printf ("%02x", (unsigned) (data[j])); + else + printf (" "); + if ((j & 3) == 3) + printf (" "); } - if (last_arfile != NULL) - bfd_close (last_arfile); + printf (" "); + for (j = addr_offset * opb; + j < addr_offset * opb + onaline; j++) + { + if (j >= stop_offset * opb) + printf (" "); + else + printf ("%c", ISPRINT (data[j]) ? data[j] : '.'); + } + putchar ('\n'); } - else - display_bfd (file); - - bfd_close (file); + free (data); } - + /* Actually display the various requested regions. */ static void -dump_data (abfd) - bfd *abfd; +dump_data (bfd *abfd) { - asection *section; - bfd_byte *data = 0; - bfd_size_type datasize = 0; - 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) - { - int onaline = 16; - - if (only == (char *) NULL || - strcmp (only, section->name) == 0) - { - if (section->flags & SEC_HAS_CONTENTS) - { - printf (_("Contents of section %s:\n"), section->name); - - if (bfd_section_size (abfd, section) == 0) - continue; - data = (bfd_byte *) xmalloc ((size_t) bfd_section_size (abfd, section)); - datasize = bfd_section_size (abfd, section); - - - bfd_get_section_contents (abfd, section, (PTR) data, 0, bfd_section_size (abfd, section)); - - 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 / opb) - { - bfd_size_type j; - - printf (" %04lx ", (unsigned long int) - (addr_offset + section->vma)); - for (j = addr_offset * opb; - j < addr_offset * opb + onaline; j++) - { - if (j < stop_offset * opb) - printf ("%02x", (unsigned) (data[j])); - else - printf (" "); - if ((j & 3) == 3) - printf (" "); - } - - printf (" "); - for (j = addr_offset * opb; - j < addr_offset * opb + onaline; j++) - { - if (j >= stop_offset * opb) - printf (" "); - else - printf ("%c", ISPRINT (data[j]) ? data[j] : '.'); - } - putchar ('\n'); - } - free (data); - } - } - } + bfd_map_over_sections (abfd, dump_section, NULL); } /* Should perhaps share code and display with nm? */ static void -dump_symbols (abfd, dynamic) - bfd *abfd ATTRIBUTE_UNUSED; - bfd_boolean dynamic; +dump_symbols (bfd *abfd ATTRIBUTE_UNUSED, bfd_boolean dynamic) { asymbol **current; long max; @@ -2317,140 +2493,48 @@ dump_symbols (abfd, dynamic) for (count = 0; count < max; count++) { - if (*current) + bfd *cur_bfd; + + if (*current == NULL) + printf (_("no information for symbol number %ld\n"), count); + + else if ((cur_bfd = bfd_asymbol_bfd (*current)) == NULL) + printf (_("could not determine the type of symbol number %ld\n"), + count); + + else if (process_section_p ((* current)->section) + && (dump_special_syms + || !bfd_is_target_special_symbol (cur_bfd, *current))) { - bfd *cur_bfd = bfd_asymbol_bfd (*current); + const char *name = (*current)->name; - if (cur_bfd != NULL) + if (do_demangle && name != NULL && *name != '\0') { - const char *name; char *alloc; - name = (*current)->name; - alloc = NULL; - if (do_demangle && name != NULL && *name != '\0') - { - /* If we want to demangle the name, we demangle it - here, and temporarily clobber it while calling - bfd_print_symbol. FIXME: This is a gross hack. */ - alloc = demangle (cur_bfd, name); - (*current)->name = alloc; - } - + /* If we want to demangle the name, we demangle it + here, and temporarily clobber it while calling + bfd_print_symbol. FIXME: This is a gross hack. */ + alloc = demangle (cur_bfd, name); + (*current)->name = alloc; bfd_print_symbol (cur_bfd, stdout, *current, bfd_print_symbol_all); - (*current)->name = name; - if (alloc != NULL) - free (alloc); - - printf ("\n"); + free (alloc); } - } - current++; - } - printf ("\n"); - printf ("\n"); -} - -static void -dump_relocs (abfd) - bfd *abfd; -{ - arelent **relpp; - long relcount; - asection *a; - - for (a = abfd->sections; a != (asection *) NULL; a = a->next) - { - long relsize; - - if (bfd_is_abs_section (a)) - continue; - if (bfd_is_und_section (a)) - continue; - if (bfd_is_com_section (a)) - continue; - - if (only) - { - if (strcmp (only, a->name)) - continue; - } - 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 (relsize == 0) - { - printf (" (none)\n\n"); - } - else - { - relpp = (arelent **) xmalloc (relsize); - relcount = bfd_canonicalize_reloc (abfd, a, relpp, syms); - - if (relcount < 0) - bfd_fatal (bfd_get_filename (abfd)); - else if (relcount == 0) - printf (" (none)\n\n"); else - { - printf ("\n"); - dump_reloc_set (abfd, a, relpp, relcount); - printf ("\n\n"); - } - free (relpp); - } - } -} - -static void -dump_dynamic_relocs (abfd) - bfd *abfd; -{ - long relsize; - arelent **relpp; - long relcount; - - 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 - { + bfd_print_symbol (cur_bfd, stdout, *current, + bfd_print_symbol_all); printf ("\n"); - dump_reloc_set (abfd, (asection *) NULL, relpp, relcount); - printf ("\n\n"); } - free (relpp); + + current++; } + printf ("\n\n"); } - + static void -dump_reloc_set (abfd, sec, relpp, relcount) - bfd *abfd; - asection *sec; - arelent **relpp; - long relcount; +dump_reloc_set (bfd *abfd, asection *sec, arelent **relpp, long relcount) { arelent **p; char *last_filename, *last_functionname; @@ -2463,6 +2547,7 @@ dump_reloc_set (abfd, sec, relpp, relcount) if (width == 0) { char buf[30]; + bfd_sprintf_vma (abfd, buf, (bfd_vma) -1); width = strlen (buf) - 7; } @@ -2473,7 +2558,7 @@ dump_reloc_set (abfd, sec, relpp, relcount) last_functionname = NULL; last_line = 0; - for (p = relpp; relcount && *p != (arelent *) NULL; p++, relcount--) + for (p = relpp; relcount && *p != NULL; p++, relcount--) { arelent *q = *p; const char *filename, *functionname; @@ -2531,24 +2616,20 @@ dump_reloc_set (abfd, sec, relpp, relcount) section_name = NULL; } + bfd_printf_vma (abfd, q->address); + if (q->howto == NULL) + printf (" *unknown* "); + else if (q->howto->name) + printf (" %-16s ", q->howto->name); + else + printf (" %-16d ", q->howto->type); if (sym_name) - { - bfd_printf_vma (abfd, 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); - } + objdump_print_symname (abfd, NULL, *q->sym_ptr_ptr); else { - if (section_name == (const char *) NULL) + if (section_name == NULL) section_name = "*unknown*"; - bfd_printf_vma (abfd, q->address); - printf (" %-16s [%s]", - q->howto->name, - section_name); + printf ("[%s]", section_name); } if (q->addend) @@ -2560,24 +2641,331 @@ dump_reloc_set (abfd, sec, relpp, relcount) printf ("\n"); } } - -int main PARAMS ((int, char **)); +static void +dump_relocs_in_section (bfd *abfd, + asection *section, + void *dummy ATTRIBUTE_UNUSED) +{ + arelent **relpp; + long relcount; + long relsize; + + if ( bfd_is_abs_section (section) + || bfd_is_und_section (section) + || bfd_is_com_section (section) + || (! process_section_p (section)) + || ((section->flags & SEC_RELOC) == 0)) + return; + + relsize = bfd_get_reloc_upper_bound (abfd, section); + if (relsize < 0) + bfd_fatal (bfd_get_filename (abfd)); + + printf ("RELOCATION RECORDS FOR [%s]:", section->name); + + if (relsize == 0) + { + printf (" (none)\n\n"); + return; + } + + relpp = xmalloc (relsize); + relcount = bfd_canonicalize_reloc (abfd, section, relpp, syms); + + if (relcount < 0) + bfd_fatal (bfd_get_filename (abfd)); + else if (relcount == 0) + printf (" (none)\n\n"); + else + { + printf ("\n"); + dump_reloc_set (abfd, section, relpp, relcount); + printf ("\n\n"); + } + free (relpp); +} + +static void +dump_relocs (bfd *abfd) +{ + bfd_map_over_sections (abfd, dump_relocs_in_section, NULL); +} + +static void +dump_dynamic_relocs (bfd *abfd) +{ + long relsize; + arelent **relpp; + long relcount; + + 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 = 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, NULL, relpp, relcount); + printf ("\n\n"); + } + free (relpp); + } +} + +/* Creates a table of paths, to search for source files. */ + +static void +add_include_path (const char *path) +{ + if (path[0] == 0) + return; + include_path_count++; + include_paths = xrealloc (include_paths, + include_path_count * sizeof (*include_paths)); +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + if (path[1] == ':' && path[2] == 0) + path = concat (path, ".", (const char *) 0); +#endif + include_paths[include_path_count - 1] = path; +} + +static void +adjust_addresses (bfd *abfd ATTRIBUTE_UNUSED, + asection *section, + void *arg) +{ + if ((section->flags & SEC_DEBUGGING) == 0) + { + bfd_boolean *has_reloc_p = (bfd_boolean *) arg; + section->vma += adjust_section_vma; + if (*has_reloc_p) + section->lma += adjust_section_vma; + } +} + +/* Dump selected contents of ABFD. */ + +static void +dump_bfd (bfd *abfd) +{ + /* 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) + { + bfd_boolean has_reloc = (abfd->flags & HAS_RELOC); + bfd_map_over_sections (abfd, adjust_addresses, &has_reloc); + } + + if (! dump_debugging_tags) + 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); + if (! dump_debugging_tags) + putchar ('\n'); + if (dump_section_headers) + dump_headers (abfd); + + if (dump_symtab + || dump_reloc_info + || disassemble + || dump_debugging + || dump_dwarf_section_info) + syms = slurp_symtab (abfd); + if (dump_dynamic_symtab || dump_dynamic_reloc_info + || (disassemble && bfd_get_dynamic_symtab_upper_bound (abfd) > 0)) + dynsyms = slurp_dynamic_symtab (abfd); + if (disassemble) + { + synthcount = bfd_get_synthetic_symtab (abfd, symcount, syms, + dynsymcount, dynsyms, &synthsyms); + if (synthcount < 0) + synthcount = 0; + } + + if (dump_symtab) + dump_symbols (abfd, FALSE); + if (dump_dynamic_symtab) + dump_symbols (abfd, TRUE); + if (dump_dwarf_section_info) + dump_dwarf (abfd); + if (dump_stab_section_info) + dump_stabs (abfd); + if (dump_reloc_info && ! disassemble) + dump_relocs (abfd); + if (dump_dynamic_reloc_info && ! disassemble) + dump_dynamic_relocs (abfd); + if (dump_section_contents) + dump_data (abfd); + if (disassemble) + disassemble_data (abfd); + + if (dump_debugging) + { + void *dhandle; + + dhandle = read_debugging_info (abfd, syms, symcount); + if (dhandle != NULL) + { + if (! print_debugging_info (stdout, dhandle, abfd, syms, demangle, + dump_debugging_tags ? TRUE : FALSE)) + { + 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; + } + + if (synthsyms) + { + free (synthsyms); + synthsyms = NULL; + } + + symcount = 0; + dynsymcount = 0; + synthcount = 0; +} + +static void +display_bfd (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 +display_file (char *filename, char *target) +{ + bfd *file; + bfd *arfile = NULL; + + if (get_file_size (filename) < 1) + { + exit_status = 1; + return; + } + + file = bfd_openr (filename, target); + if (file == NULL) + { + nonfatal (filename); + return; + } + + /* If the file is an archive, process all of its elements. */ + if (bfd_check_format (file, bfd_archive)) + { + bfd *last_arfile = NULL; + + printf (_("In archive %s:\n"), bfd_get_filename (file)); + for (;;) + { + bfd_set_error (bfd_error_no_error); + + arfile = bfd_openr_next_archived_file (file, arfile); + if (arfile == NULL) + { + if (bfd_get_error () != bfd_error_no_more_archived_files) + nonfatal (bfd_get_filename (file)); + break; + } + + display_bfd (arfile); + + if (last_arfile != NULL) + bfd_close (last_arfile); + last_arfile = arfile; + } + + if (last_arfile != NULL) + bfd_close (last_arfile); + } + else + display_bfd (file); + + bfd_close (file); +} + int -main (argc, argv) - int argc; - char **argv; +main (int argc, char **argv) { int c; char *target = default_target; bfd_boolean seenflag = FALSE; -#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) +#if defined (HAVE_SETLOCALE) +#if defined (HAVE_LC_MESSAGES) setlocale (LC_MESSAGES, ""); #endif -#if defined (HAVE_SETLOCALE) setlocale (LC_CTYPE, ""); #endif + bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); @@ -2586,10 +2974,12 @@ main (argc, argv) START_PROGRESS (program_name, 0); + expandargv (&argc, &argv); + bfd_init (); set_default_bfd_target (); - while ((c = getopt_long (argc, argv, "pib:m:M:VvCdDlfaHhrRtTxsSj:wE:zgG", + while ((c = getopt_long (argc, argv, "pib:m:M:VvCdDlfaHhrRtTxsSI:j:wE:zgeGW", long_options, (int *) 0)) != EOF) { @@ -2601,10 +2991,20 @@ main (argc, argv) machine = optarg; break; case 'M': - disassembler_options = optarg; + if (disassembler_options) + /* Ignore potential memory leak for now. */ + disassembler_options = concat (disassembler_options, ",", + optarg, NULL); + else + disassembler_options = optarg; break; case 'j': - only = optarg; + if (only_used == only_size) + { + only_size += 8; + only = xrealloc (only, only_size * sizeof (char *)); + } + only [only_used++] = optarg; break; case 'l': with_line_numbers = TRUE; @@ -2669,6 +3069,9 @@ main (argc, argv) formats_info = TRUE; seenflag = TRUE; break; + case 'I': + add_include_path (optarg); + break; case 'p': dump_private_headers = TRUE; seenflag = TRUE; @@ -2711,6 +3114,26 @@ main (argc, argv) dump_debugging = 1; seenflag = TRUE; break; + case 'e': + dump_debugging = 1; + dump_debugging_tags = 1; + do_demangle = TRUE; + seenflag = TRUE; + break; + case 'W': + dump_dwarf_section_info = TRUE; + seenflag = TRUE; + do_debug_info = 1; + do_debug_abbrevs = 1; + do_debug_lines = 1; + do_debug_pubnames = 1; + do_debug_aranges = 1; + do_debug_ranges = 1; + do_debug_frames = 1; + do_debug_macinfo = 1; + do_debug_str = 1; + do_debug_loc = 1; + break; case 'G': dump_stab_section_info = TRUE; seenflag = TRUE;