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