home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga GigaPD 3
/
Amiga_GigaPD_v3_3of3.iso
/
netbsd
/
incoming
/
binpatch.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-25
|
6KB
|
257 lines
#include <sys/types.h>
#include <a.out.h>
#include <stdio.h>
static char usage[] = "
NAME
\t%s - Allows the patching of BSD binaries
SYNOPSIS
\t%s [-b|-w|-l] [-o offset] {-s symbol | -a address} [-r value] binary
DESCRIPTION
\tAllows the patching of BSD binaries, for example,a distributed
\tkernel. To go into details, read the source.
OPTIONS
\t-a patch variable by specifying address
\t-b symbol or address to be patched is 1 byte in size
\t-l symbol or address to be patched is 4 bytes in size(The default)
\t-o offset to begin patching value relative to symbol or address
\t-r replace value, and print out previous value to stdout
\t-s patch variable by specifying symbol name
\t-w symbol or address to be patched is 2 bytes in size
EXAMPLES
This should print 100 (this is a nice reality check...)
\tbinpatch -l -s _hz vmunix
Now it gets more advanced, replace the value:
\tbinpatch -l -s _scsi_debug -r 1 vmunix
So if kernel cannot finding your drives, you could enable all available
debugging options helping to shed light on that problem.
\tbinpatch -l -s _scsi_debug -r 1 vmunix scsi-level
\tbinpatch -l -s _sddebug -r 1 vmunix sd-level (disk-driver)
\tbinpatch -l -s _acdebug -r 1 vmunix autoconfig-level
";
extern char *optarg;
extern int optind;
volatile void error ();
static void Usage(char *program_name);
/* The variables below seem to be so binpatch can be tested on itself? */
int test = 1;
int testbss;
char foo = 23;
int
main(argc, argv)
int argc;
char *argv[];
{
struct exec e;
int c;
u_long addr = 0, offset = 0;
u_long replace = 0, do_replace = 0;
char *symbol = 0;
char size = 4; /* default to long */
char *fname;
char *pgname = argv[0]; /* Program name */
int fd;
int type, off;
u_long lval;
u_short sval;
u_char cval;
while ((c = getopt (argc, argv, "a:bwlr:s:o:")) != EOF)
switch (c)
{
case 'a':
if (addr || symbol)
error ("only one address/symbol allowed");
if (! strncmp (optarg, "0x", 2))
sscanf (optarg, "%x", &addr);
else
addr = atoi (optarg);
if (! addr)
error ("invalid address");
break;
case 'b':
size = 1;
break;
case 'w':
size = 2;
break;
case 'l':
size = 4;
break;
case 'r':
do_replace = 1;
if (! strncmp (optarg, "0x", 2))
sscanf (optarg, "%x", &replace);
else
replace = atoi (optarg);
break;
case 's':
if (addr || symbol)
error ("only one address/symbol allowed");
symbol = optarg;
break;
case 'o':
if (offset)
error ("only one offset allowed");
if (! strncmp (optarg, "0x", 2))
sscanf (optarg, "%x", &offset);
else
offset = atoi (optarg);
break;
}/* while switch() */
if (argc > 1)
{
if (addr || symbol)
{
argv += optind;
argc -= optind;
if (argc < 1)
error ("No file to patch.");
fname = argv[0];
if ((fd = open (fname, 0)) < 0)
error ("Can't open file");
if (read (fd, &e, sizeof (e)) != sizeof (e)
|| N_BADMAG (e))
error ("Not a valid executable.");
/* fake mid, so the N_ macros work on the amiga.. */
e.a_midmag |= 127 << 16;
if (symbol)
{
struct nlist nl[2];
nl[0].n_un.n_name = symbol;
nl[1].n_un.n_name = 0;
if (nlist (fname, nl) != 0)
error ("Symbol not found.");
addr = nl[0].n_value;
type = nl[0].n_type & N_TYPE;
}
else
{
type = N_UNDF;
if (addr >= N_TXTADDR(e) && addr < N_DATADDR(e))
type = N_TEXT;
else if (addr >= N_DATADDR(e) && addr < N_DATADDR(e) + e.a_data)
type = N_DATA;
}
addr += offset;
/* if replace-mode, have to reopen the file for writing.
Can't do that from the beginning, or nlist() will not
work (at least not under AmigaDOS) */
if (do_replace)
{
close (fd);
if ((fd = open (fname, 2)) == -1)
error ("Can't reopen file for writing.");
}
if (type != N_TEXT && type != N_DATA)
error ("address/symbol is not in text or data section.");
if (type == N_TEXT)
off = addr - N_TXTADDR(e) + N_TXTOFF(e);
else
off = addr - N_DATADDR(e) + N_DATOFF(e);
if (lseek (fd, off, 0) == -1)
error ("lseek");
/* not beautiful, but works on big and little endian machines */
switch (size)
{
case 1:
if (read (fd, &cval, 1) != 1)
error ("cread");
lval = cval;
break;
case 2:
if (read (fd, &sval, 2) != 2)
error ("sread");
lval = sval;
break;
case 4:
if (read (fd, &lval, 4) != 4)
error ("lread");
break;
}/* switch size */
if (symbol)
printf ("%s(0x%x): %d (0x%x)\n", symbol, addr, lval, lval);
else
printf ("0x%x: %d (0x%x)\n", addr, lval, lval);
if (do_replace)
{
if (lseek (fd, off, 0) == -1)
error ("write-lseek");
switch (size)
{
case 1:
cval = replace;
if (cval != replace)
error ("byte-value overflow.");
if (write (fd, &cval, 1) != 1)
error ("cwrite");
break;
case 2:
sval = replace;
if (sval != replace)
error ("word-value overflow.");
if (write (fd, &sval, 2) != 2)
error ("swrite");
break;
case 4:
if (write (fd, &replace, 4) != 4)
error ("lwrite");
break;
}/* switch(size) */
}/* if (do_replace) */
close (fd);
}/* if(addr || symbol ) */
else
{
exit("Must specify either address or symbol.");
}
}/* if argc < 1 */
else
{
Usage(pgname);
}
}/* main () */
volatile void error (str)
char *str;
{
fprintf (stderr, "%s\n", str);
exit (1);
}
static void Usage(char *pgname)
{
fprintf(stdout,usage,pgname,pgname);
}