elfpatch (Re: feedback requested on proposed new directive)

Antti P Miettinen antti.p.miettinen at nokia.com
Fri Sep 1 10:52:30 UTC 2000


"Rosimildo da Silva" <rdasilva at connecttel.com> writes:
> /* default_args.c   */
> char *global_argv[] =
> {
>      "rtems"
> };
> int global_argc  = sizeof( global_argv ) / sizeof( global_argv[ 0 ] ) ;
> /* end default_args.c */
> 
> int main( int argc, char **argv )
> {
> 
> }
> 
> Rosimildo.

A bit related to this. Here's a little tool I wrote. Not very robust
in argument parsing or safe to use, but seems to work for me. You
could use it for example to patch a binary to have new args or change
the IP address, put a hardcoded breakpoint somewhere, etc. The
functionality should probably be an option in objcopy but reading elf.h
seemed easier than learning BFD :)

/* -*- c -*-
 *
 * elfpatch.c
 *
 * For usage see usage().
 *
 * Feel free to make changes and fix bugs.
 *
 * Antti Miettinen <anmietti at trshp.ntc.nokia.com>
 * Nokia Networks
 */

#include <assert.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

static unsigned short
gleShort(const unsigned char *buf)
{
    return buf[0] | (buf[1] << 8);
}

static unsigned long
gleLong(const unsigned char *buf)
{
    return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
}

static void
pleShort(unsigned char *buf, unsigned short val)
{
    buf[0] = val & 0xff;
    buf[1] = (val >> 8) & 0xff;
}

static void
pleLong(unsigned char *buf, unsigned long val)
{
    buf[0] = val & 0xff;
    buf[1] = (val >> 8) & 0xff;
    buf[2] = (val >> 16) & 0xff;
    buf[3] = (val >> 24) & 0xff;
}

static unsigned short
gbeShort(const unsigned char *buf)
{
    return (buf[0] << 8) | buf[1];
}

static unsigned long
gbeLong(const unsigned char *buf)
{
    return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
}

static void
pbeShort(unsigned char *buf, unsigned short val)
{
    buf[0] = (val >> 8) & 0xff;
    buf[1] = val & 0xff;
}

static void
pbeLong(unsigned char *buf, unsigned long val)
{
    buf[0] = (val >> 24) & 0xff;
    buf[1] = (val >> 16) & 0xff;
    buf[2] = (val >> 8) & 0xff;
    buf[3] = val & 0xff;
}

static struct ifuncs
{
    unsigned short (*getShort)(const unsigned char *);
    unsigned long (*getLong)(const unsigned char *);
    void (*putShort)(unsigned char *, unsigned short);
    void (*putLong)(unsigned char *, unsigned long);
} *ifp, ifunctbl[] = {
    { gleShort, gleLong, pleShort, pleLong },
    { gbeShort, gbeLong, pbeShort, pbeLong }
};

#define ET_STR(x)							\
  ((x) == 0 ? "NONE"							\
   : (x) == 1 ? "relocatable file"					\
   : (x) == 2 ? "executable file"					\
   : (x) == 3 ? "shared object file"					\
   : (x) == 4 ? "core file"						\
   : (x) == 0xff00 || (x) == 0xffff ? "processor specific" : "???")

#define EM_STR(x)				\
  ((x) == 0 ? "NONE"				\
   : (x) == 1 ? "AT&T WE 32100"			\
   : (x) == 2 ? "SUN SPARC"			\
   : (x) == 3 ? "Intel 80386"			\
   : (x) == 4 ? "Motorola m68k family"		\
   : (x) == 5 ? "Motorola m88k family"		\
   : (x) == 6 ? "Intel 80486"			\
   : (x) == 7 ? "Intel 80860"			\
   : (x) == 8 ? "MIPS R3000 big-endian"		\
   : (x) == 9 ? "Amdahl"			\
   : (x) == 10 ? "MIPS R4000 big-endian"	\
   : (x) == 11 ? "RS6000"			\
   : (x) == 15 ? "HPPA"				\
   : (x) == 16 ? "nCUBE"			\
   : (x) == 17 ? "Fujitsu VPP500"		\
   : (x) == 18 ? "Sun\'s \"v8plus\""		\
   : (x) == 19 ? "Intel 80960"			\
   : (x) == 20 ? "PowerPC"			\
   : (x) == 36 ? "NEC V800 series"		\
   : (x) == 37 ? "Fujitsu FR20"			\
   : (x) == 38 ? "TRW RH32"			\
   : (x) == 39 ? "Fujitsu MMA"			\
   : (x) == 40 ? "ARM"				\
   : (x) == 41 ? "Digital Alpha"		\
   : (x) == 42 ? "Hitachi SH"			\
   : (x) == 43 ? "SPARC v9 64-bit"		\
   : (x) == 44 ? "Siemens Tricore"		\
   : (x) == 45 ? "Argonaut RISC Core"		\
   : (x) == 46 ? "Hitachi H8/300"		\
   : (x) == 47 ? "Hitachi H8/300H"		\
   : (x) == 48 ? "Hitachi H8S"			\
   : (x) == 49 ? "Hitachi H8/500"		\
   : (x) == 50 ? "Intel Merced"			\
   : (x) == 51 ? "Stanford MIPS-X"		\
   : (x) == 52 ? "Motorola Coldfire"		\
   : (x) == 53 ? "Motorola M68HC12" : "???")

#define PT_STR(x)							\
  ((x) == 0 ? "unused"							\
   : (x) == 1 ? "loadable program segment"				\
   : (x) == 2 ? "dynamic linking information"				\
   : (x) == 3 ? "program interpreter"					\
   : (x) == 4 ? "auxiliary information"					\
   : (x) == 5 ? "reserved"						\
   : (x) == 6 ? "header table itself"					\
   : (x) >= 0x60000000 && (x) <= 0x6fffffff ? "OS specific"		\
   : (x) >= 0x70000000 && (x) <= 0x7fffffff ? "CPU specific" : "???")

static char *
pf_str(unsigned long mask)
{
    static char ret[16];
    char *p = ret;
    int i;
    for (i = 0; i < 3; ++i)
	if (mask & (1 << i))
	    *p++ = "XWR"[i];
    *p = '\0';
    return *ret ? ret : "none";
}

#define PF_STR(x) pf_str(x)

#define SHN_STR(x)					\
  ((x) == 0 ? "undefined"				\
   : (x) >= 0xff00 && (x) <= 0xff1f ? "CPU specific"	\
   : (x) == 0xfff1 ? "ABSOLUTE"				\
   : (x) == 0xfff2 ? "COMMON"				\
   : (x) >= 0xff00 && (x) <= 0xffff ? "reserved" : "???" )

#define SHT_STR(x)							      \
  ((x) == 0 ? "unused"							      \
   : (x) == 1 ? "program data"						      \
   : (x) == 2 ? "symbol table"						      \
   : (x) == 3 ? "string table"						      \
   : (x) == 4 ? "relocation entries with addends"			      \
   : (x) == 5 ? "symbol hash table"					      \
   : (x) == 6 ? "dynamic linking information"				      \
   : (x) == 7 ? "notes"							      \
   : (x) == 8 ? "program space with no data (BSS)"			      \
   : (x) == 9 ? "relocation entries without addends"			      \
   : (x) == 10 ? "reserved"						      \
   : (x) == 11 ? "dynamic linker symbol table"				      \
   : (x) == 0x6ffffffb ? "Sun COMDAT"					      \
   : (x) == 0x6ffffffc ? "Sun syminfo"					      \
   : (x) == 0x6ffffffd ? "GNU version definition"			      \
   : (x) == 0x6ffffffe ? "GNU version needs"				      \
   : (x) == 0x6fffffff ? "GNU version symbol table"			      \
   : (x) >= 0x60000000 && (x) <= 0x6fffffff ? "OS specific"		      \
   : (x) >= 0x70000000 && (x) <= 0x7fffffff ? "CPU specific"		      \
   : (x) >= 0x80000000 && (x) <= 0x8fffffff ? "application specific" : "???")

static char *
shf_str(unsigned long mask)
{
    static char ret[16];
    char *p = ret;
    int i;
    for (i = 0; i < 3; ++i)
	if (mask & (1 << i))
	    *p++ = "WAX"[i];
    *p = '\0';
    return *ret ? ret : "none";
}

#define SHF_STR(x) shf_str(x)

#define SI_BSTR(x)					\
  ((x) == 0 ? "local"					\
   : (x) == 1 ? "global"				\
   : (x) == 2 ? "weak"					\
   : (x) >= 10 && (x) <= 12 ? "OS specific"		\
   : (x) >= 13 && (x) <= 15 ? "CPU specific" : "???")

#define SI_TSTR(x)					\
  ((x) == 0 ? "unspecified"				\
   : (x) == 1 ? "data"					\
   : (x) == 2 ? "code"					\
   : (x) == 3 ? "section"				\
   : (x) == 4 ? "file"					\
   : (x) >= 11 && (x) <= 12 ? "OS specific"		\
   : (x) >= 13 && (x) <= 15 ? "CPU specific" : "???")

static void
usage(const char *prog)
{
    fprintf(stderr,
	    "usage: %s [-opts] name=value file\n"
	    " -r      read (default)\n"
	    " -w      write\n"
	    " -o off  read/write at given offset\n"
	    " -z[+|-] zero terminate (or not) string\n"
	    " -L      long integer (default)\n"
	    " -S      short integer\n"
	    " -h      dump ELF header\n"
	    " -m      dump more ELF header\n"
	    " -p      dump program headers\n"
	    " -se     dump section headers\n"
	    " -sy     dump symbols\n"
	    " -l      search for a local symbol\n"
	    " -g      search for a global symbol (default)\n"
	    " -c      search for a function symbol\n"
	    " -d      search for a data symbol (default)\n",
	    prog);
}

int
main(int ac, char **av)
{
    struct {
	unsigned long ni;
	unsigned long type;
	unsigned long off;
	unsigned long sz;
	unsigned long link;
	unsigned long esz;
	unsigned long va;
	char *str;
    } *shinfo;
    int scope = 1; /* global */
    int type = 1; /* data */
    int isShort = 0;
    enum {
	ENC_INT,
	ENC_HEX,
	ENC_STR
    } enc = ENC_HEX;
    enum {
	OP_READ, OP_WRITE
    } op = OP_READ;
    unsigned long intVal = 0;
    int zeroTerm = 1;
    int i, j;
    int dumpHeader = 0, dumpMoreHeader = 0, dumpProgramHeaders = 0;
    int dumpSectionHeaders = 0, dumpSymbols = 0;
    unsigned long phoff, shoff, stroff, valoff = 0, strsz;
    unsigned long extraoff = 0, readSize = 0, writeSize = 0;
    unsigned short phsz, phnum, shsz, shnum, stridx;
    unsigned char buf[1024], varValue[1024];
    char *str, *varName = 0, *fileName = 0, *p;
    FILE *fp;

    for (i = 1; i < ac; ++i)
    {
	if (strncmp(av[i], "-h", 2) == 0)
	{
	    dumpHeader = 1;
	}
	else if (strncmp(av[i], "-m", 2) == 0)
	{
	    dumpMoreHeader = 1;
	}
	else if (strncmp(av[i], "-p", 2) == 0)
	{
	    dumpProgramHeaders = 1;
	}
	else if (strncmp(av[i], "-se", 3) == 0)
	{
	    dumpSectionHeaders = 1;
	}
	else if (strncmp(av[i], "-sy", 3) == 0)
	{
	    dumpSymbols = 1;
	}
	else if (strncmp(av[i], "-z", 2) == 0)
	{
	    if (av[i][2] == '-')
		zeroTerm = 0;
	    else
		zeroTerm = 1;
	}
	else if (strncmp(av[i], "-o", 2) == 0 && i+1 < ac)
	{
	    char *s;
	    extraoff = strtoul(av[++i], &s, 0);
	    if (s == av[i])
	    {
		usage(av[0]);
		return 1;
	    }
	}
	else if (strncmp(av[i], "-l", 2) == 0)
	{
	    scope = 0; /* local */
	}
	else if (strncmp(av[i], "-g", 2) == 0)
	{
	    scope = 1; /* global */
	}
	else if (strncmp(av[i], "-c", 2) == 0)
	{
	    type = 2; /* code */
	}
	else if (strncmp(av[i], "-d", 2) == 0)
	{
	    type = 1; /* data */
	}
	else if (strncmp(av[i], "-r", 2) == 0)
	{
	    op = OP_READ;
	}
	else if (strncmp(av[i], "-w", 2) == 0)
	{
	    op = OP_WRITE;
	}
	else if (strncmp(av[i], "-S", 2) == 0)
	{
	    isShort = 1;
	}
	else if (strncmp(av[i], "-L", 2) == 0)
	{
	    isShort = 0;
	}
	else if ((p = strchr(av[i], '=')) != 0)
	{
	    char *s;
	    int k;
	    varName = av[i];
	    *p++ = '\0';
	    intVal = strtoul(p, &s, 0);
	    if (s != p)
	    {
		enc = ENC_INT;
	    }
	    else if (p[0] == '\"')
	    {
		++p;
		for (k = 0; *p && *p != '\"'; ++k, ++p)
		{
		    assert(k < sizeof(varValue));
		    varValue[k] = *p;
		}
		writeSize = k;
		enc = ENC_STR;
	    }
	    else
	    {
		for (k = 0; *p; ++k, p += 2)
		{
		    unsigned short byte;
		    if (sscanf(p, "%02hx", &byte) != 1)
		    {
			fprintf(stderr, "%s: specify value as a hexdump\n",
				av[0]);
			return 1;
		    }
		    assert(k < sizeof(varValue));
		    varValue[k] = (unsigned char)byte;
		}
		writeSize = k;
		enc = ENC_HEX;
	    }
	}
	else if (fileName == 0)
	{
	    fileName = av[i];
	}
	else
	{
	    usage(av[0]);
	    return 1;
	}
    }
    if (varName == 0 || fileName == 0)
    {
	usage(av[0]);
	return 1;
    }
    if (enc == ENC_STR)
    {
	if (zeroTerm && op == OP_WRITE)
	    varValue[writeSize++] = '\0';
    }
    else if (enc == ENC_INT)
    {
	if (isShort)
	{
	    assert(intVal <= 65535);
	    readSize = writeSize = 2;
	}
	else
	{
	    readSize = writeSize = 4;
	}
    }
    if (op == OP_WRITE && writeSize == 0)
    {
	fprintf(stderr, "%s: please indicate non zero value size\n", av[0]);
	return 1;
    }
    fp = fopen(fileName, op == OP_WRITE ? "r+b" : "rb");
    if (!fp)
    {
	fprintf(stderr, "%s: failed opening `%s', %s\n",
		av[0], av[1], strerror(errno));
	return 1;
    }
    if (fread(buf, 1, 52, fp) != 52)
    {
	fprintf(stderr, "%s: failed reading ELF file header, %s\n",
		av[0], strerror(errno));
	return 1;
    }
    if (memcmp(buf, "\177ELF", 4) != 0)
    {
	fprintf(stderr, "%s: not ELF magic in `%s', %02x%02x%02x%02x\n",
		av[0], av[1],
		(unsigned)buf[0],(unsigned)buf[1],
		(unsigned)buf[2],(unsigned)buf[3]);
	return 1;
    }
    if (dumpHeader)
	printf("class: %s\nencoding: %s\nfile version: %d\n"
	       "ABI: %s\nABI version: %d\n",
	       buf[4] == 0 ? "invalid"
	       : buf[4] == 1 ? "32 bit"
	       : buf[4] == 2 ? "64 bit" : "???",
	       buf[5] == 0 ? "invalid"
	       : buf[5] == 1 ? "2\'s complement, little endian"
	       : buf[5] == 2 ? "2\'s complement, big endian" : "???",
	       (int)buf[6],
	       buf[7] == 0 ? "UNIX System V"
	       : buf[7] == 1 ? "HP-UX"
	       : buf[7] == 97 ? "ARM"
	       : buf[7] == 255 ? "embedded" : "???",
	       (int)buf[8]);
    if (buf[4] != 1 || (buf[5] != 1 && buf[5] != 2))
    {
	fprintf(stderr, "%s: too weird file\n", av[0]);
	return 1;
    }
    ifp = &ifunctbl[buf[5] == 1 ? 0 : 1];
    if (enc == ENC_INT)
    {
	if (isShort)
	    ifp->putShort(varValue, (unsigned short)intVal);
	else
	    ifp->putLong(varValue, intVal);
    }
    phoff = ifp->getLong(&buf[28]);
    phsz = ifp->getShort(&buf[42]);
    phnum = ifp->getShort(&buf[44]);
    shoff = ifp->getLong(&buf[32]);
    shsz = ifp->getShort(&buf[46]);
    shnum = ifp->getShort(&buf[48]);
    stridx = ifp->getShort(&buf[50]);
    if (dumpMoreHeader)
	printf("object type: %s (0x%04hx)\n"
	       "machine architecture: %s (0x%04hx)\n"
	       "object version: 0x%08lx\nentry: 0x%08lx\n"
	       "program header table:\n"
	       "\tat 0x%08lx, entry size 0x%04hx, count 0x%04hx\n"
	       "section header table:\n"
	       "\tat 0x%08lx, entry size 0x%04hx, count 0x%04hx, "
	       "strings 0x%04hx\n"
	       "flags: 0x%08lx\nELF header size: 0x%04hx\n",
	       ET_STR(ifp->getShort(&buf[16])), ifp->getShort(&buf[16]),
	       EM_STR(ifp->getShort(&buf[18])), ifp->getShort(&buf[18]),
	       ifp->getLong(&buf[20]), ifp->getLong(&buf[24]),
	       phoff, phsz, phnum,
	       shoff, shsz, shnum, stridx,
	       ifp->getLong(&buf[36]), ifp->getShort(&buf[40]));
    if (phsz < 32 || shsz < 40)
    {
	fprintf(stderr,
		"%s: program header size (%hu) has to be at least 32\n"
		"%s: section header size (%hu) has to be at least 40\n",
		av[0], phsz, av[0], shsz);
	return 1;	
    }
    if (fseek(fp, phoff, SEEK_SET) != 0)
    {
	fprintf(stderr, "%s: cannot seek to offset 0x%08lx, %s\n",
		av[0], phoff, strerror(errno));
	return 1;
    }
    for (i = 0; dumpProgramHeaders && i < phnum; ++i)
    {
	if (fread(buf, 1, phsz, fp) != phsz)
	{
	    fprintf(stderr, "%s: cannot read program header %d, %s\n",
		    av[0], i, strerror(errno));
	    return 1;
	}
	printf("PH%d\n"
	       "\ttype: %s (0x%08lx)\n"
	       "\tfile offset: 0x%08lx, VA: 0x%08lx, PA: 0x%08lx\n"
	       "\tsize in file: 0x%08lx, size in memory: 0x%08lx\n"
	       "\tflags: 0x%08lx (%s)\n\talignment: 0x%08lx\n",
	       i,
	       PT_STR(ifp->getLong(buf)), ifp->getLong(buf),
	       ifp->getLong(&buf[4]),
	       ifp->getLong(&buf[8]), ifp->getLong(&buf[12]),
	       ifp->getLong(&buf[16]), ifp->getLong(&buf[20]),
	       ifp->getLong(&buf[24]), PF_STR(ifp->getLong(&buf[24])),
	       ifp->getLong(&buf[28]));
    }
    if (fseek(fp, shoff + stridx * shsz, SEEK_SET) != 0)
    {
	fprintf(stderr,
		"%s: cannot seek to offset 0x%08lx, %s\n",
		av[0], shoff + stridx * shsz, strerror(errno));
	return 1;
    }
    if (fread(buf, 1, shsz, fp) != shsz)
    {
	fprintf(stderr,
		"%s: cannot read string table section header, %s\n",
		av[0], strerror(errno));
	return 1;
    }
    if (ifp->getLong(&buf[4]) != 3)
    {
	fprintf(stderr,
		"%s: header at string table index not string table!?!?\n",
		av[0]);
	return 1;
    }
    stroff = ifp->getLong(&buf[16]);
    strsz = ifp->getLong(&buf[20]);
    str = malloc(strsz);
    if (!str)
    {
	fprintf(stderr,
		"%s: cannot allocate %lu bytes for string table\n",
		av[0], strsz);
	return 1;
    }
    if (fseek(fp, stroff, SEEK_SET) != 0)
    {
	fprintf(stderr, "%s: cannot seek to offset 0x%08lx, %s\n",
		av[0], stroff, strerror(errno));
	return 1;
    }
    if (fread(str, 1, strsz, fp) != strsz)
    {
	fprintf(stderr,
		"%s: cannot read string table (off=%lu, sz=%lu), %s\n",
		av[0], stroff, strsz, strerror(errno));
	return 1;
    }
    if (fseek(fp, shoff, SEEK_SET) != 0)
    {
	fprintf(stderr, "%s: cannot seek to offset 0x%08lx, %s\n",
		av[0], shoff, strerror(errno));
	return 1;
    }
    shinfo = malloc(shnum * sizeof(*shinfo));
    if (!shinfo)
    {
	fprintf(stderr,
		"%s: cannot allocate %u bytes for symbol table info\n",
		av[0], shnum * sizeof(*shinfo));
	return 1;
    }
    memset(shinfo, 0, shnum * sizeof(*shinfo));
    for (i = 0; i < shnum; ++i)
    {
	if (fread(buf, 1, shsz, fp) != shsz)
	{
	    fprintf(stderr, "%s: cannot read section header %d, %s\n",
		    av[0], i, strerror(errno));
	    return 1;
	}
	shinfo[i].ni = ifp->getLong(buf); /* name=string table index */
	shinfo[i].va = ifp->getLong(&buf[12]);
	shinfo[i].type = ifp->getLong(&buf[4]);
	shinfo[i].off = ifp->getLong(&buf[16]);
	shinfo[i].sz = ifp->getLong(&buf[20]);
	shinfo[i].link = ifp->getLong(&buf[24]);
	shinfo[i].esz = ifp->getLong(&buf[36]);
	if (dumpSectionHeaders)
	    printf("SH%d\n"
		   "\tname: %s (string table offset 0x%08lx)\n"
		   "\ttype: %s (0x%08lx)\n\tflags: 0x%08lx (%s)\n"
		   "\tVA: 0x%08lx, file offset: 0x%08lx, size: 0x%08lx\n"
		   "\tlink: 0x%08lx, info: 0x%08lx\n"
		   "\talignment: 0x%08lx, entry size: 0x%08lx\n",
		   i,
		   shinfo[i].ni == 0 ? "<undefined>" : (str + shinfo[i].ni),
		   shinfo[i].ni,
		   SHT_STR(shinfo[i].type), shinfo[i].type,
		   ifp->getLong(&buf[8]), SHF_STR(ifp->getLong(&buf[8])),
		   shinfo[i].va, shinfo[i].off, shinfo[i].sz,
		   shinfo[i].link, ifp->getLong(&buf[28]),
		   ifp->getLong(&buf[32]), ifp->getLong(&buf[36]));
    }    
    for (i = 0; i < shnum; ++i)
    {
	if (shinfo[i].type == 2)
	{ /* symbol table section */
	    if (shinfo[i].esz < 16)
	    {
		fprintf(stderr,
			"%s: symbol table entry size (%lu), should be >= 16\n",
			av[0], shinfo[i].esz);
		return 1;
	    }
	    if (shinfo[i].link < shnum && shinfo[shinfo[i].link].type == 3)
	    { /* link points to a string table */
		shinfo[i].str = malloc(shinfo[shinfo[i].link].sz);
		if (!shinfo[i].str)
		{
		    fprintf(stderr,
			    "%s: cannot allocate %lu bytes for string table\n",
			    av[0], shinfo[shinfo[i].link].sz);
		    return 1;
		}
		if (fseek(fp, shinfo[shinfo[i].link].off, SEEK_SET) != 0)
		{
		    fprintf(stderr,
			    "%s: cannot seek to offset 0x%08lx, %s\n",
			    av[0], shinfo[shinfo[i].link].off,
			    strerror(errno));
		    return 1;
		}
		if (fread(shinfo[i].str, 1, shinfo[shinfo[i].link].sz, fp)
		    != shinfo[shinfo[i].link].sz)
		{
		    fprintf(stderr,
			    "%s: cannot read string table, "
			    "offset=%lu, size=%lu, %s\n",
			    av[0],
			    shinfo[shinfo[i].link].off,
			    shinfo[shinfo[i].link].sz,
			    strerror(errno));
		    return 1;
		}
	    }
	    else
	    {
		fprintf(stderr,
			"%s: no string table link in symbol table, SH%d\n",
			av[0], i);
		return 1;
	    }
	    if (fseek(fp, shinfo[i].off, SEEK_SET) != 0)
	    {
		fprintf(stderr,
			"%s: cannot seek to offset 0x%08lx, %s\n",
			av[0], shinfo[i].off, strerror(errno));
		return 1;
	    }
	    for (j = 0; j < shinfo[i].sz/shinfo[i].esz; ++j)
	    {
		unsigned long ni, si;
		if (fread(buf, 1, shinfo[i].esz, fp) != shinfo[i].esz)
		{
		    fprintf(stderr,
			    "%s: cannot read symbol table entry %d/%d, %s\n",
			    av[0], i, j, strerror(errno));
		    return 1;
		}
		ni = ifp->getLong(buf);
		si = ifp->getShort(&buf[14]);
		if (dumpSymbols)
		    printf("SYM%d/%d: name=%s\n\tstring table offset=0x%08lx\n"
			   "\tvalue=0x%08lx, size=0x%08lx\n"
			   "\tinfo=0x%02hx (binding: %s, type: %s)\n"
			   "\tsection=0x%04hx (%s)\n",
			   i, j,
			   ni == 0 ? "<undefined>" : shinfo[i].str + ni, ni,
			   ifp->getLong(&buf[4]),
			   ifp->getLong(&buf[8]),
			   (unsigned short)buf[12],
			   SI_BSTR(buf[12] >> 4), SI_TSTR(buf[12] & 0xf),
			   ifp->getShort(&buf[14]),
			   si < shnum ? (str + shinfo[si].ni) : SHN_STR(si));
		if (valoff == 0 /* not yet found */
		    && (buf[12] >> 4) == scope /* global/local */
		    && (buf[12] & 0xf) == type /* data/code */
		    && ni && strcmp(shinfo[i].str + ni, varName) == 0)
		{
		    unsigned long addr = ifp->getLong(&buf[4]);
		    unsigned long sz = ifp->getLong(&buf[8]);
		    if (extraoff >= sz)
		    {
			fprintf(stderr,
				"%s: offset %lu past data, size %lu\n",
				av[0], extraoff, sz);
			return 1;
		    }
		    if (readSize == 0)
		    {
			readSize = sz-extraoff;
		    }
		    if (extraoff + readSize > sz)
		    {
			fprintf(stderr,
				"%s: value size %lu < offset + size %lu\n",
				av[0], sz, extraoff + readSize);
			return 1;
		    }
		    if (extraoff + writeSize > sz)
		    {
			fprintf(stderr,
				"%s: value size %lu < offset + size %lu\n",
				av[0], sz, extraoff + writeSize);
			return 1;
		    }
		    if (si < shnum)
		    {
			valoff = shinfo[si].off + addr - shinfo[si].va;
			if (!dumpSymbols)
			    break;
		    }
		    else
		    {
			fprintf(stderr,
				"%s: cannot examine %s (section index=%lu)\n",
				av[0], varName, si);
			return 1;
		    }
		}
	    }
	}
    }

    if (valoff > 0)
    {
	if (fseek(fp, valoff + extraoff, SEEK_SET) != 0)
	{
	    fprintf(stderr,
		    "%s: cannot seek to offset 0x%08lx, %s\n",
		    av[0], valoff + extraoff, strerror(errno));
	    return 1;
	}
	if (fread(buf, 1, readSize, fp) != readSize)
	{
	    fprintf(stderr, "%s: cannot read %s value, %s\n",
		    av[0], varName, strerror(errno));
	    return 1;
	}
	if (enc == ENC_INT)
	{
	    if (isShort)
		printf("current value: 0x%04hx\n", ifp->getShort(buf));
	    else
		printf("current value: 0x%08lx\n", ifp->getLong(buf));
	}
	else if (enc == ENC_STR)
	{
	    buf[readSize] = '\0';
	    printf("current value: %s\n", buf);
	}
	else
	{
	    int k;
	    printf("current value of %s, offset=%lu:\n", varName, extraoff);
	    for (k = 0; k < readSize; ++k)
	    {
		printf("%02hx", (unsigned short)buf[k]);
		if (k % 4 == 3 || k + 1 >= readSize)
		{
		    printf(" ");
		    if (k % 16 == 15 || k + 1 >= readSize)
		    {
			int l;
			for (l = k % 16; l < 16; ++l)
			    printf(l == 15 ? "* "
				   : l % 4 == 3 ? "   " : "  ");
			for (l = k & ~15; l <= k; ++l)
			    printf("%c", isprint(buf[l]) ? buf[l] : '.');
			printf("\n");
		    }
		}
	    }
	}
	if (op == OP_WRITE)
	{
	    if (fseek(fp, valoff + extraoff, SEEK_SET) != 0)
	    {
		fprintf(stderr,
			"%s: cannot seek to offset 0x%08lx, %s\n",
			av[0], valoff + extraoff, strerror(errno));
		return 1;
	    }
	    if (fwrite(varValue, 1, writeSize, fp) != writeSize)
	    {
		fprintf(stderr,
			"%s: cannot write new value, %s\n",
			av[0], strerror(errno));
		return 1;
	    }
	    if (fclose(fp) != 0)
	    {
		fprintf(stderr,
			"%s: close failed, %s\n", av[0], strerror(errno));
		return 1;
	    }
	    else
	    {
		printf("patched successfully (I hope :)\n");
	    }
	}
    }
    else
    {
	fprintf(stderr, "%s: Symbol %s not found\n", av[0], varName);
    }
    return 0;
}



More information about the users mailing list