elftoc.c

来自「ELFkickers是一组elf工具」· C语言 代码 · 共 440 行

C
440
字号
/* elftoc.c: The central module. * * Copyright (C) 1999-2001 by Brian Raiter, under the GNU General * Public License. No warranty. See COPYING for details. */#include	<stdio.h>#include	<stdlib.h>#include	<string.h>#include	<ctype.h>#include	<stdarg.h>#include	<errno.h>#include	<sys/stat.h>#include	"gen.h"#include	"elf.h"#include	"pieces.h"#include	"addr.h"#include	"shdrtab.h"#include	"dynamic.h"#include	"out.h"#include	"elftoc.h"/* The name to use for the initialized variable in the generated C code. */char const	       *varname;/* The name to use for the structure defined in the generated C code. */char const	       *structname;/* The output file. */FILE		       *outfile;/* The name of this program, taken from argv[0]. Used in error * messages. */static char const      *thisprog;/* The name of the input file, taken from argv[1]. */static char const      *thefilename = NULL;/* The input file. */static FILE	       *infile = NULL;/* The input file's ELF header. */static Elf32_Ehdr      *ehdr = NULL;/* The input file's program header table, if such is present. */static Elf32_Phdr      *phdrs = NULL;/* The input file's section header table, if such is present. */static Elf32_Shdr      *shdrs = NULL;/* The size of the input file. */static int		thefilesize;/* Displays a formatted error message on stderr. If fmt is NULL, then * prints a canned out-of-memory error and exits the program directly. * Otherwise, FALSE is returned. */int err(char const *fmt, ...){    va_list	args;    if (!fmt) {	fputs("Out of memory!\n", stderr);	exit(EXIT_FAILURE);    }    fprintf(stderr, "%s: ", thefilename ? thefilename : thisprog);    va_start(args, fmt);    vfprintf(stderr, fmt, args);    fputc('\n', stderr);    va_end(args);    return FALSE;}/* A macro to simplify using errno in reporting errors. */#define	errnomsg(msg)	\    (err(errno ? errno == ENOMEM ? NULL : strerror(errno) : (msg)))/* Reads and returns an area of the input file. */static void *getarea(int off, int size){    void       *buf = NULL;    xalloc(buf, size);    if (fseek(infile, off, SEEK_SET) || fread(buf, size, 1, infile) != 1) {	free(buf);	return NULL;    }    return buf;}/* Reads in the file's ELF header, and runs several sanity checks on * the structure's contents. FALSE is returned if the file looks to * not be an ELF file at all. */static int readelfhdr(void){    static Elf32_Ehdr	ehdrbuf = { { 0 } };    unsigned int	n;    ehdr = &ehdrbuf;    errno = 0;    n = fread(ehdr, 1, sizeof *ehdr, infile);    if (n <= EI_MAG3 || ehdr->e_ident[EI_MAG0] != ELFMAG0		     || ehdr->e_ident[EI_MAG1] != ELFMAG1		     || ehdr->e_ident[EI_MAG2] != ELFMAG2		     || ehdr->e_ident[EI_MAG3] != ELFMAG3)	return err("not an ELF file.");    if (n < sizeof *ehdr) {	err("warning: file does not contain a complete ELF header.");	recordpiece(0, n, P_SECTION, 0, "ehdr");    } else	recordpiece(0, n, P_EHDR, 0, "ehdr");    if (ehdr->e_ident[EI_CLASS] != ELFCLASS32)	err("warning: not a 32-bit ELF file.");    n = 1;    *(char*)&n = 0;    if (ehdr->e_ident[EI_DATA] != (n ? ELFDATA2MSB : ELFDATA2LSB))	err("warning: not a %s-endian ELF file.", (n ? "big" : "little"));    if (ehdr->e_ident[EI_VERSION] != EV_CURRENT)	err("warning: unknown ELF header version.");    if (ehdr->e_version != EV_CURRENT)	err("warning: unknown ELF version.");    if (ehdr->e_ehsize != sizeof(Elf32_Ehdr))	err("warning: unrecognized ELF header size.");    if (ehdr->e_phoff && ehdr->e_phentsize != sizeof(Elf32_Phdr))	err("warning: unrecognized program header table entry size.");    if (ehdr->e_shoff && ehdr->e_shentsize != sizeof(Elf32_Shdr))	err("warning: unrecognized section header table entry size.");    return TRUE;}/* Reads in the file's program header table and/or section header * table, and does some basic sanity checking. If a section header * table is present, the function also attempts to read the section * header string table. */static int readhdrtables(void){    int	n;    if (ehdr->e_phoff) {	n = ehdr->e_phnum * sizeof *phdrs;	if ((phdrs = getarea(ehdr->e_phoff, n)))	    recordpiece(ehdr->e_phoff, n, P_PHDRTAB, 0, "phdrs");	else	    err("warning: invalid program header table offset.\n");    }    if (ehdr->e_shoff) {	n = ehdr->e_shnum * sizeof *shdrs;	if ((shdrs = getarea(ehdr->e_shoff, n)))	    recordpiece(ehdr->e_shoff, n, P_SHDRTAB, 0, "shdrs");	else	    err("warning: invalid section header table offset.\n");    }    if (!phdrs && !shdrs)	err("warning: ELF file has no valid header tables.");    if (shdrs && ehdr->e_shstrndx) {	if (ehdr->e_shstrndx >= ehdr->e_shnum)	    err("warning: invalid section header string table");	else	    enumsections(ehdr, shdrs,			 getarea(shdrs[ehdr->e_shstrndx].sh_offset,				 shdrs[ehdr->e_shstrndx].sh_size));    }    return TRUE;}/* Uses the program header table to find the file offset corresponding * to a memory address. -1 is returned if no such offset exists. */static int addrtooffset(unsigned addr){    Elf32_Phdr *phdr;    unsigned	i;    for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr)	if (phdr->p_vaddr <= addr && phdr->p_vaddr + phdr->p_memsz > addr)	    return addr - phdr->p_vaddr + phdr->p_offset;    return -1;}/* Records the contents referenced by various entries in the dynamic * object as separate pieces of the file. This function helps make up * for the absence of such information when a file contains no section * header table. */static void getdynamicentries(Elf32_Dyn const *dynamic){    Elf32_Dyn const    *dyn;    Elf32_Sword		val[N_DT_COUNT];    int		       *p;    int			off, n, i;    memset(val, 0, sizeof val);    for (i = 0, dyn = dynamic ; dyn->d_tag != DT_NULL ; ++i, ++dyn)	if ((n = getdyntagid(dyn->d_tag)) > 0)	    val[n] = dyn->d_un.d_val;#define	trysegment(addr, sz, off, type, name)				\    (((off) = addrtooffset(addr)) >= 0					\	&& (recordpiece((off), ((off) + (sz) > thefilesize ?		\				     thefilesize - (off) : (sz)),	\			(type), 0, (name)), 0))    trysegment(val[N_DT_STRTAB], val[N_DT_STRSZ], off, P_SECTION, "~dynstr");    trysegment(val[N_DT_SYMINFO], val[N_DT_SYMINSZ],	       off, P_HALVES, "~syminfo");    trysegment(val[N_DT_INIT_ARRAY], val[N_DT_INIT_ARRAYSZ],	       off, P_WORDS, "~init_array");    trysegment(val[N_DT_FINI_ARRAY], val[N_DT_FINI_ARRAYSZ],	       off, P_WORDS, "~fini_array");    trysegment(val[N_DT_PREINIT_ARRAY], val[N_DT_PREINIT_ARRAYSZ],	       off, P_WORDS, "~preinit_array");    if (val[N_DT_RELENT] == sizeof(Elf32_Rel))	trysegment(val[N_DT_REL], val[N_DT_RELSZ], off, P_REL, "~rel_got");    if (val[N_DT_RELAENT] == sizeof(Elf32_Rela))	trysegment(val[N_DT_RELA], val[N_DT_RELASZ], off, P_RELA, "~rela_got");    n = val[N_DT_PLTREL] == sizeof(Elf32_Rel) ? P_REL :	val[N_DT_PLTREL] == sizeof(Elf32_Rela) ? P_RELA : 0;    if (n)	trysegment(val[N_DT_JMPREL], val[N_DT_PLTRELSZ], off, n,		   n == P_REL ? "~plt_rel" : "plt_rela");#undef trysegment    if ((off = addrtooffset(val[N_DT_HASH])) >= 0) {	if ((p = getarea(off, 8))) {	    n = (p[0] + p[1] + 2) * sizeof(Elf32_Word);	    if (off + n > thefilesize)		n = thefilesize - off;	    recordpiece(off, n, P_HASH, 0, "~hash");	    off = addrtooffset(val[N_DT_SYMTAB]);	    if (off >= 0 && val[N_DT_SYMENT] == sizeof(Elf32_Sym)) {		n = p[1] * sizeof(Elf32_Sym);		if (off + n > thefilesize)		    n = thefilesize - off;		recordpiece(off, n, P_SYMTAB, 0, "~dynsym");	    }	    free(p);	}    }}/* Records the contents referenced by the various entries in the * program header table and the section header table, each as a * separate piece of the file. Attempts to assign each piece an * appropriate name. Addresses, if present, are also recorded. */static int recordsections(void){    char	buf[64];    char const *str;    int		type;    int		i, j;    if (phdrs) {	for (i = 0 ; i < ehdr->e_phnum ; ++i) {	    switch (phdrs[i].p_type) {	      case PT_NULL:	type = 0;				break;	      case PT_PHDR:	type = P_PHDRTAB;  str = "~phdrs";	break;	      case PT_DYNAMIC:	type = P_DYNAMIC;  str = "~dynamic";	break;	      case PT_INTERP:	type = P_SECTION;  str = "~interp";	break;	      case PT_NOTE:	type = P_NOTE;     str = "~note";	break;	      default:		type = P_BYTES;	   str = NULL;		break;	    }	    if (!type)		continue;	    if (!str) {		if (phdrs[i].p_flags & PF_X)		    str = "~text";		else if (phdrs[i].p_flags & PF_W)		    str = "~data";		else		    str = "~segment";	    }	    j = phdrs[i].p_offset + phdrs[i].p_filesz;	    if (j > thefilesize)		j = thefilesize;	    j -= phdrs[i].p_offset;	    recordpiece(phdrs[i].p_offset, j, type, 0, str);	    if ((phdrs[i].p_flags & PF_R) && phdrs[i].p_vaddr)		recordaddr(phdrs[i].p_vaddr, phdrs[i].p_offset,			   phdrs[i].p_memsz, str);	    if (type == P_DYNAMIC)		getdynamicentries(getarea(phdrs[i].p_offset, j));	}    }    if (shdrs) {	for (i = 0 ; i < ehdr->e_shnum ; ++i) {	    switch (shdrs[i].sh_type) {	      case SHT_NULL:		type = 0;			break;	      case SHT_NOBITS:		type = 0;			break;	      case SHT_SYMTAB:		type = P_SYMTAB;		break;	      case SHT_DYNSYM:		type = P_SYMTAB;		break;	      case SHT_HASH:		type = P_HASH;			break;	      case SHT_DYNAMIC:		type = P_DYNAMIC;		break;	      case SHT_REL:		type = P_REL;			break;	      case SHT_RELA:		type = P_RELA;			break;	      case SHT_NOTE:		type = P_NOTE;			break;	      case SHT_GNU_verdef:	type = P_WORDS;			break;	      case SHT_GNU_verneed:	type = P_WORDS;			break;	      case SHT_GNU_versym:	type = P_HALVES;		break;	      default:		  if (shdrs[i].sh_entsize == 4)		      type = P_WORDS;		  else if (shdrs[i].sh_entsize == 2)		      type = P_HALVES;		  else		      type = P_SECTION;		  break;	    }	    if (!type)		continue;	    if ((str = getshdrtruename(i))) {		if (type == P_SECTION && !strcmp(str, ".stab"))		    type = P_WORDS;		strncpy(buf, str, sizeof buf);		buf[sizeof buf - 1] = '\0';		for (j = 0 ; buf[j] && !isalnum(buf[j]) ; ++j) ;		str = buf + j;		for ( ; buf[j] ; ++j)		    if (!isalnum(buf[j]))			buf[j] = '_';	    } else		str = "~section";	    j = shdrs[i].sh_offset + shdrs[i].sh_size;	    if (j > thefilesize)		j = thefilesize;	    j -= shdrs[i].sh_offset;	    recordpiece(shdrs[i].sh_offset, j, type, i, str);	    if ((shdrs[i].sh_flags & SHF_ALLOC) && shdrs[i].sh_addr)		recordaddr(shdrs[i].sh_addr, shdrs[i].sh_offset,			   shdrs[i].sh_size, str);	}    }    return TRUE;}/* Selects a unique name for each piece, to be used as the name of the * field in the C structure. */static int setnames(void){    int	i, j, n;    n = 0;    for (i = 0 ; i < piecenum ; ++i) {	if (*pieces[i].name != '~')	    continue;	if (pieces[i].type == P_UNCLAIMED		|| (pieces[i].type == P_BYTES && pieces[i].size < 16					      && !(pieces[i].to & 3)))	    sprintf(pieces[i].name, "pad%d", ++n);	else	    memmove(pieces[i].name, pieces[i].name + 1,				    sizeof pieces->name - 1);    }    for (i = 0 ; i < piecenum - 1 ; ++i) {	n = 1;	for (j = i + 1 ; j < piecenum ; ++j)	    if (!strcmp(pieces[i].name, pieces[j].name))		sprintf(pieces[j].name, "%s%d", pieces[i].name, ++n);	if (n > 1)	    strcat(pieces[i].name, "1");    }    setaddrnames();    return TRUE;}/* main(). */int main(int argc, char *argv[]){    void       *buf;    struct stat	st;    int		i;    thisprog = argv[0];    structname = "elf";    varname = "foo";    outfile = stdout;    if (argc != 2) {	err("Usage: elftoc ELFFILENAME");	return argc < 2;    }    thefilename = argv[1];    if (stat(thefilename, &st)) {	errnomsg("can't stat file");	return 1;    }    thefilesize = st.st_size;    if (!(infile = fopen(thefilename, "r"))		|| !readelfhdr()		|| !readhdrtables())	return 1;    recordpiece(0, thefilesize, P_UNCLAIMED, 0, "~unused");    recordsections();    arrangepieces();    verifypiecetypes();    setnames();    beginoutpieces();    for (i = 0 ; i < piecenum ; ++i) {	buf = getarea(pieces[i].from, pieces[i].size);	outpiece(pieces + i, buf);	free(buf);    }    endoutpieces();    return 0;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?