diff --git a/binutils/.Sanitize b/binutils/.Sanitize index be27465062..f3166dac95 100644 --- a/binutils/.Sanitize +++ b/binutils/.Sanitize @@ -90,6 +90,8 @@ rclex.l rcparse.y rdcoff.c rddbg.c +readelf.c +readelf.h resbin.c rescoff.c resrc.c @@ -122,6 +124,34 @@ Things-to-lose: Do-last: +v850e_files="readelf.c" +if ( echo $* | grep keep\-v850e > /dev/null ) ; then + for i in $v850e_files ; do + if test ! -d $i && (grep sanitize-v850e $i > /dev/null) ; then + if [ -n "${verbose}" ] ; then + echo Keeping v850e stuff in $i + fi + fi + done +else + for i in $v850e_files ; do + if test -r $i && (grep sanitize-v850e $i > /dev/null) ; then + if [ -n "${verbose}" ] ; then + echo Removing traces of \"v850e\" from $i... + fi + cp $i new + sed '/start\-sanitize\-v850e/,/end\-sanitize\-v850e/d' < $i > new + if [ -n "${safe}" -a ! -f .Recover/$i ] ; then + if [ -n "${verbose}" ] ; then + echo Caching $i in .Recover... + fi + mv $i .Recover + fi + mv new $i + fi + done +fi + # This must come after all other sanitizations. Re-sanitize the .pot # file. if [ -n "${verbose}" ]; then diff --git a/binutils/Makefile.am b/binutils/Makefile.am index b06b6f5264..c4529b2fe4 100644 --- a/binutils/Makefile.am +++ b/binutils/Makefile.am @@ -29,6 +29,8 @@ STRIP_PROG=strip-new STRINGS_PROG=strings +READELF_PROG=readelf + # These should all be the same program too. SIZE_PROG=size NM_PROG=nm-new @@ -49,9 +51,9 @@ SRCONV_PROG=srconv$(EXEEXT) sysdump$(EXEEXT) coffdump$(EXEEXT) man_MANS = ar.1 nm.1 objdump.1 ranlib.1 size.1 strings.1 strip.1 objcopy.1 \ addr2line.1 nlmconv.1 $(DEMANGLER_PROG).1 -PROGS = $(SIZE_PROG) $(OBJDUMP_PROG) $(NM_PROG) $(AR_PROG) $(STRINGS_PROG) $(STRIP_PROG) $(RANLIB_PROG) $(DEMANGLER_PROG) $(OBJCOPY_PROG) @BUILD_NLMCONV@ @BUILD_SRCONV@ @BUILD_DLLTOOL@ @BUILD_WINDRES@ $(ADDR2LINE_PROG) +PROGS = $(SIZE_PROG) $(OBJDUMP_PROG) $(NM_PROG) $(AR_PROG) $(STRINGS_PROG) $(STRIP_PROG) $(RANLIB_PROG) $(DEMANGLER_PROG) $(OBJCOPY_PROG) @BUILD_NLMCONV@ @BUILD_SRCONV@ @BUILD_DLLTOOL@ @BUILD_WINDRES@ $(ADDR2LINE_PROG) $(READELF_PROG) -bin_PROGRAMS = $(SIZE_PROG) $(OBJDUMP_PROG) $(AR_PROG) $(STRINGS_PROG) $(RANLIB_PROG) $(DEMANGLER_PROG) $(OBJCOPY_PROG) @BUILD_NLMCONV@ @BUILD_SRCONV@ @BUILD_DLLTOOL@ @BUILD_WINDRES@ $(ADDR2LINE_PROG) +bin_PROGRAMS = $(SIZE_PROG) $(OBJDUMP_PROG) $(AR_PROG) $(STRINGS_PROG) $(RANLIB_PROG) $(DEMANGLER_PROG) $(OBJCOPY_PROG) @BUILD_NLMCONV@ @BUILD_SRCONV@ @BUILD_DLLTOOL@ @BUILD_WINDRES@ $(ADDR2LINE_PROG) $(READELF_PROG) ## We need a special rule to install the programs which are built with -new noinst_PROGRAMS = $(NM_PROG) $(STRIP_PROG) @@ -71,7 +73,7 @@ DEP = mkdep INCLUDES = -D_GNU_SOURCE -I. -I$(srcdir) -I../bfd -I$(BFDDIR) -I$(INCDIR) @HDEFINES@ -I$(srcdir)/../intl -I../intl -DLOCALEDIR="\"$(prefix)/share/locale\"" HFILES = arsup.h bucomm.h budbg.h coffgrok.h debug.h nlmconv.h dlltool.h \ - windres.h + windres.h readelf.h GENERATED_HFILES = arparse.h sysroff.h sysinfo.h defparse.h @@ -80,7 +82,7 @@ CFILES = addr2line.c ar.c arsup.c bucomm.c coffdump.c coffgrok.c debug.c \ maybe-strip.c nlmconv.c nm.c not-ranlib.c not-strip.c \ objcopy.c objdump.c prdbg.c rdcoff.c rddbg.c size.c srconv.c \ stabs.c strings.c sysdump.c version.c wrstabs.c \ - windres.c resrc.c rescoff.c resbin.c + windres.c resrc.c rescoff.c resbin.c readelf.c GENERATED_CFILES = \ underscore.c arparse.c arlex.c sysroff.c sysinfo.c syslex.c \ @@ -154,6 +156,9 @@ objcopy_SOURCES = objcopy.c not-strip.c $(WRITE_DEBUG_SRCS) $(BULIBS) strings_SOURCES = strings.c $(BULIBS) +readelf_SOURCES = readelf.c version.c +readelf_LDADD = $(INTLLIBS) + strip_new_SOURCES = objcopy.c is-strip.c $(WRITE_DEBUG_SRCS) $(BULIBS) nm_new_SOURCES = nm.c $(BULIBS) @@ -393,6 +398,9 @@ objdump.o: objdump.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \ $(INCDIR)/getopt.h $(INCDIR)/progress.h bucomm.h config.h \ $(INCDIR)/fopen-same.h $(INCDIR)/dis-asm.h $(INCDIR)/libiberty.h \ $(INCDIR)/demangle.h debug.h budbg.h $(INCDIR)/aout/aout64.h +readelf.o: readelf.c $(INCDIR)/ansidecl.h ./readelf.h \ + $(INCDIR)/progress.h config.h $(INCDIR)/fopen-same.h ../bfd/bfd.h \ + $(INCDIR)/getopt.h $(INCDIR)/libiberty.h $(INCDIR)/elf/common.h prdbg.o: prdbg.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \ bucomm.h config.h $(INCDIR)/fopen-same.h $(INCDIR)/libiberty.h \ debug.h budbg.h diff --git a/binutils/Makefile.in b/binutils/Makefile.in index bd28203399..ee1463e1ae 100644 --- a/binutils/Makefile.in +++ b/binutils/Makefile.in @@ -102,6 +102,8 @@ STRIP_PROG=strip-new STRINGS_PROG=strings +READELF_PROG=readelf + # These should all be the same program too. SIZE_PROG=size NM_PROG=nm-new @@ -122,9 +124,9 @@ SRCONV_PROG=srconv$(EXEEXT) sysdump$(EXEEXT) coffdump$(EXEEXT) man_MANS = ar.1 nm.1 objdump.1 ranlib.1 size.1 strings.1 strip.1 objcopy.1 \ addr2line.1 nlmconv.1 $(DEMANGLER_PROG).1 -PROGS = $(SIZE_PROG) $(OBJDUMP_PROG) $(NM_PROG) $(AR_PROG) $(STRINGS_PROG) $(STRIP_PROG) $(RANLIB_PROG) $(DEMANGLER_PROG) $(OBJCOPY_PROG) @BUILD_NLMCONV@ @BUILD_SRCONV@ @BUILD_DLLTOOL@ @BUILD_WINDRES@ $(ADDR2LINE_PROG) +PROGS = $(SIZE_PROG) $(OBJDUMP_PROG) $(NM_PROG) $(AR_PROG) $(STRINGS_PROG) $(STRIP_PROG) $(RANLIB_PROG) $(DEMANGLER_PROG) $(OBJCOPY_PROG) @BUILD_NLMCONV@ @BUILD_SRCONV@ @BUILD_DLLTOOL@ @BUILD_WINDRES@ $(ADDR2LINE_PROG) $(READELF_PROG) -bin_PROGRAMS = $(SIZE_PROG) $(OBJDUMP_PROG) $(AR_PROG) $(STRINGS_PROG) $(RANLIB_PROG) $(DEMANGLER_PROG) $(OBJCOPY_PROG) @BUILD_NLMCONV@ @BUILD_SRCONV@ @BUILD_DLLTOOL@ @BUILD_WINDRES@ $(ADDR2LINE_PROG) +bin_PROGRAMS = $(SIZE_PROG) $(OBJDUMP_PROG) $(AR_PROG) $(STRINGS_PROG) $(RANLIB_PROG) $(DEMANGLER_PROG) $(OBJCOPY_PROG) @BUILD_NLMCONV@ @BUILD_SRCONV@ @BUILD_DLLTOOL@ @BUILD_WINDRES@ $(ADDR2LINE_PROG) $(READELF_PROG) noinst_PROGRAMS = $(NM_PROG) $(STRIP_PROG) @@ -143,7 +145,7 @@ DEP = mkdep INCLUDES = -D_GNU_SOURCE -I. -I$(srcdir) -I../bfd -I$(BFDDIR) -I$(INCDIR) @HDEFINES@ -I$(srcdir)/../intl -I../intl -DLOCALEDIR="\"$(prefix)/share/locale\"" HFILES = arsup.h bucomm.h budbg.h coffgrok.h debug.h nlmconv.h dlltool.h \ - windres.h + windres.h readelf.h GENERATED_HFILES = arparse.h sysroff.h sysinfo.h defparse.h @@ -152,7 +154,7 @@ CFILES = addr2line.c ar.c arsup.c bucomm.c coffdump.c coffgrok.c debug.c \ maybe-strip.c nlmconv.c nm.c not-ranlib.c not-strip.c \ objcopy.c objdump.c prdbg.c rdcoff.c rddbg.c size.c srconv.c \ stabs.c strings.c sysdump.c version.c wrstabs.c \ - windres.c resrc.c rescoff.c resbin.c + windres.c resrc.c rescoff.c resbin.c readelf.c GENERATED_CFILES = \ underscore.c arparse.c arlex.c sysroff.c sysinfo.c syslex.c \ @@ -204,6 +206,9 @@ objcopy_SOURCES = objcopy.c not-strip.c $(WRITE_DEBUG_SRCS) $(BULIBS) strings_SOURCES = strings.c $(BULIBS) +readelf_SOURCES = readelf.c version.c +readelf_LDADD = $(INTLLIBS) + strip_new_SOURCES = objcopy.c is-strip.c $(WRITE_DEBUG_SRCS) $(BULIBS) nm_new_SOURCES = nm.c $(BULIBS) @@ -254,7 +259,7 @@ CONFIG_CLEAN_FILES = bin_PROGRAMS = size$(EXEEXT) objdump$(EXEEXT) ar$(EXEEXT) \ strings$(EXEEXT) ranlib$(EXEEXT) c++filt$(EXEEXT) objcopy$(EXEEXT) \ @BUILD_NLMCONV@ @BUILD_SRCONV@ @BUILD_DLLTOOL@ @BUILD_WINDRES@ \ -addr2line$(EXEEXT) +addr2line$(EXEEXT) readelf$(EXEEXT) noinst_PROGRAMS = nm-new$(EXEEXT) strip-new$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) @@ -321,6 +326,9 @@ addr2line_OBJECTS = addr2line.o bucomm.o version.o filemode.o addr2line_LDADD = $(LDADD) addr2line_DEPENDENCIES = ../bfd/libbfd.la ../libiberty/libiberty.a addr2line_LDFLAGS = +readelf_OBJECTS = readelf.o version.o +readelf_DEPENDENCIES = +readelf_LDFLAGS = nm_new_OBJECTS = nm.o bucomm.o version.o filemode.o nm_new_LDADD = $(LDADD) nm_new_DEPENDENCIES = ../bfd/libbfd.la ../libiberty/libiberty.a @@ -360,8 +368,8 @@ DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = tar GZIP = --best -SOURCES = $(nlmconv_SOURCES) $(srconv_SOURCES) $(sysdump_SOURCES) $(coffdump_SOURCES) $(dlltool_SOURCES) $(windres_SOURCES) $(size_SOURCES) $(objdump_SOURCES) $(ar_SOURCES) $(strings_SOURCES) $(ranlib_SOURCES) $(c__filt_SOURCES) $(objcopy_SOURCES) $(addr2line_SOURCES) $(nm_new_SOURCES) $(strip_new_SOURCES) -OBJECTS = $(nlmconv_OBJECTS) $(srconv_OBJECTS) $(sysdump_OBJECTS) $(coffdump_OBJECTS) $(dlltool_OBJECTS) $(windres_OBJECTS) $(size_OBJECTS) $(objdump_OBJECTS) $(ar_OBJECTS) $(strings_OBJECTS) $(ranlib_OBJECTS) $(c__filt_OBJECTS) $(objcopy_OBJECTS) $(addr2line_OBJECTS) $(nm_new_OBJECTS) $(strip_new_OBJECTS) +SOURCES = $(nlmconv_SOURCES) $(srconv_SOURCES) $(sysdump_SOURCES) $(coffdump_SOURCES) $(dlltool_SOURCES) $(windres_SOURCES) $(size_SOURCES) $(objdump_SOURCES) $(ar_SOURCES) $(strings_SOURCES) $(ranlib_SOURCES) $(c__filt_SOURCES) $(objcopy_SOURCES) $(addr2line_SOURCES) $(readelf_SOURCES) $(nm_new_SOURCES) $(strip_new_SOURCES) +OBJECTS = $(nlmconv_OBJECTS) $(srconv_OBJECTS) $(sysdump_OBJECTS) $(coffdump_OBJECTS) $(dlltool_OBJECTS) $(windres_OBJECTS) $(size_OBJECTS) $(objdump_OBJECTS) $(ar_OBJECTS) $(strings_OBJECTS) $(ranlib_OBJECTS) $(c__filt_OBJECTS) $(objcopy_OBJECTS) $(addr2line_OBJECTS) $(readelf_OBJECTS) $(nm_new_OBJECTS) $(strip_new_OBJECTS) all: all-recursive-am all-am @@ -531,6 +539,10 @@ addr2line$(EXEEXT): $(addr2line_OBJECTS) $(addr2line_DEPENDENCIES) @rm -f addr2line$(EXEEXT) $(LINK) $(addr2line_LDFLAGS) $(addr2line_OBJECTS) $(addr2line_LDADD) $(LIBS) +readelf$(EXEEXT): $(readelf_OBJECTS) $(readelf_DEPENDENCIES) + @rm -f readelf$(EXEEXT) + $(LINK) $(readelf_LDFLAGS) $(readelf_OBJECTS) $(readelf_LDADD) $(LIBS) + nm-new$(EXEEXT): $(nm_new_OBJECTS) $(nm_new_DEPENDENCIES) @rm -f nm-new$(EXEEXT) $(LINK) $(nm_new_LDFLAGS) $(nm_new_OBJECTS) $(nm_new_LDADD) $(LIBS) @@ -1158,6 +1170,9 @@ objdump.o: objdump.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \ $(INCDIR)/getopt.h $(INCDIR)/progress.h bucomm.h config.h \ $(INCDIR)/fopen-same.h $(INCDIR)/dis-asm.h $(INCDIR)/libiberty.h \ $(INCDIR)/demangle.h debug.h budbg.h $(INCDIR)/aout/aout64.h +readelf.o: readelf.c $(INCDIR)/ansidecl.h ./readelf.h \ + $(INCDIR)/progress.h config.h $(INCDIR)/fopen-same.h ../bfd/bfd.h \ + $(INCDIR)/getopt.h $(INCDIR)/libiberty.h $(INCDIR)/elf/common.h prdbg.o: prdbg.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \ bucomm.h config.h $(INCDIR)/fopen-same.h $(INCDIR)/libiberty.h \ debug.h budbg.h diff --git a/binutils/binutils.texi b/binutils/binutils.texi index 70f68b384f..8f20e52819 100644 --- a/binutils/binutils.texi +++ b/binutils/binutils.texi @@ -6,7 +6,7 @@ @format START-INFO-DIR-ENTRY * Binutils: (binutils). The GNU binary utilities "ar", "objcopy", - "objdump", "nm", "nlmconv", "size", + "objdump", "nm", "nlmconv", "size", "readelf" "strings", "strip", "ranlib" and "dlltool". END-INFO-DIR-ENTRY @end format @@ -39,7 +39,7 @@ into another language, under the above conditions for modified versions. @synindex ky cp @c @c This file documents the GNU binary utilities "ar", "ld", "objcopy", -@c "objdump", "nm", "size", "strings", "strip", and "ranlib". +@c "objdump", "nm", "size", "strings", "strip", "readelf" and "ranlib". @c @c Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc. @c @@ -105,6 +105,9 @@ Display information from object files @item ranlib Generate index to archive contents +@item readelf +Display the contents of ELF format files. + @item size List file section sizes and total size @@ -137,6 +140,7 @@ Create the files needed to build and use Dynamic Link Libraries * objcopy:: Copy and translate object files * objdump:: Display information from object files * ranlib:: Generate index to archive contents +* readelf:: Display the contents of ELF format files. * size:: List section sizes and total size * strings:: List printable strings from files * strip:: Discard symbols @@ -2262,6 +2266,106 @@ Displays dlltool's version number and then exits. @end table +@node readelf +@chapter readelf + +@cindex ELF file information +@kindex readelf + +@smallexample +readelf [ -a | --all ] + [ -h | --file-header] + [ -l | --program-headers | --segments] + [ -S | --sections] + [ -s | --symbols] + [ -r | --relocs] + [ -d | --dynamic] + [ -V | --version-info] + [ -D | --use-dynamic] + [ -x | --hex-dump=] + [ -v | --version] + [ -H | --help] + @var{elffile}@dots{} +@end smallexample + +@code{readelf} displays information about one or more ELF format object +files. The options control what particular information to display. + +@var{elffile}@dots{} are the object files to be examined. At the +moment, @code{readelf} does not support examining archives, nor does it +support examing 64 bit ELF files. + +The long and short forms of options, shown here as alternatives, are +equivalent. At least one option besides @samp{-v} or @samp{-H} must be +given. + +@table @code +@item -a +@itemx --all +Equivalent to specifiying @samp{--file-header}, +@samp{--program-headers}, @samp{--sections}, @samp{--symbols}, +@samp{--relocs}, @samp{--dynamic} and @samp{--version-info}. + +@item -h +@itemx --file-header +@cindex ELF file header information +Displays the information contained in the ELF header at the start of the +file. + +@item -l +@itemx --program-headers +@itemx --segments +@cindex ELF program header information +@cindex ELF segment information +Displays the information contained in the file's segment headers, if it +has any. + +@item -S +@itemx --sections +@cindex ELF section information +Displays the information contained in the file's section headers, if it +has any. + +@item -s +@itemx --symbols +@cindex ELF symbol table information +Displays the entries in symbol table section of the file, if it has one. + +@item -r +@itemx --relocs +@cindex ELF reloc information +Displays the contents of the file's relocation section, if it ha one. + +@item -d +@itemx --dynamic +@cindex ELF dynamic section information +Displays the contents of the file's dynamic section, if it has one. + +@item -V +@itemx --version-info +@cindex ELF version sections informations +Displays the contents of the version sections in the file, it they +exist. + +@item -D +@itemx --use-dynamic +When displaying symbols, this option makes @code{readelf} use the +symblol table in the file's dynamic section, rather than the one in the +symbols section. + +@item -x +@itemx --hex-dump= +Displays the contents of the indicated section as a hexadecimal dump. + +@item -v +@itemx --version +Display the version number of readelf. + +@item -H +@itemx --help +Display the command line options understood by @code{readelf}. + +@end table @node Selecting The Target System diff --git a/binutils/readelf.c b/binutils/readelf.c new file mode 100644 index 0000000000..ee2f079de6 --- /dev/null +++ b/binutils/readelf.c @@ -0,0 +1,2254 @@ +/* readelf.c -- display contents of an ELF format file + Copyright (C) 1998 Free Software Foundation, Inc. + + Originally developed by Eric Youngdale + Modifications by Nick Clifton + + 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 2 of the License, 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, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "readelf.h" +#include "getopt.h" +#include "bucomm.h" + +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif + +unsigned int dynamic_addr; +unsigned int dynamic_size; +char * pint = ""; +char * program_name = "readelf"; + +int dynamic_info [DT_JMPREL + 1]; +int version_info [16]; + +int must_swap = 0; + +unsigned int rel_size; +int loadaddr = -1; + +unsigned int rela_addr; +unsigned int rela_size; +char * strtab; +int symtab_index; +int lastmapped; +char * header; + +Elf_Dyn * dpnt; +Elf_Rel * rpnt; +Elf_Shdr * elf_sections; +Elf_Ehdr * epnt; +Elf_Sym * symtab; + +int show_name; +int do_dynamic; +int do_syms; +int do_reloc; +int do_section; +int do_load; +int do_using_dynamic; +int do_header; +int do_dump; +int do_version; +long int expected_endian; + +char * dyntype[] = +{ + "NULL", "NEEDED","PLTRELSZ","PLTGOT","HASH","STRTAB","SYMTAB","RELA", + "RELASZ","RELAENT","STRSZ","SYMENT","INIT","FINI","SONAME","RPATH", + "SYMBOLIC","REL","RELSZ","RELENT","PLTREL","DEBUG","TEXTREL","JMPREL" +}; + +char * vertype[] = +{ + "VERNEEDNUM", "VERNEED", "VERDEFNUM", "VERDEF", + "", "", "", "", "", "", "", "", "", "", "", "VERSYM" +}; + +char * filtertype[] = +{ + "FILTER", "USED", "AUXILIARY" +}; + + +char * sttinfo[] = {"NOTYPE","OBJECT","FUNC","SECTION","FILE"}; +char * stbinfo[] = {"LOCAL","GLOBAL","WEAK"}; + +#define SECTION_NAME(X) (& header [lastmapped + (X)->sh_name]) + +#define NUM_DUMP_SECTS 100 +char dump_sects [NUM_DUMP_SECTS]; +#define HEX_DUMP 1 +#define DISASS_DUMP 2 + +/* Forward declarations for dumb compilers. */ +static char * get_i386_rel_type PARAMS ((bfd_vma rtype)); +static char * get_m68k_rel_type PARAMS ((bfd_vma rtype)); +static char * get_sparc_rel_type PARAMS ((bfd_vma rtype)); +static char * get_m32r_rel_type PARAMS ((bfd_vma rtype)); +static char * get_v850_rel_type PARAMS ((bfd_vma rtype)); +static char * get_d10v_rel_type PARAMS ((bfd_vma rtype)); +static char * get_d30v_rel_type PARAMS ((bfd_vma rtype)); +static char * get_sh_rel_type PARAMS ((bfd_vma rtype)); +static char * get_mn10300_rel_type PARAMS ((bfd_vma rtype)); +static char * get_mn10200_rel_type PARAMS ((bfd_vma rtype)); +static void dump_relocations PARAMS ((Elf_Rel * rpnt, int rel_size)); +static char * get_file_type PARAMS ((unsigned short e_type)); +static char * get_machine_name PARAMS ((unsigned short e_machine)); +static char * get_segment_type PARAMS ((unsigned long p_type)); +static char * get_section_type_name PARAMS ((unsigned int sh_type)); +static void usage PARAMS ((void)); +static void parse_args PARAMS ((int argc, char ** argv)); +static int process_elf_header PARAMS ((void)); +static void process_program_headers PARAMS ((void)); +static void process_section_headers PARAMS ((void)); +static void process_dynamic_segment PARAMS ((void)); +static void process_symbol_table PARAMS ((void)); +static void process_section_contents PARAMS ((void)); +static void process_file PARAMS ((char * file_name)); + + +#define SWAP2(val) ( (((val) << 8) & (0xff << 8)) \ + | (((val) >> 8) & (0xff << 0))) + +#define SWAP4(val) ( (((val) << 24) & (0xff << 24)) \ + | (((val) << 8) & (0xff << 16)) \ + | (((val) >> 8) & (0xff << 8)) \ + | (((val) >> 24) & (0xff << 0))) + +/* Warning: This macro assumes 8 bits in a char. */ +#define BYTE_SWAP(pointer, field) \ + if (sizeof ((pointer)->field) == 2) \ + { \ + unsigned short val = (pointer)->field ; \ + new_header->field = SWAP2 (val); \ + } \ + else if (sizeof ((pointer)->field) != 4) \ + abort (); \ + else \ + { \ + unsigned long val = (pointer)->field ; \ + new_header->field = SWAP4 (val); \ + } + + +#ifdef ANSI_PROTOTYPES +static void +error (const char * message, ...) +{ + va_list args; + + fprintf (stderr, _("%s: Error: "), program_name); + va_start (args, message); + vfprintf (stderr, message, args); + va_end (args); + return; +} + +static void +warn (const char * message, ...) +{ + va_list args; + + fprintf (stderr, _("%s: Warning: "), program_name); + va_start (args, message); + vfprintf (stderr, message, args); + va_end (args); + return; +} +#else +static void +error (va_alist) +{ + char * message; + va_list args; + + fprintf (stderr, _("%s: Error: "), program_name); + va_start (args); + message = va_arg (args, char *); + vfprintf (stderr, message, args); + va_end (args); + return; +} + +static void +warn (va_alist) + va_dcl; +{ + char * message; + va_list args; + + fprintf (stderr, _("%s: Warning: "), program_name); + va_start (args); + message = va_arg (args, char *); + vfprintf (stderr, message, args); + va_end (args); + return; +} +#endif + + +static char * +get_i386_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_386_NONE"; + case 1: return "R_386_32"; + case 2: return "R_386_PC32"; + case 3: return "R_386_GOT32"; + case 4: return "R_386_PLT32"; + case 5: return "R_386_COPY"; + case 6: return "R_386_GLOB_DAT"; + case 7: return "R_386_JMP_SLOT"; + case 8: return "R_386_RELATIVE"; + case 9: return "R_386_GOTOFF"; + case 10: return "R_386_GOTPC"; + case 20: return "R_386_16"; + case 21: return "R_386_PC16"; + case 22: return "R_386_PC8"; + case 23: return "R_386_max"; + default: return _("*INVALID*"); + } +} + +static char * +get_m68k_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_68K_NONE"; + case 1: return "R_68K_32"; + case 2: return "R_68K_16"; + case 3: return "R_68K_8"; + case 4: return "R_68K_PC32"; + case 5: return "R_68K_PC16"; + case 6: return "R_68K_PC8"; + case 7: return "R_68K_GOT32"; + case 8: return "R_68K_GOT16"; + case 9: return "R_68K_GOT8"; + case 10: return "R_68K_GOT32O"; + case 11: return "R_68K_GOT16O"; + case 12: return "R_68K_GOT8O"; + case 13: return "R_68K_PLT32"; + case 14: return "R_68K_PLT16"; + case 15: return "R_68K_PLT8"; + case 16: return "R_68K_PLT32O"; + case 17: return "R_68K_PLT16O"; + case 18: return "R_68K_PLT8O"; + case 19: return "R_68K_COPY"; + case 20: return "R_68K_GLOB_DAT"; + case 21: return "R_68K_JMP_SLOT"; + case 22: return "R_68K_RELATIVE"; + default: return _("*INVALID*"); + } +} + + +static char * +get_sparc_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_SPARC_NONE"; + case 1: return "R_SPARC_8"; + case 2: return "R_SPARC_16"; + case 3: return "R_SPARC_32"; + case 4: return "R_SPARC_DISP8"; + case 5: return "R_SPARC_DISP16"; + case 6: return "R_SPARC_DISP32"; + case 7: return "R_SPARC_WDISP30"; + case 8: return "R_SPARC_WDISP22"; + case 9: return "R_SPARC_HI22"; + case 10: return "R_SPARC_22"; + case 11: return "R_SPARC_13"; + case 12: return "R_SPARC_LO10"; + case 13: return "R_SPARC_GOT10"; + case 14: return "R_SPARC_GOT13"; + case 15: return "R_SPARC_GOT22"; + case 16: return "R_SPARC_PC10"; + case 17: return "R_SPARC_PC22"; + case 18: return "R_SPARC_WPLT30"; + case 19: return "R_SPARC_COPY"; + case 20: return "R_SPARC_GLOB_DAT"; + case 21: return "R_SPARC_JMP_SLOT"; + case 22: return "R_SPARC_RELATIVE"; + case 23: return "R_SPARC_UA32"; + case 24: return "R_SPARC_10"; + case 25: return "R_SPARC_11"; + case 26: return "R_SPARC_64"; + case 27: return "R_SPARC_OLO10"; + case 28: return "R_SPARC_HH22"; + case 29: return "R_SPARC_HM10"; + case 30: return "R_SPARC_LM22"; + case 31: return "R_SPARC_PC_HH22"; + case 32: return "R_SPARC_PC_HM10"; + case 33: return "R_SPARC_PC_LM22"; + case 34: return "R_SPARC_WDISP16"; + case 35: return "R_SPARC_WDISP19"; + case 36: return "R_SPARC_UNUSED_42"; + case 37: return "R_SPARC_7"; + case 38: return "R_SPARC_5"; + case 39: return "R_SPARC_6"; + case 40: return "R_SPARC_DISP64"; + case 41: return "R_SPARC_PLT64"; + case 42: return "R_SPARC_HIX22"; + case 43: return "R_SPARC_LOX10"; + case 44: return "R_SPARC_H44"; + case 45: return "R_SPARC_M44"; + case 46: return "R_SPARC_L44"; + case 47: return "R_SPARC_REGISTER"; + case 48: return "R_SPARC_UA64"; + case 49: return "R_SPARC_UA16"; + case 50: return "R_SPARC_32LE"; + default: return _("*INVALID*"); + } +} + + +static char * +get_m32r_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_M32R_NONE"; + case 1: return "R_M32R_16"; + case 2: return "R_M32R_32"; + case 3: return "R_M32R_24"; + case 4: return "R_M32R_10_PCREL"; + case 5: return "R_M32R_18_PCREL"; + case 6: return "R_M32R_26_PCREL"; + case 7: return "R_M32R_HI16_ULO"; + case 8: return "R_M32R_HI16_SLO"; + case 9: return "R_M32R_LO16"; + case 10: return "R_M32R_SDA16"; + default: return _("*INVALID*"); + } +} + + +static char * +get_v850_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_V850_NONE"; + case 1: return "R_V850_9_PCREL"; + case 2: return "R_V850_22_PCREL"; + case 3: return "R_V850_HI16_S"; + case 4: return "R_V850_HI16"; + case 5: return "R_V850_LO16"; + case 6: return "R_V850_32"; + case 7: return "R_V850_16"; + case 8: return "R_V850_8"; + case 9: return "R_V850_SDA_16_16_OFFSET"; + case 10: return "R_V850_SDA_15_16_OFFSET"; + case 11: return "R_V850_ZDA_16_16_OFFSET"; + case 12: return "R_V850_ZDA_15_16_OFFSET"; + case 13: return "R_V850_TDA_6_8_OFFSET"; + case 14: return "R_V850_TDA_7_8_OFFSET"; + case 15: return "R_V850_TDA_7_7_OFFSET"; + case 16: return "R_V850_TDA_16_16_OFFSET"; +/* start-sanitize-v850e */ + case 17: return "R_V850_TDA_4_5_OFFSET"; + case 18: return "R_V850_TDA_4_4_OFFSET"; + case 19: return "R_V850_SDA_16_16_SPLIT_OFFSET"; + case 20: return "R_V850_ZDA_16_16_SPLIT_OFFSET"; + case 21: return "R_V850_CALLT_6_7_OFFSET"; + case 22: return "R_V850_CALLT_16_16_OFFSET"; +/* end-sanitize-v850e */ + default: return _("*INVALID*"); + } +} + + +static char * +get_d10v_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_D10V_NONE"; + case 1: return "R_D10V_10_PCREL_R"; + case 2: return "R_D10V_10_PCREL_L"; + case 3: return "R_D10V_16"; + case 4: return "R_D10V_18"; + case 5: return "R_D10V_18_PCREL"; + case 6: return "R_D10V_32"; + default: return _("*INVALID*"); + } +} + + +static char * +get_d30v_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_D30V_NONE"; + case 1: return "R_D30V_6"; + case 2: return "R_D30V_9_PCREL"; + case 3: return "R_D30V_9_PCREL_R"; + case 4: return "R_D30V_15"; + case 5: return "R_D30V_15_PCREL"; + case 6: return "R_D30V_15_PCREL_R"; + case 7: return "R_D30V_21"; + case 8: return "R_D30V_21_PCREL"; + case 9: return "R_D30V_21_PCREL_R"; + case 10: return "R_D30V_32"; + case 11: return "R_D30V_32_PCREL"; + case 12: return "R_D30V_32_NORMAL"; + default: return _("*INVALID*"); + } +} + + +static char * +get_sh_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_SH_NONE"; + case 1: return "R_SH_DIR32"; + case 2: return "R_SH_REL32"; + case 3: return "R_SH_DIR8WPN"; + case 4: return "R_SH_IND12W"; + case 5: return "R_SH_DIR8WPL"; + case 6: return "R_SH_DIR8WPZ"; + case 7: return "R_SH_DIR8BP"; + case 8: return "R_SH_DIR8W"; + case 9: return "R_SH_DIR8L"; + case 25: return "R_SH_SWITCH16"; + case 26: return "R_SH_SWITCH32"; + case 27: return "R_SH_USES"; + case 28: return "R_SH_COUNT"; + case 29: return "R_SH_ALIGN"; + case 30: return "R_SH_CODE"; + case 31: return "R_SH_DATA"; + case 32: return "R_SH_LABEL"; + default: return _("*INVALID*"); + } +} + + +static char * +get_mn10300_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_MN10300_NONE"; + case 1: return "R_MN10300_32"; + case 2: return "R_MN10300_16"; + case 3: return "R_MN10300_8"; + case 4: return "R_MN10300_PCREL32"; + case 5: return "R_MN10300_PCREL16"; + case 6: return "R_MN10300_PCREL8"; + default: return _("*INVALID*"); + } +} + + +static char * +get_mn10200_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_MN10200_NONE"; + case 1: return "R_MN10200_32"; + case 2: return "R_MN10200_16"; + case 3: return "R_MN10200_8"; + case 4: return "R_MN10200_24"; + case 5: return "R_MN10200_PCREL8"; + case 6: return "R_MN10200_PCREL16"; + case 7: return "R_MN10200_PCREL24"; + default: return _("*INVALID*"); + } +} + + +static void +dump_relocations (rpnt, rel_size) + Elf_Rel * rpnt; + int rel_size; +{ + int i; + int is_rela; + Elf_Rela * rapnt; + Elf_Rela * relocs = NULL; + + + rapnt = (Elf_Rela *) rpnt; + + /* Compute number of relocations. */ + switch (epnt->e_machine) + { + case EM_386: + case EM_486: + case EM_CYGNUS_M32R: + case EM_CYGNUS_D10V: + rel_size = rel_size / sizeof (Elf_Rel); + + if (must_swap) + { + Elf_Rel * new_header = malloc (sizeof (* new_header) * rel_size); + + if (new_header == NULL) + { + error (_("out of memory\n")); + return; + } + + memcpy (new_header, rpnt, sizeof (* new_header) * rel_size); + + rpnt = new_header; + relocs = (Elf_Rela *) new_header; + + for (i = 0; i < rel_size; i++) + { + BYTE_SWAP (rpnt + i, r_offset); + BYTE_SWAP (rpnt + i, r_info); + + new_header ++; + } + } + + is_rela = 0; + break; + + case EM_68K: + case EM_SPARC: + case EM_CYGNUS_V850: + case EM_CYGNUS_D30V: + case EM_CYGNUS_MN10200: + case EM_CYGNUS_MN10300: + case EM_SH: + rel_size = rel_size / sizeof (Elf_Rela); + + if (must_swap) + { + Elf_Rela * new_header = malloc (sizeof (* new_header) * rel_size); + + if (new_header == NULL) + { + error (_("out of memory\n")); + return; + } + + memcpy (new_header, rpnt, sizeof (* new_header) * rel_size); + + relocs = rapnt = new_header; + + for (i = rel_size; i--;) + { + BYTE_SWAP (new_header, r_offset); + BYTE_SWAP (new_header, r_info); + BYTE_SWAP (new_header, r_addend); + + new_header ++; + } + } + + is_rela = 1; + break; + + default: + warn (_("Don't know about relocations on this machine architecture\n")); + return; + } + + if (is_rela) + printf (_(" Offset Value Type Symbol's Value Symbol Name Addend\n")); + else + printf (_(" Offset Value Type Symbol's Value Symbol Name\n")); + + for (i = 0; i < rel_size; i++) + { + char * rtype; + + if (is_rela) + rpnt = (Elf_Rel *) rapnt; + + printf (" %5.5x %5.5x ", rpnt->r_offset, rpnt->r_info); + + switch (epnt->e_machine) + { + case EM_CYGNUS_M32R: + rtype = get_m32r_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + + case EM_386: + case EM_486: + rtype = get_i386_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + + case EM_68K: + rtype = get_m68k_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + + case EM_SPARC: + rtype = get_sparc_rel_type (ELF32_R_TYPE (rapnt->r_info)); + break; + + case EM_CYGNUS_V850: + rtype = get_v850_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + + case EM_CYGNUS_D10V: + rtype = get_d10v_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + + case EM_CYGNUS_D30V: + rtype = get_d30v_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + + case EM_SH: + rtype = get_sh_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + + case EM_CYGNUS_MN10300: + rtype = get_mn10300_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + + case EM_CYGNUS_MN10200: + rtype = get_mn10200_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + } + + printf ("%-18s", rtype); + + symtab_index = ELF32_R_SYM (rpnt->r_info); + + if (symtab_index) + { + Elf_Sym ssym; + Elf_Sym * psym; + + psym = symtab + symtab_index; + + if (must_swap) + { + Elf_Sym * new_header = & ssym; + + ssym = * psym; + + BYTE_SWAP (psym, st_name); + BYTE_SWAP (psym, st_value); + /* BYTE_SWAP (psym, st_size); */ + BYTE_SWAP (psym, st_shndx); + + psym = new_header; + } + + if (psym->st_name == 0) + printf (" %08x %-15s", psym->st_value, + SECTION_NAME (elf_sections + psym->st_shndx)); + else + printf (" %08x %-15s", psym->st_value, strtab + psym->st_name); + + if (is_rela) + printf (" + %x", rapnt->r_addend); + } + + putchar ('\n'); + rapnt ++; + rpnt ++; + } + + if (relocs != NULL) + free (relocs); +} + +static char * +get_file_type (e_type) + unsigned short e_type; +{ + static char buff [32]; + + switch (e_type) + { + case ET_NONE: return _("None"); + case ET_REL: return _("Relocatable file"); + case ET_EXEC: return _("Executable file"); + case ET_DYN: return _("Shared object file"); + case ET_CORE: return _("Core file"); + + default: + if ((e_type >= ET_LOPROC) && (e_type <= ET_HIPROC)) + sprintf (buff, _("Processor Specific: (%x)"), e_type); + else + sprintf (buff, _(": %x"), e_type); + return buff; + } +} + +static char * +get_machine_name (e_machine) + unsigned short e_machine; +{ + static char buff [32]; + + switch (e_machine) + { + case EM_NONE: return _("None"); + case EM_M32: return "WE32100"; + case EM_SPARC: return "Sparc"; + case EM_386: return "80386"; + case EM_68K: return "MC68000"; + case EM_88K: return "MC88000"; + case EM_486: return "Intel 80486"; + case EM_860: return "Intel 80860"; + case EM_MIPS: return "MIPS R3000 big-endian"; + case EM_S370: return "Amdahl"; + case EM_MIPS_RS4_BE: return "MIPS R400 big-endian"; + case EM_PARISC: return "HPPA"; + case EM_SPARC32PLUS: return "Sparc v8+" ; + case EM_PPC: return "Power PCC"; + case EM_SPARCV9: return "Sparc v9"; + case EM_ARM: return "ARM"; + case EM_SH: return "Hitachi SH"; + case EM_ALPHA: return "Alpha"; + case EM_CYGNUS_D10V: return "d10v"; + case EM_CYGNUS_D30V: return "d30v"; + case EM_CYGNUS_M32R: return "M32r"; + case EM_CYGNUS_V850: return "v850"; + case EM_CYGNUS_MN10300: return "mn10300"; + case EM_CYGNUS_MN10200: return "mn10200"; + + default: + sprintf (buff, _(": %x"), e_machine); + return buff; + } +} + +static char * +get_segment_type (p_type) + unsigned long p_type; +{ + static char buff [32]; + + switch (p_type) + { + case PT_NULL: return _("Unused"); + case PT_LOAD: return _("Loadable"); + case PT_DYNAMIC: return _("Dynamic link info"); + case PT_INTERP: return _("Interpreter"); + case PT_NOTE: return _("Auxillary Info"); + case PT_SHLIB: return _("Shared Library"); + case PT_PHDR: return _("Program Headers"); + + default: + if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC)) + return _("processor specific"); + else + { + sprintf (buff, _(": %x"), p_type); + return buff; + } + } +} + +static char * +get_section_type_name (sh_type) + unsigned int sh_type; +{ + static char buff [32]; + + switch (sh_type) + { + case SHT_NULL: return _("Unused"); + case SHT_PROGBITS: return _("Program data"); + case SHT_SYMTAB: return _("Symbol table"); + case SHT_STRTAB: return _("String table"); + case SHT_RELA: return _("Relocs, addends"); + case SHT_HASH: return _("Symbol hash table"); + case SHT_DYNAMIC: return _("Dynamic linking info"); + case SHT_NOTE: return _("Notes"); + case SHT_NOBITS: return _("Space, no data"); + case SHT_REL: return _("Relocs, no addends"); + case SHT_SHLIB: return _("Shared Library info"); + case SHT_DYNSYM: return _("Dynamic linker symbols"); + case SHT_GNU_verdef: return _("Version definition"); + case SHT_GNU_verneed: return _("Version needs"); + case SHT_GNU_versym: return _("Version symbols"); + case 0x6ffffff0: return "VERSYM"; + case 0x6ffffffc: return "VERDEF"; + case 0x7ffffffd: return "AUXILIARY"; + case 0x7fffffff: return "FILTER"; + + default: + if ((sh_type >= SHT_LOPROC) && (sh_type <= SHT_HIPROC)) + return _("processor specific"); + else if ((sh_type >= SHT_LOUSER) && (sh_type <= SHT_HIUSER)) + return _("application specific"); + else + { + sprintf (buff, _(": %x"), sh_type); + return buff; + } + } +} + +struct option options [] = +{ + {"all", no_argument, 0, 'a'}, + {"file-header", no_argument, 0, 'h'}, + {"program-headers", no_argument, 0, 'l'}, + {"segments", no_argument, 0, 'l'}, + {"sections", no_argument, 0, 'S'}, + {"symbols", no_argument, 0, 's'}, + {"relocs", no_argument, 0, 'r'}, + {"dynamic", no_argument, 0, 'd'}, + {"version-info", no_argument, 0, 'V'}, + {"use-dynamic", no_argument, 0, 'D'}, + + {"hex-dump", required_argument, 0, 'x'}, +#ifdef SUPPORT_DISASSEMBLY + {"instruction-dump", required_argument, 0, 'i'}, +#endif + + {"version", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'H'}, + + {0, no_argument, 0, 0} +}; + +static void +usage () +{ + fprintf (stderr, _("Usage: readelf {options} elf-file(s)\n")); + fprintf (stderr, _(" Options are:\n")); + fprintf (stderr, _(" -a or --all Display all the information\n")); + fprintf (stderr, _(" -h or --file-header Display the ELF file header\n")); + fprintf (stderr, _(" -l or --program-headers or --segments\n")); + fprintf (stderr, _(" Display the program headers\n")); + fprintf (stderr, _(" -S or --sections Display the sections' headers\n")); + fprintf (stderr, _(" -s or --symbols Display the symbol table\n")); + fprintf (stderr, _(" -r or --relocs Display the relocations (if present)\n")); + fprintf (stderr, _(" -d or --dynamic Display the dynamic section (if present)\n")); + fprintf (stderr, _(" -V or --version-info Display the version sections (if present)\n")); + fprintf (stderr, _(" -D or --use-dynamic Use the dynamic section info when displaying symbols\n")); + fprintf (stderr, _(" -x or --hex-dump=\n")); + fprintf (stderr, _(" Dump the contents of section \n")); +#ifdef SUPPORT_DISASSEMBLY + fprintf (stderr, _(" -i or --instruction-dump=\n")); + fprintf (stderr, _(" Disassemble the contents of section \n")); +#endif + fprintf (stderr, _(" -v or --version Display the version number of readelf\n")); + fprintf (stderr, _(" -H or --help Display this information\n")); + + exit (0); +} + +static void +parse_args (argc, argv) + int argc; + char ** argv; +{ + char c; + + if (argc < 2) + usage (); + + while ((c = getopt_long + (argc, argv, "rsahldSDx:i:vV", options, NULL)) != EOF) + { + char * cp; + int section; + + switch (c) + { + case 'H': + usage (); + break; + + case 'a': + do_syms++; + do_reloc++; + do_dynamic++; + do_header++; + do_section++; + do_load++; + do_version++; + break; + case 'D': + do_using_dynamic++; + break; + case 'r': + do_reloc++; + break; + case 'h': + do_header++; + break; + case 'l': + do_load++; + break; + case 's': + do_syms++; + break; + case 'S': + do_section++; + break; + case 'd': + do_dynamic++; + break; + case 'x': + do_dump ++; + section = strtoul (optarg, & cp, 0); + if (! * cp && section >= 0 && section < NUM_DUMP_SECTS) + { + dump_sects [section] |= HEX_DUMP; + break; + } + goto oops; +#ifdef SUPPORT_DISASSEMBLY + case 'i': + do_dump ++; + section = strtoul (optarg, & cp, 0); + if (! * cp && section >= 0 && section < NUM_DUMP_SECTS) + { + dump_sects [section] |= DISASS_DUMP; + break; + } + goto oops; +#endif + case 'v': + print_version (program_name); + break; + case 'V': + do_version ++; + break; + default: + oops: + /* xgettext:c-format */ + error (_("Invalid option '-%c'\n"), c); + /* Drop through. */ + case '?': + usage (); + } + } + + if (!do_dynamic && !do_syms && !do_reloc && !do_section + && !do_load && !do_header && !do_dump && !do_version) + usage (); + else if (argc < 3) + warn (_("Nothing to do.\n")); +} + +static int +process_elf_header () +{ + if ( epnt->e_ident [EI_MAG0] != ELFMAG0 + || epnt->e_ident [EI_MAG1] != ELFMAG1 + || epnt->e_ident [EI_MAG2] != ELFMAG2 + || epnt->e_ident [EI_MAG3] != ELFMAG3) + { + error (_("Not an ELF file - it has the wrong magic bytes at the start\n")); + return 0; + } + + if (epnt->e_ident [EI_CLASS] != ELFCLASS32) + { + error (_("Not a 32 bit ELF file\n")); + return 0; + } + + if (epnt->e_ident [EI_DATA] != expected_endian) + must_swap = 1; + + if (must_swap) + { + Elf_Ehdr * new_header = malloc (sizeof (* new_header)); + + if (new_header == NULL) + { + error (_("out of memory\n")); + return 0; + } + + memcpy (new_header, epnt, sizeof (* new_header)); + + BYTE_SWAP (epnt, e_type); + BYTE_SWAP (epnt, e_machine); + BYTE_SWAP (epnt, e_version); + BYTE_SWAP (epnt, e_entry); + BYTE_SWAP (epnt, e_phoff); + BYTE_SWAP (epnt, e_shoff); + BYTE_SWAP (epnt, e_flags); + BYTE_SWAP (epnt, e_ehsize); + BYTE_SWAP (epnt, e_phentsize); + BYTE_SWAP (epnt, e_phnum); + BYTE_SWAP (epnt, e_shentsize); + BYTE_SWAP (epnt, e_shnum); + BYTE_SWAP (epnt, e_shstrndx); + + epnt = new_header; + } + + if (do_header) + { + int i; + + printf (_("ELF Header....\n")); + printf (_(" Magic: ")); + for (i = 0; i < EI_NIDENT; i ++) + printf ("%2.2x ", epnt->e_ident [i]); + printf ("\n"); + printf (_(" Type: %s\n"), get_file_type (epnt->e_type)); + printf (_(" Machine: %s\n"), get_machine_name (epnt->e_machine)); + printf (_(" Version: %x\n"), epnt->e_version); + printf (_(" Entry point address: %x\n"), epnt->e_entry); + printf (_(" Start of program headers: %d (bytes into file)\n"), epnt->e_phoff); + printf (_(" Start of section headers: %d (bytes into file)\n"), epnt->e_shoff); + printf (_(" Flags: %x\n"), epnt->e_flags); + printf (_(" Size of this header: %d (bytes)\n"), epnt->e_ehsize); + printf (_(" Size of program headers: %d (bytes)\n"), epnt->e_phentsize); + printf (_(" Number of program headers: %d\n"), epnt->e_phnum); + printf (_(" Size of section headers: %d (bytes)\n"), epnt->e_shentsize); + printf (_(" Number of section headers: %d\n"), epnt->e_shnum); + printf (_(" Section header string table index: %d\n"), epnt->e_shstrndx); + } + + return 1; +} + + +static void +process_program_headers () +{ + Elf_Phdr * elf_segments; + Elf_Phdr * ppnt; + int i; + + if (epnt->e_phnum == 0) + { + if (do_load) + printf (_("\nThere are no program headers in this file\n")); + return; + } + + if (do_load && !do_header) + { + printf (_("\nElf file is %s\n"), get_file_type (epnt->e_type)); + printf (_("Entry point 0x%x\n"), epnt->e_entry); + printf (_("There are %d program headers, starting at offset %x:\n"), + epnt->e_phnum, epnt->e_phoff); + } + + if (must_swap) + { + Elf_Phdr * new_header = malloc (sizeof (* new_header) * epnt->e_phnum); + + if (new_header == NULL) + { + error (_("out of memory\n")); + return; + } + + memcpy (new_header, & header [epnt->e_phoff], + sizeof (* new_header) * epnt->e_phnum); + + elf_segments = ppnt = new_header; + + for (i = 0; i < epnt->e_phnum; i++) + { + BYTE_SWAP (ppnt + i, p_type); + BYTE_SWAP (ppnt + i, p_flags); + BYTE_SWAP (ppnt + i, p_offset); + BYTE_SWAP (ppnt + i, p_vaddr); + BYTE_SWAP (ppnt + i, p_paddr); + BYTE_SWAP (ppnt + i, p_filesz); + BYTE_SWAP (ppnt + i, p_memsz); + BYTE_SWAP (ppnt + i, p_align); + + new_header ++; + } + } + else + { + ppnt = (Elf_Phdr *) & header [epnt->e_phoff]; + elf_segments = NULL; + } + + if (do_load) + { + printf (_("\nProgram Header%s....\n"), epnt->e_phnum > 1 ? "s" : ""); + printf (_(" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n")); + } + + loadaddr = -1; + dynamic_addr = 0; + + for (i = 0; i < epnt->e_phnum; i++) + { + if (loadaddr == -1 && ppnt->p_type == PT_LOAD) + loadaddr = (ppnt->p_vaddr & 0xfffff000) + - (ppnt->p_offset & 0xfffff000); + + if (do_load) + { + printf (" %-10s ", get_segment_type (ppnt->p_type)); + printf ("0x%5.5x ",ppnt->p_offset); + printf ("0x%8.8x ",ppnt->p_vaddr); + printf ("0x%8.8x ",ppnt->p_paddr); + printf ("0x%5.5x 0x%5.5x ",ppnt->p_filesz, ppnt->p_memsz); + printf ("%c%c%c ", + (ppnt->p_flags & 4 ? 'R' : ' '), + (ppnt->p_flags & 2 ? 'W' : ' '), + (ppnt->p_flags & 1 ? 'E' : ' ')); + printf ("%#x", ppnt->p_align); + } + + if (ppnt->p_type == PT_DYNAMIC) + { + if (dynamic_addr) + error (_("more than one dynamic section\n")); + + dynamic_addr = ppnt->p_offset; + dynamic_size = ppnt->p_filesz; + } + + if (ppnt->p_type == PT_INTERP) + { + if (do_load) + printf (_("\nRequesting program interpreter [%s]"), + & header [ppnt->p_offset]); + pint = strdup (& header [ppnt->p_offset]); + } + + if (do_load) + putc ('\n', stdout); + + ppnt ++; + } + + if (do_load) + { + printf (_("\n Section to Segment mapping:\n")); + printf (_(" Segment Sections...\n")); + + if (elf_segments) + ppnt = elf_segments; + else + ppnt = (Elf_Phdr *) & header [epnt->e_phoff]; + + for (i = 0; i < epnt->e_phnum; i++, ppnt++) + { + int j; + Elf_Shdr * spnt; + + printf (" %2.2d ", i); + + spnt = (Elf_Shdr *) & header [epnt->e_shoff]; + + if (must_swap) + { + lastmapped = SWAP4 (spnt[epnt->e_shstrndx].sh_offset); + + for (j = 0; j < epnt->e_shnum; j++) + { + bfd_vma addr; + bfd_size_type size; + unsigned int name; + + addr = SWAP4 (spnt[j].sh_addr); + size = SWAP4 (spnt[j].sh_size); + name = SWAP4 (spnt[j].sh_name); + + if (size > 0 + && (addr >= ppnt->p_vaddr) + && (addr + size) <= (ppnt->p_vaddr + ppnt->p_memsz)) + printf ("%s ", header + lastmapped + name); + } + } + else + { + lastmapped = spnt[epnt->e_shstrndx].sh_offset; + + for (j = 0; j < epnt->e_shnum; j++, spnt++) + { + if (spnt->sh_size > 0 + && (spnt->sh_addr >= ppnt->p_vaddr) + && (spnt->sh_addr + spnt->sh_size) + <= (ppnt->p_vaddr + ppnt->p_memsz)) + printf ("%s ", SECTION_NAME (spnt)); + } + } + + putc ('\n',stdout); + } + } + + if (elf_segments) + free (elf_segments); +} + + +static void +process_section_headers () +{ + Elf_Shdr * spnt; + int i; + + if (must_swap) + { + Elf_Shdr * new_header = malloc (sizeof (* new_header) * epnt->e_shnum); + + if (new_header == NULL) + { + error (_("out of memory\n")); + return; + } + + memcpy (new_header, & header [epnt->e_shoff], + sizeof (* new_header) * epnt->e_shnum); + + elf_sections = spnt = new_header; + + for (i = 0; i < epnt->e_shnum; i++) + { + BYTE_SWAP (spnt + i, sh_name); + BYTE_SWAP (spnt + i, sh_type); + BYTE_SWAP (spnt + i, sh_flags); + BYTE_SWAP (spnt + i, sh_addr); + BYTE_SWAP (spnt + i, sh_offset); + BYTE_SWAP (spnt + i, sh_size); + BYTE_SWAP (spnt + i, sh_link); + BYTE_SWAP (spnt + i, sh_info); + BYTE_SWAP (spnt + i, sh_addralign); + BYTE_SWAP (spnt + i, sh_entsize); + + new_header ++; + } + } + else + { + elf_sections = spnt = (Elf_Shdr *) & header [epnt->e_shoff]; + } + + spnt += epnt->e_shstrndx; + lastmapped = spnt->sh_offset; + spnt = elf_sections; + + if (! do_section || (epnt->e_shnum == 0)) + return; + + if (! do_header) + printf (_("There are %d section headers, starting at offset %x:\n"), + epnt->e_shnum, epnt->e_shoff); + + printf (_("\nSection Header%s....\n"), epnt->e_shnum > 1 ? "s" : ""); + printf (_(" [Nr] Name Type Addr Off Size ES Flg Lk In Al\n")); + + for (i = 0; i < epnt->e_shnum; i++) + { + printf (" [%2d] %-14s", i, SECTION_NAME (spnt)); + + printf (" %-18s ",get_section_type_name (spnt->sh_type)); + printf ( "%8.8x %6.6x %6.6x %2.2x", + spnt->sh_addr, + spnt->sh_offset, + spnt->sh_size, + spnt->sh_entsize); + + printf (" %c%c%c %2d %2x %d \n", + (spnt->sh_flags & 1 ? 'W' : ' '), + (spnt->sh_flags & 2 ? 'A' : ' '), + (spnt->sh_flags & 4 ? 'X' : ' '), + spnt->sh_link, + spnt->sh_info, + spnt->sh_addralign); + spnt ++; + } +} + +/* Parse the dynamic segment */ +static void +process_dynamic_segment () +{ + Elf_Dyn * elf_dynamic; + unsigned int i; + + dynamic_size = dynamic_size / sizeof (Elf_Dyn); + + if (must_swap) + { + Elf_Dyn * new_header = malloc (sizeof (* new_header) * dynamic_size); + + if (new_header == NULL) + { + error (_("out of memory\n")); + return; + } + + memcpy (new_header, & header [dynamic_addr], + sizeof (* new_header) * dynamic_size); + + elf_dynamic = dpnt = new_header; + + for (i = 0; i < dynamic_size; i++) + { + BYTE_SWAP (dpnt + i, d_tag); + BYTE_SWAP (dpnt + i, d_un.d_ptr); + + new_header ++; + } + } + else + { + dpnt = (Elf_Dyn *) & header [dynamic_addr]; + elf_dynamic = NULL; + } + + /* Find symtab. */ + for (i = 0; i < dynamic_size; ++i, ++dpnt) + if (dpnt->d_tag == DT_SYMTAB) + { + dynamic_info [DT_SYMTAB] = dpnt->d_un.d_val; + symtab = (Elf_Sym *) (header - loadaddr + + dynamic_info[DT_SYMTAB]); + } + else if (dpnt->d_tag == DT_STRTAB) + { + dynamic_info [DT_STRTAB] = dpnt->d_un.d_val; + strtab = (char *) (header - loadaddr + dynamic_info[DT_STRTAB]); + } + + if (do_dynamic && dynamic_addr) + { + printf (_("\n Dynamic section data: %x, %d entries\n"), + dynamic_addr, dynamic_size ); + } + + for (i = 0; i < dynamic_size; i++) + { + if (do_dynamic) + printf (_(" Tag: %#10x: "), dpnt->d_tag); + + switch (dpnt->d_tag) + { + case DT_AUXILIARY: + case DT_FILTER: + if (do_dynamic) + { + printf ("(%-11s)", filtertype [DT_FILTER - dpnt->d_tag]); + + if (dynamic_info [DT_STRTAB]) + { + if (dpnt->d_tag == DT_AUXILIARY) + printf (_("Auxiliary library")); + else + printf (_("Filter library")); + + printf (": [%s]\n", (dpnt->d_un.d_val + strtab)); + } + else + printf (_("Value %x\n"), dpnt->d_un.d_val); + } + break; + + case DT_NULL : + case DT_NEEDED : + case DT_PLTRELSZ: + case DT_PLTGOT : + case DT_HASH : + case DT_STRTAB : + case DT_SYMTAB : + case DT_RELA : + case DT_RELASZ : + case DT_RELAENT : + case DT_STRSZ : + case DT_SYMENT : + case DT_INIT : + case DT_FINI : + case DT_SONAME : + case DT_RPATH : + case DT_SYMBOLIC: + case DT_REL : + case DT_RELSZ : + case DT_RELENT : + case DT_PLTREL : + case DT_DEBUG : + case DT_TEXTREL : + case DT_JMPREL : + dynamic_info [dpnt->d_tag] = dpnt->d_un.d_val; + + if (do_dynamic) + { + printf ("(%-11s)", dyntype [dpnt->d_tag]); + + if (dynamic_info [DT_STRTAB]) + { + switch (dpnt->d_tag) + { + case DT_NEEDED: + printf (_("Shared library: [%s]\n"), + (dpnt->d_un.d_val + strtab)); + + if (strcmp (dpnt->d_un.d_val + strtab, pint)) + printf ("\n"); + else + printf (_(" program interpreter\n")); + break; + + case DT_SONAME: + printf (_("Library soname: [%s]\n"), + (dpnt->d_un.d_val + strtab)); + break; + + case DT_RPATH: + printf (_("Library rpath: [%s]\n"), + (dpnt->d_un.d_val + strtab)); + break; + + default: + printf (_("Value %x\n"), dpnt->d_un.d_val); + } + } + else + printf (_("Value %x\n"), dpnt->d_un.d_val); + } + break; + + default: + if ((dpnt->d_tag >= DT_VERSYM) && (dpnt->d_tag <= DT_VERNEEDNUM)) + { + version_info [DT_VERSIONTAGIDX (dpnt->d_tag)] = dpnt->d_un.d_val; + + if (do_dynamic) + printf (_("(%-11s) Value %#x\n"), + vertype [DT_VERSIONTAGIDX (dpnt->d_tag)], + dpnt->d_un.d_ptr); + } + else + warn (_(" Value %#x\n"), dpnt->d_un.d_ptr); + break; + } + + dpnt ++; + } + + if (do_reloc) + { + if (do_using_dynamic) + { + if (dynamic_info [DT_REL]) + { + rpnt = (Elf_Rel *) (header + dynamic_info [DT_REL] - loadaddr); + rel_size = dynamic_info [DT_RELSZ]; + if (rel_size) + { + printf (_("\nRelocation section data: %x %x\n"), + dynamic_info[DT_REL], rel_size); + dump_relocations (rpnt, rel_size); + } + else + printf (_("\nNo Relocations in this file\n")); + } + + if (dynamic_info[DT_RELA]) + { + rpnt = (Elf_Rel *) (header + dynamic_info[DT_RELA] - loadaddr); + rel_size = dynamic_info[DT_RELASZ]; + if (rel_size) + { + printf (_("\nRelocation section data: %x %x\n"), + dynamic_info[DT_RELA], rel_size); + dump_relocations (rpnt, rel_size); + } + else + printf (_("\nNo Relocations in this file\n")); + } + + if (dynamic_info[DT_JMPREL]) + { + rpnt = (Elf_Rel *) (header + dynamic_info[DT_JMPREL] + - loadaddr); + rel_size = dynamic_info[DT_PLTRELSZ]; + if (rel_size) + { + printf (_("\nJumptable Relocation section data: %x %x\n"), + dynamic_info[DT_JMPREL], rel_size); + dump_relocations (rpnt, rel_size); + } + else + printf (_("\nNo Relocations in this file\n")); + } + } + else + { + Elf_Shdr * spnt; + + spnt = elf_sections; + + for (i = 0; i < epnt->e_shnum; i++, spnt++) + { + Elf_Shdr * symsec; + + + if (spnt->sh_type != SHT_RELA && spnt->sh_type != SHT_REL) + continue; + + rpnt = (Elf_Rel *) (header + spnt->sh_offset); + + rel_size = spnt->sh_size; + + if (rel_size) + { + printf (_("\nRelocation section data: %s (%#x entries)\n"), + SECTION_NAME (spnt), rel_size / spnt->sh_entsize); + + symsec = & elf_sections [spnt->sh_link]; + symtab = (Elf_Sym *) (header + symsec->sh_offset); + strtab = (char *) (header + + elf_sections [symsec->sh_link].sh_offset); + + dump_relocations (rpnt, rel_size); + } + else + printf (_("\nNo Relocations in this file\n")); + } + } + } + + if (elf_dynamic) + free (elf_dynamic); +} + +/* Dump the symbol table */ +static void +process_symbol_table () +{ + char * pnt; + int i; + Elf_Shdr * spnt; + + if (! do_syms) + return; + + if (dynamic_info [DT_HASH] && do_using_dynamic) + { + int nbucket; + int nchain; + int * elf_buckets; + int * chains; + int hn; + int si; + int * hash_addr; + + hash_addr = (int *) (dynamic_info [DT_HASH] + header - loadaddr); + + nbucket = *hash_addr++; + nchain = *hash_addr++; + elf_buckets = hash_addr; + hash_addr += nbucket; + chains = hash_addr; + + printf (_("\n Symbol table for image\n")); + printf (_(" Num Buc: Value Size Type Bind Ot Ndx Name\n")); + + for (hn = 0; hn < nbucket; hn++) + { + if (! elf_buckets [hn]) + continue; + + for (si = elf_buckets[hn]; si; si = chains[si]) + { + pnt = strtab + symtab[si].st_name; + + printf ("%3d %3d: %8x %5d %6s %6s %2d ", si, hn, + symtab[si].st_value, + symtab[si].st_size, + sttinfo [ELF_ST_TYPE (symtab[si].st_info)], + stbinfo [ELF_ST_BIND (symtab[si].st_info)], + symtab[si].st_other); + + if (symtab[si].st_shndx == 0) + printf ("UND"); + else if ((symtab[si].st_shndx & 0xffff) == 0xfff1) + printf ("ABS"); + else if ((symtab[si].st_shndx & 0xffff) == 0xfff2) + printf ("COM"); + else + printf ("%3d", symtab[si].st_shndx); + printf (" %s\n", pnt); + } + } + } + else if (!do_using_dynamic) + { + int i; + unsigned short * vers_addr; + + spnt = elf_sections; + vers_addr = (short *) (version_info [DT_VERNEEDNUM - DT_VERSYM] + + header - loadaddr); + + for (i = 0; i < epnt->e_shnum; i++, spnt++) + { + unsigned int si; + + if (spnt->sh_type != SHT_SYMTAB && spnt->sh_type != SHT_DYNSYM) + continue; + + printf (_("\nSymbol data for: %s\n"), SECTION_NAME (spnt)); + printf (_(" Num: Value Size Type Bind Ot Ndx Name\n")); + + symtab = (Elf_Sym *) (header + spnt->sh_offset); + strtab = (char *) (header + elf_sections [spnt->sh_link].sh_offset); + + for (si = 0; si < spnt->sh_size / spnt->sh_entsize; si++) + { + Elf_Sym ssym; + Elf_Sym * psym; + Elf_Sym * new_header; + + psym = symtab + si; + + if (must_swap) + { + ssym = * psym; + + new_header = & ssym; + + BYTE_SWAP (psym, st_name); + BYTE_SWAP (psym, st_value); + BYTE_SWAP (psym, st_size); + BYTE_SWAP (psym, st_shndx); + + psym = new_header; + } + + pnt = strtab + psym->st_name; + + printf (" %3d: %8x %5d %-7s %-6s %2d ", si, + psym->st_value, + psym->st_size, + sttinfo [ELF_ST_TYPE (psym->st_info)], + stbinfo [ELF_ST_BIND (psym->st_info)], + psym->st_other); + + if (psym->st_shndx == 0) + printf ("UND"); + else if ((psym->st_shndx & 0xffff) == 0xfff1) + printf ("ABS"); + else if ((psym->st_shndx & 0xffff) == 0xfff2) + printf ("COM"); + else + printf ("%3d", psym->st_shndx); + printf (" %s", pnt); + + if (spnt->sh_type == SHT_DYNSYM && + version_info [DT_VERSIONTAGIDX (DT_VERSYM)] != 0 && + ((vers_addr[si] & 0x8000) || vers_addr[si] > 1)) + { + Elf_Vernaux * a; + + if (elf_sections [psym->st_shndx].sh_type == SHT_NOBITS + || psym->st_shndx == SHN_UNDEF) + { + Elf_Verneed * v; + + /* We must test both. */ + v = (Elf_Verneed *) + (version_info [DT_VERSIONTAGIDX (DT_VERNEED)] + + header - loadaddr); + + for (;;) + { + a = (Elf_Vernaux *)((char *)v + v->vn_aux); + + while (a->vna_other != vers_addr[si] + && a->vna_next != 0) + a = (Elf_Vernaux *)((char *)a + a->vna_next); + + if (a->vna_other == vers_addr[si]) + break; + + if (v->vn_next == 0) + { + if (elf_sections [psym->st_shndx].sh_type + != SHT_NOBITS) + error (_("bad dynamic symbol")); + + a = NULL; + break; + } + + v = (Elf_Verneed *)((char *)v + v->vn_next); + } + + if (a != NULL) + printf ("@%s (%d)", strtab + a->vna_name, a->vna_other); + } + else if ((elf_sections [psym->st_shndx].sh_type + == SHT_NOBITS && a == NULL) + || psym->st_shndx != SHN_UNDEF) + { + Elf_Verdef * v; + Elf_Verdaux * b; + + v = (Elf_Verdef *) + (version_info [DT_VERSIONTAGIDX (DT_VERDEF)] + + header - loadaddr); + + if (vers_addr[si] == 0x8001) + pnt = ""; + else + { + while (v->vd_ndx != (vers_addr [si] & 0x7fff)) + v = (Elf_Verdef *)((char *)v + v->vd_next); + + b = (Elf_Verdaux *) ((char *)v + v->vd_aux); + + if (psym->st_name != b->vda_name) + pnt = strtab + b->vda_name; + else + pnt = NULL; + } + + if (pnt) + printf ((vers_addr [si] & 0x8000) + ? "@%s" : "@@%s", pnt); + } + } + + puts (""); + } + } + } + + if (! do_version) + return; + + spnt = elf_sections; + + for (i = 0; i < epnt->e_shnum; i++, spnt++) + { + if (spnt->sh_type == SHT_GNU_verdef) + { + Elf_Shdr * dspnt = &elf_sections[spnt->sh_link]; + unsigned int idx; + unsigned int cnt; + + strtab = (char *) (header - loadaddr + dynamic_info[DT_STRTAB]); + + printf (_("\n Version definitions:%s (%#0x entries)\n"), + SECTION_NAME(spnt), spnt->sh_info); + printf (_("Addr: %#08x Offset: %#08x Link: %x (%s)\n"), + spnt->sh_addr, spnt->sh_offset, spnt->sh_link, + SECTION_NAME(dspnt)); + + for (idx = cnt = 0; cnt < spnt->sh_info; ++cnt) + { + Elf_Verdef * ent = (Elf_Verdef *) + ((char *) header + spnt->sh_offset + idx); + Elf_Verdaux * aux = (Elf_Verdaux *) + ((char *) ent + ent->vd_aux); + int j, isum; + + printf (_("%#06x: Rev: %d Flags: "), idx, ent->vd_version); + + if (ent->vd_flags == 0) + printf (_("none")); + else + { + int f = 1; + if (ent->vd_flags & 0x1) + { + printf (_("BASE")); + f = 0; + } + if (ent->vd_flags & 0x2) + { + printf (_("%sWEAK"), f ? "" : "|"); + f = 0; + } + } + printf (_(" Index: %d Cnt: %d Name: %s\n"), + ent->vd_ndx, ent->vd_cnt, strtab + aux->vda_name); + j = 1; + isum = idx + ent->vd_aux; + while (j < ent->vd_cnt) + { + isum += aux->vda_next; + aux = (Elf_Verdaux *)((char *)aux + aux->vda_next); + printf (_(" %#06x: Parent %d: %s\n"), isum, j, + strtab + aux->vda_name); + ++j; + } + + idx += ent->vd_next; + } + } + + if (spnt->sh_type == SHT_GNU_verneed) + { + Elf_Shdr * dspnt = &elf_sections[spnt->sh_link]; + unsigned int idx; + unsigned int cnt; + + strtab = (char *) (header - loadaddr + dynamic_info[DT_STRTAB]); + printf (_("\n Needed versions:%s (%#0x entries)\n"), + SECTION_NAME (spnt), spnt->sh_info); + printf (_("Addr: %#08x Offset: %#08x Link: %x (%s)\n"), + spnt->sh_addr, spnt->sh_offset, spnt->sh_link, + SECTION_NAME (dspnt)); + + for (idx = cnt = 0; cnt < spnt->sh_info; ++cnt) + { + Elf_Verneed * ent = (Elf_Verneed *) + ((char *) header + spnt->sh_offset + idx); + Elf_Vernaux * aux = (Elf_Vernaux *) + ((char *) ent + ent->vn_aux); + int j, isum; + + printf (_("%#06x: Version: %d File: %s Cnt: %d\n"), + idx, ent->vn_version, strtab + ent->vn_file,ent->vn_cnt); + + for (j = 0, isum = idx + ent->vn_aux; j < ent->vn_cnt; ++j) + { + printf (_(" %#06x: Name: %s Flags: %s Version: %d\n"), + isum, strtab+aux->vna_name, + aux->vna_flags & 0x2 ? "WEAK" : "none", + aux->vna_other); + isum += aux->vna_next; + aux = (Elf_Vernaux *)((char *) aux + aux->vna_next); + } + + idx += ent->vn_next; + } + } + + if (spnt->sh_type == SHT_GNU_versym) + { + Elf_Shdr * dspnt = &elf_sections[spnt->sh_link]; + int total = spnt->sh_size / spnt->sh_entsize; + int cnt; + unsigned short * p = (short *) + (version_info[DT_VERNEEDNUM - DT_VERSYM] + header - loadaddr); + + symtab = (Elf_Sym *) (header + dspnt->sh_offset); + strtab = (char *) (header + elf_sections[dspnt->sh_link].sh_offset); + + printf (_("\n Version symbols:%s (%#0x entries)\n"), + SECTION_NAME (spnt), total); + printf (_("Addr: %#08x Offset: %#08x Link: %x (%s)\n"), + spnt->sh_addr, spnt->sh_offset, spnt->sh_link, + SECTION_NAME (dspnt)); + + for (cnt = 0; cnt < total; cnt += 4) + { + int j, nn; + + printf ("%#08x:", cnt); + + for (j = 0; (j < 4) && (cnt + j) < total; ++j) + switch (p[cnt + j]) + { + case 0: + printf (" 0 (*local*) "); + break; + case 1: + printf (" 1 (*global*) "); + break; + default: + nn = printf ("%4x%c", p[cnt + j] & 0x7fff, + p[cnt + j] & 0x8000 ? 'h' : ' '); + if (elf_sections[symtab[cnt + j].st_shndx].sh_type + == SHT_NOBITS) + { + /* We must test both. */ + Elf_Verneed * v = (Elf_Verneed *) + (version_info [DT_VERNEEDNUM - DT_VERNEED] + + header - loadaddr); + Elf_Vernaux * a = NULL; + + for (;;) + { + a = (Elf_Vernaux *)((char *) v + v->vn_aux); + + while (a->vna_other != p[cnt + j] + && a->vna_next != 0) + a = (Elf_Vernaux *)((char *) a + a->vna_next); + + if (a->vna_other == p[cnt + j]) + break; + + if (v->vn_next == 0) + { + a = NULL; + break; + } + + v = (Elf_Verneed *)((char *)v + v->vn_next); + } + + if (a != NULL) + nn += printf ("(%s)", strtab + a->vna_name); + else + { + Elf_Verdef * v = (Elf_Verdef *) + (version_info [DT_VERNEEDNUM - DT_VERDEF] + + header - loadaddr); + Elf_Verdaux * a; + + if (p[cnt + j] == 0x8001) + pnt = ""; + else + { + while (v->vd_ndx != (p[cnt + j]&0x7fff)) + v = (Elf_Verdef *)((char *)v + v->vd_next); + + a = (Elf_Verdaux *) ((char *) v + v->vd_aux); + pnt = strtab + a->vda_name; + } + + if (pnt) + nn += printf ("(%s)", pnt); + } + + if (nn <16) + printf ("%*c", 16 - nn, ' '); + } + else if (symtab[cnt + j].st_shndx ==SHN_UNDEF) + { + Elf_Verneed * v = (Elf_Verneed *) + (version_info [DT_VERNEEDNUM - DT_VERNEED] + + header - loadaddr); + Elf_Vernaux * a; + + for (;;) + { + a = (Elf_Vernaux *)((char *) v + v->vn_aux); + + while (a->vna_other != p[cnt + j] + && a->vna_next != 0) + a = (Elf_Vernaux *)((char *)a + a->vna_next); + + if (a->vna_other == p[cnt + j]) + break; + + v = (Elf_Verneed *)((char *) v + v->vn_next); + } + + nn += printf ("(%s)", strtab + a->vna_name); + + if (nn <16) + printf ("%*c", 16 - nn, ' '); + } + else + { + Elf_Verdef * v = (Elf_Verdef *) + (version_info [DT_VERNEEDNUM - DT_VERDEF] + + header - loadaddr); + Elf_Verdaux * a; + + if (p[cnt + j] == 0x8001) + pnt = ""; + else + { + while (v->vd_ndx != (p[cnt + j] & 0x7fff)) + v = (Elf_Verdef *)((char *) v + v->vd_next); + + a = (Elf_Verdaux *) ((char *) v + v->vd_aux); + pnt = strtab + a->vda_name; + } + + if (pnt) + nn += printf ("(%s)", pnt); + + if (nn <16) + printf ("%*c", 16 - nn, ' '); + } + } + + printf ("\n"); + } + } + } +} + +static void +process_section_contents () +{ + Elf_Shdr * spnt; + int i; + + if (! do_dump) + return; + + spnt = elf_sections; + + for (i = 0; i < epnt->e_shnum; i++, spnt++) + { + int bytes; + int addr; + int lbytes; + unsigned char * my_addr; + +#ifdef SUPPORT_DISASSEMBLY + /* See if we need an assembly dump of this section */ + + if ((i < NUM_DUMP_SECTS) && (dump_sects[i] & DISASS_DUMP)) + { + printf (_("\nAssembly dump of section %s\n"), SECTION_NAME (spnt)); + + bytes = spnt->sh_size; + addr = spnt->sh_addr; + my_addr = (unsigned char *) (header + spnt->sh_offset); + + while (bytes > 0) + { + printf ("0x%8.8x ", addr); + + switch (epnt->e_machine) + { + case EM_386: + case EM_486: + lbytes = db_disasm ((unsigned int) my_addr, 0, 0) - + ((unsigned int) my_addr); + break; + case EM_68K: + lbytes = (m68k_disass ((unsigned int) my_addr, addr) + - (unsigned int) my_addr); + break; + default: + warn (_("Unable to disassemble code for this platform\n")); + return; + } + + addr += lbytes; + my_addr += lbytes; + bytes -= lbytes; + + printf ("\n"); + } + } +#endif + + /* OK, see if we need a hex dump of this section. */ + if ((i < NUM_DUMP_SECTS) && (dump_sects[i] & HEX_DUMP)) + { + int j; + int k; + + printf (_("\nHex dump of section %s\n"), SECTION_NAME (spnt)); + + bytes = spnt->sh_size; + addr = spnt->sh_addr; + my_addr = (unsigned char *) (header + spnt->sh_offset); + + while (bytes) + { + lbytes = (bytes > 16 ? 16 : bytes); + + printf ("0x%8.8x ",addr); + + switch (epnt->e_ident [EI_DATA]) + { + case ELFDATA2LSB: + for (j = 15; j >= 0; j --) + { + if (j < lbytes) + printf ("%2.2x", my_addr[j]); + else + printf (" "); + + if (!(j & 0x3)) + printf (" "); + } + break; + + case ELFDATA2MSB: + for (j = 0; j < 16; j++) + { + if (j < lbytes) + printf ("%2.2x", my_addr[j]); + else + printf (" "); + + if ((j & 3) == 3) + printf (" "); + } + break; + } + + for (j = 0; j < lbytes; j++) + { + k = my_addr [j]; + if (k >= ' ' && k < 0x80) + printf ("%c", k); + else + printf ("."); + } + + printf ("\n"); + + my_addr += lbytes; + addr += lbytes; + bytes -= lbytes; + } + } + } +} + +static void +process_file (file_name) + char * file_name; +{ + int fd; + struct stat statbuf; + + must_swap = 0; + + fd = open (file_name, O_RDONLY); + if (fd == -1) + { + error (_("Input file %s not found.\n"), file_name); + return; + } + + if (fstat (fd, & statbuf) < 0) + { + error (_("Cannot stat input file %s.\n"), file_name); + close (fd); + return; + } + + header = mmap (0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + + if ((header == (char *) -1) || (header == NULL)) + { + error (_("Cannot mmap %s: %s\n"), file_name, strerror (errno)); + close (fd); + return; + } + + close (fd); + + epnt = (Elf_Ehdr *) header; + + if (show_name) + printf (_("\nFile: %s\n"), file_name); + + if (! process_elf_header ()) + { + munmap (header, statbuf.st_size); + return; + } + + process_program_headers (); + + if (loadaddr == -1) + { + /* Very strange. */ + loadaddr = 0; + } + + process_section_headers (); + + process_dynamic_segment (); + + process_symbol_table (); + + process_section_contents (); + + munmap (header, statbuf.st_size); + + if (must_swap) + { + if (epnt) + { + free (epnt); + epnt = NULL; + } + + if (elf_sections) + { + free (elf_sections); + elf_sections = NULL; + } + } +} + +#ifdef SUPPORT_DISASSEMBLY +/* Needed by the i386 disassembler. For extra credit, someone could +fix this so that we insert symbolic addresses here, esp for GOT/PLT +symbols */ + +void +print_address (unsigned int addr, FILE * outfile) +{ + fprintf (outfile,"0x%8.8x", addr); +} + +/* Needed by the i386 disassembler. */ +void +db_task_printsym (unsigned int addr) +{ + print_address (addr, stderr); +} +#endif + +int +main (argc, argv) + int argc; + char ** argv; +{ + parse_args (argc, argv); + + expected_endian = 0x12345678; + + if (* ((char *) & expected_endian) == 0x12) + expected_endian = ELFDATA2MSB; + else + expected_endian = ELFDATA2LSB; + + if (optind < (argc - 1)) + show_name = 1; + + while (optind < argc) + process_file (argv [optind ++]); + + return 0; +} diff --git a/binutils/readelf.h b/binutils/readelf.h new file mode 100644 index 0000000000..371716ed2f --- /dev/null +++ b/binutils/readelf.h @@ -0,0 +1,173 @@ +/* readelf.h -- This file contains structures similar to those found in + include/elf/internal.h. These structures however, match the layout of + the information in the file, rather than being optimised for internal + storage. + + Copyright (C) 1998 Free Software Foundation, Inc. + +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 2 of the License, 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, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _READELF_H +#define _READELF_H + +#include "bfd.h" +#include "elf/common.h" + +/* The type 'bfd_vma' is used in places where the 64 bit version of the + structure has a 64 bit wide field, and the 32 bit version has a 32 bit wide + field. It does not necessarily imply that the field contains an address. */ + +#define EI_NIDENT 16 + +/* The ELF file header. This appears at the start of every ELF file. */ +typedef struct +{ + unsigned char e_ident [EI_NIDENT]; /* Magic number and other info */ + unsigned short e_type; /* Object file type */ + unsigned short e_machine; /* Architecture */ + unsigned long e_version; /* Object file version */ + bfd_vma e_entry; /* Entry point virtual address */ + bfd_vma e_phoff; /* Program header table file offset */ + bfd_vma e_shoff; /* Section header table file offset */ + unsigned long e_flags; /* Processor-specific flags */ + unsigned short e_ehsize; /* ELF header size in bytes */ + unsigned short e_phentsize; /* Program header table entry size */ + unsigned short e_phnum; /* Program header table entry count */ + unsigned short e_shentsize; /* Section header table entry size */ + unsigned short e_shnum; /* Section header table entry count */ + unsigned short e_shstrndx; /* Section header string table index */ +} +Elf_Ehdr; + +/* Program Segment Header. (Might be wrong for 64 bit ELF formats). */ +typedef struct +{ + unsigned long p_type; /* Segment type */ + bfd_vma p_offset; /* Segment file offset */ + bfd_vma p_vaddr; /* Segment virtual address */ + bfd_vma p_paddr; /* Segment physical address */ + unsigned long p_filesz; /* Segment size in file */ + unsigned long p_memsz; /* Segment size in memory */ + unsigned long p_flags; /* Segment flags */ + unsigned long p_align; /* Segment alignment */ +} +Elf_Phdr; + +/* Section header. */ +typedef struct +{ + unsigned long sh_name; /* Section name (string tbl index) */ + unsigned long sh_type; /* Section type */ + bfd_vma sh_flags; /* Section flags */ + bfd_vma sh_addr; /* Section virtual addr at execution */ + bfd_vma sh_offset; /* Section file offset */ + unsigned long sh_size; /* Section size in bytes */ + unsigned long sh_link; /* Link to another section */ + unsigned long sh_info; /* Additional section information */ + bfd_vma sh_addralign; /* Section alignment */ + bfd_vma sh_entsize; /* Entry size if section holds table */ +} +Elf_Shdr; + +/* Symbol table entry. (Might be incorrect for 64 bit ELF formats) */ +typedef struct +{ + unsigned long st_name; /* Symbol name (string tbl index) */ + bfd_vma st_value; /* Symbol value */ + bfd_vma st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* No defined meaning, 0 */ + unsigned short st_shndx; /* Section index */ +} +Elf_Sym; + +/* Version definition sections. */ +typedef struct +{ + unsigned short vd_version; /* Version number of structure. */ + unsigned short vd_flags; /* Flags (VER_FLG_*). */ + unsigned short vd_ndx; /* Version index. */ + unsigned short vd_cnt; /* Number of verdaux entries. */ + unsigned long vd_hash; /* Hash of name. */ + unsigned long vd_aux; /* Offset to verdaux entries. */ + unsigned long vd_next; /* Offset to next verdef. */ +} +Elf_Verdef; + +/* Auxialiary version information. */ +typedef struct +{ + unsigned long vda_name; /* String table offset of name. */ + unsigned long vda_next; /* Offset to next verdaux. */ +} +Elf_Verdaux; + +/* Version dependency section. */ +typedef struct +{ + unsigned short vn_version; /* Version number of structure. */ + unsigned short vn_cnt; /* Number of vernaux entries. */ + unsigned long vn_file; /* String table offset of library name. */ + unsigned long vn_aux; /* Offset to vernaux entries. */ + unsigned long vn_next; /* Offset to next verneed. */ +} +Elf_Verneed; + +/* Auxiliary needed version information. */ +typedef struct +{ + unsigned long vna_hash; /* Hash of dependency name. */ + unsigned short vna_flags; /* Flags (VER_FLG_*). */ + unsigned short vna_other; /* Unused. */ + unsigned long vna_name; /* String table offset to version name. */ + unsigned long vna_next; /* Offset to next vernaux. */ +} +Elf_Vernaux; + +/* Relocation table entry without addend. */ +typedef struct +{ + bfd_vma r_offset; /* Location at which to apply the action */ + bfd_vma r_info; /* index and type of relocation */ +} +Elf_Rel; + +/* Relocation table entry with addend. */ +typedef struct +{ + bfd_vma r_offset; /* Location at which to apply the action */ + bfd_vma r_info; /* Index and Type of relocation */ + bfd_signed_vma r_addend; /* Constant addend used to compute value */ +} +Elf_Rela; + +/* Dynamic section entry. */ +typedef struct +{ + signed long d_tag; /* Dynamic entry type */ + union + { + bfd_vma d_val; /* Integer value */ + bfd_vma d_ptr; /* Address value */ + } d_un; +} +Elf_Dyn; + + +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ + +#endif /* _READELF_H */