home *** CD-ROM | disk | FTP | other *** search
- #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);
- }
-
-