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