Home | History | Annotate | Line # | Download | only in binpatch
      1  1.16    andvar /*	$NetBSD: binpatch.c,v 1.16 2025/08/18 20:59:56 andvar Exp $	*/
      2   1.6    chopps 
      3   1.6    chopps /* Author: Markus Wild mw (at) eunet.ch ???   */
      4   1.6    chopps /* Modified: Rob Leland leland (at) mitre.org */
      5   1.3    chopps 
      6   1.1        mw #include <sys/types.h>
      7   1.1        mw #include <a.out.h>
      8   1.6    chopps #include <fcntl.h>
      9   1.1        mw #include <stdio.h>
     10   1.6    chopps #include <stdlib.h>
     11   1.6    chopps #include <string.h>
     12   1.6    chopps #include <unistd.h>
     13   1.5    chopps 
     14   1.5    chopps #ifdef __NetBSD__
     15   1.5    chopps /*
     16   1.5    chopps  * assume NMAGIC files are linked at 0 (for kernel)
     17   1.5    chopps  */
     18   1.5    chopps #undef N_TXTADDR
     19   1.5    chopps #define N_TXTADDR(ex) \
     20   1.5    chopps 	((N_GETMAGIC2(ex) == (ZMAGIC|0x10000) || N_GETMAGIC2(ex) == NMAGIC) ? \
     21  1.10   thorpej 	0 : AOUT_LDPGSZ)
     22   1.5    chopps #endif
     23   1.1        mw 
     24   1.6    chopps 
     25   1.9   thorpej static char synusage[] =
     26   1.9   thorpej "NAME\n"
     27   1.9   thorpej "\t%s - Allows the patching of BSD binaries\n"
     28   1.9   thorpej "SYNOPSIS\n"
     29   1.9   thorpej "\t%s [-HELP]\n"
     30   1.9   thorpej "\t%s [-b|-w|-l] -s symbol[[[index]][=value]] binary\n"
     31   1.9   thorpej "\t%s [-b|-w|-l] [-o offset] -s symbol [-r value] binary\n"
     32   1.9   thorpej "\t%s [-b|-w|-l] [-o offset] -a address [-r value] binary\n";
     33  1.13  dholland 
     34   1.9   thorpej static char desusage[] =
     35   1.9   thorpej "DESCRIPTION\n"
     36  1.15  dholland "\tAllows the patching of BSD binaries, for example, a distributed\n"
     37  1.16    andvar "\tkernel. Recent additions allows the user to index into an array\n"
     38   1.9   thorpej "\tand assign a value. Binpatch has internal variables to allow\n"
     39   1.9   thorpej "\tyou to test it on itself under NetBSD.\n"
     40   1.9   thorpej "OPTIONS\n"
     41   1.9   thorpej "\t-a  patch variable by specifying address in hex\n"
     42   1.9   thorpej "\t-b  symbol or address to be patched is 1 byte\n"
     43   1.9   thorpej "\t-l  symbol or address to be patched is 4 bytes  (default)\n"
     44   1.9   thorpej "\t-o  offset to begin patching value relative to symbol or address\n"
     45   1.9   thorpej "\t-r  replace value, and print out previous value to stdout\n"
     46   1.9   thorpej "\t-s  patch variable by specifying symbol name. Use '[]'\n"
     47   1.9   thorpej "\t    to specify the 'index'. If '-b, -w or -l' not specified\n"
     48   1.9   thorpej "\t    then index value is used like an offset. Also can use '='\n"
     49   1.9   thorpej "\t    to assign value\n"
     50   1.9   thorpej "\t-w  symbol or address to be patched is 2 bytes\n"
     51   1.9   thorpej "EXAMPLES\n"
     52   1.9   thorpej "\tThis should print 100 (this is a nice reality check...)\n"
     53   1.9   thorpej "\t\tbinpatch -l -s _hz netbsd\n"
     54   1.9   thorpej "\tNow it gets more advanced, replace the value:\n"
     55   1.9   thorpej "\t\tbinpatch -l -s _sbic_debug -r 1 netbsd\n"
     56   1.9   thorpej "\tNow patch a variable at a given 'index' not offset,\n"
     57   1.9   thorpej "\tunder NetBSD you must use '', under AmigaDos CLI '' is optional.:\n"
     58   1.9   thorpej "\t\tbinpatch -w -s '_vieww[4]' -r 0 a.out\n"
     59   1.9   thorpej "\tsame as\n"
     60   1.9   thorpej "\t\tbinpatch -w -o 8 -s _vieww -r 0 a.out\n"
     61   1.9   thorpej "\tAnother example of using []\n"
     62   1.9   thorpej "\t\tbinpatch -s '_viewl[4]' -r 0 a.out\n"
     63   1.9   thorpej "\tsame as\n"
     64   1.9   thorpej "\t\tbinpatch -o 4 -s _viewl -r 0 a.out\n"
     65   1.9   thorpej "\tOne last example using '=' and []\n"
     66   1.9   thorpej "\t\tbinpatch -w -s '_vieww[4]=2' a.out\n"
     67   1.9   thorpej "\tSo if the kernel is not finding your drives, you could enable\n"
     68   1.9   thorpej "\tall available debugging options, helping to shed light on that problem.\n"
     69   1.9   thorpej "\t\tbinpatch -l -s _sbic_debug -r 1 netbsd	scsi-level\n"
     70   1.9   thorpej "\t\tbinpatch -l -s _sddebug -r 1 netbsd	sd-level (disk-driver)\n"
     71   1.9   thorpej "\t\tbinpatch -l -s _acdebug -r 1 netbsd	autoconfig-level\n"
     72   1.9   thorpej "SEE ALSO\n"
     73   1.9   thorpej "\tbinpatch.c binpatch(1)\n";
     74   1.6    chopps 
     75   1.1        mw extern char *optarg;
     76   1.1        mw extern int optind;
     77   1.1        mw 
     78  1.15  dholland void error(char *) __attribute__((__noreturn__));
     79   1.6    chopps static void Synopsis(char *program_name);
     80   1.6    chopps static void Usage(char *program_name);
     81  1.13  dholland static u_long FindAssign(char *symbol, u_long *rvalue);
     82  1.13  dholland static void FindOffset(char *symbol, u_long *index);
     83   1.1        mw 
     84   1.6    chopps /* The following variables are so binpatch can be tested on itself */
     85   1.1        mw int test = 1;
     86   1.1        mw int testbss;
     87   1.1        mw char foo = 23;
     88   1.6    chopps char  viewb[10] = {0,0,1,0,1,1,0,1,1,1};
     89   1.6    chopps short vieww[10] = {0,0,1,0,1,1,0,1,1,1};
     90   1.6    chopps long  viewl[10] = {0,0,1,0,1,1,0,1,1,1};
     91   1.6    chopps /* End of test binpatch variables */
     92  1.13  dholland 
     93   1.1        mw int
     94   1.6    chopps main(int argc, char *argv[])
     95   1.1        mw {
     96  1.13  dholland 	struct exec e;
     97  1.13  dholland 	int c;
     98  1.13  dholland 	u_long addr = 0, offset = 0;
     99  1.14  dholland 	/* Related to offset */
    100  1.14  dholland 	u_long index = 0;
    101  1.13  dholland 	u_long replace = 0, do_replace = 0;
    102  1.13  dholland 	char *symbol = 0;
    103  1.14  dholland 	/* default to long */
    104  1.14  dholland 	char size = 4;
    105  1.14  dholland 	/* Flag to say size option was set, used with index */
    106  1.14  dholland 	char size_opt = 0;
    107  1.13  dholland 	char *fname;
    108  1.14  dholland 	/* Program name */
    109  1.14  dholland 	char *pgname = argv[0];
    110  1.13  dholland 	int fd;
    111  1.13  dholland 	int type, off;
    112  1.13  dholland 	u_long  lval;
    113  1.13  dholland 	u_short sval;
    114  1.13  dholland 	u_char  cval;
    115  1.13  dholland 
    116  1.13  dholland 
    117  1.15  dholland 	while ((c = getopt(argc, argv, "H:a:bwlr:s:o:")) != -1) {
    118  1.14  dholland 		switch (c) {
    119  1.15  dholland 		case 'H':
    120  1.13  dholland 			Usage(argv[0]);
    121  1.13  dholland 			break;
    122  1.15  dholland 		case 'a':
    123  1.14  dholland 			if (addr || symbol) {
    124  1.15  dholland 				error("only one address/symbol allowed");
    125  1.14  dholland 			}
    126  1.14  dholland 			if (!strncmp(optarg, "0x", 2)) {
    127  1.15  dholland 				sscanf(optarg, "%x", &addr);
    128  1.14  dholland 			} else {
    129  1.15  dholland 				addr = atoi(optarg);
    130  1.14  dholland 			}
    131  1.14  dholland 			if (!addr) {
    132  1.15  dholland 				error("invalid address");
    133  1.14  dholland 			}
    134  1.13  dholland 			break;
    135  1.13  dholland 
    136  1.15  dholland 		case 'b':
    137  1.13  dholland 			size = 1;
    138  1.13  dholland 			size_opt = 1;
    139  1.13  dholland 			break;
    140  1.13  dholland 
    141  1.15  dholland 		case 'w':
    142  1.13  dholland 			size = 2;
    143  1.13  dholland 			size_opt = 1;
    144  1.13  dholland 			break;
    145  1.13  dholland 
    146  1.15  dholland 		case 'l':
    147  1.13  dholland 			size = 4;
    148  1.13  dholland 			size_opt = 1;
    149  1.13  dholland 			break;
    150  1.13  dholland 
    151  1.15  dholland 		case 'r':
    152  1.13  dholland 			do_replace = 1;
    153  1.14  dholland 			if (!strncmp(optarg, "0x", 2)) {
    154  1.15  dholland 				sscanf(optarg, "%x", &replace);
    155  1.14  dholland 			} else {
    156  1.15  dholland 				replace = atoi(optarg);
    157  1.14  dholland 			}
    158  1.13  dholland 			break;
    159  1.13  dholland 
    160  1.15  dholland 		case 's':
    161  1.14  dholland 			if (addr || symbol) {
    162  1.15  dholland 				error("only one address/symbol allowed");
    163  1.14  dholland 			}
    164  1.13  dholland 			symbol = optarg;
    165  1.13  dholland 			break;
    166  1.13  dholland 
    167  1.15  dholland 		case 'o':
    168  1.14  dholland 			if (offset) {
    169  1.15  dholland 				error("only one offset allowed");
    170  1.14  dholland 			}
    171  1.15  dholland 			if (!strncmp(optarg, "0x", 2)) {
    172  1.15  dholland 				sscanf(optarg, "%x", &offset);
    173  1.14  dholland 			} else {
    174  1.15  dholland 				offset = atoi(optarg);
    175  1.14  dholland 			}
    176  1.13  dholland 			break;
    177  1.14  dholland 		}
    178  1.14  dholland 		/* end while switch() */
    179  1.14  dholland 	}
    180   1.1        mw 
    181  1.14  dholland 	if (argc > 1) {
    182  1.14  dholland 		if (addr || symbol) {
    183  1.13  dholland 			argv += optind;
    184  1.13  dholland 			argc -= optind;
    185  1.13  dholland 
    186  1.14  dholland 			if (argc < 1) {
    187  1.15  dholland 				error("No file to patch.");
    188  1.14  dholland 			}
    189  1.13  dholland 
    190  1.13  dholland 			fname = argv[0];
    191  1.15  dholland 			if ((fd = open(fname, 0)) < 0) {
    192  1.15  dholland 				error("Can't open file");
    193  1.14  dholland 			}
    194  1.13  dholland 
    195  1.15  dholland 			if (read(fd, &e, sizeof(e)) != sizeof(e)
    196  1.15  dholland 			    || N_BADMAG(e)) {
    197  1.15  dholland 				error("Not a valid executable.");
    198  1.14  dholland 			}
    199  1.13  dholland 
    200  1.13  dholland 			/* fake mid, so the N_ macros work on the amiga.. */
    201  1.13  dholland 			e.a_midmag |= 127 << 16;
    202  1.13  dholland 
    203  1.14  dholland 			if (symbol) {
    204  1.13  dholland 				struct nlist nl[2];
    205  1.14  dholland 
    206  1.14  dholland 				if (offset == 0) {
    207  1.13  dholland 					u_long new_do_replace = 0;
    208  1.13  dholland 
    209  1.14  dholland 					new_do_replace = FindAssign(symbol,
    210  1.14  dholland 								&replace);
    211  1.13  dholland 					if (new_do_replace && do_replace)
    212  1.14  dholland 						error("Cannot use both '=' "
    213  1.14  dholland 						      "and '-r' option!");
    214  1.15  dholland 					FindOffset(symbol, &index);
    215  1.14  dholland 					if (size_opt) {
    216  1.14  dholland 						/* Treat like an index */
    217  1.14  dholland 						offset = index*size;
    218  1.14  dholland 					} else {
    219  1.14  dholland 						/* Treat like an offset */
    220  1.14  dholland 						offset = index;
    221  1.14  dholland 					}
    222  1.13  dholland 					if (new_do_replace)
    223  1.13  dholland 						do_replace = new_do_replace;
    224  1.13  dholland 				}
    225  1.13  dholland 				nl[0].n_un.n_name = symbol;
    226  1.13  dholland 				nl[1].n_un.n_name = 0;
    227  1.15  dholland 				if (nlist(fname, nl) != 0) {
    228  1.15  dholland 					fprintf(stderr, "Symbol is %s ",
    229  1.15  dholland 						symbol);
    230  1.15  dholland 					error("Symbol not found.");
    231  1.13  dholland 				}
    232  1.13  dholland 				addr = nl[0].n_value;
    233  1.13  dholland 				type = nl[0].n_type & N_TYPE;
    234  1.14  dholland 			} else {
    235  1.13  dholland 				type = N_UNDF;
    236  1.14  dholland 				if (addr >= N_TXTADDR(e) &&
    237  1.14  dholland 				    addr < N_DATADDR(e)) {
    238  1.13  dholland 					type = N_TEXT;
    239  1.14  dholland 				} else if (addr >= N_DATADDR(e) &&
    240  1.14  dholland 				    addr < N_DATADDR(e) + e.a_data) {
    241  1.13  dholland 					type = N_DATA;
    242  1.14  dholland 				}
    243  1.13  dholland 			}
    244  1.13  dholland 			addr += offset;
    245  1.13  dholland 
    246  1.14  dholland 			/*
    247  1.14  dholland 			 * if replace-mode, have to reopen the file
    248  1.14  dholland 			 * for writing. Can't do that from the
    249  1.14  dholland 			 * beginning, or nlist() will not work (at
    250  1.14  dholland 			 * least not under AmigaDOS)
    251  1.14  dholland 			 */
    252  1.14  dholland 			if (do_replace) {
    253  1.15  dholland 				close(fd);
    254  1.15  dholland 				if ((fd = open(fname, 2)) == -1) {
    255  1.14  dholland 					error("Can't reopen file for writing.");
    256  1.14  dholland 				}
    257  1.13  dholland 			}
    258  1.13  dholland 
    259  1.14  dholland 			if (type != N_TEXT && type != N_DATA) {
    260  1.14  dholland 				error("address/symbol is not in text "
    261  1.14  dholland 				      "or data section.");
    262  1.14  dholland 			}
    263  1.13  dholland 
    264  1.14  dholland 			if (type == N_TEXT) {
    265  1.13  dholland 				off = addr - N_TXTADDR(e) + N_TXTOFF(e);
    266  1.14  dholland 			} else {
    267  1.13  dholland 				off = addr - N_DATADDR(e) + N_DATOFF(e);
    268  1.14  dholland 			}
    269  1.13  dholland 
    270  1.14  dholland 			if (lseek(fd, off, 0) == -1) {
    271  1.15  dholland 				error("lseek");
    272  1.14  dholland 			}
    273  1.13  dholland 
    274  1.14  dholland 			/*
    275  1.14  dholland 			 * not beautiful, but works on big and little
    276  1.14  dholland 			 * endian machines
    277  1.14  dholland 			 */
    278  1.14  dholland 			switch (size) {
    279  1.15  dholland 			case 1:
    280  1.14  dholland 				if (read(fd, &cval, 1) != 1) {
    281  1.15  dholland 					error("cread");
    282  1.14  dholland 				}
    283  1.13  dholland 				lval = cval;
    284  1.13  dholland 				break;
    285  1.13  dholland 
    286  1.15  dholland 			case 2:
    287  1.14  dholland 				if (read(fd, &sval, 2) != 2) {
    288  1.15  dholland 					error("sread");
    289  1.14  dholland 				}
    290  1.13  dholland 				lval = sval;
    291  1.13  dholland 				break;
    292  1.13  dholland 
    293  1.15  dholland 			case 4:
    294  1.14  dholland 				if (read(fd, &lval, 4) != 4) {
    295  1.15  dholland 					error("lread");
    296  1.14  dholland 				}
    297  1.13  dholland 				break;
    298  1.13  dholland 			}/* switch size */
    299  1.13  dholland 
    300  1.13  dholland 
    301  1.14  dholland 			if (symbol) {
    302  1.14  dholland 				printf("%s(0x%x): %d (0x%x)\n", symbol, addr,
    303  1.14  dholland 					lval, lval);
    304  1.14  dholland 			} else {
    305  1.14  dholland 				printf("0x%x: %d (0x%x)\n", addr, lval, lval);
    306  1.14  dholland 			}
    307  1.14  dholland 
    308  1.14  dholland 			if (do_replace) {
    309  1.15  dholland 				if (lseek(fd, off, 0) == -1) {
    310  1.15  dholland 					error("write-lseek");
    311  1.14  dholland 				}
    312  1.14  dholland 				switch (size) {
    313  1.15  dholland 				case 1:
    314  1.13  dholland 					cval = replace;
    315  1.14  dholland 					if (cval != replace) {
    316  1.15  dholland 						error("byte-value overflow.");
    317  1.14  dholland 					}
    318  1.14  dholland 					if (write(fd, &cval, 1) != 1) {
    319  1.15  dholland 						error("cwrite");
    320  1.14  dholland 					}
    321  1.13  dholland 					break;
    322  1.13  dholland 
    323  1.15  dholland 				case 2:
    324  1.13  dholland 					sval = replace;
    325  1.14  dholland 					if (sval != replace) {
    326  1.15  dholland 						error("word-value overflow.");
    327  1.14  dholland 					}
    328  1.14  dholland 					if (write(fd, &sval, 2) != 2) {
    329  1.15  dholland 						error("swrite");
    330  1.14  dholland 					}
    331  1.13  dholland 					break;
    332  1.13  dholland 
    333  1.15  dholland 				case 4:
    334  1.14  dholland 					if (write(fd, &replace, 4) != 4) {
    335  1.15  dholland 						error("lwrite");
    336  1.14  dholland 					}
    337  1.13  dholland 					break;
    338  1.14  dholland 				}
    339  1.14  dholland 				/* end switch(size) */
    340  1.14  dholland 			}
    341  1.14  dholland 			/* end if (do_replace) */
    342  1.13  dholland 
    343  1.15  dholland 			close(fd);
    344  1.14  dholland 		} else {
    345  1.14  dholland 			/* not (addr || symbol) */
    346  1.13  dholland 			error("Must specify either address or symbol.");
    347  1.13  dholland 		}
    348  1.14  dholland 	} else {
    349  1.14  dholland 		/* if argc <= 1 */
    350  1.13  dholland 		Synopsis(pgname);
    351   1.6    chopps 	}
    352  1.14  dholland 
    353  1.14  dholland 	return 0;
    354  1.14  dholland }
    355  1.14  dholland /* end main () */
    356   1.1        mw 
    357   1.1        mw 
    358   1.1        mw 
    359  1.14  dholland void
    360  1.14  dholland error(char *str)
    361   1.6    chopps {
    362  1.15  dholland 	fprintf(stderr, "%s\n", str);
    363  1.15  dholland 	exit(1);
    364   1.1        mw }
    365   1.1        mw 
    366   1.6    chopps /* Give user very short help to avoid scrolling screen much */
    367  1.14  dholland static void
    368  1.14  dholland Synopsis(char *pgname)
    369   1.6    chopps {
    370  1.13  dholland 	fprintf(stdout, synusage, pgname, pgname, pgname, pgname, pgname);
    371   1.6    chopps }
    372   1.1        mw 
    373   1.1        mw 
    374  1.14  dholland static void
    375  1.14  dholland Usage(char *pgname)
    376   1.1        mw {
    377  1.13  dholland 	Synopsis(pgname);
    378  1.13  dholland 	fprintf(stdout, desusage);
    379  1.13  dholland 	exit(0);
    380   1.1        mw }
    381   1.6    chopps 
    382   1.6    chopps 
    383  1.14  dholland /*
    384  1.14  dholland  * FindOffset() - Determine if there is an offset, -or- index
    385  1.14  dholland  * embedded in the symbol.
    386  1.14  dholland  *
    387  1.14  dholland  * If there is, return it, and truncate symbol to exclude the [...].
    388  1.14  dholland  *
    389  1.14  dholland  * Example: If view is declared as short view[10],
    390  1.14  dholland  *                and we want to index the 3rd. element.
    391  1.14  dholland  *                which is offset = (3 -1)*sizeof(short) =4.
    392  1.14  dholland  *          we would use view[4], which becomes view,4.
    393  1.14  dholland  *
    394  1.14  dholland  *          The way the code is implemented the [value] is
    395  1.14  dholland  *          treated as a index if-and-only-if a '-b -w -l' option
    396  1.14  dholland  *          was given. Otherwise it is treated like an offset.
    397  1.14  dholland  *           See above documentation in for of help!
    398  1.14  dholland  */
    399  1.14  dholland static void
    400  1.14  dholland FindOffset(char *symbol, u_long *index)
    401   1.6    chopps {
    402  1.14  dholland 	/* Start of '[', now line must contain matching']' */
    403  1.15  dholland 	char *sb = strchr(symbol, '[');
    404  1.14  dholland 
    405  1.14  dholland 	/* End of ']' */
    406  1.15  dholland 	char *eb = strchr(symbol, ']');
    407  1.14  dholland 
    408  1.14  dholland 	/* symbol size */
    409  1.14  dholland 	short sz = strlen(symbol);
    410  1.14  dholland 
    411  1.14  dholland 	if (sb) {
    412  1.14  dholland 		if (eb && (eb > sb)) {
    413  1.14  dholland 			if ((eb - symbol) == (sz - 1)) {
    414  1.14  dholland 				/* Start of index */
    415  1.14  dholland 				char *sindex;
    416  1.13  dholland 				u_long newindex = 0;
    417  1.14  dholland 
    418  1.14  dholland 				/*
    419  1.14  dholland 				 * In the future we could get fancy
    420  1.14  dholland 				 * and parse the sindex string for
    421  1.14  dholland 				 * mathmatical expressions like: (3 -
    422  1.14  dholland 				 * 1)*2 = 4 from above example, ugh
    423  1.14  dholland 				 * forget I mentioned ot :-) !
    424  1.14  dholland 				 */
    425  1.13  dholland 				sindex = sb + 1;
    426  1.13  dholland 				*eb = '\0';
    427  1.13  dholland 				newindex = (u_long)atoi(sindex);
    428  1.14  dholland 				if (*index == 0) {
    429  1.13  dholland 					*index = newindex;
    430  1.14  dholland 					/* Make _view[3] look like _view */
    431  1.14  dholland 					*sb = '\0';
    432  1.14  dholland 				} else {
    433  1.14  dholland 					fprintf(stderr, "Error index can "
    434  1.14  dholland 						"only be specified once!\n");
    435  1.13  dholland 				}
    436  1.14  dholland 			} else {
    437  1.14  dholland 				fprintf(stderr, "Error: Garbage "
    438  1.14  dholland 					"trailing ']'\n");
    439  1.13  dholland 			}
    440  1.14  dholland 		} else {
    441  1.14  dholland 			fprintf(stderr, "Error ']' in symbol before '[' !\n");
    442  1.13  dholland 		}
    443  1.14  dholland 	}
    444  1.14  dholland 	/* end if sb != 0 */
    445  1.14  dholland }
    446  1.14  dholland /* end FindOffset */
    447   1.6    chopps 
    448  1.14  dholland /*
    449  1.14  dholland  * FindAssign : Scans symbol name for an '=number' strips it off of
    450  1.14  dholland  * the symbol and proceeds.
    451  1.14  dholland  */
    452  1.14  dholland static u_long
    453  1.14  dholland FindAssign(char *symbol, u_long *rvalue)
    454   1.6    chopps {
    455  1.14  dholland 	/* Assign symbol some number */
    456  1.15  dholland 	char *ce = rindex(symbol, '=');
    457  1.14  dholland 
    458  1.14  dholland 	/* This should point at some number, no spaces allowed */
    459  1.14  dholland 	char *cn = ce + 1;
    460  1.14  dholland 
    461  1.14  dholland 	/* flag for do_replace */
    462  1.14  dholland 	u_long dr = 0;
    463  1.14  dholland 
    464  1.14  dholland 	if (ce) {
    465  1.14  dholland 		/* number of variaables scanned in */
    466  1.14  dholland 		int nscan;
    467  1.14  dholland 
    468  1.13  dholland 		/* get the number to assign to symbol and strip off = */
    469  1.13  dholland 		for (cn=ce + 1; *cn==' '; cn++)
    470  1.13  dholland 			;
    471  1.14  dholland 		if (!strncmp(cn, "0x", 2)) {
    472  1.14  dholland 			nscan = sscanf(cn, "%x", rvalue);
    473  1.14  dholland 		} else {
    474  1.14  dholland 			nscan = sscanf(cn, "%d", rvalue);
    475  1.14  dholland 		}
    476  1.14  dholland 		if (nscan != 1) {
    477  1.13  dholland 			error("Invalid value following '='");
    478  1.14  dholland 		}
    479  1.13  dholland 		dr = 1;
    480  1.14  dholland 		/* Now were left with just symbol */
    481  1.14  dholland 		*ce = '\0';
    482  1.14  dholland 	}
    483  1.14  dholland 	/* end if (ce) */
    484  1.13  dholland 	return(dr);
    485  1.14  dholland }
    486  1.14  dholland /* end FindAssign */
    487