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, &section);
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