X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=binutils%2Fobjdump.c;h=3c5defabf743c8912be2ce34d1aef675a9980f6d;hb=0bae9e9ec550c940e263b37f577bf11b2dabf934;hp=11a11aee6520bb3bf14394d030f6c191d56c0f0b;hpb=cc5914eb31109a6481682d9bc5dc7c23fccc024c;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/objdump.c b/binutils/objdump.c index 11a11aee65..3c5defabf7 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -1,7 +1,5 @@ /* objdump.c -- dump information about an object file. - Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. + Copyright (C) 1990-2017 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -29,14 +27,14 @@ relocations, debugging directives and more. The flow of execution is as follows: - + 1. Command line arguments are checked for control switches and the information to be displayed is selected. - + 2. Any remaining arguments are assumed to be object files, and they are processed in order by display_bfd(). If the file is an archive each of its elements is processed in turn. - + 3. The file's target architecture and binary file format are determined by bfd_check_format(). If they are recognised, then dump_bfd() is called. @@ -53,8 +51,10 @@ #include "sysdep.h" #include "bfd.h" #include "elf-bfd.h" +#include "coff-bfd.h" #include "progress.h" #include "bucomm.h" +#include "elfcomm.h" #include "dwarf.h" #include "getopt.h" #include "safe-ctype.h" @@ -64,13 +64,12 @@ #include "filenames.h" #include "debug.h" #include "budbg.h" +#include "objdump.h" #ifdef HAVE_MMAP #include #endif -#include - /* Internal headers for the ELF .stab-dump code - sorry. */ #define BYTES_IN_WORD 32 #include "aout/aout64.h" @@ -92,6 +91,7 @@ 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 char *dump_private_options; /* -P */ static int prefix_addresses; /* --prefix-addresses */ static int with_line_numbers; /* -l */ static bfd_boolean with_source_code; /* -S */ @@ -109,6 +109,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 suppress_bfd_header; 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,6 +117,7 @@ static bfd_boolean display_file_offsets;/* -F */ static const char *prefix; /* --prefix */ static int prefix_strip; /* --prefix-strip */ static size_t prefix_length; +static bfd_boolean unwind_inlines; /* --inlines. */ /* A structure to record the sections mentioned in -j switches. */ struct only @@ -179,11 +181,19 @@ static long dynsymcount = 0; static bfd_byte *stabs; static bfd_size_type stab_size; -static char *strtab; +static bfd_byte *strtab; static bfd_size_type stabstr_size; static bfd_boolean is_relocatable = FALSE; + +/* Handlers for -P/--private. */ +static const struct objdump_private_desc * const objdump_private_vectors[] = + { + OBJDUMP_PRIVATE_VECTORS + NULL + }; +static void usage (FILE *, int) ATTRIBUTE_NORETURN; static void usage (FILE *stream, int status) { @@ -194,6 +204,7 @@ usage (FILE *stream, int status) -a, --archive-headers Display archive header information\n\ -f, --file-headers Display the contents of the overall file header\n\ -p, --private-headers Display object format specific file header contents\n\ + -P, --private=OPT,OPT... Display object format specific contents\n\ -h, --[section-]headers Display the contents of the section headers\n\ -x, --all-headers Display the contents of all headers\n\ -d, --disassemble Display assembler contents of executable sections\n\ @@ -206,7 +217,8 @@ usage (FILE *stream, int status) -W[lLiaprmfFsoRt] or\n\ --dwarf[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,\n\ =frames-interp,=str,=loc,=Ranges,=pubtypes,\n\ - =trace_info,=trace_abbrev,=trace_aranges]\n\ + =gdb_index,=trace_info,=trace_abbrev,=trace_aranges,\n\ + =addr,=cu_index]\n\ 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\ @@ -219,6 +231,8 @@ usage (FILE *stream, int status) ")); if (status != 2) { + const struct objdump_private_desc * const *desc; + fprintf (stream, _("\n The following switches are optional:\n")); fprintf (stream, _("\ -b, --target=BFDNAME Specify the target object format as BFDNAME\n\ @@ -241,16 +255,30 @@ usage (FILE *stream, int status) --stop-address=ADDR Only process data whose address is <= ADDR\n\ --prefix-addresses Print complete address alongside disassembly\n\ --[no-]show-raw-insn Display hex alongside symbolic disassembly\n\ - --insn-width=WIDTH Display WIDTH bytes on a signle line for -d\n\ + --insn-width=WIDTH Display WIDTH bytes on a single line for -d\n\ --adjust-vma=OFFSET Add OFFSET to all displayed section addresses\n\ --special-syms Include special symbols in symbol dumps\n\ + --inlines Print all inlines for source line (with -l)\n\ --prefix=PREFIX Add PREFIX to absolute paths for -S\n\ - --prefix-strip=LEVEL Strip initial directory names for -S\n\ -\n")); + --prefix-strip=LEVEL Strip initial directory names for -S\n")); + fprintf (stream, _("\ + --dwarf-depth=N Do not display DIEs at depth N or greater\n\ + --dwarf-start=N Display DIEs starting with N, at the same depth\n\ + or deeper\n\ + --dwarf-check Make additional dwarf internal consistency checks.\ + \n\n")); list_supported_targets (program_name, stream); list_supported_architectures (program_name, stream); disassembler_usage (stream); + + if (objdump_private_vectors[0] != NULL) + { + fprintf (stream, + _("\nOptions supported for -P/--private switch:\n")); + for (desc = objdump_private_vectors; *desc != NULL; desc++) + (*desc)->help (stream); + } } if (REPORT_BUGS_TO[0] && status == 0) fprintf (stream, _("Report bugs to %s.\n"), REPORT_BUGS_TO); @@ -267,7 +295,11 @@ enum option_values OPTION_PREFIX, OPTION_PREFIX_STRIP, OPTION_INSN_WIDTH, - OPTION_ADJUST_VMA + OPTION_ADJUST_VMA, + OPTION_DWARF_DEPTH, + OPTION_DWARF_CHECK, + OPTION_DWARF_START, + OPTION_INLINES }; static struct option long_options[]= @@ -275,6 +307,7 @@ 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'}, + {"private", required_argument, NULL, 'P'}, {"architecture", required_argument, NULL, 'm'}, {"archive-headers", no_argument, NULL, 'a'}, {"debugging", no_argument, NULL, 'g'}, @@ -315,6 +348,10 @@ static struct option long_options[]= {"prefix", required_argument, NULL, OPTION_PREFIX}, {"prefix-strip", required_argument, NULL, OPTION_PREFIX_STRIP}, {"insn-width", required_argument, NULL, OPTION_INSN_WIDTH}, + {"dwarf-depth", required_argument, 0, OPTION_DWARF_DEPTH}, + {"dwarf-start", required_argument, 0, OPTION_DWARF_START}, + {"dwarf-check", no_argument, 0, OPTION_DWARF_CHECK}, + {"inlines", no_argument, 0, OPTION_INLINES}, {0, no_argument, 0, 0} }; @@ -405,11 +442,11 @@ free_only_list (void) static void -dump_section_header (bfd *abfd, asection *section, - void *ignored ATTRIBUTE_UNUSED) +dump_section_header (bfd *abfd, asection *section, void *data) { char *comma = ""; unsigned int opb = bfd_octets_per_byte (abfd); + int longest_section_name = *((int *) data); /* Ignore linker created section. See elfNN_ia64_object_p in bfd/elfxx-ia64.c. */ @@ -420,7 +457,7 @@ dump_section_header (bfd *abfd, asection *section, if (! process_section_p (section)) return; - printf ("%3d %-13s %08lx ", section->index, + printf ("%3d %-*s %08lx ", section->index, longest_section_name, bfd_get_section_name (abfd, section), (unsigned long) bfd_section_size (abfd, section) / opb); bfd_printf_vma (abfd, bfd_get_section_vma (abfd, section)); @@ -455,9 +492,18 @@ dump_section_header (bfd *abfd, asection *section, } PF (SEC_SMALL_DATA, "SMALL_DATA"); if (bfd_get_flavour (abfd) == bfd_target_coff_flavour) - PF (SEC_COFF_SHARED, "SHARED"); + { + PF (SEC_COFF_SHARED, "SHARED"); + PF (SEC_COFF_NOREAD, "NOREAD"); + } + else if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + PF (SEC_ELF_PURECODE, "PURECODE"); PF (SEC_THREAD_LOCAL, "THREAD_LOCAL"); PF (SEC_GROUP, "GROUP"); + if (bfd_get_arch (abfd) == bfd_arch_mep) + { + PF (SEC_MEP_VLIW, "VLIW"); + } if ((section->flags & SEC_LINK_ONCE) != 0) { @@ -494,26 +540,64 @@ dump_section_header (bfd *abfd, asection *section, #undef PF } +/* Called on each SECTION in ABFD, update the int variable pointed to by + DATA which contains the string length of the longest section name. */ + +static void +find_longest_section_name (bfd *abfd, asection *section, void *data) +{ + int *longest_so_far = (int *) data; + const char *name; + int len; + + /* Ignore linker created section. */ + if (section->flags & SEC_LINKER_CREATED) + return; + + /* Skip sections that we are ignoring. */ + if (! process_section_p (section)) + return; + + name = bfd_get_section_name (abfd, section); + len = (int) strlen (name); + if (len > *longest_so_far) + *longest_so_far = len; +} + static void dump_headers (bfd *abfd) { - printf (_("Sections:\n")); + /* The default width of 13 is just an arbitrary choice. */ + int max_section_name_length = 13; + int bfd_vma_width; #ifndef BFD64 - printf (_("Idx Name Size VMA LMA File off Algn")); + bfd_vma_width = 10; #else /* With BFD64, non-ELF returns -1 and wants always 64 bit addresses. */ if (bfd_get_arch_size (abfd) == 32) - printf (_("Idx Name Size VMA LMA File off Algn")); + bfd_vma_width = 10; else - printf (_("Idx Name Size VMA LMA File off Algn")); + bfd_vma_width = 18; #endif + printf (_("Sections:\n")); + + if (wide_output) + bfd_map_over_sections (abfd, find_longest_section_name, + &max_section_name_length); + + printf (_("Idx %-*s Size %-*s%-*sFile off Algn"), + max_section_name_length, "Name", + bfd_vma_width, "VMA", + bfd_vma_width, "LMA"); + if (wide_output) printf (_(" Flags")); printf ("\n"); - bfd_map_over_sections (abfd, dump_section_header, NULL); + bfd_map_over_sections (abfd, dump_section_header, + &max_section_name_length); } static asymbol ** @@ -530,7 +614,10 @@ slurp_symtab (bfd *abfd) storage = bfd_get_symtab_upper_bound (abfd); if (storage < 0) - bfd_fatal (bfd_get_filename (abfd)); + { + non_fatal (_("failed to read symbol table from: %s"), bfd_get_filename (abfd)); + bfd_fatal (_("error message was")); + } if (storage) sy = (asymbol **) xmalloc (storage); @@ -570,6 +657,18 @@ slurp_dynamic_symtab (bfd *abfd) return sy; } +/* Some symbol names are significant and should be kept in the + table of sorted symbol names, even if they are marked as + debugging/section symbols. */ + +static bfd_boolean +is_significant_symbol_name (const char * name) +{ + return strcmp (name, ".plt") == 0 + || strcmp (name, ".got") == 0 + || strcmp (name, ".plt.got") == 0; +} + /* Filter out (in place) symbols that are useless for disassembly. COUNT is the number of elements in SYMBOLS. Return the number of useful symbols. */ @@ -585,7 +684,8 @@ remove_useless_symbols (asymbol **symbols, long count) if (sym->name == NULL || sym->name[0] == '\0') continue; - if (sym->flags & (BSF_DEBUGGING | BSF_SECTION_SYM)) + if ((sym->flags & (BSF_DEBUGGING | BSF_SECTION_SYM)) + && ! is_significant_symbol_name (sym->name)) continue; if (bfd_is_und_section (sym->section) || bfd_is_com_section (sym->section)) @@ -693,6 +793,21 @@ compare_symbols (const void *ap, const void *bp) return 1; } + if (bfd_get_flavour (bfd_asymbol_bfd (a)) == bfd_target_elf_flavour + && bfd_get_flavour (bfd_asymbol_bfd (b)) == bfd_target_elf_flavour) + { + bfd_vma asz, bsz; + + asz = 0; + if ((a->flags & BSF_SYNTHETIC) == 0) + asz = ((elf_symbol_type *) a)->internal_elf_sym.st_size; + bsz = 0; + if ((b->flags & BSF_SYNTHETIC) == 0) + bsz = ((elf_symbol_type *) b)->internal_elf_sym.st_size; + if (asz != bsz) + return asz > bsz ? -1 : 1; + } + /* Symbols that start with '.' might be section names, so sort them after symbols that don't start with '.'. */ if (an[0] == '.' && bn[0] != '.') @@ -760,7 +875,8 @@ objdump_print_symname (bfd *abfd, struct disassemble_info *inf, asymbol *sym) { char *alloc; - const char *name; + const char *name, *version_string = NULL; + bfd_boolean hidden = FALSE; alloc = NULL; name = bfd_asymbol_name (sym); @@ -772,10 +888,25 @@ objdump_print_symname (bfd *abfd, struct disassemble_info *inf, name = alloc; } + if ((sym->flags & BSF_SYNTHETIC) == 0) + version_string = bfd_get_symbol_version_string (abfd, sym, &hidden); + + if (bfd_is_und_section (bfd_get_section (sym))) + hidden = TRUE; + if (inf != NULL) - (*inf->fprintf_func) (inf->stream, "%s", name); + { + (*inf->fprintf_func) (inf->stream, "%s", name); + if (version_string && *version_string != '\0') + (*inf->fprintf_func) (inf->stream, hidden ? "@%s" : "@@%s", + version_string); + } else - printf ("%s", name); + { + printf ("%s", name); + if (version_string && *version_string != '\0') + printf (hidden ? "@%s" : "@@%s", version_string); + } if (alloc != NULL) free (alloc); @@ -837,11 +968,14 @@ find_symbol_for_address (bfd_vma vma, /* The symbol we want is now in min, the low end of the range we were searching. If there are several symbols with the same - value, we want the first one. */ + value, we want the first (non-section/non-debugging) one. */ thisplace = min; while (thisplace > 0 && (bfd_asymbol_value (sorted_syms[thisplace]) - == bfd_asymbol_value (sorted_syms[thisplace - 1]))) + == bfd_asymbol_value (sorted_syms[thisplace - 1])) + && ((sorted_syms[thisplace - 1]->flags + & (BSF_SECTION_SYM | BSF_DEBUGGING)) == 0) + ) --thisplace; /* Prefer a symbol in the current section if we have multple symbols @@ -873,7 +1007,7 @@ find_symbol_for_address (bfd_vma vma, sections have overlapping memory ranges, but in that case there's no way to tell what's desired without looking at the relocation table. - + Also give the target a chance to reject symbols. */ want_section = (aux->require_sec || ((abfd->flags & HAS_RELOC) != 0 @@ -927,6 +1061,41 @@ find_symbol_for_address (bfd_vma vma, return NULL; } + /* If we have not found an exact match for the specified address + and we have dynamic relocations available, then we can produce + a better result by matching a relocation to the address and + using the symbol associated with that relocation. */ + if (!want_section + && aux->dynrelbuf != NULL + && sorted_syms[thisplace]->value != vma + /* If we have matched a synthetic symbol, then stick with that. */ + && (sorted_syms[thisplace]->flags & BSF_SYNTHETIC) == 0) + { + long rel_count; + arelent ** rel_pp; + + for (rel_count = aux->dynrelcount, rel_pp = aux->dynrelbuf; + rel_count--;) + { + arelent * rel = rel_pp[rel_count]; + + if (rel->address == vma + && rel->sym_ptr_ptr != NULL + /* Absolute relocations do not provide a more helpful symbolic address. */ + && ! bfd_is_abs_section ((* rel->sym_ptr_ptr)->section)) + { + if (place != NULL) + * place = thisplace; + return * rel->sym_ptr_ptr; + } + + /* We are scanning backwards, so if we go below the target address + we have failed. */ + if (rel_pp[rel_count]->address < vma) + break; + } + } + if (place != NULL) *place = thisplace; @@ -964,8 +1133,21 @@ objdump_print_addr_with_sym (bfd *abfd, asection *sec, asymbol *sym, else { (*inf->fprintf_func) (inf->stream, " <"); + objdump_print_symname (abfd, inf, sym); - if (bfd_asymbol_value (sym) > vma) + + if (bfd_asymbol_value (sym) == vma) + ; + /* Undefined symbols in an executables and dynamic objects do not have + a value associated with them, so it does not make sense to display + an offset relative to them. Normally we would not be provided with + this kind of symbol, but the target backend might choose to do so, + and the code in find_symbol_for_address might return an as yet + unresolved symbol associated with a dynamic reloc. */ + else if ((bfd_get_file_flags (abfd) & (EXEC_P | DYNAMIC)) + && bfd_is_und_section (sym->section)) + ; + else if (bfd_asymbol_value (sym) > vma) { (*inf->fprintf_func) (inf->stream, "-0x"); objdump_print_value (bfd_asymbol_value (sym) - vma, inf, TRUE); @@ -975,6 +1157,7 @@ objdump_print_addr_with_sym (bfd *abfd, asection *sec, asymbol *sym, (*inf->fprintf_func) (inf->stream, "+0x"); objdump_print_value (vma - bfd_asymbol_value (sym), inf, TRUE); } + (*inf->fprintf_func) (inf->stream, ">"); } @@ -1054,6 +1237,7 @@ objdump_symbol_at_address (bfd_vma vma, struct disassemble_info * inf) static char *prev_functionname; static unsigned int prev_line; +static unsigned int prev_discriminator; /* We keep a list of all files that we have seen when doing a disassembly with source, so that we know how much of the file to @@ -1064,11 +1248,12 @@ struct print_file_list struct print_file_list *next; const char *filename; const char *modname; - const char *map; + const char *map; size_t mapsize; - const char **linemap; + const char **linemap; unsigned maxline; unsigned last_line; + unsigned max_printed; int first; }; @@ -1082,76 +1267,78 @@ static struct print_file_list *print_files; /* Read a complete file into memory. */ static const char * -slurp_file (const char *fn, size_t *size) +slurp_file (const char *fn, size_t *size, struct stat *fst) { #ifdef HAVE_MMAP int ps = getpagesize (); size_t msize; #endif const char *map; - struct stat st; int fd = open (fn, O_RDONLY | O_BINARY); if (fd < 0) return NULL; - if (fstat (fd, &st) < 0) - return NULL; - *size = st.st_size; + if (fstat (fd, fst) < 0) + { + close (fd); + return NULL; + } + *size = fst->st_size; #ifdef HAVE_MMAP msize = (*size + ps - 1) & ~(ps - 1); map = mmap (NULL, msize, PROT_READ, MAP_SHARED, fd, 0); - if (map != (char *)-1L) + if (map != (char *) -1L) { - close(fd); - return map; + close (fd); + return map; } #endif map = (const char *) malloc (*size); - if (!map || (size_t) read (fd, (char *)map, *size) != *size) - { - free ((void *)map); + if (!map || (size_t) read (fd, (char *) map, *size) != *size) + { + free ((void *) map); map = NULL; } close (fd); - return map; + return map; } #define line_map_decrease 5 /* Precompute array of lines for a mapped file. */ -static const char ** -index_file (const char *map, size_t size, unsigned int *maxline) +static const char ** +index_file (const char *map, size_t size, unsigned int *maxline) { const char *p, *lstart, *end; int chars_per_line = 45; /* First iteration will use 40. */ unsigned int lineno; - const char **linemap = NULL; + const char **linemap = NULL; unsigned long line_map_size = 0; - + lineno = 0; lstart = map; end = map + size; - for (p = map; p < end; p++) - { - if (*p == '\n') - { - if (p + 1 < end && p[1] == '\r') - p++; - } - else if (*p == '\r') - { + for (p = map; p < end; p++) + { + if (*p == '\n') + { + if (p + 1 < end && p[1] == '\r') + p++; + } + else if (*p == '\r') + { if (p + 1 < end && p[1] == '\n') p++; } else continue; - + /* End of line found. */ - if (linemap == NULL || line_map_size < lineno + 1) - { + if (linemap == NULL || line_map_size < lineno + 1) + { unsigned long newsize; chars_per_line -= line_map_decrease; @@ -1164,11 +1351,11 @@ index_file (const char *map, size_t size, unsigned int *maxline) linemap = (const char **) xrealloc (linemap, newsize); } - linemap[lineno++] = lstart; - lstart = p + 1; + linemap[lineno++] = lstart; + lstart = p + 1; } - - *maxline = lineno; + + *maxline = lineno; return linemap; } @@ -1176,21 +1363,22 @@ index_file (const char *map, size_t size, unsigned int *maxline) linked list and returns that node. Returns NULL on failure. */ static struct print_file_list * -try_print_file_open (const char *origname, const char *modname) +try_print_file_open (const char *origname, const char *modname, struct stat *fst) { struct print_file_list *p; p = (struct print_file_list *) xmalloc (sizeof (struct print_file_list)); - p->map = slurp_file (modname, &p->mapsize); + p->map = slurp_file (modname, &p->mapsize, fst); if (p->map == NULL) { free (p); return NULL; } - + p->linemap = index_file (p->map, p->mapsize, &p->maxline); p->last_line = 0; + p->max_printed = 0; p->filename = origname; p->modname = modname; p->next = print_files; @@ -1199,52 +1387,63 @@ try_print_file_open (const char *origname, const char *modname) return p; } -/* If the the source file, as described in the symtab, is not found +/* If the source file, as described in the symtab, is not found try to locate it in one of the paths specified with -I If found, add location to print_files linked list. */ static struct print_file_list * -update_source_path (const char *filename) +update_source_path (const char *filename, bfd *abfd) { struct print_file_list *p; const char *fname; + struct stat fst; int i; - p = try_print_file_open (filename, filename); - if (p != NULL) - return p; + p = try_print_file_open (filename, filename, &fst); + if (p == NULL) + { + if (include_path_count == 0) + return NULL; - if (include_path_count == 0) - return NULL; + /* Get the name of the file. */ + fname = lbasename (filename); - /* Get the name of the file. */ - fname = lbasename (filename); + /* If file exists under a new path, we need to add it to the list + so that show_line knows about it. */ + for (i = 0; i < include_path_count; i++) + { + char *modname = concat (include_paths[i], "/", fname, + (const char *) 0); - /* If file exists under a new path, we need to add it to the list - so that show_line knows about it. */ - for (i = 0; i < include_path_count; i++) - { - char *modname = concat (include_paths[i], "/", fname, (const char *) 0); + p = try_print_file_open (filename, modname, &fst); + if (p) + break; + + free (modname); + } + } - p = try_print_file_open (filename, modname); - if (p) - return p; + if (p != NULL) + { + long mtime = bfd_get_mtime (abfd); - free (modname); + if (fst.st_mtime > mtime) + warn (_("source file %s is more recent than object file\n"), + filename); } - return NULL; + return p; } /* Print a source file line. */ -static void +static void print_line (struct print_file_list *p, unsigned int linenum) { const char *l; size_t len; - - --linenum; + + --linenum; if (linenum >= p->maxline) return; l = p->linemap [linenum]; @@ -1261,7 +1460,7 @@ dump_lines (struct print_file_list *p, unsigned int start, unsigned int end) { if (p->map == NULL) return; - while (start <= end) + while (start <= end) { print_line (p, start); start++; @@ -1277,13 +1476,16 @@ show_line (bfd *abfd, asection *section, bfd_vma addr_offset) const char *filename; const char *functionname; unsigned int linenumber; + unsigned int discriminator; bfd_boolean reloc; + char *path = NULL; if (! with_line_numbers && ! with_source_code) return; - if (! bfd_find_nearest_line (abfd, section, syms, addr_offset, &filename, - &functionname, &linenumber)) + if (! bfd_find_nearest_line_discriminator (abfd, section, syms, addr_offset, + &filename, &functionname, + &linenumber, &discriminator)) return; if (filename != NULL && *filename == '\0') @@ -1297,20 +1499,21 @@ show_line (bfd *abfd, asection *section, bfd_vma addr_offset) { char *path_up; const char *fname = filename; - char *path = (char *) alloca (prefix_length + PATH_MAX + 1); + + path = xmalloc (prefix_length + PATH_MAX + 1); if (prefix_length) memcpy (path, prefix, prefix_length); path_up = path + prefix_length; /* Build relocated filename, stripping off leading directories - from the initial filename if requested. */ + from the initial filename if requested. */ if (prefix_strip > 0) { int level = 0; const char *s; - /* Skip selected directory levels. */ + /* Skip selected directory levels. */ for (s = fname + 1; *s != '\0' && level < prefix_strip; s++) if (IS_DIR_SEPARATOR(*s)) { @@ -1319,7 +1522,7 @@ show_line (bfd *abfd, asection *section, bfd_vma addr_offset) } } - /* Update complete filename. */ + /* Update complete filename. */ strncpy (path_up, fname, PATH_MAX); path_up[PATH_MAX] = '\0'; @@ -1335,8 +1538,26 @@ show_line (bfd *abfd, asection *section, bfd_vma addr_offset) && (prev_functionname == NULL || strcmp (functionname, prev_functionname) != 0)) printf ("%s():\n", functionname); - if (linenumber > 0 && linenumber != prev_line) - printf ("%s:%u\n", filename == NULL ? "???" : filename, linenumber); + if (linenumber > 0 && (linenumber != prev_line || + (discriminator != prev_discriminator))) + { + if (discriminator > 0) + printf ("%s:%u (discriminator %u)\n", filename == NULL ? "???" : filename, + linenumber, discriminator); + else + printf ("%s:%u\n", filename == NULL ? "???" : filename, linenumber); + } + if (unwind_inlines) + { + const char *filename2; + const char *functionname2; + unsigned line2; + + while (bfd_find_inliner_info (abfd, &filename2, &functionname2, + &line2)) + printf ("inlined by %s:%u (%s)\n", filename2, line2, + functionname2); + } } if (with_source_code @@ -1347,7 +1568,7 @@ show_line (bfd *abfd, asection *section, bfd_vma addr_offset) unsigned l; for (pp = &print_files; *pp != NULL; pp = &(*pp)->next) - if (strcmp ((*pp)->filename, filename) == 0) + if (filename_cmp ((*pp)->filename, filename) == 0) break; p = *pp; @@ -1355,22 +1576,29 @@ show_line (bfd *abfd, asection *section, bfd_vma addr_offset) { if (reloc) filename = xstrdup (filename); - p = update_source_path (filename); + p = update_source_path (filename, abfd); } if (p != NULL && linenumber != p->last_line) { - if (file_start_context && p->first) + if (file_start_context && p->first) l = 1; - else + else { l = linenumber - SHOW_PRECEDING_CONTEXT_LINES; - if (l >= linenumber) + if (l >= linenumber) l = 1; - if (p->last_line >= l && p->last_line <= linenumber) - l = p->last_line + 1; + if (p->max_printed >= l) + { + if (p->max_printed < linenumber) + l = p->max_printed + 1; + else + l = linenumber; + } } dump_lines (p, l, linenumber); + if (p->max_printed < linenumber) + p->max_printed = linenumber; p->last_line = linenumber; p->first = 0; } @@ -1388,6 +1616,12 @@ show_line (bfd *abfd, asection *section, bfd_vma addr_offset) if (linenumber > 0 && linenumber != prev_line) prev_line = linenumber; + + if (discriminator != prev_discriminator) + prev_discriminator = discriminator; + + if (path) + free (path); } /* Pseudo FILE object for strings. */ @@ -1409,19 +1643,19 @@ objdump_sprintf (SFILE *f, const char *format, ...) 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); if (space > n) break; - + f->alloc = (f->alloc + n) * 2; f->buffer = (char *) xrealloc (f->buffer, f->alloc); } f->pos += n; - + return n; } @@ -1469,7 +1703,7 @@ disassemble_bytes (struct disassemble_info * inf, sfile.alloc = 120; sfile.buffer = (char *) xmalloc (sfile.alloc); sfile.pos = 0; - + if (insn_width) octets_per_line = insn_width; else if (insns) @@ -1618,7 +1852,18 @@ disassemble_bytes (struct disassemble_info * inf, } } + if (! disassemble_all + && (section->flags & (SEC_CODE | SEC_HAS_CONTENTS)) + == (SEC_CODE | SEC_HAS_CONTENTS)) + /* Set a stop_vma so that the disassembler will not read + beyond the next symbol. We assume that symbols appear on + the boundaries between instructions. We only do this when + disassembling code of course, and when -D is in effect. */ + inf->stop_vma = section->vma + stop_offset; + octets = (*disassemble_fn) (section->vma + addr_offset, inf); + + inf->stop_vma = 0; inf->fprintf_func = (fprintf_ftype) fprintf; inf->stream = stdout; if (insn_width == 0 && inf->bytes_per_line != 0) @@ -1673,20 +1918,23 @@ disassemble_bytes (struct disassemble_info * inf, for (j = addr_offset * opb; j < addr_offset * opb + pb; j += bpc) { - int k; - - if (bpc > 1 && inf->display_endian == BFD_ENDIAN_LITTLE) - { - for (k = bpc - 1; k >= 0; k--) - printf ("%02x", (unsigned) data[j + k]); - putchar (' '); - } - else + /* PR 21580: Check for a buffer ending early. */ + if (j + bpc <= stop_offset * opb) { - for (k = 0; k < bpc; k++) - printf ("%02x", (unsigned) data[j + k]); - putchar (' '); + int k; + + if (inf->display_endian == BFD_ENDIAN_LITTLE) + { + for (k = bpc - 1; k >= 0; k--) + printf ("%02x", (unsigned) data[j + k]); + } + else + { + for (k = 0; k < bpc; k++) + printf ("%02x", (unsigned) data[j + k]); + } } + putchar (' '); } for (; pb < octets_per_line; pb += bpc) @@ -1734,20 +1982,23 @@ disassemble_bytes (struct disassemble_info * inf, pb = octets; for (; j < addr_offset * opb + pb; j += bpc) { - int k; - - if (bpc > 1 && inf->display_endian == BFD_ENDIAN_LITTLE) - { - for (k = bpc - 1; k >= 0; k--) - printf ("%02x", (unsigned) data[j + k]); - putchar (' '); - } - else + /* PR 21619: Check for a buffer ending early. */ + if (j + bpc <= stop_offset * opb) { - for (k = 0; k < bpc; k++) - printf ("%02x", (unsigned) data[j + k]); - putchar (' '); + int k; + + if (inf->display_endian == BFD_ENDIAN_LITTLE) + { + for (k = bpc - 1; k >= 0; k--) + printf ("%02x", (unsigned) data[j + k]); + } + else + { + for (k = 0; k < bpc; k++) + printf ("%02x", (unsigned) data[j + k]); + } } + putchar (' '); } } } @@ -1805,8 +2056,15 @@ disassemble_bytes (struct disassemble_info * inf, if (q->addend) { - printf ("+0x"); - objdump_print_value (q->addend, inf, TRUE); + bfd_signed_vma addend = q->addend; + if (addend < 0) + { + printf ("-0x"); + addend = -addend; + } + else + printf ("+0x"); + objdump_print_value (addend, inf, TRUE); } printf ("\n"); @@ -1837,7 +2095,7 @@ disassemble_section (bfd *abfd, asection *section, void *inf) arelent ** rel_pp = NULL; arelent ** rel_ppstart = NULL; arelent ** rel_ppend; - unsigned long stop_offset; + bfd_vma stop_offset; asymbol * sym = NULL; long place = 0; long rel_count; @@ -1859,9 +2117,30 @@ disassemble_section (bfd *abfd, asection *section, void *inf) if (datasize == 0) return; + if (start_address == (bfd_vma) -1 + || start_address < section->vma) + addr_offset = 0; + else + addr_offset = start_address - section->vma; + + if (stop_address == (bfd_vma) -1) + stop_offset = datasize / opb; + else + { + if (stop_address < section->vma) + stop_offset = 0; + else + stop_offset = stop_address - section->vma; + if (stop_offset > datasize / opb) + stop_offset = datasize / opb; + } + + if (addr_offset >= stop_offset) + return; + /* Decide which set of relocs to use. Load them if necessary. */ paux = (struct objdump_disasm_info *) pinfo->application_data; - if (paux->dynrelbuf) + if (paux->dynrelbuf && dump_dynamic_reloc_info) { rel_pp = paux->dynrelbuf; rel_count = paux->dynrelcount; @@ -1899,9 +2178,12 @@ disassemble_section (bfd *abfd, asection *section, void *inf) } rel_ppend = rel_pp + rel_count; - data = (bfd_byte *) xmalloc (datasize); - - bfd_get_section_contents (abfd, section, data, 0, datasize); + if (!bfd_malloc_and_get_section (abfd, section, &data)) + { + non_fatal (_("Reading section %s failed because: %s"), + section->name, bfd_errmsg (bfd_get_error ())); + return; + } paux->sec = section; pinfo->buffer = data; @@ -1909,32 +2191,13 @@ disassemble_section (bfd *abfd, asection *section, void *inf) pinfo->buffer_length = datasize; pinfo->section = section; - if (start_address == (bfd_vma) -1 - || start_address < pinfo->buffer_vma) - addr_offset = 0; - else - addr_offset = start_address - pinfo->buffer_vma; - - if (stop_address == (bfd_vma) -1) - stop_offset = datasize / opb; - else - { - if (stop_address < pinfo->buffer_vma) - stop_offset = 0; - else - stop_offset = stop_address - pinfo->buffer_vma; - if (stop_offset > pinfo->buffer_length / opb) - stop_offset = pinfo->buffer_length / opb; - } - /* Skip over the relocs belonging to addresses below the start address. */ while (rel_pp < rel_ppend && (*rel_pp)->address < rel_offset + addr_offset) ++rel_pp; - if (addr_offset < stop_offset) - printf (_("\nDisassembly of section %s:\n"), section->name); + printf (_("\nDisassembly of section %s:\n"), section->name); /* Find the nearest symbol forwards from our current position. */ paux->require_sec = TRUE; @@ -1959,7 +2222,7 @@ disassemble_section (bfd *abfd, asection *section, void *inf) { bfd_vma addr; asymbol *nextsym; - unsigned long nextstop_offset; + bfd_vma nextstop_offset; bfd_boolean insns; addr = section->vma + addr_offset; @@ -2004,7 +2267,7 @@ disassemble_section (bfd *abfd, asection *section, void *inf) ((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 @@ -2050,7 +2313,7 @@ disassemble_section (bfd *abfd, asection *section, void *inf) disassemble_bytes (pinfo, paux->disassemble_fn, insns, data, addr_offset, nextstop_offset, rel_offset, &rel_pp, rel_ppend); - + addr_offset = nextstop_offset; sym = nextsym; } @@ -2073,6 +2336,7 @@ disassemble_data (bfd *abfd) print_files = NULL; prev_functionname = NULL; prev_line = -1; + prev_discriminator = 0; /* We make a copy of syms to sort. We don't want to sort syms because that will screw up the relocs. */ @@ -2126,7 +2390,9 @@ disassemble_data (bfd *abfd) } /* Use libopcodes to locate a suitable disassembler. */ - aux.disassemble_fn = disassembler (abfd); + aux.disassemble_fn = disassembler (bfd_get_arch (abfd), + bfd_big_endian (abfd), + bfd_get_mach (abfd), abfd); if (!aux.disassemble_fn) { non_fatal (_("can't disassemble for architecture %s\n"), @@ -2156,13 +2422,11 @@ disassemble_data (bfd *abfd) /* 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) + /* Pre-load the dynamic relocs as we may need them during the disassembly. */ { long relsize = bfd_get_dynamic_reloc_upper_bound (abfd); - - if (relsize < 0) + + if (relsize < 0 && dump_dynamic_reloc_info) bfd_fatal (bfd_get_filename (abfd)); if (relsize > 0) @@ -2201,9 +2465,12 @@ load_specific_debug_section (enum dwarf_section_display_enum debug, if (section->start != NULL) return 1; - section->address = 0; + section->reloc_info = NULL; + section->num_relocs = 0; + section->address = bfd_get_section_vma (abfd, sec); section->size = bfd_get_section_size (sec); section->start = NULL; + section->user_data = sec; ret = bfd_get_full_section_contents (abfd, sec, §ion->start); if (! ret) @@ -2216,13 +2483,7 @@ load_specific_debug_section (enum dwarf_section_display_enum debug, if (is_relocatable && debug_displays [debug].relocate) { - /* We want to relocate the data we've already read (and - decompressed), so we store a pointer to the data in - the bfd_section, and tell it that the contents are - already in memory. */ - sec->contents = section->start; - sec->flags |= SEC_IN_MEMORY; - sec->size = section->size; + bfd_cache_section_contents (sec, section->start); ret = bfd_simple_get_relocated_section_contents (abfd, sec, @@ -2236,11 +2497,49 @@ load_specific_debug_section (enum dwarf_section_display_enum debug, section->name); return 0; } + + long reloc_size; + + reloc_size = bfd_get_reloc_upper_bound (abfd, sec); + if (reloc_size > 0) + { + unsigned long reloc_count; + arelent **relocs; + + relocs = (arelent **) xmalloc (reloc_size); + + reloc_count = bfd_canonicalize_reloc (abfd, sec, relocs, NULL); + if (reloc_count == 0) + free (relocs); + else + { + section->reloc_info = relocs; + section->num_relocs = reloc_count; + } + } } return 1; } +bfd_boolean +reloc_at (struct dwarf_section * dsec, dwarf_vma offset) +{ + arelent ** relocs; + arelent * rp; + + if (dsec == NULL || dsec->reloc_info == NULL) + return FALSE; + + relocs = (arelent **) dsec->reloc_info; + + for (; (rp = * relocs) != NULL; ++ relocs) + if (rp->address == offset) + return TRUE; + + return FALSE; +} + int load_debug_section (enum dwarf_section_display_enum debug, void *file) { @@ -2276,6 +2575,23 @@ free_debug_section (enum dwarf_section_display_enum debug) if (section->start == NULL) return; + /* PR 17512: file: 0f67f69d. */ + if (section->user_data != NULL) + { + asection * sec = (asection *) section->user_data; + + /* If we are freeing contents that are also pointed to by the BFD + library's section structure then make sure to update those pointers + too. Otherwise, the next time we try to load data for this section + we can end up using a stale pointer. */ + if (section->start == sec->contents) + { + sec->contents = NULL; + sec->flags &= ~ SEC_IN_MEMORY; + sec->compress_status = COMPRESS_SECTION_NONE; + } + } + free ((char *) section->start); section->start = NULL; section->address = 0; @@ -2311,7 +2627,7 @@ dump_dwarf_section (bfd *abfd, asection *section, section, abfd)) { debug_displays [i].display (sec, abfd); - + if (i != info && i != abbrev) free_debug_section ((enum dwarf_section_display_enum) i); } @@ -2333,7 +2649,12 @@ dump_dwarf (bfd *abfd) else if (bfd_little_endian (abfd)) byte_get = byte_get_little_endian; else - abort (); + /* PR 17512: file: objdump-s-endless-loop.tekhex. */ + { + warn (_("File %s does not contain any dwarf debug information\n"), + bfd_get_filename (abfd)); + return; + } switch (bfd_get_arch (abfd)) { @@ -2342,6 +2663,10 @@ dump_dwarf (bfd *abfd) { case bfd_mach_x86_64: case bfd_mach_x86_64_intel_syntax: + case bfd_mach_x86_64_nacl: + case bfd_mach_x64_32: + case bfd_mach_x64_32_intel_syntax: + case bfd_mach_x64_32_nacl: init_dwarf_regnames_x86_64 (); break; @@ -2351,6 +2676,18 @@ dump_dwarf (bfd *abfd) } break; + case bfd_arch_iamcu: + init_dwarf_regnames_iamcu (); + break; + + case bfd_arch_aarch64: + init_dwarf_regnames_aarch64(); + break; + + case bfd_arch_s390: + init_dwarf_regnames_s390 (); + break; + default: break; } @@ -2363,12 +2700,11 @@ dump_dwarf (bfd *abfd) /* Read ABFD's stabs section STABSECT_NAME, and return a pointer to it. Return NULL on failure. */ -static char * +static bfd_byte * read_section_stabs (bfd *abfd, const char *sect_name, bfd_size_type *size_ptr) { asection *stabsect; - bfd_size_type size; - char *contents; + bfd_byte *contents; stabsect = bfd_get_section_by_name (abfd, sect_name); if (stabsect == NULL) @@ -2377,10 +2713,7 @@ read_section_stabs (bfd *abfd, const char *sect_name, bfd_size_type *size_ptr) return FALSE; } - size = bfd_section_size (abfd, stabsect); - contents = (char *) xmalloc (size); - - if (! bfd_get_section_contents (abfd, stabsect, contents, 0, size)) + if (!bfd_malloc_and_get_section (abfd, stabsect, &contents)) { non_fatal (_("reading %s section of %s failed: %s"), sect_name, bfd_get_filename (abfd), @@ -2390,7 +2723,7 @@ read_section_stabs (bfd *abfd, const char *sect_name, bfd_size_type *size_ptr) return NULL; } - *size_ptr = size; + *size_ptr = bfd_section_size (abfd, stabsect); return contents; } @@ -2433,7 +2766,7 @@ print_section_stabs (bfd *abfd, 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 += STABSIZE, i++) + for (i = -1; stabp <= stabs_end - STABSIZE; stabp += STABSIZE, i++) { const char *name; unsigned long strx; @@ -2471,10 +2804,13 @@ print_section_stabs (bfd *abfd, } else { + bfd_size_type amt = strx + file_string_table_offset; + /* Using the (possibly updated) string table offset, print the string (if any) associated with this symbol. */ - if ((strx + file_string_table_offset) < stabstr_size) - printf (" %s", &strtab[strx + file_string_table_offset]); + if (amt < stabstr_size) + /* PR 17512: file: 079-79389-0.001:0.1. */ + printf (" %.*s", (int)(stabstr_size - amt), strtab + amt); else printf (" *"); } @@ -2511,11 +2847,10 @@ find_stabs_section (bfd *abfd, asection *section, void *names) if (strtab == NULL) strtab = read_section_stabs (abfd, sought->string_section_name, &stabstr_size); - + if (strtab) { - stabs = (bfd_byte *) read_section_stabs (abfd, section->name, - &stab_size); + stabs = read_section_stabs (abfd, section->name, &stab_size); if (stabs) print_section_stabs (abfd, section->name, &sought->string_offset); } @@ -2573,7 +2908,6 @@ dump_bfd_header (bfd *abfd) PF (WP_TEXT, "WP_TEXT"); PF (D_PAGED, "D_PAGED"); PF (BFD_IS_RELAXABLE, "BFD_IS_RELAXABLE"); - PF (HAS_LOAD_PAGE, "HAS_LOAD_PAGE"); printf (_("\nstart address 0x")); bfd_printf_vma (abfd, abfd->start_address); printf ("\n"); @@ -2586,6 +2920,57 @@ dump_bfd_private_header (bfd *abfd) bfd_print_private_bfd_data (abfd, stdout); } +static void +dump_target_specific (bfd *abfd) +{ + const struct objdump_private_desc * const *desc; + struct objdump_private_option *opt; + char *e, *b; + + /* Find the desc. */ + for (desc = objdump_private_vectors; *desc != NULL; desc++) + if ((*desc)->filter (abfd)) + break; + + if (*desc == NULL) + { + non_fatal (_("option -P/--private not supported by this file")); + return; + } + + /* Clear all options. */ + for (opt = (*desc)->options; opt->name; opt++) + opt->selected = FALSE; + + /* Decode options. */ + b = dump_private_options; + do + { + e = strchr (b, ','); + + if (e) + *e = 0; + + for (opt = (*desc)->options; opt->name; opt++) + if (strcmp (opt->name, b) == 0) + { + opt->selected = TRUE; + break; + } + if (opt->name == NULL) + non_fatal (_("target specific dump '%s' not supported"), b); + + if (e) + { + *e = ','; + b = e + 1; + } + } + while (e != NULL); + + /* Dump. */ + (*desc)->dump (abfd); +} /* Display a section in hexadecimal format with associated characters. Each line prefixed by the zero padded address. */ @@ -2593,11 +2978,11 @@ dump_bfd_private_header (bfd *abfd) static void dump_section (bfd *abfd, asection *section, void *dummy ATTRIBUTE_UNUSED) { - bfd_byte *data = 0; + bfd_byte *data = NULL; bfd_size_type datasize; - bfd_size_type addr_offset; - bfd_size_type start_offset; - bfd_size_type stop_offset; + bfd_vma addr_offset; + bfd_vma start_offset; + bfd_vma stop_offset; unsigned int opb = bfd_octets_per_byte (abfd); /* Bytes per line. */ const int onaline = 16; @@ -2610,7 +2995,7 @@ dump_section (bfd *abfd, asection *section, void *dummy ATTRIBUTE_UNUSED) if (! process_section_p (section)) return; - + if ((datasize = bfd_section_size (abfd, section)) == 0) return; @@ -2636,7 +3021,7 @@ dump_section (bfd *abfd, asection *section, void *dummy ATTRIBUTE_UNUSED) if (start_offset >= stop_offset) return; - + printf (_("Contents of section %s:"), section->name); if (display_file_offsets) printf (_(" (Starting at file offset: 0x%lx)"), @@ -2645,7 +3030,8 @@ dump_section (bfd *abfd, asection *section, void *dummy ATTRIBUTE_UNUSED) if (!bfd_get_full_section_contents (abfd, section, &data)) { - non_fatal (_("Reading section failed")); + non_fatal (_("Reading section %s failed because: %s"), + section->name, bfd_errmsg (bfd_get_error ())); return; } @@ -2802,6 +3188,7 @@ dump_reloc_set (bfd *abfd, asection *sec, arelent **relpp, long relcount) arelent **p; char *last_filename, *last_functionname; unsigned int last_line; + unsigned int last_discriminator; /* Get column headers lined up reasonably. */ { @@ -2820,14 +3207,17 @@ dump_reloc_set (bfd *abfd, asection *sec, arelent **relpp, long relcount) last_filename = NULL; last_functionname = NULL; last_line = 0; + last_discriminator = 0; for (p = relpp; relcount && *p != NULL; p++, relcount--) { arelent *q = *p; const char *filename, *functionname; unsigned int linenumber; + unsigned int discriminator; const char *sym_name; const char *section_name; + bfd_vma addend2 = 0; if (start_address != (bfd_vma) -1 && q->address < start_address) @@ -2838,8 +3228,9 @@ dump_reloc_set (bfd *abfd, asection *sec, arelent **relpp, long relcount) if (with_line_numbers && sec != NULL - && bfd_find_nearest_line (abfd, sec, syms, q->address, - &filename, &functionname, &linenumber)) + && bfd_find_nearest_line_discriminator (abfd, sec, syms, q->address, + &filename, &functionname, + &linenumber, &discriminator)) { if (functionname != NULL && (last_functionname == NULL @@ -2855,10 +3246,16 @@ dump_reloc_set (bfd *abfd, asection *sec, arelent **relpp, long relcount) && (linenumber != last_line || (filename != NULL && last_filename != NULL - && strcmp (filename, last_filename) != 0))) + && filename_cmp (filename, last_filename) != 0) + || (discriminator != last_discriminator))) { - printf ("%s:%u\n", filename == NULL ? "???" : filename, linenumber); + if (discriminator > 0) + printf ("%s:%u\n", filename == NULL ? "???" : filename, linenumber); + else + printf ("%s:%u (discriminator %u)\n", filename == NULL ? "???" : filename, + linenumber, discriminator); last_line = linenumber; + last_discriminator = discriminator; if (last_filename != NULL) free (last_filename); if (filename == NULL) @@ -2883,7 +3280,37 @@ dump_reloc_set (bfd *abfd, asection *sec, arelent **relpp, long relcount) if (q->howto == NULL) printf (" *unknown* "); else if (q->howto->name) - printf (" %-16s ", q->howto->name); + { + const char *name = q->howto->name; + + /* R_SPARC_OLO10 relocations contain two addends. + But because 'arelent' lacks enough storage to + store them both, the 64-bit ELF Sparc backend + records this as two relocations. One R_SPARC_LO10 + and one R_SPARC_13, both pointing to the same + address. This is merely so that we have some + place to store both addend fields. + + Undo this transformation, otherwise the output + will be confusing. */ + if (abfd->xvec->flavour == bfd_target_elf_flavour + && elf_tdata(abfd)->elf_header->e_machine == EM_SPARCV9 + && relcount > 1 + && !strcmp (q->howto->name, "R_SPARC_LO10")) + { + arelent *q2 = *(p + 1); + if (q2 != NULL + && q2->howto + && q->address == q2->address + && !strcmp (q2->howto->name, "R_SPARC_13")) + { + name = "R_SPARC_OLO10"; + addend2 = q2->addend; + p++; + } + } + printf (" %-16s ", name); + } else printf (" %-16d ", q->howto->type); @@ -2899,13 +3326,30 @@ dump_reloc_set (bfd *abfd, asection *sec, arelent **relpp, long relcount) } if (q->addend) + { + bfd_signed_vma addend = q->addend; + if (addend < 0) + { + printf ("-0x"); + addend = -addend; + } + else + printf ("+0x"); + bfd_printf_vma (abfd, addend); + } + if (addend2) { printf ("+0x"); - bfd_printf_vma (abfd, q->addend); + bfd_printf_vma (abfd, addend2); } printf ("\n"); } + + if (last_filename != NULL) + free (last_filename); + if (last_functionname != NULL) + free (last_functionname); } static void @@ -2936,11 +3380,23 @@ dump_relocs_in_section (bfd *abfd, return; } + if ((bfd_get_file_flags (abfd) & (BFD_IN_MEMORY | BFD_LINKER_CREATED)) == 0 + && (ufile_ptr) relsize > bfd_get_file_size (abfd)) + { + printf (" (too many: 0x%x)\n", section->reloc_count); + bfd_set_error (bfd_error_file_truncated); + bfd_fatal (bfd_get_filename (abfd)); + } + relpp = (arelent **) xmalloc (relsize); relcount = bfd_canonicalize_reloc (abfd, section, relpp, syms); if (relcount < 0) - bfd_fatal (bfd_get_filename (abfd)); + { + printf ("\n"); + non_fatal (_("failed to read relocs in: %s"), bfd_get_filename (abfd)); + bfd_fatal (_("error message was")); + } else if (relcount == 0) printf (" (none)\n\n"); else @@ -3037,7 +3493,7 @@ dump_bfd (bfd *abfd) bfd_map_over_sections (abfd, adjust_addresses, &has_reloc); } - if (! dump_debugging_tags) + if (! dump_debugging_tags && ! suppress_bfd_header) printf (_("\n%s: file format %s\n"), bfd_get_filename (abfd), abfd->xvec->name); if (dump_ar_hdrs) @@ -3046,10 +3502,10 @@ dump_bfd (bfd *abfd) dump_bfd_header (abfd); if (dump_private_headers) dump_bfd_private_header (abfd); - if (! dump_debugging_tags) + if (dump_private_options != NULL) + dump_target_specific (abfd); + if (! dump_debugging_tags && ! suppress_bfd_header) putchar ('\n'); - if (dump_section_headers) - dump_headers (abfd); if (dump_symtab || dump_reloc_info @@ -3057,6 +3513,10 @@ dump_bfd (bfd *abfd) || dump_debugging || dump_dwarf_section_info) syms = slurp_symtab (abfd); + + if (dump_section_headers) + dump_headers (abfd); + if (dump_dynamic_symtab || dump_dynamic_reloc_info || (disassemble && bfd_get_dynamic_symtab_upper_bound (abfd) > 0)) dynsyms = slurp_dynamic_symtab (abfd); @@ -3105,6 +3565,7 @@ dump_bfd (bfd *abfd) info in the file, try DWARF instead. */ else if (! dump_dwarf_section_info) { + dwarf_select_sections_all (); dump_dwarf (abfd); } } @@ -3133,7 +3594,7 @@ dump_bfd (bfd *abfd) } static void -display_bfd (bfd *abfd) +display_object_bfd (bfd *abfd) { char **matching; @@ -3173,24 +3634,8 @@ display_bfd (bfd *abfd) } static void -display_file (char *filename, char *target) +display_any_bfd (bfd *file, int level) { - bfd *file; - bfd *arfile = NULL; - - if (get_file_size (filename) < 1) - { - exit_status = 1; - return; - } - - file = bfd_openr (filename, target); - if (file == NULL) - { - nonfatal (filename); - return; - } - /* Decompress sections unless dumping the section contents. */ if (!dump_section_contents) file->flags |= BFD_DECOMPRESS; @@ -3198,9 +3643,21 @@ display_file (char *filename, char *target) /* If the file is an archive, process all of its elements. */ if (bfd_check_format (file, bfd_archive)) { + bfd *arfile = NULL; bfd *last_arfile = NULL; - printf (_("In archive %s:\n"), bfd_get_filename (file)); + if (level == 0) + printf (_("In archive %s:\n"), bfd_get_filename (file)); + else if (level > 100) + { + /* Prevent corrupted files from spinning us into an + infinite loop. 100 is an arbitrary heuristic. */ + fatal (_("Archive nesting is too deep")); + return; + } + else + printf (_("In nested archive %s:\n"), bfd_get_filename (file)); + for (;;) { bfd_set_error (bfd_error_no_error); @@ -3213,10 +3670,18 @@ display_file (char *filename, char *target) break; } - display_bfd (arfile); + display_any_bfd (arfile, level + 1); if (last_arfile != NULL) - bfd_close (last_arfile); + { + bfd_close (last_arfile); + /* PR 17512: file: ac585d01. */ + if (arfile == last_arfile) + { + last_arfile = NULL; + break; + } + } last_arfile = arfile; } @@ -3224,9 +3689,41 @@ display_file (char *filename, char *target) bfd_close (last_arfile); } else - display_bfd (file); + display_object_bfd (file); +} + +static void +display_file (char *filename, char *target, bfd_boolean last_file) +{ + bfd *file; + + if (get_file_size (filename) < 1) + { + exit_status = 1; + return; + } + + file = bfd_openr (filename, target); + if (file == NULL) + { + nonfatal (filename); + return; + } + + display_any_bfd (file, 0); - bfd_close (file); + /* This is an optimization to improve the speed of objdump, especially when + dumping a file with lots of associated debug informatiom. Calling + bfd_close on such a file can take a non-trivial amount of time as there + are lots of lists to walk and buffers to free. This is only really + necessary however if we are about to load another file and we need the + memory back. Otherwise, if we are about to exit, then we can save (a lot + of) time by only doing a quick close, and allowing the OS to reclaim the + memory for us. */ + if (! last_file) + bfd_close (file); + else + bfd_close_all_done (file); } int @@ -3248,6 +3745,7 @@ main (int argc, char **argv) program_name = *argv; xmalloc_set_program_name (program_name); + bfd_set_error_program_name (program_name); START_PROGRESS (program_name, 0); @@ -3257,7 +3755,7 @@ main (int argc, char **argv) set_default_bfd_target (); while ((c = getopt_long (argc, argv, - "pib:m:M:VvCdDlfFaHhrRtTxsSI:j:wE:zgeGW::", + "pP:ib:m:M:VvCdDlfFaHhrRtTxsSI:j:wE:zgeGW::", long_options, (int *) 0)) != EOF) { @@ -3269,12 +3767,16 @@ main (int argc, char **argv) machine = optarg; break; case 'M': - if (disassembler_options) - /* Ignore potential memory leak for now. */ - disassembler_options = concat (disassembler_options, ",", - optarg, (const char *) NULL); - else - disassembler_options = optarg; + { + char *options; + if (disassembler_options) + /* Ignore potential memory leak for now. */ + options = concat (disassembler_options, ",", + optarg, (const char *) NULL); + else + options = optarg; + disassembler_options = remove_whitespace_and_extra_commas (options); + } break; case 'j': add_only (optarg); @@ -3303,7 +3805,7 @@ main (int argc, char **argv) } break; case 'w': - wide_output = TRUE; + do_wide = wide_output = TRUE; break; case OPTION_ADJUST_VMA: adjust_section_vma = parse_vma (optarg, "--adjust-vma"); @@ -3335,6 +3837,9 @@ main (int argc, char **argv) if (insn_width <= 0) fatal (_("error: instruction width must be positive")); break; + case OPTION_INLINES: + unwind_inlines = TRUE; + break; case 'E': if (strcmp (optarg, "B") == 0) endian = BFD_ENDIAN_BIG; @@ -3374,6 +3879,10 @@ main (int argc, char **argv) dump_private_headers = TRUE; seenflag = TRUE; break; + case 'P': + dump_private_options = optarg; + seenflag = TRUE; + break; case 'x': dump_private_headers = TRUE; dump_symtab = TRUE; @@ -3434,6 +3943,22 @@ main (int argc, char **argv) else dwarf_select_sections_all (); break; + case OPTION_DWARF_DEPTH: + { + char *cp; + dwarf_cutoff_level = strtoul (optarg, & cp, 0); + } + break; + case OPTION_DWARF_START: + { + char *cp; + dwarf_start_die = strtoul (optarg, & cp, 0); + suppress_bfd_header = 1; + } + break; + case OPTION_DWARF_CHECK: + dwarf_check = TRUE; + break; case 'G': dump_stab_section_info = TRUE; seenflag = TRUE; @@ -3458,15 +3983,15 @@ main (int argc, char **argv) dump_section_headers = TRUE; seenflag = TRUE; break; - case 'H': - usage (stdout, 0); - seenflag = TRUE; case 'v': case 'V': show_version = TRUE; seenflag = TRUE; break; + case 'H': + usage (stdout, 0); + /* No need to set seenflag or to break - usage() does not return. */ default: usage (stderr, 1); } @@ -3483,10 +4008,13 @@ main (int argc, char **argv) else { if (optind == argc) - display_file ("a.out", target); + display_file ("a.out", target, TRUE); else for (; optind < argc;) - display_file (argv[optind++], target); + { + display_file (argv[optind], target, optind == argc - 1); + optind++; + } } free_only_list ();