diff options
author | Eric Andersen <andersen@codepoet.org> | 2001-06-04 23:08:09 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2001-06-04 23:08:09 +0000 |
commit | 2a115f6c06d812d7507e7df891ae994a8e731be8 (patch) | |
tree | 8bb42b11b371ae213b5558c8f2f363d6b47e2630 | |
parent | f68eb8d50b11310628f53a9378bf612e8d4bfa09 (diff) |
Add a new 'readelf' util I wrote this weekend.
-Erik
-rw-r--r-- | ldso/util/Makefile | 40 | ||||
-rw-r--r-- | ldso/util/ldconfig.c | 2 | ||||
-rw-r--r-- | ldso/util/ldd.c | 2 | ||||
-rw-r--r-- | ldso/util/lddstub.S | 42 | ||||
-rw-r--r-- | ldso/util/readelf.c | 362 |
5 files changed, 325 insertions, 123 deletions
diff --git a/ldso/util/Makefile b/ldso/util/Makefile index 8fe733eb9..e61e1b62d 100644 --- a/ldso/util/Makefile +++ b/ldso/util/Makefile @@ -1,27 +1,26 @@ TOPDIR=../../ -include $(TOPDIR)/ldso/Rules.mak +include $(TOPDIR)Rules.mak -CFLAGS += -DLDSO_ADDR="0x62f00020" # needed by ldd.o -#CFLAGS += -I./ -I../../include/ -#LDFLAGS += -nostdlib $(TOPDIR)lib/libc.a $(TOPDIR)lib/crt0.o $(GCCINCDIR)/../libgcc.a -LDFLAGS += $(TOPDIR)lib/libc.a $(TOPDIR)lib/crt0.o $(GCCINCDIR)/../libgcc.a +CFLAGS=-Wall -Os -I- -I../../include -I. +CC = $(TOPDIR)extra/gcc-uClibc/$(NATIVE_ARCH)-uclibc-gcc -ALL = ldconfig ldd readelf # lddstub +all: ldconfig ldd readelf -all: $(ALL) - -CSRC= readelf.c ldconfig.c ldd.c readsoname.c -COBJS=$(patsubst %.c,%.o, $(CSRC)) -OBJS=$(COBJS) - -$(COBJS): %.o : %.c +readsoname.o: readsoname.c readsoname2.c $(CC) $(CFLAGS) -c $< -o $@ $(STRIPTOOL) -x -R .note -R .comment $*.o -readsoname.o: readsoname.c readsoname2.c +ldconfig.o: ldconfig.c + $(CC) $(CFLAGS) -DUCLIBC_ROOT_DIR=\"$(ROOT_DIR)\" -c $< -o $@ + $(STRIPTOOL) -x -R .note -R .comment $*.o -readelf: readelf.o - $(CC) $(CFLAGS) $^ -o $@ +ldd.o: ldd.c + $(CC) $(CFLAGS) -DUCLIBC_ROOT_DIR=\"$(ROOT_DIR)\" \ + -DLDSO_ADDR="0x62f00020" -c $< -o $@ + $(STRIPTOOL) -x -R .note -R .comment $*.o + +readelf: readelf.c + $(CC) $(CFLAGS) readelf.c -o $@ ldconfig: ldconfig.o readsoname.o $(CC) $(CFLAGS) $^ -o $@ @@ -29,13 +28,6 @@ ldconfig: ldconfig.o readsoname.o ldd: ldd.o readsoname.o $(CC) $(CFLAGS) $^ -o $@ -#ifeq ($(DEBUG),true) -#STUBFLAGS = -Wl,-dynamic-linker,../d-link/ld-linux.so -#endif - -#lddstub: lddstub.o -# $(CC) $(CFLAGS) $(LDFLAGS) $(STUBFLAGS) $^ -o $@ - clean: - rm -f $(ALL) *.o *~ core + rm -f ldconfig ldd readelf *.o *~ core diff --git a/ldso/util/ldconfig.c b/ldso/util/ldconfig.c index 58f9cb10b..8ea344043 100644 --- a/ldso/util/ldconfig.c +++ b/ldso/util/ldconfig.c @@ -617,7 +617,7 @@ int main(int argc, char **argv) /* allow me to introduce myself, hi, my name is ... */ if (verbose > 0) - printf("%s: version %s\n", argv[0], VERSION); + printf("%s: uClibc version\n", argv[0]); if (printcache) { diff --git a/ldso/util/ldd.c b/ldso/util/ldd.c index dcf895d19..29800bc20 100644 --- a/ldso/util/ldd.c +++ b/ldso/util/ldd.c @@ -206,7 +206,7 @@ int main(int argc, char **argv, char **envp) { case 'v': /* print our version number */ - printf("%s: version %s\n", argv[0], VERSION); + printf("%s: uClibc version\n", argv[0]); vprinted = 1; break; case 'd': diff --git a/ldso/util/lddstub.S b/ldso/util/lddstub.S deleted file mode 100644 index 33a67ee8d..000000000 --- a/ldso/util/lddstub.S +++ /dev/null @@ -1,42 +0,0 @@ - .text -.globl main -.globl exit -main: -exit: -#if defined(__i386__) - movl $1,%eax - movl $0,%ebx - int $0x80 -#elif defined(__mc68000__) - movel #1,%d0 - clrl %d1 - trap #0 -#elif defined(__sparc__) - mov 1,%g1 - mov 0,%o0 - t 0x10 -#else -#error Only know how to support i386, m68k and sparc architectures -#endif - -.globl atexit -.globl __libc_init -.globl __setfpucw -atexit: -__libc_init: -__setfpucw: -#if defined(__i386__) - ret -#elif defined(__mc68000__) - rts -#elif defined(__sparc__) - ret - nop -#else -#error Only know how to support i386, m68k and sparc architectures -#endif - - .data -.globl __fpu_control -__fpu_control: - .long 0 diff --git a/ldso/util/readelf.c b/ldso/util/readelf.c index ba93d2d31..c0a3e1eb7 100644 --- a/ldso/util/readelf.c +++ b/ldso/util/readelf.c @@ -1,61 +1,313 @@ -/* adapted from Eric Youngdale's readelf program */ +/* vi: set sw=4 ts=4: */ +/* + * A small little readelf implementation for uClibc + * + * Copyright (C) 2001 by Lineo, inc. + * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> + * + * Several functions in this file (specifically, elf_find_section_type(), + * elf_find_phdr_type(), and elf_find_dynamic(), were stolen from elflib.c from + * elfvector (http://www.BitWagon.com/elfvector.html) by John F. Reiser + * <jreiser@BitWagon.com>, and which is copyright 2000 BitWagon Software LLC + * (GPL2). + * + * 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 <elf.h> +#include <fcntl.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <link.h> -#include <elf.h> #include <unistd.h> -#include "../config.h" -#include "readelf.h" +#include <sys/mman.h> +#include <sys/stat.h> #include <sys/types.h> -void warn(char *fmt, ...); -char *xstrdup(char *); - -struct needed_tab -{ - char *soname; - int type; -}; - -struct needed_tab needed_tab[] = { - { "libc.so.5", LIB_ELF_LIBC5 }, - { "libm.so.5", LIB_ELF_LIBC5 }, - { "libdl.so.1", LIB_ELF_LIBC5 }, - { "libc.so.6", LIB_ELF_LIBC6 }, - { "libm.so.6", LIB_ELF_LIBC6 }, - { "libdl.so.2", LIB_ELF_LIBC6 }, - { NULL, LIB_ELF } -}; - -char *readsoname(char *name, FILE *infile, int expected_type, - int *type, int elfclass) -{ - char *res; - - if (elfclass == ELFCLASS32) - res = readsoname32(name, infile, expected_type, type); - else - { - res = readsoname64(name, infile, expected_type, type); -#if 0 - *type |= LIB_ELF64; -#endif - } - - return res; -} - -#undef __ELF_NATIVE_CLASS -#undef readsonameXX -#define readsonameXX readsoname32 -#define __ELF_NATIVE_CLASS 32 -#include "readelf2.c" - -#undef __ELF_NATIVE_CLASS -#undef readsonameXX -#define readsonameXX readsoname64 -#define __ELF_NATIVE_CLASS 64 -#include "readelf2.c" + + +Elf32_Shdr * elf_find_section_type( int key, Elf32_Ehdr *ehdr) +{ + int j; + Elf32_Shdr *shdr = (Elf32_Shdr *)(ehdr->e_shoff + (char *)ehdr); + for (j = ehdr->e_shnum; --j>=0; ++shdr) { + if (shdr->sh_type == key) { + return shdr; + } + } + return 0; +} + +Elf32_Phdr * elf_find_phdr_type( int type, Elf32_Ehdr *ehdr) +{ + int j; + Elf32_Phdr *phdr = (Elf32_Phdr *)(ehdr->e_phoff + (char *)ehdr); + for (j = ehdr->e_phnum; --j>=0; ++phdr) { + if (type==phdr->p_type) { + return phdr; + } + } + return 0; +} + +/* Returns value if return_val==1, ptr otherwise */ +void * elf_find_dynamic(int const key, Elf32_Dyn *dynp, + Elf32_Ehdr *ehdr, int return_val) +{ + Elf32_Phdr *pt_text = elf_find_phdr_type(PT_LOAD, ehdr); + unsigned tx_reloc = pt_text->p_vaddr - pt_text->p_offset; + for (; DT_NULL!=dynp->d_tag; ++dynp) { + if (dynp->d_tag == key) { + if (return_val == 1) + return (void *)dynp->d_un.d_val; + else + return (void *)(dynp->d_un.d_val - tx_reloc + (char *)ehdr ); + } + } + return 0; +} + +int check_elf_header(Elf32_Ehdr const *const ehdr) +{ + if (! ehdr || strncmp((void *)ehdr, ELFMAG, SELFMAG) != 0 || + ehdr->e_ident[EI_CLASS] != ELFCLASS32 || + ehdr->e_ident[EI_VERSION] != EV_CURRENT) + { + return 1; + } + return 0; +} + +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_AIX 7 /* AIX */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ +#define ELFOSABI_ARM 97 /* ARM */ +static void describe_elf_hdr(Elf32_Ehdr* ehdr) +{ + char *tmp, *tmp1; + + switch (ehdr->e_type) { + case ET_NONE: tmp = "None"; tmp1 = "NONE"; break; + case ET_REL: tmp = "Relocatable File"; tmp1 = "REL"; break; + case ET_EXEC: tmp = "Executable file"; tmp1 = "EXEC"; break; + case ET_DYN: tmp = "Shared object file"; tmp1 = "DYN"; break; + case ET_CORE: tmp = "Core file"; tmp1 = "CORE"; break; + default: + tmp = tmp1 = "Unknown"; + } + printf( "Type:\t\t%s (%s)\n", tmp1, tmp); + + switch (ehdr->e_machine) { + case EM_NONE: tmp="No machine"; break; + case EM_M32: tmp="AT&T WE 32100"; break; + case EM_SPARC: tmp="SUN SPARC"; break; + case EM_386: tmp="Intel 80386"; break; + case EM_68K: tmp="Motorola m68k family"; break; + case EM_88K: tmp="Motorola m88k family"; break; + case EM_860: tmp="Intel 80860"; break; + case EM_MIPS: tmp="MIPS R3000 big-endian"; break; + case EM_S370: tmp="IBM System/370"; break; + case EM_MIPS_RS3_LE: tmp="MIPS R3000 little-endian"; break; + case EM_PARISC: tmp="HPPA"; break; + case EM_VPP500: tmp="Fujitsu VPP500"; break; + case EM_SPARC32PLUS: tmp="Sun's v8plus"; break; + case EM_960: tmp="Intel 80960"; break; + case EM_PPC: tmp="PowerPC"; break; + case EM_PPC64: tmp="PowerPC 64-bit"; break; + case EM_S390: tmp="IBM S390"; break; + case EM_V800: tmp="NEC V800 series"; break; + case EM_FR20: tmp="Fujitsu FR20"; break; + case EM_RH32: tmp="TRW RH-32"; break; + case EM_RCE: tmp="Motorola RCE"; break; + case EM_ARM: tmp="ARM"; break; + case EM_FAKE_ALPHA: tmp="Digital Alpha"; break; + case EM_SH: tmp="Hitachi SH"; break; + case EM_SPARCV9: tmp="SPARC v9 64-bit"; break; + case EM_TRICORE: tmp="Siemens Tricore"; break; + case EM_ARC: tmp="Argonaut RISC Core"; break; + case EM_H8_300: tmp="Hitachi H8/300"; break; + case EM_H8_300H: tmp="Hitachi H8/300H"; break; + case EM_H8S: tmp="Hitachi H8S"; break; + case EM_H8_500: tmp="Hitachi H8/500"; break; + case EM_IA_64: tmp="Intel Merced"; break; + case EM_MIPS_X: tmp="Stanford MIPS-X"; break; + case EM_COLDFIRE: tmp="Motorola Coldfire"; break; + case EM_68HC12: tmp="Motorola M68HC12"; break; + case EM_MMA: tmp="Fujitsu MMA Multimedia Accelerator"; break; + case EM_PCP: tmp="Siemens PCP"; break; + case EM_NCPU: tmp="Sony nCPU embeeded RISC"; break; + case EM_NDR1: tmp="Denso NDR1 microprocessor"; break; + case EM_STARCORE: tmp="Motorola Start*Core processor"; break; + case EM_ME16: tmp="Toyota ME16 processor"; break; + case EM_ST100: tmp="STMicroelectronic ST100 processor"; break; + case EM_TINYJ: tmp="Advanced Logic Corp. Tinyj emb.fam"; break; + case EM_X86_64: tmp="AMD x86-64 architecture"; break; + case EM_PDSP: tmp="Sony DSP Processor"; break; + case EM_FX66: tmp="Siemens FX66 microcontroller"; break; + case EM_ST9PLUS: tmp="STMicroelectronics ST9+ 8/16 mc"; break; + case EM_ST7: tmp="STmicroelectronics ST7 8 bit mc"; break; + case EM_68HC16: tmp="Motorola MC68HC16 microcontroller"; break; + case EM_68HC11: tmp="Motorola MC68HC11 microcontroller"; break; + case EM_68HC08: tmp="Motorola MC68HC08 microcontroller"; break; + case EM_68HC05: tmp="Motorola MC68HC05 microcontroller"; break; + case EM_SVX: tmp="Silicon Graphics SVx"; break; + case EM_AT19: tmp="STMicroelectronics ST19 8 bit mc"; break; + case EM_VAX: tmp="Digital VAX"; break; + case EM_CRIS: tmp="Axis Communications 32-bit embedded processor"; break; + case EM_JAVELIN: tmp="Infineon Technologies 32-bit embedded processor"; break; + case EM_FIREPATH: tmp="Element 14 64-bit DSP Processor"; break; + case EM_ZSP: tmp="LSI Logic 16-bit DSP Processor"; break; + case EM_MMIX: tmp="Donald Knuth's educational 64-bit processor"; break; + case EM_HUANY: tmp="Harvard University machine-independent object files"; break; + case EM_PRISM: tmp="SiTera Prism"; break; + case EM_AVR: tmp="Atmel AVR 8-bit microcontroller"; break; + case EM_FR30: tmp="Fujitsu FR30"; break; + case EM_D10V: tmp="Mitsubishi D10V"; break; + case EM_D30V: tmp="Mitsubishi D30V"; break; + case EM_V850: tmp="NEC v850"; break; + case EM_M32R: tmp="Mitsubishi M32R"; break; + case EM_MN10300: tmp="Matsushita MN10300"; break; + case EM_MN10200: tmp="Matsushita MN10200"; break; + case EM_PJ: tmp="picoJava"; break; + default: tmp="unknown"; + } + printf( "Machine:\t%s\n", tmp); + + switch (ehdr->e_ident[EI_CLASS]) { + case ELFCLASSNONE: tmp = "Invalid class"; break; + case ELFCLASS32: tmp = "ELF32"; break; + case ELFCLASS64: tmp = "ELF64"; break; + default: tmp = "Unknown"; + } + printf( "Class:\t\t%s\n", tmp); + + switch (ehdr->e_ident[EI_DATA]) { + case ELFDATANONE: tmp = "Invalid data encoding"; break; + case ELFDATA2LSB: tmp = "2's complement, little endian"; break; + case ELFDATA2MSB: tmp = "2's complement, big endian"; break; + default: tmp = "Unknown"; + } + printf( "Data:\t\t%s\n", tmp); + + printf( "Version:\t%d %s\n", ehdr->e_ident[EI_VERSION], + (ehdr->e_ident[EI_VERSION]==EV_CURRENT)? + "(current)" : "(unknown: %lx)"); + + switch (ehdr->e_ident[EI_OSABI]) { + case ELFOSABI_SYSV: tmp ="UNIX - System V"; break; + case ELFOSABI_HPUX: tmp ="UNIX - HP-UX"; break; + case ELFOSABI_NETBSD: tmp ="UNIX - NetBSD"; break; + case ELFOSABI_LINUX: tmp ="UNIX - Linux"; break; + case ELFOSABI_HURD: tmp ="GNU/Hurd"; break; + case ELFOSABI_SOLARIS: tmp ="UNIX - Solaris"; break; + case ELFOSABI_AIX: tmp ="UNIX - AIX"; break; + case ELFOSABI_IRIX: tmp ="UNIX - IRIX"; break; + case ELFOSABI_FREEBSD: tmp ="UNIX - FreeBSD"; break; + case ELFOSABI_TRU64: tmp ="UNIX - TRU64"; break; + case ELFOSABI_MODESTO: tmp ="Novell - Modesto"; break; + case ELFOSABI_OPENBSD: tmp ="UNIX - OpenBSD"; break; + case ELFOSABI_STANDALONE: tmp ="Standalone App"; break; + case ELFOSABI_ARM: tmp ="ARM"; break; + default: tmp = "Unknown"; + } + printf( "OS/ABI:\t\t%s\n", tmp); + + printf( "ABI Version:\t%d\n", ehdr->e_ident[EI_ABIVERSION]); +} + +static void list_needed_libraries(Elf32_Dyn* dynamic, char *strtab) +{ + Elf32_Dyn *dyns; + + printf("Dependancies:\n"); + for (dyns=dynamic; dyns->d_tag!=DT_NULL; ++dyns) { + if (dyns->d_tag == DT_NEEDED) { + printf("\t%s\n", (char*)strtab + dyns->d_un.d_val); + } + } +} + +static void describe_elf_interpreter(Elf32_Ehdr* ehdr) +{ + Elf32_Phdr *phdr; + phdr = elf_find_phdr_type(PT_INTERP, ehdr); + if (phdr) { + printf("Interpreter:\t%s\n", (char*)phdr->p_paddr); + } +} + +int main( int argc, char** argv) +{ + /* map the .so, and locate interesting pieces */ + char *dynstr; + char *thefilename = argv[1]; + FILE *thefile; + struct stat statbuf; + Elf32_Ehdr *ehdr = 0; + Elf32_Shdr *dynsec; + Elf32_Dyn *dynamic; + + + if (!thefilename) { + fprintf(stderr, "No filename specified.\n"); + exit(EXIT_FAILURE); + } + if (!(thefile = fopen(thefilename, "r"))) { + perror(thefilename); + exit(EXIT_FAILURE); + } + if (fstat(fileno(thefile), &statbuf) < 0) { + perror(thefilename); + exit(EXIT_FAILURE); + } + + if (statbuf.st_size < sizeof(Elf32_Ehdr)) + goto foo; + + /* mmap the file to make reading stuff from it effortless */ + ehdr = (Elf32_Ehdr *)mmap(0, statbuf.st_size, + PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(thefile), 0); + +foo: + /* Check if this looks legit */ + if (check_elf_header(ehdr)) { + fprintf(stderr, "This does not appear to be an ELF file.\n"); + exit(EXIT_FAILURE); + } + describe_elf_hdr(ehdr); + describe_elf_interpreter(ehdr); + + dynsec = elf_find_section_type(SHT_DYNAMIC, ehdr); + if (dynsec) { + dynamic = (Elf32_Dyn*)(dynsec->sh_offset + (int)ehdr); + dynstr = (char *)elf_find_dynamic(DT_STRTAB, dynamic, ehdr, 0); + list_needed_libraries(dynamic, dynstr); + } + + return 0; +} + |