160484Sobrien/* readelf.c -- display contents of an ELF format file 2218822Sdim Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 3218822Sdim Free Software Foundation, Inc. 460484Sobrien 560484Sobrien Originally developed by Eric Youngdale <eric@andante.jic.com> 680016Sobrien Modifications by Nick Clifton <nickc@redhat.com> 760484Sobrien 860484Sobrien This file is part of GNU Binutils. 960484Sobrien 1060484Sobrien This program is free software; you can redistribute it and/or modify 1160484Sobrien it under the terms of the GNU General Public License as published by 1260484Sobrien the Free Software Foundation; either version 2 of the License, or 1360484Sobrien (at your option) any later version. 1460484Sobrien 1560484Sobrien This program is distributed in the hope that it will be useful, 1660484Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 1760484Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1860484Sobrien GNU General Public License for more details. 1960484Sobrien 2060484Sobrien You should have received a copy of the GNU General Public License 2160484Sobrien along with this program; if not, write to the Free Software 22218822Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 23218822Sdim 02110-1301, USA. */ 2460484Sobrien 25130561Sobrien/* The difference between readelf and objdump: 2660484Sobrien 27218822Sdim Both programs are capable of displaying the contents of ELF format files, 28130561Sobrien so why does the binutils project have two file dumpers ? 29130561Sobrien 30130561Sobrien The reason is that objdump sees an ELF file through a BFD filter of the 31130561Sobrien world; if BFD has a bug where, say, it disagrees about a machine constant 32130561Sobrien in e_flags, then the odds are good that it will remain internally 33130561Sobrien consistent. The linker sees it the BFD way, objdump sees it the BFD way, 34130561Sobrien GAS sees it the BFD way. There was need for a tool to go find out what 35130561Sobrien the file actually says. 36130561Sobrien 37130561Sobrien This is why the readelf program does not link against the BFD library - it 38130561Sobrien exists as an independent program to help verify the correct working of BFD. 39130561Sobrien 40130561Sobrien There is also the case that readelf can provide more information about an 41130561Sobrien ELF file than is provided by objdump. In particular it can display DWARF 42130561Sobrien debugging information which (at the moment) objdump cannot. */ 43130561Sobrien 44218822Sdim#include "sysdep.h" 4560484Sobrien#include <assert.h> 4660484Sobrien#include <sys/stat.h> 4760484Sobrien#include <time.h> 4860484Sobrien 49218822Sdim/* for PATH_MAX */ 50218822Sdim#ifdef HAVE_LIMITS_H 51218822Sdim#include <limits.h> 52218822Sdim#endif 53218822Sdim 54218822Sdim#ifndef PATH_MAX 55218822Sdim/* for MAXPATHLEN */ 56218822Sdim# ifdef HAVE_SYS_PARAM_H 57218822Sdim# include <sys/param.h> 58218822Sdim# endif 59218822Sdim# ifndef PATH_MAX 60218822Sdim# ifdef MAXPATHLEN 61218822Sdim# define PATH_MAX MAXPATHLEN 62218822Sdim# else 63218822Sdim# define PATH_MAX 1024 64218822Sdim# endif 65218822Sdim# endif 66218822Sdim#endif 67218822Sdim 6860484Sobrien#if __GNUC__ >= 2 6960484Sobrien/* Define BFD64 here, even if our default architecture is 32 bit ELF 7060484Sobrien as this will allow us to read in and parse 64bit and 32bit ELF files. 71130561Sobrien Only do this if we believe that the compiler can support a 64 bit 7260484Sobrien data type. For now we only rely on GCC being able to do this. */ 7360484Sobrien#define BFD64 7460484Sobrien#endif 7560484Sobrien 7660484Sobrien#include "bfd.h" 77218822Sdim#include "bucomm.h" 78218822Sdim#include "dwarf.h" 7960484Sobrien 8060484Sobrien#include "elf/common.h" 8160484Sobrien#include "elf/external.h" 8260484Sobrien#include "elf/internal.h" 8360484Sobrien 84218822Sdim 85218822Sdim/* Included here, before RELOC_MACROS_GEN_FUNC is defined, so that 86218822Sdim we can obtain the H8 reloc numbers. We need these for the 87218822Sdim get_reloc_size() function. We include h8.h again after defining 88218822Sdim RELOC_MACROS_GEN_FUNC so that we get the naming function as well. */ 89218822Sdim 90218822Sdim#include "elf/h8.h" 91218822Sdim#undef _ELF_H8_H 92218822Sdim 93218822Sdim/* Undo the effects of #including reloc-macros.h. */ 94218822Sdim 95218822Sdim#undef START_RELOC_NUMBERS 96218822Sdim#undef RELOC_NUMBER 97218822Sdim#undef FAKE_RELOC 98218822Sdim#undef EMPTY_RELOC 99218822Sdim#undef END_RELOC_NUMBERS 100218822Sdim#undef _RELOC_MACROS_H 101218822Sdim 10260484Sobrien/* The following headers use the elf/reloc-macros.h file to 10360484Sobrien automatically generate relocation recognition functions 10460484Sobrien such as elf_mips_reloc_type() */ 10560484Sobrien 10660484Sobrien#define RELOC_MACROS_GEN_FUNC 10760484Sobrien 10860484Sobrien#include "elf/alpha.h" 10991041Sobrien#include "elf/arc.h" 11060484Sobrien#include "elf/arm.h" 11191041Sobrien#include "elf/avr.h" 112218822Sdim#include "elf/bfin.h" 11391041Sobrien#include "elf/cris.h" 114218822Sdim#include "elf/crx.h" 11560484Sobrien#include "elf/d10v.h" 11660484Sobrien#include "elf/d30v.h" 117104834Sobrien#include "elf/dlx.h" 11891041Sobrien#include "elf/fr30.h" 119104834Sobrien#include "elf/frv.h" 12091041Sobrien#include "elf/h8.h" 12160484Sobrien#include "elf/hppa.h" 12291041Sobrien#include "elf/i386.h" 123130561Sobrien#include "elf/i370.h" 12491041Sobrien#include "elf/i860.h" 12591041Sobrien#include "elf/i960.h" 12691041Sobrien#include "elf/ia64.h" 127130561Sobrien#include "elf/ip2k.h" 128218822Sdim#include "elf/iq2000.h" 129218822Sdim#include "elf/m32c.h" 13091041Sobrien#include "elf/m32r.h" 13191041Sobrien#include "elf/m68k.h" 132104834Sobrien#include "elf/m68hc11.h" 13360484Sobrien#include "elf/mcore.h" 134218822Sdim#include "elf/mep.h" 13591041Sobrien#include "elf/mips.h" 13689857Sobrien#include "elf/mmix.h" 13791041Sobrien#include "elf/mn10200.h" 13891041Sobrien#include "elf/mn10300.h" 139218822Sdim#include "elf/mt.h" 140130561Sobrien#include "elf/msp430.h" 14191041Sobrien#include "elf/or32.h" 14260484Sobrien#include "elf/pj.h" 14391041Sobrien#include "elf/ppc.h" 144130561Sobrien#include "elf/ppc64.h" 14591041Sobrien#include "elf/s390.h" 146218822Sdim#include "elf/score.h" 14791041Sobrien#include "elf/sh.h" 14891041Sobrien#include "elf/sparc.h" 149218822Sdim#include "elf/spu.h" 15091041Sobrien#include "elf/v850.h" 151104834Sobrien#include "elf/vax.h" 15277298Sobrien#include "elf/x86-64.h" 15389857Sobrien#include "elf/xstormy16.h" 154130561Sobrien#include "elf/xtensa.h" 15560484Sobrien 156130561Sobrien#include "aout/ar.h" 157130561Sobrien 15860484Sobrien#include "getopt.h" 159130561Sobrien#include "libiberty.h" 16060484Sobrien 161130561Sobrienchar *program_name = "readelf"; 162218822Sdimstatic long archive_file_offset; 163218822Sdimstatic unsigned long archive_file_size; 164218822Sdimstatic unsigned long dynamic_addr; 165218822Sdimstatic bfd_size_type dynamic_size; 166218822Sdimstatic unsigned int dynamic_nent; 167218822Sdimstatic char *dynamic_strings; 168218822Sdimstatic unsigned long dynamic_strings_length; 169218822Sdimstatic char *string_table; 170218822Sdimstatic unsigned long string_table_length; 171218822Sdimstatic unsigned long num_dynamic_syms; 172218822Sdimstatic Elf_Internal_Sym *dynamic_symbols; 173218822Sdimstatic Elf_Internal_Syminfo *dynamic_syminfo; 174218822Sdimstatic unsigned long dynamic_syminfo_offset; 175218822Sdimstatic unsigned int dynamic_syminfo_nent; 176218822Sdimstatic char program_interpreter[PATH_MAX]; 177240208Sdimstatic bfd_vma dynamic_info[DT_ENCODING]; 178218822Sdimstatic bfd_vma dynamic_info_DT_GNU_HASH; 179218822Sdimstatic bfd_vma version_info[16]; 180218822Sdimstatic Elf_Internal_Ehdr elf_header; 181218822Sdimstatic Elf_Internal_Shdr *section_headers; 182218822Sdimstatic Elf_Internal_Phdr *program_headers; 183218822Sdimstatic Elf_Internal_Dyn *dynamic_section; 184218822Sdimstatic Elf_Internal_Shdr *symtab_shndx_hdr; 185218822Sdimstatic int show_name; 186218822Sdimstatic int do_dynamic; 187218822Sdimstatic int do_syms; 188218822Sdimstatic int do_reloc; 189218822Sdimstatic int do_sections; 190218822Sdimstatic int do_section_groups; 191218822Sdimstatic int do_section_details; 192218822Sdimstatic int do_segments; 193218822Sdimstatic int do_unwind; 194218822Sdimstatic int do_using_dynamic; 195218822Sdimstatic int do_header; 196218822Sdimstatic int do_dump; 197218822Sdimstatic int do_version; 198218822Sdimstatic int do_wide; 199218822Sdimstatic int do_histogram; 200218822Sdimstatic int do_debugging; 201218822Sdimstatic int do_arch; 202218822Sdimstatic int do_notes; 203218822Sdimstatic int is_32bit_elf; 20460484Sobrien 205218822Sdimstruct group_list 206218822Sdim{ 207218822Sdim struct group_list *next; 208218822Sdim unsigned int section_index; 209218822Sdim}; 210218822Sdim 211218822Sdimstruct group 212218822Sdim{ 213218822Sdim struct group_list *root; 214218822Sdim unsigned int group_index; 215218822Sdim}; 216218822Sdim 217218822Sdimstatic size_t group_count; 218218822Sdimstatic struct group *section_groups; 219218822Sdimstatic struct group **section_headers_groups; 220218822Sdim 221218822Sdim/* A linked list of the section names for which dumps were requested 222218822Sdim by name. */ 223218822Sdimstruct dump_list_entry 224218822Sdim{ 225218822Sdim char *name; 226218822Sdim int type; 227218822Sdim struct dump_list_entry *next; 228218822Sdim}; 229218822Sdimstatic struct dump_list_entry *dump_sects_byname; 230218822Sdim 231218822Sdim/* A dynamic array of flags indicating for which sections a hex dump 232218822Sdim has been requested (via the -x switch) and/or a disassembly dump 233218822Sdim (via the -i switch). */ 234218822Sdimchar *cmdline_dump_sects = NULL; 235218822Sdimunsigned num_cmdline_dump_sects = 0; 236218822Sdim 237218822Sdim/* A dynamic array of flags indicating for which sections a dump of 238218822Sdim some kind has been requested. It is reset on a per-object file 239218822Sdim basis and then initialised from the cmdline_dump_sects array, 240218822Sdim the results of interpreting the -w switch, and the 241218822Sdim dump_sects_byname list. */ 242130561Sobrienchar *dump_sects = NULL; 243130561Sobrienunsigned int num_dump_sects = 0; 24460484Sobrien 24560484Sobrien#define HEX_DUMP (1 << 0) 24660484Sobrien#define DISASS_DUMP (1 << 1) 24760484Sobrien#define DEBUG_DUMP (1 << 2) 24860484Sobrien 249218822Sdim/* How to print a vma value. */ 25060484Sobrientypedef enum print_mode 25160484Sobrien{ 25260484Sobrien HEX, 25360484Sobrien DEC, 25460484Sobrien DEC_5, 25560484Sobrien UNSIGNED, 25660484Sobrien PREFIX_HEX, 25760484Sobrien FULL_HEX, 25860484Sobrien LONG_HEX 25960484Sobrien} 26060484Sobrienprint_mode; 26160484Sobrien 262130561Sobrienstatic void (*byte_put) (unsigned char *, bfd_vma, int); 26360484Sobrien 26460484Sobrien#define UNKNOWN -1 26560484Sobrien 266218822Sdim#define SECTION_NAME(X) \ 267218822Sdim ((X) == NULL ? "<none>" \ 268218822Sdim : string_table == NULL ? "<no-name>" \ 269218822Sdim : ((X)->sh_name >= string_table_length ? "<corrupt>" \ 270218822Sdim : string_table + (X)->sh_name)) 27160484Sobrien 27289857Sobrien/* Given st_shndx I, map to section_headers index. */ 27389857Sobrien#define SECTION_HEADER_INDEX(I) \ 27489857Sobrien ((I) < SHN_LORESERVE \ 27589857Sobrien ? (I) \ 27689857Sobrien : ((I) <= SHN_HIRESERVE \ 27789857Sobrien ? 0 \ 27889857Sobrien : (I) - (SHN_HIRESERVE + 1 - SHN_LORESERVE))) 27989857Sobrien 28089857Sobrien/* Reverse of the above. */ 28189857Sobrien#define SECTION_HEADER_NUM(N) \ 28289857Sobrien ((N) < SHN_LORESERVE \ 28389857Sobrien ? (N) \ 28489857Sobrien : (N) + (SHN_HIRESERVE + 1 - SHN_LORESERVE)) 28589857Sobrien 28689857Sobrien#define SECTION_HEADER(I) (section_headers + SECTION_HEADER_INDEX (I)) 28789857Sobrien 288130561Sobrien#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ 28960484Sobrien 29078828Sobrien#define BYTE_GET(field) byte_get (field, sizeof (field)) 29160484Sobrien 29289857Sobrien#define NUM_ELEM(array) (sizeof (array) / sizeof ((array)[0])) 29360484Sobrien 29489857Sobrien#define GET_ELF_SYMBOLS(file, section) \ 29589857Sobrien (is_32bit_elf ? get_32bit_elf_symbols (file, section) \ 29689857Sobrien : get_64bit_elf_symbols (file, section)) 29760484Sobrien 298218822Sdim#define VALID_DYNAMIC_NAME(offset) ((dynamic_strings != NULL) && (offset < dynamic_strings_length)) 299218822Sdim/* GET_DYNAMIC_NAME asssumes that VALID_DYNAMIC_NAME has 300218822Sdim already been called and verified that the string exists. */ 301218822Sdim#define GET_DYNAMIC_NAME(offset) (dynamic_strings + offset) 30260484Sobrien 303218822Sdim/* This is just a bit of syntatic sugar. */ 304218822Sdim#define streq(a,b) (strcmp ((a), (b)) == 0) 305218822Sdim#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) 306218822Sdim#define const_strneq(a,b) (strncmp ((a), (b), sizeof (b) - 1) == 0) 307218822Sdim 308130561Sobrienstatic void * 309218822Sdimget_data (void *var, FILE *file, long offset, size_t size, size_t nmemb, 310218822Sdim const char *reason) 31160484Sobrien{ 312130561Sobrien void *mvar; 31360484Sobrien 314218822Sdim if (size == 0 || nmemb == 0) 31589857Sobrien return NULL; 31689857Sobrien 317130561Sobrien if (fseek (file, archive_file_offset + offset, SEEK_SET)) 31889857Sobrien { 319218822Sdim error (_("Unable to seek to 0x%lx for %s\n"), 320130561Sobrien archive_file_offset + offset, reason); 32189857Sobrien return NULL; 32289857Sobrien } 32389857Sobrien 32489857Sobrien mvar = var; 32589857Sobrien if (mvar == NULL) 32689857Sobrien { 327218822Sdim /* Check for overflow. */ 328218822Sdim if (nmemb < (~(size_t) 0 - 1) / size) 329218822Sdim /* + 1 so that we can '\0' terminate invalid string table sections. */ 330218822Sdim mvar = malloc (size * nmemb + 1); 33189857Sobrien 33289857Sobrien if (mvar == NULL) 33389857Sobrien { 334218822Sdim error (_("Out of memory allocating 0x%lx bytes for %s\n"), 335218822Sdim (unsigned long)(size * nmemb), reason); 33689857Sobrien return NULL; 33789857Sobrien } 338218822Sdim 339218822Sdim ((char *) mvar)[size * nmemb] = '\0'; 34089857Sobrien } 34189857Sobrien 342218822Sdim if (fread (mvar, size, nmemb, file) != nmemb) 34389857Sobrien { 344218822Sdim error (_("Unable to read in 0x%lx bytes of %s\n"), 345218822Sdim (unsigned long)(size * nmemb), reason); 34689857Sobrien if (mvar != var) 34789857Sobrien free (mvar); 34889857Sobrien return NULL; 34989857Sobrien } 35089857Sobrien 35189857Sobrien return mvar; 35260484Sobrien} 35360484Sobrien 354130561Sobrienstatic void 355130561Sobrienbyte_put_little_endian (unsigned char *field, bfd_vma value, int size) 356130561Sobrien{ 357130561Sobrien switch (size) 358130561Sobrien { 359130561Sobrien case 8: 360130561Sobrien field[7] = (((value >> 24) >> 24) >> 8) & 0xff; 361130561Sobrien field[6] = ((value >> 24) >> 24) & 0xff; 362130561Sobrien field[5] = ((value >> 24) >> 16) & 0xff; 363130561Sobrien field[4] = ((value >> 24) >> 8) & 0xff; 364130561Sobrien /* Fall through. */ 365130561Sobrien case 4: 366130561Sobrien field[3] = (value >> 24) & 0xff; 367130561Sobrien field[2] = (value >> 16) & 0xff; 368130561Sobrien /* Fall through. */ 369130561Sobrien case 2: 370130561Sobrien field[1] = (value >> 8) & 0xff; 371130561Sobrien /* Fall through. */ 372130561Sobrien case 1: 373130561Sobrien field[0] = value & 0xff; 374130561Sobrien break; 375130561Sobrien 376130561Sobrien default: 377130561Sobrien error (_("Unhandled data length: %d\n"), size); 378130561Sobrien abort (); 379130561Sobrien } 380130561Sobrien} 381130561Sobrien 382218822Sdim#if defined BFD64 && !BFD_HOST_64BIT_LONG 383218822Sdimstatic int 384218822Sdimprint_dec_vma (bfd_vma vma, int is_signed) 385218822Sdim{ 386218822Sdim char buf[40]; 387218822Sdim char *bufp = buf; 388218822Sdim int nc = 0; 389218822Sdim 390218822Sdim if (is_signed && (bfd_signed_vma) vma < 0) 391218822Sdim { 392218822Sdim vma = -vma; 393218822Sdim putchar ('-'); 394218822Sdim nc = 1; 395218822Sdim } 396218822Sdim 397218822Sdim do 398218822Sdim { 399218822Sdim *bufp++ = '0' + vma % 10; 400218822Sdim vma /= 10; 401218822Sdim } 402218822Sdim while (vma != 0); 403218822Sdim nc += bufp - buf; 404218822Sdim 405218822Sdim while (bufp > buf) 406218822Sdim putchar (*--bufp); 407218822Sdim return nc; 408218822Sdim} 409218822Sdim 410218822Sdimstatic int 411218822Sdimprint_hex_vma (bfd_vma vma) 412218822Sdim{ 413218822Sdim char buf[32]; 414218822Sdim char *bufp = buf; 415218822Sdim int nc; 416218822Sdim 417218822Sdim do 418218822Sdim { 419218822Sdim char digit = '0' + (vma & 0x0f); 420218822Sdim if (digit > '9') 421218822Sdim digit += 'a' - '0' - 10; 422218822Sdim *bufp++ = digit; 423218822Sdim vma >>= 4; 424218822Sdim } 425218822Sdim while (vma != 0); 426218822Sdim nc = bufp - buf; 427218822Sdim 428218822Sdim while (bufp > buf) 429218822Sdim putchar (*--bufp); 430218822Sdim return nc; 431218822Sdim} 432218822Sdim#endif 433218822Sdim 43460484Sobrien/* Print a VMA value. */ 435218822Sdimstatic int 436130561Sobrienprint_vma (bfd_vma vma, print_mode mode) 43760484Sobrien{ 43860484Sobrien#ifdef BFD64 43960484Sobrien if (is_32bit_elf) 44060484Sobrien#endif 44160484Sobrien { 44260484Sobrien switch (mode) 44360484Sobrien { 444130561Sobrien case FULL_HEX: 445218822Sdim return printf ("0x%8.8lx", (unsigned long) vma); 446218822Sdim 447130561Sobrien case LONG_HEX: 448218822Sdim return printf ("%8.8lx", (unsigned long) vma); 449130561Sobrien 450130561Sobrien case DEC_5: 451130561Sobrien if (vma <= 99999) 452218822Sdim return printf ("%5ld", (long) vma); 453130561Sobrien /* Drop through. */ 454218822Sdim 455130561Sobrien case PREFIX_HEX: 456218822Sdim return printf ("0x%lx", (unsigned long) vma); 457218822Sdim 458130561Sobrien case HEX: 459218822Sdim return printf ("%lx", (unsigned long) vma); 460130561Sobrien 461130561Sobrien case DEC: 462218822Sdim return printf ("%ld", (unsigned long) vma); 463130561Sobrien 464130561Sobrien case UNSIGNED: 465218822Sdim return printf ("%lu", (unsigned long) vma); 46660484Sobrien } 46760484Sobrien } 46860484Sobrien#ifdef BFD64 46960484Sobrien else 47060484Sobrien { 471218822Sdim int nc = 0; 472218822Sdim 47360484Sobrien switch (mode) 47460484Sobrien { 47560484Sobrien case FULL_HEX: 476218822Sdim nc = printf ("0x"); 477130561Sobrien /* Drop through. */ 47877298Sobrien 47960484Sobrien case LONG_HEX: 48060484Sobrien printf_vma (vma); 481218822Sdim return nc + 16; 48277298Sobrien 48360484Sobrien case PREFIX_HEX: 484218822Sdim nc = printf ("0x"); 485130561Sobrien /* Drop through. */ 48677298Sobrien 48760484Sobrien case HEX: 48860484Sobrien#if BFD_HOST_64BIT_LONG 489218822Sdim return nc + printf ("%lx", vma); 49060484Sobrien#else 491218822Sdim return nc + print_hex_vma (vma); 49260484Sobrien#endif 49360484Sobrien 49460484Sobrien case DEC: 49560484Sobrien#if BFD_HOST_64BIT_LONG 496218822Sdim return printf ("%ld", vma); 49760484Sobrien#else 498218822Sdim return print_dec_vma (vma, 1); 49977298Sobrien#endif 50060484Sobrien 50160484Sobrien case DEC_5: 50260484Sobrien#if BFD_HOST_64BIT_LONG 503130561Sobrien if (vma <= 99999) 504218822Sdim return printf ("%5ld", vma); 505130561Sobrien else 506218822Sdim return printf ("%#lx", vma); 50760484Sobrien#else 508218822Sdim if (vma <= 99999) 509218822Sdim return printf ("%5ld", _bfd_int64_low (vma)); 51060484Sobrien else 511218822Sdim return print_hex_vma (vma); 51277298Sobrien#endif 51377298Sobrien 51460484Sobrien case UNSIGNED: 51560484Sobrien#if BFD_HOST_64BIT_LONG 516218822Sdim return printf ("%lu", vma); 51777298Sobrien#else 518218822Sdim return print_dec_vma (vma, 0); 51960484Sobrien#endif 52060484Sobrien } 52160484Sobrien } 52260484Sobrien#endif 523218822Sdim return 0; 52460484Sobrien} 52560484Sobrien 52689857Sobrien/* Display a symbol on stdout. If do_wide is not true then 52789857Sobrien format the symbol to be at most WIDTH characters, 528104834Sobrien truncating as necessary. If WIDTH is negative then 52989857Sobrien format the string to be exactly - WIDTH characters, 53089857Sobrien truncating or padding as necessary. */ 53189857Sobrien 53289857Sobrienstatic void 533130561Sobrienprint_symbol (int width, const char *symbol) 53489857Sobrien{ 53589857Sobrien if (do_wide) 536130561Sobrien printf ("%s", symbol); 53789857Sobrien else if (width < 0) 53889857Sobrien printf ("%-*.*s", width, width, symbol); 539104834Sobrien else 54089857Sobrien printf ("%-.*s", width, symbol); 54189857Sobrien} 54289857Sobrien 543130561Sobrienstatic void 544130561Sobrienbyte_put_big_endian (unsigned char *field, bfd_vma value, int size) 545130561Sobrien{ 546130561Sobrien switch (size) 547130561Sobrien { 548130561Sobrien case 8: 549130561Sobrien field[7] = value & 0xff; 550130561Sobrien field[6] = (value >> 8) & 0xff; 551130561Sobrien field[5] = (value >> 16) & 0xff; 552130561Sobrien field[4] = (value >> 24) & 0xff; 553130561Sobrien value >>= 16; 554130561Sobrien value >>= 16; 555130561Sobrien /* Fall through. */ 556130561Sobrien case 4: 557130561Sobrien field[3] = value & 0xff; 558130561Sobrien field[2] = (value >> 8) & 0xff; 559130561Sobrien value >>= 16; 560130561Sobrien /* Fall through. */ 561130561Sobrien case 2: 562130561Sobrien field[1] = value & 0xff; 563130561Sobrien value >>= 8; 564130561Sobrien /* Fall through. */ 565130561Sobrien case 1: 566130561Sobrien field[0] = value & 0xff; 567130561Sobrien break; 568130561Sobrien 569130561Sobrien default: 570130561Sobrien error (_("Unhandled data length: %d\n"), size); 571130561Sobrien abort (); 572130561Sobrien } 573130561Sobrien} 574130561Sobrien 575218822Sdim/* Return a pointer to section NAME, or NULL if no such section exists. */ 576218822Sdim 577218822Sdimstatic Elf_Internal_Shdr * 578218822Sdimfind_section (const char *name) 579218822Sdim{ 580218822Sdim unsigned int i; 581218822Sdim 582218822Sdim for (i = 0; i < elf_header.e_shnum; i++) 583218822Sdim if (streq (SECTION_NAME (section_headers + i), name)) 584218822Sdim return section_headers + i; 585218822Sdim 586218822Sdim return NULL; 587218822Sdim} 588218822Sdim 58977298Sobrien/* Guess the relocation size commonly used by the specific machines. */ 59060484Sobrien 59160484Sobrienstatic int 592130561Sobrienguess_is_rela (unsigned long e_machine) 59360484Sobrien{ 59460484Sobrien switch (e_machine) 59560484Sobrien { 59660484Sobrien /* Targets that use REL relocations. */ 59760484Sobrien case EM_386: 59860484Sobrien case EM_486: 59960484Sobrien case EM_960: 600218822Sdim case EM_ARM: 60189857Sobrien case EM_D10V: 60260484Sobrien case EM_CYGNUS_D10V: 603218822Sdim case EM_DLX: 60460484Sobrien case EM_MIPS: 60578828Sobrien case EM_MIPS_RS3_LE: 606218822Sdim case EM_CYGNUS_M32R: 607218822Sdim case EM_OPENRISC: 608218822Sdim case EM_OR32: 609218822Sdim case EM_SCORE: 61060484Sobrien return FALSE; 61160484Sobrien 61260484Sobrien /* Targets that use RELA relocations. */ 61360484Sobrien case EM_68K: 614218822Sdim case EM_860: 615218822Sdim case EM_ALPHA: 616218822Sdim case EM_ALTERA_NIOS2: 617218822Sdim case EM_AVR: 618218822Sdim case EM_AVR_OLD: 619218822Sdim case EM_BLACKFIN: 620218822Sdim case EM_CRIS: 621218822Sdim case EM_CRX: 62289857Sobrien case EM_D30V: 62360484Sobrien case EM_CYGNUS_D30V: 62489857Sobrien case EM_FR30: 62560484Sobrien case EM_CYGNUS_FR30: 626104834Sobrien case EM_CYGNUS_FRV: 627218822Sdim case EM_H8S: 628218822Sdim case EM_H8_300: 629218822Sdim case EM_H8_300H: 630218822Sdim case EM_IA_64: 631218822Sdim case EM_IP2K: 632218822Sdim case EM_IP2K_OLD: 633218822Sdim case EM_IQ2000: 634218822Sdim case EM_M32C: 635218822Sdim case EM_M32R: 63660484Sobrien case EM_MCORE: 637218822Sdim case EM_CYGNUS_MEP: 63889857Sobrien case EM_MMIX: 639218822Sdim case EM_MN10200: 640218822Sdim case EM_CYGNUS_MN10200: 641218822Sdim case EM_MN10300: 642218822Sdim case EM_CYGNUS_MN10300: 643130561Sobrien case EM_MSP430: 644130561Sobrien case EM_MSP430_OLD: 645218822Sdim case EM_MT: 646218822Sdim case EM_NIOS32: 647218822Sdim case EM_PPC64: 648218822Sdim case EM_PPC: 649218822Sdim case EM_S390: 650218822Sdim case EM_S390_OLD: 651218822Sdim case EM_SH: 652218822Sdim case EM_SPARC: 653218822Sdim case EM_SPARC32PLUS: 654218822Sdim case EM_SPARCV9: 655218822Sdim case EM_SPU: 656218822Sdim case EM_V850: 657218822Sdim case EM_CYGNUS_V850: 658218822Sdim case EM_VAX: 659218822Sdim case EM_X86_64: 66089857Sobrien case EM_XSTORMY16: 661130561Sobrien case EM_XTENSA: 662130561Sobrien case EM_XTENSA_OLD: 66360484Sobrien return TRUE; 66460484Sobrien 665218822Sdim case EM_68HC05: 666218822Sdim case EM_68HC08: 667218822Sdim case EM_68HC11: 668218822Sdim case EM_68HC16: 669218822Sdim case EM_FX66: 670218822Sdim case EM_ME16: 67160484Sobrien case EM_MMA: 67260484Sobrien case EM_NCPU: 67360484Sobrien case EM_NDR1: 674218822Sdim case EM_PCP: 67560484Sobrien case EM_ST100: 676218822Sdim case EM_ST19: 677218822Sdim case EM_ST7: 67860484Sobrien case EM_ST9PLUS: 679218822Sdim case EM_STARCORE: 68060484Sobrien case EM_SVX: 681218822Sdim case EM_TINYJ: 68260484Sobrien default: 68360484Sobrien warn (_("Don't know about relocations on this machine architecture\n")); 68460484Sobrien return FALSE; 68560484Sobrien } 68660484Sobrien} 68760484Sobrien 68860484Sobrienstatic int 689130561Sobrienslurp_rela_relocs (FILE *file, 690130561Sobrien unsigned long rel_offset, 691130561Sobrien unsigned long rel_size, 692130561Sobrien Elf_Internal_Rela **relasp, 693130561Sobrien unsigned long *nrelasp) 69460484Sobrien{ 69578828Sobrien Elf_Internal_Rela *relas; 69678828Sobrien unsigned long nrelas; 69778828Sobrien unsigned int i; 69860484Sobrien 69978828Sobrien if (is_32bit_elf) 70078828Sobrien { 701130561Sobrien Elf32_External_Rela *erelas; 70260484Sobrien 703218822Sdim erelas = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs")); 70489857Sobrien if (!erelas) 70589857Sobrien return 0; 70660484Sobrien 70778828Sobrien nrelas = rel_size / sizeof (Elf32_External_Rela); 70878828Sobrien 709218822Sdim relas = cmalloc (nrelas, sizeof (Elf_Internal_Rela)); 71078828Sobrien 71178828Sobrien if (relas == NULL) 71260484Sobrien { 713218822Sdim free (erelas); 714218822Sdim error (_("out of memory parsing relocs\n")); 71578828Sobrien return 0; 71678828Sobrien } 71760484Sobrien 71878828Sobrien for (i = 0; i < nrelas; i++) 71978828Sobrien { 72078828Sobrien relas[i].r_offset = BYTE_GET (erelas[i].r_offset); 72178828Sobrien relas[i].r_info = BYTE_GET (erelas[i].r_info); 72278828Sobrien relas[i].r_addend = BYTE_GET (erelas[i].r_addend); 72378828Sobrien } 72460484Sobrien 72578828Sobrien free (erelas); 72678828Sobrien } 72778828Sobrien else 72878828Sobrien { 729130561Sobrien Elf64_External_Rela *erelas; 73060484Sobrien 731218822Sdim erelas = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs")); 73289857Sobrien if (!erelas) 73389857Sobrien return 0; 73460484Sobrien 73578828Sobrien nrelas = rel_size / sizeof (Elf64_External_Rela); 73660484Sobrien 737218822Sdim relas = cmalloc (nrelas, sizeof (Elf_Internal_Rela)); 73860484Sobrien 73978828Sobrien if (relas == NULL) 74078828Sobrien { 741218822Sdim free (erelas); 742218822Sdim error (_("out of memory parsing relocs\n")); 74378828Sobrien return 0; 74478828Sobrien } 74560484Sobrien 74678828Sobrien for (i = 0; i < nrelas; i++) 74778828Sobrien { 748218822Sdim relas[i].r_offset = BYTE_GET (erelas[i].r_offset); 749218822Sdim relas[i].r_info = BYTE_GET (erelas[i].r_info); 750218822Sdim relas[i].r_addend = BYTE_GET (erelas[i].r_addend); 75160484Sobrien } 75260484Sobrien 75378828Sobrien free (erelas); 75478828Sobrien } 75578828Sobrien *relasp = relas; 75678828Sobrien *nrelasp = nrelas; 75778828Sobrien return 1; 75878828Sobrien} 75960484Sobrien 76078828Sobrienstatic int 761130561Sobrienslurp_rel_relocs (FILE *file, 762130561Sobrien unsigned long rel_offset, 763130561Sobrien unsigned long rel_size, 764130561Sobrien Elf_Internal_Rela **relsp, 765130561Sobrien unsigned long *nrelsp) 76678828Sobrien{ 767130561Sobrien Elf_Internal_Rela *rels; 76878828Sobrien unsigned long nrels; 76978828Sobrien unsigned int i; 77060484Sobrien 77178828Sobrien if (is_32bit_elf) 77278828Sobrien { 773130561Sobrien Elf32_External_Rel *erels; 77460484Sobrien 775218822Sdim erels = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs")); 77689857Sobrien if (!erels) 77789857Sobrien return 0; 77860484Sobrien 77978828Sobrien nrels = rel_size / sizeof (Elf32_External_Rel); 78060484Sobrien 781218822Sdim rels = cmalloc (nrels, sizeof (Elf_Internal_Rela)); 78260484Sobrien 78378828Sobrien if (rels == NULL) 78478828Sobrien { 785218822Sdim free (erels); 786218822Sdim error (_("out of memory parsing relocs\n")); 78778828Sobrien return 0; 78860484Sobrien } 78978828Sobrien 79078828Sobrien for (i = 0; i < nrels; i++) 79178828Sobrien { 79278828Sobrien rels[i].r_offset = BYTE_GET (erels[i].r_offset); 79378828Sobrien rels[i].r_info = BYTE_GET (erels[i].r_info); 794130561Sobrien rels[i].r_addend = 0; 79578828Sobrien } 79678828Sobrien 79778828Sobrien free (erels); 79860484Sobrien } 79960484Sobrien else 80060484Sobrien { 801130561Sobrien Elf64_External_Rel *erels; 80260484Sobrien 803218822Sdim erels = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs")); 80489857Sobrien if (!erels) 80589857Sobrien return 0; 80660484Sobrien 80778828Sobrien nrels = rel_size / sizeof (Elf64_External_Rel); 80860484Sobrien 809218822Sdim rels = cmalloc (nrels, sizeof (Elf_Internal_Rela)); 81060484Sobrien 81178828Sobrien if (rels == NULL) 81278828Sobrien { 813218822Sdim free (erels); 814218822Sdim error (_("out of memory parsing relocs\n")); 81578828Sobrien return 0; 81678828Sobrien } 81760484Sobrien 81878828Sobrien for (i = 0; i < nrels; i++) 81978828Sobrien { 820218822Sdim rels[i].r_offset = BYTE_GET (erels[i].r_offset); 821218822Sdim rels[i].r_info = BYTE_GET (erels[i].r_info); 822130561Sobrien rels[i].r_addend = 0; 82360484Sobrien } 82460484Sobrien 82578828Sobrien free (erels); 82678828Sobrien } 82778828Sobrien *relsp = rels; 82878828Sobrien *nrelsp = nrels; 82978828Sobrien return 1; 83078828Sobrien} 83160484Sobrien 832130561Sobrien/* Display the contents of the relocation data found at the specified 833130561Sobrien offset. */ 834130561Sobrien 83578828Sobrienstatic int 836130561Sobriendump_relocations (FILE *file, 837130561Sobrien unsigned long rel_offset, 838130561Sobrien unsigned long rel_size, 839130561Sobrien Elf_Internal_Sym *symtab, 840130561Sobrien unsigned long nsyms, 841130561Sobrien char *strtab, 842218822Sdim unsigned long strtablen, 843130561Sobrien int is_rela) 84478828Sobrien{ 845130561Sobrien unsigned int i; 846130561Sobrien Elf_Internal_Rela *rels; 84760484Sobrien 84860484Sobrien 84978828Sobrien if (is_rela == UNKNOWN) 85078828Sobrien is_rela = guess_is_rela (elf_header.e_machine); 85160484Sobrien 85278828Sobrien if (is_rela) 85378828Sobrien { 854130561Sobrien if (!slurp_rela_relocs (file, rel_offset, rel_size, &rels, &rel_size)) 85578828Sobrien return 0; 85660484Sobrien } 85778828Sobrien else 85878828Sobrien { 85978828Sobrien if (!slurp_rel_relocs (file, rel_offset, rel_size, &rels, &rel_size)) 86078828Sobrien return 0; 86178828Sobrien } 86260484Sobrien 86389857Sobrien if (is_32bit_elf) 86489857Sobrien { 86589857Sobrien if (is_rela) 86699461Sobrien { 86799461Sobrien if (do_wide) 86899461Sobrien printf (_(" Offset Info Type Sym. Value Symbol's Name + Addend\n")); 86999461Sobrien else 87099461Sobrien printf (_(" Offset Info Type Sym.Value Sym. Name + Addend\n")); 87199461Sobrien } 87289857Sobrien else 87399461Sobrien { 87499461Sobrien if (do_wide) 87599461Sobrien printf (_(" Offset Info Type Sym. Value Symbol's Name\n")); 87699461Sobrien else 87799461Sobrien printf (_(" Offset Info Type Sym.Value Sym. Name\n")); 87899461Sobrien } 87989857Sobrien } 88060484Sobrien else 88189857Sobrien { 88289857Sobrien if (is_rela) 88399461Sobrien { 88499461Sobrien if (do_wide) 885130561Sobrien printf (_(" Offset Info Type Symbol's Value Symbol's Name + Addend\n")); 88699461Sobrien else 88799461Sobrien printf (_(" Offset Info Type Sym. Value Sym. Name + Addend\n")); 88899461Sobrien } 88989857Sobrien else 89099461Sobrien { 89199461Sobrien if (do_wide) 892130561Sobrien printf (_(" Offset Info Type Symbol's Value Symbol's Name\n")); 89399461Sobrien else 89499461Sobrien printf (_(" Offset Info Type Sym. Value Sym. Name\n")); 89599461Sobrien } 89689857Sobrien } 89760484Sobrien 89860484Sobrien for (i = 0; i < rel_size; i++) 89960484Sobrien { 900130561Sobrien const char *rtype; 901130561Sobrien const char *rtype2 = NULL; 902130561Sobrien const char *rtype3 = NULL; 903130561Sobrien bfd_vma offset; 904130561Sobrien bfd_vma info; 905130561Sobrien bfd_vma symtab_index; 906130561Sobrien bfd_vma type; 907130561Sobrien bfd_vma type2 = 0; 908130561Sobrien bfd_vma type3 = 0; 90960484Sobrien 910130561Sobrien offset = rels[i].r_offset; 911130561Sobrien info = rels[i].r_info; 91260484Sobrien 91360484Sobrien if (is_32bit_elf) 91460484Sobrien { 91560484Sobrien type = ELF32_R_TYPE (info); 91660484Sobrien symtab_index = ELF32_R_SYM (info); 91760484Sobrien } 91860484Sobrien else 91960484Sobrien { 920130561Sobrien /* The #ifdef BFD64 below is to prevent a compile time warning. 921130561Sobrien We know that if we do not have a 64 bit data type that we 922130561Sobrien will never execute this code anyway. */ 923130561Sobrien#ifdef BFD64 924104834Sobrien if (elf_header.e_machine == EM_MIPS) 92599461Sobrien { 926130561Sobrien /* In little-endian objects, r_info isn't really a 64-bit 927130561Sobrien little-endian value: it has a 32-bit little-endian 928130561Sobrien symbol index followed by four individual byte fields. 929130561Sobrien Reorder INFO accordingly. */ 930130561Sobrien if (elf_header.e_ident[EI_DATA] != ELFDATA2MSB) 931130561Sobrien info = (((info & 0xffffffff) << 32) 932130561Sobrien | ((info >> 56) & 0xff) 933130561Sobrien | ((info >> 40) & 0xff00) 934130561Sobrien | ((info >> 24) & 0xff0000) 935130561Sobrien | ((info >> 8) & 0xff000000)); 93699461Sobrien type = ELF64_MIPS_R_TYPE (info); 93799461Sobrien type2 = ELF64_MIPS_R_TYPE2 (info); 93899461Sobrien type3 = ELF64_MIPS_R_TYPE3 (info); 93999461Sobrien } 94099461Sobrien else if (elf_header.e_machine == EM_SPARCV9) 94199461Sobrien type = ELF64_R_TYPE_ID (info); 94260484Sobrien else 94399461Sobrien type = ELF64_R_TYPE (info); 944130561Sobrien 94560484Sobrien symtab_index = ELF64_R_SYM (info); 94660484Sobrien#endif 94760484Sobrien } 94860484Sobrien 94989857Sobrien if (is_32bit_elf) 95089857Sobrien { 95160484Sobrien#ifdef _bfd_int64_low 95289857Sobrien printf ("%8.8lx %8.8lx ", _bfd_int64_low (offset), _bfd_int64_low (info)); 95360484Sobrien#else 95489857Sobrien printf ("%8.8lx %8.8lx ", offset, info); 95560484Sobrien#endif 95689857Sobrien } 95789857Sobrien else 95889857Sobrien { 95989857Sobrien#ifdef _bfd_int64_low 96099461Sobrien printf (do_wide 96199461Sobrien ? "%8.8lx%8.8lx %8.8lx%8.8lx " 96299461Sobrien : "%4.4lx%8.8lx %4.4lx%8.8lx ", 96389857Sobrien _bfd_int64_high (offset), 96489857Sobrien _bfd_int64_low (offset), 96589857Sobrien _bfd_int64_high (info), 96689857Sobrien _bfd_int64_low (info)); 96789857Sobrien#else 96899461Sobrien printf (do_wide 96999461Sobrien ? "%16.16lx %16.16lx " 97099461Sobrien : "%12.12lx %12.12lx ", 97199461Sobrien offset, info); 97289857Sobrien#endif 97389857Sobrien } 97460484Sobrien 97560484Sobrien switch (elf_header.e_machine) 97660484Sobrien { 97760484Sobrien default: 97860484Sobrien rtype = NULL; 97960484Sobrien break; 98060484Sobrien 98189857Sobrien case EM_M32R: 98260484Sobrien case EM_CYGNUS_M32R: 98360484Sobrien rtype = elf_m32r_reloc_type (type); 98460484Sobrien break; 98560484Sobrien 98660484Sobrien case EM_386: 98760484Sobrien case EM_486: 98860484Sobrien rtype = elf_i386_reloc_type (type); 98960484Sobrien break; 99060484Sobrien 991218822Sdim case EM_68HC11: 992218822Sdim case EM_68HC12: 993218822Sdim rtype = elf_m68hc11_reloc_type (type); 994218822Sdim break; 995104834Sobrien 99660484Sobrien case EM_68K: 99760484Sobrien rtype = elf_m68k_reloc_type (type); 99860484Sobrien break; 99960484Sobrien 100060484Sobrien case EM_960: 100160484Sobrien rtype = elf_i960_reloc_type (type); 100260484Sobrien break; 100360484Sobrien 100460484Sobrien case EM_AVR: 100589857Sobrien case EM_AVR_OLD: 100660484Sobrien rtype = elf_avr_reloc_type (type); 100760484Sobrien break; 100860484Sobrien 100960484Sobrien case EM_OLD_SPARCV9: 101060484Sobrien case EM_SPARC32PLUS: 101160484Sobrien case EM_SPARCV9: 101260484Sobrien case EM_SPARC: 101360484Sobrien rtype = elf_sparc_reloc_type (type); 101460484Sobrien break; 101560484Sobrien 1016218822Sdim case EM_SPU: 1017218822Sdim rtype = elf_spu_reloc_type (type); 1018218822Sdim break; 1019218822Sdim 102089857Sobrien case EM_V850: 102160484Sobrien case EM_CYGNUS_V850: 102260484Sobrien rtype = v850_reloc_type (type); 102360484Sobrien break; 102460484Sobrien 102589857Sobrien case EM_D10V: 102660484Sobrien case EM_CYGNUS_D10V: 102760484Sobrien rtype = elf_d10v_reloc_type (type); 102860484Sobrien break; 102960484Sobrien 103089857Sobrien case EM_D30V: 103160484Sobrien case EM_CYGNUS_D30V: 103260484Sobrien rtype = elf_d30v_reloc_type (type); 103360484Sobrien break; 103460484Sobrien 1035104834Sobrien case EM_DLX: 1036104834Sobrien rtype = elf_dlx_reloc_type (type); 1037104834Sobrien break; 1038104834Sobrien 103960484Sobrien case EM_SH: 104060484Sobrien rtype = elf_sh_reloc_type (type); 104160484Sobrien break; 104260484Sobrien 104389857Sobrien case EM_MN10300: 104460484Sobrien case EM_CYGNUS_MN10300: 104560484Sobrien rtype = elf_mn10300_reloc_type (type); 104660484Sobrien break; 104760484Sobrien 104889857Sobrien case EM_MN10200: 104960484Sobrien case EM_CYGNUS_MN10200: 105060484Sobrien rtype = elf_mn10200_reloc_type (type); 105160484Sobrien break; 105260484Sobrien 105389857Sobrien case EM_FR30: 105460484Sobrien case EM_CYGNUS_FR30: 105560484Sobrien rtype = elf_fr30_reloc_type (type); 105660484Sobrien break; 105760484Sobrien 1058218822Sdim case EM_CYGNUS_FRV: 1059218822Sdim rtype = elf_frv_reloc_type (type); 1060218822Sdim break; 1061104834Sobrien 106260484Sobrien case EM_MCORE: 106360484Sobrien rtype = elf_mcore_reloc_type (type); 106460484Sobrien break; 106560484Sobrien 106689857Sobrien case EM_MMIX: 106789857Sobrien rtype = elf_mmix_reloc_type (type); 106889857Sobrien break; 106989857Sobrien 1070130561Sobrien case EM_MSP430: 1071130561Sobrien case EM_MSP430_OLD: 1072130561Sobrien rtype = elf_msp430_reloc_type (type); 1073130561Sobrien break; 1074130561Sobrien 107560484Sobrien case EM_PPC: 107660484Sobrien rtype = elf_ppc_reloc_type (type); 107760484Sobrien break; 107860484Sobrien 1079130561Sobrien case EM_PPC64: 1080130561Sobrien rtype = elf_ppc64_reloc_type (type); 1081130561Sobrien break; 1082130561Sobrien 108360484Sobrien case EM_MIPS: 108478828Sobrien case EM_MIPS_RS3_LE: 108560484Sobrien rtype = elf_mips_reloc_type (type); 1086104834Sobrien if (!is_32bit_elf) 108799461Sobrien { 108899461Sobrien rtype2 = elf_mips_reloc_type (type2); 108999461Sobrien rtype3 = elf_mips_reloc_type (type3); 109099461Sobrien } 109160484Sobrien break; 109260484Sobrien 109360484Sobrien case EM_ALPHA: 109460484Sobrien rtype = elf_alpha_reloc_type (type); 109560484Sobrien break; 109660484Sobrien 109760484Sobrien case EM_ARM: 109860484Sobrien rtype = elf_arm_reloc_type (type); 109960484Sobrien break; 110060484Sobrien 110177298Sobrien case EM_ARC: 110260484Sobrien rtype = elf_arc_reloc_type (type); 110360484Sobrien break; 110460484Sobrien 110560484Sobrien case EM_PARISC: 110660484Sobrien rtype = elf_hppa_reloc_type (type); 110760484Sobrien break; 110860484Sobrien 110989857Sobrien case EM_H8_300: 111089857Sobrien case EM_H8_300H: 111189857Sobrien case EM_H8S: 111289857Sobrien rtype = elf_h8_reloc_type (type); 111389857Sobrien break; 111489857Sobrien 111591041Sobrien case EM_OPENRISC: 111691041Sobrien case EM_OR32: 111791041Sobrien rtype = elf_or32_reloc_type (type); 111891041Sobrien break; 111991041Sobrien 112060484Sobrien case EM_PJ: 112189857Sobrien case EM_PJ_OLD: 112260484Sobrien rtype = elf_pj_reloc_type (type); 112360484Sobrien break; 112477298Sobrien case EM_IA_64: 112577298Sobrien rtype = elf_ia64_reloc_type (type); 112677298Sobrien break; 112777298Sobrien 112877298Sobrien case EM_CRIS: 112977298Sobrien rtype = elf_cris_reloc_type (type); 113077298Sobrien break; 113177298Sobrien 113277298Sobrien case EM_860: 113377298Sobrien rtype = elf_i860_reloc_type (type); 113477298Sobrien break; 113577298Sobrien 113677298Sobrien case EM_X86_64: 113777298Sobrien rtype = elf_x86_64_reloc_type (type); 113877298Sobrien break; 113989857Sobrien 1140130561Sobrien case EM_S370: 1141130561Sobrien rtype = i370_reloc_type (type); 1142130561Sobrien break; 1143130561Sobrien 1144104834Sobrien case EM_S390_OLD: 1145104834Sobrien case EM_S390: 1146104834Sobrien rtype = elf_s390_reloc_type (type); 1147104834Sobrien break; 114889857Sobrien 1149218822Sdim case EM_SCORE: 1150218822Sdim rtype = elf_score_reloc_type (type); 1151218822Sdim break; 1152218822Sdim 115389857Sobrien case EM_XSTORMY16: 115489857Sobrien rtype = elf_xstormy16_reloc_type (type); 115589857Sobrien break; 1156104834Sobrien 1157218822Sdim case EM_CRX: 1158218822Sdim rtype = elf_crx_reloc_type (type); 1159218822Sdim break; 1160218822Sdim 1161104834Sobrien case EM_VAX: 1162104834Sobrien rtype = elf_vax_reloc_type (type); 1163104834Sobrien break; 1164130561Sobrien 1165130561Sobrien case EM_IP2K: 1166130561Sobrien case EM_IP2K_OLD: 1167130561Sobrien rtype = elf_ip2k_reloc_type (type); 1168130561Sobrien break; 1169130561Sobrien 1170130561Sobrien case EM_IQ2000: 1171130561Sobrien rtype = elf_iq2000_reloc_type (type); 1172130561Sobrien break; 1173130561Sobrien 1174130561Sobrien case EM_XTENSA_OLD: 1175130561Sobrien case EM_XTENSA: 1176130561Sobrien rtype = elf_xtensa_reloc_type (type); 1177130561Sobrien break; 1178218822Sdim 1179218822Sdim case EM_M32C: 1180218822Sdim rtype = elf_m32c_reloc_type (type); 1181218822Sdim break; 1182218822Sdim 1183218822Sdim case EM_MT: 1184218822Sdim rtype = elf_mt_reloc_type (type); 1185218822Sdim break; 1186218822Sdim 1187218822Sdim case EM_BLACKFIN: 1188218822Sdim rtype = elf_bfin_reloc_type (type); 1189218822Sdim break; 1190218822Sdim 1191218822Sdim case EM_CYGNUS_MEP: 1192218822Sdim rtype = elf_mep_reloc_type (type); 1193218822Sdim break; 119460484Sobrien } 119560484Sobrien 119660484Sobrien if (rtype == NULL) 119760484Sobrien#ifdef _bfd_int64_low 119899461Sobrien printf (_("unrecognized: %-7lx"), _bfd_int64_low (type)); 119960484Sobrien#else 120099461Sobrien printf (_("unrecognized: %-7lx"), type); 120160484Sobrien#endif 120260484Sobrien else 1203130561Sobrien printf (do_wide ? "%-22.22s" : "%-17.17s", rtype); 120460484Sobrien 1205218822Sdim if (elf_header.e_machine == EM_ALPHA 1206218822Sdim && rtype != NULL 1207218822Sdim && streq (rtype, "R_ALPHA_LITUSE") 1208218822Sdim && is_rela) 120960484Sobrien { 1210218822Sdim switch (rels[i].r_addend) 1211218822Sdim { 1212218822Sdim case LITUSE_ALPHA_ADDR: rtype = "ADDR"; break; 1213218822Sdim case LITUSE_ALPHA_BASE: rtype = "BASE"; break; 1214218822Sdim case LITUSE_ALPHA_BYTOFF: rtype = "BYTOFF"; break; 1215218822Sdim case LITUSE_ALPHA_JSR: rtype = "JSR"; break; 1216218822Sdim case LITUSE_ALPHA_TLSGD: rtype = "TLSGD"; break; 1217218822Sdim case LITUSE_ALPHA_TLSLDM: rtype = "TLSLDM"; break; 1218218822Sdim case LITUSE_ALPHA_JSRDIRECT: rtype = "JSRDIRECT"; break; 1219218822Sdim default: rtype = NULL; 1220218822Sdim } 1221218822Sdim if (rtype) 1222218822Sdim printf (" (%s)", rtype); 1223218822Sdim else 1224218822Sdim { 1225218822Sdim putchar (' '); 1226218822Sdim printf (_("<unknown addend: %lx>"), 1227218822Sdim (unsigned long) rels[i].r_addend); 1228218822Sdim } 1229218822Sdim } 1230218822Sdim else if (symtab_index) 1231218822Sdim { 123289857Sobrien if (symtab == NULL || symtab_index >= nsyms) 123389857Sobrien printf (" bad symbol index: %08lx", (unsigned long) symtab_index); 123489857Sobrien else 123560484Sobrien { 1236130561Sobrien Elf_Internal_Sym *psym; 123760484Sobrien 123889857Sobrien psym = symtab + symtab_index; 123960484Sobrien 124089857Sobrien printf (" "); 124189857Sobrien print_vma (psym->st_value, LONG_HEX); 124299461Sobrien printf (is_32bit_elf ? " " : " "); 124360484Sobrien 124489857Sobrien if (psym->st_name == 0) 1245130561Sobrien { 1246130561Sobrien const char *sec_name = "<null>"; 1247130561Sobrien char name_buf[40]; 1248130561Sobrien 1249130561Sobrien if (ELF_ST_TYPE (psym->st_info) == STT_SECTION) 1250130561Sobrien { 1251130561Sobrien bfd_vma sec_index = (bfd_vma) -1; 1252130561Sobrien 1253130561Sobrien if (psym->st_shndx < SHN_LORESERVE) 1254130561Sobrien sec_index = psym->st_shndx; 1255218822Sdim else if (psym->st_shndx > SHN_HIRESERVE) 1256130561Sobrien sec_index = psym->st_shndx - (SHN_HIRESERVE + 1 1257130561Sobrien - SHN_LORESERVE); 1258130561Sobrien 1259130561Sobrien if (sec_index != (bfd_vma) -1) 1260130561Sobrien sec_name = SECTION_NAME (section_headers + sec_index); 1261130561Sobrien else if (psym->st_shndx == SHN_ABS) 1262130561Sobrien sec_name = "ABS"; 1263130561Sobrien else if (psym->st_shndx == SHN_COMMON) 1264130561Sobrien sec_name = "COMMON"; 1265218822Sdim else if (elf_header.e_machine == EM_MIPS 1266218822Sdim && psym->st_shndx == SHN_MIPS_SCOMMON) 1267218822Sdim sec_name = "SCOMMON"; 1268218822Sdim else if (elf_header.e_machine == EM_MIPS 1269218822Sdim && psym->st_shndx == SHN_MIPS_SUNDEFINED) 1270218822Sdim sec_name = "SUNDEF"; 1271218822Sdim else if (elf_header.e_machine == EM_X86_64 1272218822Sdim && psym->st_shndx == SHN_X86_64_LCOMMON) 1273218822Sdim sec_name = "LARGE_COMMON"; 1274130561Sobrien else if (elf_header.e_machine == EM_IA_64 1275130561Sobrien && elf_header.e_ident[EI_OSABI] == ELFOSABI_HPUX 1276130561Sobrien && psym->st_shndx == SHN_IA_64_ANSI_COMMON) 1277130561Sobrien sec_name = "ANSI_COM"; 1278130561Sobrien else 1279130561Sobrien { 1280130561Sobrien sprintf (name_buf, "<section 0x%x>", 1281130561Sobrien (unsigned int) psym->st_shndx); 1282130561Sobrien sec_name = name_buf; 1283130561Sobrien } 1284130561Sobrien } 1285130561Sobrien print_symbol (22, sec_name); 1286130561Sobrien } 128789857Sobrien else if (strtab == NULL) 1288218822Sdim printf (_("<string table index: %3ld>"), psym->st_name); 1289218822Sdim else if (psym->st_name >= strtablen) 1290218822Sdim printf (_("<corrupt string table index: %3ld>"), psym->st_name); 129189857Sobrien else 129299461Sobrien print_symbol (22, strtab + psym->st_name); 129360484Sobrien 129489857Sobrien if (is_rela) 1295130561Sobrien printf (" + %lx", (unsigned long) rels[i].r_addend); 129660484Sobrien } 129760484Sobrien } 129860484Sobrien else if (is_rela) 129960484Sobrien { 1300218822Sdim printf ("%*c", is_32bit_elf ? 1301218822Sdim (do_wide ? 34 : 28) : (do_wide ? 26 : 20), ' '); 1302130561Sobrien print_vma (rels[i].r_addend, LONG_HEX); 130360484Sobrien } 130460484Sobrien 130560484Sobrien if (elf_header.e_machine == EM_SPARCV9 1306218822Sdim && rtype != NULL 1307218822Sdim && streq (rtype, "R_SPARC_OLO10")) 130860484Sobrien printf (" + %lx", (unsigned long) ELF64_R_TYPE_DATA (info)); 130960484Sobrien 131060484Sobrien putchar ('\n'); 131199461Sobrien 1312104834Sobrien if (! is_32bit_elf && elf_header.e_machine == EM_MIPS) 131399461Sobrien { 131499461Sobrien printf (" Type2: "); 131599461Sobrien 131699461Sobrien if (rtype2 == NULL) 131799461Sobrien#ifdef _bfd_int64_low 131899461Sobrien printf (_("unrecognized: %-7lx"), _bfd_int64_low (type2)); 131999461Sobrien#else 132099461Sobrien printf (_("unrecognized: %-7lx"), type2); 132199461Sobrien#endif 132299461Sobrien else 132399461Sobrien printf ("%-17.17s", rtype2); 132499461Sobrien 1325218822Sdim printf ("\n Type3: "); 132699461Sobrien 132799461Sobrien if (rtype3 == NULL) 132899461Sobrien#ifdef _bfd_int64_low 132999461Sobrien printf (_("unrecognized: %-7lx"), _bfd_int64_low (type3)); 133099461Sobrien#else 133199461Sobrien printf (_("unrecognized: %-7lx"), type3); 133299461Sobrien#endif 133399461Sobrien else 133499461Sobrien printf ("%-17.17s", rtype3); 133599461Sobrien 1336104834Sobrien putchar ('\n'); 133799461Sobrien } 133860484Sobrien } 133960484Sobrien 1340130561Sobrien free (rels); 134160484Sobrien 134260484Sobrien return 1; 134360484Sobrien} 134460484Sobrien 134560484Sobrienstatic const char * 1346130561Sobrienget_mips_dynamic_type (unsigned long type) 134760484Sobrien{ 134860484Sobrien switch (type) 134960484Sobrien { 135060484Sobrien case DT_MIPS_RLD_VERSION: return "MIPS_RLD_VERSION"; 135160484Sobrien case DT_MIPS_TIME_STAMP: return "MIPS_TIME_STAMP"; 135260484Sobrien case DT_MIPS_ICHECKSUM: return "MIPS_ICHECKSUM"; 135360484Sobrien case DT_MIPS_IVERSION: return "MIPS_IVERSION"; 135460484Sobrien case DT_MIPS_FLAGS: return "MIPS_FLAGS"; 135560484Sobrien case DT_MIPS_BASE_ADDRESS: return "MIPS_BASE_ADDRESS"; 135660484Sobrien case DT_MIPS_MSYM: return "MIPS_MSYM"; 135760484Sobrien case DT_MIPS_CONFLICT: return "MIPS_CONFLICT"; 135860484Sobrien case DT_MIPS_LIBLIST: return "MIPS_LIBLIST"; 135960484Sobrien case DT_MIPS_LOCAL_GOTNO: return "MIPS_LOCAL_GOTNO"; 136060484Sobrien case DT_MIPS_CONFLICTNO: return "MIPS_CONFLICTNO"; 136160484Sobrien case DT_MIPS_LIBLISTNO: return "MIPS_LIBLISTNO"; 136260484Sobrien case DT_MIPS_SYMTABNO: return "MIPS_SYMTABNO"; 136360484Sobrien case DT_MIPS_UNREFEXTNO: return "MIPS_UNREFEXTNO"; 136460484Sobrien case DT_MIPS_GOTSYM: return "MIPS_GOTSYM"; 136560484Sobrien case DT_MIPS_HIPAGENO: return "MIPS_HIPAGENO"; 136660484Sobrien case DT_MIPS_RLD_MAP: return "MIPS_RLD_MAP"; 136760484Sobrien case DT_MIPS_DELTA_CLASS: return "MIPS_DELTA_CLASS"; 136860484Sobrien case DT_MIPS_DELTA_CLASS_NO: return "MIPS_DELTA_CLASS_NO"; 136960484Sobrien case DT_MIPS_DELTA_INSTANCE: return "MIPS_DELTA_INSTANCE"; 137060484Sobrien case DT_MIPS_DELTA_INSTANCE_NO: return "MIPS_DELTA_INSTANCE_NO"; 137160484Sobrien case DT_MIPS_DELTA_RELOC: return "MIPS_DELTA_RELOC"; 137260484Sobrien case DT_MIPS_DELTA_RELOC_NO: return "MIPS_DELTA_RELOC_NO"; 137360484Sobrien case DT_MIPS_DELTA_SYM: return "MIPS_DELTA_SYM"; 137460484Sobrien case DT_MIPS_DELTA_SYM_NO: return "MIPS_DELTA_SYM_NO"; 137560484Sobrien case DT_MIPS_DELTA_CLASSSYM: return "MIPS_DELTA_CLASSSYM"; 137660484Sobrien case DT_MIPS_DELTA_CLASSSYM_NO: return "MIPS_DELTA_CLASSSYM_NO"; 137760484Sobrien case DT_MIPS_CXX_FLAGS: return "MIPS_CXX_FLAGS"; 137860484Sobrien case DT_MIPS_PIXIE_INIT: return "MIPS_PIXIE_INIT"; 137960484Sobrien case DT_MIPS_SYMBOL_LIB: return "MIPS_SYMBOL_LIB"; 138060484Sobrien case DT_MIPS_LOCALPAGE_GOTIDX: return "MIPS_LOCALPAGE_GOTIDX"; 138160484Sobrien case DT_MIPS_LOCAL_GOTIDX: return "MIPS_LOCAL_GOTIDX"; 138260484Sobrien case DT_MIPS_HIDDEN_GOTIDX: return "MIPS_HIDDEN_GOTIDX"; 138360484Sobrien case DT_MIPS_PROTECTED_GOTIDX: return "MIPS_PROTECTED_GOTIDX"; 138460484Sobrien case DT_MIPS_OPTIONS: return "MIPS_OPTIONS"; 138560484Sobrien case DT_MIPS_INTERFACE: return "MIPS_INTERFACE"; 138660484Sobrien case DT_MIPS_DYNSTR_ALIGN: return "MIPS_DYNSTR_ALIGN"; 138760484Sobrien case DT_MIPS_INTERFACE_SIZE: return "MIPS_INTERFACE_SIZE"; 138860484Sobrien case DT_MIPS_RLD_TEXT_RESOLVE_ADDR: return "MIPS_RLD_TEXT_RESOLVE_ADDR"; 138960484Sobrien case DT_MIPS_PERF_SUFFIX: return "MIPS_PERF_SUFFIX"; 139060484Sobrien case DT_MIPS_COMPACT_SIZE: return "MIPS_COMPACT_SIZE"; 139160484Sobrien case DT_MIPS_GP_VALUE: return "MIPS_GP_VALUE"; 139260484Sobrien case DT_MIPS_AUX_DYNAMIC: return "MIPS_AUX_DYNAMIC"; 139360484Sobrien default: 139460484Sobrien return NULL; 139560484Sobrien } 139660484Sobrien} 139760484Sobrien 139860484Sobrienstatic const char * 1399130561Sobrienget_sparc64_dynamic_type (unsigned long type) 140060484Sobrien{ 140160484Sobrien switch (type) 140260484Sobrien { 140360484Sobrien case DT_SPARC_REGISTER: return "SPARC_REGISTER"; 140460484Sobrien default: 140560484Sobrien return NULL; 140660484Sobrien } 140760484Sobrien} 140860484Sobrien 140960484Sobrienstatic const char * 1410218822Sdimget_ppc_dynamic_type (unsigned long type) 1411218822Sdim{ 1412218822Sdim switch (type) 1413218822Sdim { 1414218822Sdim case DT_PPC_GOT: return "PPC_GOT"; 1415218822Sdim default: 1416218822Sdim return NULL; 1417218822Sdim } 1418218822Sdim} 1419218822Sdim 1420218822Sdimstatic const char * 1421130561Sobrienget_ppc64_dynamic_type (unsigned long type) 142289857Sobrien{ 142389857Sobrien switch (type) 142489857Sobrien { 142589857Sobrien case DT_PPC64_GLINK: return "PPC64_GLINK"; 142691041Sobrien case DT_PPC64_OPD: return "PPC64_OPD"; 142791041Sobrien case DT_PPC64_OPDSZ: return "PPC64_OPDSZ"; 142889857Sobrien default: 142989857Sobrien return NULL; 143089857Sobrien } 143189857Sobrien} 143289857Sobrien 143389857Sobrienstatic const char * 1434130561Sobrienget_parisc_dynamic_type (unsigned long type) 143560484Sobrien{ 143660484Sobrien switch (type) 143760484Sobrien { 143860484Sobrien case DT_HP_LOAD_MAP: return "HP_LOAD_MAP"; 143960484Sobrien case DT_HP_DLD_FLAGS: return "HP_DLD_FLAGS"; 144060484Sobrien case DT_HP_DLD_HOOK: return "HP_DLD_HOOK"; 144160484Sobrien case DT_HP_UX10_INIT: return "HP_UX10_INIT"; 144260484Sobrien case DT_HP_UX10_INITSZ: return "HP_UX10_INITSZ"; 144360484Sobrien case DT_HP_PREINIT: return "HP_PREINIT"; 144460484Sobrien case DT_HP_PREINITSZ: return "HP_PREINITSZ"; 144560484Sobrien case DT_HP_NEEDED: return "HP_NEEDED"; 144660484Sobrien case DT_HP_TIME_STAMP: return "HP_TIME_STAMP"; 144760484Sobrien case DT_HP_CHECKSUM: return "HP_CHECKSUM"; 144860484Sobrien case DT_HP_GST_SIZE: return "HP_GST_SIZE"; 144960484Sobrien case DT_HP_GST_VERSION: return "HP_GST_VERSION"; 145060484Sobrien case DT_HP_GST_HASHVAL: return "HP_GST_HASHVAL"; 1451218822Sdim case DT_HP_EPLTREL: return "HP_GST_EPLTREL"; 1452218822Sdim case DT_HP_EPLTRELSZ: return "HP_GST_EPLTRELSZ"; 1453218822Sdim case DT_HP_FILTERED: return "HP_FILTERED"; 1454218822Sdim case DT_HP_FILTER_TLS: return "HP_FILTER_TLS"; 1455218822Sdim case DT_HP_COMPAT_FILTERED: return "HP_COMPAT_FILTERED"; 1456218822Sdim case DT_HP_LAZYLOAD: return "HP_LAZYLOAD"; 1457218822Sdim case DT_HP_BIND_NOW_COUNT: return "HP_BIND_NOW_COUNT"; 1458218822Sdim case DT_PLT: return "PLT"; 1459218822Sdim case DT_PLT_SIZE: return "PLT_SIZE"; 1460218822Sdim case DT_DLT: return "DLT"; 1461218822Sdim case DT_DLT_SIZE: return "DLT_SIZE"; 146260484Sobrien default: 146360484Sobrien return NULL; 146460484Sobrien } 146560484Sobrien} 146660484Sobrien 146760484Sobrienstatic const char * 1468130561Sobrienget_ia64_dynamic_type (unsigned long type) 146960484Sobrien{ 1470130561Sobrien switch (type) 1471130561Sobrien { 1472130561Sobrien case DT_IA_64_PLT_RESERVE: return "IA_64_PLT_RESERVE"; 1473130561Sobrien default: 1474130561Sobrien return NULL; 1475130561Sobrien } 1476130561Sobrien} 147760484Sobrien 1478130561Sobrienstatic const char * 1479218822Sdimget_alpha_dynamic_type (unsigned long type) 1480218822Sdim{ 1481218822Sdim switch (type) 1482218822Sdim { 1483218822Sdim case DT_ALPHA_PLTRO: return "ALPHA_PLTRO"; 1484218822Sdim default: 1485218822Sdim return NULL; 1486218822Sdim } 1487218822Sdim} 1488218822Sdim 1489218822Sdimstatic const char * 1490218822Sdimget_score_dynamic_type (unsigned long type) 1491218822Sdim{ 1492218822Sdim switch (type) 1493218822Sdim { 1494218822Sdim case DT_SCORE_BASE_ADDRESS: return "SCORE_BASE_ADDRESS"; 1495218822Sdim case DT_SCORE_LOCAL_GOTNO: return "SCORE_LOCAL_GOTNO"; 1496218822Sdim case DT_SCORE_SYMTABNO: return "SCORE_SYMTABNO"; 1497218822Sdim case DT_SCORE_GOTSYM: return "SCORE_GOTSYM"; 1498218822Sdim case DT_SCORE_UNREFEXTNO: return "SCORE_UNREFEXTNO"; 1499218822Sdim case DT_SCORE_HIPAGENO: return "SCORE_HIPAGENO"; 1500218822Sdim default: 1501218822Sdim return NULL; 1502218822Sdim } 1503218822Sdim} 1504218822Sdim 1505218822Sdim 1506218822Sdimstatic const char * 1507130561Sobrienget_dynamic_type (unsigned long type) 1508130561Sobrien{ 1509218822Sdim static char buff[64]; 1510130561Sobrien 151160484Sobrien switch (type) 151260484Sobrien { 151360484Sobrien case DT_NULL: return "NULL"; 151460484Sobrien case DT_NEEDED: return "NEEDED"; 151560484Sobrien case DT_PLTRELSZ: return "PLTRELSZ"; 151660484Sobrien case DT_PLTGOT: return "PLTGOT"; 151760484Sobrien case DT_HASH: return "HASH"; 151860484Sobrien case DT_STRTAB: return "STRTAB"; 151960484Sobrien case DT_SYMTAB: return "SYMTAB"; 152060484Sobrien case DT_RELA: return "RELA"; 152160484Sobrien case DT_RELASZ: return "RELASZ"; 152260484Sobrien case DT_RELAENT: return "RELAENT"; 152360484Sobrien case DT_STRSZ: return "STRSZ"; 152460484Sobrien case DT_SYMENT: return "SYMENT"; 152560484Sobrien case DT_INIT: return "INIT"; 152660484Sobrien case DT_FINI: return "FINI"; 152760484Sobrien case DT_SONAME: return "SONAME"; 152860484Sobrien case DT_RPATH: return "RPATH"; 152960484Sobrien case DT_SYMBOLIC: return "SYMBOLIC"; 153060484Sobrien case DT_REL: return "REL"; 153160484Sobrien case DT_RELSZ: return "RELSZ"; 153260484Sobrien case DT_RELENT: return "RELENT"; 153360484Sobrien case DT_PLTREL: return "PLTREL"; 153460484Sobrien case DT_DEBUG: return "DEBUG"; 153560484Sobrien case DT_TEXTREL: return "TEXTREL"; 153660484Sobrien case DT_JMPREL: return "JMPREL"; 153760484Sobrien case DT_BIND_NOW: return "BIND_NOW"; 153860484Sobrien case DT_INIT_ARRAY: return "INIT_ARRAY"; 153960484Sobrien case DT_FINI_ARRAY: return "FINI_ARRAY"; 154060484Sobrien case DT_INIT_ARRAYSZ: return "INIT_ARRAYSZ"; 154160484Sobrien case DT_FINI_ARRAYSZ: return "FINI_ARRAYSZ"; 154260484Sobrien case DT_RUNPATH: return "RUNPATH"; 154360484Sobrien case DT_FLAGS: return "FLAGS"; 154460484Sobrien 154560484Sobrien case DT_PREINIT_ARRAY: return "PREINIT_ARRAY"; 154660484Sobrien case DT_PREINIT_ARRAYSZ: return "PREINIT_ARRAYSZ"; 154760484Sobrien 154868765Sobrien case DT_CHECKSUM: return "CHECKSUM"; 154960484Sobrien case DT_PLTPADSZ: return "PLTPADSZ"; 155060484Sobrien case DT_MOVEENT: return "MOVEENT"; 155160484Sobrien case DT_MOVESZ: return "MOVESZ"; 155268765Sobrien case DT_FEATURE: return "FEATURE"; 155360484Sobrien case DT_POSFLAG_1: return "POSFLAG_1"; 155460484Sobrien case DT_SYMINSZ: return "SYMINSZ"; 155560484Sobrien case DT_SYMINENT: return "SYMINENT"; /* aka VALRNGHI */ 155660484Sobrien 155760484Sobrien case DT_ADDRRNGLO: return "ADDRRNGLO"; 155868765Sobrien case DT_CONFIG: return "CONFIG"; 155968765Sobrien case DT_DEPAUDIT: return "DEPAUDIT"; 156068765Sobrien case DT_AUDIT: return "AUDIT"; 156168765Sobrien case DT_PLTPAD: return "PLTPAD"; 156268765Sobrien case DT_MOVETAB: return "MOVETAB"; 156360484Sobrien case DT_SYMINFO: return "SYMINFO"; /* aka ADDRRNGHI */ 156460484Sobrien 156560484Sobrien case DT_VERSYM: return "VERSYM"; 156660484Sobrien 1567218822Sdim case DT_TLSDESC_GOT: return "TLSDESC_GOT"; 1568218822Sdim case DT_TLSDESC_PLT: return "TLSDESC_PLT"; 156960484Sobrien case DT_RELACOUNT: return "RELACOUNT"; 157060484Sobrien case DT_RELCOUNT: return "RELCOUNT"; 157160484Sobrien case DT_FLAGS_1: return "FLAGS_1"; 157260484Sobrien case DT_VERDEF: return "VERDEF"; 157360484Sobrien case DT_VERDEFNUM: return "VERDEFNUM"; 157460484Sobrien case DT_VERNEED: return "VERNEED"; 157560484Sobrien case DT_VERNEEDNUM: return "VERNEEDNUM"; 157660484Sobrien 157768765Sobrien case DT_AUXILIARY: return "AUXILIARY"; 157860484Sobrien case DT_USED: return "USED"; 157960484Sobrien case DT_FILTER: return "FILTER"; 158060484Sobrien 1581104834Sobrien case DT_GNU_PRELINKED: return "GNU_PRELINKED"; 1582104834Sobrien case DT_GNU_CONFLICT: return "GNU_CONFLICT"; 1583104834Sobrien case DT_GNU_CONFLICTSZ: return "GNU_CONFLICTSZ"; 1584104834Sobrien case DT_GNU_LIBLIST: return "GNU_LIBLIST"; 1585104834Sobrien case DT_GNU_LIBLISTSZ: return "GNU_LIBLISTSZ"; 1586218822Sdim case DT_GNU_HASH: return "GNU_HASH"; 1587104834Sobrien 158860484Sobrien default: 158960484Sobrien if ((type >= DT_LOPROC) && (type <= DT_HIPROC)) 159060484Sobrien { 1591130561Sobrien const char *result; 159260484Sobrien 159360484Sobrien switch (elf_header.e_machine) 159460484Sobrien { 159560484Sobrien case EM_MIPS: 159678828Sobrien case EM_MIPS_RS3_LE: 159760484Sobrien result = get_mips_dynamic_type (type); 159860484Sobrien break; 159960484Sobrien case EM_SPARCV9: 160060484Sobrien result = get_sparc64_dynamic_type (type); 160160484Sobrien break; 1602218822Sdim case EM_PPC: 1603218822Sdim result = get_ppc_dynamic_type (type); 1604218822Sdim break; 160589857Sobrien case EM_PPC64: 160689857Sobrien result = get_ppc64_dynamic_type (type); 160789857Sobrien break; 1608130561Sobrien case EM_IA_64: 1609130561Sobrien result = get_ia64_dynamic_type (type); 1610130561Sobrien break; 1611218822Sdim case EM_ALPHA: 1612218822Sdim result = get_alpha_dynamic_type (type); 1613218822Sdim break; 1614218822Sdim case EM_SCORE: 1615218822Sdim result = get_score_dynamic_type (type); 1616218822Sdim break; 161760484Sobrien default: 161860484Sobrien result = NULL; 161960484Sobrien break; 162060484Sobrien } 162160484Sobrien 162260484Sobrien if (result != NULL) 162360484Sobrien return result; 162460484Sobrien 1625218822Sdim snprintf (buff, sizeof (buff), _("Processor Specific: %lx"), type); 162660484Sobrien } 1627218822Sdim else if (((type >= DT_LOOS) && (type <= DT_HIOS)) 1628218822Sdim || (elf_header.e_machine == EM_PARISC 1629218822Sdim && (type >= OLD_DT_LOOS) && (type <= OLD_DT_HIOS))) 163060484Sobrien { 1631130561Sobrien const char *result; 163260484Sobrien 163360484Sobrien switch (elf_header.e_machine) 163460484Sobrien { 163560484Sobrien case EM_PARISC: 163660484Sobrien result = get_parisc_dynamic_type (type); 163760484Sobrien break; 163860484Sobrien default: 163960484Sobrien result = NULL; 164060484Sobrien break; 164160484Sobrien } 164260484Sobrien 164360484Sobrien if (result != NULL) 164460484Sobrien return result; 164560484Sobrien 1646218822Sdim snprintf (buff, sizeof (buff), _("Operating System specific: %lx"), 1647218822Sdim type); 164860484Sobrien } 164960484Sobrien else 1650218822Sdim snprintf (buff, sizeof (buff), _("<unknown>: %lx"), type); 165160484Sobrien 165260484Sobrien return buff; 165360484Sobrien } 165460484Sobrien} 165560484Sobrien 165660484Sobrienstatic char * 1657130561Sobrienget_file_type (unsigned e_type) 165860484Sobrien{ 1659130561Sobrien static char buff[32]; 166060484Sobrien 166160484Sobrien switch (e_type) 166260484Sobrien { 166360484Sobrien case ET_NONE: return _("NONE (None)"); 166460484Sobrien case ET_REL: return _("REL (Relocatable file)"); 1665218822Sdim case ET_EXEC: return _("EXEC (Executable file)"); 1666218822Sdim case ET_DYN: return _("DYN (Shared object file)"); 1667218822Sdim case ET_CORE: return _("CORE (Core file)"); 166860484Sobrien 166960484Sobrien default: 167060484Sobrien if ((e_type >= ET_LOPROC) && (e_type <= ET_HIPROC)) 1671218822Sdim snprintf (buff, sizeof (buff), _("Processor Specific: (%x)"), e_type); 167260484Sobrien else if ((e_type >= ET_LOOS) && (e_type <= ET_HIOS)) 1673218822Sdim snprintf (buff, sizeof (buff), _("OS Specific: (%x)"), e_type); 167460484Sobrien else 1675218822Sdim snprintf (buff, sizeof (buff), _("<unknown>: %x"), e_type); 167660484Sobrien return buff; 167760484Sobrien } 167860484Sobrien} 167960484Sobrien 168060484Sobrienstatic char * 1681130561Sobrienget_machine_name (unsigned e_machine) 168260484Sobrien{ 1683130561Sobrien static char buff[64]; /* XXX */ 168460484Sobrien 168560484Sobrien switch (e_machine) 168660484Sobrien { 168789857Sobrien case EM_NONE: return _("None"); 168889857Sobrien case EM_M32: return "WE32100"; 168989857Sobrien case EM_SPARC: return "Sparc"; 1690218822Sdim case EM_SPU: return "SPU"; 169189857Sobrien case EM_386: return "Intel 80386"; 169289857Sobrien case EM_68K: return "MC68000"; 169389857Sobrien case EM_88K: return "MC88000"; 169489857Sobrien case EM_486: return "Intel 80486"; 169589857Sobrien case EM_860: return "Intel 80860"; 169689857Sobrien case EM_MIPS: return "MIPS R3000"; 169789857Sobrien case EM_S370: return "IBM System/370"; 169878828Sobrien case EM_MIPS_RS3_LE: return "MIPS R4000 big-endian"; 169960484Sobrien case EM_OLD_SPARCV9: return "Sparc v9 (old)"; 170089857Sobrien case EM_PARISC: return "HPPA"; 170160484Sobrien case EM_PPC_OLD: return "Power PC (old)"; 170278828Sobrien case EM_SPARC32PLUS: return "Sparc v8+" ; 170389857Sobrien case EM_960: return "Intel 90860"; 170489857Sobrien case EM_PPC: return "PowerPC"; 170589857Sobrien case EM_PPC64: return "PowerPC64"; 170689857Sobrien case EM_V800: return "NEC V800"; 170789857Sobrien case EM_FR20: return "Fujitsu FR20"; 170889857Sobrien case EM_RH32: return "TRW RH32"; 1709130561Sobrien case EM_MCORE: return "MCORE"; 171078828Sobrien case EM_ARM: return "ARM"; 171178828Sobrien case EM_OLD_ALPHA: return "Digital Alpha (old)"; 1712130561Sobrien case EM_SH: return "Renesas / SuperH SH"; 171389857Sobrien case EM_SPARCV9: return "Sparc v9"; 171489857Sobrien case EM_TRICORE: return "Siemens Tricore"; 171577298Sobrien case EM_ARC: return "ARC"; 1716130561Sobrien case EM_H8_300: return "Renesas H8/300"; 1717130561Sobrien case EM_H8_300H: return "Renesas H8/300H"; 1718130561Sobrien case EM_H8S: return "Renesas H8S"; 1719130561Sobrien case EM_H8_500: return "Renesas H8/500"; 172060484Sobrien case EM_IA_64: return "Intel IA-64"; 172160484Sobrien case EM_MIPS_X: return "Stanford MIPS-X"; 172260484Sobrien case EM_COLDFIRE: return "Motorola Coldfire"; 172360484Sobrien case EM_68HC12: return "Motorola M68HC12"; 172489857Sobrien case EM_ALPHA: return "Alpha"; 172589857Sobrien case EM_CYGNUS_D10V: 172689857Sobrien case EM_D10V: return "d10v"; 172789857Sobrien case EM_CYGNUS_D30V: 1728130561Sobrien case EM_D30V: return "d30v"; 172989857Sobrien case EM_CYGNUS_M32R: 1730130561Sobrien case EM_M32R: return "Renesas M32R (formerly Mitsubishi M32r)"; 173189857Sobrien case EM_CYGNUS_V850: 173289857Sobrien case EM_V850: return "NEC v850"; 173389857Sobrien case EM_CYGNUS_MN10300: 173489857Sobrien case EM_MN10300: return "mn10300"; 173589857Sobrien case EM_CYGNUS_MN10200: 173689857Sobrien case EM_MN10200: return "mn10200"; 173789857Sobrien case EM_CYGNUS_FR30: 173889857Sobrien case EM_FR30: return "Fujitsu FR30"; 1739130561Sobrien case EM_CYGNUS_FRV: return "Fujitsu FR-V"; 174089857Sobrien case EM_PJ_OLD: 1741130561Sobrien case EM_PJ: return "picoJava"; 174278828Sobrien case EM_MMA: return "Fujitsu Multimedia Accelerator"; 174378828Sobrien case EM_PCP: return "Siemens PCP"; 174478828Sobrien case EM_NCPU: return "Sony nCPU embedded RISC processor"; 174578828Sobrien case EM_NDR1: return "Denso NDR1 microprocesspr"; 174678828Sobrien case EM_STARCORE: return "Motorola Star*Core processor"; 174778828Sobrien case EM_ME16: return "Toyota ME16 processor"; 174878828Sobrien case EM_ST100: return "STMicroelectronics ST100 processor"; 174978828Sobrien case EM_TINYJ: return "Advanced Logic Corp. TinyJ embedded processor"; 175078828Sobrien case EM_FX66: return "Siemens FX66 microcontroller"; 175178828Sobrien case EM_ST9PLUS: return "STMicroelectronics ST9+ 8/16 bit microcontroller"; 175278828Sobrien case EM_ST7: return "STMicroelectronics ST7 8-bit microcontroller"; 175378828Sobrien case EM_68HC16: return "Motorola MC68HC16 Microcontroller"; 175478828Sobrien case EM_68HC11: return "Motorola MC68HC11 Microcontroller"; 175578828Sobrien case EM_68HC08: return "Motorola MC68HC08 Microcontroller"; 175678828Sobrien case EM_68HC05: return "Motorola MC68HC05 Microcontroller"; 175778828Sobrien case EM_SVX: return "Silicon Graphics SVx"; 175878828Sobrien case EM_ST19: return "STMicroelectronics ST19 8-bit microcontroller"; 175978828Sobrien case EM_VAX: return "Digital VAX"; 176089857Sobrien case EM_AVR_OLD: 1761130561Sobrien case EM_AVR: return "Atmel AVR 8-bit microcontroller"; 176277298Sobrien case EM_CRIS: return "Axis Communications 32-bit embedded processor"; 176389857Sobrien case EM_JAVELIN: return "Infineon Technologies 32-bit embedded cpu"; 176489857Sobrien case EM_FIREPATH: return "Element 14 64-bit DSP processor"; 176589857Sobrien case EM_ZSP: return "LSI Logic's 16-bit DSP processor"; 1766130561Sobrien case EM_MMIX: return "Donald Knuth's educational 64-bit processor"; 176789857Sobrien case EM_HUANY: return "Harvard Universitys's machine-independent object format"; 1768130561Sobrien case EM_PRISM: return "Vitesse Prism"; 176977298Sobrien case EM_X86_64: return "Advanced Micro Devices X86-64"; 177089857Sobrien case EM_S390_OLD: 1771130561Sobrien case EM_S390: return "IBM S/390"; 1772218822Sdim case EM_SCORE: return "SUNPLUS S+Core"; 177389857Sobrien case EM_XSTORMY16: return "Sanyo Xstormy16 CPU core"; 177491041Sobrien case EM_OPENRISC: 177591041Sobrien case EM_OR32: return "OpenRISC"; 1776218822Sdim case EM_CRX: return "National Semiconductor CRX microprocessor"; 1777104834Sobrien case EM_DLX: return "OpenDLX"; 1778130561Sobrien case EM_IP2K_OLD: 1779130561Sobrien case EM_IP2K: return "Ubicom IP2xxx 8-bit microcontrollers"; 1780130561Sobrien case EM_IQ2000: return "Vitesse IQ2000"; 1781130561Sobrien case EM_XTENSA_OLD: 1782130561Sobrien case EM_XTENSA: return "Tensilica Xtensa Processor"; 1783218822Sdim case EM_M32C: return "Renesas M32c"; 1784218822Sdim case EM_MT: return "Morpho Techologies MT processor"; 1785218822Sdim case EM_BLACKFIN: return "Analog Devices Blackfin"; 1786218822Sdim case EM_NIOS32: return "Altera Nios"; 1787218822Sdim case EM_ALTERA_NIOS2: return "Altera Nios II"; 1788218822Sdim case EM_XC16X: return "Infineon Technologies xc16x"; 1789218822Sdim case EM_CYGNUS_MEP: return "Toshiba MeP Media Engine"; 179060484Sobrien default: 1791218822Sdim snprintf (buff, sizeof (buff), _("<unknown>: 0x%x"), e_machine); 179260484Sobrien return buff; 179360484Sobrien } 179460484Sobrien} 179560484Sobrien 179677298Sobrienstatic void 1797130561Sobriendecode_ARM_machine_flags (unsigned e_flags, char buf[]) 179877298Sobrien{ 179977298Sobrien unsigned eabi; 180077298Sobrien int unknown = 0; 180177298Sobrien 180277298Sobrien eabi = EF_ARM_EABI_VERSION (e_flags); 180377298Sobrien e_flags &= ~ EF_ARM_EABIMASK; 180477298Sobrien 180577298Sobrien /* Handle "generic" ARM flags. */ 180677298Sobrien if (e_flags & EF_ARM_RELEXEC) 180777298Sobrien { 180877298Sobrien strcat (buf, ", relocatable executable"); 180977298Sobrien e_flags &= ~ EF_ARM_RELEXEC; 181077298Sobrien } 181177298Sobrien 181277298Sobrien if (e_flags & EF_ARM_HASENTRY) 181377298Sobrien { 181477298Sobrien strcat (buf, ", has entry point"); 181577298Sobrien e_flags &= ~ EF_ARM_HASENTRY; 181677298Sobrien } 181777298Sobrien 181877298Sobrien /* Now handle EABI specific flags. */ 181977298Sobrien switch (eabi) 182077298Sobrien { 182177298Sobrien default: 182299461Sobrien strcat (buf, ", <unrecognized EABI>"); 182377298Sobrien if (e_flags) 182477298Sobrien unknown = 1; 182577298Sobrien break; 182677298Sobrien 182777298Sobrien case EF_ARM_EABI_VER1: 182889857Sobrien strcat (buf, ", Version1 EABI"); 182977298Sobrien while (e_flags) 183077298Sobrien { 183177298Sobrien unsigned flag; 183277298Sobrien 183377298Sobrien /* Process flags one bit at a time. */ 183477298Sobrien flag = e_flags & - e_flags; 183577298Sobrien e_flags &= ~ flag; 183677298Sobrien 183777298Sobrien switch (flag) 183877298Sobrien { 183989857Sobrien case EF_ARM_SYMSARESORTED: /* Conflicts with EF_ARM_INTERWORK. */ 184077298Sobrien strcat (buf, ", sorted symbol tables"); 184177298Sobrien break; 184277298Sobrien 184377298Sobrien default: 184477298Sobrien unknown = 1; 184577298Sobrien break; 184677298Sobrien } 184777298Sobrien } 184877298Sobrien break; 184977298Sobrien 185089857Sobrien case EF_ARM_EABI_VER2: 185189857Sobrien strcat (buf, ", Version2 EABI"); 185289857Sobrien while (e_flags) 185389857Sobrien { 185489857Sobrien unsigned flag; 185589857Sobrien 185689857Sobrien /* Process flags one bit at a time. */ 185789857Sobrien flag = e_flags & - e_flags; 185889857Sobrien e_flags &= ~ flag; 185989857Sobrien 186089857Sobrien switch (flag) 186189857Sobrien { 186289857Sobrien case EF_ARM_SYMSARESORTED: /* Conflicts with EF_ARM_INTERWORK. */ 186389857Sobrien strcat (buf, ", sorted symbol tables"); 186489857Sobrien break; 186589857Sobrien 186689857Sobrien case EF_ARM_DYNSYMSUSESEGIDX: 186789857Sobrien strcat (buf, ", dynamic symbols use segment index"); 186889857Sobrien break; 186989857Sobrien 187089857Sobrien case EF_ARM_MAPSYMSFIRST: 187189857Sobrien strcat (buf, ", mapping symbols precede others"); 187289857Sobrien break; 187389857Sobrien 187489857Sobrien default: 187589857Sobrien unknown = 1; 187689857Sobrien break; 187789857Sobrien } 187889857Sobrien } 187989857Sobrien break; 188089857Sobrien 1881218822Sdim case EF_ARM_EABI_VER3: 1882218822Sdim strcat (buf, ", Version3 EABI"); 1883218822Sdim break; 1884218822Sdim 1885218822Sdim case EF_ARM_EABI_VER4: 1886218822Sdim strcat (buf, ", Version4 EABI"); 1887218822Sdim goto eabi; 1888218822Sdim 1889218822Sdim case EF_ARM_EABI_VER5: 1890218822Sdim strcat (buf, ", Version5 EABI"); 1891218822Sdim eabi: 1892218822Sdim while (e_flags) 1893218822Sdim { 1894218822Sdim unsigned flag; 1895218822Sdim 1896218822Sdim /* Process flags one bit at a time. */ 1897218822Sdim flag = e_flags & - e_flags; 1898218822Sdim e_flags &= ~ flag; 1899218822Sdim 1900218822Sdim switch (flag) 1901218822Sdim { 1902218822Sdim case EF_ARM_BE8: 1903218822Sdim strcat (buf, ", BE8"); 1904218822Sdim break; 1905218822Sdim 1906218822Sdim case EF_ARM_LE8: 1907218822Sdim strcat (buf, ", LE8"); 1908218822Sdim break; 1909218822Sdim 1910218822Sdim default: 1911218822Sdim unknown = 1; 1912218822Sdim break; 1913218822Sdim } 1914218822Sdim } 1915218822Sdim break; 1916218822Sdim 191777298Sobrien case EF_ARM_EABI_UNKNOWN: 191889857Sobrien strcat (buf, ", GNU EABI"); 191977298Sobrien while (e_flags) 192077298Sobrien { 192177298Sobrien unsigned flag; 192277298Sobrien 192377298Sobrien /* Process flags one bit at a time. */ 192477298Sobrien flag = e_flags & - e_flags; 192577298Sobrien e_flags &= ~ flag; 192677298Sobrien 192777298Sobrien switch (flag) 192877298Sobrien { 192989857Sobrien case EF_ARM_INTERWORK: 193077298Sobrien strcat (buf, ", interworking enabled"); 193177298Sobrien break; 193277298Sobrien 193389857Sobrien case EF_ARM_APCS_26: 193477298Sobrien strcat (buf, ", uses APCS/26"); 193577298Sobrien break; 193677298Sobrien 193789857Sobrien case EF_ARM_APCS_FLOAT: 193877298Sobrien strcat (buf, ", uses APCS/float"); 193977298Sobrien break; 194077298Sobrien 194189857Sobrien case EF_ARM_PIC: 194277298Sobrien strcat (buf, ", position independent"); 194377298Sobrien break; 194477298Sobrien 194589857Sobrien case EF_ARM_ALIGN8: 194677298Sobrien strcat (buf, ", 8 bit structure alignment"); 194777298Sobrien break; 194877298Sobrien 194989857Sobrien case EF_ARM_NEW_ABI: 195077298Sobrien strcat (buf, ", uses new ABI"); 195177298Sobrien break; 195277298Sobrien 195389857Sobrien case EF_ARM_OLD_ABI: 195477298Sobrien strcat (buf, ", uses old ABI"); 195577298Sobrien break; 195677298Sobrien 195789857Sobrien case EF_ARM_SOFT_FLOAT: 195877298Sobrien strcat (buf, ", software FP"); 195977298Sobrien break; 196077298Sobrien 1961218822Sdim case EF_ARM_VFP_FLOAT: 1962218822Sdim strcat (buf, ", VFP"); 1963218822Sdim break; 1964218822Sdim 1965130561Sobrien case EF_ARM_MAVERICK_FLOAT: 1966130561Sobrien strcat (buf, ", Maverick FP"); 1967130561Sobrien break; 1968130561Sobrien 196977298Sobrien default: 197077298Sobrien unknown = 1; 197177298Sobrien break; 197277298Sobrien } 197377298Sobrien } 197477298Sobrien } 197577298Sobrien 197677298Sobrien if (unknown) 197777298Sobrien strcat (buf,", <unknown>"); 197877298Sobrien} 197977298Sobrien 198060484Sobrienstatic char * 1981130561Sobrienget_machine_flags (unsigned e_flags, unsigned e_machine) 198260484Sobrien{ 1983130561Sobrien static char buf[1024]; 198460484Sobrien 198560484Sobrien buf[0] = '\0'; 198677298Sobrien 198760484Sobrien if (e_flags) 198860484Sobrien { 198960484Sobrien switch (e_machine) 199060484Sobrien { 199160484Sobrien default: 199260484Sobrien break; 199360484Sobrien 199477298Sobrien case EM_ARM: 199577298Sobrien decode_ARM_machine_flags (e_flags, buf); 199677298Sobrien break; 199777298Sobrien 1998218822Sdim case EM_CYGNUS_FRV: 1999218822Sdim switch (e_flags & EF_FRV_CPU_MASK) 2000218822Sdim { 2001218822Sdim case EF_FRV_CPU_GENERIC: 2002218822Sdim break; 2003218822Sdim 2004218822Sdim default: 2005218822Sdim strcat (buf, ", fr???"); 2006218822Sdim break; 2007218822Sdim 2008218822Sdim case EF_FRV_CPU_FR300: 2009218822Sdim strcat (buf, ", fr300"); 2010218822Sdim break; 2011218822Sdim 2012218822Sdim case EF_FRV_CPU_FR400: 2013218822Sdim strcat (buf, ", fr400"); 2014218822Sdim break; 2015218822Sdim case EF_FRV_CPU_FR405: 2016218822Sdim strcat (buf, ", fr405"); 2017218822Sdim break; 2018218822Sdim 2019218822Sdim case EF_FRV_CPU_FR450: 2020218822Sdim strcat (buf, ", fr450"); 2021218822Sdim break; 2022218822Sdim 2023218822Sdim case EF_FRV_CPU_FR500: 2024218822Sdim strcat (buf, ", fr500"); 2025218822Sdim break; 2026218822Sdim case EF_FRV_CPU_FR550: 2027218822Sdim strcat (buf, ", fr550"); 2028218822Sdim break; 2029218822Sdim 2030218822Sdim case EF_FRV_CPU_SIMPLE: 2031218822Sdim strcat (buf, ", simple"); 2032218822Sdim break; 2033218822Sdim case EF_FRV_CPU_TOMCAT: 2034218822Sdim strcat (buf, ", tomcat"); 2035218822Sdim break; 2036218822Sdim } 2037218822Sdim break; 2038218822Sdim 2039104834Sobrien case EM_68K: 2040218822Sdim if ((e_flags & EF_M68K_ARCH_MASK) == EF_M68K_M68000) 2041218822Sdim strcat (buf, ", m68000"); 2042218822Sdim else if ((e_flags & EF_M68K_ARCH_MASK) == EF_M68K_CPU32) 2043104834Sobrien strcat (buf, ", cpu32"); 2044218822Sdim else if ((e_flags & EF_M68K_ARCH_MASK) == EF_M68K_FIDO) 2045218822Sdim strcat (buf, ", fido_a"); 2046218822Sdim else 2047218822Sdim { 2048218822Sdim char const *isa = _("unknown"); 2049218822Sdim char const *mac = _("unknown mac"); 2050218822Sdim char const *additional = NULL; 2051218822Sdim 2052218822Sdim switch (e_flags & EF_M68K_CF_ISA_MASK) 2053218822Sdim { 2054218822Sdim case EF_M68K_CF_ISA_A_NODIV: 2055218822Sdim isa = "A"; 2056218822Sdim additional = ", nodiv"; 2057218822Sdim break; 2058218822Sdim case EF_M68K_CF_ISA_A: 2059218822Sdim isa = "A"; 2060218822Sdim break; 2061218822Sdim case EF_M68K_CF_ISA_A_PLUS: 2062218822Sdim isa = "A+"; 2063218822Sdim break; 2064218822Sdim case EF_M68K_CF_ISA_B_NOUSP: 2065218822Sdim isa = "B"; 2066218822Sdim additional = ", nousp"; 2067218822Sdim break; 2068218822Sdim case EF_M68K_CF_ISA_B: 2069218822Sdim isa = "B"; 2070218822Sdim break; 2071218822Sdim } 2072218822Sdim strcat (buf, ", cf, isa "); 2073218822Sdim strcat (buf, isa); 2074218822Sdim if (additional) 2075218822Sdim strcat (buf, additional); 2076218822Sdim if (e_flags & EF_M68K_CF_FLOAT) 2077218822Sdim strcat (buf, ", float"); 2078218822Sdim switch (e_flags & EF_M68K_CF_MAC_MASK) 2079218822Sdim { 2080218822Sdim case 0: 2081218822Sdim mac = NULL; 2082218822Sdim break; 2083218822Sdim case EF_M68K_CF_MAC: 2084218822Sdim mac = "mac"; 2085218822Sdim break; 2086218822Sdim case EF_M68K_CF_EMAC: 2087218822Sdim mac = "emac"; 2088218822Sdim break; 2089218822Sdim } 2090218822Sdim if (mac) 2091218822Sdim { 2092218822Sdim strcat (buf, ", "); 2093218822Sdim strcat (buf, mac); 2094218822Sdim } 2095218822Sdim } 2096104834Sobrien break; 209760484Sobrien 209860484Sobrien case EM_PPC: 209960484Sobrien if (e_flags & EF_PPC_EMB) 210060484Sobrien strcat (buf, ", emb"); 210160484Sobrien 210260484Sobrien if (e_flags & EF_PPC_RELOCATABLE) 210360484Sobrien strcat (buf, ", relocatable"); 210460484Sobrien 210560484Sobrien if (e_flags & EF_PPC_RELOCATABLE_LIB) 210660484Sobrien strcat (buf, ", relocatable-lib"); 210760484Sobrien break; 210860484Sobrien 210989857Sobrien case EM_V850: 211060484Sobrien case EM_CYGNUS_V850: 211160484Sobrien switch (e_flags & EF_V850_ARCH) 211260484Sobrien { 2113130561Sobrien case E_V850E1_ARCH: 2114130561Sobrien strcat (buf, ", v850e1"); 2115130561Sobrien break; 211660484Sobrien case E_V850E_ARCH: 211760484Sobrien strcat (buf, ", v850e"); 211860484Sobrien break; 211960484Sobrien case E_V850_ARCH: 212060484Sobrien strcat (buf, ", v850"); 212160484Sobrien break; 212260484Sobrien default: 212360484Sobrien strcat (buf, ", unknown v850 architecture variant"); 212460484Sobrien break; 212560484Sobrien } 212660484Sobrien break; 212760484Sobrien 212889857Sobrien case EM_M32R: 212960484Sobrien case EM_CYGNUS_M32R: 213060484Sobrien if ((e_flags & EF_M32R_ARCH) == E_M32R_ARCH) 213160484Sobrien strcat (buf, ", m32r"); 213260484Sobrien break; 213360484Sobrien 213460484Sobrien case EM_MIPS: 213578828Sobrien case EM_MIPS_RS3_LE: 213660484Sobrien if (e_flags & EF_MIPS_NOREORDER) 213760484Sobrien strcat (buf, ", noreorder"); 213860484Sobrien 213960484Sobrien if (e_flags & EF_MIPS_PIC) 214060484Sobrien strcat (buf, ", pic"); 214160484Sobrien 214260484Sobrien if (e_flags & EF_MIPS_CPIC) 214360484Sobrien strcat (buf, ", cpic"); 214460484Sobrien 214589857Sobrien if (e_flags & EF_MIPS_UCODE) 214689857Sobrien strcat (buf, ", ugen_reserved"); 214789857Sobrien 214860484Sobrien if (e_flags & EF_MIPS_ABI2) 214960484Sobrien strcat (buf, ", abi2"); 215060484Sobrien 215189857Sobrien if (e_flags & EF_MIPS_OPTIONS_FIRST) 215289857Sobrien strcat (buf, ", odk first"); 215360484Sobrien 215489857Sobrien if (e_flags & EF_MIPS_32BITMODE) 215589857Sobrien strcat (buf, ", 32bitmode"); 215660484Sobrien 215777298Sobrien switch ((e_flags & EF_MIPS_MACH)) 215877298Sobrien { 215977298Sobrien case E_MIPS_MACH_3900: strcat (buf, ", 3900"); break; 216077298Sobrien case E_MIPS_MACH_4010: strcat (buf, ", 4010"); break; 216177298Sobrien case E_MIPS_MACH_4100: strcat (buf, ", 4100"); break; 2162130561Sobrien case E_MIPS_MACH_4111: strcat (buf, ", 4111"); break; 2163130561Sobrien case E_MIPS_MACH_4120: strcat (buf, ", 4120"); break; 216477298Sobrien case E_MIPS_MACH_4650: strcat (buf, ", 4650"); break; 2165130561Sobrien case E_MIPS_MACH_5400: strcat (buf, ", 5400"); break; 2166130561Sobrien case E_MIPS_MACH_5500: strcat (buf, ", 5500"); break; 216777298Sobrien case E_MIPS_MACH_SB1: strcat (buf, ", sb1"); break; 2168218822Sdim case E_MIPS_MACH_9000: strcat (buf, ", 9000"); break; 216989857Sobrien case 0: 217089857Sobrien /* We simply ignore the field in this case to avoid confusion: 217189857Sobrien MIPS ELF does not specify EF_MIPS_MACH, it is a GNU 217289857Sobrien extension. */ 217389857Sobrien break; 217489857Sobrien default: strcat (buf, ", unknown CPU"); break; 217577298Sobrien } 217689857Sobrien 217789857Sobrien switch ((e_flags & EF_MIPS_ABI)) 217889857Sobrien { 217989857Sobrien case E_MIPS_ABI_O32: strcat (buf, ", o32"); break; 218089857Sobrien case E_MIPS_ABI_O64: strcat (buf, ", o64"); break; 218189857Sobrien case E_MIPS_ABI_EABI32: strcat (buf, ", eabi32"); break; 218289857Sobrien case E_MIPS_ABI_EABI64: strcat (buf, ", eabi64"); break; 218389857Sobrien case 0: 218489857Sobrien /* We simply ignore the field in this case to avoid confusion: 218589857Sobrien MIPS ELF does not specify EF_MIPS_ABI, it is a GNU extension. 218689857Sobrien This means it is likely to be an o32 file, but not for 218789857Sobrien sure. */ 218889857Sobrien break; 218989857Sobrien default: strcat (buf, ", unknown ABI"); break; 219089857Sobrien } 219189857Sobrien 219289857Sobrien if (e_flags & EF_MIPS_ARCH_ASE_MDMX) 219389857Sobrien strcat (buf, ", mdmx"); 219489857Sobrien 219589857Sobrien if (e_flags & EF_MIPS_ARCH_ASE_M16) 219689857Sobrien strcat (buf, ", mips16"); 219789857Sobrien 219889857Sobrien switch ((e_flags & EF_MIPS_ARCH)) 219989857Sobrien { 220089857Sobrien case E_MIPS_ARCH_1: strcat (buf, ", mips1"); break; 220189857Sobrien case E_MIPS_ARCH_2: strcat (buf, ", mips2"); break; 220289857Sobrien case E_MIPS_ARCH_3: strcat (buf, ", mips3"); break; 220389857Sobrien case E_MIPS_ARCH_4: strcat (buf, ", mips4"); break; 220489857Sobrien case E_MIPS_ARCH_5: strcat (buf, ", mips5"); break; 220589857Sobrien case E_MIPS_ARCH_32: strcat (buf, ", mips32"); break; 2206130561Sobrien case E_MIPS_ARCH_32R2: strcat (buf, ", mips32r2"); break; 220789857Sobrien case E_MIPS_ARCH_64: strcat (buf, ", mips64"); break; 2208130561Sobrien case E_MIPS_ARCH_64R2: strcat (buf, ", mips64r2"); break; 220989857Sobrien default: strcat (buf, ", unknown ISA"); break; 221089857Sobrien } 221189857Sobrien 221260484Sobrien break; 221360484Sobrien 2214218822Sdim case EM_SH: 2215218822Sdim switch ((e_flags & EF_SH_MACH_MASK)) 2216218822Sdim { 2217218822Sdim case EF_SH1: strcat (buf, ", sh1"); break; 2218218822Sdim case EF_SH2: strcat (buf, ", sh2"); break; 2219218822Sdim case EF_SH3: strcat (buf, ", sh3"); break; 2220218822Sdim case EF_SH_DSP: strcat (buf, ", sh-dsp"); break; 2221218822Sdim case EF_SH3_DSP: strcat (buf, ", sh3-dsp"); break; 2222218822Sdim case EF_SH4AL_DSP: strcat (buf, ", sh4al-dsp"); break; 2223218822Sdim case EF_SH3E: strcat (buf, ", sh3e"); break; 2224218822Sdim case EF_SH4: strcat (buf, ", sh4"); break; 2225218822Sdim case EF_SH5: strcat (buf, ", sh5"); break; 2226218822Sdim case EF_SH2E: strcat (buf, ", sh2e"); break; 2227218822Sdim case EF_SH4A: strcat (buf, ", sh4a"); break; 2228218822Sdim case EF_SH2A: strcat (buf, ", sh2a"); break; 2229218822Sdim case EF_SH4_NOFPU: strcat (buf, ", sh4-nofpu"); break; 2230218822Sdim case EF_SH4A_NOFPU: strcat (buf, ", sh4a-nofpu"); break; 2231218822Sdim case EF_SH2A_NOFPU: strcat (buf, ", sh2a-nofpu"); break; 2232218822Sdim case EF_SH3_NOMMU: strcat (buf, ", sh3-nommu"); break; 2233218822Sdim case EF_SH4_NOMMU_NOFPU: strcat (buf, ", sh4-nommu-nofpu"); break; 2234218822Sdim case EF_SH2A_SH4_NOFPU: strcat (buf, ", sh2a-nofpu-or-sh4-nommu-nofpu"); break; 2235218822Sdim case EF_SH2A_SH3_NOFPU: strcat (buf, ", sh2a-nofpu-or-sh3-nommu"); break; 2236218822Sdim case EF_SH2A_SH4: strcat (buf, ", sh2a-or-sh4"); break; 2237218822Sdim case EF_SH2A_SH3E: strcat (buf, ", sh2a-or-sh3e"); break; 2238218822Sdim default: strcat (buf, ", unknown ISA"); break; 2239218822Sdim } 2240218822Sdim 2241218822Sdim break; 2242218822Sdim 224360484Sobrien case EM_SPARCV9: 224460484Sobrien if (e_flags & EF_SPARC_32PLUS) 224560484Sobrien strcat (buf, ", v8+"); 224660484Sobrien 224760484Sobrien if (e_flags & EF_SPARC_SUN_US1) 224860484Sobrien strcat (buf, ", ultrasparcI"); 224960484Sobrien 225060484Sobrien if (e_flags & EF_SPARC_SUN_US3) 225160484Sobrien strcat (buf, ", ultrasparcIII"); 225260484Sobrien 225360484Sobrien if (e_flags & EF_SPARC_HAL_R1) 225460484Sobrien strcat (buf, ", halr1"); 225560484Sobrien 225660484Sobrien if (e_flags & EF_SPARC_LEDATA) 225760484Sobrien strcat (buf, ", ledata"); 225860484Sobrien 225960484Sobrien if ((e_flags & EF_SPARCV9_MM) == EF_SPARCV9_TSO) 226060484Sobrien strcat (buf, ", tso"); 226160484Sobrien 226260484Sobrien if ((e_flags & EF_SPARCV9_MM) == EF_SPARCV9_PSO) 226360484Sobrien strcat (buf, ", pso"); 226460484Sobrien 226560484Sobrien if ((e_flags & EF_SPARCV9_MM) == EF_SPARCV9_RMO) 226660484Sobrien strcat (buf, ", rmo"); 226760484Sobrien break; 226860484Sobrien 226960484Sobrien case EM_PARISC: 227060484Sobrien switch (e_flags & EF_PARISC_ARCH) 227160484Sobrien { 227260484Sobrien case EFA_PARISC_1_0: 227360484Sobrien strcpy (buf, ", PA-RISC 1.0"); 227460484Sobrien break; 227560484Sobrien case EFA_PARISC_1_1: 227660484Sobrien strcpy (buf, ", PA-RISC 1.1"); 227760484Sobrien break; 227860484Sobrien case EFA_PARISC_2_0: 227960484Sobrien strcpy (buf, ", PA-RISC 2.0"); 228060484Sobrien break; 228160484Sobrien default: 228260484Sobrien break; 228360484Sobrien } 228460484Sobrien if (e_flags & EF_PARISC_TRAPNIL) 228560484Sobrien strcat (buf, ", trapnil"); 228660484Sobrien if (e_flags & EF_PARISC_EXT) 228760484Sobrien strcat (buf, ", ext"); 228860484Sobrien if (e_flags & EF_PARISC_LSB) 228960484Sobrien strcat (buf, ", lsb"); 229060484Sobrien if (e_flags & EF_PARISC_WIDE) 229160484Sobrien strcat (buf, ", wide"); 229260484Sobrien if (e_flags & EF_PARISC_NO_KABP) 229360484Sobrien strcat (buf, ", no kabp"); 229460484Sobrien if (e_flags & EF_PARISC_LAZYSWAP) 229560484Sobrien strcat (buf, ", lazyswap"); 229660484Sobrien break; 229777298Sobrien 229860484Sobrien case EM_PJ: 229989857Sobrien case EM_PJ_OLD: 230060484Sobrien if ((e_flags & EF_PICOJAVA_NEWCALLS) == EF_PICOJAVA_NEWCALLS) 230160484Sobrien strcat (buf, ", new calling convention"); 230260484Sobrien 230360484Sobrien if ((e_flags & EF_PICOJAVA_GNUCALLS) == EF_PICOJAVA_GNUCALLS) 230460484Sobrien strcat (buf, ", gnu calling convention"); 230560484Sobrien break; 230678828Sobrien 230778828Sobrien case EM_IA_64: 230878828Sobrien if ((e_flags & EF_IA_64_ABI64)) 230978828Sobrien strcat (buf, ", 64-bit"); 231078828Sobrien else 231178828Sobrien strcat (buf, ", 32-bit"); 231278828Sobrien if ((e_flags & EF_IA_64_REDUCEDFP)) 231378828Sobrien strcat (buf, ", reduced fp model"); 231478828Sobrien if ((e_flags & EF_IA_64_NOFUNCDESC_CONS_GP)) 231578828Sobrien strcat (buf, ", no function descriptors, constant gp"); 231678828Sobrien else if ((e_flags & EF_IA_64_CONS_GP)) 231778828Sobrien strcat (buf, ", constant gp"); 231878828Sobrien if ((e_flags & EF_IA_64_ABSOLUTE)) 231978828Sobrien strcat (buf, ", absolute"); 232078828Sobrien break; 2321104834Sobrien 2322104834Sobrien case EM_VAX: 2323104834Sobrien if ((e_flags & EF_VAX_NONPIC)) 2324104834Sobrien strcat (buf, ", non-PIC"); 2325104834Sobrien if ((e_flags & EF_VAX_DFLOAT)) 2326104834Sobrien strcat (buf, ", D-Float"); 2327104834Sobrien if ((e_flags & EF_VAX_GFLOAT)) 2328104834Sobrien strcat (buf, ", G-Float"); 2329104834Sobrien break; 233060484Sobrien } 233160484Sobrien } 233260484Sobrien 233360484Sobrien return buf; 233460484Sobrien} 233560484Sobrien 233660484Sobrienstatic const char * 2337130561Sobrienget_osabi_name (unsigned int osabi) 233860484Sobrien{ 2339130561Sobrien static char buff[32]; 2340130561Sobrien 2341130561Sobrien switch (osabi) 2342130561Sobrien { 2343130561Sobrien case ELFOSABI_NONE: return "UNIX - System V"; 2344130561Sobrien case ELFOSABI_HPUX: return "UNIX - HP-UX"; 2345130561Sobrien case ELFOSABI_NETBSD: return "UNIX - NetBSD"; 2346130561Sobrien case ELFOSABI_LINUX: return "UNIX - Linux"; 2347130561Sobrien case ELFOSABI_HURD: return "GNU/Hurd"; 2348130561Sobrien case ELFOSABI_SOLARIS: return "UNIX - Solaris"; 2349130561Sobrien case ELFOSABI_AIX: return "UNIX - AIX"; 2350130561Sobrien case ELFOSABI_IRIX: return "UNIX - IRIX"; 2351130561Sobrien case ELFOSABI_FREEBSD: return "UNIX - FreeBSD"; 2352130561Sobrien case ELFOSABI_TRU64: return "UNIX - TRU64"; 2353130561Sobrien case ELFOSABI_MODESTO: return "Novell - Modesto"; 2354130561Sobrien case ELFOSABI_OPENBSD: return "UNIX - OpenBSD"; 2355130561Sobrien case ELFOSABI_OPENVMS: return "VMS - OpenVMS"; 2356130561Sobrien case ELFOSABI_NSK: return "HP - Non-Stop Kernel"; 2357130561Sobrien case ELFOSABI_AROS: return "Amiga Research OS"; 2358130561Sobrien case ELFOSABI_STANDALONE: return _("Standalone App"); 2359130561Sobrien case ELFOSABI_ARM: return "ARM"; 2360130561Sobrien default: 2361218822Sdim snprintf (buff, sizeof (buff), _("<unknown: %x>"), osabi); 2362130561Sobrien return buff; 2363130561Sobrien } 2364130561Sobrien} 2365130561Sobrien 2366130561Sobrienstatic const char * 2367218822Sdimget_arm_segment_type (unsigned long type) 2368218822Sdim{ 2369218822Sdim switch (type) 2370218822Sdim { 2371218822Sdim case PT_ARM_EXIDX: 2372218822Sdim return "EXIDX"; 2373218822Sdim default: 2374218822Sdim break; 2375218822Sdim } 2376218822Sdim 2377218822Sdim return NULL; 2378218822Sdim} 2379218822Sdim 2380218822Sdimstatic const char * 2381130561Sobrienget_mips_segment_type (unsigned long type) 2382130561Sobrien{ 238360484Sobrien switch (type) 238460484Sobrien { 238560484Sobrien case PT_MIPS_REGINFO: 238660484Sobrien return "REGINFO"; 238760484Sobrien case PT_MIPS_RTPROC: 238860484Sobrien return "RTPROC"; 238960484Sobrien case PT_MIPS_OPTIONS: 239060484Sobrien return "OPTIONS"; 239160484Sobrien default: 239260484Sobrien break; 239360484Sobrien } 239460484Sobrien 239560484Sobrien return NULL; 239660484Sobrien} 239760484Sobrien 239860484Sobrienstatic const char * 2399130561Sobrienget_parisc_segment_type (unsigned long type) 240060484Sobrien{ 240160484Sobrien switch (type) 240260484Sobrien { 240360484Sobrien case PT_HP_TLS: return "HP_TLS"; 240460484Sobrien case PT_HP_CORE_NONE: return "HP_CORE_NONE"; 240560484Sobrien case PT_HP_CORE_VERSION: return "HP_CORE_VERSION"; 240660484Sobrien case PT_HP_CORE_KERNEL: return "HP_CORE_KERNEL"; 240760484Sobrien case PT_HP_CORE_COMM: return "HP_CORE_COMM"; 240860484Sobrien case PT_HP_CORE_PROC: return "HP_CORE_PROC"; 240960484Sobrien case PT_HP_CORE_LOADABLE: return "HP_CORE_LOADABLE"; 241060484Sobrien case PT_HP_CORE_STACK: return "HP_CORE_STACK"; 241160484Sobrien case PT_HP_CORE_SHM: return "HP_CORE_SHM"; 241260484Sobrien case PT_HP_CORE_MMF: return "HP_CORE_MMF"; 241360484Sobrien case PT_HP_PARALLEL: return "HP_PARALLEL"; 241460484Sobrien case PT_HP_FASTBIND: return "HP_FASTBIND"; 2415218822Sdim case PT_HP_OPT_ANNOT: return "HP_OPT_ANNOT"; 2416218822Sdim case PT_HP_HSL_ANNOT: return "HP_HSL_ANNOT"; 2417218822Sdim case PT_HP_STACK: return "HP_STACK"; 2418218822Sdim case PT_HP_CORE_UTSNAME: return "HP_CORE_UTSNAME"; 241960484Sobrien case PT_PARISC_ARCHEXT: return "PARISC_ARCHEXT"; 242060484Sobrien case PT_PARISC_UNWIND: return "PARISC_UNWIND"; 2421218822Sdim case PT_PARISC_WEAKORDER: return "PARISC_WEAKORDER"; 242260484Sobrien default: 242360484Sobrien break; 242460484Sobrien } 242560484Sobrien 242660484Sobrien return NULL; 242760484Sobrien} 242860484Sobrien 242960484Sobrienstatic const char * 2430130561Sobrienget_ia64_segment_type (unsigned long type) 243178828Sobrien{ 243278828Sobrien switch (type) 243378828Sobrien { 243478828Sobrien case PT_IA_64_ARCHEXT: return "IA_64_ARCHEXT"; 243578828Sobrien case PT_IA_64_UNWIND: return "IA_64_UNWIND"; 243689857Sobrien case PT_HP_TLS: return "HP_TLS"; 243789857Sobrien case PT_IA_64_HP_OPT_ANOT: return "HP_OPT_ANNOT"; 243889857Sobrien case PT_IA_64_HP_HSL_ANOT: return "HP_HSL_ANNOT"; 243989857Sobrien case PT_IA_64_HP_STACK: return "HP_STACK"; 244078828Sobrien default: 244178828Sobrien break; 244278828Sobrien } 244378828Sobrien 244478828Sobrien return NULL; 244578828Sobrien} 244678828Sobrien 244778828Sobrienstatic const char * 2448130561Sobrienget_segment_type (unsigned long p_type) 244960484Sobrien{ 2450130561Sobrien static char buff[32]; 245160484Sobrien 245260484Sobrien switch (p_type) 245360484Sobrien { 2454130561Sobrien case PT_NULL: return "NULL"; 2455130561Sobrien case PT_LOAD: return "LOAD"; 245660484Sobrien case PT_DYNAMIC: return "DYNAMIC"; 2457130561Sobrien case PT_INTERP: return "INTERP"; 2458130561Sobrien case PT_NOTE: return "NOTE"; 2459130561Sobrien case PT_SHLIB: return "SHLIB"; 2460130561Sobrien case PT_PHDR: return "PHDR"; 2461104834Sobrien case PT_TLS: return "TLS"; 246260484Sobrien 246389857Sobrien case PT_GNU_EH_FRAME: 246489857Sobrien return "GNU_EH_FRAME"; 2465218822Sdim case PT_GNU_STACK: return "GNU_STACK"; 2466218822Sdim case PT_GNU_RELRO: return "GNU_RELRO"; 246789857Sobrien 246860484Sobrien default: 246960484Sobrien if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC)) 247060484Sobrien { 2471130561Sobrien const char *result; 247260484Sobrien 247360484Sobrien switch (elf_header.e_machine) 247460484Sobrien { 2475218822Sdim case EM_ARM: 2476218822Sdim result = get_arm_segment_type (p_type); 2477218822Sdim break; 247860484Sobrien case EM_MIPS: 247978828Sobrien case EM_MIPS_RS3_LE: 248060484Sobrien result = get_mips_segment_type (p_type); 248160484Sobrien break; 248260484Sobrien case EM_PARISC: 248360484Sobrien result = get_parisc_segment_type (p_type); 248460484Sobrien break; 248578828Sobrien case EM_IA_64: 248678828Sobrien result = get_ia64_segment_type (p_type); 248778828Sobrien break; 248860484Sobrien default: 248960484Sobrien result = NULL; 249060484Sobrien break; 249160484Sobrien } 249260484Sobrien 249360484Sobrien if (result != NULL) 249460484Sobrien return result; 249560484Sobrien 249660484Sobrien sprintf (buff, "LOPROC+%lx", p_type - PT_LOPROC); 249760484Sobrien } 249860484Sobrien else if ((p_type >= PT_LOOS) && (p_type <= PT_HIOS)) 249960484Sobrien { 2500130561Sobrien const char *result; 250160484Sobrien 250260484Sobrien switch (elf_header.e_machine) 250360484Sobrien { 250460484Sobrien case EM_PARISC: 250560484Sobrien result = get_parisc_segment_type (p_type); 250660484Sobrien break; 250789857Sobrien case EM_IA_64: 250889857Sobrien result = get_ia64_segment_type (p_type); 250989857Sobrien break; 251060484Sobrien default: 251160484Sobrien result = NULL; 251260484Sobrien break; 251360484Sobrien } 251460484Sobrien 251560484Sobrien if (result != NULL) 251660484Sobrien return result; 251760484Sobrien 251860484Sobrien sprintf (buff, "LOOS+%lx", p_type - PT_LOOS); 251960484Sobrien } 252060484Sobrien else 2521218822Sdim snprintf (buff, sizeof (buff), _("<unknown>: %lx"), p_type); 252260484Sobrien 252360484Sobrien return buff; 252460484Sobrien } 252560484Sobrien} 252660484Sobrien 252760484Sobrienstatic const char * 2528130561Sobrienget_mips_section_type_name (unsigned int sh_type) 252960484Sobrien{ 253060484Sobrien switch (sh_type) 253160484Sobrien { 2532130561Sobrien case SHT_MIPS_LIBLIST: return "MIPS_LIBLIST"; 2533130561Sobrien case SHT_MIPS_MSYM: return "MIPS_MSYM"; 2534130561Sobrien case SHT_MIPS_CONFLICT: return "MIPS_CONFLICT"; 2535130561Sobrien case SHT_MIPS_GPTAB: return "MIPS_GPTAB"; 2536130561Sobrien case SHT_MIPS_UCODE: return "MIPS_UCODE"; 2537130561Sobrien case SHT_MIPS_DEBUG: return "MIPS_DEBUG"; 2538130561Sobrien case SHT_MIPS_REGINFO: return "MIPS_REGINFO"; 2539130561Sobrien case SHT_MIPS_PACKAGE: return "MIPS_PACKAGE"; 2540130561Sobrien case SHT_MIPS_PACKSYM: return "MIPS_PACKSYM"; 2541130561Sobrien case SHT_MIPS_RELD: return "MIPS_RELD"; 2542130561Sobrien case SHT_MIPS_IFACE: return "MIPS_IFACE"; 2543130561Sobrien case SHT_MIPS_CONTENT: return "MIPS_CONTENT"; 2544130561Sobrien case SHT_MIPS_OPTIONS: return "MIPS_OPTIONS"; 2545130561Sobrien case SHT_MIPS_SHDR: return "MIPS_SHDR"; 2546130561Sobrien case SHT_MIPS_FDESC: return "MIPS_FDESC"; 2547130561Sobrien case SHT_MIPS_EXTSYM: return "MIPS_EXTSYM"; 2548130561Sobrien case SHT_MIPS_DENSE: return "MIPS_DENSE"; 2549130561Sobrien case SHT_MIPS_PDESC: return "MIPS_PDESC"; 2550130561Sobrien case SHT_MIPS_LOCSYM: return "MIPS_LOCSYM"; 2551130561Sobrien case SHT_MIPS_AUXSYM: return "MIPS_AUXSYM"; 2552130561Sobrien case SHT_MIPS_OPTSYM: return "MIPS_OPTSYM"; 2553130561Sobrien case SHT_MIPS_LOCSTR: return "MIPS_LOCSTR"; 2554130561Sobrien case SHT_MIPS_LINE: return "MIPS_LINE"; 2555130561Sobrien case SHT_MIPS_RFDESC: return "MIPS_RFDESC"; 2556130561Sobrien case SHT_MIPS_DELTASYM: return "MIPS_DELTASYM"; 2557130561Sobrien case SHT_MIPS_DELTAINST: return "MIPS_DELTAINST"; 2558130561Sobrien case SHT_MIPS_DELTACLASS: return "MIPS_DELTACLASS"; 2559130561Sobrien case SHT_MIPS_DWARF: return "MIPS_DWARF"; 2560130561Sobrien case SHT_MIPS_DELTADECL: return "MIPS_DELTADECL"; 2561130561Sobrien case SHT_MIPS_SYMBOL_LIB: return "MIPS_SYMBOL_LIB"; 2562130561Sobrien case SHT_MIPS_EVENTS: return "MIPS_EVENTS"; 2563130561Sobrien case SHT_MIPS_TRANSLATE: return "MIPS_TRANSLATE"; 2564130561Sobrien case SHT_MIPS_PIXIE: return "MIPS_PIXIE"; 2565130561Sobrien case SHT_MIPS_XLATE: return "MIPS_XLATE"; 2566130561Sobrien case SHT_MIPS_XLATE_DEBUG: return "MIPS_XLATE_DEBUG"; 2567130561Sobrien case SHT_MIPS_WHIRL: return "MIPS_WHIRL"; 2568130561Sobrien case SHT_MIPS_EH_REGION: return "MIPS_EH_REGION"; 2569130561Sobrien case SHT_MIPS_XLATE_OLD: return "MIPS_XLATE_OLD"; 257060484Sobrien case SHT_MIPS_PDR_EXCEPTION: return "MIPS_PDR_EXCEPTION"; 257160484Sobrien default: 257260484Sobrien break; 257360484Sobrien } 257460484Sobrien return NULL; 257560484Sobrien} 257660484Sobrien 257760484Sobrienstatic const char * 2578130561Sobrienget_parisc_section_type_name (unsigned int sh_type) 257960484Sobrien{ 258060484Sobrien switch (sh_type) 258160484Sobrien { 258260484Sobrien case SHT_PARISC_EXT: return "PARISC_EXT"; 258360484Sobrien case SHT_PARISC_UNWIND: return "PARISC_UNWIND"; 258460484Sobrien case SHT_PARISC_DOC: return "PARISC_DOC"; 2585218822Sdim case SHT_PARISC_ANNOT: return "PARISC_ANNOT"; 2586218822Sdim case SHT_PARISC_SYMEXTN: return "PARISC_SYMEXTN"; 2587218822Sdim case SHT_PARISC_STUBS: return "PARISC_STUBS"; 2588218822Sdim case SHT_PARISC_DLKM: return "PARISC_DLKM"; 258960484Sobrien default: 259060484Sobrien break; 259160484Sobrien } 259260484Sobrien return NULL; 259360484Sobrien} 259460484Sobrien 259560484Sobrienstatic const char * 2596130561Sobrienget_ia64_section_type_name (unsigned int sh_type) 259778828Sobrien{ 2598218822Sdim /* If the top 8 bits are 0x78 the next 8 are the os/abi ID. */ 2599130561Sobrien if ((sh_type & 0xFF000000) == SHT_IA_64_LOPSREG) 2600130561Sobrien return get_osabi_name ((sh_type & 0x00FF0000) >> 16); 2601130561Sobrien 260278828Sobrien switch (sh_type) 260378828Sobrien { 2604130561Sobrien case SHT_IA_64_EXT: return "IA_64_EXT"; 2605130561Sobrien case SHT_IA_64_UNWIND: return "IA_64_UNWIND"; 2606130561Sobrien case SHT_IA_64_PRIORITY_INIT: return "IA_64_PRIORITY_INIT"; 260778828Sobrien default: 260878828Sobrien break; 260978828Sobrien } 261078828Sobrien return NULL; 261178828Sobrien} 261278828Sobrien 261378828Sobrienstatic const char * 2614218822Sdimget_x86_64_section_type_name (unsigned int sh_type) 2615218822Sdim{ 2616218822Sdim switch (sh_type) 2617218822Sdim { 2618218822Sdim case SHT_X86_64_UNWIND: return "X86_64_UNWIND"; 2619218822Sdim default: 2620218822Sdim break; 2621218822Sdim } 2622218822Sdim return NULL; 2623218822Sdim} 2624218822Sdim 2625218822Sdimstatic const char * 2626218822Sdimget_arm_section_type_name (unsigned int sh_type) 2627218822Sdim{ 2628218822Sdim switch (sh_type) 2629218822Sdim { 2630218822Sdim case SHT_ARM_EXIDX: 2631218822Sdim return "ARM_EXIDX"; 2632218822Sdim case SHT_ARM_PREEMPTMAP: 2633218822Sdim return "ARM_PREEMPTMAP"; 2634218822Sdim case SHT_ARM_ATTRIBUTES: 2635218822Sdim return "ARM_ATTRIBUTES"; 2636218822Sdim default: 2637218822Sdim break; 2638218822Sdim } 2639218822Sdim return NULL; 2640218822Sdim} 2641218822Sdim 2642218822Sdimstatic const char * 2643130561Sobrienget_section_type_name (unsigned int sh_type) 264460484Sobrien{ 2645130561Sobrien static char buff[32]; 264660484Sobrien 264760484Sobrien switch (sh_type) 264860484Sobrien { 264960484Sobrien case SHT_NULL: return "NULL"; 265060484Sobrien case SHT_PROGBITS: return "PROGBITS"; 265160484Sobrien case SHT_SYMTAB: return "SYMTAB"; 265260484Sobrien case SHT_STRTAB: return "STRTAB"; 265360484Sobrien case SHT_RELA: return "RELA"; 265460484Sobrien case SHT_HASH: return "HASH"; 265560484Sobrien case SHT_DYNAMIC: return "DYNAMIC"; 265660484Sobrien case SHT_NOTE: return "NOTE"; 265760484Sobrien case SHT_NOBITS: return "NOBITS"; 265860484Sobrien case SHT_REL: return "REL"; 265960484Sobrien case SHT_SHLIB: return "SHLIB"; 266060484Sobrien case SHT_DYNSYM: return "DYNSYM"; 266160484Sobrien case SHT_INIT_ARRAY: return "INIT_ARRAY"; 266260484Sobrien case SHT_FINI_ARRAY: return "FINI_ARRAY"; 266360484Sobrien case SHT_PREINIT_ARRAY: return "PREINIT_ARRAY"; 2664218822Sdim case SHT_GNU_HASH: return "GNU_HASH"; 266577298Sobrien case SHT_GROUP: return "GROUP"; 266677298Sobrien case SHT_SYMTAB_SHNDX: return "SYMTAB SECTION INDICIES"; 266760484Sobrien case SHT_GNU_verdef: return "VERDEF"; 266860484Sobrien case SHT_GNU_verneed: return "VERNEED"; 266960484Sobrien case SHT_GNU_versym: return "VERSYM"; 2670130561Sobrien case 0x6ffffff0: return "VERSYM"; 2671130561Sobrien case 0x6ffffffc: return "VERDEF"; 267260484Sobrien case 0x7ffffffd: return "AUXILIARY"; 267360484Sobrien case 0x7fffffff: return "FILTER"; 2674104834Sobrien case SHT_GNU_LIBLIST: return "GNU_LIBLIST"; 267560484Sobrien 267660484Sobrien default: 267760484Sobrien if ((sh_type >= SHT_LOPROC) && (sh_type <= SHT_HIPROC)) 267860484Sobrien { 2679130561Sobrien const char *result; 268060484Sobrien 268160484Sobrien switch (elf_header.e_machine) 268260484Sobrien { 268360484Sobrien case EM_MIPS: 268478828Sobrien case EM_MIPS_RS3_LE: 268560484Sobrien result = get_mips_section_type_name (sh_type); 268660484Sobrien break; 268760484Sobrien case EM_PARISC: 268860484Sobrien result = get_parisc_section_type_name (sh_type); 268960484Sobrien break; 269078828Sobrien case EM_IA_64: 269178828Sobrien result = get_ia64_section_type_name (sh_type); 269278828Sobrien break; 2693218822Sdim case EM_X86_64: 2694218822Sdim result = get_x86_64_section_type_name (sh_type); 2695218822Sdim break; 2696218822Sdim case EM_ARM: 2697218822Sdim result = get_arm_section_type_name (sh_type); 2698218822Sdim break; 269960484Sobrien default: 270060484Sobrien result = NULL; 270160484Sobrien break; 270260484Sobrien } 270360484Sobrien 270460484Sobrien if (result != NULL) 270560484Sobrien return result; 270660484Sobrien 270789857Sobrien sprintf (buff, "LOPROC+%x", sh_type - SHT_LOPROC); 270860484Sobrien } 270960484Sobrien else if ((sh_type >= SHT_LOOS) && (sh_type <= SHT_HIOS)) 271089857Sobrien sprintf (buff, "LOOS+%x", sh_type - SHT_LOOS); 271160484Sobrien else if ((sh_type >= SHT_LOUSER) && (sh_type <= SHT_HIUSER)) 271289857Sobrien sprintf (buff, "LOUSER+%x", sh_type - SHT_LOUSER); 271360484Sobrien else 2714218822Sdim snprintf (buff, sizeof (buff), _("<unknown>: %x"), sh_type); 271560484Sobrien 271660484Sobrien return buff; 271760484Sobrien } 271860484Sobrien} 271960484Sobrien 2720104834Sobrien#define OPTION_DEBUG_DUMP 512 2721104834Sobrien 2722218822Sdimstatic struct option options[] = 272360484Sobrien{ 2724130561Sobrien {"all", no_argument, 0, 'a'}, 272560484Sobrien {"file-header", no_argument, 0, 'h'}, 272660484Sobrien {"program-headers", no_argument, 0, 'l'}, 2727130561Sobrien {"headers", no_argument, 0, 'e'}, 2728130561Sobrien {"histogram", no_argument, 0, 'I'}, 2729130561Sobrien {"segments", no_argument, 0, 'l'}, 2730130561Sobrien {"sections", no_argument, 0, 'S'}, 273160484Sobrien {"section-headers", no_argument, 0, 'S'}, 2732218822Sdim {"section-groups", no_argument, 0, 'g'}, 2733218822Sdim {"section-details", no_argument, 0, 't'}, 2734218822Sdim {"full-section-name",no_argument, 0, 'N'}, 2735130561Sobrien {"symbols", no_argument, 0, 's'}, 2736130561Sobrien {"syms", no_argument, 0, 's'}, 2737130561Sobrien {"relocs", no_argument, 0, 'r'}, 2738130561Sobrien {"notes", no_argument, 0, 'n'}, 2739130561Sobrien {"dynamic", no_argument, 0, 'd'}, 274060484Sobrien {"arch-specific", no_argument, 0, 'A'}, 274160484Sobrien {"version-info", no_argument, 0, 'V'}, 274260484Sobrien {"use-dynamic", no_argument, 0, 'D'}, 2743130561Sobrien {"hex-dump", required_argument, 0, 'x'}, 2744104834Sobrien {"debug-dump", optional_argument, 0, OPTION_DEBUG_DUMP}, 274578828Sobrien {"unwind", no_argument, 0, 'u'}, 274660484Sobrien#ifdef SUPPORT_DISASSEMBLY 274760484Sobrien {"instruction-dump", required_argument, 0, 'i'}, 274860484Sobrien#endif 274960484Sobrien 2750130561Sobrien {"version", no_argument, 0, 'v'}, 2751130561Sobrien {"wide", no_argument, 0, 'W'}, 2752130561Sobrien {"help", no_argument, 0, 'H'}, 2753130561Sobrien {0, no_argument, 0, 0} 275460484Sobrien}; 275560484Sobrien 275660484Sobrienstatic void 2757218822Sdimusage (FILE *stream) 275860484Sobrien{ 2759218822Sdim fprintf (stream, _("Usage: readelf <option(s)> elf-file(s)\n")); 2760218822Sdim fprintf (stream, _(" Display information about the contents of ELF format files\n")); 2761218822Sdim fprintf (stream, _(" Options are:\n\ 276289857Sobrien -a --all Equivalent to: -h -l -S -s -r -d -V -A -I\n\ 276389857Sobrien -h --file-header Display the ELF file header\n\ 276489857Sobrien -l --program-headers Display the program headers\n\ 276589857Sobrien --segments An alias for --program-headers\n\ 276689857Sobrien -S --section-headers Display the sections' header\n\ 276789857Sobrien --sections An alias for --section-headers\n\ 2768218822Sdim -g --section-groups Display the section groups\n\ 2769218822Sdim -t --section-details Display the section details\n\ 277089857Sobrien -e --headers Equivalent to: -h -l -S\n\ 277189857Sobrien -s --syms Display the symbol table\n\ 277289857Sobrien --symbols An alias for --syms\n\ 277389857Sobrien -n --notes Display the core notes (if present)\n\ 277489857Sobrien -r --relocs Display the relocations (if present)\n\ 277589857Sobrien -u --unwind Display the unwind info (if present)\n\ 2776218822Sdim -d --dynamic Display the dynamic section (if present)\n\ 277789857Sobrien -V --version-info Display the version sections (if present)\n\ 277889857Sobrien -A --arch-specific Display architecture specific information (if any).\n\ 277989857Sobrien -D --use-dynamic Use the dynamic section info when displaying symbols\n\ 278089857Sobrien -x --hex-dump=<number> Dump the contents of section <number>\n\ 2781218822Sdim -w[liaprmfFsoR] or\n\ 2782218822Sdim --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=str,=loc,=Ranges]\n\ 278389857Sobrien Display the contents of DWARF2 debug sections\n")); 278460484Sobrien#ifdef SUPPORT_DISASSEMBLY 2785218822Sdim fprintf (stream, _("\ 278689857Sobrien -i --instruction-dump=<number>\n\ 278789857Sobrien Disassemble the contents of section <number>\n")); 278860484Sobrien#endif 2789218822Sdim fprintf (stream, _("\ 279089857Sobrien -I --histogram Display histogram of bucket list lengths\n\ 279189857Sobrien -W --wide Allow output width to exceed 80 characters\n\ 2792218822Sdim @<file> Read options from <file>\n\ 279389857Sobrien -H --help Display this information\n\ 279489857Sobrien -v --version Display the version number of readelf\n")); 2795218822Sdim 2796218822Sdim if (REPORT_BUGS_TO[0] && stream == stdout) 2797218822Sdim fprintf (stdout, _("Report bugs to %s\n"), REPORT_BUGS_TO); 279860484Sobrien 2799218822Sdim exit (stream == stdout ? 0 : 1); 280060484Sobrien} 280160484Sobrien 2802218822Sdim/* Record the fact that the user wants the contents of section number 2803218822Sdim SECTION to be displayed using the method(s) encoded as flags bits 2804218822Sdim in TYPE. Note, TYPE can be zero if we are creating the array for 2805218822Sdim the first time. */ 2806218822Sdim 280760484Sobrienstatic void 2808130561Sobrienrequest_dump (unsigned int section, int type) 280960484Sobrien{ 281060484Sobrien if (section >= num_dump_sects) 281160484Sobrien { 2812130561Sobrien char *new_dump_sects; 281360484Sobrien 2814130561Sobrien new_dump_sects = calloc (section + 1, 1); 281560484Sobrien 281660484Sobrien if (new_dump_sects == NULL) 2817218822Sdim error (_("Out of memory allocating dump request table.\n")); 281860484Sobrien else 281960484Sobrien { 282060484Sobrien /* Copy current flag settings. */ 282160484Sobrien memcpy (new_dump_sects, dump_sects, num_dump_sects); 282260484Sobrien 282360484Sobrien free (dump_sects); 282460484Sobrien 282560484Sobrien dump_sects = new_dump_sects; 282660484Sobrien num_dump_sects = section + 1; 282760484Sobrien } 282860484Sobrien } 282960484Sobrien 283060484Sobrien if (dump_sects) 2831130561Sobrien dump_sects[section] |= type; 283260484Sobrien 283360484Sobrien return; 283460484Sobrien} 283560484Sobrien 2836218822Sdim/* Request a dump by section name. */ 2837218822Sdim 283860484Sobrienstatic void 2839218822Sdimrequest_dump_byname (const char *section, int type) 2840218822Sdim{ 2841218822Sdim struct dump_list_entry *new_request; 2842218822Sdim 2843218822Sdim new_request = malloc (sizeof (struct dump_list_entry)); 2844218822Sdim if (!new_request) 2845218822Sdim error (_("Out of memory allocating dump request table.\n")); 2846218822Sdim 2847218822Sdim new_request->name = strdup (section); 2848218822Sdim if (!new_request->name) 2849218822Sdim error (_("Out of memory allocating dump request table.\n")); 2850218822Sdim 2851218822Sdim new_request->type = type; 2852218822Sdim 2853218822Sdim new_request->next = dump_sects_byname; 2854218822Sdim dump_sects_byname = new_request; 2855218822Sdim} 2856218822Sdim 2857218822Sdimstatic void 2858130561Sobrienparse_args (int argc, char **argv) 285960484Sobrien{ 286060484Sobrien int c; 286160484Sobrien 286260484Sobrien if (argc < 2) 2863218822Sdim usage (stderr); 286460484Sobrien 286560484Sobrien while ((c = getopt_long 2866218822Sdim (argc, argv, "ersuahnldSDAINtgw::x:i:vVWH", options, NULL)) != EOF) 286760484Sobrien { 2868130561Sobrien char *cp; 2869130561Sobrien int section; 287060484Sobrien 287160484Sobrien switch (c) 287260484Sobrien { 287360484Sobrien case 0: 287460484Sobrien /* Long options. */ 287560484Sobrien break; 287660484Sobrien case 'H': 2877218822Sdim usage (stdout); 287860484Sobrien break; 287960484Sobrien 288060484Sobrien case 'a': 2881130561Sobrien do_syms++; 2882130561Sobrien do_reloc++; 2883130561Sobrien do_unwind++; 2884130561Sobrien do_dynamic++; 2885130561Sobrien do_header++; 2886130561Sobrien do_sections++; 2887218822Sdim do_section_groups++; 2888130561Sobrien do_segments++; 2889130561Sobrien do_version++; 2890130561Sobrien do_histogram++; 2891130561Sobrien do_arch++; 2892130561Sobrien do_notes++; 289360484Sobrien break; 2894218822Sdim case 'g': 2895218822Sdim do_section_groups++; 2896218822Sdim break; 2897218822Sdim case 't': 2898218822Sdim case 'N': 2899218822Sdim do_sections++; 2900218822Sdim do_section_details++; 2901218822Sdim break; 290260484Sobrien case 'e': 2903130561Sobrien do_header++; 2904130561Sobrien do_sections++; 2905130561Sobrien do_segments++; 290660484Sobrien break; 290760484Sobrien case 'A': 2908130561Sobrien do_arch++; 290960484Sobrien break; 291060484Sobrien case 'D': 2911130561Sobrien do_using_dynamic++; 291260484Sobrien break; 291360484Sobrien case 'r': 2914130561Sobrien do_reloc++; 291560484Sobrien break; 291678828Sobrien case 'u': 2917130561Sobrien do_unwind++; 291878828Sobrien break; 291960484Sobrien case 'h': 2920130561Sobrien do_header++; 292160484Sobrien break; 292260484Sobrien case 'l': 2923130561Sobrien do_segments++; 292460484Sobrien break; 292560484Sobrien case 's': 2926130561Sobrien do_syms++; 292760484Sobrien break; 292860484Sobrien case 'S': 2929130561Sobrien do_sections++; 293060484Sobrien break; 293160484Sobrien case 'd': 2932130561Sobrien do_dynamic++; 293360484Sobrien break; 293460484Sobrien case 'I': 2935130561Sobrien do_histogram++; 293660484Sobrien break; 293760484Sobrien case 'n': 2938130561Sobrien do_notes++; 293960484Sobrien break; 294060484Sobrien case 'x': 2941130561Sobrien do_dump++; 294260484Sobrien section = strtoul (optarg, & cp, 0); 2943130561Sobrien if (! *cp && section >= 0) 2944218822Sdim request_dump (section, HEX_DUMP); 2945218822Sdim else 2946218822Sdim request_dump_byname (optarg, HEX_DUMP); 2947218822Sdim break; 294860484Sobrien case 'w': 2949130561Sobrien do_dump++; 295060484Sobrien if (optarg == 0) 295160484Sobrien do_debugging = 1; 295260484Sobrien else 295360484Sobrien { 295489857Sobrien unsigned int index = 0; 2955104834Sobrien 295660484Sobrien do_debugging = 0; 295760484Sobrien 295889857Sobrien while (optarg[index]) 295989857Sobrien switch (optarg[index++]) 296089857Sobrien { 296189857Sobrien case 'i': 296289857Sobrien case 'I': 296389857Sobrien do_debug_info = 1; 296489857Sobrien break; 296560484Sobrien 296689857Sobrien case 'a': 296789857Sobrien case 'A': 296889857Sobrien do_debug_abbrevs = 1; 296989857Sobrien break; 297060484Sobrien 297189857Sobrien case 'l': 297289857Sobrien case 'L': 297389857Sobrien do_debug_lines = 1; 297489857Sobrien break; 297560484Sobrien 297689857Sobrien case 'p': 297789857Sobrien case 'P': 297889857Sobrien do_debug_pubnames = 1; 297989857Sobrien break; 298060484Sobrien 298189857Sobrien case 'r': 298289857Sobrien do_debug_aranges = 1; 298389857Sobrien break; 298477298Sobrien 2985218822Sdim case 'R': 2986218822Sdim do_debug_ranges = 1; 2987218822Sdim break; 2988218822Sdim 298989857Sobrien case 'F': 299089857Sobrien do_debug_frames_interp = 1; 299189857Sobrien case 'f': 299289857Sobrien do_debug_frames = 1; 299389857Sobrien break; 299489857Sobrien 299589857Sobrien case 'm': 299689857Sobrien case 'M': 299789857Sobrien do_debug_macinfo = 1; 299889857Sobrien break; 299989857Sobrien 300089857Sobrien case 's': 300189857Sobrien case 'S': 300289857Sobrien do_debug_str = 1; 300389857Sobrien break; 300489857Sobrien 300599461Sobrien case 'o': 300699461Sobrien case 'O': 300799461Sobrien do_debug_loc = 1; 300899461Sobrien break; 3009104834Sobrien 301089857Sobrien default: 301199461Sobrien warn (_("Unrecognized debug option '%s'\n"), optarg); 301289857Sobrien break; 301389857Sobrien } 301460484Sobrien } 301560484Sobrien break; 3016104834Sobrien case OPTION_DEBUG_DUMP: 3017130561Sobrien do_dump++; 3018104834Sobrien if (optarg == 0) 3019104834Sobrien do_debugging = 1; 3020104834Sobrien else 3021104834Sobrien { 3022218822Sdim typedef struct 3023218822Sdim { 3024218822Sdim const char * option; 3025218822Sdim int * variable; 3026218822Sdim } 3027218822Sdim debug_dump_long_opts; 3028218822Sdim 3029218822Sdim debug_dump_long_opts opts_table [] = 3030218822Sdim { 3031218822Sdim /* Please keep this table alpha- sorted. */ 3032218822Sdim { "Ranges", & do_debug_ranges }, 3033218822Sdim { "abbrev", & do_debug_abbrevs }, 3034218822Sdim { "aranges", & do_debug_aranges }, 3035218822Sdim { "frames", & do_debug_frames }, 3036218822Sdim { "frames-interp", & do_debug_frames_interp }, 3037218822Sdim { "info", & do_debug_info }, 3038218822Sdim { "line", & do_debug_lines }, 3039218822Sdim { "loc", & do_debug_loc }, 3040218822Sdim { "macro", & do_debug_macinfo }, 3041218822Sdim { "pubnames", & do_debug_pubnames }, 3042218822Sdim /* This entry is for compatability 3043218822Sdim with earlier versions of readelf. */ 3044218822Sdim { "ranges", & do_debug_aranges }, 3045218822Sdim { "str", & do_debug_str }, 3046218822Sdim { NULL, NULL } 3047218822Sdim }; 3048218822Sdim 3049104834Sobrien const char *p; 3050104834Sobrien 3051104834Sobrien do_debugging = 0; 3052104834Sobrien 3053104834Sobrien p = optarg; 3054104834Sobrien while (*p) 3055104834Sobrien { 3056218822Sdim debug_dump_long_opts * entry; 3057218822Sdim 3058218822Sdim for (entry = opts_table; entry->option; entry++) 3059104834Sobrien { 3060218822Sdim size_t len = strlen (entry->option); 3061104834Sobrien 3062218822Sdim if (strneq (p, entry->option, len) 3063104834Sobrien && (p[len] == ',' || p[len] == '\0')) 3064104834Sobrien { 3065218822Sdim * entry->variable = 1; 3066104834Sobrien 3067218822Sdim /* The --debug-dump=frames-interp option also 3068218822Sdim enables the --debug-dump=frames option. */ 3069218822Sdim if (do_debug_frames_interp) 3070218822Sdim do_debug_frames = 1; 3071104834Sobrien 3072104834Sobrien p += len; 3073104834Sobrien break; 3074104834Sobrien } 3075104834Sobrien } 3076104834Sobrien 3077218822Sdim if (entry->option == NULL) 3078104834Sobrien { 3079104834Sobrien warn (_("Unrecognized debug option '%s'\n"), p); 3080104834Sobrien p = strchr (p, ','); 3081104834Sobrien if (p == NULL) 3082104834Sobrien break; 3083104834Sobrien } 3084104834Sobrien 3085104834Sobrien if (*p == ',') 3086104834Sobrien p++; 3087104834Sobrien } 3088104834Sobrien } 3089104834Sobrien break; 309060484Sobrien#ifdef SUPPORT_DISASSEMBLY 309160484Sobrien case 'i': 3092130561Sobrien do_dump++; 309360484Sobrien section = strtoul (optarg, & cp, 0); 3094130561Sobrien if (! *cp && section >= 0) 309560484Sobrien { 309660484Sobrien request_dump (section, DISASS_DUMP); 309760484Sobrien break; 309860484Sobrien } 309960484Sobrien goto oops; 310060484Sobrien#endif 310160484Sobrien case 'v': 310260484Sobrien print_version (program_name); 310360484Sobrien break; 310460484Sobrien case 'V': 3105130561Sobrien do_version++; 310660484Sobrien break; 310789857Sobrien case 'W': 3108130561Sobrien do_wide++; 310989857Sobrien break; 311060484Sobrien default: 3111218822Sdim#ifdef SUPPORT_DISASSEMBLY 311260484Sobrien oops: 3113218822Sdim#endif 311460484Sobrien /* xgettext:c-format */ 311560484Sobrien error (_("Invalid option '-%c'\n"), c); 311660484Sobrien /* Drop through. */ 311760484Sobrien case '?': 3118218822Sdim usage (stderr); 311960484Sobrien } 312060484Sobrien } 312160484Sobrien 312278828Sobrien if (!do_dynamic && !do_syms && !do_reloc && !do_unwind && !do_sections 312360484Sobrien && !do_segments && !do_header && !do_dump && !do_version 3124218822Sdim && !do_histogram && !do_debugging && !do_arch && !do_notes 3125218822Sdim && !do_section_groups) 3126218822Sdim usage (stderr); 312760484Sobrien else if (argc < 3) 312860484Sobrien { 312960484Sobrien warn (_("Nothing to do.\n")); 3130218822Sdim usage (stderr); 313160484Sobrien } 313260484Sobrien} 313360484Sobrien 313460484Sobrienstatic const char * 3135130561Sobrienget_elf_class (unsigned int elf_class) 313660484Sobrien{ 3137130561Sobrien static char buff[32]; 313860484Sobrien 313960484Sobrien switch (elf_class) 314060484Sobrien { 314160484Sobrien case ELFCLASSNONE: return _("none"); 314289857Sobrien case ELFCLASS32: return "ELF32"; 314389857Sobrien case ELFCLASS64: return "ELF64"; 314460484Sobrien default: 3145218822Sdim snprintf (buff, sizeof (buff), _("<unknown: %x>"), elf_class); 314660484Sobrien return buff; 314760484Sobrien } 314860484Sobrien} 314960484Sobrien 315060484Sobrienstatic const char * 3151130561Sobrienget_data_encoding (unsigned int encoding) 315260484Sobrien{ 3153130561Sobrien static char buff[32]; 315460484Sobrien 315560484Sobrien switch (encoding) 315660484Sobrien { 315760484Sobrien case ELFDATANONE: return _("none"); 315860484Sobrien case ELFDATA2LSB: return _("2's complement, little endian"); 315960484Sobrien case ELFDATA2MSB: return _("2's complement, big endian"); 316060484Sobrien default: 3161218822Sdim snprintf (buff, sizeof (buff), _("<unknown: %x>"), encoding); 316260484Sobrien return buff; 316360484Sobrien } 316460484Sobrien} 316560484Sobrien 3166130561Sobrien/* Decode the data held in 'elf_header'. */ 316760484Sobrien 316860484Sobrienstatic int 3169130561Sobrienprocess_file_header (void) 317060484Sobrien{ 3171130561Sobrien if ( elf_header.e_ident[EI_MAG0] != ELFMAG0 3172130561Sobrien || elf_header.e_ident[EI_MAG1] != ELFMAG1 3173130561Sobrien || elf_header.e_ident[EI_MAG2] != ELFMAG2 3174130561Sobrien || elf_header.e_ident[EI_MAG3] != ELFMAG3) 317560484Sobrien { 317660484Sobrien error 317760484Sobrien (_("Not an ELF file - it has the wrong magic bytes at the start\n")); 317860484Sobrien return 0; 317960484Sobrien } 318060484Sobrien 318160484Sobrien if (do_header) 318260484Sobrien { 318360484Sobrien int i; 318460484Sobrien 318560484Sobrien printf (_("ELF Header:\n")); 318660484Sobrien printf (_(" Magic: ")); 3187130561Sobrien for (i = 0; i < EI_NIDENT; i++) 3188130561Sobrien printf ("%2.2x ", elf_header.e_ident[i]); 318960484Sobrien printf ("\n"); 319060484Sobrien printf (_(" Class: %s\n"), 3191130561Sobrien get_elf_class (elf_header.e_ident[EI_CLASS])); 319260484Sobrien printf (_(" Data: %s\n"), 3193130561Sobrien get_data_encoding (elf_header.e_ident[EI_DATA])); 319460484Sobrien printf (_(" Version: %d %s\n"), 3195130561Sobrien elf_header.e_ident[EI_VERSION], 3196130561Sobrien (elf_header.e_ident[EI_VERSION] == EV_CURRENT 319760484Sobrien ? "(current)" 3198130561Sobrien : (elf_header.e_ident[EI_VERSION] != EV_NONE 319960484Sobrien ? "<unknown: %lx>" 320060484Sobrien : ""))); 320160484Sobrien printf (_(" OS/ABI: %s\n"), 3202130561Sobrien get_osabi_name (elf_header.e_ident[EI_OSABI])); 320360484Sobrien printf (_(" ABI Version: %d\n"), 3204130561Sobrien elf_header.e_ident[EI_ABIVERSION]); 320560484Sobrien printf (_(" Type: %s\n"), 320660484Sobrien get_file_type (elf_header.e_type)); 320760484Sobrien printf (_(" Machine: %s\n"), 320860484Sobrien get_machine_name (elf_header.e_machine)); 320960484Sobrien printf (_(" Version: 0x%lx\n"), 321060484Sobrien (unsigned long) elf_header.e_version); 321177298Sobrien 321260484Sobrien printf (_(" Entry point address: ")); 321360484Sobrien print_vma ((bfd_vma) elf_header.e_entry, PREFIX_HEX); 321460484Sobrien printf (_("\n Start of program headers: ")); 321560484Sobrien print_vma ((bfd_vma) elf_header.e_phoff, DEC); 321660484Sobrien printf (_(" (bytes into file)\n Start of section headers: ")); 321760484Sobrien print_vma ((bfd_vma) elf_header.e_shoff, DEC); 321860484Sobrien printf (_(" (bytes into file)\n")); 321977298Sobrien 322060484Sobrien printf (_(" Flags: 0x%lx%s\n"), 322160484Sobrien (unsigned long) elf_header.e_flags, 322260484Sobrien get_machine_flags (elf_header.e_flags, elf_header.e_machine)); 322360484Sobrien printf (_(" Size of this header: %ld (bytes)\n"), 322460484Sobrien (long) elf_header.e_ehsize); 322560484Sobrien printf (_(" Size of program headers: %ld (bytes)\n"), 322660484Sobrien (long) elf_header.e_phentsize); 322760484Sobrien printf (_(" Number of program headers: %ld\n"), 322860484Sobrien (long) elf_header.e_phnum); 322960484Sobrien printf (_(" Size of section headers: %ld (bytes)\n"), 323060484Sobrien (long) elf_header.e_shentsize); 323189857Sobrien printf (_(" Number of section headers: %ld"), 323260484Sobrien (long) elf_header.e_shnum); 323389857Sobrien if (section_headers != NULL && elf_header.e_shnum == 0) 323489857Sobrien printf (" (%ld)", (long) section_headers[0].sh_size); 323589857Sobrien putc ('\n', stdout); 323689857Sobrien printf (_(" Section header string table index: %ld"), 323760484Sobrien (long) elf_header.e_shstrndx); 323889857Sobrien if (section_headers != NULL && elf_header.e_shstrndx == SHN_XINDEX) 323989857Sobrien printf (" (%ld)", (long) section_headers[0].sh_link); 3240218822Sdim else if (elf_header.e_shstrndx != SHN_UNDEF 3241218822Sdim && (elf_header.e_shstrndx >= elf_header.e_shnum 3242218822Sdim || (elf_header.e_shstrndx >= SHN_LORESERVE 3243218822Sdim && elf_header.e_shstrndx <= SHN_HIRESERVE))) 3244218822Sdim printf (" <corrupt: out of range>"); 324589857Sobrien putc ('\n', stdout); 324660484Sobrien } 324760484Sobrien 324889857Sobrien if (section_headers != NULL) 324989857Sobrien { 325089857Sobrien if (elf_header.e_shnum == 0) 325189857Sobrien elf_header.e_shnum = section_headers[0].sh_size; 325289857Sobrien if (elf_header.e_shstrndx == SHN_XINDEX) 325389857Sobrien elf_header.e_shstrndx = section_headers[0].sh_link; 3254218822Sdim else if (elf_header.e_shstrndx != SHN_UNDEF 3255218822Sdim && (elf_header.e_shstrndx >= elf_header.e_shnum 3256218822Sdim || (elf_header.e_shstrndx >= SHN_LORESERVE 3257218822Sdim && elf_header.e_shstrndx <= SHN_HIRESERVE))) 3258218822Sdim elf_header.e_shstrndx = SHN_UNDEF; 325989857Sobrien free (section_headers); 326089857Sobrien section_headers = NULL; 326189857Sobrien } 326289857Sobrien 326360484Sobrien return 1; 326460484Sobrien} 326560484Sobrien 326660484Sobrien 326760484Sobrienstatic int 3268130561Sobrienget_32bit_program_headers (FILE *file, Elf_Internal_Phdr *program_headers) 326960484Sobrien{ 3270130561Sobrien Elf32_External_Phdr *phdrs; 3271130561Sobrien Elf32_External_Phdr *external; 3272130561Sobrien Elf_Internal_Phdr *internal; 3273130561Sobrien unsigned int i; 327460484Sobrien 3275130561Sobrien phdrs = get_data (NULL, file, elf_header.e_phoff, 3276218822Sdim elf_header.e_phentsize, elf_header.e_phnum, 3277130561Sobrien _("program headers")); 327889857Sobrien if (!phdrs) 327989857Sobrien return 0; 328060484Sobrien 328160484Sobrien for (i = 0, internal = program_headers, external = phdrs; 328260484Sobrien i < elf_header.e_phnum; 3283130561Sobrien i++, internal++, external++) 328460484Sobrien { 328560484Sobrien internal->p_type = BYTE_GET (external->p_type); 328660484Sobrien internal->p_offset = BYTE_GET (external->p_offset); 328760484Sobrien internal->p_vaddr = BYTE_GET (external->p_vaddr); 328860484Sobrien internal->p_paddr = BYTE_GET (external->p_paddr); 328960484Sobrien internal->p_filesz = BYTE_GET (external->p_filesz); 329060484Sobrien internal->p_memsz = BYTE_GET (external->p_memsz); 329160484Sobrien internal->p_flags = BYTE_GET (external->p_flags); 329260484Sobrien internal->p_align = BYTE_GET (external->p_align); 329360484Sobrien } 329460484Sobrien 329560484Sobrien free (phdrs); 329660484Sobrien 329760484Sobrien return 1; 329860484Sobrien} 329960484Sobrien 330060484Sobrienstatic int 3301130561Sobrienget_64bit_program_headers (FILE *file, Elf_Internal_Phdr *program_headers) 330260484Sobrien{ 3303130561Sobrien Elf64_External_Phdr *phdrs; 3304130561Sobrien Elf64_External_Phdr *external; 3305130561Sobrien Elf_Internal_Phdr *internal; 3306130561Sobrien unsigned int i; 330760484Sobrien 3308130561Sobrien phdrs = get_data (NULL, file, elf_header.e_phoff, 3309218822Sdim elf_header.e_phentsize, elf_header.e_phnum, 3310130561Sobrien _("program headers")); 331189857Sobrien if (!phdrs) 331289857Sobrien return 0; 331360484Sobrien 331460484Sobrien for (i = 0, internal = program_headers, external = phdrs; 331560484Sobrien i < elf_header.e_phnum; 3316130561Sobrien i++, internal++, external++) 331760484Sobrien { 331860484Sobrien internal->p_type = BYTE_GET (external->p_type); 331960484Sobrien internal->p_flags = BYTE_GET (external->p_flags); 3320218822Sdim internal->p_offset = BYTE_GET (external->p_offset); 3321218822Sdim internal->p_vaddr = BYTE_GET (external->p_vaddr); 3322218822Sdim internal->p_paddr = BYTE_GET (external->p_paddr); 3323218822Sdim internal->p_filesz = BYTE_GET (external->p_filesz); 3324218822Sdim internal->p_memsz = BYTE_GET (external->p_memsz); 3325218822Sdim internal->p_align = BYTE_GET (external->p_align); 332660484Sobrien } 332760484Sobrien 332860484Sobrien free (phdrs); 332960484Sobrien 333060484Sobrien return 1; 333160484Sobrien} 333260484Sobrien 3333130561Sobrien/* Returns 1 if the program headers were read into `program_headers'. */ 3334130561Sobrien 333560484Sobrienstatic int 3336130561Sobrienget_program_headers (FILE *file) 333760484Sobrien{ 3338130561Sobrien Elf_Internal_Phdr *phdrs; 333960484Sobrien 3340130561Sobrien /* Check cache of prior read. */ 3341130561Sobrien if (program_headers != NULL) 3342130561Sobrien return 1; 3343130561Sobrien 3344218822Sdim phdrs = cmalloc (elf_header.e_phnum, sizeof (Elf_Internal_Phdr)); 3345130561Sobrien 3346130561Sobrien if (phdrs == NULL) 3347130561Sobrien { 3348130561Sobrien error (_("Out of memory\n")); 3349130561Sobrien return 0; 3350130561Sobrien } 3351130561Sobrien 3352130561Sobrien if (is_32bit_elf 3353130561Sobrien ? get_32bit_program_headers (file, phdrs) 3354130561Sobrien : get_64bit_program_headers (file, phdrs)) 3355130561Sobrien { 3356130561Sobrien program_headers = phdrs; 3357130561Sobrien return 1; 3358130561Sobrien } 3359130561Sobrien 3360130561Sobrien free (phdrs); 3361130561Sobrien return 0; 3362130561Sobrien} 3363130561Sobrien 3364130561Sobrien/* Returns 1 if the program headers were loaded. */ 3365130561Sobrien 3366130561Sobrienstatic int 3367130561Sobrienprocess_program_headers (FILE *file) 3368130561Sobrien{ 3369130561Sobrien Elf_Internal_Phdr *segment; 3370130561Sobrien unsigned int i; 3371130561Sobrien 337260484Sobrien if (elf_header.e_phnum == 0) 337360484Sobrien { 337460484Sobrien if (do_segments) 337560484Sobrien printf (_("\nThere are no program headers in this file.\n")); 3376130561Sobrien return 0; 337760484Sobrien } 337860484Sobrien 337960484Sobrien if (do_segments && !do_header) 338060484Sobrien { 338160484Sobrien printf (_("\nElf file type is %s\n"), get_file_type (elf_header.e_type)); 338260484Sobrien printf (_("Entry point ")); 338360484Sobrien print_vma ((bfd_vma) elf_header.e_entry, PREFIX_HEX); 338460484Sobrien printf (_("\nThere are %d program headers, starting at offset "), 338560484Sobrien elf_header.e_phnum); 338660484Sobrien print_vma ((bfd_vma) elf_header.e_phoff, DEC); 338760484Sobrien printf ("\n"); 338860484Sobrien } 338960484Sobrien 3390130561Sobrien if (! get_program_headers (file)) 339160484Sobrien return 0; 339260484Sobrien 339360484Sobrien if (do_segments) 339460484Sobrien { 3395104834Sobrien if (elf_header.e_phnum > 1) 3396104834Sobrien printf (_("\nProgram Headers:\n")); 3397104834Sobrien else 3398104834Sobrien printf (_("\nProgram Headers:\n")); 339977298Sobrien 340060484Sobrien if (is_32bit_elf) 340160484Sobrien printf 340260484Sobrien (_(" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n")); 340389857Sobrien else if (do_wide) 340489857Sobrien printf 340589857Sobrien (_(" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n")); 340660484Sobrien else 340760484Sobrien { 340860484Sobrien printf 340960484Sobrien (_(" Type Offset VirtAddr PhysAddr\n")); 341060484Sobrien printf 341160484Sobrien (_(" FileSiz MemSiz Flags Align\n")); 341260484Sobrien } 341360484Sobrien } 341460484Sobrien 341560484Sobrien dynamic_addr = 0; 341660484Sobrien dynamic_size = 0; 341760484Sobrien 341860484Sobrien for (i = 0, segment = program_headers; 341960484Sobrien i < elf_header.e_phnum; 3420130561Sobrien i++, segment++) 342160484Sobrien { 342260484Sobrien if (do_segments) 342360484Sobrien { 342460484Sobrien printf (" %-14.14s ", get_segment_type (segment->p_type)); 342560484Sobrien 342660484Sobrien if (is_32bit_elf) 342760484Sobrien { 342860484Sobrien printf ("0x%6.6lx ", (unsigned long) segment->p_offset); 342960484Sobrien printf ("0x%8.8lx ", (unsigned long) segment->p_vaddr); 343060484Sobrien printf ("0x%8.8lx ", (unsigned long) segment->p_paddr); 343160484Sobrien printf ("0x%5.5lx ", (unsigned long) segment->p_filesz); 343260484Sobrien printf ("0x%5.5lx ", (unsigned long) segment->p_memsz); 343360484Sobrien printf ("%c%c%c ", 343460484Sobrien (segment->p_flags & PF_R ? 'R' : ' '), 343560484Sobrien (segment->p_flags & PF_W ? 'W' : ' '), 343660484Sobrien (segment->p_flags & PF_X ? 'E' : ' ')); 343760484Sobrien printf ("%#lx", (unsigned long) segment->p_align); 343860484Sobrien } 343989857Sobrien else if (do_wide) 344089857Sobrien { 344189857Sobrien if ((unsigned long) segment->p_offset == segment->p_offset) 344289857Sobrien printf ("0x%6.6lx ", (unsigned long) segment->p_offset); 344389857Sobrien else 344489857Sobrien { 344589857Sobrien print_vma (segment->p_offset, FULL_HEX); 344689857Sobrien putchar (' '); 344789857Sobrien } 344889857Sobrien 344989857Sobrien print_vma (segment->p_vaddr, FULL_HEX); 345089857Sobrien putchar (' '); 345189857Sobrien print_vma (segment->p_paddr, FULL_HEX); 345289857Sobrien putchar (' '); 345389857Sobrien 345489857Sobrien if ((unsigned long) segment->p_filesz == segment->p_filesz) 345589857Sobrien printf ("0x%6.6lx ", (unsigned long) segment->p_filesz); 345689857Sobrien else 345789857Sobrien { 345889857Sobrien print_vma (segment->p_filesz, FULL_HEX); 345989857Sobrien putchar (' '); 346089857Sobrien } 346189857Sobrien 346289857Sobrien if ((unsigned long) segment->p_memsz == segment->p_memsz) 346389857Sobrien printf ("0x%6.6lx", (unsigned long) segment->p_memsz); 346489857Sobrien else 346589857Sobrien { 346689857Sobrien print_vma (segment->p_offset, FULL_HEX); 346789857Sobrien } 346889857Sobrien 346989857Sobrien printf (" %c%c%c ", 347089857Sobrien (segment->p_flags & PF_R ? 'R' : ' '), 347189857Sobrien (segment->p_flags & PF_W ? 'W' : ' '), 347289857Sobrien (segment->p_flags & PF_X ? 'E' : ' ')); 347389857Sobrien 347489857Sobrien if ((unsigned long) segment->p_align == segment->p_align) 347589857Sobrien printf ("%#lx", (unsigned long) segment->p_align); 347689857Sobrien else 347789857Sobrien { 347889857Sobrien print_vma (segment->p_align, PREFIX_HEX); 347989857Sobrien } 348089857Sobrien } 348160484Sobrien else 348260484Sobrien { 348360484Sobrien print_vma (segment->p_offset, FULL_HEX); 348460484Sobrien putchar (' '); 348560484Sobrien print_vma (segment->p_vaddr, FULL_HEX); 348660484Sobrien putchar (' '); 348760484Sobrien print_vma (segment->p_paddr, FULL_HEX); 348860484Sobrien printf ("\n "); 348960484Sobrien print_vma (segment->p_filesz, FULL_HEX); 349060484Sobrien putchar (' '); 349160484Sobrien print_vma (segment->p_memsz, FULL_HEX); 349260484Sobrien printf (" %c%c%c ", 349360484Sobrien (segment->p_flags & PF_R ? 'R' : ' '), 349460484Sobrien (segment->p_flags & PF_W ? 'W' : ' '), 349560484Sobrien (segment->p_flags & PF_X ? 'E' : ' ')); 349660484Sobrien print_vma (segment->p_align, HEX); 349760484Sobrien } 349860484Sobrien } 349960484Sobrien 350060484Sobrien switch (segment->p_type) 350160484Sobrien { 350260484Sobrien case PT_DYNAMIC: 350360484Sobrien if (dynamic_addr) 350460484Sobrien error (_("more than one dynamic segment\n")); 350560484Sobrien 3506218822Sdim /* Try to locate the .dynamic section. If there is 3507218822Sdim a section header table, we can easily locate it. */ 3508218822Sdim if (section_headers != NULL) 3509218822Sdim { 3510218822Sdim Elf_Internal_Shdr *sec; 3511218822Sdim 3512218822Sdim sec = find_section (".dynamic"); 3513218822Sdim if (sec == NULL || sec->sh_size == 0) 3514218822Sdim { 3515218822Sdim error (_("no .dynamic section in the dynamic segment\n")); 3516218822Sdim break; 3517218822Sdim } 3518218822Sdim 3519218822Sdim if (sec->sh_type == SHT_NOBITS) 3520218822Sdim break; 3521218822Sdim 3522218822Sdim dynamic_addr = sec->sh_offset; 3523218822Sdim dynamic_size = sec->sh_size; 3524218822Sdim 3525218822Sdim if (dynamic_addr < segment->p_offset 3526218822Sdim || dynamic_addr > segment->p_offset + segment->p_filesz) 3527218822Sdim warn (_("the .dynamic section is not contained within the dynamic segment\n")); 3528218822Sdim else if (dynamic_addr > segment->p_offset) 3529218822Sdim warn (_("the .dynamic section is not the first section in the dynamic segment.\n")); 3530218822Sdim } 3531218822Sdim else 3532218822Sdim { 3533218822Sdim /* Otherwise, we can only assume that the .dynamic 3534218822Sdim section is the first section in the DYNAMIC segment. */ 3535218822Sdim dynamic_addr = segment->p_offset; 3536218822Sdim dynamic_size = segment->p_filesz; 3537218822Sdim } 353860484Sobrien break; 353960484Sobrien 354060484Sobrien case PT_INTERP: 3541130561Sobrien if (fseek (file, archive_file_offset + (long) segment->p_offset, 3542130561Sobrien SEEK_SET)) 354360484Sobrien error (_("Unable to find program interpreter name\n")); 354460484Sobrien else 354560484Sobrien { 3546218822Sdim char fmt [32]; 3547218822Sdim int ret = snprintf (fmt, sizeof (fmt), "%%%ds", PATH_MAX); 3548218822Sdim 3549218822Sdim if (ret >= (int) sizeof (fmt) || ret < 0) 3550218822Sdim error (_("Internal error: failed to create format string to display program interpreter\n")); 3551218822Sdim 355260484Sobrien program_interpreter[0] = 0; 3553218822Sdim if (fscanf (file, fmt, program_interpreter) <= 0) 3554218822Sdim error (_("Unable to read program interpreter name\n")); 355560484Sobrien 355660484Sobrien if (do_segments) 355760484Sobrien printf (_("\n [Requesting program interpreter: %s]"), 355860484Sobrien program_interpreter); 355960484Sobrien } 356060484Sobrien break; 356160484Sobrien } 356260484Sobrien 356360484Sobrien if (do_segments) 356460484Sobrien putc ('\n', stdout); 356560484Sobrien } 356660484Sobrien 3567218822Sdim if (do_segments && section_headers != NULL && string_table != NULL) 356860484Sobrien { 356960484Sobrien printf (_("\n Section to Segment mapping:\n")); 357060484Sobrien printf (_(" Segment Sections...\n")); 357160484Sobrien 357260484Sobrien for (i = 0; i < elf_header.e_phnum; i++) 357360484Sobrien { 357489857Sobrien unsigned int j; 3575130561Sobrien Elf_Internal_Shdr *section; 357660484Sobrien 357760484Sobrien segment = program_headers + i; 357860484Sobrien section = section_headers; 357960484Sobrien 358060484Sobrien printf (" %2.2d ", i); 358160484Sobrien 3582130561Sobrien for (j = 1; j < elf_header.e_shnum; j++, section++) 358360484Sobrien { 3584218822Sdim if (ELF_IS_SECTION_IN_SEGMENT_MEMORY(section, segment)) 358560484Sobrien printf ("%s ", SECTION_NAME (section)); 358660484Sobrien } 358760484Sobrien 358860484Sobrien putc ('\n',stdout); 358960484Sobrien } 359060484Sobrien } 359160484Sobrien 359260484Sobrien return 1; 359360484Sobrien} 359460484Sobrien 359560484Sobrien 3596130561Sobrien/* Find the file offset corresponding to VMA by using the program headers. */ 3597130561Sobrien 3598130561Sobrienstatic long 3599130561Sobrienoffset_from_vma (FILE *file, bfd_vma vma, bfd_size_type size) 3600130561Sobrien{ 3601130561Sobrien Elf_Internal_Phdr *seg; 3602130561Sobrien 3603130561Sobrien if (! get_program_headers (file)) 3604130561Sobrien { 3605130561Sobrien warn (_("Cannot interpret virtual addresses without program headers.\n")); 3606130561Sobrien return (long) vma; 3607130561Sobrien } 3608130561Sobrien 3609130561Sobrien for (seg = program_headers; 3610130561Sobrien seg < program_headers + elf_header.e_phnum; 3611130561Sobrien ++seg) 3612130561Sobrien { 3613130561Sobrien if (seg->p_type != PT_LOAD) 3614130561Sobrien continue; 3615130561Sobrien 3616130561Sobrien if (vma >= (seg->p_vaddr & -seg->p_align) 3617130561Sobrien && vma + size <= seg->p_vaddr + seg->p_filesz) 3618130561Sobrien return vma - seg->p_vaddr + seg->p_offset; 3619130561Sobrien } 3620130561Sobrien 3621130561Sobrien warn (_("Virtual address 0x%lx not located in any PT_LOAD segment.\n"), 3622130561Sobrien (long) vma); 3623130561Sobrien return (long) vma; 3624130561Sobrien} 3625130561Sobrien 3626130561Sobrien 362760484Sobrienstatic int 3628130561Sobrienget_32bit_section_headers (FILE *file, unsigned int num) 362960484Sobrien{ 3630130561Sobrien Elf32_External_Shdr *shdrs; 3631130561Sobrien Elf_Internal_Shdr *internal; 3632130561Sobrien unsigned int i; 363360484Sobrien 3634130561Sobrien shdrs = get_data (NULL, file, elf_header.e_shoff, 3635218822Sdim elf_header.e_shentsize, num, _("section headers")); 363689857Sobrien if (!shdrs) 363789857Sobrien return 0; 363860484Sobrien 3639218822Sdim section_headers = cmalloc (num, sizeof (Elf_Internal_Shdr)); 364060484Sobrien 364160484Sobrien if (section_headers == NULL) 364260484Sobrien { 364360484Sobrien error (_("Out of memory\n")); 364460484Sobrien return 0; 364560484Sobrien } 364660484Sobrien 364760484Sobrien for (i = 0, internal = section_headers; 364889857Sobrien i < num; 3649130561Sobrien i++, internal++) 365060484Sobrien { 365160484Sobrien internal->sh_name = BYTE_GET (shdrs[i].sh_name); 365260484Sobrien internal->sh_type = BYTE_GET (shdrs[i].sh_type); 365360484Sobrien internal->sh_flags = BYTE_GET (shdrs[i].sh_flags); 365460484Sobrien internal->sh_addr = BYTE_GET (shdrs[i].sh_addr); 365560484Sobrien internal->sh_offset = BYTE_GET (shdrs[i].sh_offset); 365660484Sobrien internal->sh_size = BYTE_GET (shdrs[i].sh_size); 365760484Sobrien internal->sh_link = BYTE_GET (shdrs[i].sh_link); 365860484Sobrien internal->sh_info = BYTE_GET (shdrs[i].sh_info); 365960484Sobrien internal->sh_addralign = BYTE_GET (shdrs[i].sh_addralign); 366060484Sobrien internal->sh_entsize = BYTE_GET (shdrs[i].sh_entsize); 366160484Sobrien } 366260484Sobrien 366360484Sobrien free (shdrs); 366460484Sobrien 366560484Sobrien return 1; 366660484Sobrien} 366760484Sobrien 366860484Sobrienstatic int 3669130561Sobrienget_64bit_section_headers (FILE *file, unsigned int num) 367060484Sobrien{ 3671130561Sobrien Elf64_External_Shdr *shdrs; 3672130561Sobrien Elf_Internal_Shdr *internal; 3673130561Sobrien unsigned int i; 367460484Sobrien 3675130561Sobrien shdrs = get_data (NULL, file, elf_header.e_shoff, 3676218822Sdim elf_header.e_shentsize, num, _("section headers")); 367789857Sobrien if (!shdrs) 367889857Sobrien return 0; 367960484Sobrien 3680218822Sdim section_headers = cmalloc (num, sizeof (Elf_Internal_Shdr)); 368160484Sobrien 368260484Sobrien if (section_headers == NULL) 368360484Sobrien { 368460484Sobrien error (_("Out of memory\n")); 368560484Sobrien return 0; 368660484Sobrien } 368760484Sobrien 368860484Sobrien for (i = 0, internal = section_headers; 368989857Sobrien i < num; 3690130561Sobrien i++, internal++) 369160484Sobrien { 369260484Sobrien internal->sh_name = BYTE_GET (shdrs[i].sh_name); 369360484Sobrien internal->sh_type = BYTE_GET (shdrs[i].sh_type); 3694218822Sdim internal->sh_flags = BYTE_GET (shdrs[i].sh_flags); 3695218822Sdim internal->sh_addr = BYTE_GET (shdrs[i].sh_addr); 3696218822Sdim internal->sh_size = BYTE_GET (shdrs[i].sh_size); 3697218822Sdim internal->sh_entsize = BYTE_GET (shdrs[i].sh_entsize); 369860484Sobrien internal->sh_link = BYTE_GET (shdrs[i].sh_link); 369960484Sobrien internal->sh_info = BYTE_GET (shdrs[i].sh_info); 370060484Sobrien internal->sh_offset = BYTE_GET (shdrs[i].sh_offset); 370160484Sobrien internal->sh_addralign = BYTE_GET (shdrs[i].sh_addralign); 370260484Sobrien } 370360484Sobrien 370460484Sobrien free (shdrs); 370560484Sobrien 370660484Sobrien return 1; 370760484Sobrien} 370860484Sobrien 370960484Sobrienstatic Elf_Internal_Sym * 3710130561Sobrienget_32bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section) 371160484Sobrien{ 371289857Sobrien unsigned long number; 3713130561Sobrien Elf32_External_Sym *esyms; 371489857Sobrien Elf_External_Sym_Shndx *shndx; 3715130561Sobrien Elf_Internal_Sym *isyms; 3716130561Sobrien Elf_Internal_Sym *psym; 3717130561Sobrien unsigned int j; 371860484Sobrien 3719218822Sdim esyms = get_data (NULL, file, section->sh_offset, 1, section->sh_size, 3720130561Sobrien _("symbols")); 372189857Sobrien if (!esyms) 372289857Sobrien return NULL; 372360484Sobrien 372489857Sobrien shndx = NULL; 372589857Sobrien if (symtab_shndx_hdr != NULL 372689857Sobrien && (symtab_shndx_hdr->sh_link 372789857Sobrien == (unsigned long) SECTION_HEADER_NUM (section - section_headers))) 372889857Sobrien { 3729130561Sobrien shndx = get_data (NULL, file, symtab_shndx_hdr->sh_offset, 3730218822Sdim 1, symtab_shndx_hdr->sh_size, _("symtab shndx")); 373189857Sobrien if (!shndx) 373289857Sobrien { 373389857Sobrien free (esyms); 373489857Sobrien return NULL; 373589857Sobrien } 373689857Sobrien } 373789857Sobrien 373889857Sobrien number = section->sh_size / section->sh_entsize; 3739218822Sdim isyms = cmalloc (number, sizeof (Elf_Internal_Sym)); 374060484Sobrien 374160484Sobrien if (isyms == NULL) 374260484Sobrien { 374360484Sobrien error (_("Out of memory\n")); 374489857Sobrien if (shndx) 374589857Sobrien free (shndx); 374660484Sobrien free (esyms); 374760484Sobrien return NULL; 374860484Sobrien } 374960484Sobrien 375060484Sobrien for (j = 0, psym = isyms; 375160484Sobrien j < number; 3752130561Sobrien j++, psym++) 375360484Sobrien { 375460484Sobrien psym->st_name = BYTE_GET (esyms[j].st_name); 375560484Sobrien psym->st_value = BYTE_GET (esyms[j].st_value); 375660484Sobrien psym->st_size = BYTE_GET (esyms[j].st_size); 375760484Sobrien psym->st_shndx = BYTE_GET (esyms[j].st_shndx); 375889857Sobrien if (psym->st_shndx == SHN_XINDEX && shndx != NULL) 375989857Sobrien psym->st_shndx 376089857Sobrien = byte_get ((unsigned char *) &shndx[j], sizeof (shndx[j])); 376160484Sobrien psym->st_info = BYTE_GET (esyms[j].st_info); 376260484Sobrien psym->st_other = BYTE_GET (esyms[j].st_other); 376360484Sobrien } 376460484Sobrien 376589857Sobrien if (shndx) 376689857Sobrien free (shndx); 376760484Sobrien free (esyms); 376860484Sobrien 376960484Sobrien return isyms; 377060484Sobrien} 377160484Sobrien 377260484Sobrienstatic Elf_Internal_Sym * 3773130561Sobrienget_64bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section) 377460484Sobrien{ 377589857Sobrien unsigned long number; 3776130561Sobrien Elf64_External_Sym *esyms; 377789857Sobrien Elf_External_Sym_Shndx *shndx; 3778130561Sobrien Elf_Internal_Sym *isyms; 3779130561Sobrien Elf_Internal_Sym *psym; 3780130561Sobrien unsigned int j; 378160484Sobrien 3782218822Sdim esyms = get_data (NULL, file, section->sh_offset, 1, section->sh_size, 3783130561Sobrien _("symbols")); 378489857Sobrien if (!esyms) 378589857Sobrien return NULL; 378660484Sobrien 378789857Sobrien shndx = NULL; 378889857Sobrien if (symtab_shndx_hdr != NULL 378989857Sobrien && (symtab_shndx_hdr->sh_link 379089857Sobrien == (unsigned long) SECTION_HEADER_NUM (section - section_headers))) 379189857Sobrien { 3792130561Sobrien shndx = get_data (NULL, file, symtab_shndx_hdr->sh_offset, 3793218822Sdim 1, symtab_shndx_hdr->sh_size, _("symtab shndx")); 379489857Sobrien if (!shndx) 379589857Sobrien { 379689857Sobrien free (esyms); 379789857Sobrien return NULL; 379889857Sobrien } 379989857Sobrien } 380089857Sobrien 380189857Sobrien number = section->sh_size / section->sh_entsize; 3802218822Sdim isyms = cmalloc (number, sizeof (Elf_Internal_Sym)); 380360484Sobrien 380460484Sobrien if (isyms == NULL) 380560484Sobrien { 380660484Sobrien error (_("Out of memory\n")); 380789857Sobrien if (shndx) 380889857Sobrien free (shndx); 380960484Sobrien free (esyms); 381060484Sobrien return NULL; 381160484Sobrien } 381260484Sobrien 381360484Sobrien for (j = 0, psym = isyms; 381460484Sobrien j < number; 3815130561Sobrien j++, psym++) 381660484Sobrien { 381760484Sobrien psym->st_name = BYTE_GET (esyms[j].st_name); 381860484Sobrien psym->st_info = BYTE_GET (esyms[j].st_info); 381960484Sobrien psym->st_other = BYTE_GET (esyms[j].st_other); 382060484Sobrien psym->st_shndx = BYTE_GET (esyms[j].st_shndx); 382189857Sobrien if (psym->st_shndx == SHN_XINDEX && shndx != NULL) 382289857Sobrien psym->st_shndx 382389857Sobrien = byte_get ((unsigned char *) &shndx[j], sizeof (shndx[j])); 3824218822Sdim psym->st_value = BYTE_GET (esyms[j].st_value); 3825218822Sdim psym->st_size = BYTE_GET (esyms[j].st_size); 382660484Sobrien } 382760484Sobrien 382889857Sobrien if (shndx) 382989857Sobrien free (shndx); 383060484Sobrien free (esyms); 383160484Sobrien 383260484Sobrien return isyms; 383360484Sobrien} 383460484Sobrien 383560484Sobrienstatic const char * 3836130561Sobrienget_elf_section_flags (bfd_vma sh_flags) 383760484Sobrien{ 3838218822Sdim static char buff[1024]; 3839218822Sdim char *p = buff; 3840218822Sdim int field_size = is_32bit_elf ? 8 : 16; 3841218822Sdim int index, size = sizeof (buff) - (field_size + 4 + 1); 3842218822Sdim bfd_vma os_flags = 0; 3843218822Sdim bfd_vma proc_flags = 0; 3844218822Sdim bfd_vma unknown_flags = 0; 3845218822Sdim const struct 3846218822Sdim { 3847218822Sdim const char *str; 3848218822Sdim int len; 3849218822Sdim } 3850218822Sdim flags [] = 3851218822Sdim { 3852218822Sdim { "WRITE", 5 }, 3853218822Sdim { "ALLOC", 5 }, 3854218822Sdim { "EXEC", 4 }, 3855218822Sdim { "MERGE", 5 }, 3856218822Sdim { "STRINGS", 7 }, 3857218822Sdim { "INFO LINK", 9 }, 3858218822Sdim { "LINK ORDER", 10 }, 3859218822Sdim { "OS NONCONF", 10 }, 3860218822Sdim { "GROUP", 5 }, 3861218822Sdim { "TLS", 3 } 3862218822Sdim }; 386360484Sobrien 3864218822Sdim if (do_section_details) 3865218822Sdim { 3866218822Sdim sprintf (buff, "[%*.*lx]: ", 3867218822Sdim field_size, field_size, (unsigned long) sh_flags); 3868218822Sdim p += field_size + 4; 3869218822Sdim } 387077298Sobrien 387160484Sobrien while (sh_flags) 387260484Sobrien { 387360484Sobrien bfd_vma flag; 387460484Sobrien 387560484Sobrien flag = sh_flags & - sh_flags; 387660484Sobrien sh_flags &= ~ flag; 387777298Sobrien 3878218822Sdim if (do_section_details) 387960484Sobrien { 3880218822Sdim switch (flag) 3881218822Sdim { 3882218822Sdim case SHF_WRITE: index = 0; break; 3883218822Sdim case SHF_ALLOC: index = 1; break; 3884218822Sdim case SHF_EXECINSTR: index = 2; break; 3885218822Sdim case SHF_MERGE: index = 3; break; 3886218822Sdim case SHF_STRINGS: index = 4; break; 3887218822Sdim case SHF_INFO_LINK: index = 5; break; 3888218822Sdim case SHF_LINK_ORDER: index = 6; break; 3889218822Sdim case SHF_OS_NONCONFORMING: index = 7; break; 3890218822Sdim case SHF_GROUP: index = 8; break; 3891218822Sdim case SHF_TLS: index = 9; break; 389277298Sobrien 3893218822Sdim default: 3894218822Sdim index = -1; 3895218822Sdim break; 3896218822Sdim } 3897218822Sdim 3898218822Sdim if (index != -1) 389960484Sobrien { 3900218822Sdim if (p != buff + field_size + 4) 3901218822Sdim { 3902218822Sdim if (size < (10 + 2)) 3903218822Sdim abort (); 3904218822Sdim size -= 2; 3905218822Sdim *p++ = ','; 3906218822Sdim *p++ = ' '; 3907218822Sdim } 3908218822Sdim 3909218822Sdim size -= flags [index].len; 3910218822Sdim p = stpcpy (p, flags [index].str); 391160484Sobrien } 3912218822Sdim else if (flag & SHF_MASKOS) 3913218822Sdim os_flags |= flag; 391460484Sobrien else if (flag & SHF_MASKPROC) 3915218822Sdim proc_flags |= flag; 3916218822Sdim else 3917218822Sdim unknown_flags |= flag; 3918218822Sdim } 3919218822Sdim else 3920218822Sdim { 3921218822Sdim switch (flag) 392260484Sobrien { 3923218822Sdim case SHF_WRITE: *p = 'W'; break; 3924218822Sdim case SHF_ALLOC: *p = 'A'; break; 3925218822Sdim case SHF_EXECINSTR: *p = 'X'; break; 3926218822Sdim case SHF_MERGE: *p = 'M'; break; 3927218822Sdim case SHF_STRINGS: *p = 'S'; break; 3928218822Sdim case SHF_INFO_LINK: *p = 'I'; break; 3929218822Sdim case SHF_LINK_ORDER: *p = 'L'; break; 3930218822Sdim case SHF_OS_NONCONFORMING: *p = 'O'; break; 3931218822Sdim case SHF_GROUP: *p = 'G'; break; 3932218822Sdim case SHF_TLS: *p = 'T'; break; 3933218822Sdim 3934218822Sdim default: 3935218822Sdim if (elf_header.e_machine == EM_X86_64 3936218822Sdim && flag == SHF_X86_64_LARGE) 3937218822Sdim *p = 'l'; 3938218822Sdim else if (flag & SHF_MASKOS) 3939218822Sdim { 3940218822Sdim *p = 'o'; 3941218822Sdim sh_flags &= ~ SHF_MASKOS; 3942218822Sdim } 3943218822Sdim else if (flag & SHF_MASKPROC) 3944218822Sdim { 3945218822Sdim *p = 'p'; 3946218822Sdim sh_flags &= ~ SHF_MASKPROC; 3947218822Sdim } 3948218822Sdim else 3949218822Sdim *p = 'x'; 3950218822Sdim break; 395160484Sobrien } 3952218822Sdim p++; 395360484Sobrien } 395460484Sobrien } 395577298Sobrien 3956218822Sdim if (do_section_details) 3957218822Sdim { 3958218822Sdim if (os_flags) 3959218822Sdim { 3960218822Sdim size -= 5 + field_size; 3961218822Sdim if (p != buff + field_size + 4) 3962218822Sdim { 3963218822Sdim if (size < (2 + 1)) 3964218822Sdim abort (); 3965218822Sdim size -= 2; 3966218822Sdim *p++ = ','; 3967218822Sdim *p++ = ' '; 3968218822Sdim } 3969218822Sdim sprintf (p, "OS (%*.*lx)", field_size, field_size, 3970218822Sdim (unsigned long) os_flags); 3971218822Sdim p += 5 + field_size; 3972218822Sdim } 3973218822Sdim if (proc_flags) 3974218822Sdim { 3975218822Sdim size -= 7 + field_size; 3976218822Sdim if (p != buff + field_size + 4) 3977218822Sdim { 3978218822Sdim if (size < (2 + 1)) 3979218822Sdim abort (); 3980218822Sdim size -= 2; 3981218822Sdim *p++ = ','; 3982218822Sdim *p++ = ' '; 3983218822Sdim } 3984218822Sdim sprintf (p, "PROC (%*.*lx)", field_size, field_size, 3985218822Sdim (unsigned long) proc_flags); 3986218822Sdim p += 7 + field_size; 3987218822Sdim } 3988218822Sdim if (unknown_flags) 3989218822Sdim { 3990218822Sdim size -= 10 + field_size; 3991218822Sdim if (p != buff + field_size + 4) 3992218822Sdim { 3993218822Sdim if (size < (2 + 1)) 3994218822Sdim abort (); 3995218822Sdim size -= 2; 3996218822Sdim *p++ = ','; 3997218822Sdim *p++ = ' '; 3998218822Sdim } 3999218822Sdim sprintf (p, "UNKNOWN (%*.*lx)", field_size, field_size, 4000218822Sdim (unsigned long) unknown_flags); 4001218822Sdim p += 10 + field_size; 4002218822Sdim } 4003218822Sdim } 4004218822Sdim 4005218822Sdim *p = '\0'; 400660484Sobrien return buff; 400760484Sobrien} 400860484Sobrien 400960484Sobrienstatic int 4010130561Sobrienprocess_section_headers (FILE *file) 401160484Sobrien{ 4012130561Sobrien Elf_Internal_Shdr *section; 4013130561Sobrien unsigned int i; 401460484Sobrien 401560484Sobrien section_headers = NULL; 401660484Sobrien 401760484Sobrien if (elf_header.e_shnum == 0) 401860484Sobrien { 401960484Sobrien if (do_sections) 402060484Sobrien printf (_("\nThere are no sections in this file.\n")); 402160484Sobrien 402260484Sobrien return 1; 402360484Sobrien } 402460484Sobrien 402560484Sobrien if (do_sections && !do_header) 402660484Sobrien printf (_("There are %d section headers, starting at offset 0x%lx:\n"), 402760484Sobrien elf_header.e_shnum, (unsigned long) elf_header.e_shoff); 402860484Sobrien 402960484Sobrien if (is_32bit_elf) 403060484Sobrien { 403189857Sobrien if (! get_32bit_section_headers (file, elf_header.e_shnum)) 403260484Sobrien return 0; 403360484Sobrien } 403489857Sobrien else if (! get_64bit_section_headers (file, elf_header.e_shnum)) 403560484Sobrien return 0; 403660484Sobrien 403760484Sobrien /* Read in the string table, so that we have names to display. */ 4038218822Sdim if (elf_header.e_shstrndx != SHN_UNDEF 4039218822Sdim && SECTION_HEADER_INDEX (elf_header.e_shstrndx) < elf_header.e_shnum) 404060484Sobrien { 4041218822Sdim section = SECTION_HEADER (elf_header.e_shstrndx); 404277298Sobrien 4043218822Sdim if (section->sh_size != 0) 4044218822Sdim { 4045218822Sdim string_table = get_data (NULL, file, section->sh_offset, 4046218822Sdim 1, section->sh_size, _("string table")); 4047130561Sobrien 4048218822Sdim string_table_length = string_table != NULL ? section->sh_size : 0; 4049218822Sdim } 405060484Sobrien } 405160484Sobrien 405260484Sobrien /* Scan the sections for the dynamic symbol table 405389857Sobrien and dynamic string table and debug sections. */ 405460484Sobrien dynamic_symbols = NULL; 405560484Sobrien dynamic_strings = NULL; 405660484Sobrien dynamic_syminfo = NULL; 4057130561Sobrien symtab_shndx_hdr = NULL; 405860484Sobrien 4059218822Sdim eh_addr_size = is_32bit_elf ? 4 : 8; 4060218822Sdim switch (elf_header.e_machine) 4061218822Sdim { 4062218822Sdim case EM_MIPS: 4063218822Sdim case EM_MIPS_RS3_LE: 4064218822Sdim /* The 64-bit MIPS EABI uses a combination of 32-bit ELF and 64-bit 4065218822Sdim FDE addresses. However, the ABI also has a semi-official ILP32 4066218822Sdim variant for which the normal FDE address size rules apply. 4067218822Sdim 4068218822Sdim GCC 4.0 marks EABI64 objects with a dummy .gcc_compiled_longXX 4069218822Sdim section, where XX is the size of longs in bits. Unfortunately, 4070218822Sdim earlier compilers provided no way of distinguishing ILP32 objects 4071218822Sdim from LP64 objects, so if there's any doubt, we should assume that 4072218822Sdim the official LP64 form is being used. */ 4073218822Sdim if ((elf_header.e_flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI64 4074218822Sdim && find_section (".gcc_compiled_long32") == NULL) 4075218822Sdim eh_addr_size = 8; 4076218822Sdim break; 4077218822Sdim 4078218822Sdim case EM_H8_300: 4079218822Sdim case EM_H8_300H: 4080218822Sdim switch (elf_header.e_flags & EF_H8_MACH) 4081218822Sdim { 4082218822Sdim case E_H8_MACH_H8300: 4083218822Sdim case E_H8_MACH_H8300HN: 4084218822Sdim case E_H8_MACH_H8300SN: 4085218822Sdim case E_H8_MACH_H8300SXN: 4086218822Sdim eh_addr_size = 2; 4087218822Sdim break; 4088218822Sdim case E_H8_MACH_H8300H: 4089218822Sdim case E_H8_MACH_H8300S: 4090218822Sdim case E_H8_MACH_H8300SX: 4091218822Sdim eh_addr_size = 4; 4092218822Sdim break; 4093218822Sdim } 4094218822Sdim } 4095218822Sdim 4096218822Sdim#define CHECK_ENTSIZE_VALUES(section, i, size32, size64) \ 4097218822Sdim do \ 4098218822Sdim { \ 4099218822Sdim size_t expected_entsize \ 4100218822Sdim = is_32bit_elf ? size32 : size64; \ 4101218822Sdim if (section->sh_entsize != expected_entsize) \ 4102218822Sdim error (_("Section %d has invalid sh_entsize %lx (expected %lx)\n"), \ 4103218822Sdim i, (unsigned long int) section->sh_entsize, \ 4104218822Sdim (unsigned long int) expected_entsize); \ 4105218822Sdim section->sh_entsize = expected_entsize; \ 4106218822Sdim } \ 4107218822Sdim while (0) 4108218822Sdim#define CHECK_ENTSIZE(section, i, type) \ 4109218822Sdim CHECK_ENTSIZE_VALUES (section, i, sizeof (Elf32_External_##type), \ 4110218822Sdim sizeof (Elf64_External_##type)) 4111218822Sdim 411260484Sobrien for (i = 0, section = section_headers; 411360484Sobrien i < elf_header.e_shnum; 4114130561Sobrien i++, section++) 411560484Sobrien { 4116130561Sobrien char *name = SECTION_NAME (section); 411760484Sobrien 411860484Sobrien if (section->sh_type == SHT_DYNSYM) 411960484Sobrien { 412060484Sobrien if (dynamic_symbols != NULL) 412160484Sobrien { 412260484Sobrien error (_("File contains multiple dynamic symbol tables\n")); 412360484Sobrien continue; 412460484Sobrien } 412560484Sobrien 4126218822Sdim CHECK_ENTSIZE (section, i, Sym); 412760484Sobrien num_dynamic_syms = section->sh_size / section->sh_entsize; 412889857Sobrien dynamic_symbols = GET_ELF_SYMBOLS (file, section); 412960484Sobrien } 413060484Sobrien else if (section->sh_type == SHT_STRTAB 4131218822Sdim && streq (name, ".dynstr")) 413260484Sobrien { 413360484Sobrien if (dynamic_strings != NULL) 413460484Sobrien { 413560484Sobrien error (_("File contains multiple dynamic string tables\n")); 413660484Sobrien continue; 413760484Sobrien } 413860484Sobrien 4139130561Sobrien dynamic_strings = get_data (NULL, file, section->sh_offset, 4140218822Sdim 1, section->sh_size, _("dynamic strings")); 4141218822Sdim dynamic_strings_length = section->sh_size; 414260484Sobrien } 414389857Sobrien else if (section->sh_type == SHT_SYMTAB_SHNDX) 414489857Sobrien { 414589857Sobrien if (symtab_shndx_hdr != NULL) 414689857Sobrien { 414789857Sobrien error (_("File contains multiple symtab shndx tables\n")); 414889857Sobrien continue; 414989857Sobrien } 415089857Sobrien symtab_shndx_hdr = section; 415189857Sobrien } 4152218822Sdim else if (section->sh_type == SHT_SYMTAB) 4153218822Sdim CHECK_ENTSIZE (section, i, Sym); 4154218822Sdim else if (section->sh_type == SHT_GROUP) 4155218822Sdim CHECK_ENTSIZE_VALUES (section, i, GRP_ENTRY_SIZE, GRP_ENTRY_SIZE); 4156218822Sdim else if (section->sh_type == SHT_REL) 4157218822Sdim CHECK_ENTSIZE (section, i, Rel); 4158218822Sdim else if (section->sh_type == SHT_RELA) 4159218822Sdim CHECK_ENTSIZE (section, i, Rela); 416060484Sobrien else if ((do_debugging || do_debug_info || do_debug_abbrevs 416178828Sobrien || do_debug_lines || do_debug_pubnames || do_debug_aranges 416299461Sobrien || do_debug_frames || do_debug_macinfo || do_debug_str 4163218822Sdim || do_debug_loc || do_debug_ranges) 4164218822Sdim && const_strneq (name, ".debug_")) 416560484Sobrien { 416660484Sobrien name += 7; 416760484Sobrien 416860484Sobrien if (do_debugging 4169218822Sdim || (do_debug_info && streq (name, "info")) 4170218822Sdim || (do_debug_abbrevs && streq (name, "abbrev")) 4171218822Sdim || (do_debug_lines && streq (name, "line")) 4172218822Sdim || (do_debug_pubnames && streq (name, "pubnames")) 4173218822Sdim || (do_debug_aranges && streq (name, "aranges")) 4174218822Sdim || (do_debug_ranges && streq (name, "ranges")) 4175218822Sdim || (do_debug_frames && streq (name, "frame")) 4176218822Sdim || (do_debug_macinfo && streq (name, "macinfo")) 4177218822Sdim || (do_debug_str && streq (name, "str")) 4178218822Sdim || (do_debug_loc && streq (name, "loc")) 417960484Sobrien ) 418060484Sobrien request_dump (i, DEBUG_DUMP); 418160484Sobrien } 418277298Sobrien /* linkonce section to be combined with .debug_info at link time. */ 418377298Sobrien else if ((do_debugging || do_debug_info) 4184218822Sdim && const_strneq (name, ".gnu.linkonce.wi.")) 418577298Sobrien request_dump (i, DEBUG_DUMP); 4186218822Sdim else if (do_debug_frames && streq (name, ".eh_frame")) 418777298Sobrien request_dump (i, DEBUG_DUMP); 418860484Sobrien } 418960484Sobrien 419060484Sobrien if (! do_sections) 419160484Sobrien return 1; 419260484Sobrien 4193104834Sobrien if (elf_header.e_shnum > 1) 4194104834Sobrien printf (_("\nSection Headers:\n")); 4195104834Sobrien else 4196104834Sobrien printf (_("\nSection Header:\n")); 419777298Sobrien 419860484Sobrien if (is_32bit_elf) 4199218822Sdim { 4200218822Sdim if (do_section_details) 4201218822Sdim { 4202218822Sdim printf (_(" [Nr] Name\n")); 4203218822Sdim printf (_(" Type Addr Off Size ES Lk Inf Al\n")); 4204218822Sdim } 4205218822Sdim else 4206218822Sdim printf 4207218822Sdim (_(" [Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n")); 4208218822Sdim } 420989857Sobrien else if (do_wide) 4210218822Sdim { 4211218822Sdim if (do_section_details) 4212218822Sdim { 4213218822Sdim printf (_(" [Nr] Name\n")); 4214218822Sdim printf (_(" Type Address Off Size ES Lk Inf Al\n")); 4215218822Sdim } 4216218822Sdim else 4217218822Sdim printf 4218218822Sdim (_(" [Nr] Name Type Address Off Size ES Flg Lk Inf Al\n")); 4219218822Sdim } 422060484Sobrien else 422160484Sobrien { 4222218822Sdim if (do_section_details) 4223218822Sdim { 4224218822Sdim printf (_(" [Nr] Name\n")); 4225218822Sdim printf (_(" Type Address Offset Link\n")); 4226218822Sdim printf (_(" Size EntSize Info Align\n")); 4227218822Sdim } 4228218822Sdim else 4229218822Sdim { 4230218822Sdim printf (_(" [Nr] Name Type Address Offset\n")); 4231218822Sdim printf (_(" Size EntSize Flags Link Info Align\n")); 4232218822Sdim } 423360484Sobrien } 423460484Sobrien 4235218822Sdim if (do_section_details) 4236218822Sdim printf (_(" Flags\n")); 4237218822Sdim 423860484Sobrien for (i = 0, section = section_headers; 423960484Sobrien i < elf_header.e_shnum; 4240130561Sobrien i++, section++) 424160484Sobrien { 4242218822Sdim if (do_section_details) 4243218822Sdim { 4244218822Sdim printf (" [%2u] %s\n", 4245218822Sdim SECTION_HEADER_NUM (i), 4246218822Sdim SECTION_NAME (section)); 4247218822Sdim if (is_32bit_elf || do_wide) 4248218822Sdim printf (" %-15.15s ", 4249218822Sdim get_section_type_name (section->sh_type)); 4250218822Sdim } 4251218822Sdim else 4252218822Sdim printf (" [%2u] %-17.17s %-15.15s ", 4253218822Sdim SECTION_HEADER_NUM (i), 4254218822Sdim SECTION_NAME (section), 4255218822Sdim get_section_type_name (section->sh_type)); 425660484Sobrien 425760484Sobrien if (is_32bit_elf) 425860484Sobrien { 425960484Sobrien print_vma (section->sh_addr, LONG_HEX); 426077298Sobrien 426160484Sobrien printf ( " %6.6lx %6.6lx %2.2lx", 426260484Sobrien (unsigned long) section->sh_offset, 426360484Sobrien (unsigned long) section->sh_size, 426460484Sobrien (unsigned long) section->sh_entsize); 426560484Sobrien 4266218822Sdim if (do_section_details) 4267218822Sdim fputs (" ", stdout); 4268218822Sdim else 4269218822Sdim printf (" %3s ", get_elf_section_flags (section->sh_flags)); 427077298Sobrien 4271218822Sdim printf ("%2ld %3lu %2ld\n", 427260484Sobrien (unsigned long) section->sh_link, 427360484Sobrien (unsigned long) section->sh_info, 427460484Sobrien (unsigned long) section->sh_addralign); 427560484Sobrien } 427689857Sobrien else if (do_wide) 427789857Sobrien { 427889857Sobrien print_vma (section->sh_addr, LONG_HEX); 427989857Sobrien 428089857Sobrien if ((long) section->sh_offset == section->sh_offset) 428189857Sobrien printf (" %6.6lx", (unsigned long) section->sh_offset); 428289857Sobrien else 428389857Sobrien { 428489857Sobrien putchar (' '); 428589857Sobrien print_vma (section->sh_offset, LONG_HEX); 428689857Sobrien } 428789857Sobrien 428889857Sobrien if ((unsigned long) section->sh_size == section->sh_size) 428989857Sobrien printf (" %6.6lx", (unsigned long) section->sh_size); 429089857Sobrien else 429189857Sobrien { 429289857Sobrien putchar (' '); 429389857Sobrien print_vma (section->sh_size, LONG_HEX); 429489857Sobrien } 429589857Sobrien 429689857Sobrien if ((unsigned long) section->sh_entsize == section->sh_entsize) 429789857Sobrien printf (" %2.2lx", (unsigned long) section->sh_entsize); 429889857Sobrien else 429989857Sobrien { 430089857Sobrien putchar (' '); 430189857Sobrien print_vma (section->sh_entsize, LONG_HEX); 430289857Sobrien } 430389857Sobrien 4304218822Sdim if (do_section_details) 4305218822Sdim fputs (" ", stdout); 4306218822Sdim else 4307218822Sdim printf (" %3s ", get_elf_section_flags (section->sh_flags)); 430889857Sobrien 4309218822Sdim printf ("%2ld %3lu ", 431089857Sobrien (unsigned long) section->sh_link, 431189857Sobrien (unsigned long) section->sh_info); 431289857Sobrien 431389857Sobrien if ((unsigned long) section->sh_addralign == section->sh_addralign) 431489857Sobrien printf ("%2ld\n", (unsigned long) section->sh_addralign); 431589857Sobrien else 431689857Sobrien { 431789857Sobrien print_vma (section->sh_addralign, DEC); 431889857Sobrien putchar ('\n'); 431989857Sobrien } 432089857Sobrien } 4321218822Sdim else if (do_section_details) 4322218822Sdim { 4323218822Sdim printf (" %-15.15s ", 4324218822Sdim get_section_type_name (section->sh_type)); 4325218822Sdim print_vma (section->sh_addr, LONG_HEX); 4326218822Sdim if ((long) section->sh_offset == section->sh_offset) 4327218822Sdim printf (" %16.16lx", (unsigned long) section->sh_offset); 4328218822Sdim else 4329218822Sdim { 4330218822Sdim printf (" "); 4331218822Sdim print_vma (section->sh_offset, LONG_HEX); 4332218822Sdim } 4333218822Sdim printf (" %ld\n ", (unsigned long) section->sh_link); 4334218822Sdim print_vma (section->sh_size, LONG_HEX); 4335218822Sdim putchar (' '); 4336218822Sdim print_vma (section->sh_entsize, LONG_HEX); 4337218822Sdim 4338218822Sdim printf (" %-16lu %ld\n", 4339218822Sdim (unsigned long) section->sh_info, 4340218822Sdim (unsigned long) section->sh_addralign); 4341218822Sdim } 434260484Sobrien else 434360484Sobrien { 434460484Sobrien putchar (' '); 434560484Sobrien print_vma (section->sh_addr, LONG_HEX); 4346104834Sobrien if ((long) section->sh_offset == section->sh_offset) 4347104834Sobrien printf (" %8.8lx", (unsigned long) section->sh_offset); 4348104834Sobrien else 4349104834Sobrien { 4350104834Sobrien printf (" "); 4351104834Sobrien print_vma (section->sh_offset, LONG_HEX); 4352104834Sobrien } 435360484Sobrien printf ("\n "); 435460484Sobrien print_vma (section->sh_size, LONG_HEX); 435560484Sobrien printf (" "); 435660484Sobrien print_vma (section->sh_entsize, LONG_HEX); 435777298Sobrien 435860484Sobrien printf (" %3s ", get_elf_section_flags (section->sh_flags)); 435977298Sobrien 4360218822Sdim printf (" %2ld %3lu %ld\n", 436160484Sobrien (unsigned long) section->sh_link, 436260484Sobrien (unsigned long) section->sh_info, 436360484Sobrien (unsigned long) section->sh_addralign); 436460484Sobrien } 4365218822Sdim 4366218822Sdim if (do_section_details) 4367218822Sdim printf (" %s\n", get_elf_section_flags (section->sh_flags)); 436860484Sobrien } 436960484Sobrien 4370218822Sdim if (!do_section_details) 4371218822Sdim printf (_("Key to Flags:\n\ 437289857Sobrien W (write), A (alloc), X (execute), M (merge), S (strings)\n\ 437389857Sobrien I (info), L (link order), G (group), x (unknown)\n\ 437489857Sobrien O (extra OS processing required) o (OS specific), p (processor specific)\n")); 437560484Sobrien 437660484Sobrien return 1; 437760484Sobrien} 437860484Sobrien 4379218822Sdimstatic const char * 4380218822Sdimget_group_flags (unsigned int flags) 4381130561Sobrien{ 4382218822Sdim static char buff[32]; 4383218822Sdim switch (flags) 4384218822Sdim { 4385218822Sdim case GRP_COMDAT: 4386218822Sdim return "COMDAT"; 4387218822Sdim 4388218822Sdim default: 4389218822Sdim snprintf (buff, sizeof (buff), _("[<unknown>: 0x%x]"), flags); 4390218822Sdim break; 4391218822Sdim } 4392218822Sdim return buff; 4393218822Sdim} 4394218822Sdim 4395218822Sdimstatic int 4396218822Sdimprocess_section_groups (FILE *file) 4397218822Sdim{ 4398218822Sdim Elf_Internal_Shdr *section; 4399218822Sdim unsigned int i; 4400218822Sdim struct group *group; 4401218822Sdim Elf_Internal_Shdr *symtab_sec, *strtab_sec; 4402218822Sdim Elf_Internal_Sym *symtab; 4403218822Sdim char *strtab; 4404218822Sdim size_t strtab_size; 4405218822Sdim 4406218822Sdim /* Don't process section groups unless needed. */ 4407218822Sdim if (!do_unwind && !do_section_groups) 4408218822Sdim return 1; 4409218822Sdim 4410218822Sdim if (elf_header.e_shnum == 0) 4411218822Sdim { 4412218822Sdim if (do_section_groups) 4413218822Sdim printf (_("\nThere are no sections in this file.\n")); 4414218822Sdim 4415218822Sdim return 1; 4416218822Sdim } 4417218822Sdim 4418218822Sdim if (section_headers == NULL) 4419218822Sdim { 4420218822Sdim error (_("Section headers are not available!\n")); 4421218822Sdim abort (); 4422218822Sdim } 4423218822Sdim 4424218822Sdim section_headers_groups = calloc (elf_header.e_shnum, 4425218822Sdim sizeof (struct group *)); 4426218822Sdim 4427218822Sdim if (section_headers_groups == NULL) 4428218822Sdim { 4429218822Sdim error (_("Out of memory\n")); 4430218822Sdim return 0; 4431218822Sdim } 4432218822Sdim 4433218822Sdim /* Scan the sections for the group section. */ 4434218822Sdim group_count = 0; 4435218822Sdim for (i = 0, section = section_headers; 4436218822Sdim i < elf_header.e_shnum; 4437218822Sdim i++, section++) 4438218822Sdim if (section->sh_type == SHT_GROUP) 4439218822Sdim group_count++; 4440218822Sdim 4441218822Sdim if (group_count == 0) 4442218822Sdim { 4443218822Sdim if (do_section_groups) 4444218822Sdim printf (_("\nThere are no section groups in this file.\n")); 4445218822Sdim 4446218822Sdim return 1; 4447218822Sdim } 4448218822Sdim 4449218822Sdim section_groups = calloc (group_count, sizeof (struct group)); 4450218822Sdim 4451218822Sdim if (section_groups == NULL) 4452218822Sdim { 4453218822Sdim error (_("Out of memory\n")); 4454218822Sdim return 0; 4455218822Sdim } 4456218822Sdim 4457218822Sdim symtab_sec = NULL; 4458218822Sdim strtab_sec = NULL; 4459218822Sdim symtab = NULL; 4460218822Sdim strtab = NULL; 4461218822Sdim strtab_size = 0; 4462218822Sdim for (i = 0, section = section_headers, group = section_groups; 4463218822Sdim i < elf_header.e_shnum; 4464218822Sdim i++, section++) 4465218822Sdim { 4466218822Sdim if (section->sh_type == SHT_GROUP) 4467218822Sdim { 4468218822Sdim char *name = SECTION_NAME (section); 4469218822Sdim char *group_name; 4470218822Sdim unsigned char *start, *indices; 4471218822Sdim unsigned int entry, j, size; 4472218822Sdim Elf_Internal_Shdr *sec; 4473218822Sdim Elf_Internal_Sym *sym; 4474218822Sdim 4475218822Sdim /* Get the symbol table. */ 4476218822Sdim if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum 4477218822Sdim || ((sec = SECTION_HEADER (section->sh_link))->sh_type 4478218822Sdim != SHT_SYMTAB)) 4479218822Sdim { 4480218822Sdim error (_("Bad sh_link in group section `%s'\n"), name); 4481218822Sdim continue; 4482218822Sdim } 4483218822Sdim 4484218822Sdim if (symtab_sec != sec) 4485218822Sdim { 4486218822Sdim symtab_sec = sec; 4487218822Sdim if (symtab) 4488218822Sdim free (symtab); 4489218822Sdim symtab = GET_ELF_SYMBOLS (file, symtab_sec); 4490218822Sdim } 4491218822Sdim 4492218822Sdim sym = symtab + section->sh_info; 4493218822Sdim 4494218822Sdim if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) 4495218822Sdim { 4496218822Sdim bfd_vma sec_index = SECTION_HEADER_INDEX (sym->st_shndx); 4497218822Sdim if (sec_index == 0) 4498218822Sdim { 4499218822Sdim error (_("Bad sh_info in group section `%s'\n"), name); 4500218822Sdim continue; 4501218822Sdim } 4502218822Sdim 4503218822Sdim group_name = SECTION_NAME (section_headers + sec_index); 4504218822Sdim strtab_sec = NULL; 4505218822Sdim if (strtab) 4506218822Sdim free (strtab); 4507218822Sdim strtab = NULL; 4508218822Sdim strtab_size = 0; 4509218822Sdim } 4510218822Sdim else 4511218822Sdim { 4512218822Sdim /* Get the string table. */ 4513218822Sdim if (SECTION_HEADER_INDEX (symtab_sec->sh_link) 4514218822Sdim >= elf_header.e_shnum) 4515218822Sdim { 4516218822Sdim strtab_sec = NULL; 4517218822Sdim if (strtab) 4518218822Sdim free (strtab); 4519218822Sdim strtab = NULL; 4520218822Sdim strtab_size = 0; 4521218822Sdim } 4522218822Sdim else if (strtab_sec 4523218822Sdim != (sec = SECTION_HEADER (symtab_sec->sh_link))) 4524218822Sdim { 4525218822Sdim strtab_sec = sec; 4526218822Sdim if (strtab) 4527218822Sdim free (strtab); 4528218822Sdim strtab = get_data (NULL, file, strtab_sec->sh_offset, 4529218822Sdim 1, strtab_sec->sh_size, 4530218822Sdim _("string table")); 4531218822Sdim strtab_size = strtab != NULL ? strtab_sec->sh_size : 0; 4532218822Sdim } 4533218822Sdim group_name = sym->st_name < strtab_size 4534218822Sdim ? strtab + sym->st_name : "<corrupt>"; 4535218822Sdim } 4536218822Sdim 4537218822Sdim start = get_data (NULL, file, section->sh_offset, 4538218822Sdim 1, section->sh_size, _("section data")); 4539218822Sdim 4540218822Sdim indices = start; 4541218822Sdim size = (section->sh_size / section->sh_entsize) - 1; 4542218822Sdim entry = byte_get (indices, 4); 4543218822Sdim indices += 4; 4544218822Sdim 4545218822Sdim if (do_section_groups) 4546218822Sdim { 4547218822Sdim printf ("\n%s group section [%5u] `%s' [%s] contains %u sections:\n", 4548218822Sdim get_group_flags (entry), i, name, group_name, size); 4549218822Sdim 4550218822Sdim printf (_(" [Index] Name\n")); 4551218822Sdim } 4552218822Sdim 4553218822Sdim group->group_index = i; 4554218822Sdim 4555218822Sdim for (j = 0; j < size; j++) 4556218822Sdim { 4557218822Sdim struct group_list *g; 4558218822Sdim 4559218822Sdim entry = byte_get (indices, 4); 4560218822Sdim indices += 4; 4561218822Sdim 4562218822Sdim if (SECTION_HEADER_INDEX (entry) >= elf_header.e_shnum) 4563218822Sdim { 4564218822Sdim error (_("section [%5u] in group section [%5u] > maximum section [%5u]\n"), 4565218822Sdim entry, i, elf_header.e_shnum - 1); 4566218822Sdim continue; 4567218822Sdim } 4568218822Sdim else if (entry >= SHN_LORESERVE && entry <= SHN_HIRESERVE) 4569218822Sdim { 4570218822Sdim error (_("invalid section [%5u] in group section [%5u]\n"), 4571218822Sdim entry, i); 4572218822Sdim continue; 4573218822Sdim } 4574218822Sdim 4575218822Sdim if (section_headers_groups [SECTION_HEADER_INDEX (entry)] 4576218822Sdim != NULL) 4577218822Sdim { 4578218822Sdim if (entry) 4579218822Sdim { 4580218822Sdim error (_("section [%5u] in group section [%5u] already in group section [%5u]\n"), 4581218822Sdim entry, i, 4582218822Sdim section_headers_groups [SECTION_HEADER_INDEX (entry)]->group_index); 4583218822Sdim continue; 4584218822Sdim } 4585218822Sdim else 4586218822Sdim { 4587218822Sdim /* Intel C/C++ compiler may put section 0 in a 4588218822Sdim section group. We just warn it the first time 4589218822Sdim and ignore it afterwards. */ 4590218822Sdim static int warned = 0; 4591218822Sdim if (!warned) 4592218822Sdim { 4593218822Sdim error (_("section 0 in group section [%5u]\n"), 4594218822Sdim section_headers_groups [SECTION_HEADER_INDEX (entry)]->group_index); 4595218822Sdim warned++; 4596218822Sdim } 4597218822Sdim } 4598218822Sdim } 4599218822Sdim 4600218822Sdim section_headers_groups [SECTION_HEADER_INDEX (entry)] 4601218822Sdim = group; 4602218822Sdim 4603218822Sdim if (do_section_groups) 4604218822Sdim { 4605218822Sdim sec = SECTION_HEADER (entry); 4606218822Sdim printf (" [%5u] %s\n", entry, SECTION_NAME (sec)); 4607218822Sdim } 4608218822Sdim 4609218822Sdim g = xmalloc (sizeof (struct group_list)); 4610218822Sdim g->section_index = entry; 4611218822Sdim g->next = group->root; 4612218822Sdim group->root = g; 4613218822Sdim } 4614218822Sdim 4615218822Sdim if (start) 4616218822Sdim free (start); 4617218822Sdim 4618218822Sdim group++; 4619218822Sdim } 4620218822Sdim } 4621218822Sdim 4622218822Sdim if (symtab) 4623218822Sdim free (symtab); 4624218822Sdim if (strtab) 4625218822Sdim free (strtab); 4626218822Sdim return 1; 4627218822Sdim} 4628218822Sdim 4629218822Sdimstatic struct 4630218822Sdim{ 4631130561Sobrien const char *name; 4632130561Sobrien int reloc; 4633130561Sobrien int size; 4634130561Sobrien int rela; 4635130561Sobrien} dynamic_relocations [] = 4636130561Sobrien{ 4637130561Sobrien { "REL", DT_REL, DT_RELSZ, FALSE }, 4638130561Sobrien { "RELA", DT_RELA, DT_RELASZ, TRUE }, 4639130561Sobrien { "PLT", DT_JMPREL, DT_PLTRELSZ, UNKNOWN } 4640130561Sobrien}; 4641130561Sobrien 464260484Sobrien/* Process the reloc section. */ 4643218822Sdim 464460484Sobrienstatic int 4645130561Sobrienprocess_relocs (FILE *file) 464660484Sobrien{ 4647130561Sobrien unsigned long rel_size; 4648130561Sobrien unsigned long rel_offset; 464960484Sobrien 465060484Sobrien 465160484Sobrien if (!do_reloc) 465260484Sobrien return 1; 465360484Sobrien 465460484Sobrien if (do_using_dynamic) 465560484Sobrien { 4656130561Sobrien int is_rela; 4657130561Sobrien const char *name; 4658130561Sobrien int has_dynamic_reloc; 4659130561Sobrien unsigned int i; 466060484Sobrien 4661130561Sobrien has_dynamic_reloc = 0; 466260484Sobrien 4663130561Sobrien for (i = 0; i < ARRAY_SIZE (dynamic_relocations); i++) 466460484Sobrien { 4665130561Sobrien is_rela = dynamic_relocations [i].rela; 4666130561Sobrien name = dynamic_relocations [i].name; 4667130561Sobrien rel_size = dynamic_info [dynamic_relocations [i].size]; 4668130561Sobrien rel_offset = dynamic_info [dynamic_relocations [i].reloc]; 466960484Sobrien 4670130561Sobrien has_dynamic_reloc |= rel_size; 4671130561Sobrien 4672130561Sobrien if (is_rela == UNKNOWN) 467360484Sobrien { 4674130561Sobrien if (dynamic_relocations [i].reloc == DT_JMPREL) 4675130561Sobrien switch (dynamic_info[DT_PLTREL]) 4676130561Sobrien { 4677130561Sobrien case DT_REL: 4678130561Sobrien is_rela = FALSE; 4679130561Sobrien break; 4680130561Sobrien case DT_RELA: 4681130561Sobrien is_rela = TRUE; 4682130561Sobrien break; 4683130561Sobrien } 468460484Sobrien } 468560484Sobrien 4686130561Sobrien if (rel_size) 4687130561Sobrien { 4688130561Sobrien printf 4689130561Sobrien (_("\n'%s' relocation section at offset 0x%lx contains %ld bytes:\n"), 4690130561Sobrien name, rel_offset, rel_size); 469160484Sobrien 4692130561Sobrien dump_relocations (file, 4693130561Sobrien offset_from_vma (file, rel_offset, rel_size), 4694130561Sobrien rel_size, 4695130561Sobrien dynamic_symbols, num_dynamic_syms, 4696218822Sdim dynamic_strings, dynamic_strings_length, is_rela); 4697130561Sobrien } 469860484Sobrien } 4699130561Sobrien 4700130561Sobrien if (! has_dynamic_reloc) 470160484Sobrien printf (_("\nThere are no dynamic relocations in this file.\n")); 470260484Sobrien } 470360484Sobrien else 470460484Sobrien { 4705130561Sobrien Elf_Internal_Shdr *section; 4706130561Sobrien unsigned long i; 4707130561Sobrien int found = 0; 470860484Sobrien 470960484Sobrien for (i = 0, section = section_headers; 471060484Sobrien i < elf_header.e_shnum; 4711130561Sobrien i++, section++) 471260484Sobrien { 471360484Sobrien if ( section->sh_type != SHT_RELA 471460484Sobrien && section->sh_type != SHT_REL) 471560484Sobrien continue; 471660484Sobrien 471760484Sobrien rel_offset = section->sh_offset; 471860484Sobrien rel_size = section->sh_size; 471960484Sobrien 472060484Sobrien if (rel_size) 472160484Sobrien { 4722130561Sobrien Elf_Internal_Shdr *strsec; 4723130561Sobrien int is_rela; 472460484Sobrien 472560484Sobrien printf (_("\nRelocation section ")); 472660484Sobrien 472760484Sobrien if (string_table == NULL) 472860484Sobrien printf ("%d", section->sh_name); 472960484Sobrien else 4730104834Sobrien printf (_("'%s'"), SECTION_NAME (section)); 473160484Sobrien 473260484Sobrien printf (_(" at offset 0x%lx contains %lu entries:\n"), 473360484Sobrien rel_offset, (unsigned long) (rel_size / section->sh_entsize)); 473460484Sobrien 4735218822Sdim is_rela = section->sh_type == SHT_RELA; 4736218822Sdim 4737218822Sdim if (section->sh_link 4738218822Sdim && SECTION_HEADER_INDEX (section->sh_link) 4739218822Sdim < elf_header.e_shnum) 474089857Sobrien { 4741130561Sobrien Elf_Internal_Shdr *symsec; 4742218822Sdim Elf_Internal_Sym *symtab; 4743218822Sdim unsigned long nsyms; 4744218822Sdim unsigned long strtablen = 0; 4745218822Sdim char *strtab = NULL; 474660484Sobrien 474789857Sobrien symsec = SECTION_HEADER (section->sh_link); 4748218822Sdim if (symsec->sh_type != SHT_SYMTAB 4749218822Sdim && symsec->sh_type != SHT_DYNSYM) 4750218822Sdim continue; 4751218822Sdim 475289857Sobrien nsyms = symsec->sh_size / symsec->sh_entsize; 475389857Sobrien symtab = GET_ELF_SYMBOLS (file, symsec); 475460484Sobrien 475589857Sobrien if (symtab == NULL) 475689857Sobrien continue; 475760484Sobrien 4758218822Sdim if (SECTION_HEADER_INDEX (symsec->sh_link) 4759218822Sdim < elf_header.e_shnum) 4760218822Sdim { 4761218822Sdim strsec = SECTION_HEADER (symsec->sh_link); 476260484Sobrien 4763218822Sdim strtab = get_data (NULL, file, strsec->sh_offset, 4764218822Sdim 1, strsec->sh_size, 4765218822Sdim _("string table")); 4766218822Sdim strtablen = strtab == NULL ? 0 : strsec->sh_size; 4767218822Sdim } 4768218822Sdim 4769218822Sdim dump_relocations (file, rel_offset, rel_size, 4770218822Sdim symtab, nsyms, strtab, strtablen, is_rela); 4771218822Sdim if (strtab) 4772218822Sdim free (strtab); 4773218822Sdim free (symtab); 477489857Sobrien } 4775218822Sdim else 4776218822Sdim dump_relocations (file, rel_offset, rel_size, 4777218822Sdim NULL, 0, NULL, 0, is_rela); 477860484Sobrien 477960484Sobrien found = 1; 478060484Sobrien } 478160484Sobrien } 478260484Sobrien 478360484Sobrien if (! found) 478460484Sobrien printf (_("\nThere are no relocations in this file.\n")); 478560484Sobrien } 478660484Sobrien 478760484Sobrien return 1; 478860484Sobrien} 478960484Sobrien 4790218822Sdim/* Process the unwind section. */ 4791218822Sdim 479278828Sobrien#include "unwind-ia64.h" 479360484Sobrien 479478828Sobrien/* An absolute address consists of a section and an offset. If the 479578828Sobrien section is NULL, the offset itself is the address, otherwise, the 479678828Sobrien address equals to LOAD_ADDRESS(section) + offset. */ 479778828Sobrien 479878828Sobrienstruct absaddr 479978828Sobrien { 480078828Sobrien unsigned short section; 480178828Sobrien bfd_vma offset; 480278828Sobrien }; 480378828Sobrien 4804218822Sdim#define ABSADDR(a) \ 4805218822Sdim ((a).section \ 4806218822Sdim ? section_headers [(a).section].sh_addr + (a).offset \ 4807218822Sdim : (a).offset) 4808218822Sdim 4809218822Sdimstruct ia64_unw_aux_info 481078828Sobrien { 4811218822Sdim struct ia64_unw_table_entry 481278828Sobrien { 4813130561Sobrien struct absaddr start; 4814130561Sobrien struct absaddr end; 4815130561Sobrien struct absaddr info; 481678828Sobrien } 4817130561Sobrien *table; /* Unwind table. */ 4818130561Sobrien unsigned long table_len; /* Length of unwind table. */ 4819130561Sobrien unsigned char *info; /* Unwind info. */ 4820130561Sobrien unsigned long info_size; /* Size of unwind info. */ 4821130561Sobrien bfd_vma info_addr; /* starting address of unwind info. */ 4822130561Sobrien bfd_vma seg_base; /* Starting address of segment. */ 4823130561Sobrien Elf_Internal_Sym *symtab; /* The symbol table. */ 4824130561Sobrien unsigned long nsyms; /* Number of symbols. */ 4825130561Sobrien char *strtab; /* The string table. */ 4826130561Sobrien unsigned long strtab_size; /* Size of string table. */ 482778828Sobrien }; 482878828Sobrien 482960484Sobrienstatic void 4830218822Sdimfind_symbol_for_address (Elf_Internal_Sym *symtab, 4831218822Sdim unsigned long nsyms, 4832218822Sdim const char *strtab, 4833218822Sdim unsigned long strtab_size, 4834130561Sobrien struct absaddr addr, 4835130561Sobrien const char **symname, 4836130561Sobrien bfd_vma *offset) 483778828Sobrien{ 4838130561Sobrien bfd_vma dist = 0x100000; 483978828Sobrien Elf_Internal_Sym *sym, *best = NULL; 484078828Sobrien unsigned long i; 484178828Sobrien 4842218822Sdim for (i = 0, sym = symtab; i < nsyms; ++i, ++sym) 484378828Sobrien { 484478828Sobrien if (ELF_ST_TYPE (sym->st_info) == STT_FUNC 484578828Sobrien && sym->st_name != 0 484678828Sobrien && (addr.section == SHN_UNDEF || addr.section == sym->st_shndx) 484778828Sobrien && addr.offset >= sym->st_value 484878828Sobrien && addr.offset - sym->st_value < dist) 484978828Sobrien { 485078828Sobrien best = sym; 485178828Sobrien dist = addr.offset - sym->st_value; 485278828Sobrien if (!dist) 485378828Sobrien break; 485478828Sobrien } 485578828Sobrien } 485678828Sobrien if (best) 485778828Sobrien { 4858218822Sdim *symname = (best->st_name >= strtab_size 4859218822Sdim ? "<corrupt>" : strtab + best->st_name); 486078828Sobrien *offset = dist; 486178828Sobrien return; 486278828Sobrien } 486378828Sobrien *symname = NULL; 486478828Sobrien *offset = addr.offset; 486578828Sobrien} 486678828Sobrien 486778828Sobrienstatic void 4868218822Sdimdump_ia64_unwind (struct ia64_unw_aux_info *aux) 486978828Sobrien{ 4870218822Sdim struct ia64_unw_table_entry *tp; 487178828Sobrien int in_body; 487278828Sobrien 487378828Sobrien for (tp = aux->table; tp < aux->table + aux->table_len; ++tp) 487478828Sobrien { 487578828Sobrien bfd_vma stamp; 487678828Sobrien bfd_vma offset; 4877130561Sobrien const unsigned char *dp; 4878130561Sobrien const unsigned char *head; 4879130561Sobrien const char *procname; 488078828Sobrien 4881218822Sdim find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab, 4882218822Sdim aux->strtab_size, tp->start, &procname, &offset); 488378828Sobrien 488478828Sobrien fputs ("\n<", stdout); 488578828Sobrien 488678828Sobrien if (procname) 488778828Sobrien { 488878828Sobrien fputs (procname, stdout); 488978828Sobrien 489078828Sobrien if (offset) 489178828Sobrien printf ("+%lx", (unsigned long) offset); 489278828Sobrien } 489378828Sobrien 489478828Sobrien fputs (">: [", stdout); 489578828Sobrien print_vma (tp->start.offset, PREFIX_HEX); 489678828Sobrien fputc ('-', stdout); 489778828Sobrien print_vma (tp->end.offset, PREFIX_HEX); 4898130561Sobrien printf ("], info at +0x%lx\n", 489978828Sobrien (unsigned long) (tp->info.offset - aux->seg_base)); 490078828Sobrien 4901218822Sdim head = aux->info + (ABSADDR (tp->info) - aux->info_addr); 4902218822Sdim stamp = byte_get ((unsigned char *) head, sizeof (stamp)); 490378828Sobrien 4904130561Sobrien printf (" v%u, flags=0x%lx (%s%s), len=%lu bytes\n", 490578828Sobrien (unsigned) UNW_VER (stamp), 490678828Sobrien (unsigned long) ((stamp & UNW_FLAG_MASK) >> 32), 490778828Sobrien UNW_FLAG_EHANDLER (stamp) ? " ehandler" : "", 490878828Sobrien UNW_FLAG_UHANDLER (stamp) ? " uhandler" : "", 4909218822Sdim (unsigned long) (eh_addr_size * UNW_LENGTH (stamp))); 491078828Sobrien 491178828Sobrien if (UNW_VER (stamp) != 1) 491278828Sobrien { 491378828Sobrien printf ("\tUnknown version.\n"); 491478828Sobrien continue; 491578828Sobrien } 491678828Sobrien 491778828Sobrien in_body = 0; 4918218822Sdim for (dp = head + 8; dp < head + 8 + eh_addr_size * UNW_LENGTH (stamp);) 491978828Sobrien dp = unw_decode (dp, in_body, & in_body); 492078828Sobrien } 492178828Sobrien} 492278828Sobrien 492378828Sobrienstatic int 4924130561Sobrienslurp_ia64_unwind_table (FILE *file, 4925218822Sdim struct ia64_unw_aux_info *aux, 4926130561Sobrien Elf_Internal_Shdr *sec) 492778828Sobrien{ 4928218822Sdim unsigned long size, nrelas, i; 4929130561Sobrien Elf_Internal_Phdr *seg; 4930218822Sdim struct ia64_unw_table_entry *tep; 4931130561Sobrien Elf_Internal_Shdr *relsec; 493278828Sobrien Elf_Internal_Rela *rela, *rp; 493378828Sobrien unsigned char *table, *tp; 493478828Sobrien Elf_Internal_Sym *sym; 493578828Sobrien const char *relname; 493678828Sobrien 493778828Sobrien /* First, find the starting address of the segment that includes 493878828Sobrien this section: */ 493978828Sobrien 494078828Sobrien if (elf_header.e_phnum) 494178828Sobrien { 4942130561Sobrien if (! get_program_headers (file)) 494378828Sobrien return 0; 494478828Sobrien 4945130561Sobrien for (seg = program_headers; 4946130561Sobrien seg < program_headers + elf_header.e_phnum; 4947130561Sobrien ++seg) 494878828Sobrien { 494978828Sobrien if (seg->p_type != PT_LOAD) 495078828Sobrien continue; 495178828Sobrien 495278828Sobrien if (sec->sh_addr >= seg->p_vaddr 495378828Sobrien && (sec->sh_addr + sec->sh_size <= seg->p_vaddr + seg->p_memsz)) 495478828Sobrien { 495578828Sobrien aux->seg_base = seg->p_vaddr; 495678828Sobrien break; 495778828Sobrien } 495878828Sobrien } 495978828Sobrien } 496078828Sobrien 496178828Sobrien /* Second, build the unwind table from the contents of the unwind section: */ 496278828Sobrien size = sec->sh_size; 4963218822Sdim table = get_data (NULL, file, sec->sh_offset, 1, size, _("unwind table")); 496489857Sobrien if (!table) 496589857Sobrien return 0; 496678828Sobrien 4967218822Sdim aux->table = xcmalloc (size / (3 * eh_addr_size), sizeof (aux->table[0])); 4968218822Sdim tep = aux->table; 4969218822Sdim for (tp = table; tp < table + size; tp += 3 * eh_addr_size, ++tep) 497078828Sobrien { 497178828Sobrien tep->start.section = SHN_UNDEF; 497278828Sobrien tep->end.section = SHN_UNDEF; 497378828Sobrien tep->info.section = SHN_UNDEF; 497478828Sobrien if (is_32bit_elf) 497578828Sobrien { 497678828Sobrien tep->start.offset = byte_get ((unsigned char *) tp + 0, 4); 497778828Sobrien tep->end.offset = byte_get ((unsigned char *) tp + 4, 4); 497878828Sobrien tep->info.offset = byte_get ((unsigned char *) tp + 8, 4); 497978828Sobrien } 498078828Sobrien else 498178828Sobrien { 4982218822Sdim tep->start.offset = BYTE_GET ((unsigned char *) tp + 0); 4983218822Sdim tep->end.offset = BYTE_GET ((unsigned char *) tp + 8); 4984218822Sdim tep->info.offset = BYTE_GET ((unsigned char *) tp + 16); 498578828Sobrien } 498678828Sobrien tep->start.offset += aux->seg_base; 498778828Sobrien tep->end.offset += aux->seg_base; 498878828Sobrien tep->info.offset += aux->seg_base; 498978828Sobrien } 499078828Sobrien free (table); 499178828Sobrien 499278828Sobrien /* Third, apply any relocations to the unwind table: */ 499378828Sobrien 499478828Sobrien for (relsec = section_headers; 499578828Sobrien relsec < section_headers + elf_header.e_shnum; 499678828Sobrien ++relsec) 499778828Sobrien { 499878828Sobrien if (relsec->sh_type != SHT_RELA 4999218822Sdim || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum 500089857Sobrien || SECTION_HEADER (relsec->sh_info) != sec) 500178828Sobrien continue; 500278828Sobrien 500378828Sobrien if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size, 500478828Sobrien & rela, & nrelas)) 500578828Sobrien return 0; 500678828Sobrien 500778828Sobrien for (rp = rela; rp < rela + nrelas; ++rp) 500878828Sobrien { 500978828Sobrien if (is_32bit_elf) 501078828Sobrien { 501178828Sobrien relname = elf_ia64_reloc_type (ELF32_R_TYPE (rp->r_info)); 501278828Sobrien sym = aux->symtab + ELF32_R_SYM (rp->r_info); 501378828Sobrien } 501478828Sobrien else 501578828Sobrien { 501678828Sobrien relname = elf_ia64_reloc_type (ELF64_R_TYPE (rp->r_info)); 501778828Sobrien sym = aux->symtab + ELF64_R_SYM (rp->r_info); 501878828Sobrien } 501978828Sobrien 5020218822Sdim if (! const_strneq (relname, "R_IA64_SEGREL")) 502178828Sobrien { 502289857Sobrien warn (_("Skipping unexpected relocation type %s\n"), relname); 502378828Sobrien continue; 502478828Sobrien } 502578828Sobrien 5026218822Sdim i = rp->r_offset / (3 * eh_addr_size); 502778828Sobrien 5028218822Sdim switch (rp->r_offset/eh_addr_size % 3) 502978828Sobrien { 503078828Sobrien case 0: 503178828Sobrien aux->table[i].start.section = sym->st_shndx; 5032218822Sdim aux->table[i].start.offset += rp->r_addend + sym->st_value; 503378828Sobrien break; 503478828Sobrien case 1: 503578828Sobrien aux->table[i].end.section = sym->st_shndx; 5036218822Sdim aux->table[i].end.offset += rp->r_addend + sym->st_value; 503778828Sobrien break; 503878828Sobrien case 2: 503978828Sobrien aux->table[i].info.section = sym->st_shndx; 5040218822Sdim aux->table[i].info.offset += rp->r_addend + sym->st_value; 504178828Sobrien break; 504278828Sobrien default: 504378828Sobrien break; 504478828Sobrien } 504578828Sobrien } 504678828Sobrien 504778828Sobrien free (rela); 504878828Sobrien } 504978828Sobrien 5050218822Sdim aux->table_len = size / (3 * eh_addr_size); 505178828Sobrien return 1; 505278828Sobrien} 505378828Sobrien 505478828Sobrienstatic int 5055218822Sdimia64_process_unwind (FILE *file) 505678828Sobrien{ 5057130561Sobrien Elf_Internal_Shdr *sec, *unwsec = NULL, *strsec; 5058218822Sdim unsigned long i, unwcount = 0, unwstart = 0; 5059218822Sdim struct ia64_unw_aux_info aux; 506078828Sobrien 506178828Sobrien memset (& aux, 0, sizeof (aux)); 506278828Sobrien 506378828Sobrien for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec) 506478828Sobrien { 5065218822Sdim if (sec->sh_type == SHT_SYMTAB 5066218822Sdim && SECTION_HEADER_INDEX (sec->sh_link) < elf_header.e_shnum) 506778828Sobrien { 506878828Sobrien aux.nsyms = sec->sh_size / sec->sh_entsize; 506989857Sobrien aux.symtab = GET_ELF_SYMBOLS (file, sec); 507078828Sobrien 507189857Sobrien strsec = SECTION_HEADER (sec->sh_link); 5072130561Sobrien aux.strtab = get_data (NULL, file, strsec->sh_offset, 5073218822Sdim 1, strsec->sh_size, _("string table")); 5074218822Sdim aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0; 507578828Sobrien } 507678828Sobrien else if (sec->sh_type == SHT_IA_64_UNWIND) 507778828Sobrien unwcount++; 507878828Sobrien } 507978828Sobrien 508078828Sobrien if (!unwcount) 508178828Sobrien printf (_("\nThere are no unwind sections in this file.\n")); 508278828Sobrien 508378828Sobrien while (unwcount-- > 0) 508478828Sobrien { 508578828Sobrien char *suffix; 508678828Sobrien size_t len, len2; 508778828Sobrien 508878828Sobrien for (i = unwstart, sec = section_headers + unwstart; 508978828Sobrien i < elf_header.e_shnum; ++i, ++sec) 509078828Sobrien if (sec->sh_type == SHT_IA_64_UNWIND) 509178828Sobrien { 509278828Sobrien unwsec = sec; 509378828Sobrien break; 509478828Sobrien } 509578828Sobrien 509678828Sobrien unwstart = i + 1; 509778828Sobrien len = sizeof (ELF_STRING_ia64_unwind_once) - 1; 509878828Sobrien 5099218822Sdim if ((unwsec->sh_flags & SHF_GROUP) != 0) 510078828Sobrien { 5101218822Sdim /* We need to find which section group it is in. */ 5102218822Sdim struct group_list *g = section_headers_groups [i]->root; 5103218822Sdim 5104218822Sdim for (; g != NULL; g = g->next) 5105218822Sdim { 5106218822Sdim sec = SECTION_HEADER (g->section_index); 5107218822Sdim 5108218822Sdim if (streq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info)) 5109218822Sdim break; 5110218822Sdim } 5111218822Sdim 5112218822Sdim if (g == NULL) 5113218822Sdim i = elf_header.e_shnum; 5114218822Sdim } 5115218822Sdim else if (strneq (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind_once, len)) 5116218822Sdim { 5117218822Sdim /* .gnu.linkonce.ia64unw.FOO -> .gnu.linkonce.ia64unwi.FOO. */ 511878828Sobrien len2 = sizeof (ELF_STRING_ia64_unwind_info_once) - 1; 511978828Sobrien suffix = SECTION_NAME (unwsec) + len; 512078828Sobrien for (i = 0, sec = section_headers; i < elf_header.e_shnum; 512178828Sobrien ++i, ++sec) 5122218822Sdim if (strneq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info_once, len2) 5123218822Sdim && streq (SECTION_NAME (sec) + len2, suffix)) 512478828Sobrien break; 512578828Sobrien } 512678828Sobrien else 512778828Sobrien { 512878828Sobrien /* .IA_64.unwindFOO -> .IA_64.unwind_infoFOO 5129218822Sdim .IA_64.unwind or BAR -> .IA_64.unwind_info. */ 513078828Sobrien len = sizeof (ELF_STRING_ia64_unwind) - 1; 513178828Sobrien len2 = sizeof (ELF_STRING_ia64_unwind_info) - 1; 513278828Sobrien suffix = ""; 5133218822Sdim if (strneq (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind, len)) 513478828Sobrien suffix = SECTION_NAME (unwsec) + len; 513578828Sobrien for (i = 0, sec = section_headers; i < elf_header.e_shnum; 513678828Sobrien ++i, ++sec) 5137218822Sdim if (strneq (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info, len2) 5138218822Sdim && streq (SECTION_NAME (sec) + len2, suffix)) 513978828Sobrien break; 514078828Sobrien } 514178828Sobrien 514278828Sobrien if (i == elf_header.e_shnum) 514378828Sobrien { 514478828Sobrien printf (_("\nCould not find unwind info section for ")); 514578828Sobrien 514678828Sobrien if (string_table == NULL) 514778828Sobrien printf ("%d", unwsec->sh_name); 514878828Sobrien else 5149104834Sobrien printf (_("'%s'"), SECTION_NAME (unwsec)); 515078828Sobrien } 515178828Sobrien else 515278828Sobrien { 515378828Sobrien aux.info_size = sec->sh_size; 515478828Sobrien aux.info_addr = sec->sh_addr; 5155218822Sdim aux.info = get_data (NULL, file, sec->sh_offset, 1, aux.info_size, 5156130561Sobrien _("unwind info")); 515778828Sobrien 515878828Sobrien printf (_("\nUnwind section ")); 515978828Sobrien 516078828Sobrien if (string_table == NULL) 516178828Sobrien printf ("%d", unwsec->sh_name); 516278828Sobrien else 5163104834Sobrien printf (_("'%s'"), SECTION_NAME (unwsec)); 516478828Sobrien 516578828Sobrien printf (_(" at offset 0x%lx contains %lu entries:\n"), 516689857Sobrien (unsigned long) unwsec->sh_offset, 5167218822Sdim (unsigned long) (unwsec->sh_size / (3 * eh_addr_size))); 516878828Sobrien 516978828Sobrien (void) slurp_ia64_unwind_table (file, & aux, unwsec); 517078828Sobrien 517178828Sobrien if (aux.table_len > 0) 517278828Sobrien dump_ia64_unwind (& aux); 517378828Sobrien 517478828Sobrien if (aux.table) 517578828Sobrien free ((char *) aux.table); 517678828Sobrien if (aux.info) 517778828Sobrien free ((char *) aux.info); 517878828Sobrien aux.table = NULL; 517978828Sobrien aux.info = NULL; 518078828Sobrien } 518178828Sobrien } 518278828Sobrien 518378828Sobrien if (aux.symtab) 518478828Sobrien free (aux.symtab); 518578828Sobrien if (aux.strtab) 518678828Sobrien free ((char *) aux.strtab); 518778828Sobrien 518878828Sobrien return 1; 518978828Sobrien} 519078828Sobrien 5191218822Sdimstruct hppa_unw_aux_info 5192218822Sdim { 5193218822Sdim struct hppa_unw_table_entry 5194218822Sdim { 5195218822Sdim struct absaddr start; 5196218822Sdim struct absaddr end; 5197218822Sdim unsigned int Cannot_unwind:1; /* 0 */ 5198218822Sdim unsigned int Millicode:1; /* 1 */ 5199218822Sdim unsigned int Millicode_save_sr0:1; /* 2 */ 5200218822Sdim unsigned int Region_description:2; /* 3..4 */ 5201218822Sdim unsigned int reserved1:1; /* 5 */ 5202218822Sdim unsigned int Entry_SR:1; /* 6 */ 5203218822Sdim unsigned int Entry_FR:4; /* number saved */ /* 7..10 */ 5204218822Sdim unsigned int Entry_GR:5; /* number saved */ /* 11..15 */ 5205218822Sdim unsigned int Args_stored:1; /* 16 */ 5206218822Sdim unsigned int Variable_Frame:1; /* 17 */ 5207218822Sdim unsigned int Separate_Package_Body:1; /* 18 */ 5208218822Sdim unsigned int Frame_Extension_Millicode:1; /* 19 */ 5209218822Sdim unsigned int Stack_Overflow_Check:1; /* 20 */ 5210218822Sdim unsigned int Two_Instruction_SP_Increment:1; /* 21 */ 5211218822Sdim unsigned int Ada_Region:1; /* 22 */ 5212218822Sdim unsigned int cxx_info:1; /* 23 */ 5213218822Sdim unsigned int cxx_try_catch:1; /* 24 */ 5214218822Sdim unsigned int sched_entry_seq:1; /* 25 */ 5215218822Sdim unsigned int reserved2:1; /* 26 */ 5216218822Sdim unsigned int Save_SP:1; /* 27 */ 5217218822Sdim unsigned int Save_RP:1; /* 28 */ 5218218822Sdim unsigned int Save_MRP_in_frame:1; /* 29 */ 5219218822Sdim unsigned int extn_ptr_defined:1; /* 30 */ 5220218822Sdim unsigned int Cleanup_defined:1; /* 31 */ 5221218822Sdim 5222218822Sdim unsigned int MPE_XL_interrupt_marker:1; /* 0 */ 5223218822Sdim unsigned int HP_UX_interrupt_marker:1; /* 1 */ 5224218822Sdim unsigned int Large_frame:1; /* 2 */ 5225218822Sdim unsigned int Pseudo_SP_Set:1; /* 3 */ 5226218822Sdim unsigned int reserved4:1; /* 4 */ 5227218822Sdim unsigned int Total_frame_size:27; /* 5..31 */ 5228218822Sdim } 5229218822Sdim *table; /* Unwind table. */ 5230218822Sdim unsigned long table_len; /* Length of unwind table. */ 5231218822Sdim bfd_vma seg_base; /* Starting address of segment. */ 5232218822Sdim Elf_Internal_Sym *symtab; /* The symbol table. */ 5233218822Sdim unsigned long nsyms; /* Number of symbols. */ 5234218822Sdim char *strtab; /* The string table. */ 5235218822Sdim unsigned long strtab_size; /* Size of string table. */ 5236218822Sdim }; 5237218822Sdim 523878828Sobrienstatic void 5239218822Sdimdump_hppa_unwind (struct hppa_unw_aux_info *aux) 524060484Sobrien{ 5241218822Sdim struct hppa_unw_table_entry *tp; 5242218822Sdim 5243218822Sdim for (tp = aux->table; tp < aux->table + aux->table_len; ++tp) 5244218822Sdim { 5245218822Sdim bfd_vma offset; 5246218822Sdim const char *procname; 5247218822Sdim 5248218822Sdim find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab, 5249218822Sdim aux->strtab_size, tp->start, &procname, 5250218822Sdim &offset); 5251218822Sdim 5252218822Sdim fputs ("\n<", stdout); 5253218822Sdim 5254218822Sdim if (procname) 5255218822Sdim { 5256218822Sdim fputs (procname, stdout); 5257218822Sdim 5258218822Sdim if (offset) 5259218822Sdim printf ("+%lx", (unsigned long) offset); 5260218822Sdim } 5261218822Sdim 5262218822Sdim fputs (">: [", stdout); 5263218822Sdim print_vma (tp->start.offset, PREFIX_HEX); 5264218822Sdim fputc ('-', stdout); 5265218822Sdim print_vma (tp->end.offset, PREFIX_HEX); 5266218822Sdim printf ("]\n\t"); 5267218822Sdim 5268218822Sdim#define PF(_m) if (tp->_m) printf (#_m " "); 5269218822Sdim#define PV(_m) if (tp->_m) printf (#_m "=%d ", tp->_m); 5270218822Sdim PF(Cannot_unwind); 5271218822Sdim PF(Millicode); 5272218822Sdim PF(Millicode_save_sr0); 5273218822Sdim /* PV(Region_description); */ 5274218822Sdim PF(Entry_SR); 5275218822Sdim PV(Entry_FR); 5276218822Sdim PV(Entry_GR); 5277218822Sdim PF(Args_stored); 5278218822Sdim PF(Variable_Frame); 5279218822Sdim PF(Separate_Package_Body); 5280218822Sdim PF(Frame_Extension_Millicode); 5281218822Sdim PF(Stack_Overflow_Check); 5282218822Sdim PF(Two_Instruction_SP_Increment); 5283218822Sdim PF(Ada_Region); 5284218822Sdim PF(cxx_info); 5285218822Sdim PF(cxx_try_catch); 5286218822Sdim PF(sched_entry_seq); 5287218822Sdim PF(Save_SP); 5288218822Sdim PF(Save_RP); 5289218822Sdim PF(Save_MRP_in_frame); 5290218822Sdim PF(extn_ptr_defined); 5291218822Sdim PF(Cleanup_defined); 5292218822Sdim PF(MPE_XL_interrupt_marker); 5293218822Sdim PF(HP_UX_interrupt_marker); 5294218822Sdim PF(Large_frame); 5295218822Sdim PF(Pseudo_SP_Set); 5296218822Sdim PV(Total_frame_size); 5297218822Sdim#undef PF 5298218822Sdim#undef PV 5299218822Sdim } 5300218822Sdim 5301218822Sdim printf ("\n"); 5302218822Sdim} 5303218822Sdim 5304218822Sdimstatic int 5305218822Sdimslurp_hppa_unwind_table (FILE *file, 5306218822Sdim struct hppa_unw_aux_info *aux, 5307218822Sdim Elf_Internal_Shdr *sec) 5308218822Sdim{ 5309218822Sdim unsigned long size, unw_ent_size, nentries, nrelas, i; 5310218822Sdim Elf_Internal_Phdr *seg; 5311218822Sdim struct hppa_unw_table_entry *tep; 5312218822Sdim Elf_Internal_Shdr *relsec; 5313218822Sdim Elf_Internal_Rela *rela, *rp; 5314218822Sdim unsigned char *table, *tp; 5315218822Sdim Elf_Internal_Sym *sym; 5316218822Sdim const char *relname; 5317218822Sdim 5318218822Sdim /* First, find the starting address of the segment that includes 5319218822Sdim this section. */ 5320218822Sdim 5321218822Sdim if (elf_header.e_phnum) 5322218822Sdim { 5323218822Sdim if (! get_program_headers (file)) 5324218822Sdim return 0; 5325218822Sdim 5326218822Sdim for (seg = program_headers; 5327218822Sdim seg < program_headers + elf_header.e_phnum; 5328218822Sdim ++seg) 5329218822Sdim { 5330218822Sdim if (seg->p_type != PT_LOAD) 5331218822Sdim continue; 5332218822Sdim 5333218822Sdim if (sec->sh_addr >= seg->p_vaddr 5334218822Sdim && (sec->sh_addr + sec->sh_size <= seg->p_vaddr + seg->p_memsz)) 5335218822Sdim { 5336218822Sdim aux->seg_base = seg->p_vaddr; 5337218822Sdim break; 5338218822Sdim } 5339218822Sdim } 5340218822Sdim } 5341218822Sdim 5342218822Sdim /* Second, build the unwind table from the contents of the unwind 5343218822Sdim section. */ 5344218822Sdim size = sec->sh_size; 5345218822Sdim table = get_data (NULL, file, sec->sh_offset, 1, size, _("unwind table")); 5346218822Sdim if (!table) 5347218822Sdim return 0; 5348218822Sdim 5349218822Sdim unw_ent_size = 16; 5350218822Sdim nentries = size / unw_ent_size; 5351218822Sdim size = unw_ent_size * nentries; 5352218822Sdim 5353218822Sdim tep = aux->table = xcmalloc (nentries, sizeof (aux->table[0])); 5354218822Sdim 5355218822Sdim for (tp = table; tp < table + size; tp += unw_ent_size, ++tep) 5356218822Sdim { 5357218822Sdim unsigned int tmp1, tmp2; 5358218822Sdim 5359218822Sdim tep->start.section = SHN_UNDEF; 5360218822Sdim tep->end.section = SHN_UNDEF; 5361218822Sdim 5362218822Sdim tep->start.offset = byte_get ((unsigned char *) tp + 0, 4); 5363218822Sdim tep->end.offset = byte_get ((unsigned char *) tp + 4, 4); 5364218822Sdim tmp1 = byte_get ((unsigned char *) tp + 8, 4); 5365218822Sdim tmp2 = byte_get ((unsigned char *) tp + 12, 4); 5366218822Sdim 5367218822Sdim tep->start.offset += aux->seg_base; 5368218822Sdim tep->end.offset += aux->seg_base; 5369218822Sdim 5370218822Sdim tep->Cannot_unwind = (tmp1 >> 31) & 0x1; 5371218822Sdim tep->Millicode = (tmp1 >> 30) & 0x1; 5372218822Sdim tep->Millicode_save_sr0 = (tmp1 >> 29) & 0x1; 5373218822Sdim tep->Region_description = (tmp1 >> 27) & 0x3; 5374218822Sdim tep->reserved1 = (tmp1 >> 26) & 0x1; 5375218822Sdim tep->Entry_SR = (tmp1 >> 25) & 0x1; 5376218822Sdim tep->Entry_FR = (tmp1 >> 21) & 0xf; 5377218822Sdim tep->Entry_GR = (tmp1 >> 16) & 0x1f; 5378218822Sdim tep->Args_stored = (tmp1 >> 15) & 0x1; 5379218822Sdim tep->Variable_Frame = (tmp1 >> 14) & 0x1; 5380218822Sdim tep->Separate_Package_Body = (tmp1 >> 13) & 0x1; 5381218822Sdim tep->Frame_Extension_Millicode = (tmp1 >> 12) & 0x1; 5382218822Sdim tep->Stack_Overflow_Check = (tmp1 >> 11) & 0x1; 5383218822Sdim tep->Two_Instruction_SP_Increment = (tmp1 >> 10) & 0x1; 5384218822Sdim tep->Ada_Region = (tmp1 >> 9) & 0x1; 5385218822Sdim tep->cxx_info = (tmp1 >> 8) & 0x1; 5386218822Sdim tep->cxx_try_catch = (tmp1 >> 7) & 0x1; 5387218822Sdim tep->sched_entry_seq = (tmp1 >> 6) & 0x1; 5388218822Sdim tep->reserved2 = (tmp1 >> 5) & 0x1; 5389218822Sdim tep->Save_SP = (tmp1 >> 4) & 0x1; 5390218822Sdim tep->Save_RP = (tmp1 >> 3) & 0x1; 5391218822Sdim tep->Save_MRP_in_frame = (tmp1 >> 2) & 0x1; 5392218822Sdim tep->extn_ptr_defined = (tmp1 >> 1) & 0x1; 5393218822Sdim tep->Cleanup_defined = tmp1 & 0x1; 5394218822Sdim 5395218822Sdim tep->MPE_XL_interrupt_marker = (tmp2 >> 31) & 0x1; 5396218822Sdim tep->HP_UX_interrupt_marker = (tmp2 >> 30) & 0x1; 5397218822Sdim tep->Large_frame = (tmp2 >> 29) & 0x1; 5398218822Sdim tep->Pseudo_SP_Set = (tmp2 >> 28) & 0x1; 5399218822Sdim tep->reserved4 = (tmp2 >> 27) & 0x1; 5400218822Sdim tep->Total_frame_size = tmp2 & 0x7ffffff; 5401218822Sdim } 5402218822Sdim free (table); 5403218822Sdim 5404218822Sdim /* Third, apply any relocations to the unwind table. */ 5405218822Sdim 5406218822Sdim for (relsec = section_headers; 5407218822Sdim relsec < section_headers + elf_header.e_shnum; 5408218822Sdim ++relsec) 5409218822Sdim { 5410218822Sdim if (relsec->sh_type != SHT_RELA 5411218822Sdim || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum 5412218822Sdim || SECTION_HEADER (relsec->sh_info) != sec) 5413218822Sdim continue; 5414218822Sdim 5415218822Sdim if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size, 5416218822Sdim & rela, & nrelas)) 5417218822Sdim return 0; 5418218822Sdim 5419218822Sdim for (rp = rela; rp < rela + nrelas; ++rp) 5420218822Sdim { 5421218822Sdim if (is_32bit_elf) 5422218822Sdim { 5423218822Sdim relname = elf_hppa_reloc_type (ELF32_R_TYPE (rp->r_info)); 5424218822Sdim sym = aux->symtab + ELF32_R_SYM (rp->r_info); 5425218822Sdim } 5426218822Sdim else 5427218822Sdim { 5428218822Sdim relname = elf_hppa_reloc_type (ELF64_R_TYPE (rp->r_info)); 5429218822Sdim sym = aux->symtab + ELF64_R_SYM (rp->r_info); 5430218822Sdim } 5431218822Sdim 5432218822Sdim /* R_PARISC_SEGREL32 or R_PARISC_SEGREL64. */ 5433218822Sdim if (! const_strneq (relname, "R_PARISC_SEGREL")) 5434218822Sdim { 5435218822Sdim warn (_("Skipping unexpected relocation type %s\n"), relname); 5436218822Sdim continue; 5437218822Sdim } 5438218822Sdim 5439218822Sdim i = rp->r_offset / unw_ent_size; 5440218822Sdim 5441218822Sdim switch ((rp->r_offset % unw_ent_size) / eh_addr_size) 5442218822Sdim { 5443218822Sdim case 0: 5444218822Sdim aux->table[i].start.section = sym->st_shndx; 5445218822Sdim aux->table[i].start.offset += sym->st_value + rp->r_addend; 5446218822Sdim break; 5447218822Sdim case 1: 5448218822Sdim aux->table[i].end.section = sym->st_shndx; 5449218822Sdim aux->table[i].end.offset += sym->st_value + rp->r_addend; 5450218822Sdim break; 5451218822Sdim default: 5452218822Sdim break; 5453218822Sdim } 5454218822Sdim } 5455218822Sdim 5456218822Sdim free (rela); 5457218822Sdim } 5458218822Sdim 5459218822Sdim aux->table_len = nentries; 5460218822Sdim 5461218822Sdim return 1; 5462218822Sdim} 5463218822Sdim 5464218822Sdimstatic int 5465218822Sdimhppa_process_unwind (FILE *file) 5466218822Sdim{ 5467218822Sdim struct hppa_unw_aux_info aux; 5468218822Sdim Elf_Internal_Shdr *unwsec = NULL; 5469218822Sdim Elf_Internal_Shdr *strsec; 5470218822Sdim Elf_Internal_Shdr *sec; 5471218822Sdim unsigned long i; 5472218822Sdim 5473218822Sdim memset (& aux, 0, sizeof (aux)); 5474218822Sdim 5475218822Sdim if (string_table == NULL) 5476218822Sdim return 1; 5477218822Sdim 5478218822Sdim for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec) 5479218822Sdim { 5480218822Sdim if (sec->sh_type == SHT_SYMTAB 5481218822Sdim && SECTION_HEADER_INDEX (sec->sh_link) < elf_header.e_shnum) 5482218822Sdim { 5483218822Sdim aux.nsyms = sec->sh_size / sec->sh_entsize; 5484218822Sdim aux.symtab = GET_ELF_SYMBOLS (file, sec); 5485218822Sdim 5486218822Sdim strsec = SECTION_HEADER (sec->sh_link); 5487218822Sdim aux.strtab = get_data (NULL, file, strsec->sh_offset, 5488218822Sdim 1, strsec->sh_size, _("string table")); 5489218822Sdim aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0; 5490218822Sdim } 5491218822Sdim else if (streq (SECTION_NAME (sec), ".PARISC.unwind")) 5492218822Sdim unwsec = sec; 5493218822Sdim } 5494218822Sdim 5495218822Sdim if (!unwsec) 5496218822Sdim printf (_("\nThere are no unwind sections in this file.\n")); 5497218822Sdim 5498218822Sdim for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec) 5499218822Sdim { 5500218822Sdim if (streq (SECTION_NAME (sec), ".PARISC.unwind")) 5501218822Sdim { 5502218822Sdim printf (_("\nUnwind section ")); 5503218822Sdim printf (_("'%s'"), SECTION_NAME (sec)); 5504218822Sdim 5505218822Sdim printf (_(" at offset 0x%lx contains %lu entries:\n"), 5506218822Sdim (unsigned long) sec->sh_offset, 5507218822Sdim (unsigned long) (sec->sh_size / (2 * eh_addr_size + 8))); 5508218822Sdim 5509218822Sdim slurp_hppa_unwind_table (file, &aux, sec); 5510218822Sdim if (aux.table_len > 0) 5511218822Sdim dump_hppa_unwind (&aux); 5512218822Sdim 5513218822Sdim if (aux.table) 5514218822Sdim free ((char *) aux.table); 5515218822Sdim aux.table = NULL; 5516218822Sdim } 5517218822Sdim } 5518218822Sdim 5519218822Sdim if (aux.symtab) 5520218822Sdim free (aux.symtab); 5521218822Sdim if (aux.strtab) 5522218822Sdim free ((char *) aux.strtab); 5523218822Sdim 5524218822Sdim return 1; 5525218822Sdim} 5526218822Sdim 5527218822Sdimstatic int 5528218822Sdimprocess_unwind (FILE *file) 5529218822Sdim{ 5530218822Sdim struct unwind_handler { 5531218822Sdim int machtype; 5532218822Sdim int (*handler)(FILE *file); 5533218822Sdim } handlers[] = { 5534218822Sdim { EM_IA_64, ia64_process_unwind }, 5535218822Sdim { EM_PARISC, hppa_process_unwind }, 5536218822Sdim { 0, 0 } 5537218822Sdim }; 5538218822Sdim int i; 5539218822Sdim 5540218822Sdim if (!do_unwind) 5541218822Sdim return 1; 5542218822Sdim 5543218822Sdim for (i = 0; handlers[i].handler != NULL; i++) 5544218822Sdim if (elf_header.e_machine == handlers[i].machtype) 5545218822Sdim return handlers[i].handler (file); 5546218822Sdim 5547218822Sdim printf (_("\nThere are no unwind sections in this file.\n")); 5548218822Sdim return 1; 5549218822Sdim} 5550218822Sdim 5551218822Sdimstatic void 5552218822Sdimdynamic_section_mips_val (Elf_Internal_Dyn *entry) 5553218822Sdim{ 555460484Sobrien switch (entry->d_tag) 555560484Sobrien { 555660484Sobrien case DT_MIPS_FLAGS: 555760484Sobrien if (entry->d_un.d_val == 0) 555860484Sobrien printf ("NONE\n"); 555960484Sobrien else 556060484Sobrien { 556160484Sobrien static const char * opts[] = 556260484Sobrien { 556360484Sobrien "QUICKSTART", "NOTPOT", "NO_LIBRARY_REPLACEMENT", 556460484Sobrien "NO_MOVE", "SGI_ONLY", "GUARANTEE_INIT", "DELTA_C_PLUS_PLUS", 556560484Sobrien "GUARANTEE_START_INIT", "PIXIE", "DEFAULT_DELAY_LOAD", 556660484Sobrien "REQUICKSTART", "REQUICKSTARTED", "CORD", "NO_UNRES_UNDEF", 556760484Sobrien "RLD_ORDER_SAFE" 556860484Sobrien }; 556960484Sobrien unsigned int cnt; 557060484Sobrien int first = 1; 5571130561Sobrien for (cnt = 0; cnt < NUM_ELEM (opts); ++cnt) 557260484Sobrien if (entry->d_un.d_val & (1 << cnt)) 557360484Sobrien { 557460484Sobrien printf ("%s%s", first ? "" : " ", opts[cnt]); 557560484Sobrien first = 0; 557660484Sobrien } 557760484Sobrien puts (""); 557860484Sobrien } 557960484Sobrien break; 558060484Sobrien 558160484Sobrien case DT_MIPS_IVERSION: 5582218822Sdim if (VALID_DYNAMIC_NAME (entry->d_un.d_val)) 5583218822Sdim printf ("Interface Version: %s\n", GET_DYNAMIC_NAME (entry->d_un.d_val)); 558460484Sobrien else 5585218822Sdim printf ("<corrupt: %ld>\n", (long) entry->d_un.d_ptr); 558660484Sobrien break; 558760484Sobrien 558860484Sobrien case DT_MIPS_TIME_STAMP: 558960484Sobrien { 559060484Sobrien char timebuf[20]; 5591130561Sobrien struct tm *tmp; 559260484Sobrien 559360484Sobrien time_t time = entry->d_un.d_val; 559460484Sobrien tmp = gmtime (&time); 5595218822Sdim snprintf (timebuf, sizeof (timebuf), "%04u-%02u-%02uT%02u:%02u:%02u", 5596218822Sdim tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, 5597218822Sdim tmp->tm_hour, tmp->tm_min, tmp->tm_sec); 559860484Sobrien printf ("Time Stamp: %s\n", timebuf); 559960484Sobrien } 560060484Sobrien break; 560160484Sobrien 560260484Sobrien case DT_MIPS_RLD_VERSION: 560360484Sobrien case DT_MIPS_LOCAL_GOTNO: 560460484Sobrien case DT_MIPS_CONFLICTNO: 560560484Sobrien case DT_MIPS_LIBLISTNO: 560660484Sobrien case DT_MIPS_SYMTABNO: 560760484Sobrien case DT_MIPS_UNREFEXTNO: 560860484Sobrien case DT_MIPS_HIPAGENO: 560960484Sobrien case DT_MIPS_DELTA_CLASS_NO: 561060484Sobrien case DT_MIPS_DELTA_INSTANCE_NO: 561160484Sobrien case DT_MIPS_DELTA_RELOC_NO: 561260484Sobrien case DT_MIPS_DELTA_SYM_NO: 561360484Sobrien case DT_MIPS_DELTA_CLASSSYM_NO: 561460484Sobrien case DT_MIPS_COMPACT_SIZE: 561560484Sobrien printf ("%ld\n", (long) entry->d_un.d_ptr); 561660484Sobrien break; 561760484Sobrien 561860484Sobrien default: 561960484Sobrien printf ("%#lx\n", (long) entry->d_un.d_ptr); 562060484Sobrien } 562160484Sobrien} 562260484Sobrien 562360484Sobrien 562460484Sobrienstatic void 5625218822Sdimdynamic_section_parisc_val (Elf_Internal_Dyn *entry) 562660484Sobrien{ 562760484Sobrien switch (entry->d_tag) 562860484Sobrien { 562960484Sobrien case DT_HP_DLD_FLAGS: 563060484Sobrien { 563160484Sobrien static struct 563260484Sobrien { 563360484Sobrien long int bit; 5634130561Sobrien const char *str; 563560484Sobrien } 563660484Sobrien flags[] = 563760484Sobrien { 563860484Sobrien { DT_HP_DEBUG_PRIVATE, "HP_DEBUG_PRIVATE" }, 563960484Sobrien { DT_HP_DEBUG_CALLBACK, "HP_DEBUG_CALLBACK" }, 564060484Sobrien { DT_HP_DEBUG_CALLBACK_BOR, "HP_DEBUG_CALLBACK_BOR" }, 564160484Sobrien { DT_HP_NO_ENVVAR, "HP_NO_ENVVAR" }, 564260484Sobrien { DT_HP_BIND_NOW, "HP_BIND_NOW" }, 564360484Sobrien { DT_HP_BIND_NONFATAL, "HP_BIND_NONFATAL" }, 564460484Sobrien { DT_HP_BIND_VERBOSE, "HP_BIND_VERBOSE" }, 564560484Sobrien { DT_HP_BIND_RESTRICTED, "HP_BIND_RESTRICTED" }, 564660484Sobrien { DT_HP_BIND_SYMBOLIC, "HP_BIND_SYMBOLIC" }, 564760484Sobrien { DT_HP_RPATH_FIRST, "HP_RPATH_FIRST" }, 5648218822Sdim { DT_HP_BIND_DEPTH_FIRST, "HP_BIND_DEPTH_FIRST" }, 5649218822Sdim { DT_HP_GST, "HP_GST" }, 5650218822Sdim { DT_HP_SHLIB_FIXED, "HP_SHLIB_FIXED" }, 5651218822Sdim { DT_HP_MERGE_SHLIB_SEG, "HP_MERGE_SHLIB_SEG" }, 5652218822Sdim { DT_HP_NODELETE, "HP_NODELETE" }, 5653218822Sdim { DT_HP_GROUP, "HP_GROUP" }, 5654218822Sdim { DT_HP_PROTECT_LINKAGE_TABLE, "HP_PROTECT_LINKAGE_TABLE" } 565560484Sobrien }; 565660484Sobrien int first = 1; 565760484Sobrien size_t cnt; 565860484Sobrien bfd_vma val = entry->d_un.d_val; 565960484Sobrien 566060484Sobrien for (cnt = 0; cnt < sizeof (flags) / sizeof (flags[0]); ++cnt) 566160484Sobrien if (val & flags[cnt].bit) 566260484Sobrien { 566360484Sobrien if (! first) 566460484Sobrien putchar (' '); 566560484Sobrien fputs (flags[cnt].str, stdout); 566660484Sobrien first = 0; 566760484Sobrien val ^= flags[cnt].bit; 566860484Sobrien } 566977298Sobrien 567060484Sobrien if (val != 0 || first) 567160484Sobrien { 567260484Sobrien if (! first) 567360484Sobrien putchar (' '); 567460484Sobrien print_vma (val, HEX); 567560484Sobrien } 567660484Sobrien } 567760484Sobrien break; 567877298Sobrien 567960484Sobrien default: 568060484Sobrien print_vma (entry->d_un.d_ptr, PREFIX_HEX); 568160484Sobrien break; 568260484Sobrien } 5683130561Sobrien putchar ('\n'); 568460484Sobrien} 568560484Sobrien 5686130561Sobrienstatic void 5687218822Sdimdynamic_section_ia64_val (Elf_Internal_Dyn *entry) 5688130561Sobrien{ 5689130561Sobrien switch (entry->d_tag) 5690130561Sobrien { 5691130561Sobrien case DT_IA_64_PLT_RESERVE: 5692130561Sobrien /* First 3 slots reserved. */ 5693130561Sobrien print_vma (entry->d_un.d_ptr, PREFIX_HEX); 5694130561Sobrien printf (" -- "); 5695130561Sobrien print_vma (entry->d_un.d_ptr + (3 * 8), PREFIX_HEX); 5696130561Sobrien break; 5697130561Sobrien 5698130561Sobrien default: 5699130561Sobrien print_vma (entry->d_un.d_ptr, PREFIX_HEX); 5700130561Sobrien break; 5701130561Sobrien } 5702130561Sobrien putchar ('\n'); 5703130561Sobrien} 5704130561Sobrien 570560484Sobrienstatic int 5706218822Sdimget_32bit_dynamic_section (FILE *file) 570760484Sobrien{ 5708218822Sdim Elf32_External_Dyn *edyn, *ext; 5709130561Sobrien Elf_Internal_Dyn *entry; 571060484Sobrien 5711218822Sdim edyn = get_data (NULL, file, dynamic_addr, 1, dynamic_size, 5712218822Sdim _("dynamic section")); 571389857Sobrien if (!edyn) 571489857Sobrien return 0; 571560484Sobrien 5716218822Sdim/* SGI's ELF has more than one section in the DYNAMIC segment, and we 5717218822Sdim might not have the luxury of section headers. Look for the DT_NULL 5718218822Sdim terminator to determine the number of entries. */ 5719218822Sdim for (ext = edyn, dynamic_nent = 0; 5720218822Sdim (char *) ext < (char *) edyn + dynamic_size; 5721218822Sdim ext++) 5722218822Sdim { 5723218822Sdim dynamic_nent++; 5724218822Sdim if (BYTE_GET (ext->d_tag) == DT_NULL) 5725218822Sdim break; 5726218822Sdim } 572760484Sobrien 5728218822Sdim dynamic_section = cmalloc (dynamic_nent, sizeof (*entry)); 5729218822Sdim if (dynamic_section == NULL) 573060484Sobrien { 573160484Sobrien error (_("Out of memory\n")); 573260484Sobrien free (edyn); 573360484Sobrien return 0; 573460484Sobrien } 573560484Sobrien 5736218822Sdim for (ext = edyn, entry = dynamic_section; 5737218822Sdim entry < dynamic_section + dynamic_nent; 5738218822Sdim ext++, entry++) 573960484Sobrien { 5740218822Sdim entry->d_tag = BYTE_GET (ext->d_tag); 5741218822Sdim entry->d_un.d_val = BYTE_GET (ext->d_un.d_val); 574260484Sobrien } 574360484Sobrien 574460484Sobrien free (edyn); 574560484Sobrien 574660484Sobrien return 1; 574760484Sobrien} 574860484Sobrien 574960484Sobrienstatic int 5750218822Sdimget_64bit_dynamic_section (FILE *file) 575160484Sobrien{ 5752218822Sdim Elf64_External_Dyn *edyn, *ext; 5753130561Sobrien Elf_Internal_Dyn *entry; 575460484Sobrien 5755218822Sdim edyn = get_data (NULL, file, dynamic_addr, 1, dynamic_size, 5756218822Sdim _("dynamic section")); 575789857Sobrien if (!edyn) 575889857Sobrien return 0; 575960484Sobrien 5760218822Sdim/* SGI's ELF has more than one section in the DYNAMIC segment, and we 5761218822Sdim might not have the luxury of section headers. Look for the DT_NULL 5762218822Sdim terminator to determine the number of entries. */ 5763218822Sdim for (ext = edyn, dynamic_nent = 0; 5764218822Sdim (char *) ext < (char *) edyn + dynamic_size; 5765218822Sdim ext++) 5766218822Sdim { 5767218822Sdim dynamic_nent++; 5768218822Sdim if (BYTE_GET (ext->d_tag) == DT_NULL) 5769218822Sdim break; 5770218822Sdim } 577160484Sobrien 5772218822Sdim dynamic_section = cmalloc (dynamic_nent, sizeof (*entry)); 5773218822Sdim if (dynamic_section == NULL) 577460484Sobrien { 577560484Sobrien error (_("Out of memory\n")); 577660484Sobrien free (edyn); 577760484Sobrien return 0; 577860484Sobrien } 577960484Sobrien 5780218822Sdim for (ext = edyn, entry = dynamic_section; 5781218822Sdim entry < dynamic_section + dynamic_nent; 5782218822Sdim ext++, entry++) 578360484Sobrien { 5784218822Sdim entry->d_tag = BYTE_GET (ext->d_tag); 5785218822Sdim entry->d_un.d_val = BYTE_GET (ext->d_un.d_val); 578660484Sobrien } 578760484Sobrien 578860484Sobrien free (edyn); 578960484Sobrien 579060484Sobrien return 1; 579160484Sobrien} 579260484Sobrien 5793218822Sdimstatic void 5794218822Sdimprint_dynamic_flags (bfd_vma flags) 579560484Sobrien{ 5796218822Sdim int first = 1; 5797104834Sobrien 579860484Sobrien while (flags) 579960484Sobrien { 580060484Sobrien bfd_vma flag; 580160484Sobrien 580260484Sobrien flag = flags & - flags; 580360484Sobrien flags &= ~ flag; 580460484Sobrien 5805218822Sdim if (first) 5806218822Sdim first = 0; 5807218822Sdim else 5808218822Sdim putc (' ', stdout); 5809104834Sobrien 581060484Sobrien switch (flag) 581160484Sobrien { 5812218822Sdim case DF_ORIGIN: fputs ("ORIGIN", stdout); break; 5813218822Sdim case DF_SYMBOLIC: fputs ("SYMBOLIC", stdout); break; 5814218822Sdim case DF_TEXTREL: fputs ("TEXTREL", stdout); break; 5815218822Sdim case DF_BIND_NOW: fputs ("BIND_NOW", stdout); break; 5816218822Sdim case DF_STATIC_TLS: fputs ("STATIC_TLS", stdout); break; 5817218822Sdim default: fputs ("unknown", stdout); break; 581860484Sobrien } 581960484Sobrien } 5820218822Sdim puts (""); 582160484Sobrien} 582260484Sobrien 5823218822Sdim/* Parse and display the contents of the dynamic section. */ 5824218822Sdim 582560484Sobrienstatic int 5826218822Sdimprocess_dynamic_section (FILE *file) 582760484Sobrien{ 5828130561Sobrien Elf_Internal_Dyn *entry; 582960484Sobrien 583060484Sobrien if (dynamic_size == 0) 583160484Sobrien { 583260484Sobrien if (do_dynamic) 5833218822Sdim printf (_("\nThere is no dynamic section in this file.\n")); 583460484Sobrien 583560484Sobrien return 1; 583660484Sobrien } 583760484Sobrien 583860484Sobrien if (is_32bit_elf) 583960484Sobrien { 5840218822Sdim if (! get_32bit_dynamic_section (file)) 584160484Sobrien return 0; 584260484Sobrien } 5843218822Sdim else if (! get_64bit_dynamic_section (file)) 584460484Sobrien return 0; 584560484Sobrien 584660484Sobrien /* Find the appropriate symbol table. */ 584760484Sobrien if (dynamic_symbols == NULL) 584860484Sobrien { 5849218822Sdim for (entry = dynamic_section; 5850218822Sdim entry < dynamic_section + dynamic_nent; 5851218822Sdim ++entry) 585260484Sobrien { 5853130561Sobrien Elf_Internal_Shdr section; 585460484Sobrien 585560484Sobrien if (entry->d_tag != DT_SYMTAB) 585660484Sobrien continue; 585760484Sobrien 585860484Sobrien dynamic_info[DT_SYMTAB] = entry->d_un.d_val; 585960484Sobrien 586060484Sobrien /* Since we do not know how big the symbol table is, 586160484Sobrien we default to reading in the entire file (!) and 586260484Sobrien processing that. This is overkill, I know, but it 586389857Sobrien should work. */ 5864130561Sobrien section.sh_offset = offset_from_vma (file, entry->d_un.d_val, 0); 586560484Sobrien 5866130561Sobrien if (archive_file_offset != 0) 5867130561Sobrien section.sh_size = archive_file_size - section.sh_offset; 5868130561Sobrien else 5869130561Sobrien { 5870130561Sobrien if (fseek (file, 0, SEEK_END)) 5871218822Sdim error (_("Unable to seek to end of file!\n")); 587260484Sobrien 5873130561Sobrien section.sh_size = ftell (file) - section.sh_offset; 5874130561Sobrien } 5875130561Sobrien 587660484Sobrien if (is_32bit_elf) 587789857Sobrien section.sh_entsize = sizeof (Elf32_External_Sym); 587860484Sobrien else 587989857Sobrien section.sh_entsize = sizeof (Elf64_External_Sym); 588060484Sobrien 588189857Sobrien num_dynamic_syms = section.sh_size / section.sh_entsize; 588260484Sobrien if (num_dynamic_syms < 1) 588360484Sobrien { 588460484Sobrien error (_("Unable to determine the number of symbols to load\n")); 588560484Sobrien continue; 588660484Sobrien } 588760484Sobrien 588889857Sobrien dynamic_symbols = GET_ELF_SYMBOLS (file, §ion); 588960484Sobrien } 589060484Sobrien } 589160484Sobrien 589260484Sobrien /* Similarly find a string table. */ 589360484Sobrien if (dynamic_strings == NULL) 589460484Sobrien { 5895218822Sdim for (entry = dynamic_section; 5896218822Sdim entry < dynamic_section + dynamic_nent; 5897218822Sdim ++entry) 589860484Sobrien { 589960484Sobrien unsigned long offset; 5900130561Sobrien long str_tab_len; 590160484Sobrien 590260484Sobrien if (entry->d_tag != DT_STRTAB) 590360484Sobrien continue; 590460484Sobrien 590560484Sobrien dynamic_info[DT_STRTAB] = entry->d_un.d_val; 590660484Sobrien 590760484Sobrien /* Since we do not know how big the string table is, 590860484Sobrien we default to reading in the entire file (!) and 590960484Sobrien processing that. This is overkill, I know, but it 591089857Sobrien should work. */ 591160484Sobrien 5912130561Sobrien offset = offset_from_vma (file, entry->d_un.d_val, 0); 591360484Sobrien 5914130561Sobrien if (archive_file_offset != 0) 5915130561Sobrien str_tab_len = archive_file_size - offset; 5916130561Sobrien else 5917130561Sobrien { 5918130561Sobrien if (fseek (file, 0, SEEK_END)) 5919130561Sobrien error (_("Unable to seek to end of file\n")); 5920130561Sobrien str_tab_len = ftell (file) - offset; 5921130561Sobrien } 5922130561Sobrien 592360484Sobrien if (str_tab_len < 1) 592460484Sobrien { 592560484Sobrien error 592660484Sobrien (_("Unable to determine the length of the dynamic string table\n")); 592760484Sobrien continue; 592860484Sobrien } 592960484Sobrien 5930218822Sdim dynamic_strings = get_data (NULL, file, offset, 1, str_tab_len, 5931130561Sobrien _("dynamic string table")); 5932218822Sdim dynamic_strings_length = str_tab_len; 593360484Sobrien break; 593460484Sobrien } 593560484Sobrien } 593660484Sobrien 593760484Sobrien /* And find the syminfo section if available. */ 593860484Sobrien if (dynamic_syminfo == NULL) 593960484Sobrien { 5940130561Sobrien unsigned long syminsz = 0; 594160484Sobrien 5942218822Sdim for (entry = dynamic_section; 5943218822Sdim entry < dynamic_section + dynamic_nent; 5944218822Sdim ++entry) 594560484Sobrien { 594660484Sobrien if (entry->d_tag == DT_SYMINENT) 594760484Sobrien { 594860484Sobrien /* Note: these braces are necessary to avoid a syntax 594960484Sobrien error from the SunOS4 C compiler. */ 595060484Sobrien assert (sizeof (Elf_External_Syminfo) == entry->d_un.d_val); 595160484Sobrien } 595260484Sobrien else if (entry->d_tag == DT_SYMINSZ) 595360484Sobrien syminsz = entry->d_un.d_val; 595460484Sobrien else if (entry->d_tag == DT_SYMINFO) 5955130561Sobrien dynamic_syminfo_offset = offset_from_vma (file, entry->d_un.d_val, 5956130561Sobrien syminsz); 595760484Sobrien } 595860484Sobrien 595960484Sobrien if (dynamic_syminfo_offset != 0 && syminsz != 0) 596060484Sobrien { 5961218822Sdim Elf_External_Syminfo *extsyminfo, *extsym; 5962130561Sobrien Elf_Internal_Syminfo *syminfo; 596360484Sobrien 596460484Sobrien /* There is a syminfo section. Read the data. */ 5965218822Sdim extsyminfo = get_data (NULL, file, dynamic_syminfo_offset, 1, 5966218822Sdim syminsz, _("symbol information")); 596789857Sobrien if (!extsyminfo) 596889857Sobrien return 0; 596960484Sobrien 5970130561Sobrien dynamic_syminfo = malloc (syminsz); 597160484Sobrien if (dynamic_syminfo == NULL) 597260484Sobrien { 597360484Sobrien error (_("Out of memory\n")); 597460484Sobrien return 0; 597560484Sobrien } 597660484Sobrien 597760484Sobrien dynamic_syminfo_nent = syminsz / sizeof (Elf_External_Syminfo); 5978218822Sdim for (syminfo = dynamic_syminfo, extsym = extsyminfo; 5979218822Sdim syminfo < dynamic_syminfo + dynamic_syminfo_nent; 5980218822Sdim ++syminfo, ++extsym) 598160484Sobrien { 5982218822Sdim syminfo->si_boundto = BYTE_GET (extsym->si_boundto); 5983218822Sdim syminfo->si_flags = BYTE_GET (extsym->si_flags); 598460484Sobrien } 598560484Sobrien 598660484Sobrien free (extsyminfo); 598760484Sobrien } 598860484Sobrien } 598960484Sobrien 599060484Sobrien if (do_dynamic && dynamic_addr) 5991218822Sdim printf (_("\nDynamic section at offset 0x%lx contains %u entries:\n"), 5992218822Sdim dynamic_addr, dynamic_nent); 599360484Sobrien if (do_dynamic) 599460484Sobrien printf (_(" Tag Type Name/Value\n")); 599560484Sobrien 5996218822Sdim for (entry = dynamic_section; 5997218822Sdim entry < dynamic_section + dynamic_nent; 5998218822Sdim entry++) 599960484Sobrien { 600060484Sobrien if (do_dynamic) 600160484Sobrien { 6002130561Sobrien const char *dtype; 600360484Sobrien 600460484Sobrien putchar (' '); 600560484Sobrien print_vma (entry->d_tag, FULL_HEX); 600660484Sobrien dtype = get_dynamic_type (entry->d_tag); 600760484Sobrien printf (" (%s)%*s", dtype, 600860484Sobrien ((is_32bit_elf ? 27 : 19) 600960484Sobrien - (int) strlen (dtype)), 601060484Sobrien " "); 601160484Sobrien } 601260484Sobrien 601360484Sobrien switch (entry->d_tag) 601460484Sobrien { 601560484Sobrien case DT_FLAGS: 601660484Sobrien if (do_dynamic) 6017218822Sdim print_dynamic_flags (entry->d_un.d_val); 601860484Sobrien break; 601977298Sobrien 602060484Sobrien case DT_AUXILIARY: 602160484Sobrien case DT_FILTER: 602268765Sobrien case DT_CONFIG: 602368765Sobrien case DT_DEPAUDIT: 602468765Sobrien case DT_AUDIT: 602560484Sobrien if (do_dynamic) 602660484Sobrien { 602768765Sobrien switch (entry->d_tag) 6028130561Sobrien { 602968765Sobrien case DT_AUXILIARY: 603068765Sobrien printf (_("Auxiliary library")); 603168765Sobrien break; 603260484Sobrien 603368765Sobrien case DT_FILTER: 603468765Sobrien printf (_("Filter library")); 603568765Sobrien break; 603668765Sobrien 6037130561Sobrien case DT_CONFIG: 603868765Sobrien printf (_("Configuration file")); 603968765Sobrien break; 604068765Sobrien 604168765Sobrien case DT_DEPAUDIT: 604268765Sobrien printf (_("Dependency audit library")); 604368765Sobrien break; 604468765Sobrien 604568765Sobrien case DT_AUDIT: 604668765Sobrien printf (_("Audit library")); 604768765Sobrien break; 604868765Sobrien } 604968765Sobrien 6050218822Sdim if (VALID_DYNAMIC_NAME (entry->d_un.d_val)) 6051218822Sdim printf (": [%s]\n", GET_DYNAMIC_NAME (entry->d_un.d_val)); 605260484Sobrien else 605360484Sobrien { 605460484Sobrien printf (": "); 605560484Sobrien print_vma (entry->d_un.d_val, PREFIX_HEX); 605660484Sobrien putchar ('\n'); 605760484Sobrien } 605860484Sobrien } 605960484Sobrien break; 606060484Sobrien 606168765Sobrien case DT_FEATURE: 606260484Sobrien if (do_dynamic) 606360484Sobrien { 606460484Sobrien printf (_("Flags:")); 6065130561Sobrien 606660484Sobrien if (entry->d_un.d_val == 0) 606760484Sobrien printf (_(" None\n")); 606860484Sobrien else 606960484Sobrien { 607060484Sobrien unsigned long int val = entry->d_un.d_val; 6071130561Sobrien 607260484Sobrien if (val & DTF_1_PARINIT) 607360484Sobrien { 607460484Sobrien printf (" PARINIT"); 607560484Sobrien val ^= DTF_1_PARINIT; 607660484Sobrien } 607768765Sobrien if (val & DTF_1_CONFEXP) 607868765Sobrien { 607968765Sobrien printf (" CONFEXP"); 608068765Sobrien val ^= DTF_1_CONFEXP; 608168765Sobrien } 608260484Sobrien if (val != 0) 608360484Sobrien printf (" %lx", val); 608460484Sobrien puts (""); 608560484Sobrien } 608660484Sobrien } 608760484Sobrien break; 608860484Sobrien 608960484Sobrien case DT_POSFLAG_1: 609060484Sobrien if (do_dynamic) 609160484Sobrien { 609260484Sobrien printf (_("Flags:")); 6093130561Sobrien 609460484Sobrien if (entry->d_un.d_val == 0) 609560484Sobrien printf (_(" None\n")); 609660484Sobrien else 609760484Sobrien { 609860484Sobrien unsigned long int val = entry->d_un.d_val; 6099130561Sobrien 610060484Sobrien if (val & DF_P1_LAZYLOAD) 610160484Sobrien { 610260484Sobrien printf (" LAZYLOAD"); 610360484Sobrien val ^= DF_P1_LAZYLOAD; 610460484Sobrien } 610560484Sobrien if (val & DF_P1_GROUPPERM) 610660484Sobrien { 610760484Sobrien printf (" GROUPPERM"); 610860484Sobrien val ^= DF_P1_GROUPPERM; 610960484Sobrien } 611060484Sobrien if (val != 0) 611160484Sobrien printf (" %lx", val); 611260484Sobrien puts (""); 611360484Sobrien } 611460484Sobrien } 611560484Sobrien break; 611660484Sobrien 611760484Sobrien case DT_FLAGS_1: 611860484Sobrien if (do_dynamic) 611960484Sobrien { 612060484Sobrien printf (_("Flags:")); 612160484Sobrien if (entry->d_un.d_val == 0) 612260484Sobrien printf (_(" None\n")); 612360484Sobrien else 612460484Sobrien { 612560484Sobrien unsigned long int val = entry->d_un.d_val; 6126130561Sobrien 612760484Sobrien if (val & DF_1_NOW) 612860484Sobrien { 612960484Sobrien printf (" NOW"); 613060484Sobrien val ^= DF_1_NOW; 613160484Sobrien } 613260484Sobrien if (val & DF_1_GLOBAL) 613360484Sobrien { 613460484Sobrien printf (" GLOBAL"); 613560484Sobrien val ^= DF_1_GLOBAL; 613660484Sobrien } 613760484Sobrien if (val & DF_1_GROUP) 613860484Sobrien { 613960484Sobrien printf (" GROUP"); 614060484Sobrien val ^= DF_1_GROUP; 614160484Sobrien } 614260484Sobrien if (val & DF_1_NODELETE) 614360484Sobrien { 614460484Sobrien printf (" NODELETE"); 614560484Sobrien val ^= DF_1_NODELETE; 614660484Sobrien } 614760484Sobrien if (val & DF_1_LOADFLTR) 614860484Sobrien { 614960484Sobrien printf (" LOADFLTR"); 615060484Sobrien val ^= DF_1_LOADFLTR; 615160484Sobrien } 615260484Sobrien if (val & DF_1_INITFIRST) 615360484Sobrien { 615460484Sobrien printf (" INITFIRST"); 615560484Sobrien val ^= DF_1_INITFIRST; 615660484Sobrien } 615760484Sobrien if (val & DF_1_NOOPEN) 615860484Sobrien { 615960484Sobrien printf (" NOOPEN"); 616060484Sobrien val ^= DF_1_NOOPEN; 616160484Sobrien } 616260484Sobrien if (val & DF_1_ORIGIN) 616360484Sobrien { 616460484Sobrien printf (" ORIGIN"); 616560484Sobrien val ^= DF_1_ORIGIN; 616660484Sobrien } 616760484Sobrien if (val & DF_1_DIRECT) 616860484Sobrien { 616960484Sobrien printf (" DIRECT"); 617060484Sobrien val ^= DF_1_DIRECT; 617160484Sobrien } 617260484Sobrien if (val & DF_1_TRANS) 617360484Sobrien { 617460484Sobrien printf (" TRANS"); 617560484Sobrien val ^= DF_1_TRANS; 617660484Sobrien } 617760484Sobrien if (val & DF_1_INTERPOSE) 617860484Sobrien { 617960484Sobrien printf (" INTERPOSE"); 618060484Sobrien val ^= DF_1_INTERPOSE; 618160484Sobrien } 618268765Sobrien if (val & DF_1_NODEFLIB) 618368765Sobrien { 618468765Sobrien printf (" NODEFLIB"); 618568765Sobrien val ^= DF_1_NODEFLIB; 618668765Sobrien } 618768765Sobrien if (val & DF_1_NODUMP) 618868765Sobrien { 618968765Sobrien printf (" NODUMP"); 619068765Sobrien val ^= DF_1_NODUMP; 619168765Sobrien } 619268765Sobrien if (val & DF_1_CONLFAT) 619368765Sobrien { 619468765Sobrien printf (" CONLFAT"); 619568765Sobrien val ^= DF_1_CONLFAT; 619668765Sobrien } 619760484Sobrien if (val != 0) 619860484Sobrien printf (" %lx", val); 619960484Sobrien puts (""); 620060484Sobrien } 620160484Sobrien } 620260484Sobrien break; 620360484Sobrien 620460484Sobrien case DT_PLTREL: 6205130561Sobrien dynamic_info[entry->d_tag] = entry->d_un.d_val; 620660484Sobrien if (do_dynamic) 620760484Sobrien puts (get_dynamic_type (entry->d_un.d_val)); 620860484Sobrien break; 620960484Sobrien 621060484Sobrien case DT_NULL : 621160484Sobrien case DT_NEEDED : 621260484Sobrien case DT_PLTGOT : 621360484Sobrien case DT_HASH : 621460484Sobrien case DT_STRTAB : 621560484Sobrien case DT_SYMTAB : 621660484Sobrien case DT_RELA : 621760484Sobrien case DT_INIT : 621860484Sobrien case DT_FINI : 621960484Sobrien case DT_SONAME : 622060484Sobrien case DT_RPATH : 622160484Sobrien case DT_SYMBOLIC: 622260484Sobrien case DT_REL : 622360484Sobrien case DT_DEBUG : 622460484Sobrien case DT_TEXTREL : 622560484Sobrien case DT_JMPREL : 622668765Sobrien case DT_RUNPATH : 622760484Sobrien dynamic_info[entry->d_tag] = entry->d_un.d_val; 622860484Sobrien 622960484Sobrien if (do_dynamic) 623060484Sobrien { 6231130561Sobrien char *name; 623260484Sobrien 6233218822Sdim if (VALID_DYNAMIC_NAME (entry->d_un.d_val)) 6234218822Sdim name = GET_DYNAMIC_NAME (entry->d_un.d_val); 6235218822Sdim else 623660484Sobrien name = NULL; 623760484Sobrien 623860484Sobrien if (name) 623960484Sobrien { 624060484Sobrien switch (entry->d_tag) 624160484Sobrien { 624260484Sobrien case DT_NEEDED: 624360484Sobrien printf (_("Shared library: [%s]"), name); 624460484Sobrien 6245218822Sdim if (streq (name, program_interpreter)) 624660484Sobrien printf (_(" program interpreter")); 624760484Sobrien break; 624860484Sobrien 624960484Sobrien case DT_SONAME: 625060484Sobrien printf (_("Library soname: [%s]"), name); 625160484Sobrien break; 625260484Sobrien 625360484Sobrien case DT_RPATH: 625460484Sobrien printf (_("Library rpath: [%s]"), name); 625560484Sobrien break; 625660484Sobrien 625768765Sobrien case DT_RUNPATH: 625868765Sobrien printf (_("Library runpath: [%s]"), name); 625968765Sobrien break; 626068765Sobrien 626160484Sobrien default: 626260484Sobrien print_vma (entry->d_un.d_val, PREFIX_HEX); 626360484Sobrien break; 626460484Sobrien } 626560484Sobrien } 626660484Sobrien else 626760484Sobrien print_vma (entry->d_un.d_val, PREFIX_HEX); 626860484Sobrien 626960484Sobrien putchar ('\n'); 627060484Sobrien } 627160484Sobrien break; 627260484Sobrien 627360484Sobrien case DT_PLTRELSZ: 627460484Sobrien case DT_RELASZ : 627560484Sobrien case DT_STRSZ : 627660484Sobrien case DT_RELSZ : 627760484Sobrien case DT_RELAENT : 627860484Sobrien case DT_SYMENT : 627960484Sobrien case DT_RELENT : 6280130561Sobrien dynamic_info[entry->d_tag] = entry->d_un.d_val; 628160484Sobrien case DT_PLTPADSZ: 628260484Sobrien case DT_MOVEENT : 628360484Sobrien case DT_MOVESZ : 628460484Sobrien case DT_INIT_ARRAYSZ: 628560484Sobrien case DT_FINI_ARRAYSZ: 6286104834Sobrien case DT_GNU_CONFLICTSZ: 6287104834Sobrien case DT_GNU_LIBLISTSZ: 628860484Sobrien if (do_dynamic) 628960484Sobrien { 629060484Sobrien print_vma (entry->d_un.d_val, UNSIGNED); 629160484Sobrien printf (" (bytes)\n"); 629260484Sobrien } 629360484Sobrien break; 629460484Sobrien 629560484Sobrien case DT_VERDEFNUM: 629660484Sobrien case DT_VERNEEDNUM: 629760484Sobrien case DT_RELACOUNT: 629860484Sobrien case DT_RELCOUNT: 629960484Sobrien if (do_dynamic) 630060484Sobrien { 630160484Sobrien print_vma (entry->d_un.d_val, UNSIGNED); 630260484Sobrien putchar ('\n'); 630360484Sobrien } 630460484Sobrien break; 630560484Sobrien 630660484Sobrien case DT_SYMINSZ: 630760484Sobrien case DT_SYMINENT: 630860484Sobrien case DT_SYMINFO: 630960484Sobrien case DT_USED: 631060484Sobrien case DT_INIT_ARRAY: 631160484Sobrien case DT_FINI_ARRAY: 631260484Sobrien if (do_dynamic) 631360484Sobrien { 6314218822Sdim if (entry->d_tag == DT_USED 6315218822Sdim && VALID_DYNAMIC_NAME (entry->d_un.d_val)) 631660484Sobrien { 6317218822Sdim char *name = GET_DYNAMIC_NAME (entry->d_un.d_val); 631860484Sobrien 6319130561Sobrien if (*name) 632060484Sobrien { 632160484Sobrien printf (_("Not needed object: [%s]\n"), name); 632260484Sobrien break; 632360484Sobrien } 632460484Sobrien } 632560484Sobrien 632660484Sobrien print_vma (entry->d_un.d_val, PREFIX_HEX); 632760484Sobrien putchar ('\n'); 632860484Sobrien } 632960484Sobrien break; 633060484Sobrien 633160484Sobrien case DT_BIND_NOW: 633260484Sobrien /* The value of this entry is ignored. */ 6333130561Sobrien if (do_dynamic) 6334130561Sobrien putchar ('\n'); 633560484Sobrien break; 633660484Sobrien 6337104834Sobrien case DT_GNU_PRELINKED: 6338104834Sobrien if (do_dynamic) 6339104834Sobrien { 6340130561Sobrien struct tm *tmp; 6341104834Sobrien time_t time = entry->d_un.d_val; 6342104834Sobrien 6343104834Sobrien tmp = gmtime (&time); 6344104834Sobrien printf ("%04u-%02u-%02uT%02u:%02u:%02u\n", 6345104834Sobrien tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, 6346104834Sobrien tmp->tm_hour, tmp->tm_min, tmp->tm_sec); 6347104834Sobrien 6348104834Sobrien } 6349104834Sobrien break; 6350104834Sobrien 6351218822Sdim case DT_GNU_HASH: 6352218822Sdim dynamic_info_DT_GNU_HASH = entry->d_un.d_val; 6353218822Sdim if (do_dynamic) 6354218822Sdim { 6355218822Sdim print_vma (entry->d_un.d_val, PREFIX_HEX); 6356218822Sdim putchar ('\n'); 6357218822Sdim } 6358218822Sdim break; 6359218822Sdim 636060484Sobrien default: 636160484Sobrien if ((entry->d_tag >= DT_VERSYM) && (entry->d_tag <= DT_VERNEEDNUM)) 6362130561Sobrien version_info[DT_VERSIONTAGIDX (entry->d_tag)] = 636360484Sobrien entry->d_un.d_val; 636460484Sobrien 636560484Sobrien if (do_dynamic) 636660484Sobrien { 636760484Sobrien switch (elf_header.e_machine) 636860484Sobrien { 636960484Sobrien case EM_MIPS: 637078828Sobrien case EM_MIPS_RS3_LE: 6371218822Sdim dynamic_section_mips_val (entry); 637260484Sobrien break; 637360484Sobrien case EM_PARISC: 6374218822Sdim dynamic_section_parisc_val (entry); 637560484Sobrien break; 6376130561Sobrien case EM_IA_64: 6377218822Sdim dynamic_section_ia64_val (entry); 6378130561Sobrien break; 637960484Sobrien default: 638060484Sobrien print_vma (entry->d_un.d_val, PREFIX_HEX); 638160484Sobrien putchar ('\n'); 638260484Sobrien } 638360484Sobrien } 638460484Sobrien break; 638560484Sobrien } 638660484Sobrien } 638760484Sobrien 638860484Sobrien return 1; 638960484Sobrien} 639060484Sobrien 639160484Sobrienstatic char * 6392130561Sobrienget_ver_flags (unsigned int flags) 639360484Sobrien{ 6394130561Sobrien static char buff[32]; 639560484Sobrien 639660484Sobrien buff[0] = 0; 639760484Sobrien 639860484Sobrien if (flags == 0) 639960484Sobrien return _("none"); 640060484Sobrien 640160484Sobrien if (flags & VER_FLG_BASE) 640260484Sobrien strcat (buff, "BASE "); 640360484Sobrien 640460484Sobrien if (flags & VER_FLG_WEAK) 640560484Sobrien { 640660484Sobrien if (flags & VER_FLG_BASE) 640760484Sobrien strcat (buff, "| "); 640860484Sobrien 640960484Sobrien strcat (buff, "WEAK "); 641060484Sobrien } 641160484Sobrien 641260484Sobrien if (flags & ~(VER_FLG_BASE | VER_FLG_WEAK)) 641360484Sobrien strcat (buff, "| <unknown>"); 641460484Sobrien 641560484Sobrien return buff; 641660484Sobrien} 641760484Sobrien 641860484Sobrien/* Display the contents of the version sections. */ 641960484Sobrienstatic int 6420130561Sobrienprocess_version_sections (FILE *file) 642160484Sobrien{ 6422130561Sobrien Elf_Internal_Shdr *section; 6423130561Sobrien unsigned i; 6424130561Sobrien int found = 0; 642560484Sobrien 642660484Sobrien if (! do_version) 642760484Sobrien return 1; 642860484Sobrien 642960484Sobrien for (i = 0, section = section_headers; 643060484Sobrien i < elf_header.e_shnum; 6431130561Sobrien i++, section++) 643260484Sobrien { 643360484Sobrien switch (section->sh_type) 643460484Sobrien { 643560484Sobrien case SHT_GNU_verdef: 643660484Sobrien { 6437130561Sobrien Elf_External_Verdef *edefs; 6438130561Sobrien unsigned int idx; 6439130561Sobrien unsigned int cnt; 644060484Sobrien 644160484Sobrien found = 1; 644260484Sobrien 644360484Sobrien printf 644460484Sobrien (_("\nVersion definition section '%s' contains %ld entries:\n"), 644560484Sobrien SECTION_NAME (section), section->sh_info); 644660484Sobrien 644760484Sobrien printf (_(" Addr: 0x")); 644860484Sobrien printf_vma (section->sh_addr); 644960484Sobrien printf (_(" Offset: %#08lx Link: %lx (%s)\n"), 645060484Sobrien (unsigned long) section->sh_offset, section->sh_link, 6451218822Sdim SECTION_HEADER_INDEX (section->sh_link) 6452218822Sdim < elf_header.e_shnum 6453218822Sdim ? SECTION_NAME (SECTION_HEADER (section->sh_link)) 6454218822Sdim : "<corrupt>"); 645560484Sobrien 6456218822Sdim edefs = get_data (NULL, file, section->sh_offset, 1, 6457218822Sdim section->sh_size, 6458130561Sobrien _("version definition section")); 645989857Sobrien if (!edefs) 646089857Sobrien break; 646160484Sobrien 6462130561Sobrien for (idx = cnt = 0; cnt < section->sh_info; ++cnt) 646360484Sobrien { 6464130561Sobrien char *vstart; 6465130561Sobrien Elf_External_Verdef *edef; 6466130561Sobrien Elf_Internal_Verdef ent; 6467130561Sobrien Elf_External_Verdaux *eaux; 6468130561Sobrien Elf_Internal_Verdaux aux; 6469130561Sobrien int j; 6470130561Sobrien int isum; 647160484Sobrien 647260484Sobrien vstart = ((char *) edefs) + idx; 647360484Sobrien 647460484Sobrien edef = (Elf_External_Verdef *) vstart; 647560484Sobrien 647660484Sobrien ent.vd_version = BYTE_GET (edef->vd_version); 647760484Sobrien ent.vd_flags = BYTE_GET (edef->vd_flags); 647860484Sobrien ent.vd_ndx = BYTE_GET (edef->vd_ndx); 647960484Sobrien ent.vd_cnt = BYTE_GET (edef->vd_cnt); 648060484Sobrien ent.vd_hash = BYTE_GET (edef->vd_hash); 648160484Sobrien ent.vd_aux = BYTE_GET (edef->vd_aux); 648260484Sobrien ent.vd_next = BYTE_GET (edef->vd_next); 648360484Sobrien 648460484Sobrien printf (_(" %#06x: Rev: %d Flags: %s"), 648560484Sobrien idx, ent.vd_version, get_ver_flags (ent.vd_flags)); 648660484Sobrien 648760484Sobrien printf (_(" Index: %d Cnt: %d "), 648860484Sobrien ent.vd_ndx, ent.vd_cnt); 648960484Sobrien 649060484Sobrien vstart += ent.vd_aux; 649160484Sobrien 649260484Sobrien eaux = (Elf_External_Verdaux *) vstart; 649360484Sobrien 649460484Sobrien aux.vda_name = BYTE_GET (eaux->vda_name); 649560484Sobrien aux.vda_next = BYTE_GET (eaux->vda_next); 649660484Sobrien 6497218822Sdim if (VALID_DYNAMIC_NAME (aux.vda_name)) 6498218822Sdim printf (_("Name: %s\n"), GET_DYNAMIC_NAME (aux.vda_name)); 649960484Sobrien else 650060484Sobrien printf (_("Name index: %ld\n"), aux.vda_name); 650160484Sobrien 650260484Sobrien isum = idx + ent.vd_aux; 650360484Sobrien 6504130561Sobrien for (j = 1; j < ent.vd_cnt; j++) 650560484Sobrien { 650660484Sobrien isum += aux.vda_next; 650760484Sobrien vstart += aux.vda_next; 650860484Sobrien 650960484Sobrien eaux = (Elf_External_Verdaux *) vstart; 651060484Sobrien 651160484Sobrien aux.vda_name = BYTE_GET (eaux->vda_name); 651260484Sobrien aux.vda_next = BYTE_GET (eaux->vda_next); 651360484Sobrien 6514218822Sdim if (VALID_DYNAMIC_NAME (aux.vda_name)) 651560484Sobrien printf (_(" %#06x: Parent %d: %s\n"), 6516218822Sdim isum, j, GET_DYNAMIC_NAME (aux.vda_name)); 651760484Sobrien else 651860484Sobrien printf (_(" %#06x: Parent %d, name index: %ld\n"), 651960484Sobrien isum, j, aux.vda_name); 652060484Sobrien } 652160484Sobrien 652260484Sobrien idx += ent.vd_next; 652360484Sobrien } 652460484Sobrien 652560484Sobrien free (edefs); 652660484Sobrien } 652760484Sobrien break; 652860484Sobrien 652960484Sobrien case SHT_GNU_verneed: 653060484Sobrien { 6531130561Sobrien Elf_External_Verneed *eneed; 6532130561Sobrien unsigned int idx; 6533130561Sobrien unsigned int cnt; 653460484Sobrien 653560484Sobrien found = 1; 653660484Sobrien 653760484Sobrien printf (_("\nVersion needs section '%s' contains %ld entries:\n"), 653860484Sobrien SECTION_NAME (section), section->sh_info); 653960484Sobrien 654060484Sobrien printf (_(" Addr: 0x")); 654160484Sobrien printf_vma (section->sh_addr); 654260484Sobrien printf (_(" Offset: %#08lx Link to section: %ld (%s)\n"), 654360484Sobrien (unsigned long) section->sh_offset, section->sh_link, 6544218822Sdim SECTION_HEADER_INDEX (section->sh_link) 6545218822Sdim < elf_header.e_shnum 6546218822Sdim ? SECTION_NAME (SECTION_HEADER (section->sh_link)) 6547218822Sdim : "<corrupt>"); 654860484Sobrien 6549218822Sdim eneed = get_data (NULL, file, section->sh_offset, 1, 6550218822Sdim section->sh_size, 6551130561Sobrien _("version need section")); 655289857Sobrien if (!eneed) 655389857Sobrien break; 655460484Sobrien 655560484Sobrien for (idx = cnt = 0; cnt < section->sh_info; ++cnt) 655660484Sobrien { 6557130561Sobrien Elf_External_Verneed *entry; 6558130561Sobrien Elf_Internal_Verneed ent; 6559130561Sobrien int j; 6560130561Sobrien int isum; 6561130561Sobrien char *vstart; 656260484Sobrien 656360484Sobrien vstart = ((char *) eneed) + idx; 656460484Sobrien 656560484Sobrien entry = (Elf_External_Verneed *) vstart; 656660484Sobrien 656760484Sobrien ent.vn_version = BYTE_GET (entry->vn_version); 656860484Sobrien ent.vn_cnt = BYTE_GET (entry->vn_cnt); 656960484Sobrien ent.vn_file = BYTE_GET (entry->vn_file); 657060484Sobrien ent.vn_aux = BYTE_GET (entry->vn_aux); 657160484Sobrien ent.vn_next = BYTE_GET (entry->vn_next); 657260484Sobrien 657360484Sobrien printf (_(" %#06x: Version: %d"), idx, ent.vn_version); 657460484Sobrien 6575218822Sdim if (VALID_DYNAMIC_NAME (ent.vn_file)) 6576218822Sdim printf (_(" File: %s"), GET_DYNAMIC_NAME (ent.vn_file)); 657760484Sobrien else 657860484Sobrien printf (_(" File: %lx"), ent.vn_file); 657960484Sobrien 658060484Sobrien printf (_(" Cnt: %d\n"), ent.vn_cnt); 658160484Sobrien 658260484Sobrien vstart += ent.vn_aux; 658360484Sobrien 658460484Sobrien for (j = 0, isum = idx + ent.vn_aux; j < ent.vn_cnt; ++j) 658560484Sobrien { 6586130561Sobrien Elf_External_Vernaux *eaux; 6587130561Sobrien Elf_Internal_Vernaux aux; 658860484Sobrien 658960484Sobrien eaux = (Elf_External_Vernaux *) vstart; 659060484Sobrien 659160484Sobrien aux.vna_hash = BYTE_GET (eaux->vna_hash); 659260484Sobrien aux.vna_flags = BYTE_GET (eaux->vna_flags); 659360484Sobrien aux.vna_other = BYTE_GET (eaux->vna_other); 659460484Sobrien aux.vna_name = BYTE_GET (eaux->vna_name); 659560484Sobrien aux.vna_next = BYTE_GET (eaux->vna_next); 659660484Sobrien 6597218822Sdim if (VALID_DYNAMIC_NAME (aux.vna_name)) 6598130561Sobrien printf (_(" %#06x: Name: %s"), 6599218822Sdim isum, GET_DYNAMIC_NAME (aux.vna_name)); 660060484Sobrien else 6601130561Sobrien printf (_(" %#06x: Name index: %lx"), 660260484Sobrien isum, aux.vna_name); 660360484Sobrien 660460484Sobrien printf (_(" Flags: %s Version: %d\n"), 660560484Sobrien get_ver_flags (aux.vna_flags), aux.vna_other); 660660484Sobrien 660760484Sobrien isum += aux.vna_next; 660860484Sobrien vstart += aux.vna_next; 660960484Sobrien } 661060484Sobrien 661160484Sobrien idx += ent.vn_next; 661260484Sobrien } 661360484Sobrien 661460484Sobrien free (eneed); 661560484Sobrien } 661660484Sobrien break; 661760484Sobrien 661860484Sobrien case SHT_GNU_versym: 661960484Sobrien { 6620130561Sobrien Elf_Internal_Shdr *link_section; 6621130561Sobrien int total; 6622130561Sobrien int cnt; 6623130561Sobrien unsigned char *edata; 6624130561Sobrien unsigned short *data; 6625130561Sobrien char *strtab; 6626130561Sobrien Elf_Internal_Sym *symbols; 6627130561Sobrien Elf_Internal_Shdr *string_sec; 6628130561Sobrien long off; 662960484Sobrien 6630218822Sdim if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum) 6631218822Sdim break; 6632218822Sdim 663389857Sobrien link_section = SECTION_HEADER (section->sh_link); 6634218822Sdim total = section->sh_size / sizeof (Elf_External_Versym); 663560484Sobrien 6636218822Sdim if (SECTION_HEADER_INDEX (link_section->sh_link) 6637218822Sdim >= elf_header.e_shnum) 6638218822Sdim break; 6639218822Sdim 664060484Sobrien found = 1; 664160484Sobrien 664289857Sobrien symbols = GET_ELF_SYMBOLS (file, link_section); 664360484Sobrien 664489857Sobrien string_sec = SECTION_HEADER (link_section->sh_link); 664560484Sobrien 6646218822Sdim strtab = get_data (NULL, file, string_sec->sh_offset, 1, 6647130561Sobrien string_sec->sh_size, _("version string table")); 664889857Sobrien if (!strtab) 664989857Sobrien break; 665060484Sobrien 665160484Sobrien printf (_("\nVersion symbols section '%s' contains %d entries:\n"), 665260484Sobrien SECTION_NAME (section), total); 665360484Sobrien 665460484Sobrien printf (_(" Addr: ")); 665560484Sobrien printf_vma (section->sh_addr); 665660484Sobrien printf (_(" Offset: %#08lx Link: %lx (%s)\n"), 665760484Sobrien (unsigned long) section->sh_offset, section->sh_link, 665860484Sobrien SECTION_NAME (link_section)); 665960484Sobrien 6660130561Sobrien off = offset_from_vma (file, 6661130561Sobrien version_info[DT_VERSIONTAGIDX (DT_VERSYM)], 6662130561Sobrien total * sizeof (short)); 6663218822Sdim edata = get_data (NULL, file, off, total, sizeof (short), 6664130561Sobrien _("version symbol data")); 666589857Sobrien if (!edata) 666689857Sobrien { 666789857Sobrien free (strtab); 666889857Sobrien break; 666989857Sobrien } 667060484Sobrien 6671218822Sdim data = cmalloc (total, sizeof (short)); 667260484Sobrien 667360484Sobrien for (cnt = total; cnt --;) 6674130561Sobrien data[cnt] = byte_get (edata + cnt * sizeof (short), 6675130561Sobrien sizeof (short)); 667660484Sobrien 667760484Sobrien free (edata); 667860484Sobrien 667960484Sobrien for (cnt = 0; cnt < total; cnt += 4) 668060484Sobrien { 668160484Sobrien int j, nn; 668277298Sobrien int check_def, check_need; 6683130561Sobrien char *name; 668460484Sobrien 668560484Sobrien printf (" %03x:", cnt); 668660484Sobrien 668760484Sobrien for (j = 0; (j < 4) && (cnt + j) < total; ++j) 6688130561Sobrien switch (data[cnt + j]) 668960484Sobrien { 669060484Sobrien case 0: 669160484Sobrien fputs (_(" 0 (*local*) "), stdout); 669260484Sobrien break; 669360484Sobrien 669460484Sobrien case 1: 669560484Sobrien fputs (_(" 1 (*global*) "), stdout); 669660484Sobrien break; 669760484Sobrien 669860484Sobrien default: 6699130561Sobrien nn = printf ("%4x%c", data[cnt + j] & 0x7fff, 6700130561Sobrien data[cnt + j] & 0x8000 ? 'h' : ' '); 670160484Sobrien 670277298Sobrien check_def = 1; 670377298Sobrien check_need = 1; 6704218822Sdim if (SECTION_HEADER_INDEX (symbols[cnt + j].st_shndx) 6705218822Sdim >= elf_header.e_shnum 6706218822Sdim || SECTION_HEADER (symbols[cnt + j].st_shndx)->sh_type 6707218822Sdim != SHT_NOBITS) 670860484Sobrien { 6709130561Sobrien if (symbols[cnt + j].st_shndx == SHN_UNDEF) 671077298Sobrien check_def = 0; 671177298Sobrien else 671277298Sobrien check_need = 0; 671377298Sobrien } 671460484Sobrien 671577298Sobrien if (check_need 6716130561Sobrien && version_info[DT_VERSIONTAGIDX (DT_VERNEED)]) 671760484Sobrien { 6718130561Sobrien Elf_Internal_Verneed ivn; 6719130561Sobrien unsigned long offset; 672060484Sobrien 6721130561Sobrien offset = offset_from_vma 6722130561Sobrien (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)], 6723130561Sobrien sizeof (Elf_External_Verneed)); 672460484Sobrien 6725130561Sobrien do 672660484Sobrien { 6727130561Sobrien Elf_Internal_Vernaux ivna; 6728130561Sobrien Elf_External_Verneed evn; 6729130561Sobrien Elf_External_Vernaux evna; 6730130561Sobrien unsigned long a_off; 673160484Sobrien 6732218822Sdim get_data (&evn, file, offset, sizeof (evn), 1, 673389857Sobrien _("version need")); 673460484Sobrien 673560484Sobrien ivn.vn_aux = BYTE_GET (evn.vn_aux); 673660484Sobrien ivn.vn_next = BYTE_GET (evn.vn_next); 673760484Sobrien 673860484Sobrien a_off = offset + ivn.vn_aux; 673960484Sobrien 674060484Sobrien do 674160484Sobrien { 674289857Sobrien get_data (&evna, file, a_off, sizeof (evna), 6743218822Sdim 1, _("version need aux (2)")); 674460484Sobrien 674560484Sobrien ivna.vna_next = BYTE_GET (evna.vna_next); 674660484Sobrien ivna.vna_other = BYTE_GET (evna.vna_other); 674760484Sobrien 674860484Sobrien a_off += ivna.vna_next; 674960484Sobrien } 6750130561Sobrien while (ivna.vna_other != data[cnt + j] 675160484Sobrien && ivna.vna_next != 0); 675260484Sobrien 6753130561Sobrien if (ivna.vna_other == data[cnt + j]) 675460484Sobrien { 675560484Sobrien ivna.vna_name = BYTE_GET (evna.vna_name); 675660484Sobrien 675760484Sobrien name = strtab + ivna.vna_name; 675860484Sobrien nn += printf ("(%s%-*s", 675960484Sobrien name, 676060484Sobrien 12 - (int) strlen (name), 676160484Sobrien ")"); 676277298Sobrien check_def = 0; 676360484Sobrien break; 676460484Sobrien } 676560484Sobrien 676660484Sobrien offset += ivn.vn_next; 676760484Sobrien } 676860484Sobrien while (ivn.vn_next); 676960484Sobrien } 677077298Sobrien 6771130561Sobrien if (check_def && data[cnt + j] != 0x8001 6772130561Sobrien && version_info[DT_VERSIONTAGIDX (DT_VERDEF)]) 677360484Sobrien { 6774130561Sobrien Elf_Internal_Verdef ivd; 6775130561Sobrien Elf_External_Verdef evd; 6776130561Sobrien unsigned long offset; 677760484Sobrien 6778130561Sobrien offset = offset_from_vma 6779130561Sobrien (file, version_info[DT_VERSIONTAGIDX (DT_VERDEF)], 6780130561Sobrien sizeof evd); 678160484Sobrien 678260484Sobrien do 678360484Sobrien { 6784218822Sdim get_data (&evd, file, offset, sizeof (evd), 1, 678589857Sobrien _("version def")); 678660484Sobrien 678760484Sobrien ivd.vd_next = BYTE_GET (evd.vd_next); 678860484Sobrien ivd.vd_ndx = BYTE_GET (evd.vd_ndx); 678960484Sobrien 679060484Sobrien offset += ivd.vd_next; 679160484Sobrien } 6792130561Sobrien while (ivd.vd_ndx != (data[cnt + j] & 0x7fff) 679360484Sobrien && ivd.vd_next != 0); 679460484Sobrien 6795130561Sobrien if (ivd.vd_ndx == (data[cnt + j] & 0x7fff)) 679660484Sobrien { 6797130561Sobrien Elf_External_Verdaux evda; 6798130561Sobrien Elf_Internal_Verdaux ivda; 679960484Sobrien 680060484Sobrien ivd.vd_aux = BYTE_GET (evd.vd_aux); 680160484Sobrien 680289857Sobrien get_data (&evda, file, 680389857Sobrien offset - ivd.vd_next + ivd.vd_aux, 6804218822Sdim sizeof (evda), 1, 6805218822Sdim _("version def aux")); 680660484Sobrien 680760484Sobrien ivda.vda_name = BYTE_GET (evda.vda_name); 680860484Sobrien 680960484Sobrien name = strtab + ivda.vda_name; 681060484Sobrien nn += printf ("(%s%-*s", 681160484Sobrien name, 681260484Sobrien 12 - (int) strlen (name), 681360484Sobrien ")"); 681460484Sobrien } 681560484Sobrien } 681660484Sobrien 681760484Sobrien if (nn < 18) 681860484Sobrien printf ("%*c", 18 - nn, ' '); 681960484Sobrien } 682060484Sobrien 682160484Sobrien putchar ('\n'); 682260484Sobrien } 682360484Sobrien 682460484Sobrien free (data); 682560484Sobrien free (strtab); 682660484Sobrien free (symbols); 682760484Sobrien } 682860484Sobrien break; 682960484Sobrien 683060484Sobrien default: 683160484Sobrien break; 683260484Sobrien } 683360484Sobrien } 683460484Sobrien 683560484Sobrien if (! found) 683660484Sobrien printf (_("\nNo version information found in this file.\n")); 683760484Sobrien 683860484Sobrien return 1; 683960484Sobrien} 684060484Sobrien 684160484Sobrienstatic const char * 6842130561Sobrienget_symbol_binding (unsigned int binding) 684360484Sobrien{ 6844130561Sobrien static char buff[32]; 684560484Sobrien 684660484Sobrien switch (binding) 684760484Sobrien { 6848130561Sobrien case STB_LOCAL: return "LOCAL"; 6849130561Sobrien case STB_GLOBAL: return "GLOBAL"; 6850130561Sobrien case STB_WEAK: return "WEAK"; 685160484Sobrien default: 685260484Sobrien if (binding >= STB_LOPROC && binding <= STB_HIPROC) 6853218822Sdim snprintf (buff, sizeof (buff), _("<processor specific>: %d"), 6854218822Sdim binding); 685560484Sobrien else if (binding >= STB_LOOS && binding <= STB_HIOS) 6856218822Sdim snprintf (buff, sizeof (buff), _("<OS specific>: %d"), binding); 685760484Sobrien else 6858218822Sdim snprintf (buff, sizeof (buff), _("<unknown>: %d"), binding); 685960484Sobrien return buff; 686060484Sobrien } 686160484Sobrien} 686260484Sobrien 686360484Sobrienstatic const char * 6864130561Sobrienget_symbol_type (unsigned int type) 686560484Sobrien{ 6866130561Sobrien static char buff[32]; 686760484Sobrien 686860484Sobrien switch (type) 686960484Sobrien { 6870130561Sobrien case STT_NOTYPE: return "NOTYPE"; 6871130561Sobrien case STT_OBJECT: return "OBJECT"; 6872130561Sobrien case STT_FUNC: return "FUNC"; 6873130561Sobrien case STT_SECTION: return "SECTION"; 6874130561Sobrien case STT_FILE: return "FILE"; 6875130561Sobrien case STT_COMMON: return "COMMON"; 6876130561Sobrien case STT_TLS: return "TLS"; 6877218822Sdim case STT_RELC: return "RELC"; 6878218822Sdim case STT_SRELC: return "SRELC"; 687960484Sobrien default: 688060484Sobrien if (type >= STT_LOPROC && type <= STT_HIPROC) 688160484Sobrien { 688260484Sobrien if (elf_header.e_machine == EM_ARM && type == STT_ARM_TFUNC) 688360484Sobrien return "THUMB_FUNC"; 688460484Sobrien 688560484Sobrien if (elf_header.e_machine == EM_SPARCV9 && type == STT_REGISTER) 688660484Sobrien return "REGISTER"; 688760484Sobrien 688860484Sobrien if (elf_header.e_machine == EM_PARISC && type == STT_PARISC_MILLI) 688960484Sobrien return "PARISC_MILLI"; 689060484Sobrien 6891218822Sdim snprintf (buff, sizeof (buff), _("<processor specific>: %d"), type); 689260484Sobrien } 689360484Sobrien else if (type >= STT_LOOS && type <= STT_HIOS) 689460484Sobrien { 689560484Sobrien if (elf_header.e_machine == EM_PARISC) 689660484Sobrien { 689760484Sobrien if (type == STT_HP_OPAQUE) 689860484Sobrien return "HP_OPAQUE"; 689960484Sobrien if (type == STT_HP_STUB) 690060484Sobrien return "HP_STUB"; 690160484Sobrien } 690260484Sobrien 6903218822Sdim snprintf (buff, sizeof (buff), _("<OS specific>: %d"), type); 690460484Sobrien } 690560484Sobrien else 6906218822Sdim snprintf (buff, sizeof (buff), _("<unknown>: %d"), type); 690760484Sobrien return buff; 690860484Sobrien } 690960484Sobrien} 691060484Sobrien 691160484Sobrienstatic const char * 6912130561Sobrienget_symbol_visibility (unsigned int visibility) 691360484Sobrien{ 691460484Sobrien switch (visibility) 691560484Sobrien { 6916130561Sobrien case STV_DEFAULT: return "DEFAULT"; 6917130561Sobrien case STV_INTERNAL: return "INTERNAL"; 6918130561Sobrien case STV_HIDDEN: return "HIDDEN"; 691960484Sobrien case STV_PROTECTED: return "PROTECTED"; 692060484Sobrien default: abort (); 692160484Sobrien } 692260484Sobrien} 692360484Sobrien 692460484Sobrienstatic const char * 6925218822Sdimget_mips_symbol_other (unsigned int other) 6926218822Sdim{ 6927218822Sdim switch (other) 6928218822Sdim { 6929218822Sdim case STO_OPTIONAL: return "OPTIONAL"; 6930218822Sdim case STO_MIPS16: return "MIPS16"; 6931218822Sdim default: return NULL; 6932218822Sdim } 6933218822Sdim} 6934218822Sdim 6935218822Sdimstatic const char * 6936218822Sdimget_symbol_other (unsigned int other) 6937218822Sdim{ 6938218822Sdim const char * result = NULL; 6939218822Sdim static char buff [32]; 6940218822Sdim 6941218822Sdim if (other == 0) 6942218822Sdim return ""; 6943218822Sdim 6944218822Sdim switch (elf_header.e_machine) 6945218822Sdim { 6946218822Sdim case EM_MIPS: 6947218822Sdim result = get_mips_symbol_other (other); 6948218822Sdim default: 6949218822Sdim break; 6950218822Sdim } 6951218822Sdim 6952218822Sdim if (result) 6953218822Sdim return result; 6954218822Sdim 6955218822Sdim snprintf (buff, sizeof buff, _("<other>: %x"), other); 6956218822Sdim return buff; 6957218822Sdim} 6958218822Sdim 6959218822Sdimstatic const char * 6960130561Sobrienget_symbol_index_type (unsigned int type) 696160484Sobrien{ 6962130561Sobrien static char buff[32]; 6963130561Sobrien 696460484Sobrien switch (type) 696560484Sobrien { 6966130561Sobrien case SHN_UNDEF: return "UND"; 6967130561Sobrien case SHN_ABS: return "ABS"; 6968130561Sobrien case SHN_COMMON: return "COM"; 696960484Sobrien default: 6970130561Sobrien if (type == SHN_IA_64_ANSI_COMMON 6971130561Sobrien && elf_header.e_machine == EM_IA_64 6972130561Sobrien && elf_header.e_ident[EI_OSABI] == ELFOSABI_HPUX) 6973130561Sobrien return "ANSI_COM"; 6974218822Sdim else if (elf_header.e_machine == EM_X86_64 6975218822Sdim && type == SHN_X86_64_LCOMMON) 6976218822Sdim return "LARGE_COM"; 6977218822Sdim else if (type == SHN_MIPS_SCOMMON 6978218822Sdim && elf_header.e_machine == EM_MIPS) 6979218822Sdim return "SCOM"; 6980218822Sdim else if (type == SHN_MIPS_SUNDEFINED 6981218822Sdim && elf_header.e_machine == EM_MIPS) 6982218822Sdim return "SUND"; 6983130561Sobrien else if (type >= SHN_LOPROC && type <= SHN_HIPROC) 6984130561Sobrien sprintf (buff, "PRC[0x%04x]", type); 698589857Sobrien else if (type >= SHN_LOOS && type <= SHN_HIOS) 6986130561Sobrien sprintf (buff, "OS [0x%04x]", type); 698760484Sobrien else if (type >= SHN_LORESERVE && type <= SHN_HIRESERVE) 6988130561Sobrien sprintf (buff, "RSV[0x%04x]", type); 698960484Sobrien else 6990130561Sobrien sprintf (buff, "%3d", type); 6991130561Sobrien break; 6992130561Sobrien } 699360484Sobrien 6994130561Sobrien return buff; 699560484Sobrien} 699660484Sobrien 6997218822Sdimstatic bfd_vma * 6998218822Sdimget_dynamic_data (FILE *file, unsigned int number, unsigned int ent_size) 699960484Sobrien{ 7000130561Sobrien unsigned char *e_data; 7001218822Sdim bfd_vma *i_data; 700260484Sobrien 7003218822Sdim e_data = cmalloc (number, ent_size); 700460484Sobrien 700560484Sobrien if (e_data == NULL) 700660484Sobrien { 700760484Sobrien error (_("Out of memory\n")); 700860484Sobrien return NULL; 700960484Sobrien } 701060484Sobrien 7011218822Sdim if (fread (e_data, ent_size, number, file) != number) 701260484Sobrien { 701360484Sobrien error (_("Unable to read in dynamic data\n")); 701460484Sobrien return NULL; 701560484Sobrien } 701660484Sobrien 7017218822Sdim i_data = cmalloc (number, sizeof (*i_data)); 701860484Sobrien 701960484Sobrien if (i_data == NULL) 702060484Sobrien { 702160484Sobrien error (_("Out of memory\n")); 702260484Sobrien free (e_data); 702360484Sobrien return NULL; 702460484Sobrien } 702560484Sobrien 702660484Sobrien while (number--) 7027218822Sdim i_data[number] = byte_get (e_data + number * ent_size, ent_size); 702860484Sobrien 702960484Sobrien free (e_data); 703060484Sobrien 703160484Sobrien return i_data; 703260484Sobrien} 703360484Sobrien 703489857Sobrien/* Dump the symbol table. */ 703560484Sobrienstatic int 7036130561Sobrienprocess_symbol_table (FILE *file) 703760484Sobrien{ 7038130561Sobrien Elf_Internal_Shdr *section; 7039218822Sdim bfd_vma nbuckets = 0; 7040218822Sdim bfd_vma nchains = 0; 7041218822Sdim bfd_vma *buckets = NULL; 7042218822Sdim bfd_vma *chains = NULL; 7043218822Sdim bfd_vma ngnubuckets = 0; 7044218822Sdim bfd_vma *gnubuckets = NULL; 7045218822Sdim bfd_vma *gnuchains = NULL; 704660484Sobrien 704760484Sobrien if (! do_syms && !do_histogram) 704860484Sobrien return 1; 704960484Sobrien 705060484Sobrien if (dynamic_info[DT_HASH] && ((do_using_dynamic && dynamic_strings != NULL) 705160484Sobrien || do_histogram)) 705260484Sobrien { 7053218822Sdim unsigned char nb[8]; 7054218822Sdim unsigned char nc[8]; 7055218822Sdim int hash_ent_size = 4; 7056218822Sdim 7057218822Sdim if ((elf_header.e_machine == EM_ALPHA 7058218822Sdim || elf_header.e_machine == EM_S390 7059218822Sdim || elf_header.e_machine == EM_S390_OLD) 7060218822Sdim && elf_header.e_ident[EI_CLASS] == ELFCLASS64) 7061218822Sdim hash_ent_size = 8; 7062218822Sdim 7063130561Sobrien if (fseek (file, 7064130561Sobrien (archive_file_offset 7065130561Sobrien + offset_from_vma (file, dynamic_info[DT_HASH], 7066130561Sobrien sizeof nb + sizeof nc)), 7067130561Sobrien SEEK_SET)) 706860484Sobrien { 7069218822Sdim error (_("Unable to seek to start of dynamic information\n")); 707060484Sobrien return 0; 707160484Sobrien } 707260484Sobrien 7073218822Sdim if (fread (nb, hash_ent_size, 1, file) != 1) 707460484Sobrien { 707560484Sobrien error (_("Failed to read in number of buckets\n")); 707660484Sobrien return 0; 707760484Sobrien } 707860484Sobrien 7079218822Sdim if (fread (nc, hash_ent_size, 1, file) != 1) 708060484Sobrien { 708160484Sobrien error (_("Failed to read in number of chains\n")); 708260484Sobrien return 0; 708360484Sobrien } 708460484Sobrien 7085218822Sdim nbuckets = byte_get (nb, hash_ent_size); 7086218822Sdim nchains = byte_get (nc, hash_ent_size); 708760484Sobrien 7088218822Sdim buckets = get_dynamic_data (file, nbuckets, hash_ent_size); 7089218822Sdim chains = get_dynamic_data (file, nchains, hash_ent_size); 709060484Sobrien 709160484Sobrien if (buckets == NULL || chains == NULL) 709260484Sobrien return 0; 709360484Sobrien } 709460484Sobrien 709560484Sobrien if (do_syms 709660484Sobrien && dynamic_info[DT_HASH] && do_using_dynamic && dynamic_strings != NULL) 709760484Sobrien { 7098218822Sdim unsigned long hn; 7099218822Sdim bfd_vma si; 710060484Sobrien 710160484Sobrien printf (_("\nSymbol table for image:\n")); 710260484Sobrien if (is_32bit_elf) 710360484Sobrien printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n")); 710460484Sobrien else 710560484Sobrien printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n")); 710660484Sobrien 710760484Sobrien for (hn = 0; hn < nbuckets; hn++) 710860484Sobrien { 7109130561Sobrien if (! buckets[hn]) 711060484Sobrien continue; 711160484Sobrien 7112130561Sobrien for (si = buckets[hn]; si < nchains && si > 0; si = chains[si]) 711360484Sobrien { 7114130561Sobrien Elf_Internal_Sym *psym; 7115218822Sdim int n; 711660484Sobrien 711760484Sobrien psym = dynamic_symbols + si; 711860484Sobrien 7119218822Sdim n = print_vma (si, DEC_5); 7120218822Sdim if (n < 5) 7121218822Sdim fputs (" " + n, stdout); 7122218822Sdim printf (" %3lu: ", hn); 712360484Sobrien print_vma (psym->st_value, LONG_HEX); 7124218822Sdim putchar (' '); 712560484Sobrien print_vma (psym->st_size, DEC_5); 712677298Sobrien 712760484Sobrien printf (" %6s", get_symbol_type (ELF_ST_TYPE (psym->st_info))); 712860484Sobrien printf (" %6s", get_symbol_binding (ELF_ST_BIND (psym->st_info))); 712960484Sobrien printf (" %3s", get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other))); 7130218822Sdim /* Check to see if any other bits in the st_other field are set. 7131218822Sdim Note - displaying this information disrupts the layout of the 7132218822Sdim table being generated, but for the moment this case is very rare. */ 7133218822Sdim if (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other)) 7134218822Sdim printf (" [%s] ", get_symbol_other (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other))); 713589857Sobrien printf (" %3.3s ", get_symbol_index_type (psym->st_shndx)); 7136218822Sdim if (VALID_DYNAMIC_NAME (psym->st_name)) 7137218822Sdim print_symbol (25, GET_DYNAMIC_NAME (psym->st_name)); 7138218822Sdim else 7139218822Sdim printf (" <corrupt: %14ld>", psym->st_name); 714089857Sobrien putchar ('\n'); 714160484Sobrien } 714260484Sobrien } 714360484Sobrien } 714460484Sobrien else if (do_syms && !do_using_dynamic) 714560484Sobrien { 7146130561Sobrien unsigned int i; 714760484Sobrien 714860484Sobrien for (i = 0, section = section_headers; 714960484Sobrien i < elf_header.e_shnum; 715060484Sobrien i++, section++) 715160484Sobrien { 7152130561Sobrien unsigned int si; 7153218822Sdim char *strtab = NULL; 7154218822Sdim unsigned long int strtab_size = 0; 7155130561Sobrien Elf_Internal_Sym *symtab; 7156130561Sobrien Elf_Internal_Sym *psym; 715760484Sobrien 715860484Sobrien 715960484Sobrien if ( section->sh_type != SHT_SYMTAB 716060484Sobrien && section->sh_type != SHT_DYNSYM) 716160484Sobrien continue; 716260484Sobrien 716360484Sobrien printf (_("\nSymbol table '%s' contains %lu entries:\n"), 716460484Sobrien SECTION_NAME (section), 716560484Sobrien (unsigned long) (section->sh_size / section->sh_entsize)); 716660484Sobrien if (is_32bit_elf) 716760484Sobrien printf (_(" Num: Value Size Type Bind Vis Ndx Name\n")); 716860484Sobrien else 716960484Sobrien printf (_(" Num: Value Size Type Bind Vis Ndx Name\n")); 717060484Sobrien 717189857Sobrien symtab = GET_ELF_SYMBOLS (file, section); 717260484Sobrien if (symtab == NULL) 717360484Sobrien continue; 717460484Sobrien 717560484Sobrien if (section->sh_link == elf_header.e_shstrndx) 717660484Sobrien { 7177218822Sdim strtab = string_table; 7178218822Sdim strtab_size = string_table_length; 7179218822Sdim } 7180218822Sdim else if (SECTION_HEADER_INDEX (section->sh_link) < elf_header.e_shnum) 7181218822Sdim { 7182130561Sobrien Elf_Internal_Shdr *string_sec; 718360484Sobrien 718489857Sobrien string_sec = SECTION_HEADER (section->sh_link); 718560484Sobrien 7186130561Sobrien strtab = get_data (NULL, file, string_sec->sh_offset, 7187218822Sdim 1, string_sec->sh_size, _("string table")); 7188218822Sdim strtab_size = strtab != NULL ? string_sec->sh_size : 0; 718960484Sobrien } 719060484Sobrien 719160484Sobrien for (si = 0, psym = symtab; 719260484Sobrien si < section->sh_size / section->sh_entsize; 7193130561Sobrien si++, psym++) 719460484Sobrien { 719560484Sobrien printf ("%6d: ", si); 719660484Sobrien print_vma (psym->st_value, LONG_HEX); 719760484Sobrien putchar (' '); 719860484Sobrien print_vma (psym->st_size, DEC_5); 719960484Sobrien printf (" %-7s", get_symbol_type (ELF_ST_TYPE (psym->st_info))); 720060484Sobrien printf (" %-6s", get_symbol_binding (ELF_ST_BIND (psym->st_info))); 720160484Sobrien printf (" %-3s", get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other))); 7202218822Sdim /* Check to see if any other bits in the st_other field are set. 7203218822Sdim Note - displaying this information disrupts the layout of the 7204218822Sdim table being generated, but for the moment this case is very rare. */ 7205218822Sdim if (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other)) 7206218822Sdim printf (" [%s] ", get_symbol_other (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other))); 720789857Sobrien printf (" %4s ", get_symbol_index_type (psym->st_shndx)); 7208218822Sdim print_symbol (25, psym->st_name < strtab_size 7209218822Sdim ? strtab + psym->st_name : "<corrupt>"); 721060484Sobrien 721160484Sobrien if (section->sh_type == SHT_DYNSYM && 7212130561Sobrien version_info[DT_VERSIONTAGIDX (DT_VERSYM)] != 0) 721360484Sobrien { 7214130561Sobrien unsigned char data[2]; 7215130561Sobrien unsigned short vers_data; 7216130561Sobrien unsigned long offset; 7217130561Sobrien int is_nobits; 7218130561Sobrien int check_def; 721960484Sobrien 7220130561Sobrien offset = offset_from_vma 7221130561Sobrien (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)], 7222130561Sobrien sizeof data + si * sizeof (vers_data)); 722360484Sobrien 722489857Sobrien get_data (&data, file, offset + si * sizeof (vers_data), 7225218822Sdim sizeof (data), 1, _("version data")); 722660484Sobrien 722760484Sobrien vers_data = byte_get (data, 2); 722860484Sobrien 7229218822Sdim is_nobits = (SECTION_HEADER_INDEX (psym->st_shndx) 7230218822Sdim < elf_header.e_shnum 7231218822Sdim && SECTION_HEADER (psym->st_shndx)->sh_type 7232218822Sdim == SHT_NOBITS); 723360484Sobrien 723460484Sobrien check_def = (psym->st_shndx != SHN_UNDEF); 723560484Sobrien 723660484Sobrien if ((vers_data & 0x8000) || vers_data > 1) 723760484Sobrien { 7238130561Sobrien if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)] 723977298Sobrien && (is_nobits || ! check_def)) 724060484Sobrien { 7241130561Sobrien Elf_External_Verneed evn; 7242130561Sobrien Elf_Internal_Verneed ivn; 7243130561Sobrien Elf_Internal_Vernaux ivna; 724460484Sobrien 724560484Sobrien /* We must test both. */ 7246130561Sobrien offset = offset_from_vma 7247130561Sobrien (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)], 7248130561Sobrien sizeof evn); 724960484Sobrien 725060484Sobrien do 725160484Sobrien { 7252130561Sobrien unsigned long vna_off; 725360484Sobrien 7254218822Sdim get_data (&evn, file, offset, sizeof (evn), 1, 725589857Sobrien _("version need")); 725660484Sobrien 725760484Sobrien ivn.vn_aux = BYTE_GET (evn.vn_aux); 725860484Sobrien ivn.vn_next = BYTE_GET (evn.vn_next); 725960484Sobrien 726060484Sobrien vna_off = offset + ivn.vn_aux; 726160484Sobrien 726260484Sobrien do 726360484Sobrien { 7264130561Sobrien Elf_External_Vernaux evna; 726560484Sobrien 726689857Sobrien get_data (&evna, file, vna_off, 7267218822Sdim sizeof (evna), 1, 726889857Sobrien _("version need aux (3)")); 726960484Sobrien 727060484Sobrien ivna.vna_other = BYTE_GET (evna.vna_other); 727160484Sobrien ivna.vna_next = BYTE_GET (evna.vna_next); 727260484Sobrien ivna.vna_name = BYTE_GET (evna.vna_name); 727360484Sobrien 727460484Sobrien vna_off += ivna.vna_next; 727560484Sobrien } 727660484Sobrien while (ivna.vna_other != vers_data 727760484Sobrien && ivna.vna_next != 0); 727860484Sobrien 727960484Sobrien if (ivna.vna_other == vers_data) 728060484Sobrien break; 728160484Sobrien 728260484Sobrien offset += ivn.vn_next; 728360484Sobrien } 728460484Sobrien while (ivn.vn_next != 0); 728560484Sobrien 728660484Sobrien if (ivna.vna_other == vers_data) 728760484Sobrien { 728860484Sobrien printf ("@%s (%d)", 7289218822Sdim ivna.vna_name < strtab_size 7290218822Sdim ? strtab + ivna.vna_name : "<corrupt>", 7291218822Sdim ivna.vna_other); 729260484Sobrien check_def = 0; 729360484Sobrien } 729460484Sobrien else if (! is_nobits) 7295218822Sdim error (_("bad dynamic symbol\n")); 729660484Sobrien else 729760484Sobrien check_def = 1; 729860484Sobrien } 729960484Sobrien 730060484Sobrien if (check_def) 730160484Sobrien { 730277298Sobrien if (vers_data != 0x8001 7303130561Sobrien && version_info[DT_VERSIONTAGIDX (DT_VERDEF)]) 730460484Sobrien { 7305130561Sobrien Elf_Internal_Verdef ivd; 7306130561Sobrien Elf_Internal_Verdaux ivda; 7307130561Sobrien Elf_External_Verdaux evda; 7308130561Sobrien unsigned long offset; 730960484Sobrien 7310130561Sobrien offset = offset_from_vma 7311130561Sobrien (file, 7312130561Sobrien version_info[DT_VERSIONTAGIDX (DT_VERDEF)], 7313130561Sobrien sizeof (Elf_External_Verdef)); 731460484Sobrien 731560484Sobrien do 731660484Sobrien { 7317130561Sobrien Elf_External_Verdef evd; 731860484Sobrien 731989857Sobrien get_data (&evd, file, offset, sizeof (evd), 7320218822Sdim 1, _("version def")); 732160484Sobrien 7322130561Sobrien ivd.vd_ndx = BYTE_GET (evd.vd_ndx); 7323130561Sobrien ivd.vd_aux = BYTE_GET (evd.vd_aux); 732460484Sobrien ivd.vd_next = BYTE_GET (evd.vd_next); 732560484Sobrien 732660484Sobrien offset += ivd.vd_next; 732760484Sobrien } 732860484Sobrien while (ivd.vd_ndx != (vers_data & 0x7fff) 732960484Sobrien && ivd.vd_next != 0); 733060484Sobrien 733160484Sobrien offset -= ivd.vd_next; 733260484Sobrien offset += ivd.vd_aux; 733360484Sobrien 733489857Sobrien get_data (&evda, file, offset, sizeof (evda), 7335218822Sdim 1, _("version def aux")); 733660484Sobrien 733760484Sobrien ivda.vda_name = BYTE_GET (evda.vda_name); 733860484Sobrien 733960484Sobrien if (psym->st_name != ivda.vda_name) 734060484Sobrien printf ((vers_data & 0x8000) 734160484Sobrien ? "@%s" : "@@%s", 7342218822Sdim ivda.vda_name < strtab_size 7343218822Sdim ? strtab + ivda.vda_name : "<corrupt>"); 734460484Sobrien } 734560484Sobrien } 734660484Sobrien } 734760484Sobrien } 734860484Sobrien 734960484Sobrien putchar ('\n'); 735060484Sobrien } 735160484Sobrien 735260484Sobrien free (symtab); 735360484Sobrien if (strtab != string_table) 735460484Sobrien free (strtab); 735560484Sobrien } 735660484Sobrien } 735760484Sobrien else if (do_syms) 735860484Sobrien printf 735960484Sobrien (_("\nDynamic symbol information is not available for displaying symbols.\n")); 736060484Sobrien 736160484Sobrien if (do_histogram && buckets != NULL) 736260484Sobrien { 7363218822Sdim unsigned long *lengths; 7364218822Sdim unsigned long *counts; 7365218822Sdim unsigned long hn; 7366218822Sdim bfd_vma si; 7367218822Sdim unsigned long maxlength = 0; 7368218822Sdim unsigned long nzero_counts = 0; 7369218822Sdim unsigned long nsyms = 0; 737060484Sobrien 7371218822Sdim printf (_("\nHistogram for bucket list length (total of %lu buckets):\n"), 7372218822Sdim (unsigned long) nbuckets); 737360484Sobrien printf (_(" Length Number %% of total Coverage\n")); 737460484Sobrien 7375218822Sdim lengths = calloc (nbuckets, sizeof (*lengths)); 737660484Sobrien if (lengths == NULL) 737760484Sobrien { 7378218822Sdim error (_("Out of memory\n")); 737960484Sobrien return 0; 738060484Sobrien } 738160484Sobrien for (hn = 0; hn < nbuckets; ++hn) 738260484Sobrien { 738360484Sobrien for (si = buckets[hn]; si > 0 && si < nchains; si = chains[si]) 738460484Sobrien { 7385130561Sobrien ++nsyms; 738660484Sobrien if (maxlength < ++lengths[hn]) 7387130561Sobrien ++maxlength; 738860484Sobrien } 738960484Sobrien } 739060484Sobrien 7391218822Sdim counts = calloc (maxlength + 1, sizeof (*counts)); 739260484Sobrien if (counts == NULL) 739360484Sobrien { 7394218822Sdim error (_("Out of memory\n")); 739560484Sobrien return 0; 739660484Sobrien } 739760484Sobrien 739860484Sobrien for (hn = 0; hn < nbuckets; ++hn) 7399130561Sobrien ++counts[lengths[hn]]; 740060484Sobrien 740160484Sobrien if (nbuckets > 0) 740260484Sobrien { 7403218822Sdim unsigned long i; 7404218822Sdim printf (" 0 %-10lu (%5.1f%%)\n", 740560484Sobrien counts[0], (counts[0] * 100.0) / nbuckets); 7406218822Sdim for (i = 1; i <= maxlength; ++i) 740760484Sobrien { 7408218822Sdim nzero_counts += counts[i] * i; 7409218822Sdim printf ("%7lu %-10lu (%5.1f%%) %5.1f%%\n", 7410218822Sdim i, counts[i], (counts[i] * 100.0) / nbuckets, 741160484Sobrien (nzero_counts * 100.0) / nsyms); 741260484Sobrien } 741360484Sobrien } 741460484Sobrien 741560484Sobrien free (counts); 741660484Sobrien free (lengths); 741760484Sobrien } 741860484Sobrien 741960484Sobrien if (buckets != NULL) 742060484Sobrien { 742160484Sobrien free (buckets); 742260484Sobrien free (chains); 742360484Sobrien } 742460484Sobrien 7425218822Sdim if (do_histogram && dynamic_info_DT_GNU_HASH) 7426218822Sdim { 7427218822Sdim unsigned char nb[16]; 7428218822Sdim bfd_vma i, maxchain = 0xffffffff, symidx, bitmaskwords; 7429218822Sdim unsigned long *lengths; 7430218822Sdim unsigned long *counts; 7431218822Sdim unsigned long hn; 7432218822Sdim unsigned long maxlength = 0; 7433218822Sdim unsigned long nzero_counts = 0; 7434218822Sdim unsigned long nsyms = 0; 7435218822Sdim bfd_vma buckets_vma; 7436218822Sdim 7437218822Sdim if (fseek (file, 7438218822Sdim (archive_file_offset 7439218822Sdim + offset_from_vma (file, dynamic_info_DT_GNU_HASH, 7440218822Sdim sizeof nb)), 7441218822Sdim SEEK_SET)) 7442218822Sdim { 7443218822Sdim error (_("Unable to seek to start of dynamic information\n")); 7444218822Sdim return 0; 7445218822Sdim } 7446218822Sdim 7447218822Sdim if (fread (nb, 16, 1, file) != 1) 7448218822Sdim { 7449218822Sdim error (_("Failed to read in number of buckets\n")); 7450218822Sdim return 0; 7451218822Sdim } 7452218822Sdim 7453218822Sdim ngnubuckets = byte_get (nb, 4); 7454218822Sdim symidx = byte_get (nb + 4, 4); 7455218822Sdim bitmaskwords = byte_get (nb + 8, 4); 7456218822Sdim buckets_vma = dynamic_info_DT_GNU_HASH + 16; 7457218822Sdim if (is_32bit_elf) 7458218822Sdim buckets_vma += bitmaskwords * 4; 7459218822Sdim else 7460218822Sdim buckets_vma += bitmaskwords * 8; 7461218822Sdim 7462218822Sdim if (fseek (file, 7463218822Sdim (archive_file_offset 7464218822Sdim + offset_from_vma (file, buckets_vma, 4)), 7465218822Sdim SEEK_SET)) 7466218822Sdim { 7467218822Sdim error (_("Unable to seek to start of dynamic information\n")); 7468218822Sdim return 0; 7469218822Sdim } 7470218822Sdim 7471218822Sdim gnubuckets = get_dynamic_data (file, ngnubuckets, 4); 7472218822Sdim 7473218822Sdim if (gnubuckets == NULL) 7474218822Sdim return 0; 7475218822Sdim 7476218822Sdim for (i = 0; i < ngnubuckets; i++) 7477218822Sdim if (gnubuckets[i] != 0) 7478218822Sdim { 7479218822Sdim if (gnubuckets[i] < symidx) 7480218822Sdim return 0; 7481218822Sdim 7482218822Sdim if (maxchain == 0xffffffff || gnubuckets[i] > maxchain) 7483218822Sdim maxchain = gnubuckets[i]; 7484218822Sdim } 7485218822Sdim 7486218822Sdim if (maxchain == 0xffffffff) 7487218822Sdim return 0; 7488218822Sdim 7489218822Sdim maxchain -= symidx; 7490218822Sdim 7491218822Sdim if (fseek (file, 7492218822Sdim (archive_file_offset 7493218822Sdim + offset_from_vma (file, buckets_vma 7494218822Sdim + 4 * (ngnubuckets + maxchain), 4)), 7495218822Sdim SEEK_SET)) 7496218822Sdim { 7497218822Sdim error (_("Unable to seek to start of dynamic information\n")); 7498218822Sdim return 0; 7499218822Sdim } 7500218822Sdim 7501218822Sdim do 7502218822Sdim { 7503218822Sdim if (fread (nb, 4, 1, file) != 1) 7504218822Sdim { 7505218822Sdim error (_("Failed to determine last chain length\n")); 7506218822Sdim return 0; 7507218822Sdim } 7508218822Sdim 7509218822Sdim if (maxchain + 1 == 0) 7510218822Sdim return 0; 7511218822Sdim 7512218822Sdim ++maxchain; 7513218822Sdim } 7514218822Sdim while ((byte_get (nb, 4) & 1) == 0); 7515218822Sdim 7516218822Sdim if (fseek (file, 7517218822Sdim (archive_file_offset 7518218822Sdim + offset_from_vma (file, buckets_vma + 4 * ngnubuckets, 4)), 7519218822Sdim SEEK_SET)) 7520218822Sdim { 7521218822Sdim error (_("Unable to seek to start of dynamic information\n")); 7522218822Sdim return 0; 7523218822Sdim } 7524218822Sdim 7525218822Sdim gnuchains = get_dynamic_data (file, maxchain, 4); 7526218822Sdim 7527218822Sdim if (gnuchains == NULL) 7528218822Sdim return 0; 7529218822Sdim 7530218822Sdim lengths = calloc (ngnubuckets, sizeof (*lengths)); 7531218822Sdim if (lengths == NULL) 7532218822Sdim { 7533218822Sdim error (_("Out of memory\n")); 7534218822Sdim return 0; 7535218822Sdim } 7536218822Sdim 7537218822Sdim printf (_("\nHistogram for `.gnu.hash' bucket list length (total of %lu buckets):\n"), 7538218822Sdim (unsigned long) ngnubuckets); 7539218822Sdim printf (_(" Length Number %% of total Coverage\n")); 7540218822Sdim 7541218822Sdim for (hn = 0; hn < ngnubuckets; ++hn) 7542218822Sdim if (gnubuckets[hn] != 0) 7543218822Sdim { 7544218822Sdim bfd_vma off, length = 1; 7545218822Sdim 7546218822Sdim for (off = gnubuckets[hn] - symidx; 7547218822Sdim (gnuchains[off] & 1) == 0; ++off) 7548218822Sdim ++length; 7549218822Sdim lengths[hn] = length; 7550218822Sdim if (length > maxlength) 7551218822Sdim maxlength = length; 7552218822Sdim nsyms += length; 7553218822Sdim } 7554218822Sdim 7555218822Sdim counts = calloc (maxlength + 1, sizeof (*counts)); 7556218822Sdim if (counts == NULL) 7557218822Sdim { 7558218822Sdim error (_("Out of memory\n")); 7559218822Sdim return 0; 7560218822Sdim } 7561218822Sdim 7562218822Sdim for (hn = 0; hn < ngnubuckets; ++hn) 7563218822Sdim ++counts[lengths[hn]]; 7564218822Sdim 7565218822Sdim if (ngnubuckets > 0) 7566218822Sdim { 7567218822Sdim unsigned long j; 7568218822Sdim printf (" 0 %-10lu (%5.1f%%)\n", 7569218822Sdim counts[0], (counts[0] * 100.0) / ngnubuckets); 7570218822Sdim for (j = 1; j <= maxlength; ++j) 7571218822Sdim { 7572218822Sdim nzero_counts += counts[j] * j; 7573218822Sdim printf ("%7lu %-10lu (%5.1f%%) %5.1f%%\n", 7574218822Sdim j, counts[j], (counts[j] * 100.0) / ngnubuckets, 7575218822Sdim (nzero_counts * 100.0) / nsyms); 7576218822Sdim } 7577218822Sdim } 7578218822Sdim 7579218822Sdim free (counts); 7580218822Sdim free (lengths); 7581218822Sdim free (gnubuckets); 7582218822Sdim free (gnuchains); 7583218822Sdim } 7584218822Sdim 758560484Sobrien return 1; 758660484Sobrien} 758760484Sobrien 758860484Sobrienstatic int 7589130561Sobrienprocess_syminfo (FILE *file ATTRIBUTE_UNUSED) 759060484Sobrien{ 759160484Sobrien unsigned int i; 759260484Sobrien 759360484Sobrien if (dynamic_syminfo == NULL 759460484Sobrien || !do_dynamic) 759560484Sobrien /* No syminfo, this is ok. */ 759660484Sobrien return 1; 759760484Sobrien 759860484Sobrien /* There better should be a dynamic symbol section. */ 759960484Sobrien if (dynamic_symbols == NULL || dynamic_strings == NULL) 760060484Sobrien return 0; 760160484Sobrien 760260484Sobrien if (dynamic_addr) 760360484Sobrien printf (_("\nDynamic info segment at offset 0x%lx contains %d entries:\n"), 760460484Sobrien dynamic_syminfo_offset, dynamic_syminfo_nent); 760560484Sobrien 760660484Sobrien printf (_(" Num: Name BoundTo Flags\n")); 760760484Sobrien for (i = 0; i < dynamic_syminfo_nent; ++i) 760860484Sobrien { 760960484Sobrien unsigned short int flags = dynamic_syminfo[i].si_flags; 761060484Sobrien 761189857Sobrien printf ("%4d: ", i); 7612218822Sdim if (VALID_DYNAMIC_NAME (dynamic_symbols[i].st_name)) 7613218822Sdim print_symbol (30, GET_DYNAMIC_NAME (dynamic_symbols[i].st_name)); 7614218822Sdim else 7615218822Sdim printf ("<corrupt: %19ld>", dynamic_symbols[i].st_name); 761689857Sobrien putchar (' '); 761760484Sobrien 761860484Sobrien switch (dynamic_syminfo[i].si_boundto) 761960484Sobrien { 762060484Sobrien case SYMINFO_BT_SELF: 762160484Sobrien fputs ("SELF ", stdout); 762260484Sobrien break; 762360484Sobrien case SYMINFO_BT_PARENT: 762460484Sobrien fputs ("PARENT ", stdout); 762560484Sobrien break; 762660484Sobrien default: 762760484Sobrien if (dynamic_syminfo[i].si_boundto > 0 7628218822Sdim && dynamic_syminfo[i].si_boundto < dynamic_nent 7629218822Sdim && VALID_DYNAMIC_NAME (dynamic_section[dynamic_syminfo[i].si_boundto].d_un.d_val)) 763089857Sobrien { 7631218822Sdim print_symbol (10, GET_DYNAMIC_NAME (dynamic_section[dynamic_syminfo[i].si_boundto].d_un.d_val)); 763289857Sobrien putchar (' ' ); 763389857Sobrien } 763460484Sobrien else 763560484Sobrien printf ("%-10d ", dynamic_syminfo[i].si_boundto); 763660484Sobrien break; 763760484Sobrien } 763860484Sobrien 763960484Sobrien if (flags & SYMINFO_FLG_DIRECT) 764060484Sobrien printf (" DIRECT"); 764160484Sobrien if (flags & SYMINFO_FLG_PASSTHRU) 764260484Sobrien printf (" PASSTHRU"); 764360484Sobrien if (flags & SYMINFO_FLG_COPY) 764460484Sobrien printf (" COPY"); 764560484Sobrien if (flags & SYMINFO_FLG_LAZYLOAD) 764660484Sobrien printf (" LAZYLOAD"); 764760484Sobrien 764860484Sobrien puts (""); 764960484Sobrien } 765060484Sobrien 765160484Sobrien return 1; 765260484Sobrien} 765360484Sobrien 765460484Sobrien#ifdef SUPPORT_DISASSEMBLY 7655218822Sdimstatic int 7656130561Sobriendisassemble_section (Elf_Internal_Shdr *section, FILE *file) 765760484Sobrien{ 765860484Sobrien printf (_("\nAssembly dump of section %s\n"), 765960484Sobrien SECTION_NAME (section)); 766060484Sobrien 766160484Sobrien /* XXX -- to be done --- XXX */ 766260484Sobrien 766360484Sobrien return 1; 766460484Sobrien} 766560484Sobrien#endif 766660484Sobrien 766760484Sobrienstatic int 7668130561Sobriendump_section (Elf_Internal_Shdr *section, FILE *file) 766960484Sobrien{ 7670218822Sdim Elf_Internal_Shdr *relsec; 7671130561Sobrien bfd_size_type bytes; 7672130561Sobrien bfd_vma addr; 7673130561Sobrien unsigned char *data; 7674130561Sobrien unsigned char *start; 767560484Sobrien 767660484Sobrien bytes = section->sh_size; 767760484Sobrien 7678130561Sobrien if (bytes == 0 || section->sh_type == SHT_NOBITS) 767960484Sobrien { 768060484Sobrien printf (_("\nSection '%s' has no data to dump.\n"), 768160484Sobrien SECTION_NAME (section)); 768260484Sobrien return 0; 768360484Sobrien } 768460484Sobrien else 768560484Sobrien printf (_("\nHex dump of section '%s':\n"), SECTION_NAME (section)); 768660484Sobrien 768760484Sobrien addr = section->sh_addr; 768860484Sobrien 7689218822Sdim start = get_data (NULL, file, section->sh_offset, 1, bytes, 7690218822Sdim _("section data")); 769189857Sobrien if (!start) 769289857Sobrien return 0; 769360484Sobrien 7694218822Sdim /* If the section being dumped has relocations against it the user might 7695218822Sdim be expecting these relocations to have been applied. Check for this 7696218822Sdim case and issue a warning message in order to avoid confusion. 7697218822Sdim FIXME: Maybe we ought to have an option that dumps a section with 7698218822Sdim relocs applied ? */ 7699218822Sdim for (relsec = section_headers; 7700218822Sdim relsec < section_headers + elf_header.e_shnum; 7701218822Sdim ++relsec) 7702218822Sdim { 7703218822Sdim if ((relsec->sh_type != SHT_RELA && relsec->sh_type != SHT_REL) 7704218822Sdim || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum 7705218822Sdim || SECTION_HEADER (relsec->sh_info) != section 7706218822Sdim || relsec->sh_size == 0 7707218822Sdim || SECTION_HEADER_INDEX (relsec->sh_link) >= elf_header.e_shnum) 7708218822Sdim continue; 7709218822Sdim 7710218822Sdim printf (_(" NOTE: This section has relocations against it, but these have NOT been applied to this dump.\n")); 7711218822Sdim break; 7712218822Sdim } 7713218822Sdim 771460484Sobrien data = start; 771560484Sobrien 771660484Sobrien while (bytes) 771760484Sobrien { 771860484Sobrien int j; 771960484Sobrien int k; 772060484Sobrien int lbytes; 772160484Sobrien 772260484Sobrien lbytes = (bytes > 16 ? 16 : bytes); 772360484Sobrien 772460484Sobrien printf (" 0x%8.8lx ", (unsigned long) addr); 772560484Sobrien 7726218822Sdim for (j = 0; j < 16; j++) 772760484Sobrien { 7728218822Sdim if (j < lbytes) 7729218822Sdim printf ("%2.2x", data[j]); 7730218822Sdim else 7731218822Sdim printf (" "); 773260484Sobrien 7733218822Sdim if ((j & 3) == 3) 7734218822Sdim printf (" "); 773560484Sobrien } 773660484Sobrien 773760484Sobrien for (j = 0; j < lbytes; j++) 773860484Sobrien { 7739130561Sobrien k = data[j]; 7740130561Sobrien if (k >= ' ' && k < 0x7f) 774160484Sobrien printf ("%c", k); 774260484Sobrien else 774360484Sobrien printf ("."); 774460484Sobrien } 774560484Sobrien 774660484Sobrien putchar ('\n'); 774760484Sobrien 774860484Sobrien data += lbytes; 774960484Sobrien addr += lbytes; 775060484Sobrien bytes -= lbytes; 775160484Sobrien } 775260484Sobrien 775360484Sobrien free (start); 775460484Sobrien 7755218822Sdim putchar ('\n'); 775660484Sobrien return 1; 775760484Sobrien} 775860484Sobrien 7759218822Sdim/* Return the number of bytes affected by a given reloc. 7760218822Sdim This information is architecture and reloc dependent. 7761218822Sdim Returns 4 by default, although this is not always correct. 7762218822Sdim It should return 0 if a decision cannot be made. 7763218822Sdim FIXME: This is not the correct way to solve this problem. 7764218822Sdim The proper way is to have target specific reloc sizing functions 7765218822Sdim created by the reloc-macros.h header, in the same way that it 7766218822Sdim already creates the reloc naming functions. */ 776760484Sobrien 7768130561Sobrienstatic unsigned int 7769218822Sdimget_reloc_size (Elf_Internal_Rela * reloc) 7770130561Sobrien{ 7771218822Sdim switch (elf_header.e_machine) 7772130561Sobrien { 7773218822Sdim case EM_H8S: 7774218822Sdim case EM_H8_300: 7775218822Sdim case EM_H8_300H: 7776218822Sdim case EM_H8_500: 7777218822Sdim switch (ELF32_R_TYPE (reloc->r_info)) 7778130561Sobrien { 7779218822Sdim /* PR gas/3800 - without this information we do not correctly 7780218822Sdim decode the debug information generated by the h8300 assembler. */ 7781218822Sdim case R_H8_DIR16: 7782218822Sdim return 2; 7783218822Sdim default: 7784218822Sdim return 4; 7785130561Sobrien } 7786218822Sdim default: 7787218822Sdim /* FIXME: We need to extend this switch statement to cope with other 7788218822Sdim architecture's relocs. (When those relocs are used against debug 7789218822Sdim sections, and when their size is not 4). But see the multiple 7790218822Sdim inclusions of <elf/h8.h> for an example of the hoops that we need 7791218822Sdim to jump through in order to obtain the reloc numbers. */ 7792218822Sdim return 4; 7793130561Sobrien } 7794218822Sdim} 7795130561Sobrien 7796218822Sdim/* Apply addends of RELA relocations. */ 7797130561Sobrien 779860484Sobrienstatic int 7799218822Sdimdebug_apply_rela_addends (void *file, 7800218822Sdim Elf_Internal_Shdr *section, 7801218822Sdim unsigned char *start) 780260484Sobrien{ 7803218822Sdim Elf_Internal_Shdr *relsec; 7804130561Sobrien unsigned char *end = start + section->sh_size; 780560484Sobrien 7806218822Sdim if (!is_relocatable) 7807218822Sdim return 1; 780860484Sobrien 7809218822Sdim /* SH uses RELA but uses in place value instead of the addend field. */ 7810218822Sdim if (elf_header.e_machine == EM_SH) 7811218822Sdim return 0; 7812130561Sobrien 7813218822Sdim for (relsec = section_headers; 7814218822Sdim relsec < section_headers + elf_header.e_shnum; 7815218822Sdim ++relsec) 781660484Sobrien { 7817218822Sdim unsigned long nrelas; 7818218822Sdim Elf_Internal_Rela *rela, *rp; 7819218822Sdim Elf_Internal_Shdr *symsec; 7820218822Sdim Elf_Internal_Sym *symtab; 7821218822Sdim Elf_Internal_Sym *sym; 782260484Sobrien 7823218822Sdim if (relsec->sh_type != SHT_RELA 7824218822Sdim || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum 7825218822Sdim || SECTION_HEADER (relsec->sh_info) != section 7826218822Sdim || relsec->sh_size == 0 7827218822Sdim || SECTION_HEADER_INDEX (relsec->sh_link) >= elf_header.e_shnum) 7828218822Sdim continue; 7829130561Sobrien 7830218822Sdim if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size, 7831218822Sdim &rela, &nrelas)) 7832218822Sdim return 0; 783385815Sobrien 7834218822Sdim symsec = SECTION_HEADER (relsec->sh_link); 7835218822Sdim symtab = GET_ELF_SYMBOLS (file, symsec); 783685815Sobrien 7837218822Sdim for (rp = rela; rp < rela + nrelas; ++rp) 783860484Sobrien { 7839218822Sdim unsigned char *loc; 7840218822Sdim unsigned int reloc_size; 784160484Sobrien 7842218822Sdim reloc_size = get_reloc_size (rp); 7843218822Sdim if (reloc_size == 0) 784460484Sobrien { 7845218822Sdim warn (_("skipping relocation of unknown size against offset 0x%lx in section %s\n"), 7846218822Sdim (unsigned long) rp->r_offset, 7847218822Sdim SECTION_NAME (section)); 7848218822Sdim continue; 784960484Sobrien } 785060484Sobrien 7851218822Sdim loc = start + rp->r_offset; 7852218822Sdim if ((loc + reloc_size) > end) 785360484Sobrien { 7854218822Sdim warn (_("skipping invalid relocation offset 0x%lx in section %s\n"), 7855218822Sdim (unsigned long) rp->r_offset, 7856218822Sdim SECTION_NAME (section)); 7857218822Sdim continue; 785860484Sobrien } 785960484Sobrien 7860218822Sdim if (is_32bit_elf) 7861218822Sdim { 7862218822Sdim sym = symtab + ELF32_R_SYM (rp->r_info); 786360484Sobrien 7864218822Sdim if (ELF32_R_SYM (rp->r_info) != 0 7865218822Sdim && ELF32_ST_TYPE (sym->st_info) != STT_SECTION 7866218822Sdim /* Relocations against symbols without type can happen. 7867218822Sdim Gcc -feliminate-dwarf2-dups may generate symbols 7868218822Sdim without type for debug info. */ 7869218822Sdim && ELF32_ST_TYPE (sym->st_info) != STT_NOTYPE 7870218822Sdim /* Relocations against object symbols can happen, 7871218822Sdim eg when referencing a global array. For an 7872218822Sdim example of this see the _clz.o binary in libgcc.a. */ 7873218822Sdim && ELF32_ST_TYPE (sym->st_info) != STT_OBJECT) 7874218822Sdim { 7875218822Sdim warn (_("skipping unexpected symbol type %s in relocation in section .rela%s\n"), 7876218822Sdim get_symbol_type (ELF32_ST_TYPE (sym->st_info)), 7877218822Sdim SECTION_NAME (section)); 7878218822Sdim continue; 7879218822Sdim } 7880104834Sobrien } 7881218822Sdim else 788289857Sobrien { 7883218822Sdim /* In MIPS little-endian objects, r_info isn't really a 7884218822Sdim 64-bit little-endian value: it has a 32-bit little-endian 7885218822Sdim symbol index followed by four individual byte fields. 7886218822Sdim Reorder INFO accordingly. */ 7887218822Sdim if (elf_header.e_machine == EM_MIPS 7888218822Sdim && elf_header.e_ident[EI_DATA] != ELFDATA2MSB) 7889218822Sdim rp->r_info = (((rp->r_info & 0xffffffff) << 32) 7890218822Sdim | ((rp->r_info >> 56) & 0xff) 7891218822Sdim | ((rp->r_info >> 40) & 0xff00) 7892218822Sdim | ((rp->r_info >> 24) & 0xff0000) 7893218822Sdim | ((rp->r_info >> 8) & 0xff000000)); 789460484Sobrien 7895218822Sdim sym = symtab + ELF64_R_SYM (rp->r_info); 789660484Sobrien 7897218822Sdim if (ELF64_R_SYM (rp->r_info) != 0 7898218822Sdim && ELF64_ST_TYPE (sym->st_info) != STT_SECTION 7899218822Sdim && ELF64_ST_TYPE (sym->st_info) != STT_NOTYPE 7900218822Sdim && ELF64_ST_TYPE (sym->st_info) != STT_OBJECT) 7901218822Sdim { 7902218822Sdim warn (_("skipping unexpected symbol type %s in relocation in section .rela.%s\n"), 7903218822Sdim get_symbol_type (ELF64_ST_TYPE (sym->st_info)), 7904218822Sdim SECTION_NAME (section)); 7905218822Sdim continue; 7906218822Sdim } 7907218822Sdim } 790860484Sobrien 7909218822Sdim byte_put (loc, rp->r_addend, reloc_size); 7910218822Sdim } 791160484Sobrien 7912218822Sdim free (symtab); 7913218822Sdim free (rela); 7914218822Sdim break; 7915218822Sdim } 7916218822Sdim return 1; 7917218822Sdim} 791860484Sobrien 7919218822Sdimint 7920218822Sdimload_debug_section (enum dwarf_section_display_enum debug, void *file) 7921218822Sdim{ 7922218822Sdim struct dwarf_section *section = &debug_displays [debug].section; 7923218822Sdim Elf_Internal_Shdr *sec; 7924218822Sdim char buf [64]; 792560484Sobrien 7926218822Sdim /* If it is already loaded, do nothing. */ 7927218822Sdim if (section->start != NULL) 7928218822Sdim return 1; 792960484Sobrien 7930218822Sdim /* Locate the debug section. */ 7931218822Sdim sec = find_section (section->name); 7932218822Sdim if (sec == NULL) 7933218822Sdim return 0; 793460484Sobrien 7935218822Sdim snprintf (buf, sizeof (buf), _("%s section data"), section->name); 7936218822Sdim section->address = sec->sh_addr; 7937218822Sdim section->size = sec->sh_size; 7938218822Sdim section->start = get_data (NULL, file, sec->sh_offset, 1, 7939218822Sdim sec->sh_size, buf); 794060484Sobrien 7941218822Sdim if (debug_displays [debug].relocate) 7942218822Sdim debug_apply_rela_addends (file, sec, section->start); 794360484Sobrien 7944218822Sdim return section->start != NULL; 7945218822Sdim} 7946104834Sobrien 7947218822Sdimvoid 7948218822Sdimfree_debug_section (enum dwarf_section_display_enum debug) 7949218822Sdim{ 7950218822Sdim struct dwarf_section *section = &debug_displays [debug].section; 7951104834Sobrien 7952218822Sdim if (section->start == NULL) 7953218822Sdim return; 7954104834Sobrien 7955218822Sdim free ((char *) section->start); 7956218822Sdim section->start = NULL; 7957218822Sdim section->address = 0; 7958218822Sdim section->size = 0; 795960484Sobrien} 796060484Sobrien 796160484Sobrienstatic int 7962218822Sdimdisplay_debug_section (Elf_Internal_Shdr *section, FILE *file) 796360484Sobrien{ 7964218822Sdim char *name = SECTION_NAME (section); 7965218822Sdim bfd_size_type length; 7966218822Sdim int result = 1; 7967218822Sdim enum dwarf_section_display_enum i; 796860484Sobrien 7969218822Sdim length = section->sh_size; 7970218822Sdim if (length == 0) 797160484Sobrien { 7972218822Sdim printf (_("\nSection '%s' has no debugging data.\n"), name); 7973218822Sdim return 0; 797460484Sobrien } 797560484Sobrien 7976218822Sdim if (const_strneq (name, ".gnu.linkonce.wi.")) 7977218822Sdim name = ".debug_info"; 797860484Sobrien 7979218822Sdim /* See if we know how to display the contents of this section. */ 7980218822Sdim for (i = 0; i < max; i++) 7981218822Sdim if (streq (debug_displays[i].section.name, name)) 798260484Sobrien { 7983218822Sdim struct dwarf_section *sec = &debug_displays [i].section; 798460484Sobrien 7985218822Sdim if (load_debug_section (i, file)) 7986218822Sdim { 7987218822Sdim result &= debug_displays[i].display (sec, file); 798860484Sobrien 7989218822Sdim if (i != info && i != abbrev) 7990218822Sdim free_debug_section (i); 7991218822Sdim } 799260484Sobrien 7993218822Sdim break; 799460484Sobrien } 799560484Sobrien 7996218822Sdim if (i == max) 799760484Sobrien { 7998218822Sdim printf (_("Unrecognized debug section: %s\n"), name); 7999218822Sdim result = 0; 800060484Sobrien } 800160484Sobrien 8002218822Sdim return result; 800360484Sobrien} 800460484Sobrien 8005218822Sdim/* Set DUMP_SECTS for all sections where dumps were requested 8006218822Sdim based on section name. */ 800760484Sobrien 800860484Sobrienstatic void 8009218822Sdiminitialise_dumps_byname (void) 801060484Sobrien{ 8011218822Sdim struct dump_list_entry *cur; 801260484Sobrien 8013218822Sdim for (cur = dump_sects_byname; cur; cur = cur->next) 801460484Sobrien { 8015218822Sdim unsigned int i; 8016218822Sdim int any; 801760484Sobrien 8018218822Sdim for (i = 0, any = 0; i < elf_header.e_shnum; i++) 8019218822Sdim if (streq (SECTION_NAME (section_headers + i), cur->name)) 8020218822Sdim { 8021218822Sdim request_dump (i, cur->type); 8022218822Sdim any = 1; 8023218822Sdim } 802460484Sobrien 8025218822Sdim if (!any) 8026218822Sdim warn (_("Section '%s' was not dumped because it does not exist!\n"), 8027218822Sdim cur->name); 802860484Sobrien } 802960484Sobrien} 803060484Sobrien 803160484Sobrienstatic void 8032218822Sdimprocess_section_contents (FILE *file) 803360484Sobrien{ 8034218822Sdim Elf_Internal_Shdr *section; 8035218822Sdim unsigned int i; 803660484Sobrien 8037218822Sdim if (! do_dump) 803860484Sobrien return; 803960484Sobrien 8040218822Sdim initialise_dumps_byname (); 804160484Sobrien 8042218822Sdim for (i = 0, section = section_headers; 8043218822Sdim i < elf_header.e_shnum && i < num_dump_sects; 8044218822Sdim i++, section++) 8045218822Sdim { 8046218822Sdim#ifdef SUPPORT_DISASSEMBLY 8047218822Sdim if (dump_sects[i] & DISASS_DUMP) 8048218822Sdim disassemble_section (section, file); 8049218822Sdim#endif 8050218822Sdim if (dump_sects[i] & HEX_DUMP) 8051218822Sdim dump_section (section, file); 805260484Sobrien 8053218822Sdim if (dump_sects[i] & DEBUG_DUMP) 8054218822Sdim display_debug_section (section, file); 8055218822Sdim } 8056218822Sdim 8057218822Sdim /* Check to see if the user requested a 8058218822Sdim dump of a section that does not exist. */ 8059218822Sdim while (i++ < num_dump_sects) 8060218822Sdim if (dump_sects[i]) 8061218822Sdim warn (_("Section %d was not dumped because it does not exist!\n"), i); 806260484Sobrien} 806360484Sobrien 806460484Sobrienstatic void 8065218822Sdimprocess_mips_fpe_exception (int mask) 806660484Sobrien{ 8067218822Sdim if (mask) 8068218822Sdim { 8069218822Sdim int first = 1; 8070218822Sdim if (mask & OEX_FPU_INEX) 8071218822Sdim fputs ("INEX", stdout), first = 0; 8072218822Sdim if (mask & OEX_FPU_UFLO) 8073218822Sdim printf ("%sUFLO", first ? "" : "|"), first = 0; 8074218822Sdim if (mask & OEX_FPU_OFLO) 8075218822Sdim printf ("%sOFLO", first ? "" : "|"), first = 0; 8076218822Sdim if (mask & OEX_FPU_DIV0) 8077218822Sdim printf ("%sDIV0", first ? "" : "|"), first = 0; 8078218822Sdim if (mask & OEX_FPU_INVAL) 8079218822Sdim printf ("%sINVAL", first ? "" : "|"); 8080218822Sdim } 808160484Sobrien else 8082218822Sdim fputs ("0", stdout); 808360484Sobrien} 808460484Sobrien 8085218822Sdim/* ARM EABI attributes section. */ 8086218822Sdimtypedef struct 808760484Sobrien{ 8088218822Sdim int tag; 8089218822Sdim const char *name; 8090218822Sdim /* 0 = special, 1 = string, 2 = uleb123, > 0x80 == table lookup. */ 8091218822Sdim int type; 8092218822Sdim const char **table; 8093218822Sdim} arm_attr_public_tag; 809460484Sobrien 8095218822Sdimstatic const char *arm_attr_tag_CPU_arch[] = 8096218822Sdim {"Pre-v4", "v4", "v4T", "v5T", "v5TE", "v5TEJ", "v6", "v6KZ", "v6T2", 8097218822Sdim "v6K", "v7"}; 8098218822Sdimstatic const char *arm_attr_tag_ARM_ISA_use[] = {"No", "Yes"}; 8099218822Sdimstatic const char *arm_attr_tag_THUMB_ISA_use[] = 8100218822Sdim {"No", "Thumb-1", "Thumb-2"}; 8101218822Sdim/* FIXME: VFPv3 encoding was extrapolated! */ 8102218822Sdimstatic const char *arm_attr_tag_VFP_arch[] = {"No", "VFPv1", "VFPv2", "VFPv3"}; 8103218822Sdimstatic const char *arm_attr_tag_WMMX_arch[] = {"No", "WMMXv1"}; 8104218822Sdimstatic const char *arm_attr_tag_NEON_arch[] = {"No", "NEONv1"}; 8105218822Sdimstatic const char *arm_attr_tag_ABI_PCS_config[] = 8106218822Sdim {"None", "Bare platform", "Linux application", "Linux DSO", "PalmOS 2004", 8107218822Sdim "PalmOS (reserved)", "SymbianOS 2004", "SymbianOS (reserved)"}; 8108218822Sdimstatic const char *arm_attr_tag_ABI_PCS_R9_use[] = 8109218822Sdim {"V6", "SB", "TLS", "Unused"}; 8110218822Sdimstatic const char *arm_attr_tag_ABI_PCS_RW_data[] = 8111218822Sdim {"Absolute", "PC-relative", "SB-relative", "None"}; 8112218822Sdimstatic const char *arm_attr_tag_ABI_PCS_RO_DATA[] = 8113218822Sdim {"Absolute", "PC-relative", "None"}; 8114218822Sdimstatic const char *arm_attr_tag_ABI_PCS_GOT_use[] = 8115218822Sdim {"None", "direct", "GOT-indirect"}; 8116218822Sdimstatic const char *arm_attr_tag_ABI_PCS_wchar_t[] = 8117218822Sdim {"None", "??? 1", "2", "??? 3", "4"}; 8118218822Sdimstatic const char *arm_attr_tag_ABI_FP_rounding[] = {"Unused", "Needed"}; 8119218822Sdimstatic const char *arm_attr_tag_ABI_FP_denormal[] = {"Unused", "Needed"}; 8120218822Sdimstatic const char *arm_attr_tag_ABI_FP_exceptions[] = {"Unused", "Needed"}; 8121218822Sdimstatic const char *arm_attr_tag_ABI_FP_user_exceptions[] = {"Unused", "Needed"}; 8122218822Sdimstatic const char *arm_attr_tag_ABI_FP_number_model[] = 8123218822Sdim {"Unused", "Finite", "RTABI", "IEEE 754"}; 8124218822Sdimstatic const char *arm_attr_tag_ABI_align8_needed[] = {"No", "Yes", "4-byte"}; 8125218822Sdimstatic const char *arm_attr_tag_ABI_align8_preserved[] = 8126218822Sdim {"No", "Yes, except leaf SP", "Yes"}; 8127218822Sdimstatic const char *arm_attr_tag_ABI_enum_size[] = 8128218822Sdim {"Unused", "small", "int", "forced to int"}; 8129218822Sdimstatic const char *arm_attr_tag_ABI_HardFP_use[] = 8130218822Sdim {"As Tag_VFP_arch", "SP only", "DP only", "SP and DP"}; 8131218822Sdimstatic const char *arm_attr_tag_ABI_VFP_args[] = 8132218822Sdim {"AAPCS", "VFP registers", "custom"}; 8133218822Sdimstatic const char *arm_attr_tag_ABI_WMMX_args[] = 8134218822Sdim {"AAPCS", "WMMX registers", "custom"}; 8135218822Sdimstatic const char *arm_attr_tag_ABI_optimization_goals[] = 8136218822Sdim {"None", "Prefer Speed", "Aggressive Speed", "Prefer Size", 8137218822Sdim "Aggressive Size", "Prefer Debug", "Aggressive Debug"}; 8138218822Sdimstatic const char *arm_attr_tag_ABI_FP_optimization_goals[] = 8139218822Sdim {"None", "Prefer Speed", "Aggressive Speed", "Prefer Size", 8140218822Sdim "Aggressive Size", "Prefer Accuracy", "Aggressive Accuracy"}; 814160484Sobrien 8142218822Sdim#define LOOKUP(id, name) \ 8143218822Sdim {id, #name, 0x80 | ARRAY_SIZE(arm_attr_tag_##name), arm_attr_tag_##name} 8144218822Sdimstatic arm_attr_public_tag arm_attr_public_tags[] = 8145218822Sdim{ 8146218822Sdim {4, "CPU_raw_name", 1, NULL}, 8147218822Sdim {5, "CPU_name", 1, NULL}, 8148218822Sdim LOOKUP(6, CPU_arch), 8149218822Sdim {7, "CPU_arch_profile", 0, NULL}, 8150218822Sdim LOOKUP(8, ARM_ISA_use), 8151218822Sdim LOOKUP(9, THUMB_ISA_use), 8152218822Sdim LOOKUP(10, VFP_arch), 8153218822Sdim LOOKUP(11, WMMX_arch), 8154218822Sdim LOOKUP(12, NEON_arch), 8155218822Sdim LOOKUP(13, ABI_PCS_config), 8156218822Sdim LOOKUP(14, ABI_PCS_R9_use), 8157218822Sdim LOOKUP(15, ABI_PCS_RW_data), 8158218822Sdim LOOKUP(16, ABI_PCS_RO_DATA), 8159218822Sdim LOOKUP(17, ABI_PCS_GOT_use), 8160218822Sdim LOOKUP(18, ABI_PCS_wchar_t), 8161218822Sdim LOOKUP(19, ABI_FP_rounding), 8162218822Sdim LOOKUP(20, ABI_FP_denormal), 8163218822Sdim LOOKUP(21, ABI_FP_exceptions), 8164218822Sdim LOOKUP(22, ABI_FP_user_exceptions), 8165218822Sdim LOOKUP(23, ABI_FP_number_model), 8166218822Sdim LOOKUP(24, ABI_align8_needed), 8167218822Sdim LOOKUP(25, ABI_align8_preserved), 8168218822Sdim LOOKUP(26, ABI_enum_size), 8169218822Sdim LOOKUP(27, ABI_HardFP_use), 8170218822Sdim LOOKUP(28, ABI_VFP_args), 8171218822Sdim LOOKUP(29, ABI_WMMX_args), 8172218822Sdim LOOKUP(30, ABI_optimization_goals), 8173218822Sdim LOOKUP(31, ABI_FP_optimization_goals), 8174218822Sdim {32, "compatibility", 0, NULL} 8175218822Sdim}; 8176218822Sdim#undef LOOKUP 817760484Sobrien 8178218822Sdim/* Read an unsigned LEB128 encoded value from p. Set *PLEN to the number of 8179218822Sdim bytes read. */ 8180218822Sdimstatic unsigned int 8181218822Sdimread_uleb128 (unsigned char *p, unsigned int *plen) 8182218822Sdim{ 8183218822Sdim unsigned char c; 8184218822Sdim unsigned int val; 8185218822Sdim int shift; 8186218822Sdim int len; 818760484Sobrien 8188218822Sdim val = 0; 8189218822Sdim shift = 0; 8190218822Sdim len = 0; 8191218822Sdim do 8192218822Sdim { 8193218822Sdim c = *(p++); 8194218822Sdim len++; 8195218822Sdim val |= ((unsigned int)c & 0x7f) << shift; 8196218822Sdim shift += 7; 819760484Sobrien } 8198218822Sdim while (c & 0x80); 819960484Sobrien 8200218822Sdim *plen = len; 8201218822Sdim return val; 820260484Sobrien} 820360484Sobrien 8204218822Sdimstatic unsigned char * 8205218822Sdimdisplay_arm_attribute (unsigned char *p) 820689857Sobrien{ 8207218822Sdim int tag; 8208218822Sdim unsigned int len; 8209218822Sdim int val; 8210218822Sdim arm_attr_public_tag *attr; 8211218822Sdim unsigned i; 8212218822Sdim int type; 821389857Sobrien 8214218822Sdim tag = read_uleb128 (p, &len); 8215218822Sdim p += len; 8216218822Sdim attr = NULL; 8217218822Sdim for (i = 0; i < ARRAY_SIZE(arm_attr_public_tags); i++) 821889857Sobrien { 8219218822Sdim if (arm_attr_public_tags[i].tag == tag) 822089857Sobrien { 8221218822Sdim attr = &arm_attr_public_tags[i]; 822289857Sobrien break; 822389857Sobrien } 822489857Sobrien } 822589857Sobrien 8226218822Sdim if (attr) 822760484Sobrien { 8228218822Sdim printf (" Tag_%s: ", attr->name); 8229218822Sdim switch (attr->type) 823060484Sobrien { 8231218822Sdim case 0: 8232218822Sdim switch (tag) 8233218822Sdim { 8234218822Sdim case 7: /* Tag_CPU_arch_profile. */ 8235218822Sdim val = read_uleb128 (p, &len); 8236218822Sdim p += len; 8237218822Sdim switch (val) 8238218822Sdim { 8239218822Sdim case 0: printf ("None\n"); break; 8240218822Sdim case 'A': printf ("Application\n"); break; 8241218822Sdim case 'R': printf ("Realtime\n"); break; 8242218822Sdim case 'M': printf ("Microcontroller\n"); break; 8243218822Sdim default: printf ("??? (%d)\n", val); break; 8244218822Sdim } 8245218822Sdim break; 824660484Sobrien 8247218822Sdim case 32: /* Tag_compatibility. */ 8248218822Sdim val = read_uleb128 (p, &len); 8249218822Sdim p += len; 8250218822Sdim printf ("flag = %d, vendor = %s\n", val, p); 8251218822Sdim p += strlen((char *)p) + 1; 8252218822Sdim break; 825360484Sobrien 8254218822Sdim default: 8255218822Sdim abort(); 825660484Sobrien } 8257218822Sdim return p; 825889857Sobrien 8259218822Sdim case 1: 8260218822Sdim case 2: 8261218822Sdim type = attr->type; 826277298Sobrien break; 826377298Sobrien 826477298Sobrien default: 8265218822Sdim assert (attr->type & 0x80); 8266218822Sdim val = read_uleb128 (p, &len); 8267218822Sdim p += len; 8268218822Sdim type = attr->type & 0x7f; 8269218822Sdim if (val >= type) 8270218822Sdim printf ("??? (%d)\n", val); 827177298Sobrien else 8272218822Sdim printf ("%s\n", attr->table[val]); 8273218822Sdim return p; 827477298Sobrien } 827560484Sobrien } 8276218822Sdim else 827799461Sobrien { 8278218822Sdim if (tag & 1) 8279218822Sdim type = 1; /* String. */ 8280218822Sdim else 8281218822Sdim type = 2; /* uleb128. */ 8282218822Sdim printf (" Tag_unknown_%d: ", tag); 828399461Sobrien } 8284130561Sobrien 8285218822Sdim if (type == 1) 828699461Sobrien { 8287218822Sdim printf ("\"%s\"\n", p); 8288218822Sdim p += strlen((char *)p) + 1; 828999461Sobrien } 8290218822Sdim else 8291218822Sdim { 8292218822Sdim val = read_uleb128 (p, &len); 8293218822Sdim p += len; 8294218822Sdim printf ("%d (0x%x)\n", val, val); 8295218822Sdim } 829699461Sobrien 8297218822Sdim return p; 829889857Sobrien} 829989857Sobrien 830089857Sobrien 8301218822Sdimstatic unsigned char * 8302218822Sdimdisplay_gnu_attribute (unsigned char *p, 8303218822Sdim unsigned char *(*display_proc_gnu_attribute) 8304218822Sdim (unsigned char *, int)) 830589857Sobrien{ 8306218822Sdim int tag; 8307218822Sdim unsigned int len; 8308218822Sdim int val; 8309218822Sdim int type; 831089857Sobrien 8311218822Sdim tag = read_uleb128 (p, &len); 8312218822Sdim p += len; 831389857Sobrien 8314218822Sdim /* Tag_compatibility is the only generic GNU attribute defined at 8315218822Sdim present. */ 8316218822Sdim if (tag == 32) 8317218822Sdim { 8318218822Sdim val = read_uleb128 (p, &len); 8319218822Sdim p += len; 8320218822Sdim printf ("flag = %d, vendor = %s\n", val, p); 8321218822Sdim p += strlen((char *)p) + 1; 8322218822Sdim return p; 8323218822Sdim } 832489857Sobrien 8325218822Sdim if ((tag & 2) == 0 && display_proc_gnu_attribute) 8326218822Sdim return display_proc_gnu_attribute (p, tag); 832789857Sobrien 8328218822Sdim if (tag & 1) 8329218822Sdim type = 1; /* String. */ 8330218822Sdim else 8331218822Sdim type = 2; /* uleb128. */ 8332218822Sdim printf (" Tag_unknown_%d: ", tag); 833389857Sobrien 8334218822Sdim if (type == 1) 833589857Sobrien { 8336218822Sdim printf ("\"%s\"\n", p); 8337218822Sdim p += strlen ((char *)p) + 1; 833889857Sobrien } 8339218822Sdim else 834089857Sobrien { 8341218822Sdim val = read_uleb128 (p, &len); 8342218822Sdim p += len; 8343218822Sdim printf ("%d (0x%x)\n", val, val); 834489857Sobrien } 834589857Sobrien 8346218822Sdim return p; 834789857Sobrien} 834889857Sobrien 834960484Sobrienstatic unsigned char * 8350218822Sdimdisplay_power_gnu_attribute (unsigned char *p, int tag) 835160484Sobrien{ 8352218822Sdim int type; 8353218822Sdim unsigned int len; 8354218822Sdim int val; 835560484Sobrien 8356218822Sdim if (tag == Tag_GNU_Power_ABI_FP) 835760484Sobrien { 8358218822Sdim val = read_uleb128 (p, &len); 8359218822Sdim p += len; 8360218822Sdim printf (" Tag_GNU_Power_ABI_FP: "); 8361218822Sdim switch (val) 8362130561Sobrien { 8363218822Sdim case 0: 8364218822Sdim printf ("Hard or soft float\n"); 8365130561Sobrien break; 8366218822Sdim case 1: 8367218822Sdim printf ("Hard float\n"); 8368130561Sobrien break; 8369218822Sdim case 2: 8370218822Sdim printf ("Soft float\n"); 8371130561Sobrien break; 8372130561Sobrien default: 8373218822Sdim printf ("??? (%d)\n", val); 8374130561Sobrien break; 837560484Sobrien } 8376218822Sdim return p; 8377218822Sdim } 837860484Sobrien 8379218822Sdim if (tag & 1) 8380218822Sdim type = 1; /* String. */ 8381218822Sdim else 8382218822Sdim type = 2; /* uleb128. */ 8383218822Sdim printf (" Tag_unknown_%d: ", tag); 838460484Sobrien 8385218822Sdim if (type == 1) 8386218822Sdim { 8387218822Sdim printf ("\"%s\"\n", p); 8388218822Sdim p += strlen ((char *)p) + 1; 838960484Sobrien } 8390218822Sdim else 839160484Sobrien { 8392218822Sdim val = read_uleb128 (p, &len); 8393218822Sdim p += len; 8394218822Sdim printf ("%d (0x%x)\n", val, val); 839560484Sobrien } 839660484Sobrien 8397218822Sdim return p; 839860484Sobrien} 839960484Sobrien 8400218822Sdimstatic unsigned char * 8401218822Sdimdisplay_mips_gnu_attribute (unsigned char *p, int tag) 840260484Sobrien{ 8403218822Sdim int type; 8404218822Sdim unsigned int len; 8405218822Sdim int val; 840660484Sobrien 8407218822Sdim if (tag == Tag_GNU_MIPS_ABI_FP) 840860484Sobrien { 8409218822Sdim val = read_uleb128 (p, &len); 8410218822Sdim p += len; 8411218822Sdim printf (" Tag_GNU_MIPS_ABI_FP: "); 8412218822Sdim switch (val) 841385815Sobrien { 8414218822Sdim case 0: 8415218822Sdim printf ("Hard or soft float\n"); 841668765Sobrien break; 8417218822Sdim case 1: 8418218822Sdim printf ("Hard float (-mdouble-float)\n"); 8419218822Sdim break; 8420218822Sdim case 2: 8421218822Sdim printf ("Hard float (-msingle-float)\n"); 8422218822Sdim break; 8423218822Sdim case 3: 8424218822Sdim printf ("Soft float\n"); 8425218822Sdim break; 8426218822Sdim default: 8427218822Sdim printf ("??? (%d)\n", val); 8428218822Sdim break; 842968765Sobrien } 8430218822Sdim return p; 8431218822Sdim } 843268765Sobrien 8433218822Sdim if (tag & 1) 8434218822Sdim type = 1; /* String. */ 8435218822Sdim else 8436218822Sdim type = 2; /* uleb128. */ 8437218822Sdim printf (" Tag_unknown_%d: ", tag); 843860484Sobrien 8439218822Sdim if (type == 1) 844077298Sobrien { 8441218822Sdim printf ("\"%s\"\n", p); 8442218822Sdim p += strlen ((char *)p) + 1; 844377298Sobrien } 8444130561Sobrien else 844577298Sobrien { 8446218822Sdim val = read_uleb128 (p, &len); 8447218822Sdim p += len; 8448218822Sdim printf ("%d (0x%x)\n", val, val); 844977298Sobrien } 845077298Sobrien 8451218822Sdim return p; 845278828Sobrien} 845378828Sobrien 845460484Sobrienstatic int 8455218822Sdimprocess_attributes (FILE *file, const char *public_name, 8456218822Sdim unsigned int proc_type, 8457218822Sdim unsigned char *(*display_pub_attribute) (unsigned char *), 8458218822Sdim unsigned char *(*display_proc_gnu_attribute) 8459218822Sdim (unsigned char *, int)) 846077298Sobrien{ 8461218822Sdim Elf_Internal_Shdr *sect; 8462218822Sdim unsigned char *contents; 8463218822Sdim unsigned char *p; 8464218822Sdim unsigned char *end; 8465218822Sdim bfd_vma section_len; 8466218822Sdim bfd_vma len; 8467218822Sdim unsigned i; 846877298Sobrien 8469218822Sdim /* Find the section header so that we get the size. */ 8470218822Sdim for (i = 0, sect = section_headers; 8471218822Sdim i < elf_header.e_shnum; 8472218822Sdim i++, sect++) 847377298Sobrien { 8474218822Sdim if (sect->sh_type != proc_type && sect->sh_type != SHT_GNU_ATTRIBUTES) 8475218822Sdim continue; 847677298Sobrien 8477218822Sdim contents = get_data (NULL, file, sect->sh_offset, 1, sect->sh_size, 8478218822Sdim _("attributes")); 847977298Sobrien 8480218822Sdim if (!contents) 8481218822Sdim continue; 8482218822Sdim p = contents; 8483218822Sdim if (*p == 'A') 8484130561Sobrien { 8485218822Sdim len = sect->sh_size - 1; 8486218822Sdim p++; 8487218822Sdim while (len > 0) 848877298Sobrien { 8489218822Sdim int namelen; 8490218822Sdim bfd_boolean public_section; 8491218822Sdim bfd_boolean gnu_section; 849277298Sobrien 8493218822Sdim section_len = byte_get (p, 4); 8494218822Sdim p += 4; 8495218822Sdim if (section_len > len) 849678828Sobrien { 8497218822Sdim printf (_("ERROR: Bad section length (%d > %d)\n"), 8498218822Sdim (int)section_len, (int)len); 8499218822Sdim section_len = len; 850078828Sobrien } 8501218822Sdim len -= section_len; 8502218822Sdim printf ("Attribute Section: %s\n", p); 8503218822Sdim if (public_name && strcmp ((char *)p, public_name) == 0) 8504218822Sdim public_section = TRUE; 8505218822Sdim else 8506218822Sdim public_section = FALSE; 8507218822Sdim if (strcmp ((char *)p, "gnu") == 0) 8508218822Sdim gnu_section = TRUE; 8509218822Sdim else 8510218822Sdim gnu_section = FALSE; 8511218822Sdim namelen = strlen ((char *)p) + 1; 8512218822Sdim p += namelen; 8513218822Sdim section_len -= namelen + 4; 8514218822Sdim while (section_len > 0) 851578828Sobrien { 8516218822Sdim int tag = *(p++); 8517218822Sdim int val; 8518218822Sdim bfd_vma size; 8519218822Sdim size = byte_get (p, 4); 8520218822Sdim if (size > section_len) 8521218822Sdim { 8522218822Sdim printf (_("ERROR: Bad subsection length (%d > %d)\n"), 8523218822Sdim (int)size, (int)section_len); 8524218822Sdim size = section_len; 8525218822Sdim } 8526218822Sdim section_len -= size; 8527218822Sdim end = p + size - 1; 8528218822Sdim p += 4; 8529218822Sdim switch (tag) 8530218822Sdim { 8531218822Sdim case 1: 8532218822Sdim printf ("File Attributes\n"); 8533218822Sdim break; 8534218822Sdim case 2: 8535218822Sdim printf ("Section Attributes:"); 8536218822Sdim goto do_numlist; 8537218822Sdim case 3: 8538218822Sdim printf ("Symbol Attributes:"); 8539218822Sdim do_numlist: 8540218822Sdim for (;;) 8541218822Sdim { 8542218822Sdim unsigned int i; 8543218822Sdim val = read_uleb128 (p, &i); 8544218822Sdim p += i; 8545218822Sdim if (val == 0) 8546218822Sdim break; 8547218822Sdim printf (" %d", val); 8548218822Sdim } 8549218822Sdim printf ("\n"); 8550218822Sdim break; 8551218822Sdim default: 8552218822Sdim printf ("Unknown tag: %d\n", tag); 8553218822Sdim public_section = FALSE; 8554218822Sdim break; 8555218822Sdim } 8556218822Sdim if (public_section) 8557218822Sdim { 8558218822Sdim while (p < end) 8559218822Sdim p = display_pub_attribute (p); 8560218822Sdim } 8561218822Sdim else if (gnu_section) 8562218822Sdim { 8563218822Sdim while (p < end) 8564218822Sdim p = display_gnu_attribute (p, 8565218822Sdim display_proc_gnu_attribute); 8566218822Sdim } 856778828Sobrien else 8568218822Sdim { 8569218822Sdim /* ??? Do something sensible, like dump hex. */ 8570218822Sdim printf (" Unknown section contexts\n"); 8571218822Sdim p = end; 8572218822Sdim } 857378828Sobrien } 857478828Sobrien } 857577298Sobrien } 857677298Sobrien else 857777298Sobrien { 8578218822Sdim printf (_("Unknown format '%c'\n"), *p); 857977298Sobrien } 858077298Sobrien 8581218822Sdim free(contents); 858277298Sobrien } 858377298Sobrien return 1; 858477298Sobrien} 858577298Sobrien 858677298Sobrienstatic int 8587218822Sdimprocess_arm_specific (FILE *file) 858860484Sobrien{ 8589218822Sdim return process_attributes (file, "aeabi", SHT_ARM_ATTRIBUTES, 8590218822Sdim display_arm_attribute, NULL); 859160484Sobrien} 859260484Sobrien 859360484Sobrienstatic int 8594218822Sdimprocess_power_specific (FILE *file) 859560484Sobrien{ 8596218822Sdim return process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL, 8597218822Sdim display_power_gnu_attribute); 859860484Sobrien} 859960484Sobrien 860060484Sobrienstatic int 8601130561Sobrienprocess_mips_specific (FILE *file) 860260484Sobrien{ 8603130561Sobrien Elf_Internal_Dyn *entry; 860460484Sobrien size_t liblist_offset = 0; 860560484Sobrien size_t liblistno = 0; 860660484Sobrien size_t conflictsno = 0; 860760484Sobrien size_t options_offset = 0; 860860484Sobrien size_t conflicts_offset = 0; 860960484Sobrien 8610218822Sdim process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL, 8611218822Sdim display_mips_gnu_attribute); 8612218822Sdim 861360484Sobrien /* We have a lot of special sections. Thanks SGI! */ 8614218822Sdim if (dynamic_section == NULL) 861560484Sobrien /* No information available. */ 861660484Sobrien return 0; 861760484Sobrien 8618218822Sdim for (entry = dynamic_section; entry->d_tag != DT_NULL; ++entry) 861960484Sobrien switch (entry->d_tag) 862060484Sobrien { 862160484Sobrien case DT_MIPS_LIBLIST: 8622130561Sobrien liblist_offset 8623130561Sobrien = offset_from_vma (file, entry->d_un.d_val, 8624130561Sobrien liblistno * sizeof (Elf32_External_Lib)); 862560484Sobrien break; 862660484Sobrien case DT_MIPS_LIBLISTNO: 862760484Sobrien liblistno = entry->d_un.d_val; 862860484Sobrien break; 862960484Sobrien case DT_MIPS_OPTIONS: 8630130561Sobrien options_offset = offset_from_vma (file, entry->d_un.d_val, 0); 863160484Sobrien break; 863260484Sobrien case DT_MIPS_CONFLICT: 8633130561Sobrien conflicts_offset 8634130561Sobrien = offset_from_vma (file, entry->d_un.d_val, 8635130561Sobrien conflictsno * sizeof (Elf32_External_Conflict)); 863660484Sobrien break; 863760484Sobrien case DT_MIPS_CONFLICTNO: 863860484Sobrien conflictsno = entry->d_un.d_val; 863960484Sobrien break; 864060484Sobrien default: 864160484Sobrien break; 864260484Sobrien } 864360484Sobrien 864460484Sobrien if (liblist_offset != 0 && liblistno != 0 && do_dynamic) 864560484Sobrien { 8646130561Sobrien Elf32_External_Lib *elib; 864760484Sobrien size_t cnt; 864860484Sobrien 8649130561Sobrien elib = get_data (NULL, file, liblist_offset, 8650218822Sdim liblistno, sizeof (Elf32_External_Lib), 8651130561Sobrien _("liblist")); 865289857Sobrien if (elib) 865360484Sobrien { 865489857Sobrien printf ("\nSection '.liblist' contains %lu entries:\n", 865589857Sobrien (unsigned long) liblistno); 865689857Sobrien fputs (" Library Time Stamp Checksum Version Flags\n", 865789857Sobrien stdout); 865860484Sobrien 865989857Sobrien for (cnt = 0; cnt < liblistno; ++cnt) 866089857Sobrien { 866189857Sobrien Elf32_Lib liblist; 866289857Sobrien time_t time; 866389857Sobrien char timebuf[20]; 8664130561Sobrien struct tm *tmp; 866560484Sobrien 866689857Sobrien liblist.l_name = BYTE_GET (elib[cnt].l_name); 866789857Sobrien time = BYTE_GET (elib[cnt].l_time_stamp); 866889857Sobrien liblist.l_checksum = BYTE_GET (elib[cnt].l_checksum); 866989857Sobrien liblist.l_version = BYTE_GET (elib[cnt].l_version); 867089857Sobrien liblist.l_flags = BYTE_GET (elib[cnt].l_flags); 867160484Sobrien 867289857Sobrien tmp = gmtime (&time); 8673218822Sdim snprintf (timebuf, sizeof (timebuf), 8674218822Sdim "%04u-%02u-%02uT%02u:%02u:%02u", 8675218822Sdim tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, 8676218822Sdim tmp->tm_hour, tmp->tm_min, tmp->tm_sec); 867760484Sobrien 867889857Sobrien printf ("%3lu: ", (unsigned long) cnt); 8679218822Sdim if (VALID_DYNAMIC_NAME (liblist.l_name)) 8680218822Sdim print_symbol (20, GET_DYNAMIC_NAME (liblist.l_name)); 8681218822Sdim else 8682218822Sdim printf ("<corrupt: %9ld>", liblist.l_name); 868389857Sobrien printf (" %s %#10lx %-7ld", timebuf, liblist.l_checksum, 868489857Sobrien liblist.l_version); 868560484Sobrien 868689857Sobrien if (liblist.l_flags == 0) 868789857Sobrien puts (" NONE"); 868889857Sobrien else 868989857Sobrien { 869089857Sobrien static const struct 869160484Sobrien { 8692130561Sobrien const char *name; 869389857Sobrien int bit; 869460484Sobrien } 869589857Sobrien l_flags_vals[] = 869689857Sobrien { 869789857Sobrien { " EXACT_MATCH", LL_EXACT_MATCH }, 869889857Sobrien { " IGNORE_INT_VER", LL_IGNORE_INT_VER }, 869989857Sobrien { " REQUIRE_MINOR", LL_REQUIRE_MINOR }, 870089857Sobrien { " EXPORTS", LL_EXPORTS }, 870189857Sobrien { " DELAY_LOAD", LL_DELAY_LOAD }, 870289857Sobrien { " DELTA", LL_DELTA } 870389857Sobrien }; 870489857Sobrien int flags = liblist.l_flags; 870589857Sobrien size_t fcnt; 870660484Sobrien 870789857Sobrien for (fcnt = 0; 870889857Sobrien fcnt < sizeof (l_flags_vals) / sizeof (l_flags_vals[0]); 870989857Sobrien ++fcnt) 871089857Sobrien if ((flags & l_flags_vals[fcnt].bit) != 0) 871189857Sobrien { 871289857Sobrien fputs (l_flags_vals[fcnt].name, stdout); 871389857Sobrien flags ^= l_flags_vals[fcnt].bit; 871489857Sobrien } 871589857Sobrien if (flags != 0) 871689857Sobrien printf (" %#x", (unsigned int) flags); 871789857Sobrien 871889857Sobrien puts (""); 871989857Sobrien } 872060484Sobrien } 872189857Sobrien 872289857Sobrien free (elib); 872360484Sobrien } 872460484Sobrien } 872560484Sobrien 872660484Sobrien if (options_offset != 0) 872760484Sobrien { 8728130561Sobrien Elf_External_Options *eopt; 8729130561Sobrien Elf_Internal_Shdr *sect = section_headers; 8730130561Sobrien Elf_Internal_Options *iopt; 8731130561Sobrien Elf_Internal_Options *option; 873260484Sobrien size_t offset; 873360484Sobrien int cnt; 873460484Sobrien 873560484Sobrien /* Find the section header so that we get the size. */ 873660484Sobrien while (sect->sh_type != SHT_MIPS_OPTIONS) 8737130561Sobrien ++sect; 873860484Sobrien 8739218822Sdim eopt = get_data (NULL, file, options_offset, 1, sect->sh_size, 8740130561Sobrien _("options")); 874189857Sobrien if (eopt) 874260484Sobrien { 8743218822Sdim iopt = cmalloc ((sect->sh_size / sizeof (eopt)), sizeof (*iopt)); 874489857Sobrien if (iopt == NULL) 874589857Sobrien { 8746218822Sdim error (_("Out of memory\n")); 874789857Sobrien return 0; 874889857Sobrien } 874960484Sobrien 875089857Sobrien offset = cnt = 0; 875189857Sobrien option = iopt; 875277298Sobrien 875389857Sobrien while (offset < sect->sh_size) 875489857Sobrien { 8755130561Sobrien Elf_External_Options *eoption; 875660484Sobrien 875789857Sobrien eoption = (Elf_External_Options *) ((char *) eopt + offset); 875860484Sobrien 875989857Sobrien option->kind = BYTE_GET (eoption->kind); 876089857Sobrien option->size = BYTE_GET (eoption->size); 876189857Sobrien option->section = BYTE_GET (eoption->section); 876289857Sobrien option->info = BYTE_GET (eoption->info); 876360484Sobrien 876489857Sobrien offset += option->size; 876577298Sobrien 876689857Sobrien ++option; 876789857Sobrien ++cnt; 876889857Sobrien } 876960484Sobrien 877089857Sobrien printf (_("\nSection '%s' contains %d entries:\n"), 877189857Sobrien SECTION_NAME (sect), cnt); 877260484Sobrien 877389857Sobrien option = iopt; 877477298Sobrien 877589857Sobrien while (cnt-- > 0) 877689857Sobrien { 877789857Sobrien size_t len; 877860484Sobrien 877989857Sobrien switch (option->kind) 878060484Sobrien { 878189857Sobrien case ODK_NULL: 878289857Sobrien /* This shouldn't happen. */ 878389857Sobrien printf (" NULL %d %lx", option->section, option->info); 878489857Sobrien break; 878589857Sobrien case ODK_REGINFO: 878689857Sobrien printf (" REGINFO "); 878789857Sobrien if (elf_header.e_machine == EM_MIPS) 878889857Sobrien { 878989857Sobrien /* 32bit form. */ 8790130561Sobrien Elf32_External_RegInfo *ereg; 8791130561Sobrien Elf32_RegInfo reginfo; 879260484Sobrien 879389857Sobrien ereg = (Elf32_External_RegInfo *) (option + 1); 879489857Sobrien reginfo.ri_gprmask = BYTE_GET (ereg->ri_gprmask); 879589857Sobrien reginfo.ri_cprmask[0] = BYTE_GET (ereg->ri_cprmask[0]); 879689857Sobrien reginfo.ri_cprmask[1] = BYTE_GET (ereg->ri_cprmask[1]); 879789857Sobrien reginfo.ri_cprmask[2] = BYTE_GET (ereg->ri_cprmask[2]); 879889857Sobrien reginfo.ri_cprmask[3] = BYTE_GET (ereg->ri_cprmask[3]); 879989857Sobrien reginfo.ri_gp_value = BYTE_GET (ereg->ri_gp_value); 880060484Sobrien 880189857Sobrien printf ("GPR %08lx GP 0x%lx\n", 880289857Sobrien reginfo.ri_gprmask, 880389857Sobrien (unsigned long) reginfo.ri_gp_value); 880489857Sobrien printf (" CPR0 %08lx CPR1 %08lx CPR2 %08lx CPR3 %08lx\n", 880589857Sobrien reginfo.ri_cprmask[0], reginfo.ri_cprmask[1], 880689857Sobrien reginfo.ri_cprmask[2], reginfo.ri_cprmask[3]); 880789857Sobrien } 880889857Sobrien else 880989857Sobrien { 881089857Sobrien /* 64 bit form. */ 8811130561Sobrien Elf64_External_RegInfo *ereg; 881289857Sobrien Elf64_Internal_RegInfo reginfo; 881360484Sobrien 881489857Sobrien ereg = (Elf64_External_RegInfo *) (option + 1); 881589857Sobrien reginfo.ri_gprmask = BYTE_GET (ereg->ri_gprmask); 881689857Sobrien reginfo.ri_cprmask[0] = BYTE_GET (ereg->ri_cprmask[0]); 881789857Sobrien reginfo.ri_cprmask[1] = BYTE_GET (ereg->ri_cprmask[1]); 881889857Sobrien reginfo.ri_cprmask[2] = BYTE_GET (ereg->ri_cprmask[2]); 881989857Sobrien reginfo.ri_cprmask[3] = BYTE_GET (ereg->ri_cprmask[3]); 8820218822Sdim reginfo.ri_gp_value = BYTE_GET (ereg->ri_gp_value); 882160484Sobrien 882289857Sobrien printf ("GPR %08lx GP 0x", 882389857Sobrien reginfo.ri_gprmask); 882489857Sobrien printf_vma (reginfo.ri_gp_value); 882589857Sobrien printf ("\n"); 882660484Sobrien 882789857Sobrien printf (" CPR0 %08lx CPR1 %08lx CPR2 %08lx CPR3 %08lx\n", 882889857Sobrien reginfo.ri_cprmask[0], reginfo.ri_cprmask[1], 882989857Sobrien reginfo.ri_cprmask[2], reginfo.ri_cprmask[3]); 883089857Sobrien } 883189857Sobrien ++option; 883289857Sobrien continue; 883389857Sobrien case ODK_EXCEPTIONS: 883489857Sobrien fputs (" EXCEPTIONS fpe_min(", stdout); 883589857Sobrien process_mips_fpe_exception (option->info & OEX_FPU_MIN); 883689857Sobrien fputs (") fpe_max(", stdout); 883789857Sobrien process_mips_fpe_exception ((option->info & OEX_FPU_MAX) >> 8); 883889857Sobrien fputs (")", stdout); 883989857Sobrien 884089857Sobrien if (option->info & OEX_PAGE0) 884189857Sobrien fputs (" PAGE0", stdout); 884289857Sobrien if (option->info & OEX_SMM) 884389857Sobrien fputs (" SMM", stdout); 884489857Sobrien if (option->info & OEX_FPDBUG) 884589857Sobrien fputs (" FPDBUG", stdout); 884689857Sobrien if (option->info & OEX_DISMISS) 884789857Sobrien fputs (" DISMISS", stdout); 884889857Sobrien break; 884989857Sobrien case ODK_PAD: 885089857Sobrien fputs (" PAD ", stdout); 885189857Sobrien if (option->info & OPAD_PREFIX) 885289857Sobrien fputs (" PREFIX", stdout); 885389857Sobrien if (option->info & OPAD_POSTFIX) 885489857Sobrien fputs (" POSTFIX", stdout); 885589857Sobrien if (option->info & OPAD_SYMBOL) 885689857Sobrien fputs (" SYMBOL", stdout); 885789857Sobrien break; 885889857Sobrien case ODK_HWPATCH: 885989857Sobrien fputs (" HWPATCH ", stdout); 886089857Sobrien if (option->info & OHW_R4KEOP) 886189857Sobrien fputs (" R4KEOP", stdout); 886289857Sobrien if (option->info & OHW_R8KPFETCH) 886389857Sobrien fputs (" R8KPFETCH", stdout); 886489857Sobrien if (option->info & OHW_R5KEOP) 886589857Sobrien fputs (" R5KEOP", stdout); 886689857Sobrien if (option->info & OHW_R5KCVTL) 886789857Sobrien fputs (" R5KCVTL", stdout); 886889857Sobrien break; 886989857Sobrien case ODK_FILL: 887089857Sobrien fputs (" FILL ", stdout); 887189857Sobrien /* XXX Print content of info word? */ 887289857Sobrien break; 887389857Sobrien case ODK_TAGS: 887489857Sobrien fputs (" TAGS ", stdout); 887589857Sobrien /* XXX Print content of info word? */ 887689857Sobrien break; 887789857Sobrien case ODK_HWAND: 887889857Sobrien fputs (" HWAND ", stdout); 887989857Sobrien if (option->info & OHWA0_R4KEOP_CHECKED) 888089857Sobrien fputs (" R4KEOP_CHECKED", stdout); 888189857Sobrien if (option->info & OHWA0_R4KEOP_CLEAN) 888289857Sobrien fputs (" R4KEOP_CLEAN", stdout); 888389857Sobrien break; 888489857Sobrien case ODK_HWOR: 888589857Sobrien fputs (" HWOR ", stdout); 888689857Sobrien if (option->info & OHWA0_R4KEOP_CHECKED) 888789857Sobrien fputs (" R4KEOP_CHECKED", stdout); 888889857Sobrien if (option->info & OHWA0_R4KEOP_CLEAN) 888989857Sobrien fputs (" R4KEOP_CLEAN", stdout); 889089857Sobrien break; 889189857Sobrien case ODK_GP_GROUP: 889289857Sobrien printf (" GP_GROUP %#06lx self-contained %#06lx", 889389857Sobrien option->info & OGP_GROUP, 889489857Sobrien (option->info & OGP_SELF) >> 16); 889589857Sobrien break; 889689857Sobrien case ODK_IDENT: 889789857Sobrien printf (" IDENT %#06lx self-contained %#06lx", 889889857Sobrien option->info & OGP_GROUP, 889989857Sobrien (option->info & OGP_SELF) >> 16); 890089857Sobrien break; 890189857Sobrien default: 890289857Sobrien /* This shouldn't happen. */ 890389857Sobrien printf (" %3d ??? %d %lx", 890489857Sobrien option->kind, option->section, option->info); 890589857Sobrien break; 890660484Sobrien } 890789857Sobrien 8908130561Sobrien len = sizeof (*eopt); 890989857Sobrien while (len < option->size) 891089857Sobrien if (((char *) option)[len] >= ' ' 891189857Sobrien && ((char *) option)[len] < 0x7f) 891289857Sobrien printf ("%c", ((char *) option)[len++]); 891389857Sobrien else 891489857Sobrien printf ("\\%03o", ((char *) option)[len++]); 891589857Sobrien 891689857Sobrien fputs ("\n", stdout); 891760484Sobrien ++option; 891860484Sobrien } 891960484Sobrien 892089857Sobrien free (eopt); 892160484Sobrien } 892260484Sobrien } 892360484Sobrien 892460484Sobrien if (conflicts_offset != 0 && conflictsno != 0) 892560484Sobrien { 8926130561Sobrien Elf32_Conflict *iconf; 892760484Sobrien size_t cnt; 892860484Sobrien 892960484Sobrien if (dynamic_symbols == NULL) 893060484Sobrien { 8931218822Sdim error (_("conflict list found without a dynamic symbol table\n")); 893260484Sobrien return 0; 893360484Sobrien } 893460484Sobrien 8935218822Sdim iconf = cmalloc (conflictsno, sizeof (*iconf)); 893660484Sobrien if (iconf == NULL) 893760484Sobrien { 8938218822Sdim error (_("Out of memory\n")); 893960484Sobrien return 0; 894060484Sobrien } 894160484Sobrien 894260484Sobrien if (is_32bit_elf) 894360484Sobrien { 8944130561Sobrien Elf32_External_Conflict *econf32; 894560484Sobrien 8946130561Sobrien econf32 = get_data (NULL, file, conflicts_offset, 8947218822Sdim conflictsno, sizeof (*econf32), _("conflict")); 894889857Sobrien if (!econf32) 894989857Sobrien return 0; 895089857Sobrien 895160484Sobrien for (cnt = 0; cnt < conflictsno; ++cnt) 895260484Sobrien iconf[cnt] = BYTE_GET (econf32[cnt]); 895389857Sobrien 895489857Sobrien free (econf32); 895560484Sobrien } 895660484Sobrien else 895760484Sobrien { 8958130561Sobrien Elf64_External_Conflict *econf64; 895960484Sobrien 8960130561Sobrien econf64 = get_data (NULL, file, conflicts_offset, 8961218822Sdim conflictsno, sizeof (*econf64), _("conflict")); 896289857Sobrien if (!econf64) 896389857Sobrien return 0; 896489857Sobrien 896560484Sobrien for (cnt = 0; cnt < conflictsno; ++cnt) 896660484Sobrien iconf[cnt] = BYTE_GET (econf64[cnt]); 896789857Sobrien 896889857Sobrien free (econf64); 896960484Sobrien } 897060484Sobrien 8971130561Sobrien printf (_("\nSection '.conflict' contains %lu entries:\n"), 8972130561Sobrien (unsigned long) conflictsno); 897360484Sobrien puts (_(" Num: Index Value Name")); 897460484Sobrien 897560484Sobrien for (cnt = 0; cnt < conflictsno; ++cnt) 897660484Sobrien { 8977130561Sobrien Elf_Internal_Sym *psym = & dynamic_symbols[iconf[cnt]]; 897860484Sobrien 8979130561Sobrien printf ("%5lu: %8lu ", (unsigned long) cnt, iconf[cnt]); 898060484Sobrien print_vma (psym->st_value, FULL_HEX); 898189857Sobrien putchar (' '); 8982218822Sdim if (VALID_DYNAMIC_NAME (psym->st_name)) 8983218822Sdim print_symbol (25, GET_DYNAMIC_NAME (psym->st_name)); 8984218822Sdim else 8985218822Sdim printf ("<corrupt: %14ld>", psym->st_name); 898689857Sobrien putchar ('\n'); 898760484Sobrien } 898860484Sobrien 898960484Sobrien free (iconf); 899060484Sobrien } 899160484Sobrien 899260484Sobrien return 1; 899360484Sobrien} 899460484Sobrien 8995104834Sobrienstatic int 8996130561Sobrienprocess_gnu_liblist (FILE *file) 8997104834Sobrien{ 8998130561Sobrien Elf_Internal_Shdr *section, *string_sec; 8999130561Sobrien Elf32_External_Lib *elib; 9000130561Sobrien char *strtab; 9001218822Sdim size_t strtab_size; 9002104834Sobrien size_t cnt; 9003104834Sobrien unsigned i; 9004104834Sobrien 9005104834Sobrien if (! do_arch) 9006104834Sobrien return 0; 9007104834Sobrien 9008104834Sobrien for (i = 0, section = section_headers; 9009104834Sobrien i < elf_header.e_shnum; 9010130561Sobrien i++, section++) 9011104834Sobrien { 9012104834Sobrien switch (section->sh_type) 9013104834Sobrien { 9014104834Sobrien case SHT_GNU_LIBLIST: 9015218822Sdim if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum) 9016218822Sdim break; 9017218822Sdim 9018218822Sdim elib = get_data (NULL, file, section->sh_offset, 1, section->sh_size, 9019130561Sobrien _("liblist")); 9020104834Sobrien 9021104834Sobrien if (elib == NULL) 9022104834Sobrien break; 9023104834Sobrien string_sec = SECTION_HEADER (section->sh_link); 9024104834Sobrien 9025218822Sdim strtab = get_data (NULL, file, string_sec->sh_offset, 1, 9026130561Sobrien string_sec->sh_size, _("liblist string table")); 9027218822Sdim strtab_size = string_sec->sh_size; 9028104834Sobrien 9029104834Sobrien if (strtab == NULL 9030104834Sobrien || section->sh_entsize != sizeof (Elf32_External_Lib)) 9031104834Sobrien { 9032104834Sobrien free (elib); 9033104834Sobrien break; 9034104834Sobrien } 9035104834Sobrien 9036104834Sobrien printf (_("\nLibrary list section '%s' contains %lu entries:\n"), 9037104834Sobrien SECTION_NAME (section), 9038104834Sobrien (long) (section->sh_size / sizeof (Elf32_External_Lib))); 9039104834Sobrien 9040104834Sobrien puts (" Library Time Stamp Checksum Version Flags"); 9041104834Sobrien 9042104834Sobrien for (cnt = 0; cnt < section->sh_size / sizeof (Elf32_External_Lib); 9043104834Sobrien ++cnt) 9044104834Sobrien { 9045104834Sobrien Elf32_Lib liblist; 9046104834Sobrien time_t time; 9047104834Sobrien char timebuf[20]; 9048130561Sobrien struct tm *tmp; 9049104834Sobrien 9050104834Sobrien liblist.l_name = BYTE_GET (elib[cnt].l_name); 9051104834Sobrien time = BYTE_GET (elib[cnt].l_time_stamp); 9052104834Sobrien liblist.l_checksum = BYTE_GET (elib[cnt].l_checksum); 9053104834Sobrien liblist.l_version = BYTE_GET (elib[cnt].l_version); 9054104834Sobrien liblist.l_flags = BYTE_GET (elib[cnt].l_flags); 9055104834Sobrien 9056104834Sobrien tmp = gmtime (&time); 9057218822Sdim snprintf (timebuf, sizeof (timebuf), 9058218822Sdim "%04u-%02u-%02uT%02u:%02u:%02u", 9059218822Sdim tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, 9060218822Sdim tmp->tm_hour, tmp->tm_min, tmp->tm_sec); 9061104834Sobrien 9062104834Sobrien printf ("%3lu: ", (unsigned long) cnt); 9063104834Sobrien if (do_wide) 9064218822Sdim printf ("%-20s", liblist.l_name < strtab_size 9065218822Sdim ? strtab + liblist.l_name : "<corrupt>"); 9066104834Sobrien else 9067218822Sdim printf ("%-20.20s", liblist.l_name < strtab_size 9068218822Sdim ? strtab + liblist.l_name : "<corrupt>"); 9069104834Sobrien printf (" %s %#010lx %-7ld %-7ld\n", timebuf, liblist.l_checksum, 9070104834Sobrien liblist.l_version, liblist.l_flags); 9071104834Sobrien } 9072104834Sobrien 9073104834Sobrien free (elib); 9074104834Sobrien } 9075104834Sobrien } 9076104834Sobrien 9077104834Sobrien return 1; 9078104834Sobrien} 9079104834Sobrien 908089857Sobrienstatic const char * 9081130561Sobrienget_note_type (unsigned e_type) 908260484Sobrien{ 908360484Sobrien static char buff[64]; 908460484Sobrien 9085218822Sdim if (elf_header.e_type == ET_CORE) 9086218822Sdim switch (e_type) 9087218822Sdim { 9088218822Sdim case NT_AUXV: 9089218822Sdim return _("NT_AUXV (auxiliary vector)"); 9090218822Sdim case NT_PRSTATUS: 9091218822Sdim return _("NT_PRSTATUS (prstatus structure)"); 9092218822Sdim case NT_FPREGSET: 9093218822Sdim return _("NT_FPREGSET (floating point registers)"); 9094218822Sdim case NT_PRPSINFO: 9095218822Sdim return _("NT_PRPSINFO (prpsinfo structure)"); 9096218822Sdim case NT_TASKSTRUCT: 9097218822Sdim return _("NT_TASKSTRUCT (task structure)"); 9098218822Sdim case NT_PRXFPREG: 9099218822Sdim return _("NT_PRXFPREG (user_xfpregs structure)"); 9100218822Sdim case NT_PSTATUS: 9101218822Sdim return _("NT_PSTATUS (pstatus structure)"); 9102218822Sdim case NT_FPREGS: 9103218822Sdim return _("NT_FPREGS (floating point registers)"); 9104218822Sdim case NT_PSINFO: 9105218822Sdim return _("NT_PSINFO (psinfo structure)"); 9106218822Sdim case NT_THRMISC: 9107218822Sdim return _("NT_THRMISC (thrmisc structure)"); 9108218822Sdim case NT_LWPSTATUS: 9109218822Sdim return _("NT_LWPSTATUS (lwpstatus_t structure)"); 9110218822Sdim case NT_LWPSINFO: 9111218822Sdim return _("NT_LWPSINFO (lwpsinfo_t structure)"); 9112218822Sdim case NT_WIN32PSTATUS: 9113218822Sdim return _("NT_WIN32PSTATUS (win32_pstatus structure)"); 9114218822Sdim default: 9115218822Sdim break; 9116218822Sdim } 9117218822Sdim else 9118218822Sdim switch (e_type) 9119218822Sdim { 9120218822Sdim case NT_VERSION: 9121218822Sdim return _("NT_VERSION (version)"); 9122218822Sdim case NT_ARCH: 9123218822Sdim return _("NT_ARCH (architecture)"); 9124218822Sdim default: 9125218822Sdim break; 9126218822Sdim } 9127218822Sdim 9128218822Sdim snprintf (buff, sizeof (buff), _("Unknown note type: (0x%08x)"), e_type); 9129218822Sdim return buff; 913060484Sobrien} 913160484Sobrien 913289857Sobrienstatic const char * 9133130561Sobrienget_netbsd_elfcore_note_type (unsigned e_type) 913489857Sobrien{ 913589857Sobrien static char buff[64]; 913689857Sobrien 913789857Sobrien if (e_type == NT_NETBSDCORE_PROCINFO) 913889857Sobrien { 913989857Sobrien /* NetBSD core "procinfo" structure. */ 914089857Sobrien return _("NetBSD procinfo structure"); 914189857Sobrien } 914289857Sobrien 914389857Sobrien /* As of Jan 2002 there are no other machine-independent notes 914489857Sobrien defined for NetBSD core files. If the note type is less 914589857Sobrien than the start of the machine-dependent note types, we don't 914689857Sobrien understand it. */ 914789857Sobrien 914889857Sobrien if (e_type < NT_NETBSDCORE_FIRSTMACH) 914989857Sobrien { 9150218822Sdim snprintf (buff, sizeof (buff), _("Unknown note type: (0x%08x)"), e_type); 915189857Sobrien return buff; 915289857Sobrien } 915389857Sobrien 915489857Sobrien switch (elf_header.e_machine) 915589857Sobrien { 915689857Sobrien /* On the Alpha, SPARC (32-bit and 64-bit), PT_GETREGS == mach+0 915789857Sobrien and PT_GETFPREGS == mach+2. */ 915889857Sobrien 915989857Sobrien case EM_OLD_ALPHA: 916089857Sobrien case EM_ALPHA: 916189857Sobrien case EM_SPARC: 916289857Sobrien case EM_SPARC32PLUS: 916389857Sobrien case EM_SPARCV9: 916489857Sobrien switch (e_type) 916589857Sobrien { 916689857Sobrien case NT_NETBSDCORE_FIRSTMACH+0: 916789857Sobrien return _("PT_GETREGS (reg structure)"); 916889857Sobrien case NT_NETBSDCORE_FIRSTMACH+2: 916989857Sobrien return _("PT_GETFPREGS (fpreg structure)"); 917089857Sobrien default: 917189857Sobrien break; 917289857Sobrien } 917389857Sobrien break; 917489857Sobrien 917589857Sobrien /* On all other arch's, PT_GETREGS == mach+1 and 917689857Sobrien PT_GETFPREGS == mach+3. */ 917789857Sobrien default: 917889857Sobrien switch (e_type) 917989857Sobrien { 918089857Sobrien case NT_NETBSDCORE_FIRSTMACH+1: 918189857Sobrien return _("PT_GETREGS (reg structure)"); 918289857Sobrien case NT_NETBSDCORE_FIRSTMACH+3: 918389857Sobrien return _("PT_GETFPREGS (fpreg structure)"); 918489857Sobrien default: 918589857Sobrien break; 918689857Sobrien } 918789857Sobrien } 918889857Sobrien 9189218822Sdim snprintf (buff, sizeof (buff), _("PT_FIRSTMACH+%d"), 9190218822Sdim e_type - NT_NETBSDCORE_FIRSTMACH); 919189857Sobrien return buff; 919289857Sobrien} 919389857Sobrien 919460484Sobrien/* Note that by the ELF standard, the name field is already null byte 919560484Sobrien terminated, and namesz includes the terminating null byte. 919660484Sobrien I.E. the value of namesz for the name "FSF" is 4. 919760484Sobrien 919889857Sobrien If the value of namesz is zero, there is no name present. */ 919960484Sobrienstatic int 9200130561Sobrienprocess_note (Elf_Internal_Note *pnote) 920160484Sobrien{ 920289857Sobrien const char *nt; 920389857Sobrien 920489857Sobrien if (pnote->namesz == 0) 9205218822Sdim /* If there is no note name, then use the default set of 9206218822Sdim note type strings. */ 9207218822Sdim nt = get_note_type (pnote->type); 9208218822Sdim 9209218822Sdim else if (const_strneq (pnote->namedata, "NetBSD-CORE")) 9210218822Sdim /* NetBSD-specific core file notes. */ 9211218822Sdim nt = get_netbsd_elfcore_note_type (pnote->type); 9212218822Sdim 921389857Sobrien else 9214218822Sdim /* Don't recognize this note name; just use the default set of 9215218822Sdim note type strings. */ 921689857Sobrien nt = get_note_type (pnote->type); 921789857Sobrien 921860484Sobrien printf (" %s\t\t0x%08lx\t%s\n", 921960484Sobrien pnote->namesz ? pnote->namedata : "(NONE)", 922089857Sobrien pnote->descsz, nt); 922160484Sobrien return 1; 922260484Sobrien} 922360484Sobrien 922460484Sobrien 922560484Sobrienstatic int 9226130561Sobrienprocess_corefile_note_segment (FILE *file, bfd_vma offset, bfd_vma length) 922760484Sobrien{ 9228130561Sobrien Elf_External_Note *pnotes; 9229130561Sobrien Elf_External_Note *external; 9230130561Sobrien int res = 1; 923160484Sobrien 923260484Sobrien if (length <= 0) 923360484Sobrien return 0; 923460484Sobrien 9235218822Sdim pnotes = get_data (NULL, file, offset, 1, length, _("notes")); 923689857Sobrien if (!pnotes) 923789857Sobrien return 0; 923860484Sobrien 923960484Sobrien external = pnotes; 924060484Sobrien 924160484Sobrien printf (_("\nNotes at offset 0x%08lx with length 0x%08lx:\n"), 924277298Sobrien (unsigned long) offset, (unsigned long) length); 924360484Sobrien printf (_(" Owner\t\tData size\tDescription\n")); 924460484Sobrien 924560484Sobrien while (external < (Elf_External_Note *)((char *) pnotes + length)) 924660484Sobrien { 9247130561Sobrien Elf_External_Note *next; 9248130561Sobrien Elf_Internal_Note inote; 9249130561Sobrien char *temp = NULL; 925060484Sobrien 925160484Sobrien inote.type = BYTE_GET (external->type); 925260484Sobrien inote.namesz = BYTE_GET (external->namesz); 925360484Sobrien inote.namedata = external->name; 925460484Sobrien inote.descsz = BYTE_GET (external->descsz); 925560484Sobrien inote.descdata = inote.namedata + align_power (inote.namesz, 2); 925660484Sobrien inote.descpos = offset + (inote.descdata - (char *) pnotes); 925777298Sobrien 925899461Sobrien next = (Elf_External_Note *)(inote.descdata + align_power (inote.descsz, 2)); 925960484Sobrien 926099461Sobrien if (((char *) next) > (((char *) pnotes) + length)) 926199461Sobrien { 9262218822Sdim warn (_("corrupt note found at offset %lx into core notes\n"), 9263218822Sdim (long)((char *)external - (char *)pnotes)); 9264218822Sdim warn (_(" type: %lx, namesize: %08lx, descsize: %08lx\n"), 926599461Sobrien inote.type, inote.namesz, inote.descsz); 926699461Sobrien break; 926799461Sobrien } 926899461Sobrien 926999461Sobrien external = next; 927099461Sobrien 927160484Sobrien /* Verify that name is null terminated. It appears that at least 927260484Sobrien one version of Linux (RedHat 6.0) generates corefiles that don't 927360484Sobrien comply with the ELF spec by failing to include the null byte in 927460484Sobrien namesz. */ 927560484Sobrien if (inote.namedata[inote.namesz] != '\0') 927660484Sobrien { 927760484Sobrien temp = malloc (inote.namesz + 1); 927877298Sobrien 927960484Sobrien if (temp == NULL) 928060484Sobrien { 928160484Sobrien error (_("Out of memory\n")); 928260484Sobrien res = 0; 928360484Sobrien break; 928460484Sobrien } 928577298Sobrien 928660484Sobrien strncpy (temp, inote.namedata, inote.namesz); 928760484Sobrien temp[inote.namesz] = 0; 928877298Sobrien 928960484Sobrien /* warn (_("'%s' NOTE name not properly null terminated\n"), temp); */ 929060484Sobrien inote.namedata = temp; 929160484Sobrien } 929260484Sobrien 929360484Sobrien res &= process_note (& inote); 929460484Sobrien 929560484Sobrien if (temp != NULL) 929660484Sobrien { 929760484Sobrien free (temp); 929860484Sobrien temp = NULL; 929960484Sobrien } 930060484Sobrien } 930160484Sobrien 930260484Sobrien free (pnotes); 930360484Sobrien 930460484Sobrien return res; 930560484Sobrien} 930660484Sobrien 930760484Sobrienstatic int 9308130561Sobrienprocess_corefile_note_segments (FILE *file) 930960484Sobrien{ 9310130561Sobrien Elf_Internal_Phdr *segment; 9311130561Sobrien unsigned int i; 9312130561Sobrien int res = 1; 931360484Sobrien 9314130561Sobrien if (! get_program_headers (file)) 931560484Sobrien return 0; 931660484Sobrien 931760484Sobrien for (i = 0, segment = program_headers; 931860484Sobrien i < elf_header.e_phnum; 9319130561Sobrien i++, segment++) 932060484Sobrien { 932160484Sobrien if (segment->p_type == PT_NOTE) 932260484Sobrien res &= process_corefile_note_segment (file, 932360484Sobrien (bfd_vma) segment->p_offset, 932460484Sobrien (bfd_vma) segment->p_filesz); 932560484Sobrien } 932660484Sobrien 932760484Sobrien return res; 932860484Sobrien} 932960484Sobrien 933060484Sobrienstatic int 9331218822Sdimprocess_note_sections (FILE *file) 933260484Sobrien{ 9333218822Sdim Elf_Internal_Shdr *section; 9334218822Sdim unsigned long i; 9335218822Sdim int res = 1; 9336218822Sdim 9337218822Sdim for (i = 0, section = section_headers; 9338218822Sdim i < elf_header.e_shnum; 9339218822Sdim i++, section++) 9340218822Sdim if (section->sh_type == SHT_NOTE) 9341218822Sdim res &= process_corefile_note_segment (file, 9342218822Sdim (bfd_vma) section->sh_offset, 9343218822Sdim (bfd_vma) section->sh_size); 9344218822Sdim 9345218822Sdim return res; 9346218822Sdim} 9347218822Sdim 9348218822Sdimstatic int 9349218822Sdimprocess_notes (FILE *file) 9350218822Sdim{ 935160484Sobrien /* If we have not been asked to display the notes then do nothing. */ 935260484Sobrien if (! do_notes) 935360484Sobrien return 1; 935460484Sobrien 935560484Sobrien if (elf_header.e_type != ET_CORE) 9356218822Sdim return process_note_sections (file); 935760484Sobrien 935860484Sobrien /* No program headers means no NOTE segment. */ 9359218822Sdim if (elf_header.e_phnum > 0) 9360218822Sdim return process_corefile_note_segments (file); 936160484Sobrien 9362218822Sdim printf (_("No note segments present in the core file.\n")); 9363218822Sdim return 1; 936460484Sobrien} 936560484Sobrien 936660484Sobrienstatic int 9367130561Sobrienprocess_arch_specific (FILE *file) 936860484Sobrien{ 936960484Sobrien if (! do_arch) 937060484Sobrien return 1; 937160484Sobrien 937260484Sobrien switch (elf_header.e_machine) 937360484Sobrien { 9374218822Sdim case EM_ARM: 9375218822Sdim return process_arm_specific (file); 937660484Sobrien case EM_MIPS: 937778828Sobrien case EM_MIPS_RS3_LE: 937860484Sobrien return process_mips_specific (file); 937960484Sobrien break; 9380218822Sdim case EM_PPC: 9381218822Sdim return process_power_specific (file); 9382218822Sdim break; 938360484Sobrien default: 938460484Sobrien break; 938560484Sobrien } 938660484Sobrien return 1; 938760484Sobrien} 938860484Sobrien 938960484Sobrienstatic int 9390130561Sobrienget_file_header (FILE *file) 939160484Sobrien{ 939260484Sobrien /* Read in the identity array. */ 939360484Sobrien if (fread (elf_header.e_ident, EI_NIDENT, 1, file) != 1) 939460484Sobrien return 0; 939560484Sobrien 939660484Sobrien /* Determine how to read the rest of the header. */ 9397130561Sobrien switch (elf_header.e_ident[EI_DATA]) 939860484Sobrien { 939960484Sobrien default: /* fall through */ 940060484Sobrien case ELFDATANONE: /* fall through */ 9401130561Sobrien case ELFDATA2LSB: 9402130561Sobrien byte_get = byte_get_little_endian; 9403130561Sobrien byte_put = byte_put_little_endian; 9404130561Sobrien break; 9405130561Sobrien case ELFDATA2MSB: 9406130561Sobrien byte_get = byte_get_big_endian; 9407130561Sobrien byte_put = byte_put_big_endian; 9408130561Sobrien break; 940960484Sobrien } 941060484Sobrien 941160484Sobrien /* For now we only support 32 bit and 64 bit ELF files. */ 9412130561Sobrien is_32bit_elf = (elf_header.e_ident[EI_CLASS] != ELFCLASS64); 941360484Sobrien 941460484Sobrien /* Read in the rest of the header. */ 941560484Sobrien if (is_32bit_elf) 941660484Sobrien { 941760484Sobrien Elf32_External_Ehdr ehdr32; 941860484Sobrien 941960484Sobrien if (fread (ehdr32.e_type, sizeof (ehdr32) - EI_NIDENT, 1, file) != 1) 942060484Sobrien return 0; 942160484Sobrien 942260484Sobrien elf_header.e_type = BYTE_GET (ehdr32.e_type); 942360484Sobrien elf_header.e_machine = BYTE_GET (ehdr32.e_machine); 942460484Sobrien elf_header.e_version = BYTE_GET (ehdr32.e_version); 942560484Sobrien elf_header.e_entry = BYTE_GET (ehdr32.e_entry); 942660484Sobrien elf_header.e_phoff = BYTE_GET (ehdr32.e_phoff); 942760484Sobrien elf_header.e_shoff = BYTE_GET (ehdr32.e_shoff); 942860484Sobrien elf_header.e_flags = BYTE_GET (ehdr32.e_flags); 942960484Sobrien elf_header.e_ehsize = BYTE_GET (ehdr32.e_ehsize); 943060484Sobrien elf_header.e_phentsize = BYTE_GET (ehdr32.e_phentsize); 943160484Sobrien elf_header.e_phnum = BYTE_GET (ehdr32.e_phnum); 943260484Sobrien elf_header.e_shentsize = BYTE_GET (ehdr32.e_shentsize); 943360484Sobrien elf_header.e_shnum = BYTE_GET (ehdr32.e_shnum); 943460484Sobrien elf_header.e_shstrndx = BYTE_GET (ehdr32.e_shstrndx); 943560484Sobrien } 943660484Sobrien else 943760484Sobrien { 943860484Sobrien Elf64_External_Ehdr ehdr64; 943960484Sobrien 944060484Sobrien /* If we have been compiled with sizeof (bfd_vma) == 4, then 944160484Sobrien we will not be able to cope with the 64bit data found in 944260484Sobrien 64 ELF files. Detect this now and abort before we start 9443130561Sobrien overwriting things. */ 944460484Sobrien if (sizeof (bfd_vma) < 8) 944560484Sobrien { 944689857Sobrien error (_("This instance of readelf has been built without support for a\n\ 944789857Sobrien64 bit data type and so it cannot read 64 bit ELF files.\n")); 944860484Sobrien return 0; 944960484Sobrien } 945060484Sobrien 945160484Sobrien if (fread (ehdr64.e_type, sizeof (ehdr64) - EI_NIDENT, 1, file) != 1) 945260484Sobrien return 0; 945360484Sobrien 945460484Sobrien elf_header.e_type = BYTE_GET (ehdr64.e_type); 945560484Sobrien elf_header.e_machine = BYTE_GET (ehdr64.e_machine); 945660484Sobrien elf_header.e_version = BYTE_GET (ehdr64.e_version); 9457218822Sdim elf_header.e_entry = BYTE_GET (ehdr64.e_entry); 9458218822Sdim elf_header.e_phoff = BYTE_GET (ehdr64.e_phoff); 9459218822Sdim elf_header.e_shoff = BYTE_GET (ehdr64.e_shoff); 946060484Sobrien elf_header.e_flags = BYTE_GET (ehdr64.e_flags); 946160484Sobrien elf_header.e_ehsize = BYTE_GET (ehdr64.e_ehsize); 946260484Sobrien elf_header.e_phentsize = BYTE_GET (ehdr64.e_phentsize); 946360484Sobrien elf_header.e_phnum = BYTE_GET (ehdr64.e_phnum); 946460484Sobrien elf_header.e_shentsize = BYTE_GET (ehdr64.e_shentsize); 946560484Sobrien elf_header.e_shnum = BYTE_GET (ehdr64.e_shnum); 946660484Sobrien elf_header.e_shstrndx = BYTE_GET (ehdr64.e_shstrndx); 946760484Sobrien } 946860484Sobrien 9469104834Sobrien if (elf_header.e_shoff) 9470104834Sobrien { 9471104834Sobrien /* There may be some extensions in the first section header. Don't 9472104834Sobrien bomb if we can't read it. */ 9473104834Sobrien if (is_32bit_elf) 9474104834Sobrien get_32bit_section_headers (file, 1); 9475104834Sobrien else 9476104834Sobrien get_64bit_section_headers (file, 1); 9477104834Sobrien } 947889857Sobrien 9479218822Sdim is_relocatable = elf_header.e_type == ET_REL; 9480218822Sdim 948160484Sobrien return 1; 948260484Sobrien} 948360484Sobrien 9484130561Sobrien/* Process one ELF object file according to the command line options. 9485130561Sobrien This file may actually be stored in an archive. The file is 9486130561Sobrien positioned at the start of the ELF object. */ 9487130561Sobrien 948889857Sobrienstatic int 9489130561Sobrienprocess_object (char *file_name, FILE *file) 949060484Sobrien{ 949160484Sobrien unsigned int i; 949260484Sobrien 949360484Sobrien if (! get_file_header (file)) 949460484Sobrien { 949560484Sobrien error (_("%s: Failed to read file header\n"), file_name); 949689857Sobrien return 1; 949760484Sobrien } 949860484Sobrien 949960484Sobrien /* Initialise per file variables. */ 950060484Sobrien for (i = NUM_ELEM (version_info); i--;) 950160484Sobrien version_info[i] = 0; 950260484Sobrien 950360484Sobrien for (i = NUM_ELEM (dynamic_info); i--;) 950460484Sobrien dynamic_info[i] = 0; 950560484Sobrien 950660484Sobrien /* Process the file. */ 950760484Sobrien if (show_name) 950860484Sobrien printf (_("\nFile: %s\n"), file_name); 950960484Sobrien 9510218822Sdim /* Initialise the dump_sects array from the cmdline_dump_sects array. 9511218822Sdim Note we do this even if cmdline_dump_sects is empty because we 9512218822Sdim must make sure that the dump_sets array is zeroed out before each 9513218822Sdim object file is processed. */ 9514218822Sdim if (num_dump_sects > num_cmdline_dump_sects) 9515218822Sdim memset (dump_sects, 0, num_dump_sects); 9516218822Sdim 9517218822Sdim if (num_cmdline_dump_sects > 0) 9518218822Sdim { 9519218822Sdim if (num_dump_sects == 0) 9520218822Sdim /* A sneaky way of allocating the dump_sects array. */ 9521218822Sdim request_dump (num_cmdline_dump_sects, 0); 9522218822Sdim 9523218822Sdim assert (num_dump_sects >= num_cmdline_dump_sects); 9524218822Sdim memcpy (dump_sects, cmdline_dump_sects, num_cmdline_dump_sects); 9525218822Sdim } 9526218822Sdim 952760484Sobrien if (! process_file_header ()) 9528130561Sobrien return 1; 9529130561Sobrien 9530130561Sobrien if (! process_section_headers (file)) 953160484Sobrien { 9532218822Sdim /* Without loaded section headers we cannot process lots of 9533218822Sdim things. */ 9534130561Sobrien do_unwind = do_version = do_dump = do_arch = 0; 9535130561Sobrien 9536130561Sobrien if (! do_using_dynamic) 9537130561Sobrien do_syms = do_reloc = 0; 953860484Sobrien } 953960484Sobrien 9540218822Sdim if (! process_section_groups (file)) 9541218822Sdim { 9542218822Sdim /* Without loaded section groups we cannot process unwind. */ 9543218822Sdim do_unwind = 0; 9544218822Sdim } 9545218822Sdim 9546130561Sobrien if (process_program_headers (file)) 9547218822Sdim process_dynamic_section (file); 954860484Sobrien 954960484Sobrien process_relocs (file); 955060484Sobrien 955178828Sobrien process_unwind (file); 955278828Sobrien 955360484Sobrien process_symbol_table (file); 955460484Sobrien 955560484Sobrien process_syminfo (file); 955660484Sobrien 955760484Sobrien process_version_sections (file); 955860484Sobrien 955960484Sobrien process_section_contents (file); 956060484Sobrien 9561218822Sdim process_notes (file); 956260484Sobrien 9563104834Sobrien process_gnu_liblist (file); 9564104834Sobrien 956560484Sobrien process_arch_specific (file); 956660484Sobrien 9567130561Sobrien if (program_headers) 9568130561Sobrien { 9569130561Sobrien free (program_headers); 9570130561Sobrien program_headers = NULL; 9571130561Sobrien } 957260484Sobrien 957360484Sobrien if (section_headers) 957460484Sobrien { 957560484Sobrien free (section_headers); 957660484Sobrien section_headers = NULL; 957760484Sobrien } 957860484Sobrien 957960484Sobrien if (string_table) 958060484Sobrien { 958160484Sobrien free (string_table); 958260484Sobrien string_table = NULL; 958377298Sobrien string_table_length = 0; 958460484Sobrien } 958560484Sobrien 958660484Sobrien if (dynamic_strings) 958760484Sobrien { 958860484Sobrien free (dynamic_strings); 958960484Sobrien dynamic_strings = NULL; 9590218822Sdim dynamic_strings_length = 0; 959160484Sobrien } 959260484Sobrien 959360484Sobrien if (dynamic_symbols) 959460484Sobrien { 959560484Sobrien free (dynamic_symbols); 959660484Sobrien dynamic_symbols = NULL; 959760484Sobrien num_dynamic_syms = 0; 959860484Sobrien } 959960484Sobrien 960060484Sobrien if (dynamic_syminfo) 960160484Sobrien { 960260484Sobrien free (dynamic_syminfo); 960360484Sobrien dynamic_syminfo = NULL; 960460484Sobrien } 960589857Sobrien 9606218822Sdim if (section_headers_groups) 9607218822Sdim { 9608218822Sdim free (section_headers_groups); 9609218822Sdim section_headers_groups = NULL; 9610218822Sdim } 9611218822Sdim 9612218822Sdim if (section_groups) 9613218822Sdim { 9614218822Sdim struct group_list *g, *next; 9615218822Sdim 9616218822Sdim for (i = 0; i < group_count; i++) 9617218822Sdim { 9618218822Sdim for (g = section_groups [i].root; g != NULL; g = next) 9619218822Sdim { 9620218822Sdim next = g->next; 9621218822Sdim free (g); 9622218822Sdim } 9623218822Sdim } 9624218822Sdim 9625218822Sdim free (section_groups); 9626218822Sdim section_groups = NULL; 9627218822Sdim } 9628218822Sdim 9629218822Sdim free_debug_memory (); 9630218822Sdim 963189857Sobrien return 0; 963260484Sobrien} 963360484Sobrien 9634130561Sobrien/* Process an ELF archive. The file is positioned just after the 9635130561Sobrien ARMAG string. */ 9636130561Sobrien 9637130561Sobrienstatic int 9638130561Sobrienprocess_archive (char *file_name, FILE *file) 9639130561Sobrien{ 9640130561Sobrien struct ar_hdr arhdr; 9641130561Sobrien size_t got; 9642130561Sobrien unsigned long size; 9643130561Sobrien char *longnames = NULL; 9644130561Sobrien unsigned long longnames_size = 0; 9645130561Sobrien size_t file_name_size; 9646130561Sobrien int ret; 9647130561Sobrien 9648130561Sobrien show_name = 1; 9649130561Sobrien 9650130561Sobrien got = fread (&arhdr, 1, sizeof arhdr, file); 9651130561Sobrien if (got != sizeof arhdr) 9652130561Sobrien { 9653130561Sobrien if (got == 0) 9654130561Sobrien return 0; 9655130561Sobrien 9656130561Sobrien error (_("%s: failed to read archive header\n"), file_name); 9657130561Sobrien return 1; 9658130561Sobrien } 9659130561Sobrien 9660218822Sdim if (const_strneq (arhdr.ar_name, "/ ")) 9661130561Sobrien { 9662130561Sobrien /* This is the archive symbol table. Skip it. 9663130561Sobrien FIXME: We should have an option to dump it. */ 9664130561Sobrien size = strtoul (arhdr.ar_size, NULL, 10); 9665130561Sobrien if (fseek (file, size + (size & 1), SEEK_CUR) != 0) 9666130561Sobrien { 9667130561Sobrien error (_("%s: failed to skip archive symbol table\n"), file_name); 9668130561Sobrien return 1; 9669130561Sobrien } 9670130561Sobrien 9671130561Sobrien got = fread (&arhdr, 1, sizeof arhdr, file); 9672130561Sobrien if (got != sizeof arhdr) 9673130561Sobrien { 9674130561Sobrien if (got == 0) 9675130561Sobrien return 0; 9676130561Sobrien 9677130561Sobrien error (_("%s: failed to read archive header\n"), file_name); 9678130561Sobrien return 1; 9679130561Sobrien } 9680130561Sobrien } 9681130561Sobrien 9682218822Sdim if (const_strneq (arhdr.ar_name, "// ")) 9683130561Sobrien { 9684130561Sobrien /* This is the archive string table holding long member 9685130561Sobrien names. */ 9686130561Sobrien 9687130561Sobrien longnames_size = strtoul (arhdr.ar_size, NULL, 10); 9688130561Sobrien 9689130561Sobrien longnames = malloc (longnames_size); 9690130561Sobrien if (longnames == NULL) 9691130561Sobrien { 9692130561Sobrien error (_("Out of memory\n")); 9693130561Sobrien return 1; 9694130561Sobrien } 9695130561Sobrien 9696130561Sobrien if (fread (longnames, longnames_size, 1, file) != 1) 9697130561Sobrien { 9698130561Sobrien free (longnames); 9699218822Sdim error (_("%s: failed to read string table\n"), file_name); 9700130561Sobrien return 1; 9701130561Sobrien } 9702130561Sobrien 9703130561Sobrien if ((longnames_size & 1) != 0) 9704222204Sbenl (void) getc (file); 9705130561Sobrien 9706130561Sobrien got = fread (&arhdr, 1, sizeof arhdr, file); 9707130561Sobrien if (got != sizeof arhdr) 9708130561Sobrien { 9709130561Sobrien free (longnames); 9710130561Sobrien 9711130561Sobrien if (got == 0) 9712130561Sobrien return 0; 9713130561Sobrien 9714130561Sobrien error (_("%s: failed to read archive header\n"), file_name); 9715130561Sobrien return 1; 9716130561Sobrien } 9717130561Sobrien } 9718130561Sobrien 9719130561Sobrien file_name_size = strlen (file_name); 9720130561Sobrien ret = 0; 9721130561Sobrien 9722130561Sobrien while (1) 9723130561Sobrien { 9724130561Sobrien char *name; 9725130561Sobrien char *nameend; 9726130561Sobrien char *namealc; 9727130561Sobrien 9728130561Sobrien if (arhdr.ar_name[0] == '/') 9729130561Sobrien { 9730130561Sobrien unsigned long off; 9731130561Sobrien 9732130561Sobrien off = strtoul (arhdr.ar_name + 1, NULL, 10); 9733130561Sobrien if (off >= longnames_size) 9734130561Sobrien { 9735218822Sdim error (_("%s: invalid archive string table offset %lu\n"), file_name, off); 9736130561Sobrien ret = 1; 9737130561Sobrien break; 9738130561Sobrien } 9739130561Sobrien 9740130561Sobrien name = longnames + off; 9741130561Sobrien nameend = memchr (name, '/', longnames_size - off); 9742130561Sobrien } 9743130561Sobrien else 9744130561Sobrien { 9745130561Sobrien name = arhdr.ar_name; 9746130561Sobrien nameend = memchr (name, '/', 16); 9747130561Sobrien } 9748130561Sobrien 9749130561Sobrien if (nameend == NULL) 9750130561Sobrien { 9751218822Sdim error (_("%s: bad archive file name\n"), file_name); 9752130561Sobrien ret = 1; 9753130561Sobrien break; 9754130561Sobrien } 9755130561Sobrien 9756130561Sobrien namealc = malloc (file_name_size + (nameend - name) + 3); 9757130561Sobrien if (namealc == NULL) 9758130561Sobrien { 9759130561Sobrien error (_("Out of memory\n")); 9760130561Sobrien ret = 1; 9761130561Sobrien break; 9762130561Sobrien } 9763130561Sobrien 9764130561Sobrien memcpy (namealc, file_name, file_name_size); 9765130561Sobrien namealc[file_name_size] = '('; 9766130561Sobrien memcpy (namealc + file_name_size + 1, name, nameend - name); 9767130561Sobrien namealc[file_name_size + 1 + (nameend - name)] = ')'; 9768130561Sobrien namealc[file_name_size + 2 + (nameend - name)] = '\0'; 9769130561Sobrien 9770130561Sobrien archive_file_offset = ftell (file); 9771130561Sobrien archive_file_size = strtoul (arhdr.ar_size, NULL, 10); 9772130561Sobrien 9773130561Sobrien ret |= process_object (namealc, file); 9774130561Sobrien 9775130561Sobrien free (namealc); 9776130561Sobrien 9777130561Sobrien if (fseek (file, 9778130561Sobrien (archive_file_offset 9779130561Sobrien + archive_file_size 9780130561Sobrien + (archive_file_size & 1)), 9781130561Sobrien SEEK_SET) != 0) 9782130561Sobrien { 9783130561Sobrien error (_("%s: failed to seek to next archive header\n"), file_name); 9784130561Sobrien ret = 1; 9785130561Sobrien break; 9786130561Sobrien } 9787130561Sobrien 9788130561Sobrien got = fread (&arhdr, 1, sizeof arhdr, file); 9789130561Sobrien if (got != sizeof arhdr) 9790130561Sobrien { 9791130561Sobrien if (got == 0) 9792130561Sobrien break; 9793130561Sobrien 9794130561Sobrien error (_("%s: failed to read archive header\n"), file_name); 9795130561Sobrien ret = 1; 9796130561Sobrien break; 9797130561Sobrien } 9798130561Sobrien } 9799130561Sobrien 9800130561Sobrien if (longnames != 0) 9801130561Sobrien free (longnames); 9802130561Sobrien 9803130561Sobrien return ret; 9804130561Sobrien} 9805130561Sobrien 9806130561Sobrienstatic int 9807130561Sobrienprocess_file (char *file_name) 9808130561Sobrien{ 9809130561Sobrien FILE *file; 9810130561Sobrien struct stat statbuf; 9811130561Sobrien char armag[SARMAG]; 9812130561Sobrien int ret; 9813130561Sobrien 9814130561Sobrien if (stat (file_name, &statbuf) < 0) 9815130561Sobrien { 9816130561Sobrien if (errno == ENOENT) 9817130561Sobrien error (_("'%s': No such file\n"), file_name); 9818130561Sobrien else 9819130561Sobrien error (_("Could not locate '%s'. System error message: %s\n"), 9820130561Sobrien file_name, strerror (errno)); 9821130561Sobrien return 1; 9822130561Sobrien } 9823130561Sobrien 9824130561Sobrien if (! S_ISREG (statbuf.st_mode)) 9825130561Sobrien { 9826130561Sobrien error (_("'%s' is not an ordinary file\n"), file_name); 9827130561Sobrien return 1; 9828130561Sobrien } 9829130561Sobrien 9830130561Sobrien file = fopen (file_name, "rb"); 9831130561Sobrien if (file == NULL) 9832130561Sobrien { 9833130561Sobrien error (_("Input file '%s' is not readable.\n"), file_name); 9834130561Sobrien return 1; 9835130561Sobrien } 9836130561Sobrien 9837130561Sobrien if (fread (armag, SARMAG, 1, file) != 1) 9838130561Sobrien { 9839130561Sobrien error (_("%s: Failed to read file header\n"), file_name); 9840130561Sobrien fclose (file); 9841130561Sobrien return 1; 9842130561Sobrien } 9843130561Sobrien 9844130561Sobrien if (memcmp (armag, ARMAG, SARMAG) == 0) 9845130561Sobrien ret = process_archive (file_name, file); 9846130561Sobrien else 9847130561Sobrien { 9848130561Sobrien rewind (file); 9849130561Sobrien archive_file_size = archive_file_offset = 0; 9850130561Sobrien ret = process_object (file_name, file); 9851130561Sobrien } 9852130561Sobrien 9853130561Sobrien fclose (file); 9854130561Sobrien 9855130561Sobrien return ret; 9856130561Sobrien} 9857130561Sobrien 985860484Sobrien#ifdef SUPPORT_DISASSEMBLY 985960484Sobrien/* Needed by the i386 disassembler. For extra credit, someone could 986060484Sobrien fix this so that we insert symbolic addresses here, esp for GOT/PLT 986189857Sobrien symbols. */ 986260484Sobrien 986360484Sobrienvoid 9864130561Sobrienprint_address (unsigned int addr, FILE *outfile) 986560484Sobrien{ 986660484Sobrien fprintf (outfile,"0x%8.8x", addr); 986760484Sobrien} 986860484Sobrien 986989857Sobrien/* Needed by the i386 disassembler. */ 987060484Sobrienvoid 987160484Sobriendb_task_printsym (unsigned int addr) 987260484Sobrien{ 987360484Sobrien print_address (addr, stderr); 987460484Sobrien} 987560484Sobrien#endif 987660484Sobrien 987760484Sobrienint 9878130561Sobrienmain (int argc, char **argv) 987960484Sobrien{ 988089857Sobrien int err; 988189857Sobrien 988260484Sobrien#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) 988360484Sobrien setlocale (LC_MESSAGES, ""); 988460484Sobrien#endif 988589857Sobrien#if defined (HAVE_SETLOCALE) 988689857Sobrien setlocale (LC_CTYPE, ""); 988789857Sobrien#endif 988860484Sobrien bindtextdomain (PACKAGE, LOCALEDIR); 988960484Sobrien textdomain (PACKAGE); 989060484Sobrien 9891218822Sdim expandargv (&argc, &argv); 9892218822Sdim 989360484Sobrien parse_args (argc, argv); 989460484Sobrien 9895218822Sdim if (num_dump_sects > 0) 9896130561Sobrien { 9897218822Sdim /* Make a copy of the dump_sects array. */ 9898130561Sobrien cmdline_dump_sects = malloc (num_dump_sects); 9899130561Sobrien if (cmdline_dump_sects == NULL) 9900218822Sdim error (_("Out of memory allocating dump request table.\n")); 9901130561Sobrien else 9902130561Sobrien { 9903130561Sobrien memcpy (cmdline_dump_sects, dump_sects, num_dump_sects); 9904130561Sobrien num_cmdline_dump_sects = num_dump_sects; 9905130561Sobrien } 9906130561Sobrien } 9907130561Sobrien 9908218822Sdim if (optind < (argc - 1)) 9909218822Sdim show_name = 1; 9910218822Sdim 991189857Sobrien err = 0; 991260484Sobrien while (optind < argc) 9913218822Sdim err |= process_file (argv[optind++]); 991460484Sobrien 991560484Sobrien if (dump_sects != NULL) 991660484Sobrien free (dump_sects); 9917130561Sobrien if (cmdline_dump_sects != NULL) 9918130561Sobrien free (cmdline_dump_sects); 991960484Sobrien 992089857Sobrien return err; 992160484Sobrien} 9922