X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=binutils%2Fobjdump.c;h=f2b5eea01286bb8ee104f551f6bd8578c8dec617;hb=c736ea7144dd2f698bd4a7d57af2a9a3bcb286f3;hp=358d3196122757e27cb2f7b7e16422cf8ee10b44;hpb=92c2346c02b55ad56a1070f625c289e58ddbd740;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/objdump.c b/binutils/objdump.c index 358d319612..f2b5eea012 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 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -17,7 +17,7 @@ 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. @@ -35,16 +35,16 @@ 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 determnined + 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 seperate functions to display the requested - item(s) of infomation(s). For example dissasemble_data() is called if - a disassmebly has been requested. + 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 dissassemble_bytes() on each block. The actual + 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. */ @@ -52,6 +52,7 @@ #include "bfdver.h" #include "progress.h" #include "bucomm.h" +#include "dwarf.h" #include "budemang.h" #include "getopt.h" #include "safe-ctype.h" @@ -65,7 +66,7 @@ #define BYTES_IN_WORD 32 #include "aout/aout64.h" -#ifdef NEED_DECLARATION_FPRINTF +#if !HAVE_DECL_FPRINTF /* This is needed by init_disassemble_info(). */ extern int fprintf (FILE *, const char *, ...); #endif @@ -75,7 +76,8 @@ static int exit_status = 0; static char *default_target = NULL; /* Default at runtime. */ -/* The following variables are set based on arguments passed on command line. */ +/* 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 */ @@ -90,6 +92,7 @@ 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 */ @@ -101,6 +104,7 @@ 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 */ @@ -116,7 +120,8 @@ static size_t only_used = 0; static const char **include_paths; static int include_path_count; -/* Extra info to pass to the section disassembler and address printing function. */ +/* Extra info to pass to the section disassembler and address printing + function. */ struct objdump_disasm_info { bfd * abfd; @@ -125,6 +130,9 @@ struct objdump_disasm_info arelent ** dynrelbuf; long dynrelcount; disassembler_ftype disassemble_fn; +#ifdef DISASSEMBLER_NEEDS_RELOCS + arelent * reloc; +#endif }; /* Architecture to disassemble for, or default if NULL. */ @@ -151,6 +159,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; @@ -179,10 +191,12 @@ usage (FILE *stream, int status) -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\ @@ -211,6 +225,7 @@ usage (FILE *stream, int 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); @@ -262,7 +277,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}, @@ -281,12 +298,17 @@ nonfatal (const char *msg) } static void -dump_section_header (bfd *abfd ATTRIBUTE_UNUSED, asection *section, +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); @@ -315,16 +337,21 @@ dump_section_header (bfd *abfd ATTRIBUTE_UNUSED, asection *section, 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) { @@ -345,9 +372,9 @@ dump_section_header (bfd *abfd ATTRIBUTE_UNUSED, asection *section, } 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 = ", "; } @@ -448,7 +475,7 @@ remove_useless_symbols (asymbol **symbols, long 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)) @@ -600,9 +627,9 @@ objdump_print_value (bfd_vma vma, struct disassemble_info *info, { 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; @@ -643,14 +670,16 @@ objdump_print_symname (bfd *abfd, struct disassemble_info *info, 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 (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 @@ -661,11 +690,19 @@ find_symbol_for_address (bfd *abfd, asection *sec, bfd_vma vma, 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) @@ -704,7 +741,7 @@ find_symbol_for_address (bfd *abfd, asection *sec, bfd_vma vma, 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) @@ -749,15 +786,22 @@ find_symbol_for_address (bfd *abfd, asection *sec, bfd_vma vma, } 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) @@ -816,11 +860,15 @@ objdump_print_addr_with_sym (bfd *abfd, asection *sec, asymbol *sym, If SKIP_ZEROES is TRUE, don't output leading zeroes. */ static void -objdump_print_addr (bfd_vma vma, struct disassemble_info *info, +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. */ +#ifdef DISASSEMBLER_NEEDS_RELOCS + bfd_boolean skip_find = FALSE; +#endif if (sorted_symcount < 1) { @@ -830,8 +878,25 @@ objdump_print_addr (bfd_vma vma, struct disassemble_info *info, } aux = (struct objdump_disasm_info *) info->application_data; - sym = find_symbol_for_address (aux->abfd, aux->sec, vma, aux->require_sec, - NULL); + +#ifdef DISASSEMBLER_NEEDS_RELOCS + 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) +#endif + sym = find_symbol_for_address (vma, info, NULL); + objdump_print_addr_with_sym (aux->abfd, aux->sec, sym, vma, info, skip_zeroes); } @@ -850,16 +915,9 @@ objdump_print_address (bfd_vma vma, struct disassemble_info *info) static int 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, - NULL); + sym = find_symbol_for_address (vma, info, NULL); return (sym != NULL && (bfd_asymbol_value (sym) == vma)); } @@ -871,7 +929,7 @@ 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 @@ -999,7 +1057,7 @@ skip_to_line (struct print_file_list *p, unsigned int line, } } -/* 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 @@ -1130,48 +1188,34 @@ show_line (bfd *abfd, asection *section, bfd_vma addr_offset) typedef struct { char *buffer; - size_t size; - char *current; + size_t pos; + size_t alloc; } SFILE; /* sprintf to a "stream". */ -static int +static int ATTRIBUTE_PRINTF_2 objdump_sprintf (SFILE *f, const char *format, ...) { - char *buf; size_t n; va_list args; - va_start (args, 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); - 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; + if (space > n) + break; + + f->alloc = (f->alloc + n) * 2; + f->buffer = xrealloc (f->buffer, f->alloc); } - - memcpy (f->current, buf, n); - f->current += n; - f->current[0] = '\0'; - - free (buf); - - va_end (args); + f->pos += n; + return n; } @@ -1196,9 +1240,7 @@ process_section_p (asection * section) /* 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 @@ -1207,9 +1249,7 @@ process_section_p (asection * section) 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. */ @@ -1230,11 +1270,19 @@ disassemble_bytes (struct disassemble_info * info, 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 @@ -1270,8 +1318,14 @@ disassemble_bytes (struct disassemble_info * info, while (addr_offset < stop_offset) { bfd_vma z; - int octets = 0; bfd_boolean need_nl = FALSE; +#ifdef DISASSEMBLER_NEEDS_RELOCS + int previous_octets; + + /* Remember the length of the previous instruction. */ + previous_octets = octets; +#endif + octets = 0; /* If we see more than SKIP_ZEROES octets of zeroes, we just print `...'. */ @@ -1281,9 +1335,9 @@ disassemble_bytes (struct disassemble_info * info, 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"); @@ -1299,17 +1353,13 @@ disassemble_bytes (struct disassemble_info * info, 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) { @@ -1332,26 +1382,45 @@ disassemble_bytes (struct disassemble_info * info, 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 >= rel_offset + addr_offset - && ((**relppp)->address - < rel_offset + addr_offset + octets / opb)) - info->flags = INSN_HAS_RELOC; - else + if (*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; + } #endif - info->flags = 0; - octets = (*disassemble_fn) (section->vma + addr_offset, info); info->fprintf_func = (fprintf_ftype) fprintf; info->stream = stdout; @@ -1359,9 +1428,8 @@ disassemble_bytes (struct disassemble_info * info, 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; } } @@ -1403,6 +1471,7 @@ disassemble_bytes (struct disassemble_info * info, 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--) @@ -1435,11 +1504,8 @@ disassemble_bytes (struct disassemble_info * info, 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 @@ -1503,9 +1569,15 @@ disassemble_bytes (struct disassemble_info * info, 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*"); @@ -1545,13 +1617,15 @@ disassemble_bytes (struct disassemble_info * info, 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 = (struct objdump_disasm_info *) pinfo->application_data; + struct objdump_disasm_info * paux; unsigned int opb = pinfo->octets_per_byte; bfd_byte * data = NULL; bfd_size_type datasize = 0; @@ -1569,25 +1643,27 @@ disassemble_section (bfd *abfd, asection *section, void *info) code are not normally disassembled. */ if (! disassemble_all && only == NULL - && (section->flags & SEC_CODE) == 0) + && ((section->flags & (SEC_CODE | SEC_HAS_CONTENTS)) + != (SEC_CODE | SEC_HAS_CONTENTS))) return; if (! process_section_p (section)) return; - datasize = bfd_get_section_size_before_reloc (section); + 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 corresponnding + relative. REL_OFFSET specifies the reloc address corresponding to the start of this section. */ - rel_offset = pinfo->buffer_vma; + rel_offset = section->vma; } else { @@ -1659,8 +1735,9 @@ disassemble_section (bfd *abfd, asection *section, void *info) printf (_("Disassembly of section %s:\n"), section->name); /* Find the nearest symbol forwards from our current position. */ - sym = find_symbol_for_address (abfd, section, section->vma + addr_offset, - TRUE, &place); + 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 @@ -1668,81 +1745,81 @@ disassemble_section (bfd *abfd, asection *section, void *info) 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; - if (sym != NULL - && bfd_asymbol_value (sym) <= section->vma + addr_offset) + 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]) - <= section->vma + addr_offset)); + && (bfd_asymbol_value (sorted_syms[x]) <= addr)); ++x) continue; - pinfo->symbols = & sorted_syms[place]; + pinfo->symbols = sorted_syms + place; pinfo->num_symbols = x - place; } else - pinfo->symbols = NULL; + { + pinfo->symbols = NULL; + pinfo->num_symbols = 0; + } if (! prefix_addresses) { pinfo->fprintf_func (pinfo->stream, "\n"); - objdump_print_addr_with_sym (abfd, section, sym, - section->vma + addr_offset, + objdump_print_addr_with_sym (abfd, section, sym, addr, pinfo, FALSE); pinfo->fprintf_func (pinfo->stream, ":\n"); } - if (sym != NULL - && bfd_asymbol_value (sym) > section->vma + addr_offset) + 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 - && (sorted_syms[place]->section != section - || (bfd_asymbol_value (sorted_syms[place]) - <= bfd_asymbol_value (sym)))) + && ! 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) > section->vma + addr_offset) - { - nextstop_offset = bfd_asymbol_value (sym) - section->vma; - if (nextstop_offset > stop_offset) - nextstop_offset = stop_offset; - } + 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; - } + nextstop_offset = bfd_asymbol_value (nextsym) - section->vma; + + if (nextstop_offset > stop_offset) + nextstop_offset = stop_offset; /* If a symbol is explicitly marked as being an object rather than a function, just dump the bytes without disassembling them. */ if (disassemble_all || sym == NULL - || bfd_asymbol_value (sym) > section->vma + addr_offset + || bfd_asymbol_value (sym) > addr || ((sym->flags & BSF_OBJECT) == 0 && (strstr (bfd_asymbol_name (sym), "gnu_compiled") == NULL) @@ -1774,6 +1851,7 @@ disassemble_data (bfd *abfd) { struct disassemble_info disasm_info; struct objdump_disasm_info aux; + long i; print_files = NULL; prev_functionname = NULL; @@ -1781,21 +1859,32 @@ disassemble_data (bfd *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 = 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 = (void *) &aux; aux.abfd = abfd; aux.require_sec = FALSE; aux.dynrelbuf = NULL; aux.dynrelcount = 0; +#ifdef DISASSEMBLER_NEEDS_RELOCS + aux.reloc = NULL; +#endif disasm_info.print_address_func = objdump_print_address; disasm_info.symbol_at_address_func = objdump_symbol_at_address; @@ -1835,6 +1924,8 @@ disassemble_data (bfd *abfd) disasm_info.mach = bfd_get_mach (abfd); disasm_info.disassembler_options = disassembler_options; 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; if (bfd_big_endian (abfd)) disasm_info.display_endian = disasm_info.endian = BFD_ENDIAN_BIG; @@ -1845,6 +1936,9 @@ disassemble_data (bfd *abfd) instead. */ disasm_info.endian = BFD_ENDIAN_UNKNOWN; + /* Allow the target to customize the info structure. */ + disassemble_init_for_target (& disasm_info); + /* Pre-load the dynamic relocs if we are going to be dumping them along with the disassembly. */ if (dump_dynamic_reloc_info) @@ -1857,12 +1951,15 @@ disassemble_data (bfd *abfd) if (relsize > 0) { aux.dynrelbuf = xmalloc (relsize); - aux.dynrelcount = bfd_canonicalize_dynamic_reloc (abfd, aux.dynrelbuf, dynsyms); + aux.dynrelcount = bfd_canonicalize_dynamic_reloc (abfd, + aux.dynrelbuf, + dynsyms); if (aux.dynrelcount < 0) bfd_fatal (bfd_get_filename (abfd)); /* Sort the relocs by address. */ - qsort (aux.dynrelbuf, aux.dynrelcount, sizeof (arelent *), compare_relocs); + qsort (aux.dynrelbuf, aux.dynrelcount, sizeof (arelent *), + compare_relocs); } } @@ -1873,63 +1970,196 @@ disassemble_data (bfd *abfd) free (sorted_syms); } -/* Read ABFD's stabs section STABSECT_NAME into `stabs' - and string table section STRSECT_NAME into `strtab'. - If the section exists and was read, allocate the space and return TRUE. - Otherwise return FALSE. */ - -static bfd_boolean -read_section_stabs (bfd *abfd, const char *stabsect_name, - const char *strsect_name) +int +load_debug_section (enum dwarf_section_display_enum debug, void *file) { - asection *stabsect, *stabstrsect; + struct dwarf_section *section = &debug_displays [debug].section; + bfd *abfd = file; + asection *sec; + bfd_boolean ret; - stabsect = bfd_get_section_by_name (abfd, stabsect_name); - if (stabsect == NULL) + /* If it is already loaded, do nothing. */ + if (section->start != NULL) + return 1; + + /* Locate the debug section. */ + sec = bfd_get_section_by_name (abfd, section->name); + if (sec == NULL) + return 0; + + section->address = bfd_get_section_vma (abfd, sec); + section->size = bfd_get_section_size (sec); + section->start = xmalloc (section->size); + + 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); + + if (!ret) { - printf (_("No %s section present\n\n"), stabsect_name); - return FALSE; + free_debug_section (debug); + printf (_("\nCan't get contents for section '%s'.\n"), + section->name); } - stabstrsect = bfd_get_section_by_name (abfd, strsect_name); - if (stabstrsect == NULL) + return ret; +} + +void +free_debug_section (enum dwarf_section_display_enum debug) +{ + struct dwarf_section *section = &debug_displays [debug].section; + + if (section->start == NULL) + return; + + free ((char *) section->start); + section->start = NULL; + section->address = 0; + section->size = 0; +} + +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; + + if (strncmp (name, ".gnu.linkonce.wi.", 17) == 0) + match = ".debug_info"; + else + match = name; + + 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; + } +} + +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 */ +}; + +static const char *generic_dwarf_sections [max]; + +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 (generic_dwarf_sections [0] == NULL) + for (i = 0; i < max; i++) + generic_dwarf_sections [i] = debug_displays[i].section.name; + + if (old_flavour != current_flavour) { - non_fatal (_("%s has no %s section"), - bfd_get_filename (abfd), strsect_name); - exit_status = 1; - return FALSE; + 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; } +} + +/* Dump the dwarf debugging information. */ + +static void +dump_dwarf (bfd *abfd) +{ + is_relocatable = ((abfd->flags & (HAS_RELOC | EXEC_P | DYNAMIC)) + == HAS_RELOC); + + /* 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; + + 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 (); + + check_mach_o_dwarf (abfd); - stab_size = bfd_section_size (abfd, stabsect); - stabstr_size = bfd_section_size (abfd, stabstrsect); + bfd_map_over_sections (abfd, dump_dwarf_section, NULL); - stabs = xmalloc (stab_size); - strtab = xmalloc (stabstr_size); + free_debug_memory (); +} + +/* Read ABFD's stabs section STABSECT_NAME, and return a pointer to + it. Return NULL on failure. */ - if (! bfd_get_section_contents (abfd, stabsect, stabs, 0, stab_size)) +static char * +read_section_stabs (bfd *abfd, const char *sect_name, bfd_size_type *size_ptr) +{ + asection *stabsect; + bfd_size_type size; + char *contents; + + stabsect = bfd_get_section_by_name (abfd, sect_name); + if (stabsect == NULL) { - non_fatal (_("Reading %s section of %s failed: %s"), - stabsect_name, bfd_get_filename (abfd), - bfd_errmsg (bfd_get_error ())); - free (stabs); - free (strtab); - exit_status = 1; + printf (_("No %s section present\n\n"), sect_name); return FALSE; } - if (! bfd_get_section_contents (abfd, stabstrsect, (void *) strtab, 0, - stabstr_size)) + size = bfd_section_size (abfd, stabsect); + contents = xmalloc (size); + + if (! bfd_get_section_contents (abfd, stabsect, contents, 0, size)) { - non_fatal (_("Reading %s section of %s failed: %s\n"), - strsect_name, bfd_get_filename (abfd), + non_fatal (_("Reading %s section of %s failed: %s"), + sect_name, bfd_get_filename (abfd), bfd_errmsg (bfd_get_error ())); - free (stabs); - free (strtab); + free (contents); exit_status = 1; - return FALSE; + return NULL; } - return TRUE; + *size_ptr = size; + + return contents; } /* Stabs entries use a 12 byte format: @@ -1951,11 +2181,13 @@ read_section_stabs (bfd *abfd, const char *stabsect_name, using string table section STRSECT_NAME (in `strtab'). */ static void -print_section_stabs (bfd *abfd, const char *stabsect_name) +print_section_stabs (bfd *abfd, + const char *stabsect_name, + unsigned *string_offset_ptr) { int i; unsigned file_string_table_offset = 0; - unsigned next_file_string_table_offset = 0; + unsigned next_file_string_table_offset = *string_offset_ptr; bfd_byte *stabp, *stabs_end; stabp = stabs; @@ -2015,12 +2247,14 @@ print_section_stabs (bfd *abfd, const char *stabsect_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; @@ -2031,7 +2265,7 @@ find_stabs_section (bfd *abfd, asection *section, void *names) stab_section_names * sought = (stab_section_names *) names; /* Check for section names for which stabsect_name is a prefix, to - handle .stab0, etc. */ + handle .stab.N, etc. */ len = strlen (sought->section_name); /* If the prefix matches, and the files section name ends with a @@ -2039,13 +2273,18 @@ find_stabs_section (bfd *abfd, asection *section, void *names) match or a section followed by a number. */ if (strncmp (sought->section_name, section->name, len) == 0 && (section->name[len] == 0 - || ISDIGIT (section->name[len]))) + || (section->name[len] == '.' && ISDIGIT (section->name[len + 1])))) { - if (read_section_stabs (abfd, section->name, sought->string_section_name)) + if (strtab == NULL) + strtab = read_section_stabs (abfd, sought->string_section_name, + &stabstr_size); + + if (strtab) { - print_section_stabs (abfd, section->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); } } } @@ -2057,8 +2296,12 @@ dump_stabs_section (bfd *abfd, char *stabsect_name, char *strsect_name) 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. */ @@ -2266,13 +2509,15 @@ dump_symbols (bfd *abfd ATTRIBUTE_UNUSED, bfd_boolean dynamic) bfd *cur_bfd; if (*current == NULL) - printf (_("no information for the %ld'th symbol"), count); + 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 the %ld'th symbol"), + printf (_("could not determine the type of symbol number %ld\n"), count); - else + else if (process_section_p ((* current)->section) + && (dump_special_syms + || !bfd_is_target_special_symbol (cur_bfd, *current))) { const char *name = (*current)->name; @@ -2293,9 +2538,9 @@ dump_symbols (bfd *abfd ATTRIBUTE_UNUSED, bfd_boolean dynamic) else bfd_print_symbol (cur_bfd, stdout, *current, bfd_print_symbol_all); + printf ("\n"); } - printf ("\n"); current++; } printf ("\n\n"); @@ -2384,23 +2629,20 @@ dump_reloc_set (bfd *abfd, asection *sec, arelent **relpp, long 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, NULL, *q->sym_ptr_ptr); - } + objdump_print_symname (abfd, NULL, *q->sym_ptr_ptr); else { 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) @@ -2414,7 +2656,9 @@ dump_reloc_set (bfd *abfd, asection *sec, arelent **relpp, long relcount) } static void -dump_relocs_in_section (bfd *abfd, asection *section, void *dummy ATTRIBUTE_UNUSED) +dump_relocs_in_section (bfd *abfd, + asection *section, + void *dummy ATTRIBUTE_UNUSED) { arelent **relpp; long relcount; @@ -2513,10 +2757,17 @@ add_include_path (const char *path) } static void -adjust_addresses (bfd *abfd ATTRIBUTE_UNUSED, asection *section, void *dummy ATTRIBUTE_UNUSED) +adjust_addresses (bfd *abfd ATTRIBUTE_UNUSED, + asection *section, + void *arg) { - section->vma += adjust_section_vma; - section->lma += adjust_section_vma; + 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. */ @@ -2528,7 +2779,10 @@ dump_bfd (bfd *abfd) 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_map_over_sections (abfd, adjust_addresses, NULL); + { + 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), @@ -2544,15 +2798,29 @@ dump_bfd (bfd *abfd) if (dump_section_headers) dump_headers (abfd); - if (dump_symtab || dump_reloc_info || disassemble || dump_debugging) + 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) + 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) @@ -2592,6 +2860,16 @@ dump_bfd (bfd *abfd) free (dynsyms); dynsyms = NULL; } + + if (synthsyms) + { + free (synthsyms); + synthsyms = NULL; + } + + symcount = 0; + dynsymcount = 0; + synthcount = 0; } static void @@ -2637,7 +2915,11 @@ display_bfd (bfd *abfd) static void display_file (char *filename, char *target) { - bfd *file, *arfile = NULL; + bfd *file; + bfd *arfile = NULL; + + if (get_file_size (filename) < 1) + return; file = bfd_openr (filename, target); if (file == NULL) @@ -2702,10 +2984,12 @@ main (int argc, char **argv) START_PROGRESS (program_name, 0); + expandargv (&argc, &argv); + bfd_init (); set_default_bfd_target (); - while ((c = getopt_long (argc, argv, "pib:m:M:VvCdDlfaHhrRtTxsSI:j:wE:zgeG", + while ((c = getopt_long (argc, argv, "pib:m:M:VvCdDlfaHhrRtTxsSI:j:wE:zgeGW", long_options, (int *) 0)) != EOF) { @@ -2846,6 +3130,20 @@ main (int argc, char **argv) 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;