home *** CD-ROM | disk | FTP | other *** search
/ Amiga GigaPD 3 / Amiga_GigaPD_v3_3of3.iso / netbsd / incoming / binpatch.c < prev    next >
C/C++ Source or Header  |  1993-06-25  |  6KB  |  257 lines

  1. #include <sys/types.h>
  2. #include <a.out.h>
  3. #include <stdio.h>
  4. static char usage[] = "
  5. NAME
  6. \t%s - Allows the patching of BSD binaries
  7. SYNOPSIS
  8. \t%s [-b|-w|-l] [-o offset] {-s symbol | -a address} [-r value] binary
  9. DESCRIPTION
  10. \tAllows the patching of BSD binaries, for example,a distributed
  11. \tkernel. To go into details, read the source.
  12. OPTIONS
  13. \t-a patch variable by specifying address
  14. \t-b symbol or address to be patched is 1 byte in size
  15. \t-l symbol or address to be patched is 4 bytes in size(The default)
  16. \t-o offset to begin patching value relative to symbol or address
  17. \t-r replace value, and print out previous value to stdout
  18. \t-s patch variable by specifying symbol name
  19. \t-w symbol or address to be patched is 2 bytes in size
  20. EXAMPLES
  21. This should print 100 (this is a nice reality check...)
  22. \tbinpatch -l -s _hz vmunix
  23. Now it gets more advanced, replace the value:
  24. \tbinpatch -l -s _scsi_debug -r 1 vmunix
  25. So if kernel cannot finding your drives, you could enable all available
  26. debugging options helping to shed light on that problem.
  27. \tbinpatch -l -s _scsi_debug -r 1 vmunix    scsi-level
  28. \tbinpatch -l -s _sddebug -r 1 vmunix    sd-level (disk-driver)
  29. \tbinpatch -l -s _acdebug -r 1 vmunix    autoconfig-level
  30. ";
  31.  
  32. extern char *optarg;
  33. extern int optind;
  34.  
  35. volatile void error ();
  36. static void Usage(char *program_name);
  37. /* The variables below seem to be so binpatch can be tested on itself? */
  38. int test = 1;
  39. int testbss;
  40. char foo = 23;
  41.  
  42. int
  43. main(argc, argv)
  44.      int argc;
  45.      char *argv[];
  46. {
  47.   struct exec e;
  48.   int c;
  49.   u_long addr = 0, offset = 0;
  50.   u_long replace = 0, do_replace = 0;
  51.   char *symbol = 0;
  52.   char size = 4;  /* default to long */
  53.   char *fname;
  54.   char *pgname = argv[0]; /* Program name */
  55.   int fd;
  56.   int type, off;
  57.   u_long  lval;
  58.   u_short sval;
  59.   u_char  cval;
  60.   
  61.  
  62.   while ((c = getopt (argc, argv, "a:bwlr:s:o:")) != EOF)
  63.     switch (c)
  64.       {
  65.       case 'a':
  66.     if (addr || symbol)
  67.       error ("only one address/symbol allowed");
  68.     if (! strncmp (optarg, "0x", 2))
  69.       sscanf (optarg, "%x", &addr);
  70.     else
  71.       addr = atoi (optarg);
  72.     if (! addr)
  73.       error ("invalid address");
  74.     break;
  75.  
  76.       case 'b':
  77.     size = 1;
  78.     break;
  79.  
  80.       case 'w':
  81.     size = 2;
  82.     break;
  83.  
  84.       case 'l':
  85.     size = 4;
  86.     break;
  87.  
  88.       case 'r':
  89.     do_replace = 1;
  90.     if (! strncmp (optarg, "0x", 2))
  91.       sscanf (optarg, "%x", &replace);
  92.     else
  93.       replace = atoi (optarg);
  94.     break;
  95.  
  96.       case 's':
  97.     if (addr || symbol)
  98.       error ("only one address/symbol allowed");
  99.     symbol = optarg;
  100.     break;
  101.  
  102.       case 'o':
  103.     if (offset)
  104.       error ("only one offset allowed");
  105.     if (! strncmp (optarg, "0x", 2))
  106.       sscanf (optarg, "%x", &offset);
  107.     else
  108.           offset = atoi (optarg);
  109.         break;
  110.       }/* while switch() */
  111.   
  112.   if (argc > 1)
  113.   {
  114.     if (addr || symbol)
  115.     {
  116.       argv += optind;
  117.       argc -= optind;
  118.  
  119.       if (argc < 1)
  120.         error ("No file to patch.");
  121.  
  122.       fname = argv[0];
  123.       if ((fd = open (fname, 0)) < 0)
  124.         error ("Can't open file");
  125.  
  126.       if (read (fd, &e, sizeof (e)) != sizeof (e)
  127.         || N_BADMAG (e))
  128.         error ("Not a valid executable.");
  129.  
  130.       /* fake mid, so the N_ macros work on the amiga.. */
  131.       e.a_midmag |= 127 << 16;
  132.  
  133.       if (symbol)
  134.       {
  135.         struct nlist nl[2];
  136.         nl[0].n_un.n_name = symbol;
  137.         nl[1].n_un.n_name = 0;
  138.         if (nlist (fname, nl) != 0)
  139.       error ("Symbol not found.");
  140.         addr = nl[0].n_value;
  141.         type = nl[0].n_type & N_TYPE;
  142.       }
  143.       else
  144.       {
  145.         type = N_UNDF;
  146.         if (addr >= N_TXTADDR(e) && addr < N_DATADDR(e))
  147.       type = N_TEXT;
  148.         else if (addr >= N_DATADDR(e) && addr < N_DATADDR(e) + e.a_data)
  149.       type = N_DATA;
  150.       }
  151.       addr += offset;
  152.  
  153.       /* if replace-mode, have to reopen the file for writing.
  154.          Can't do that from the beginning, or nlist() will not 
  155.          work (at least not under AmigaDOS) */
  156.       if (do_replace)
  157.       {
  158.         close (fd);
  159.         if ((fd = open (fname, 2)) == -1)
  160.       error ("Can't reopen file for writing.");
  161.       }
  162.  
  163.       if (type != N_TEXT && type != N_DATA)
  164.         error ("address/symbol is not in text or data section.");
  165.  
  166.       if (type == N_TEXT)
  167.         off = addr - N_TXTADDR(e) + N_TXTOFF(e);
  168.       else
  169.         off = addr - N_DATADDR(e) + N_DATOFF(e);
  170.  
  171.       if (lseek (fd, off, 0) == -1)
  172.         error ("lseek");
  173.  
  174.       /* not beautiful, but works on big and little endian machines */
  175.       switch (size)
  176.         {
  177.         case 1:
  178.           if (read (fd, &cval, 1) != 1)
  179.         error ("cread");
  180.           lval = cval;
  181.           break;
  182.  
  183.         case 2:
  184.           if (read (fd, &sval, 2) != 2)
  185.         error ("sread");
  186.           lval = sval;
  187.           break;
  188.  
  189.         case 4:
  190.           if (read (fd, &lval, 4) != 4)
  191.         error ("lread");
  192.           break;
  193.         }/* switch size */
  194.  
  195.   
  196.       if (symbol)
  197.         printf ("%s(0x%x): %d (0x%x)\n", symbol, addr, lval, lval);
  198.       else
  199.         printf ("0x%x: %d (0x%x)\n", addr, lval, lval);
  200.  
  201.       if (do_replace)
  202.       {
  203.         if (lseek (fd, off, 0) == -1)
  204.       error ("write-lseek");
  205.         switch (size)
  206.       {
  207.       case 1:
  208.         cval = replace;
  209.         if (cval != replace)
  210.           error ("byte-value overflow.");
  211.         if (write (fd, &cval, 1) != 1)
  212.           error ("cwrite");
  213.         break;
  214.  
  215.       case 2:
  216.         sval = replace;
  217.         if (sval != replace)
  218.           error ("word-value overflow.");
  219.         if (write (fd, &sval, 2) != 2)
  220.           error ("swrite");
  221.         break;
  222.  
  223.       case 4:
  224.         if (write (fd, &replace, 4) != 4)
  225.           error ("lwrite");
  226.         break;
  227.       }/* switch(size) */
  228.       }/* if (do_replace) */
  229.  
  230.       close (fd);
  231.     }/* if(addr || symbol ) */
  232.     else
  233.     {
  234.       exit("Must specify either address or symbol.");
  235.     }
  236.   }/* if argc < 1 */
  237.   else
  238.   {
  239.     Usage(pgname);
  240.   }
  241. }/* main () */
  242.  
  243.  
  244.  
  245. volatile void error (str)
  246.      char *str;
  247. {
  248.   fprintf (stderr, "%s\n", str);
  249.   exit (1);
  250. }
  251.  
  252. static void Usage(char *pgname)
  253. {
  254.   fprintf(stdout,usage,pgname,pgname);
  255. }
  256.  
  257.