X-Git-Url: https://repo.jachan.dev/binutils.git/blobdiff_plain/458bbd1f1e586aa857df7cd61cd7b7fd09b96f98..0bff3f4bb6e2ad90568897c3a233919f9b6bf51a:/binutils/objdump.c diff --git a/binutils/objdump.c b/binutils/objdump.c index 3279eb72c2..71bb65f081 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, 1995, 1996 Free Software Foundation, Inc. + Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 98, 1999 + Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -24,44 +25,56 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #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" #ifdef NEED_DECLARATION_FPRINTF /* This is needed by INIT_DISASSEMBLE_INFO. */ -extern int fprintf (); +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_dynamic_symtab; /* -T */ -int dump_reloc_info; /* -r */ -int dump_dynamic_reloc_info; /* -R */ -int dump_ar_hdrs; /* -a */ -int dump_private_headers; /* -p */ -int with_line_numbers; /* -l */ -boolean with_source_code; /* -S */ -int show_raw_insn; /* --show-raw-insn */ -int dump_stab_section_info; /* --stabs */ -boolean disassemble; /* -d */ -boolean disassemble_all; /* -D */ -boolean formats_info; /* -i */ -char *only; /* -j secname */ -int wide_output; /* -w */ -bfd_vma start_address = (bfd_vma) -1; /* --start-address */ -bfd_vma stop_address = (bfd_vma) -1; /* --stop-address */ -int dump_debugging; /* --debugging */ +/* 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 */ /* Extra info to pass to the disassembler address printing function. */ struct objdump_disasm_info { @@ -71,31 +84,49 @@ struct objdump_disasm_info { }; /* Architecture to disassemble for, or default if NULL. */ -char *machine = (char *) NULL; +static char *machine = (char *) NULL; + +/* 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; /* The symbol table. */ -asymbol **syms; +static asymbol **syms; /* Number of symbols in `syms'. */ -long symcount = 0; +static long symcount = 0; /* The sorted symbol table. */ -asymbol **sorted_syms; +static asymbol **sorted_syms; /* Number of symbols in `sorted_syms'. */ -long sorted_symcount = 0; +static long sorted_symcount = 0; /* The dynamic symbol table. */ -asymbol **dynsyms; +static asymbol **dynsyms; /* Number of symbols in `dynsyms'. */ -long dynsymcount = 0; +static long dynsymcount = 0; -/* Forward declarations. */ +/* Static declarations. */ + +static void +usage PARAMS ((FILE *, int)); + +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)); @@ -106,16 +137,47 @@ static void dump_dynamic_relocs PARAMS ((bfd * abfd)); static void -dump_reloc_set PARAMS ((bfd *, arelent **, long)); +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 -objdump_print_value PARAMS ((bfd_vma, FILE *)); +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 *)); @@ -123,53 +185,99 @@ 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 [-ahifdDprRtTxsSlw] [-b bfdname] [-m machine] [-j section-name]\n\ + fprintf (stream, _("\ +Usage: %s [-ahifCdDprRtTxsSlw] [-b bfdname] [-m machine] \n\ + [-j section-name] [-M disassembler-options]\n\ [--archive-headers] [--target=bfdname] [--debugging] [--disassemble]\n\ - [--disassemble-all] [--file-headers] [--section-headers] [--headers]\n\ - [--info] [--section=section-name] [--line-numbers] [--source]\n", + [--disassemble-all] [--disassemble-zeroes] [--file-headers]\n\ + [--section-headers] [--headers]\n\ + [--info] [--section=section-name] [--line-numbers] [--source]\n"), program_name); - fprintf (stream, "\ + fprintf (stream, _("\ [--architecture=machine] [--reloc] [--full-contents] [--stabs]\n\ [--syms] [--all-headers] [--dynamic-syms] [--dynamic-reloc]\n\ [--wide] [--version] [--help] [--private-headers]\n\ [--start-address=addr] [--stop-address=addr]\n\ - [--show-raw-insn] objfile...\n\ -at least one option besides -l (--line-numbers) must be given\n"); + [--prefix-addresses] [--[no-]show-raw-insn] [--demangle]\n\ + [--adjust-vma=offset] [-EB|-EL] [--endian={big|little}] objfile...\n\ +at least one option besides -l (--line-numbers) must be given\n")); list_supported_targets (program_name, stream); + if (status == 0) + fprintf (stream, _("Report bugs to bug-gnu-utils@gnu.org\n")); exit (status); } /* 150 isn't special; it's just an arbitrary non-ASCII char value. */ -#define OPTION_START_ADDRESS (150) +#define OPTION_ENDIAN (150) +#define OPTION_START_ADDRESS (OPTION_ENDIAN + 1) #define OPTION_STOP_ADDRESS (OPTION_START_ADDRESS + 1) +#define OPTION_ADJUST_VMA (OPTION_STOP_ADDRESS + 1) static struct option long_options[]= { + {"adjust-vma", required_argument, NULL, OPTION_ADJUST_VMA}, {"all-headers", no_argument, NULL, 'x'}, {"private-headers", no_argument, NULL, 'p'}, {"architecture", required_argument, NULL, 'm'}, {"archive-headers", no_argument, NULL, 'a'}, {"debugging", no_argument, &dump_debugging, 1}, + {"demangle", no_argument, &do_demangle, 1}, {"disassemble", no_argument, NULL, 'd'}, {"disassemble-all", no_argument, NULL, 'D'}, + {"disassembler-options", required_argument, NULL, 'M'}, + {"disassemble-zeroes", no_argument, &disassemble_zeroes, 1}, {"dynamic-reloc", no_argument, NULL, 'R'}, {"dynamic-syms", no_argument, NULL, 'T'}, + {"endian", required_argument, NULL, OPTION_ENDIAN}, {"file-headers", no_argument, NULL, 'f'}, {"full-contents", no_argument, NULL, 's'}, {"headers", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'H'}, {"info", no_argument, NULL, 'i'}, {"line-numbers", no_argument, NULL, 'l'}, + {"no-show-raw-insn", no_argument, &show_raw_insn, -1}, + {"prefix-addresses", no_argument, &prefix_addresses, 1}, {"reloc", no_argument, NULL, 'r'}, {"section", required_argument, NULL, 'j'}, {"section-headers", no_argument, NULL, 'h'}, @@ -186,27 +294,37 @@ static struct option long_options[]= }; 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 ("%3d %-13s %08lx ", section->index, + bfd_get_section_name (abfd, section), + (unsigned long) bfd_section_size (abfd, section)); + printf_vma (bfd_get_section_vma (abfd, section)); + printf (" "); + printf_vma (section->lma); + printf (" %08lx 2**%u", section->filepos, + bfd_get_section_alignment (abfd, section)); + if (! wide_output) + printf ("\n "); + printf (" "); +#define PF(x, y) \ + if (section->flags & x) { printf ("%s%s", comma, y); comma = ", "; } - 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 (" lma "); - printf_vma (section->lma); - printf (" align 2**%u%s ", - section->alignment_power, (wide_output) ? "" : "\n"); + PF (SEC_HAS_CONTENTS, "CONTENTS"); PF (SEC_ALLOC, "ALLOC"); PF (SEC_CONSTRUCTOR, "CONSTRUCTOR"); PF (SEC_CONSTRUCTOR_TEXT, "CONSTRUCTOR TEXT"); @@ -224,7 +342,40 @@ dump_section_header (abfd, section, ignored) PF (SEC_DEBUGGING, "DEBUGGING"); PF (SEC_NEVER_LOAD, "NEVER_LOAD"); PF (SEC_EXCLUDE, "EXCLUDE"); - PF (SEC_SORT_ENTRIES, "SORT ENTRIES"); + PF (SEC_SORT_ENTRIES, "SORT_ENTRIES"); + 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 } @@ -233,6 +384,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); } @@ -245,7 +408,7 @@ slurp_symtab (abfd) if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) { - printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd)); + fprintf (stderr, _("%s: no symbols\n"), bfd_get_filename (abfd)); symcount = 0; return NULL; } @@ -262,8 +425,7 @@ slurp_symtab (abfd) if (symcount < 0) bfd_fatal (bfd_get_filename (abfd)); if (symcount == 0) - fprintf (stderr, "%s: %s: No symbols\n", - program_name, bfd_get_filename (abfd)); + fprintf (stderr, _("%s: no symbols\n"), bfd_get_filename (abfd)); return sy; } @@ -281,7 +443,7 @@ slurp_dynamic_symtab (abfd) { if (!(bfd_get_file_flags (abfd) & DYNAMIC)) { - fprintf (stderr, "%s: %s: not a dynamic object\n", + fprintf (stderr, _("%s: %s: not a dynamic object\n"), program_name, bfd_get_filename (abfd)); dynsymcount = 0; return NULL; @@ -298,7 +460,7 @@ slurp_dynamic_symtab (abfd) if (dynsymcount < 0) bfd_fatal (bfd_get_filename (abfd)); if (dynsymcount == 0) - fprintf (stderr, "%s: %s: No dynamic symbols\n", + fprintf (stderr, _("%s: %s: No dynamic symbols\n"), program_name, bfd_get_filename (abfd)); return sy; } @@ -307,7 +469,7 @@ slurp_dynamic_symtab (abfd) COUNT is the number of elements in SYMBOLS. Return the number of useful symbols. */ -long +static long remove_useless_symbols (symbols, count) asymbol **symbols; long count; @@ -392,8 +554,8 @@ compare_symbols (ap, bp) if (! af && bf) return -1; - /* Finally, try to sort global symbols before local symbols before - debugging symbols. */ + /* Try to sort global symbols before local symbols before function + symbols before debugging symbols. */ aflags = a->flags; bflags = b->flags; @@ -405,6 +567,13 @@ compare_symbols (ap, bp) 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) @@ -412,8 +581,24 @@ compare_symbols (ap, bp) 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; - return 0; + /* 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); } /* Sort relocs into address order. */ @@ -441,28 +626,80 @@ compare_relocs (ap, bp) return 0; } -/* Print VMA to STREAM with no leading zeroes. */ +/* Print VMA to STREAM. If SKIP_ZEROES is true, omit leading zeroes. */ static void -objdump_print_value (vma, stream) +objdump_print_value (vma, info, skip_zeroes) bfd_vma vma; - FILE *stream; + struct disassemble_info *info; + boolean skip_zeroes; { char buf[30]; char *p; sprintf_vma (buf, vma); - for (p = buf; *p == '0'; ++p) - ; - fprintf (stream, "%s", p); + if (! skip_zeroes) + p = buf; + else + { + for (p = buf; *p == '0'; ++p) + ; + if (*p == '\0') + --p; + } + (*info->fprintf_func) (info->stream, "%s", p); } -/* Print VMA symbolically to INFO if possible. */ +/* Print the name of a symbol. */ static void -objdump_print_address (vma, info) - bfd_vma vma; +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; { /* @@ Would it speed things up to cache the last two symbols returned, and maybe their address ranges? For many processors, only one memory @@ -474,10 +711,8 @@ objdump_print_address (vma, info) long max = sorted_symcount; long thisplace; - fprintf_vma (info->stream, vma); - if (sorted_symcount < 1) - return; + return NULL; /* Perform a binary search looking for the closest symbol to the required value. We are searching the range (min, max]. */ @@ -508,102 +743,182 @@ objdump_print_address (vma, info) == 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. + /* 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; - long i; - - aux = (struct objdump_disasm_info *) info->application_data; - if (sorted_syms[thisplace]->section != aux->sec - && (aux->require_sec - || ((aux->abfd->flags & HAS_RELOC) != 0 - && vma >= bfd_get_section_vma (aux->abfd, aux->sec) - && vma < (bfd_get_section_vma (aux->abfd, aux->sec) - + bfd_section_size (aux->abfd, aux->sec))))) - { - for (i = thisplace + 1; i < sorted_symcount; i++) - { - if (bfd_asymbol_value (sorted_syms[i]) - != bfd_asymbol_value (sorted_syms[thisplace])) + 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))))) + { + long i; + + for (i = thisplace + 1; i < sorted_symcount; i++) + { + if (bfd_asymbol_value (sorted_syms[i]) + != bfd_asymbol_value (sorted_syms[thisplace])) + break; + } + --i; + for (; i >= 0; i--) + { + 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; - } - --i; - for (; i >= 0; i--) - { - if (sorted_syms[i]->section == aux->sec - && (i == 0 - || sorted_syms[i - 1]->section != aux->sec - || (bfd_asymbol_value (sorted_syms[i]) - != bfd_asymbol_value (sorted_syms[i - 1])))) - { - thisplace = i; - break; - } - } + } + } - if (sorted_syms[thisplace]->section != aux->sec) - { - /* We didn't find a good symbol with a smaller value. - Look for one with a larger value. */ - for (i = thisplace + 1; i < sorted_symcount; i++) - { - if (sorted_syms[i]->section == aux->sec) - { - thisplace = i; - break; - } - } - } + if (sorted_syms[thisplace]->section != sec) + { + /* We didn't find a good symbol with a smaller value. + Look for one with a larger value. */ + for (i = thisplace + 1; i < sorted_symcount; i++) + { + if (sorted_syms[i]->section == sec) + { + thisplace = i; + break; + } + } + } - if (sorted_syms[thisplace]->section != aux->sec - && (aux->require_sec - || ((aux->abfd->flags & HAS_RELOC) != 0 - && vma >= bfd_get_section_vma (aux->abfd, aux->sec) - && vma < (bfd_get_section_vma (aux->abfd, aux->sec) - + bfd_section_size (aux->abfd, aux->sec))))) - { - bfd_vma secaddr; + 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, " <%s", - bfd_get_section_name (aux->abfd, aux->sec)); - secaddr = bfd_get_section_vma (aux->abfd, aux->sec); - if (vma < secaddr) - { - fprintf (info->stream, "-"); - objdump_print_value (secaddr - vma, info->stream); - } - else if (vma > secaddr) - { - fprintf (info->stream, "+"); - objdump_print_value (vma - secaddr, info->stream); - } - fprintf (info->stream, ">"); - return; - } - } - } + if (place != NULL) + *place = thisplace; - fprintf (info->stream, " <%s", sorted_syms[thisplace]->name); - if (bfd_asymbol_value (sorted_syms[thisplace]) > vma) + return sorted_syms[thisplace]; +} + +/* Print an address to INFO symbolically. */ + +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; +{ + objdump_print_value (vma, info, skip_zeroes); + + if (sym == NULL) { - fprintf (info->stream, "-"); - objdump_print_value (bfd_asymbol_value (sorted_syms[thisplace]) - vma, - info->stream); + bfd_vma secaddr; + + (*info->fprintf_func) (info->stream, " <%s", + bfd_get_section_name (abfd, sec)); + secaddr = bfd_get_section_vma (abfd, sec); + if (vma < secaddr) + { + (*info->fprintf_func) (info->stream, "-0x"); + objdump_print_value (secaddr - vma, info, true); + } + else if (vma > secaddr) + { + (*info->fprintf_func) (info->stream, "+0x"); + objdump_print_value (vma - secaddr, info, true); + } + (*info->fprintf_func) (info->stream, ">"); } - else if (vma > bfd_asymbol_value (sorted_syms[thisplace])) + else { - fprintf (info->stream, "+"); - objdump_print_value (vma - bfd_asymbol_value (sorted_syms[thisplace]), - info->stream); + (*info->fprintf_func) (info->stream, " <"); + objdump_print_symname (abfd, info, sym); + if (bfd_asymbol_value (sym) > vma) + { + (*info->fprintf_func) (info->stream, "-0x"); + objdump_print_value (bfd_asymbol_value (sym) - vma, info, true); + } + else if (vma > bfd_asymbol_value (sym)) + { + (*info->fprintf_func) (info->stream, "+0x"); + objdump_print_value (vma - bfd_asymbol_value (sym), info, true); + } + (*info->fprintf_func) (info->stream, ">"); } - fprintf (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 @@ -805,16 +1120,425 @@ show_line (abfd, section, off) prev_line = line; } -void +/* 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 +{ +#ifndef ANSI_PROTOTYPES + SFILE *f; + const char *format; +#endif + 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 + + vasprintf (&buf, format, args); + + va_end (args); + + if (buf == NULL) + { + fprintf (stderr, _("Out of virtual memory\n")); + exit (1); + } + + n = strlen (buf); + + while ((size_t) ((f->buffer + f->size) - f->current) < n + 1) + { + 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, stop, relppp, + relppend) + struct disassemble_info *info; + disassembler_ftype disassemble_fn; + boolean insns; + bfd_byte *data; + bfd_vma start; + bfd_vma stop; + arelent ***relppp; + arelent **relppend; +{ + struct objdump_disasm_info *aux; + asection *section; + int bytes_per_line; + boolean done_dot; + int skip_addr_chars; + bfd_vma i; + + aux = (struct objdump_disasm_info *) info->application_data; + section = aux->sec; + + if (insns) + bytes_per_line = 4; + else + bytes_per_line = 16; + + /* Figure out how many characters to skip at the start of an + address, to make the disassembly look nicer. We discard leading + zeroes in chunks of 4, ensuring that there is always a leading + zero remaining. */ + skip_addr_chars = 0; + if (! prefix_addresses) + { + char buf[30]; + char *s; + + sprintf_vma (buf, + section->vma + bfd_section_size (section->owner, section)); + s = buf; + while (s[0] == '0' && s[1] == '0' && s[2] == '0' && s[3] == '0' + && s[4] == '0') + { + skip_addr_chars += 4; + s += 4; + } + } + + info->insn_info_valid = 0; + + done_dot = false; + i = start; + while (i < stop) + { + bfd_vma z; + int bytes = 0; + boolean need_nl = false; + + /* If we see more than SKIP_ZEROES bytes of zeroes, we just + print `...'. */ + for (z = i; z < stop; z++) + if (data[z] != 0) + break; + if (! disassemble_zeroes + && (info->insn_info_valid == 0 + || info->branch_delay_insns == 0) + && (z - i >= SKIP_ZEROES + || (z == stop && z - i < SKIP_ZEROES_AT_END))) + { + printf ("\t...\n"); + + /* If there are more nonzero bytes to follow, we only skip + zeroes in multiples of 4, to try to avoid running over + the start of an instruction which happens to start with + zero. */ + if (z != stop) + z = i + ((z - i) &~ 3); + + bytes = z - i; + } + 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, i); + + if (! prefix_addresses) + { + char *s; + + sprintf_vma (buf, section->vma + i); + for (s = buf + skip_addr_chars; *s == '0'; s++) + *s = ' '; + if (*s == '\0') + *--s = '0'; + printf ("%s:\t", buf + skip_addr_chars); + } + else + { + aux->require_sec = true; + objdump_print_address (section->vma + i, info); + aux->require_sec = false; + putchar (' '); + } + + if (insns) + { + sfile.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 bytes + in the last instruction, not the current one. */ + if (*relppp < relppend + && (**relppp)->address >= i + && (**relppp)->address < i + bytes) + info->flags = INSN_HAS_RELOC; + else + info->flags = 0; + + bytes = (*disassemble_fn) (section->vma + i, info); + info->fprintf_func = (fprintf_ftype) fprintf; + info->stream = stdout; + if (info->bytes_per_line != 0) + bytes_per_line = info->bytes_per_line; + if (bytes < 0) + { + if (sfile.current != sfile.buffer) + printf ("%s\n", sfile.buffer); + free (sfile.buffer); + break; + } + } + else + { + bfd_vma j; + + bytes = bytes_per_line; + if (i + bytes > stop) + bytes = stop - i; + + for (j = i; j < i + bytes; ++j) + { + if (isprint (data[j])) + buf[j - i] = data[j]; + else + buf[j - i] = '.'; + } + buf[j - i] = '\0'; + } + + if (prefix_addresses + ? show_raw_insn > 0 + : show_raw_insn >= 0) + { + bfd_vma j; + + /* If ! prefix_addresses and ! wide_output, we print + bytes_per_line bytes per line. */ + pb = bytes; + if (pb > bytes_per_line && ! prefix_addresses && ! wide_output) + pb = bytes_per_line; + + if (info->bytes_per_chunk) + bpc = info->bytes_per_chunk; + else + bpc = 1; + + for (j = i; j < i + pb; j += bpc) + { + int k; + if (bpc > 1 && info->display_endian == BFD_ENDIAN_LITTLE) + { + for (k = bpc - 1; k >= 0; k--) + printf ("%02x", (unsigned) data[j + k]); + putchar (' '); + } + else + { + for (k = 0; k < bpc; k++) + printf ("%02x", (unsigned) data[j + k]); + putchar (' '); + } + } + + for (; pb < bytes_per_line; pb += bpc) + { + int k; + + for (k = 0; k < bpc; k++) + printf (" "); + putchar (' '); + } + + /* Separate raw data from instruction by extra space. */ + if (insns) + putchar ('\t'); + else + printf (" "); + } + + 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 < bytes) + { + bfd_vma j; + char *s; + + putchar ('\n'); + j = i + pb; + + sprintf_vma (buf, section->vma + j); + for (s = buf + skip_addr_chars; *s == '0'; s++) + *s = ' '; + if (*s == '\0') + *--s = '0'; + printf ("%s:\t", buf + skip_addr_chars); + + pb += bytes_per_line; + if (pb > bytes) + pb = bytes; + for (; j < i + pb; j += bpc) + { + 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 + { + for (k = 0; k < bpc; k++) + printf ("%02x", (unsigned) data[j + k]); + putchar (' '); + } + } + } + } + + if (!wide_output) + putchar ('\n'); + else + need_nl = true; + } + + if (dump_reloc_info + && (section->flags & SEC_RELOC) != 0) + { + while ((*relppp) < relppend + && ((**relppp)->address >= (bfd_vma) i + && (**relppp)->address < (bfd_vma) i + bytes)) + { + arelent *q; + + q = **relppp; + + if (wide_output) + putchar ('\t'); + else + printf ("\t\t\t"); + + objdump_print_value (section->vma + q->address, info, true); + + printf (": %s\t", q->howto->name); + + if (q->sym_ptr_ptr == NULL || *q->sym_ptr_ptr == NULL) + printf ("*unknown*"); + else + { + const char *sym_name; + + 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; + + 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); + } + } + + if (need_nl) + printf ("\n"); + + i += bytes; + } +} + +/* Disassemble the contents of an object file. */ + +static void disassemble_data (abfd) bfd *abfd; { long i; - disassembler_ftype disassemble_fn = 0; /* New style */ + disassembler_ftype disassemble_fn; struct disassemble_info disasm_info; struct objdump_disasm_info aux; asection *section; - boolean done_dot = false; print_files = NULL; prev_functionname = NULL; @@ -830,19 +1554,19 @@ disassemble_data (abfd) /* Sort the symbols into section and symbol order */ qsort (sorted_syms, sorted_symcount, sizeof (asymbol *), compare_symbols); - INIT_DISASSEMBLE_INFO(disasm_info, stdout); + 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; - if (show_raw_insn) - disasm_info.flags |= DISASM_RAW_INSN_FLAG; + disasm_info.symbol_at_address_func = objdump_symbol_at_address; if (machine != (char *) NULL) { const bfd_arch_info_type *info = bfd_scan_arch (machine); if (info == NULL) { - fprintf (stderr, "%s: Can't use supplied machine %s\n", + fprintf (stderr, _("%s: Can't use supplied machine %s\n"), program_name, machine); exit (1); @@ -850,21 +1574,39 @@ disassemble_data (abfd) abfd->arch_info = info; } + if (endian != BFD_ENDIAN_UNKNOWN) + { + 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; + } + disassemble_fn = disassembler (abfd); if (!disassemble_fn) { - fprintf (stderr, "%s: Can't disassemble for architecture %s\n", + fprintf (stderr, _("%s: Can't disassemble for architecture %s\n"), program_name, bfd_printable_arch_mach (bfd_get_arch (abfd), 0)); - exit (1); + exit_status = 1; + return; } + 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 (bfd_big_endian (abfd)) - disasm_info.endian = BFD_ENDIAN_BIG; + 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 - disasm_info.endian = BFD_ENDIAN_LITTLE; + /* ??? 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; @@ -876,6 +1618,8 @@ disassemble_data (abfd) arelent **relpp = NULL; arelent **relppend = NULL; long stop; + asymbol *sym = NULL; + long place = 0; if ((section->flags & SEC_LOAD) == 0 || (! disassemble_all @@ -908,10 +1652,19 @@ disassemble_data (abfd) 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); + printf (_("Disassembly of section %s:\n"), section->name); datasize = bfd_get_section_size_before_reloc (section); if (datasize == 0) @@ -941,94 +1694,100 @@ disassemble_data (abfd) if (stop > disasm_info.buffer_length) stop = disasm_info.buffer_length; } + + sym = find_symbol_for_address (abfd, section, section->vma + i, + true, &place); + while (i < stop) { - int bytes; - boolean need_nl = false; + asymbol *nextsym; + long nextstop; + boolean insns; + + if (sym != NULL && bfd_asymbol_value (sym) <= section->vma + i) + { + int x; - if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 && - data[i + 3] == 0) + for (x = place; + (x < sorted_symcount + && bfd_asymbol_value (sorted_syms[x]) <= section->vma + i); + ++x) + continue; + disasm_info.symbols = & sorted_syms[place]; + disasm_info.num_symbols = x - place; + } + else + disasm_info.symbols = NULL; + + if (! prefix_addresses) { - if (done_dot == false) - { - printf ("...\n"); - done_dot = true; - } - bytes = 4; + printf ("\n"); + objdump_print_addr_with_sym (abfd, section, sym, + section->vma + i, + &disasm_info, + false); + printf (":\n"); } + + if (sym != NULL && bfd_asymbol_value (sym) > section->vma + i) + nextsym = sym; + else if (sym == NULL) + nextsym = NULL; else { - done_dot = false; - if (with_line_numbers || with_source_code) - show_line (abfd, section, i); - aux.require_sec = true; - objdump_print_address (section->vma + i, &disasm_info); - aux.require_sec = false; - putchar (' '); - - bytes = (*disassemble_fn) (section->vma + i, &disasm_info); - if (bytes < 0) - break; - - if (!wide_output) - putchar ('\n'); + /* 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 - need_nl = true; + nextsym = sorted_syms[place]; } - - if (dump_reloc_info - && (section->flags & SEC_RELOC) != 0) + + if (sym != NULL && bfd_asymbol_value (sym) > section->vma + i) { - while (relpp < relppend - && ((*relpp)->address >= (bfd_vma) i - && (*relpp)->address < (bfd_vma) i + bytes)) - { - arelent *q; - const char *sym_name; - - q = *relpp; - - printf ("\t\tRELOC: "); - - printf_vma (section->vma + q->address); - - printf (" %s ", q->howto->name); - - if (q->sym_ptr_ptr != NULL - && *q->sym_ptr_ptr != NULL) - { - sym_name = bfd_asymbol_name (*q->sym_ptr_ptr); - if (sym_name == NULL || *sym_name == '\0') - { - asection *sym_sec; - - sym_sec = bfd_get_section (*q->sym_ptr_ptr); - sym_name = bfd_get_section_name (abfd, sym_sec); - if (sym_name == NULL || *sym_name == '\0') - sym_name = "*unknown*"; - } - } - - printf ("%s", sym_name); - - if (q->addend) - { - printf ("+0x"); - printf_vma (q->addend); - } - - printf ("\n"); - need_nl = false; - ++relpp; - } + nextstop = bfd_asymbol_value (sym) - section->vma; + if (nextstop > stop) + nextstop = stop; } - - if (need_nl) - printf ("\n"); - - i += bytes; + else if (nextsym == NULL) + nextstop = stop; + else + { + nextstop = bfd_asymbol_value (nextsym) - section->vma; + if (nextstop > stop) + nextstop = stop; + } + + /* If a symbol is explicitly marked as being an object + rather than a function, just dump the bytes without + disassembling them. */ + if (disassemble_all + || sym == NULL + || bfd_asymbol_value (sym) > section->vma + i + || ((sym->flags & BSF_OBJECT) == 0 + && (strstr (bfd_asymbol_name (sym), "gnu_compiled") + == NULL) + && (strstr (bfd_asymbol_name (sym), "gcc2_compiled") + == NULL)) + || (sym->flags & BSF_FUNCTION) != 0) + insns = true; + else + insns = false; + + disassemble_bytes (&disasm_info, disassemble_fn, insns, data, i, + nextstop, &relpp, relppend); + + i = nextstop; + sym = nextsym; } - + free (data); if (relbuf != NULL) free (relbuf); @@ -1041,52 +1800,23 @@ disassemble_data (abfd) could be a direct-mapped table, but instead we build one the first time we need it. */ -char **stab_name; - -struct stab_print { - int value; - char *string; -}; - -struct stab_print stab_print[] = { -#define __define_stab(NAME, CODE, STRING) {CODE, STRING}, -#include "aout/stab.def" -#undef __define_stab - {0, ""} -}; - -void dump_section_stabs PARAMS ((bfd *abfd, char *stabsect_name, - char *strsect_name)); +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. It has to use some hooks into BFD because - string table sections are not normally visible to BFD callers. */ + uses Sun stabs encoding. */ -void +static void dump_stabs (abfd) bfd *abfd; { - /* Allocate and initialize stab name array if first time. */ - if (stab_name == NULL) - { - int i; - - 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; - } - 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 struct internal_nlist *stabs; +static bfd_byte *stabs; static bfd_size_type stab_size; static char *strtab; @@ -1097,84 +1827,94 @@ static bfd_size_type stabstr_size; If the section exists and was read, allocate the space and return true. Otherwise return false. */ -boolean +static boolean read_section_stabs (abfd, stabsect_name, strsect_name) bfd *abfd; - char *stabsect_name; - char *strsect_name; + 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); + printf (_("No %s section present\n\n"), stabsect_name); return false; } stabstrsect = bfd_get_section_by_name (abfd, strsect_name); if (0 == stabstrsect) { - fprintf (stderr, "%s: %s has no %s section\n", program_name, + fprintf (stderr, _("%s: %s has no %s section\n"), program_name, 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 = (struct internal_nlist *) xmalloc (stab_size); + stabs = (bfd_byte *) xmalloc (stab_size); strtab = (char *) xmalloc (stabstr_size); if (! bfd_get_section_contents (abfd, stabsect, (PTR) stabs, 0, stab_size)) { - fprintf (stderr, "%s: Reading %s section of %s failed: %s\n", + fprintf (stderr, _("%s: Reading %s section of %s failed: %s\n"), program_name, stabsect_name, bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ())); free (stabs); free (strtab); + exit_status = 1; return false; } if (! bfd_get_section_contents (abfd, stabstrsect, (PTR) strtab, 0, stabstr_size)) { - fprintf (stderr, "%s: Reading %s section of %s failed: %s\n", + fprintf (stderr, _("%s: Reading %s section of %s failed: %s\n"), program_name, strsect_name, bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ())); free (stabs); free (strtab); + exit_status = 1; return false; } return true; } -#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); \ -} +/* 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'). */ -void +static void print_section_stabs (abfd, stabsect_name, strsect_name) bfd *abfd; - char *stabsect_name; - char *strsect_name; + const char *stabsect_name; + const char *strsect_name ATTRIBUTE_UNUSED; { int i; unsigned file_string_table_offset = 0, next_file_string_table_offset = 0; - struct internal_nlist *stabp = stabs, - *stabs_end = (struct internal_nlist *) (stab_size + (char *) stabs); + bfd_byte *stabp, *stabs_end; + + stabp = stabs; + stabs_end = stabp + stab_size; - printf ("Contents of %s section:\n\n", stabsect_name); + 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. @@ -1182,38 +1922,50 @@ print_section_stabs (abfd, stabsect_name, strsect_name) We start the index at -1 because there is a dummy symbol on the front of stabs-in-{coff,elf} sections that supplies sizes. */ - for (i = -1; stabp < stabs_end; stabp++, i++) + for (i = -1; stabp < stabs_end; stabp += STABSIZE, i++) { - SWAP_SYMBOL (stabp, 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); /* Either print the stab name, or, if unnamed, print its number again (makes consistent formatting for tools like awk). */ - if (stab_name[stabp->n_type]) - printf ("%-6s", stab_name[stabp->n_type]); - else if (stabp->n_type == N_UNDF) + name = bfd_get_stab_name (type); + if (name != NULL) + printf ("%-6s", name); + else if (type == N_UNDF) printf ("HdrSym"); else - printf ("%-6d", stabp->n_type); - printf (" %-6d %-6d ", stabp->n_other, stabp->n_desc); - printf_vma (stabp->n_value); - printf (" %-6lu", stabp->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 (stabp->n_type == N_UNDF) + if (type == N_UNDF) { file_string_table_offset = next_file_string_table_offset; - next_file_string_table_offset += stabp->n_value; + next_file_string_table_offset += value; } else { /* Using the (possibly updated) string table offset, print the string (if any) associated with this symbol. */ - if ((stabp->n_strx + file_string_table_offset) < stabstr_size) - printf (" %s", &strtab[stabp->n_strx + file_string_table_offset]); + if ((strx + file_string_table_offset) < stabstr_size) + printf (" %s", &strtab[strx + file_string_table_offset]); else printf (" *"); } @@ -1221,7 +1973,7 @@ print_section_stabs (abfd, stabsect_name, strsect_name) printf ("\n\n"); } -void +static void dump_section_stabs (abfd, stabsect_name, strsect_name) bfd *abfd; char *stabsect_name; @@ -1235,8 +1987,16 @@ dump_section_stabs (abfd, stabsect_name, strsect_name) s != NULL; s = s->next) { - if (strncmp (stabsect_name, s->name, strlen (stabsect_name)) == 0 - && strncmp (strsect_name, s->name, strlen (strsect_name)) != 0) + 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)) { @@ -1254,10 +2014,10 @@ dump_bfd_header (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"); @@ -1270,8 +2030,9 @@ 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 @@ -1280,24 +2041,28 @@ bfd *abfd; { 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) { - bfd_nonfatal (bfd_get_filename (abfd)); - if (bfd_get_error () == 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", bfd_get_filename (abfd), + printf (_("\n%s: file format %s\n"), bfd_get_filename (abfd), abfd->xvec->name); if (dump_ar_hdrs) print_arelt_descr (stdout, abfd, true); @@ -1338,8 +2103,12 @@ display_bfd (abfd) if (dhandle != NULL) { if (! print_debugging_info (stdout, dhandle)) - fprintf (stderr, "%s: printing debugging information failed\n", - bfd_get_filename (abfd)); + { + fprintf (stderr, + _("%s: printing debugging information failed\n"), + bfd_get_filename (abfd)); + exit_status = 1; + } } } if (syms) @@ -1354,6 +2123,47 @@ display_bfd (abfd) } } +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 display_file (filename, target) char *filename; @@ -1364,7 +2174,7 @@ display_file (filename, target) file = bfd_openr (filename, target); if (file == NULL) { - bfd_nonfatal (filename); + nonfatal (filename); return; } @@ -1372,7 +2182,7 @@ display_file (filename, target) { bfd *last_arfile = NULL; - printf ("In archive %s:\n", bfd_get_filename (file)); + printf (_("In archive %s:\n"), bfd_get_filename (file)); for (;;) { bfd_set_error (bfd_error_no_error); @@ -1381,9 +2191,7 @@ display_file (filename, target) if (arfile == NULL) { if (bfd_get_error () != bfd_error_no_more_archived_files) - { - bfd_nonfatal (bfd_get_filename (file)); - } + nonfatal (bfd_get_filename (file)); break; } @@ -1425,7 +2233,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; @@ -1485,7 +2293,7 @@ dump_data (abfd) /* Should perhaps share code and display with nm? */ static void dump_symbols (abfd, dynamic) - bfd *abfd; + bfd *abfd ATTRIBUTE_UNUSED; boolean dynamic; { asymbol **current; @@ -1513,12 +2321,40 @@ dump_symbols (abfd, dynamic) { 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"); } } @@ -1578,7 +2414,7 @@ dump_relocs (abfd) else { printf ("\n"); - dump_reloc_set (abfd, relpp, relcount); + dump_reloc_set (abfd, a, relpp, relcount); printf ("\n\n"); } free (relpp); @@ -1617,7 +2453,7 @@ dump_dynamic_relocs (abfd) else { printf ("\n"); - dump_reloc_set (abfd, relpp, relcount); + dump_reloc_set (abfd, (asection *) NULL, relpp, relcount); printf ("\n\n"); } free (relpp); @@ -1625,12 +2461,15 @@ dump_dynamic_relocs (abfd) } static void -dump_reloc_set (abfd, relpp, relcount) +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. */ { @@ -1644,11 +2483,17 @@ dump_reloc_set (abfd, relpp, relcount) 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 *sym_name; - CONST char *section_name; + 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) @@ -1657,6 +2502,37 @@ dump_reloc_set (abfd, relpp, relcount) && 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; @@ -1670,9 +2546,12 @@ dump_reloc_set (abfd, relpp, relcount) if (sym_name) { printf_vma (q->address); - printf (" %-16s %s", - q->howto->name, - sym_name); + 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 { @@ -1695,10 +2574,6 @@ dump_reloc_set (abfd, relpp, relcount) /* The length of the longest architecture name + 1. */ #define LONGEST_ARCH sizeof("rs6000:6000") -#ifndef L_tmpnam -#define L_tmpnam 25 -#endif - static const char * endian_string (endian) enum bfd_endian endian; @@ -1717,13 +2592,11 @@ endian_string (endian) static void display_target_list () { - extern char *tmpnam (); extern bfd_target *bfd_target_vector[]; - char tmparg[L_tmpnam]; char *dummy_name; int t; - dummy_name = tmpnam (tmparg); + dummy_name = choose_temp_base (); for (t = 0; bfd_target_vector[t]; t++) { bfd_target *p = bfd_target_vector[t]; @@ -1736,14 +2609,14 @@ display_target_list () if (abfd == NULL) { - bfd_nonfatal (dummy_name); + nonfatal (dummy_name); continue; } if (! bfd_set_format (abfd, bfd_object)) { if (bfd_get_error () != bfd_error_invalid_operation) - bfd_nonfatal (p->name); + nonfatal (p->name); continue; } @@ -1753,6 +2626,7 @@ display_target_list () 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 @@ -1765,8 +2639,6 @@ display_info_table (first, last) int last; { extern bfd_target *bfd_target_vector[]; - extern char *tmpnam (); - char tmparg[L_tmpnam]; int t, a; char *dummy_name; @@ -1776,7 +2648,7 @@ display_info_table (first, last) printf ("%s ", bfd_target_vector[t]->name); putchar ('\n'); - dummy_name = tmpnam (tmparg); + 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) { @@ -1790,7 +2662,7 @@ display_info_table (first, last) if (abfd == NULL) { - bfd_nonfatal (p->name); + nonfatal (p->name); ok = false; } @@ -1799,7 +2671,7 @@ display_info_table (first, last) if (! bfd_set_format (abfd, bfd_object)) { if (bfd_get_error () != bfd_error_invalid_operation) - bfd_nonfatal (p->name); + nonfatal (p->name); ok = false; } } @@ -1823,6 +2695,7 @@ display_info_table (first, last) putchar ('\n'); } unlink (dummy_name); + free (dummy_name); } /* Print tables of all the target-architecture combinations that @@ -1834,7 +2707,6 @@ display_target_tables () int t, columns; extern bfd_target *bfd_target_vector[]; char *colum; - extern char *getenv (); columns = 0; colum = getenv ("COLUMNS"); @@ -1867,7 +2739,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 (); } @@ -1881,15 +2753,22 @@ main (argc, argv) char *target = default_target; boolean seenflag = false; +#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); bfd_init (); + set_default_bfd_target (); - while ((c = getopt_long (argc, argv, "pib:m:VdDlfahrRtTxsSj:w", long_options, - (int *) 0)) + while ((c = getopt_long (argc, argv, "pib:m:M:VCdDlfahrRtTxsSj:wE:", + long_options, (int *) 0)) != EOF) { if (c != 'l' && c != OPTION_START_ADDRESS && c != OPTION_STOP_ADDRESS) @@ -1901,6 +2780,9 @@ main (argc, argv) case 'm': machine = optarg; break; + case 'M': + disassembler_options = optarg; + break; case 'j': only = optarg; break; @@ -1933,6 +2815,9 @@ main (argc, argv) case 'T': dump_dynamic_symtab = 1; break; + case 'C': + do_demangle = 1; + break; case 'd': disassemble = true; break; @@ -1966,22 +2851,46 @@ main (argc, argv) case 'w': wide_output = 1; break; + case OPTION_ADJUST_VMA: + adjust_section_vma = parse_vma (optarg, "--adjust-vma"); + break; case OPTION_START_ADDRESS: start_address = parse_vma (optarg, "--start-address"); break; case OPTION_STOP_ADDRESS: stop_address = parse_vma (optarg, "--stop-address"); break; + case 'E': + if (strcmp (optarg, "B") == 0) + endian = BFD_ENDIAN_BIG; + else if (strcmp (optarg, "L") == 0) + endian = BFD_ENDIAN_LITTLE; + else + { + fprintf (stderr, _("%s: unrecognized -E option\n"), + program_name); + usage (stderr, 1); + } + break; + case OPTION_ENDIAN: + if (strncmp (optarg, "big", strlen (optarg)) == 0) + endian = BFD_ENDIAN_BIG; + else if (strncmp (optarg, "little", strlen (optarg)) == 0) + endian = BFD_ENDIAN_LITTLE; + else + { + fprintf (stderr, _("%s: unrecognized --endian type `%s'\n"), + program_name, optarg); + usage (stderr, 1); + } + break; default: usage (stderr, 1); } } if (show_version) - { - printf ("GNU %s version %s\n", program_name, program_version); - exit (0); - } + print_version ("objdump"); if (seenflag == false) usage (stderr, 1); @@ -2001,5 +2910,5 @@ main (argc, argv) END_PROGRESS (program_name); - return 0; + return exit_status; }