dbb7c4414b
* ar.c: Don't include headers already included by sysdep.h. * bucomm.c: Likewise. * budbg.h: Likewise. * dlltool.h: Likewise. * elfedit.c: Likewise. * nlmconv.c: Likewise. * objcopy.c: Likewise. * objdump.c: Likewise. * objdump.h: Likewise. * readelf.c: Likewise. * rename.c: Likewise. * resrc.c: Likewise. * strings.c: Likewise. * windres.c: Likewise. * od-macho.c: Ensure #include sysdep.h is first. * od-xcoff.c: Likewise. * dllwrap.c: Remove alloca pragma handled by sysdep.h, and remove duplicate headers. * dlltool.c: Likewise and ensure #include sysdep.h is first.
1681 lines
46 KiB
C
1681 lines
46 KiB
C
/* od-xcoff.c -- dump information about an xcoff object file.
|
|
Copyright 2011, 2012 Free Software Foundation, Inc.
|
|
Written by Tristan Gingold, Adacore.
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#include "sysdep.h"
|
|
#include <stddef.h>
|
|
#include <time.h>
|
|
#include "safe-ctype.h"
|
|
#include "bfd.h"
|
|
#include "objdump.h"
|
|
#include "bucomm.h"
|
|
#include "bfdlink.h"
|
|
/* Force the support of weak symbols. */
|
|
#ifndef AIX_WEAK_SUPPORT
|
|
#define AIX_WEAK_SUPPORT 1
|
|
#endif
|
|
#include "coff/internal.h"
|
|
#include "coff/rs6000.h"
|
|
#include "coff/xcoff.h"
|
|
#include "libcoff.h"
|
|
#include "libxcoff.h"
|
|
|
|
/* Index of the options in the options[] array. */
|
|
#define OPT_FILE_HEADER 0
|
|
#define OPT_AOUT 1
|
|
#define OPT_SECTIONS 2
|
|
#define OPT_SYMS 3
|
|
#define OPT_RELOCS 4
|
|
#define OPT_LINENO 5
|
|
#define OPT_LOADER 6
|
|
#define OPT_EXCEPT 7
|
|
#define OPT_TYPCHK 8
|
|
#define OPT_TRACEBACK 9
|
|
#define OPT_TOC 10
|
|
|
|
/* List of actions. */
|
|
static struct objdump_private_option options[] =
|
|
{
|
|
{ "header", 0 },
|
|
{ "aout", 0 },
|
|
{ "sections", 0 },
|
|
{ "syms", 0 },
|
|
{ "relocs", 0 },
|
|
{ "lineno", 0 },
|
|
{ "loader", 0 },
|
|
{ "except", 0 },
|
|
{ "typchk", 0 },
|
|
{ "traceback", 0 },
|
|
{ "toc", 0 },
|
|
{ NULL, 0 }
|
|
};
|
|
|
|
/* Display help. */
|
|
|
|
static void
|
|
xcoff_help (FILE *stream)
|
|
{
|
|
fprintf (stream, _("\
|
|
For XCOFF files:\n\
|
|
header Display the file header\n\
|
|
aout Display the auxiliary header\n\
|
|
sections Display the section headers\n\
|
|
syms Display the symbols table\n\
|
|
relocs Display the relocation entries\n\
|
|
lineno Display the line number entries\n\
|
|
loader Display loader section\n\
|
|
except Display exception table\n\
|
|
typchk Display type-check section\n\
|
|
traceback Display traceback tags\n\
|
|
toc Display toc symbols\n\
|
|
"));
|
|
}
|
|
|
|
/* Return TRUE if ABFD is handled. */
|
|
|
|
static int
|
|
xcoff_filter (bfd *abfd)
|
|
{
|
|
return bfd_get_flavour (abfd) == bfd_target_xcoff_flavour;
|
|
}
|
|
|
|
/* Translation entry type. The last entry must be {0, NULL}. */
|
|
|
|
struct xlat_table {
|
|
unsigned int val;
|
|
const char *name;
|
|
};
|
|
|
|
/* Display the list of name (from TABLE) for FLAGS, using comma to separate
|
|
them. A name is displayed if FLAGS & VAL is not 0. */
|
|
|
|
static void
|
|
dump_flags (const struct xlat_table *table, unsigned int flags)
|
|
{
|
|
unsigned int r = flags;
|
|
int first = 1;
|
|
const struct xlat_table *t;
|
|
|
|
for (t = table; t->name; t++)
|
|
if ((flags & t->val) != 0)
|
|
{
|
|
r &= ~t->val;
|
|
|
|
if (first)
|
|
first = 0;
|
|
else
|
|
putchar (',');
|
|
fputs (t->name, stdout);
|
|
}
|
|
|
|
/* Not decoded flags. */
|
|
if (r != 0)
|
|
{
|
|
if (!first)
|
|
putchar (',');
|
|
printf ("0x%x", r);
|
|
}
|
|
}
|
|
|
|
/* Display the name corresponding to VAL from TABLE, using at most
|
|
MAXLEN char (possibly passed with spaces). */
|
|
|
|
static void
|
|
dump_value (const struct xlat_table *table, unsigned int val, int maxlen)
|
|
{
|
|
const struct xlat_table *t;
|
|
|
|
for (t = table; t->name; t++)
|
|
if (t->val == val)
|
|
{
|
|
printf ("%-*s", maxlen, t->name);
|
|
return;
|
|
}
|
|
printf ("(%*x)", maxlen - 2, val);
|
|
}
|
|
|
|
/* Names of f_flags. */
|
|
static const struct xlat_table f_flag_xlat[] =
|
|
{
|
|
{ F_RELFLG, "no-rel" },
|
|
{ F_EXEC, "exec" },
|
|
{ F_LNNO, "lineno" },
|
|
{ F_LSYMS, "lsyms" },
|
|
|
|
{ F_FDPR_PROF, "fdpr-prof" },
|
|
{ F_FDPR_OPTI, "fdpr-opti" },
|
|
{ F_DSA, "dsa" },
|
|
|
|
{ F_VARPG, "varprg" },
|
|
|
|
{ F_DYNLOAD, "dynload" },
|
|
{ F_SHROBJ, "shrobj" },
|
|
{ F_NONEXEC, "nonexec" },
|
|
|
|
{ 0, NULL }
|
|
};
|
|
|
|
/* Names of s_flags. */
|
|
static const struct xlat_table s_flag_xlat[] =
|
|
{
|
|
{ STYP_PAD, "pad" },
|
|
{ STYP_DWARF, "dwarf" },
|
|
{ STYP_TEXT, "text" },
|
|
{ STYP_DATA, "data" },
|
|
{ STYP_BSS, "bss" },
|
|
|
|
{ STYP_EXCEPT, "except" },
|
|
{ STYP_INFO, "info" },
|
|
{ STYP_TDATA, "tdata" },
|
|
{ STYP_TBSS, "tbss" },
|
|
|
|
{ STYP_LOADER, "loader" },
|
|
{ STYP_DEBUG, "debug" },
|
|
{ STYP_TYPCHK, "typchk" },
|
|
{ STYP_OVRFLO, "ovrflo" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
/* Names of storage class. */
|
|
static const struct xlat_table sc_xlat[] =
|
|
{
|
|
#define SC_ENTRY(X) { C_##X, #X }
|
|
SC_ENTRY(NULL),
|
|
SC_ENTRY(AUTO),
|
|
SC_ENTRY(EXT),
|
|
SC_ENTRY(STAT),
|
|
SC_ENTRY(REG),
|
|
SC_ENTRY(EXTDEF),
|
|
SC_ENTRY(LABEL),
|
|
SC_ENTRY(ULABEL),
|
|
SC_ENTRY(MOS),
|
|
SC_ENTRY(ARG),
|
|
/* SC_ENTRY(STRARG), */
|
|
SC_ENTRY(MOU),
|
|
SC_ENTRY(UNTAG),
|
|
SC_ENTRY(TPDEF),
|
|
SC_ENTRY(USTATIC),
|
|
SC_ENTRY(ENTAG),
|
|
SC_ENTRY(MOE),
|
|
SC_ENTRY(REGPARM),
|
|
SC_ENTRY(FIELD),
|
|
SC_ENTRY(BLOCK),
|
|
SC_ENTRY(FCN),
|
|
SC_ENTRY(EOS),
|
|
SC_ENTRY(FILE),
|
|
SC_ENTRY(LINE),
|
|
SC_ENTRY(ALIAS),
|
|
SC_ENTRY(HIDDEN),
|
|
SC_ENTRY(HIDEXT),
|
|
SC_ENTRY(BINCL),
|
|
SC_ENTRY(EINCL),
|
|
SC_ENTRY(INFO),
|
|
SC_ENTRY(WEAKEXT),
|
|
SC_ENTRY(DWARF),
|
|
|
|
/* Stabs. */
|
|
SC_ENTRY (GSYM),
|
|
SC_ENTRY (LSYM),
|
|
SC_ENTRY (PSYM),
|
|
SC_ENTRY (RSYM),
|
|
SC_ENTRY (RPSYM),
|
|
SC_ENTRY (STSYM),
|
|
SC_ENTRY (TCSYM),
|
|
SC_ENTRY (BCOMM),
|
|
SC_ENTRY (ECOML),
|
|
SC_ENTRY (ECOMM),
|
|
SC_ENTRY (DECL),
|
|
SC_ENTRY (ENTRY),
|
|
SC_ENTRY (FUN),
|
|
SC_ENTRY (BSTAT),
|
|
SC_ENTRY (ESTAT),
|
|
|
|
{ 0, NULL }
|
|
#undef SC_ENTRY
|
|
};
|
|
|
|
/* Names for symbol type. */
|
|
static const struct xlat_table smtyp_xlat[] =
|
|
{
|
|
{ XTY_ER, "ER" },
|
|
{ XTY_SD, "SD" },
|
|
{ XTY_LD, "LD" },
|
|
{ XTY_CM, "CM" },
|
|
{ XTY_EM, "EM" },
|
|
{ XTY_US, "US" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
/* Names for storage-mapping class. */
|
|
static const struct xlat_table smclas_xlat[] =
|
|
{
|
|
#define SMCLAS_ENTRY(X) { XMC_##X, #X }
|
|
SMCLAS_ENTRY (PR),
|
|
SMCLAS_ENTRY (RO),
|
|
SMCLAS_ENTRY (DB),
|
|
SMCLAS_ENTRY (TC),
|
|
SMCLAS_ENTRY (UA),
|
|
SMCLAS_ENTRY (RW),
|
|
SMCLAS_ENTRY (GL),
|
|
SMCLAS_ENTRY (XO),
|
|
SMCLAS_ENTRY (SV),
|
|
SMCLAS_ENTRY (BS),
|
|
SMCLAS_ENTRY (DS),
|
|
SMCLAS_ENTRY (UC),
|
|
SMCLAS_ENTRY (TI),
|
|
SMCLAS_ENTRY (TB),
|
|
SMCLAS_ENTRY (TC0),
|
|
SMCLAS_ENTRY (TD),
|
|
SMCLAS_ENTRY (SV64),
|
|
SMCLAS_ENTRY (SV3264),
|
|
{ 0, NULL }
|
|
#undef SMCLAS_ENTRY
|
|
};
|
|
|
|
/* Names for relocation type. */
|
|
static const struct xlat_table rtype_xlat[] =
|
|
{
|
|
#define RTYPE_ENTRY(X) { R_##X, #X }
|
|
RTYPE_ENTRY (POS),
|
|
RTYPE_ENTRY (NEG),
|
|
RTYPE_ENTRY (REL),
|
|
RTYPE_ENTRY (TOC),
|
|
RTYPE_ENTRY (RTB),
|
|
RTYPE_ENTRY (GL),
|
|
RTYPE_ENTRY (TCL),
|
|
RTYPE_ENTRY (BA),
|
|
RTYPE_ENTRY (BR),
|
|
RTYPE_ENTRY (RL),
|
|
RTYPE_ENTRY (RLA),
|
|
RTYPE_ENTRY (REF),
|
|
RTYPE_ENTRY (TRL),
|
|
RTYPE_ENTRY (TRLA),
|
|
RTYPE_ENTRY (RRTBI),
|
|
RTYPE_ENTRY (RRTBA),
|
|
RTYPE_ENTRY (CAI),
|
|
RTYPE_ENTRY (CREL),
|
|
RTYPE_ENTRY (RBA),
|
|
RTYPE_ENTRY (RBAC),
|
|
RTYPE_ENTRY (RBR),
|
|
RTYPE_ENTRY (RBRC),
|
|
RTYPE_ENTRY (TLS),
|
|
RTYPE_ENTRY (TLS_IE),
|
|
RTYPE_ENTRY (TLS_LD),
|
|
RTYPE_ENTRY (TLS_LE),
|
|
RTYPE_ENTRY (TLSM),
|
|
RTYPE_ENTRY (TLSML),
|
|
RTYPE_ENTRY (TOCU),
|
|
RTYPE_ENTRY (TOCL),
|
|
{ 0, NULL }
|
|
};
|
|
|
|
/* Simplified section header. */
|
|
struct xcoff32_section
|
|
{
|
|
/* NUL terminated name. */
|
|
char name[9];
|
|
|
|
/* Section flags. */
|
|
unsigned int flags;
|
|
|
|
/* Offsets in file. */
|
|
ufile_ptr scnptr;
|
|
ufile_ptr relptr;
|
|
ufile_ptr lnnoptr;
|
|
|
|
/* Number of relocs and line numbers. */
|
|
unsigned int nreloc;
|
|
unsigned int nlnno;
|
|
};
|
|
|
|
/* Simplified symbol. */
|
|
|
|
union xcoff32_symbol
|
|
{
|
|
union external_auxent aux;
|
|
|
|
struct sym
|
|
{
|
|
/* Pointer the the NUL-terminated name. */
|
|
char *name;
|
|
|
|
/* XCOFF symbol fields. */
|
|
unsigned int val;
|
|
unsigned short scnum;
|
|
unsigned short ntype;
|
|
unsigned char sclass;
|
|
unsigned char numaux;
|
|
|
|
/* Buffer in case the name is local. */
|
|
union
|
|
{
|
|
char name[9];
|
|
unsigned int off;
|
|
} raw;
|
|
} sym;
|
|
};
|
|
|
|
/* Important fields to dump the file. */
|
|
|
|
struct xcoff_dump
|
|
{
|
|
/* From file header. */
|
|
unsigned short nscns;
|
|
unsigned int symptr;
|
|
unsigned int nsyms;
|
|
unsigned short opthdr;
|
|
|
|
/* Sections. */
|
|
struct xcoff32_section *sects;
|
|
|
|
/* Symbols. */
|
|
union xcoff32_symbol *syms;
|
|
char *strings;
|
|
unsigned int strings_size;
|
|
};
|
|
|
|
/* Print a symbol (if possible). */
|
|
|
|
static void
|
|
xcoff32_print_symbol (struct xcoff_dump *data, unsigned int symndx)
|
|
{
|
|
if (data->syms != NULL
|
|
&& symndx < data->nsyms
|
|
&& data->syms[symndx].sym.name != NULL)
|
|
printf ("%s", data->syms[symndx].sym.name);
|
|
else
|
|
printf ("%u", symndx);
|
|
}
|
|
|
|
/* Dump the file header. */
|
|
|
|
static void
|
|
dump_xcoff32_file_header (bfd *abfd, struct external_filehdr *fhdr,
|
|
struct xcoff_dump *data)
|
|
{
|
|
unsigned int timdat = bfd_h_get_32 (abfd, fhdr->f_timdat);
|
|
unsigned short flags = bfd_h_get_16 (abfd, fhdr->f_flags);
|
|
|
|
printf (_(" nbr sections: %d\n"), data->nscns);
|
|
printf (_(" time and date: 0x%08x - "), timdat);
|
|
if (timdat == 0)
|
|
printf (_("not set\n"));
|
|
else
|
|
{
|
|
/* Not correct on all platforms, but works on unix. */
|
|
time_t t = timdat;
|
|
fputs (ctime (&t), stdout);
|
|
}
|
|
printf (_(" symbols off: 0x%08x\n"), data->symptr);
|
|
printf (_(" nbr symbols: %d\n"), data->nsyms);
|
|
printf (_(" opt hdr sz: %d\n"), data->opthdr);
|
|
printf (_(" flags: 0x%04x "), flags);
|
|
dump_flags (f_flag_xlat, flags);
|
|
putchar ('\n');
|
|
}
|
|
|
|
/* Dump the a.out header. */
|
|
|
|
static void
|
|
dump_xcoff32_aout_header (bfd *abfd, struct xcoff_dump *data)
|
|
{
|
|
AOUTHDR auxhdr;
|
|
unsigned short magic;
|
|
unsigned int sz = data->opthdr;
|
|
|
|
printf (_("Auxiliary header:\n"));
|
|
if (data->opthdr == 0)
|
|
{
|
|
printf (_(" No aux header\n"));
|
|
return;
|
|
}
|
|
if (data->opthdr > sizeof (auxhdr))
|
|
{
|
|
printf (_("warning: optionnal header size too large (> %d)\n"),
|
|
(int)sizeof (auxhdr));
|
|
sz = sizeof (auxhdr);
|
|
}
|
|
if (bfd_bread (&auxhdr, sz, abfd) != sz)
|
|
{
|
|
non_fatal (_("cannot read auxhdr"));
|
|
return;
|
|
}
|
|
|
|
magic = bfd_h_get_16 (abfd, auxhdr.magic);
|
|
/* We don't translate these strings as they are fields name. */
|
|
printf (" o_mflag (magic): 0x%04x 0%04o\n", magic, magic);
|
|
printf (" o_vstamp: 0x%04x\n",
|
|
(unsigned short)bfd_h_get_16 (abfd, auxhdr.vstamp));
|
|
printf (" o_tsize: 0x%08x\n",
|
|
(unsigned int)bfd_h_get_32 (abfd, auxhdr.tsize));
|
|
printf (" o_dsize: 0x%08x\n",
|
|
(unsigned int)bfd_h_get_32 (abfd, auxhdr.dsize));
|
|
printf (" o_entry: 0x%08x\n",
|
|
(unsigned int)bfd_h_get_32 (abfd, auxhdr.entry));
|
|
printf (" o_text_start: 0x%08x\n",
|
|
(unsigned int)bfd_h_get_32 (abfd, auxhdr.text_start));
|
|
printf (" o_data_start: 0x%08x\n",
|
|
(unsigned int)bfd_h_get_32 (abfd, auxhdr.data_start));
|
|
if (sz == offsetof (AOUTHDR, o_toc))
|
|
return;
|
|
printf (" o_toc: 0x%08x\n",
|
|
(unsigned int)bfd_h_get_32 (abfd, auxhdr.o_toc));
|
|
printf (" o_snentry: 0x%04x\n",
|
|
(unsigned int)bfd_h_get_16 (abfd, auxhdr.o_snentry));
|
|
printf (" o_sntext: 0x%04x\n",
|
|
(unsigned int)bfd_h_get_16 (abfd, auxhdr.o_sntext));
|
|
printf (" o_sndata: 0x%04x\n",
|
|
(unsigned int)bfd_h_get_16 (abfd, auxhdr.o_sndata));
|
|
printf (" o_sntoc: 0x%04x\n",
|
|
(unsigned int)bfd_h_get_16 (abfd, auxhdr.o_sntoc));
|
|
printf (" o_snloader: 0x%04x\n",
|
|
(unsigned int)bfd_h_get_16 (abfd, auxhdr.o_snloader));
|
|
printf (" o_snbss: 0x%04x\n",
|
|
(unsigned int)bfd_h_get_16 (abfd, auxhdr.o_snbss));
|
|
printf (" o_algntext: %u\n",
|
|
(unsigned int)bfd_h_get_16 (abfd, auxhdr.o_algntext));
|
|
printf (" o_algndata: %u\n",
|
|
(unsigned int)bfd_h_get_16 (abfd, auxhdr.o_algndata));
|
|
printf (" o_modtype: 0x%04x",
|
|
(unsigned int)bfd_h_get_16 (abfd, auxhdr.o_modtype));
|
|
if (ISPRINT (auxhdr.o_modtype[0]) && ISPRINT (auxhdr.o_modtype[1]))
|
|
printf (" (%c%c)", auxhdr.o_modtype[0], auxhdr.o_modtype[1]);
|
|
putchar ('\n');
|
|
printf (" o_cputype: 0x%04x\n",
|
|
(unsigned int)bfd_h_get_16 (abfd, auxhdr.o_cputype));
|
|
printf (" o_maxstack: 0x%08x\n",
|
|
(unsigned int)bfd_h_get_32 (abfd, auxhdr.o_maxstack));
|
|
printf (" o_maxdata: 0x%08x\n",
|
|
(unsigned int)bfd_h_get_32 (abfd, auxhdr.o_maxdata));
|
|
#if 0
|
|
printf (" o_debugger: 0x%08x\n",
|
|
(unsigned int)bfd_h_get_32 (abfd, auxhdr.o_debugger));
|
|
#endif
|
|
}
|
|
|
|
/* Dump the sections header. */
|
|
|
|
static void
|
|
dump_xcoff32_sections_header (bfd *abfd, struct xcoff_dump *data)
|
|
{
|
|
unsigned int i;
|
|
unsigned int off;
|
|
|
|
off = sizeof (struct external_filehdr) + data->opthdr;
|
|
printf (_("Section headers (at %u+%u=0x%08x to 0x%08x):\n"),
|
|
(unsigned int)sizeof (struct external_filehdr), data->opthdr, off,
|
|
off + (unsigned int)sizeof (struct external_scnhdr) * data->nscns);
|
|
if (data->nscns == 0)
|
|
{
|
|
printf (_(" No section header\n"));
|
|
return;
|
|
}
|
|
if (bfd_seek (abfd, off, SEEK_SET) != 0)
|
|
{
|
|
non_fatal (_("cannot read section header"));
|
|
return;
|
|
}
|
|
/* We don't translate this string as it consists in fields name. */
|
|
printf (" # Name paddr vaddr size scnptr relptr lnnoptr nrel nlnno\n");
|
|
for (i = 0; i < data->nscns; i++)
|
|
{
|
|
struct external_scnhdr scn;
|
|
unsigned int flags;
|
|
|
|
if (bfd_bread (&scn, sizeof (scn), abfd) != sizeof (scn))
|
|
{
|
|
non_fatal (_("cannot read section header"));
|
|
return;
|
|
}
|
|
flags = bfd_h_get_32 (abfd, scn.s_flags);
|
|
printf ("%2d %-8.8s %08x %08x %08x %08x %08x %08x %-5d %-5d\n",
|
|
i + 1, scn.s_name,
|
|
(unsigned int)bfd_h_get_32 (abfd, scn.s_paddr),
|
|
(unsigned int)bfd_h_get_32 (abfd, scn.s_vaddr),
|
|
(unsigned int)bfd_h_get_32 (abfd, scn.s_size),
|
|
(unsigned int)bfd_h_get_32 (abfd, scn.s_scnptr),
|
|
(unsigned int)bfd_h_get_32 (abfd, scn.s_relptr),
|
|
(unsigned int)bfd_h_get_32 (abfd, scn.s_lnnoptr),
|
|
(unsigned int)bfd_h_get_16 (abfd, scn.s_nreloc),
|
|
(unsigned int)bfd_h_get_16 (abfd, scn.s_nlnno));
|
|
printf (_(" Flags: %08x "), flags);
|
|
|
|
if (~flags == 0)
|
|
{
|
|
/* Stripped executable ? */
|
|
putchar ('\n');
|
|
}
|
|
else if (flags & STYP_OVRFLO)
|
|
printf (_("overflow - nreloc: %u, nlnno: %u\n"),
|
|
(unsigned int)bfd_h_get_32 (abfd, scn.s_paddr),
|
|
(unsigned int)bfd_h_get_32 (abfd, scn.s_vaddr));
|
|
else
|
|
{
|
|
dump_flags (s_flag_xlat, flags);
|
|
putchar ('\n');
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Read section table. */
|
|
|
|
static void
|
|
xcoff32_read_sections (bfd *abfd, struct xcoff_dump *data)
|
|
{
|
|
int i;
|
|
|
|
if (bfd_seek (abfd, sizeof (struct external_filehdr) + data->opthdr,
|
|
SEEK_SET) != 0)
|
|
{
|
|
non_fatal (_("cannot read section headers"));
|
|
return;
|
|
}
|
|
|
|
data->sects = xmalloc (data->nscns * sizeof (struct xcoff32_section));
|
|
for (i = 0; i < data->nscns; i++)
|
|
{
|
|
struct external_scnhdr scn;
|
|
struct xcoff32_section *s = &data->sects[i];
|
|
|
|
if (bfd_bread (&scn, sizeof (scn), abfd) != sizeof (scn))
|
|
{
|
|
non_fatal (_("cannot read section header"));
|
|
free (data->sects);
|
|
data->sects = NULL;
|
|
return;
|
|
}
|
|
memcpy (s->name, scn.s_name, 8);
|
|
s->name[8] = 0;
|
|
s->flags = bfd_h_get_32 (abfd, scn.s_flags);
|
|
|
|
s->scnptr = bfd_h_get_32 (abfd, scn.s_scnptr);
|
|
s->relptr = bfd_h_get_32 (abfd, scn.s_relptr);
|
|
s->lnnoptr = bfd_h_get_32 (abfd, scn.s_lnnoptr);
|
|
|
|
s->nreloc = bfd_h_get_16 (abfd, scn.s_nreloc);
|
|
s->nlnno = bfd_h_get_16 (abfd, scn.s_nlnno);
|
|
|
|
if (s->flags == STYP_OVRFLO)
|
|
{
|
|
if (s->nreloc > 0 && s->nreloc <= data->nscns)
|
|
data->sects[s->nreloc - 1].nreloc =
|
|
bfd_h_get_32 (abfd, scn.s_paddr);
|
|
if (s->nlnno > 0 && s->nlnno <= data->nscns)
|
|
data->sects[s->nlnno - 1].nlnno =
|
|
bfd_h_get_32 (abfd, scn.s_vaddr);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Read symbols. */
|
|
|
|
static void
|
|
xcoff32_read_symbols (bfd *abfd, struct xcoff_dump *data)
|
|
{
|
|
unsigned int i;
|
|
char stsz_arr[4];
|
|
unsigned int stptr;
|
|
|
|
if (data->nsyms == 0)
|
|
return;
|
|
|
|
stptr = data->symptr
|
|
+ data->nsyms * (unsigned)sizeof (struct external_syment);
|
|
|
|
/* Read string table. */
|
|
if (bfd_seek (abfd, stptr, SEEK_SET) != 0
|
|
|| bfd_bread (&stsz_arr, sizeof (stsz_arr), abfd) != sizeof (stsz_arr))
|
|
{
|
|
non_fatal (_("cannot read strings table length"));
|
|
data->strings_size = 0;
|
|
}
|
|
else
|
|
{
|
|
data->strings_size = bfd_h_get_32 (abfd, stsz_arr);
|
|
if (data->strings_size > sizeof (stsz_arr))
|
|
{
|
|
unsigned int remsz = data->strings_size - sizeof (stsz_arr);
|
|
|
|
data->strings = xmalloc (data->strings_size);
|
|
|
|
memcpy (data->strings, stsz_arr, sizeof (stsz_arr));
|
|
if (bfd_bread (data->strings + sizeof (stsz_arr), remsz, abfd)
|
|
!= remsz)
|
|
{
|
|
non_fatal (_("cannot read strings table"));
|
|
goto clean;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bfd_seek (abfd, data->symptr, SEEK_SET) != 0)
|
|
{
|
|
non_fatal (_("cannot read symbol table"));
|
|
goto clean;
|
|
}
|
|
|
|
data->syms = (union xcoff32_symbol *)
|
|
xmalloc (data->nsyms * sizeof (union xcoff32_symbol));
|
|
|
|
for (i = 0; i < data->nsyms; i++)
|
|
{
|
|
struct external_syment sym;
|
|
int j;
|
|
union xcoff32_symbol *s = &data->syms[i];
|
|
|
|
if (bfd_bread (&sym, sizeof (sym), abfd) != sizeof (sym))
|
|
{
|
|
non_fatal (_("cannot read symbol entry"));
|
|
goto clean;
|
|
}
|
|
|
|
s->sym.val = bfd_h_get_32 (abfd, sym.e_value);
|
|
s->sym.scnum = bfd_h_get_16 (abfd, sym.e_scnum);
|
|
s->sym.ntype = bfd_h_get_16 (abfd, sym.e_type);
|
|
s->sym.sclass = bfd_h_get_8 (abfd, sym.e_sclass);
|
|
s->sym.numaux = bfd_h_get_8 (abfd, sym.e_numaux);
|
|
|
|
if (sym.e.e_name[0])
|
|
{
|
|
memcpy (s->sym.raw.name, sym.e.e_name, sizeof (sym.e.e_name));
|
|
s->sym.raw.name[8] = 0;
|
|
s->sym.name = s->sym.raw.name;
|
|
}
|
|
else
|
|
{
|
|
unsigned int soff = bfd_h_get_32 (abfd, sym.e.e.e_offset);
|
|
|
|
if ((s->sym.sclass & DBXMASK) == 0 && soff < data->strings_size)
|
|
s->sym.name = data->strings + soff;
|
|
else
|
|
{
|
|
s->sym.name = NULL;
|
|
s->sym.raw.off = soff;
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < s->sym.numaux; j++, i++)
|
|
{
|
|
if (bfd_bread (&s[j + 1].aux,
|
|
sizeof (union external_auxent), abfd)
|
|
!= sizeof (union external_auxent))
|
|
{
|
|
non_fatal (_("cannot read symbol aux entry"));
|
|
goto clean;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
clean:
|
|
free (data->syms);
|
|
data->syms = NULL;
|
|
free (data->strings);
|
|
data->strings = NULL;
|
|
}
|
|
|
|
/* Dump xcoff symbols. */
|
|
|
|
static void
|
|
dump_xcoff32_symbols (bfd *abfd, struct xcoff_dump *data)
|
|
{
|
|
unsigned int i;
|
|
asection *debugsec;
|
|
char *debug = NULL;
|
|
|
|
printf (_("Symbols table (strtable at 0x%08x)"),
|
|
data->symptr
|
|
+ data->nsyms * (unsigned)sizeof (struct external_syment));
|
|
if (data->nsyms == 0 || data->syms == NULL)
|
|
{
|
|
printf (_(":\n No symbols\n"));
|
|
return;
|
|
}
|
|
|
|
/* Read strings table. */
|
|
if (data->strings_size == 0)
|
|
printf (_(" (no strings):\n"));
|
|
else
|
|
printf (_(" (strings size: %08x):\n"), data->strings_size);
|
|
|
|
/* Read debug section. */
|
|
debugsec = bfd_get_section_by_name (abfd, ".debug");
|
|
if (debugsec != NULL)
|
|
{
|
|
bfd_size_type size;
|
|
|
|
size = bfd_get_section_size (debugsec);
|
|
debug = (char *) xmalloc (size);
|
|
bfd_get_section_contents (abfd, debugsec, debug, 0, size);
|
|
}
|
|
|
|
/* Translators: 'sc' is for storage class, 'off' for offset. */
|
|
printf (_(" # sc value section type aux name/off\n"));
|
|
for (i = 0; i < data->nsyms; i++)
|
|
{
|
|
union xcoff32_symbol *s = &data->syms[i];
|
|
int j;
|
|
|
|
printf ("%3u ", i);
|
|
dump_value (sc_xlat, s->sym.sclass, 10);
|
|
printf (" %08x ", s->sym.val);
|
|
if (s->sym.scnum > 0 && s->sym.scnum <= data->nscns)
|
|
{
|
|
if (data->sects != NULL)
|
|
printf ("%-8s", data->sects[s->sym.scnum - 1].name);
|
|
else
|
|
printf ("%-8u", s->sym.scnum);
|
|
}
|
|
else
|
|
switch ((signed short)s->sym.scnum)
|
|
{
|
|
case N_DEBUG:
|
|
printf ("N_DEBUG ");
|
|
break;
|
|
case N_ABS:
|
|
printf ("N_ABS ");
|
|
break;
|
|
case N_UNDEF:
|
|
printf ("N_UNDEF ");
|
|
break;
|
|
default:
|
|
printf ("(%04x) ", s->sym.scnum);
|
|
}
|
|
printf (" %04x %3u ", s->sym.ntype, s->sym.numaux);
|
|
if (s->sym.name != NULL)
|
|
printf ("%s", s->sym.name);
|
|
else
|
|
{
|
|
if ((s->sym.sclass & DBXMASK) != 0 && debug != NULL)
|
|
printf ("%s", debug + s->sym.raw.off);
|
|
else
|
|
printf ("%08x", s->sym.raw.off);
|
|
}
|
|
putchar ('\n');
|
|
|
|
for (j = 0; j < s->sym.numaux; j++, i++)
|
|
{
|
|
union external_auxent *aux = &s[j + 1].aux;
|
|
|
|
printf (" %3u ", i + 1);
|
|
switch (s->sym.sclass)
|
|
{
|
|
case C_STAT:
|
|
/* Section length, number of relocs and line number. */
|
|
printf (_(" scnlen: %08x nreloc: %-6u nlinno: %-6u\n"),
|
|
(unsigned)bfd_h_get_32 (abfd, aux->x_scn.x_scnlen),
|
|
(unsigned)bfd_h_get_16 (abfd, aux->x_scn.x_nreloc),
|
|
(unsigned)bfd_h_get_16 (abfd, aux->x_scn.x_nlinno));
|
|
break;
|
|
case C_DWARF:
|
|
/* Section length and number of relocs. */
|
|
printf (_(" scnlen: %08x nreloc: %-6u\n"),
|
|
(unsigned)bfd_h_get_32 (abfd, aux->x_scn.x_scnlen),
|
|
(unsigned)bfd_h_get_16 (abfd, aux->x_scn.x_nreloc));
|
|
break;
|
|
case C_EXT:
|
|
case C_WEAKEXT:
|
|
case C_HIDEXT:
|
|
if (j == 0 && s->sym.numaux > 1)
|
|
{
|
|
/* Function aux entry (Do not translate). */
|
|
printf (" exptr: %08x fsize: %08x lnnoptr: %08x endndx: %u\n",
|
|
(unsigned)bfd_h_get_32 (abfd, aux->x_sym.x_tagndx),
|
|
(unsigned)bfd_h_get_32
|
|
(abfd, aux->x_sym.x_misc.x_fsize),
|
|
(unsigned)bfd_h_get_32
|
|
(abfd, aux->x_sym.x_fcnary.x_fcn.x_lnnoptr),
|
|
(unsigned)bfd_h_get_32
|
|
(abfd, aux->x_sym.x_fcnary.x_fcn.x_endndx));
|
|
}
|
|
else if (j == 1 || (j == 0 && s->sym.numaux == 1))
|
|
{
|
|
/* csect aux entry. */
|
|
unsigned char smtyp;
|
|
unsigned int scnlen;
|
|
|
|
smtyp = bfd_h_get_8 (abfd, aux->x_csect.x_smtyp);
|
|
scnlen = bfd_h_get_32 (abfd, aux->x_csect.x_scnlen);
|
|
|
|
if (smtyp == XTY_LD)
|
|
printf (" scnsym: %-8u", scnlen);
|
|
else
|
|
printf (" scnlen: %08x", scnlen);
|
|
printf (" h: parm=%08x sn=%04x al: 2**%u",
|
|
(unsigned)bfd_h_get_32 (abfd, aux->x_csect.x_parmhash),
|
|
(unsigned)bfd_h_get_16 (abfd, aux->x_csect.x_snhash),
|
|
SMTYP_ALIGN (smtyp));
|
|
printf (" typ: ");
|
|
dump_value (smtyp_xlat, SMTYP_SMTYP (smtyp), 2);
|
|
printf (" cl: ");
|
|
dump_value
|
|
(smclas_xlat,
|
|
(unsigned)bfd_h_get_8 (abfd, aux->x_csect.x_smclas), 6);
|
|
putchar ('\n');
|
|
}
|
|
else
|
|
/* Do not translate - generic field name. */
|
|
printf ("aux\n");
|
|
break;
|
|
case C_FILE:
|
|
{
|
|
unsigned int off;
|
|
|
|
printf (" ftype: %02x ",
|
|
(unsigned)bfd_h_get_8 (abfd, aux->x_file.x_ftype));
|
|
if (aux->x_file.x_n.x_fname[0] != 0)
|
|
printf ("fname: %.14s", aux->x_file.x_n.x_fname);
|
|
else
|
|
{
|
|
off = (unsigned)bfd_h_get_32
|
|
(abfd, aux->x_file.x_n.x_n.x_offset);
|
|
if (data->strings != NULL && off < data->strings_size)
|
|
printf (" %s", data->strings + off);
|
|
else
|
|
printf (_("offset: %08x"), off);
|
|
}
|
|
putchar ('\n');
|
|
}
|
|
break;
|
|
case C_BLOCK:
|
|
case C_FCN:
|
|
printf (" lnno: %u\n",
|
|
(unsigned)bfd_h_get_16
|
|
(abfd, aux->x_sym.x_misc.x_lnsz.x_lnno));
|
|
break;
|
|
default:
|
|
/* Do not translate - generic field name. */
|
|
printf ("aux\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
free (debug);
|
|
}
|
|
|
|
/* Dump xcoff relocation entries. */
|
|
|
|
static void
|
|
dump_xcoff32_relocs (bfd *abfd, struct xcoff_dump *data)
|
|
{
|
|
unsigned int i;
|
|
|
|
if (data->sects == NULL)
|
|
{
|
|
non_fatal (_("cannot read section headers"));
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < data->nscns; i++)
|
|
{
|
|
struct xcoff32_section *sect = &data->sects[i];
|
|
unsigned int nrel = sect->nreloc;
|
|
unsigned int j;
|
|
|
|
if (nrel == 0)
|
|
continue;
|
|
printf (_("Relocations for %s (%u)\n"), sect->name, nrel);
|
|
if (bfd_seek (abfd, sect->relptr, SEEK_SET) != 0)
|
|
{
|
|
non_fatal (_("cannot read relocations"));
|
|
continue;
|
|
}
|
|
/* Do not translate: fields name. */
|
|
printf ("vaddr sgn mod sz type symndx symbol\n");
|
|
for (j = 0; j < nrel; j++)
|
|
{
|
|
struct external_reloc rel;
|
|
unsigned char rsize;
|
|
unsigned int symndx;
|
|
|
|
if (bfd_bread (&rel, sizeof (rel), abfd) != sizeof (rel))
|
|
{
|
|
non_fatal (_("cannot read relocation entry"));
|
|
return;
|
|
}
|
|
rsize = bfd_h_get_8 (abfd, rel.r_size);
|
|
printf ("%08x %c %c %-2u ",
|
|
(unsigned int)bfd_h_get_32 (abfd, rel.r_vaddr),
|
|
rsize & 0x80 ? 'S' : 'U',
|
|
rsize & 0x40 ? 'm' : ' ',
|
|
(rsize & 0x3f) + 1);
|
|
dump_value (rtype_xlat, bfd_h_get_8 (abfd, rel.r_type), 6);
|
|
symndx = bfd_h_get_32 (abfd, rel.r_symndx);
|
|
printf ("%-6u ", symndx);
|
|
xcoff32_print_symbol (data, symndx);
|
|
putchar ('\n');
|
|
}
|
|
putchar ('\n');
|
|
}
|
|
}
|
|
|
|
/* Dump xcoff line number entries. */
|
|
|
|
static void
|
|
dump_xcoff32_lineno (bfd *abfd, struct xcoff_dump *data)
|
|
{
|
|
unsigned int i;
|
|
|
|
if (data->sects == NULL)
|
|
{
|
|
non_fatal (_("cannot read section headers"));
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < data->nscns; i++)
|
|
{
|
|
struct xcoff32_section *sect = &data->sects[i];
|
|
unsigned int nlnno = sect->nlnno;
|
|
unsigned int j;
|
|
|
|
if (nlnno == 0)
|
|
continue;
|
|
printf (_("Line numbers for %s (%u)\n"), sect->name, nlnno);
|
|
if (bfd_seek (abfd, sect->lnnoptr, SEEK_SET) != 0)
|
|
{
|
|
non_fatal (_("cannot read line numbers"));
|
|
continue;
|
|
}
|
|
/* Line number, symbol index and physical address. */
|
|
printf (_("lineno symndx/paddr\n"));
|
|
for (j = 0; j < nlnno; j++)
|
|
{
|
|
struct external_lineno ln;
|
|
unsigned int no;
|
|
|
|
if (bfd_bread (&ln, sizeof (ln), abfd) != sizeof (ln))
|
|
{
|
|
non_fatal (_("cannot read line number entry"));
|
|
return;
|
|
}
|
|
no = bfd_h_get_16 (abfd, ln.l_lnno);
|
|
printf (" %-6u ", no);
|
|
if (no == 0)
|
|
{
|
|
unsigned int symndx = bfd_h_get_32 (abfd, ln.l_addr.l_symndx);
|
|
xcoff32_print_symbol (data, symndx);
|
|
}
|
|
else
|
|
printf ("0x%08x",
|
|
(unsigned int)bfd_h_get_32 (abfd, ln.l_addr.l_paddr));
|
|
putchar ('\n');
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Dump xcoff loader section. */
|
|
|
|
static void
|
|
dump_xcoff32_loader (bfd *abfd)
|
|
{
|
|
asection *loader;
|
|
bfd_size_type size = 0;
|
|
struct external_ldhdr *lhdr;
|
|
struct external_ldsym *ldsym;
|
|
struct external_ldrel *ldrel;
|
|
bfd_byte *ldr_data;
|
|
unsigned int version;
|
|
unsigned int ndsyms;
|
|
unsigned int ndrel;
|
|
unsigned int stlen;
|
|
unsigned int stoff;
|
|
unsigned int impoff;
|
|
unsigned int nimpid;
|
|
unsigned int i;
|
|
const char *p;
|
|
|
|
loader = bfd_get_section_by_name (abfd, ".loader");
|
|
|
|
if (loader == NULL)
|
|
{
|
|
printf (_("no .loader section in file\n"));
|
|
return;
|
|
}
|
|
size = bfd_get_section_size (loader);
|
|
if (size < sizeof (*lhdr))
|
|
{
|
|
printf (_("section .loader is too short\n"));
|
|
return;
|
|
}
|
|
|
|
ldr_data = (bfd_byte *) xmalloc (size);
|
|
bfd_get_section_contents (abfd, loader, ldr_data, 0, size);
|
|
lhdr = (struct external_ldhdr *)ldr_data;
|
|
printf (_("Loader header:\n"));
|
|
version = bfd_h_get_32 (abfd, lhdr->l_version);
|
|
printf (_(" version: %u\n"), version);
|
|
if (version != 1)
|
|
{
|
|
printf (_(" Unhandled version\n"));
|
|
free (ldr_data);
|
|
return;
|
|
}
|
|
ndsyms = bfd_h_get_32 (abfd, lhdr->l_nsyms);
|
|
printf (_(" nbr symbols: %u\n"), ndsyms);
|
|
ndrel = bfd_h_get_32 (abfd, lhdr->l_nreloc);
|
|
printf (_(" nbr relocs: %u\n"), ndrel);
|
|
/* Import string table length. */
|
|
printf (_(" import strtab len: %u\n"),
|
|
(unsigned) bfd_h_get_32 (abfd, lhdr->l_istlen));
|
|
nimpid = bfd_h_get_32 (abfd, lhdr->l_nimpid);
|
|
printf (_(" nbr import files: %u\n"), nimpid);
|
|
impoff = bfd_h_get_32 (abfd, lhdr->l_impoff);
|
|
printf (_(" import file off: %u\n"), impoff);
|
|
stlen = bfd_h_get_32 (abfd, lhdr->l_stlen);
|
|
printf (_(" string table len: %u\n"), stlen);
|
|
stoff = bfd_h_get_32 (abfd, lhdr->l_stoff);
|
|
printf (_(" string table off: %u\n"), stoff);
|
|
|
|
ldsym = (struct external_ldsym *)(ldr_data + sizeof (*lhdr));
|
|
printf (_("Dynamic symbols:\n"));
|
|
/* Do not translate: field names. */
|
|
printf (" # value sc IFEW ty class file pa name\n");
|
|
for (i = 0; i < ndsyms; i++, ldsym++)
|
|
{
|
|
unsigned char smtype;
|
|
|
|
printf (_(" %4u %08x %3u "), i,
|
|
(unsigned)bfd_h_get_32 (abfd, ldsym->l_value),
|
|
(unsigned)bfd_h_get_16 (abfd, ldsym->l_scnum));
|
|
smtype = bfd_h_get_8 (abfd, ldsym->l_smtype);
|
|
putchar (smtype & 0x40 ? 'I' : ' ');
|
|
putchar (smtype & 0x20 ? 'F' : ' ');
|
|
putchar (smtype & 0x10 ? 'E' : ' ');
|
|
putchar (smtype & 0x08 ? 'W' : ' ');
|
|
putchar (' ');
|
|
dump_value (smtyp_xlat, SMTYP_SMTYP (smtype), 2);
|
|
putchar (' ');
|
|
dump_value
|
|
(smclas_xlat, (unsigned)bfd_h_get_8 (abfd, ldsym->l_smclas), 6);
|
|
printf (_(" %3u %3u "),
|
|
(unsigned)bfd_h_get_32 (abfd, ldsym->l_ifile),
|
|
(unsigned)bfd_h_get_32 (abfd, ldsym->l_parm));
|
|
if (ldsym->_l._l_name[0] != 0)
|
|
printf ("%-.8s", ldsym->_l._l_name);
|
|
else
|
|
{
|
|
unsigned int off = bfd_h_get_32 (abfd, ldsym->_l._l_l._l_offset);
|
|
if (off > stlen)
|
|
printf (_("(bad offset: %u)"), off);
|
|
else
|
|
printf ("%s", ldr_data + stoff + off);
|
|
}
|
|
putchar ('\n');
|
|
}
|
|
|
|
printf (_("Dynamic relocs:\n"));
|
|
/* Do not translate fields name. */
|
|
printf (" vaddr sec sz typ sym\n");
|
|
ldrel = (struct external_ldrel *)(ldr_data + sizeof (*lhdr)
|
|
+ ndsyms * sizeof (*ldsym));
|
|
for (i = 0; i < ndrel; i++, ldrel++)
|
|
{
|
|
unsigned int rsize;
|
|
unsigned int rtype;
|
|
unsigned int symndx;
|
|
|
|
rsize = bfd_h_get_8 (abfd, ldrel->l_rtype + 0);
|
|
rtype = bfd_h_get_8 (abfd, ldrel->l_rtype + 1);
|
|
|
|
printf (" %08x %3u %c%c %2u ",
|
|
(unsigned)bfd_h_get_32 (abfd, ldrel->l_vaddr),
|
|
(unsigned)bfd_h_get_16 (abfd, ldrel->l_rsecnm),
|
|
rsize & 0x80 ? 'S' : 'U',
|
|
rsize & 0x40 ? 'm' : ' ',
|
|
(rsize & 0x3f) + 1);
|
|
dump_value (rtype_xlat, rtype, 6);
|
|
symndx = bfd_h_get_32 (abfd, ldrel->l_symndx);
|
|
switch (symndx)
|
|
{
|
|
case 0:
|
|
printf (".text");
|
|
break;
|
|
case 1:
|
|
printf (".data");
|
|
break;
|
|
case 2:
|
|
printf (".bss");
|
|
break;
|
|
default:
|
|
printf ("%u", symndx - 3);
|
|
break;
|
|
}
|
|
putchar ('\n');
|
|
}
|
|
|
|
printf (_("Import files:\n"));
|
|
p = (char *)ldr_data + impoff;
|
|
for (i = 0; i < nimpid; i++)
|
|
{
|
|
int n1, n2, n3;
|
|
|
|
n1 = strlen (p);
|
|
n2 = strlen (p + n1 + 1);
|
|
n3 = strlen (p + n1 + 1 + n2+ 1);
|
|
printf (" %2u: %s,%s,%s\n", i,
|
|
p, p + n1 + 1, p + n1 + n2 + 2);
|
|
p += n1 + n2 + n3 + 3;
|
|
}
|
|
|
|
free (ldr_data);
|
|
}
|
|
|
|
/* Dump xcoff exception section. */
|
|
|
|
static void
|
|
dump_xcoff32_except (bfd *abfd, struct xcoff_dump *data)
|
|
{
|
|
asection *sec;
|
|
bfd_size_type size = 0;
|
|
bfd_byte *excp_data;
|
|
struct external_exceptab *exceptab;
|
|
unsigned int i;
|
|
|
|
sec = bfd_get_section_by_name (abfd, ".except");
|
|
|
|
if (sec == NULL)
|
|
{
|
|
printf (_("no .except section in file\n"));
|
|
return;
|
|
}
|
|
size = bfd_get_section_size (sec);
|
|
excp_data = (bfd_byte *) xmalloc (size);
|
|
bfd_get_section_contents (abfd, sec, excp_data, 0, size);
|
|
exceptab = (struct external_exceptab *)excp_data;
|
|
|
|
printf (_("Exception table:\n"));
|
|
/* Do not translate fields name. */
|
|
printf ("lang reason sym/addr\n");
|
|
for (i = 0; i * sizeof (*exceptab) < size; i++, exceptab++)
|
|
{
|
|
unsigned int reason;
|
|
unsigned int addr;
|
|
|
|
addr = bfd_get_32 (abfd, exceptab->e_addr.e_paddr);
|
|
reason = bfd_get_8 (abfd, exceptab->e_reason);
|
|
printf (" %02x %02x ",
|
|
(unsigned) bfd_get_8 (abfd, exceptab->e_lang), reason);
|
|
if (reason == 0)
|
|
xcoff32_print_symbol (data, addr);
|
|
else
|
|
printf ("@%08x", addr);
|
|
putchar ('\n');
|
|
}
|
|
free (excp_data);
|
|
}
|
|
|
|
/* Dump xcoff type-check section. */
|
|
|
|
static void
|
|
dump_xcoff32_typchk (bfd *abfd)
|
|
{
|
|
asection *sec;
|
|
bfd_size_type size = 0;
|
|
bfd_byte *data;
|
|
unsigned int i;
|
|
|
|
sec = bfd_get_section_by_name (abfd, ".typchk");
|
|
|
|
if (sec == NULL)
|
|
{
|
|
printf (_("no .typchk section in file\n"));
|
|
return;
|
|
}
|
|
size = bfd_get_section_size (sec);
|
|
data = (bfd_byte *) xmalloc (size);
|
|
bfd_get_section_contents (abfd, sec, data, 0, size);
|
|
|
|
printf (_("Type-check section:\n"));
|
|
/* Do not translate field names. */
|
|
printf ("offset len lang-id general-hash language-hash\n");
|
|
for (i = 0; i < size;)
|
|
{
|
|
unsigned int len;
|
|
|
|
len = bfd_get_16 (abfd, data + i);
|
|
printf ("%08x: %-4u ", i, len);
|
|
i += 2;
|
|
|
|
if (len == 10)
|
|
{
|
|
/* Expected format. */
|
|
printf ("%04x %08x %08x\n",
|
|
(unsigned) bfd_get_16 (abfd, data + i),
|
|
(unsigned) bfd_get_32 (abfd, data + i + 2),
|
|
(unsigned) bfd_get_32 (abfd, data + i + 2 + 4));
|
|
}
|
|
else
|
|
{
|
|
unsigned int j;
|
|
|
|
for (j = 0; j < len; j++)
|
|
{
|
|
if (j % 16 == 0)
|
|
printf ("\n ");
|
|
printf (" %02x", (unsigned char)data[i + j]);
|
|
}
|
|
putchar ('\n');
|
|
}
|
|
i += len;
|
|
}
|
|
free (data);
|
|
}
|
|
|
|
/* Dump xcoff traceback tags section. */
|
|
|
|
static void
|
|
dump_xcoff32_tbtags (bfd *abfd,
|
|
const char *text, bfd_size_type text_size,
|
|
unsigned int text_start, unsigned int func_start)
|
|
{
|
|
unsigned int i;
|
|
|
|
if (func_start - text_start > text_size)
|
|
{
|
|
printf (_(" address beyond section size\n"));
|
|
return;
|
|
}
|
|
for (i = func_start - text_start; i < text_size; i+= 4)
|
|
if (bfd_get_32 (abfd, text + i) == 0)
|
|
{
|
|
unsigned int tb1;
|
|
unsigned int tb2;
|
|
unsigned int off;
|
|
|
|
printf (_(" tags at %08x\n"), i + 4);
|
|
if (i + 8 >= text_size)
|
|
goto truncated;
|
|
|
|
tb1 = bfd_get_32 (abfd, text + i + 4);
|
|
tb2 = bfd_get_32 (abfd, text + i + 8);
|
|
off = i + 12;
|
|
printf (" version: %u, lang: %u, global_link: %u, is_eprol: %u, has_tboff: %u, int_proc: %u\n",
|
|
(tb1 >> 24) & 0xff,
|
|
(tb1 >> 16) & 0xff,
|
|
(tb1 >> 15) & 1,
|
|
(tb1 >> 14) & 1,
|
|
(tb1 >> 13) & 1,
|
|
(tb1 >> 12) & 1);
|
|
printf (" has_ctl: %u, tocless: %u, fp_pres: %u, log_abort: %u, int_hndl: %u\n",
|
|
(tb1 >> 11) & 1,
|
|
(tb1 >> 10) & 1,
|
|
(tb1 >> 9) & 1,
|
|
(tb1 >> 8) & 1,
|
|
(tb1 >> 7) & 1);
|
|
printf (" name_pres: %u, uses_alloca: %u, cl_dis_inv: %u, saves_cr: %u, saves_lr: %u\n",
|
|
(tb1 >> 6) & 1,
|
|
(tb1 >> 5) & 1,
|
|
(tb1 >> 2) & 7,
|
|
(tb1 >> 1) & 1,
|
|
(tb1 >> 0) & 1);
|
|
printf (" stores_bc: %u, fixup: %u, fpr_saved: %-2u, spare3: %u, gpr_saved: %-2u\n",
|
|
(tb2 >> 31) & 1,
|
|
(tb2 >> 30) & 1,
|
|
(tb2 >> 24) & 63,
|
|
(tb2 >> 22) & 3,
|
|
(tb2 >> 16) & 63);
|
|
printf (" fixparms: %-3u floatparms: %-3u parm_on_stk: %u\n",
|
|
(tb2 >> 8) & 0xff,
|
|
(tb2 >> 1) & 0x7f,
|
|
(tb2 >> 0) & 1);
|
|
|
|
if (((tb2 >> 1) & 0x7fff) != 0)
|
|
{
|
|
unsigned int parminfo;
|
|
|
|
if (off >= text_size)
|
|
goto truncated;
|
|
parminfo = bfd_get_32 (abfd, text + off);
|
|
off += 4;
|
|
printf (" parminfo: 0x%08x\n", parminfo);
|
|
}
|
|
|
|
if ((tb1 >> 13) & 1)
|
|
{
|
|
unsigned int tboff;
|
|
|
|
if (off >= text_size)
|
|
goto truncated;
|
|
tboff = bfd_get_32 (abfd, text + off);
|
|
off += 4;
|
|
printf (" tb_offset: 0x%08x (start=0x%08x)\n",
|
|
tboff, text_start + i - tboff);
|
|
}
|
|
if ((tb1 >> 7) & 1)
|
|
{
|
|
unsigned int hand_mask;
|
|
|
|
if (off >= text_size)
|
|
goto truncated;
|
|
hand_mask = bfd_get_32 (abfd, text + off);
|
|
off += 4;
|
|
printf (" hand_mask_offset: 0x%08x\n", hand_mask);
|
|
}
|
|
if ((tb1 >> 11) & 1)
|
|
{
|
|
unsigned int ctl_info;
|
|
unsigned int j;
|
|
|
|
if (off >= text_size)
|
|
goto truncated;
|
|
ctl_info = bfd_get_32 (abfd, text + off);
|
|
off += 4;
|
|
printf (_(" number of CTL anchors: %u\n"), ctl_info);
|
|
for (j = 0; j < ctl_info; j++)
|
|
{
|
|
if (off >= text_size)
|
|
goto truncated;
|
|
printf (" CTL[%u]: %08x\n",
|
|
j, (unsigned)bfd_get_32 (abfd, text + off));
|
|
off += 4;
|
|
}
|
|
}
|
|
if ((tb1 >> 6) & 1)
|
|
{
|
|
unsigned int name_len;
|
|
unsigned int j;
|
|
|
|
if (off >= text_size)
|
|
goto truncated;
|
|
name_len = bfd_get_16 (abfd, text + off);
|
|
off += 2;
|
|
printf (_(" Name (len: %u): "), name_len);
|
|
if (off + name_len >= text_size)
|
|
{
|
|
printf (_("[truncated]\n"));
|
|
goto truncated;
|
|
}
|
|
for (j = 0; j < name_len; j++)
|
|
if (ISPRINT (text[off + j]))
|
|
putchar (text[off + j]);
|
|
else
|
|
printf ("[%02x]", (unsigned char)text[off + j]);
|
|
putchar ('\n');
|
|
off += name_len;
|
|
}
|
|
if ((tb1 >> 5) & 1)
|
|
{
|
|
if (off >= text_size)
|
|
goto truncated;
|
|
printf (" alloca reg: %u\n",
|
|
(unsigned) bfd_get_8 (abfd, text + off));
|
|
off++;
|
|
}
|
|
printf (_(" (end of tags at %08x)\n"), text_start + off);
|
|
return;
|
|
}
|
|
printf (_(" no tags found\n"));
|
|
return;
|
|
|
|
truncated:
|
|
printf (_(" Truncated .text section\n"));
|
|
return;
|
|
}
|
|
|
|
static void
|
|
dump_xcoff32_traceback (bfd *abfd, struct xcoff_dump *data)
|
|
{
|
|
unsigned int i;
|
|
unsigned int scnum_text = -1;
|
|
unsigned int text_vma;
|
|
asection *text_sec;
|
|
bfd_size_type text_size;
|
|
char *text;
|
|
|
|
if (data->syms == NULL || data->sects == NULL)
|
|
return;
|
|
|
|
/* Read text section. */
|
|
text_sec = bfd_get_section_by_name (abfd, ".text");
|
|
if (text_sec == NULL)
|
|
return;
|
|
text_vma = bfd_get_section_vma (abfd, text_sec);
|
|
|
|
text_size = bfd_get_section_size (text_sec);
|
|
text = (char *) xmalloc (text_size);
|
|
bfd_get_section_contents (abfd, text_sec, text, 0, text_size);
|
|
|
|
for (i = 0; i < data->nscns; i++)
|
|
if (data->sects[i].flags == STYP_TEXT)
|
|
{
|
|
scnum_text = i + 1;
|
|
break;
|
|
}
|
|
if (scnum_text == (unsigned int)-1)
|
|
return;
|
|
|
|
for (i = 0; i < data->nsyms; i++)
|
|
{
|
|
union xcoff32_symbol *s = &data->syms[i];
|
|
|
|
switch (s->sym.sclass)
|
|
{
|
|
case C_EXT:
|
|
case C_HIDEXT:
|
|
case C_WEAKEXT:
|
|
if (s->sym.scnum == scnum_text
|
|
&& s->sym.numaux > 0)
|
|
{
|
|
union external_auxent *aux = &s[s->sym.numaux].aux;
|
|
|
|
unsigned int smtyp;
|
|
unsigned int smclas;
|
|
|
|
smtyp = bfd_h_get_8 (abfd, aux->x_csect.x_smtyp);
|
|
smclas = bfd_h_get_8 (abfd, aux->x_csect.x_smclas);
|
|
if (SMTYP_SMTYP (smtyp) == XTY_LD
|
|
&& (smclas == XMC_PR
|
|
|| smclas == XMC_GL
|
|
|| smclas == XMC_XO))
|
|
{
|
|
printf ("%08x: ", s->sym.val);
|
|
xcoff32_print_symbol (data, i);
|
|
putchar ('\n');
|
|
dump_xcoff32_tbtags (abfd, text, text_size,
|
|
text_vma, s->sym.val);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
i += s->sym.numaux;
|
|
}
|
|
free (text);
|
|
}
|
|
|
|
/* Dump the TOC symbols. */
|
|
|
|
static void
|
|
dump_xcoff32_toc (bfd *abfd, struct xcoff_dump *data)
|
|
{
|
|
unsigned int i;
|
|
unsigned int nbr_ent;
|
|
unsigned int size;
|
|
|
|
printf (_("TOC:\n"));
|
|
|
|
if (data->syms == NULL)
|
|
return;
|
|
|
|
nbr_ent = 0;
|
|
size = 0;
|
|
|
|
for (i = 0; i < data->nsyms; i++)
|
|
{
|
|
union xcoff32_symbol *s = &data->syms[i];
|
|
|
|
switch (s->sym.sclass)
|
|
{
|
|
case C_EXT:
|
|
case C_HIDEXT:
|
|
case C_WEAKEXT:
|
|
if (s->sym.numaux > 0)
|
|
{
|
|
union external_auxent *aux = &s[s->sym.numaux].aux;
|
|
unsigned int smclas;
|
|
unsigned int ent_sz;
|
|
|
|
smclas = bfd_h_get_8 (abfd, aux->x_csect.x_smclas);
|
|
if (smclas == XMC_TC
|
|
|| smclas == XMC_TD
|
|
|| smclas == XMC_TC0)
|
|
{
|
|
ent_sz = bfd_h_get_32 (abfd, aux->x_scn.x_scnlen);
|
|
printf ("%08x %08x ",
|
|
s->sym.val, ent_sz);
|
|
xcoff32_print_symbol (data, i);
|
|
putchar ('\n');
|
|
nbr_ent++;
|
|
size += ent_sz;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
i += s->sym.numaux;
|
|
}
|
|
printf (_("Nbr entries: %-8u Size: %08x (%u)\n"),
|
|
nbr_ent, size, size);
|
|
}
|
|
|
|
/* Handle an rs6000 xcoff file. */
|
|
|
|
static void
|
|
dump_xcoff32 (bfd *abfd, struct external_filehdr *fhdr)
|
|
{
|
|
struct xcoff_dump data;
|
|
|
|
data.nscns = bfd_h_get_16 (abfd, fhdr->f_nscns);
|
|
data.symptr = bfd_h_get_32 (abfd, fhdr->f_symptr);
|
|
data.nsyms = bfd_h_get_32 (abfd, fhdr->f_nsyms);
|
|
data.opthdr = bfd_h_get_16 (abfd, fhdr->f_opthdr);
|
|
data.sects = NULL;
|
|
data.syms = NULL;
|
|
data.strings = NULL;
|
|
data.strings_size = 0;
|
|
|
|
if (options[OPT_FILE_HEADER].selected)
|
|
dump_xcoff32_file_header (abfd, fhdr, &data);
|
|
|
|
if (options[OPT_AOUT].selected)
|
|
dump_xcoff32_aout_header (abfd, &data);
|
|
|
|
if (options[OPT_SYMS].selected
|
|
|| options[OPT_RELOCS].selected
|
|
|| options[OPT_LINENO].selected
|
|
|| options[OPT_TRACEBACK].selected)
|
|
xcoff32_read_sections (abfd, &data);
|
|
|
|
if (options[OPT_SECTIONS].selected)
|
|
dump_xcoff32_sections_header (abfd, &data);
|
|
|
|
if (options[OPT_SYMS].selected
|
|
|| options[OPT_RELOCS].selected
|
|
|| options[OPT_LINENO].selected
|
|
|| options[OPT_EXCEPT].selected
|
|
|| options[OPT_TRACEBACK].selected
|
|
|| options[OPT_TOC].selected)
|
|
xcoff32_read_symbols (abfd, &data);
|
|
|
|
if (options[OPT_SYMS].selected)
|
|
dump_xcoff32_symbols (abfd, &data);
|
|
|
|
if (options[OPT_RELOCS].selected)
|
|
dump_xcoff32_relocs (abfd, &data);
|
|
|
|
if (options[OPT_LINENO].selected)
|
|
dump_xcoff32_lineno (abfd, &data);
|
|
|
|
if (options[OPT_LOADER].selected)
|
|
dump_xcoff32_loader (abfd);
|
|
|
|
if (options[OPT_EXCEPT].selected)
|
|
dump_xcoff32_except (abfd, &data);
|
|
|
|
if (options[OPT_TYPCHK].selected)
|
|
dump_xcoff32_typchk (abfd);
|
|
|
|
if (options[OPT_TRACEBACK].selected)
|
|
dump_xcoff32_traceback (abfd, &data);
|
|
|
|
if (options[OPT_TOC].selected)
|
|
dump_xcoff32_toc (abfd, &data);
|
|
|
|
free (data.sects);
|
|
free (data.strings);
|
|
free (data.syms);
|
|
}
|
|
|
|
/* Dump ABFD (according to the options[] array). */
|
|
|
|
static void
|
|
xcoff_dump (bfd *abfd)
|
|
{
|
|
struct external_filehdr fhdr;
|
|
unsigned short magic;
|
|
|
|
/* Read file header. */
|
|
if (bfd_seek (abfd, 0, SEEK_SET) != 0
|
|
|| bfd_bread (&fhdr, sizeof (fhdr), abfd) != sizeof (fhdr))
|
|
{
|
|
non_fatal (_("cannot read header"));
|
|
return;
|
|
}
|
|
|
|
/* Decoding. We don't use the bfd/coff function to get all the fields. */
|
|
magic = bfd_h_get_16 (abfd, fhdr.f_magic);
|
|
if (options[OPT_FILE_HEADER].selected)
|
|
{
|
|
printf (_("File header:\n"));
|
|
printf (_(" magic: 0x%04x (0%04o) "), magic, magic);
|
|
switch (magic)
|
|
{
|
|
case U802WRMAGIC:
|
|
printf (_("(WRMAGIC: writable text segments)"));
|
|
break;
|
|
case U802ROMAGIC:
|
|
printf (_("(ROMAGIC: readonly sharablee text segments)"));
|
|
break;
|
|
case U802TOCMAGIC:
|
|
printf (_("(TOCMAGIC: readonly text segments and TOC)"));
|
|
break;
|
|
default:
|
|
printf (_("unknown magic"));
|
|
}
|
|
putchar ('\n');
|
|
}
|
|
if (magic == U802ROMAGIC || magic == U802WRMAGIC || magic == U802TOCMAGIC)
|
|
dump_xcoff32 (abfd, &fhdr);
|
|
else
|
|
printf (_(" Unhandled magic\n"));
|
|
}
|
|
|
|
/* Vector for xcoff. */
|
|
|
|
const struct objdump_private_desc objdump_private_desc_xcoff =
|
|
{
|
|
xcoff_help,
|
|
xcoff_filter,
|
|
xcoff_dump,
|
|
options
|
|
};
|