|
|
1.1 root 1: static char Copyright[] = "$Copyright: (c) 1985, INETCO Systems, Ltd.$";
2: static char version[] = "patch version 2.6 for COHERENT v.4.0";
3:
4: /* (lgl-
5: * The information contained herein is a trade secret of Mark Williams
6: * Company, and is confidential information. It is provided under a
7: * license agreement, and may be copied or disclosed only under the
8: * terms of that agreement. Any reproduction or disclosure of this
9: * material without the express written authorization of Mark Williams
10: * Company or persuant to the license agreement is unlawful.
11: *
12: * COHERENT Version 2.3.35
13: * Copyright (c) 1982, 1983, 1984.
14: * An unpublished work by Mark Williams Company, Chicago.
15: * All rights reserved.
16: -lgl) */
17: /*
18: * Patch binary system images
19: * and possibly the running system.
20: * This program is not expected to work other than on PC Coherent.
21: * Certain hot patches may not be effective, since some values are only
22: * referenced once at system initialization.
23: *
24: * $Log: patch.c,v $
25: * Revision 1.6 92/11/25 15:32:04 bin
26: * hal: update to read fom /dev/imem
27: *
28: * Revision 1.5 92/07/06 15:41:09 bin
29: * piggy: all hex numbers have leading zeroes to indicate their length
30: *
31: * Revision 1.1 91/04/24 14:20:20 bin
32: * Initial revision
33: *
34: * 87/02/01 Allan Cornish /usr/src/cmd/conf/patch.c
35: * myatol() routine added which recognizes numeric base specifications.
36: * All references to atol() modified to use myatol().
37: * main() now enables buffering on standard output.
38: *
39: */
40: char short_helpmessage[] = "\
41: patch -- alter COFF binary image\n\
42: Usage: patch [ -v ][ -p ][ -k ] imagename symbol=value [ ... ]\n\
43: ";
44:
45: char helpmessage[] = "\
46: Options:\n\
47: -v Verbose mode--print what's being done.\n\
48: -p Peek only--do not write.\n\
49: -k Patch running system via /dev/kmem, /dev/kmemhi.\n\
50: -K Like -k but do not alter imagename.\n\
51: Patch alters the value of 'symbol' to 'value' in the binary 'imagename'.\n\
52: Both 'symbol' and 'value' may be composed of a decimal numeric constant\n\
53: or of a symbol in the image's symbol table, trailing '_' is significant,\n\
54: optionally offset by + or - a decimal numeric constant.\n\
55: The 'value' field may be optionally composed of 'makedev(d1, d2)' where 'd1'\n\
56: and 'd2' are decimal numbers and the result is a dev_t value.\n\
57: The size of the altered field is by default sizeof(int), but the 'value'\n\
58: specification may be followed by a ':' and a 'c', 's', 'i', or 'l' to\n\
59: explicitly specify a char, short, int, or long sized patch.\n\
60: \
61: ";
62:
63: #include <stdio.h>
64: #include <coff.h>
65: #include <canon.h>
66: #include <ctype.h>
67: #include <fcntl.h>
68: #include <sys/types.h>
69: #include <sys/stat.h>
70: #include "patch.h"
71:
72: /*
73: * Nlist tables and patch records.
74: */
75: #define NNLS 512
76: int nnls; /* Number of nlist elements used */
77: SYMENT nl[NNLS*2];
78: int sym_len = 0; /* Number of bytes allocated for symbols. */
79: char *symbols=NULL;
80:
81: PLIST pl[NNLS];
82:
83: char *namep; /* Name of object file to patch. */
84: int nobin = 0; /* Should we not patch the image? */
85: int hotpatch = 0; /* Are we patching /dev/kmem,/dev/kmemhi? */
86: int verbose = 0; /* Are we printing feedback? */
87: int peek = 0; /* Just peek--don't actually do the patch. */
88:
89: void main();
90: int getnames();
91: void badsym();
92: void getone();
93: void setfile();
94: void setkmem();
95: int patch();
96: long myatol();
97: void usage();
98: char *index();
99: char *realloc();
100:
101:
102: void
103: main(argc, argv)
104: int argc;
105: char *argv[];
106: {
107: static char obuf[BUFSIZ];
108: int c; /* For reading options from getopt(). */
109: int num_patches; /* Number of patches to make on this file. */
110:
111: extern int optind;
112: extern char *optarg;
113:
114: /*
115: * Enable output buffering.
116: */
117: setbuf( stdout, obuf );
118:
119: while ((c = getopt(argc, argv, "Kkpv?")) != EOF) {
120: switch (c) {
121: case 'K':
122: hotpatch++;
123: nobin++;
124: case 'k':
125: hotpatch++;
126: break;
127: case 'p':
128: peek++;
129: break;
130: case 'v':
131: verbose++;
132: break;
133: case '?':
134: fprintf(stderr, "%s\n", version);
135: usage(TRUE); /* Does not return. */
136: default:
137: usage(FALSE); /* Does not return. */
138: }
139: }
140:
141: /*
142: * There must be at least 2 arguments left.
143: */
144: if (argc - optind < 2) {
145: fprintf(stderr, "Missing arguments.\n");
146: usage(FALSE); /* Does not return */
147: }
148:
149: namep = argv[optind++]; /* Fetch the name of the file to patch. */
150:
151: num_patches = (argc - optind);
152: if (getnames(num_patches, &(argv[optind])) == 0) {
153: if (!nobin) {
154: setfile(namep, num_patches, pl);
155: }
156: if (hotpatch) {
157: setkmem(num_patches);
158: }
159: exit(0);
160: }
161: exit(1);
162: }
163:
164: /*
165: * Fill in the array of patch structures 'pl[]' based on the command line.
166: * 'nn' is the number of symbol assignments; 'npp' is an argv of symbol
167: * assignments.
168: * Returns the number of invalid assignments.
169: */
170: int
171: getnames(nn, npp)
172: int nn;
173: char **npp;
174: {
175: register int i;
176: register PLIST *p;
177: register SYMENT *np;
178: int nbad;
179:
180: nbad = 0;
181: for (i = 0; i < nn; i += 1)
182: if (i < NNLS-1)
183: getone(i, npp[i]);
184:
185: /* Now we can look up all the symbols in the symbol table. */
186: coffnlist(namep, nl, symbols, nnls);
187:
188: for (i = 0; i < nn; i += 1)
189: if (i >= NNLS)
190: fprintf(stderr,
191: "Too many patches: %s ignored\n", npp[i]);
192: else {
193: /* 'p' is the struct we fill in this time around. */
194: p = &pl[i];
195:
196: /* If the LHS was (part) symbolic, add in the value
197: * of the symbol.
198: */
199: if ((np = p->p_lvnp) != NULL) {
200: if (0xffff != np->n_type) {
201: p->p_lval += np->n_value;
202: } else {
203: nbad += 1;
204: badsym(np->n_offset);
205: }
206: }
207: /* If the RHS was (part) symbolic, add in the value
208: * of the symbol.
209: */
210: if ((np = p->p_rvnp) != NULL) {
211: if (0xffff != np->n_type) {
212: p->p_rval += np->n_value;
213: } else {
214: nbad += 1;
215: badsym(np->n_offset);
216: }
217: }
218:
219: /* Fill in the value to be assigned. */
220: switch (p->p_type) {
221: case 'c': p->p_val.p_char = p->p_rval; break;
222: case 's': p->p_val.p_short = p->p_rval; break;
223: case 'i': p->p_val.p_int = p->p_rval; break;
224: case 'l': p->p_val.p_long = p->p_rval; break;
225: default:
226: nbad += 1;
227: fprintf(stderr, "Bad data type %c in %s.\n",
228: p->p_type, npp[i]);
229: break;
230: }
231: }
232: return (nbad);
233: }
234:
235: void
236: badsym(offset)
237: long offset;
238: {
239: fprintf(stderr, "%s not found in %s\n",
240: &(symbols[offset - sizeof(long)]), namep);
241: }
242:
243: /*
244: * Parse a symbolic assignment, filling in pl[i].
245: */
246: void
247: getone(i, np)
248: int i; /* Which'th symbol assigment is this? */
249: register char *np; /* The symbol assignment itself. */
250: {
251: register int n;
252: register char *cp;
253: char *nsym; /* Temporary holder for 'symbols' realloc(). */
254: long myatol();
255:
256: pl[i].p_lvnp = NULL;
257: pl[i].p_lval = 0;
258: pl[i].p_rvnp = NULL;
259: pl[i].p_rval = 0;
260: pl[i].p_type = 'i';
261:
262: /*
263: * If there is a type indicator, get it now.
264: */
265: if (NULL != (cp = index(np, ':'))) {
266: pl[i].p_type = cp[1];
267: }
268:
269: /* Pull apart LHS of assignment. */
270: if (isalpha(*np) || *np == '_') {
271: pl[i].p_lvnp = nl + nnls; /* Allocate another SYMENT. */
272: /* Mark as not yet found. */
273: nl[nnls].n_type = 0xffff;
274: /* Point at offset into 'symbols' for new name. */
275: nl[nnls].n_zeroes = 0;
276: nl[nnls].n_offset = sizeof(long) + sym_len;
277:
278: /* Figure out how big the symbol is by looking for
279: * a non-alphanumeric or _ character.
280: */
281: cp = np;
282: for (n = 0; isalnum(*cp) || *cp == '_'; n += 1) {
283: cp += 1;
284: }
285: /* Now allocate more space for symbol names. */
286: sym_len += n + sizeof('\0');
287: if (NULL == (nsym = realloc(symbols, sym_len))) {
288: /* This assignment is too long; skip it. */
289: sym_len -= n;
290: fprintf(stderr,
291: "Assignment too long; skipping: %s\n", np);
292: return;
293: }
294: symbols = nsym; /* The realloc() worked. */
295: /* Copy the new symbol in place. */
296: cp = symbols + sym_len - (n + sizeof('\0'));
297: strncpy(cp, np, n);
298: cp[n] = '\0';
299:
300: nnls += 1; /* Move up to next empty SYMENT. */
301: np += n; /* Move on to next token. */
302: }
303: /*
304: * If there is a '+' it has served its purpose by dropping us
305: * out of the for loop above. Ignore it now.
306: */
307: if (*np == '+')
308: np += 1;
309:
310: /* Fetch a possible literal number. */
311: pl[i].p_lval = myatol(np);
312:
313: /* Pull apart RHS of assignment. */
314: np = index(np, '=');
315: if (np != NULL) {
316: np += 1;
317: if (strncmp(np, "makedev(", 8) == 0) {
318: /* RHS is a makedev() expression. */
319: int d1, d2;
320:
321: np = index(np, '(') + 1;
322: d1 = myatol(np);
323: np = index(np, ',');
324: if (np != NULL) {
325: d2 = myatol(np + 1);
326: np = index(np, ')');
327: } else
328: d2 = 0;
329: pl[i].p_rval = makedev(d1, d2);
330: pl[i].p_type = 's';
331: if (np == NULL)
332: np = "";
333: else
334: np += 1;
335: goto tail;
336: } else if (isalpha(*np) || *np == '_') {
337: /* The RHS must be a object symbol. */
338:
339: pl[i].p_rvnp = nl + nnls; /* Allocate another SYMENT. */
340: nl[nnls].n_type = 0xffff; /* Mark as not yet found. */
341:
342: /* Point at offset into 'symbols' for new name. */
343: nl[nnls].n_zeroes = 0;
344: nl[nnls].n_offset = sizeof(long) + sym_len;
345:
346: /* Figure out how big the symbol is by looking for
347: * a non-alphanumeric or _ character.
348: */
349: cp = np;
350: for (n = 0; isalnum(*cp) || *cp == '_'; n += 1) {
351: cp += 1;
352: }
353: /* Now allocate more space for symbol names. */
354: sym_len += n + sizeof('\0');
355: if (NULL == (nsym = realloc(symbols, sym_len))) {
356: /* This assignment is too long; skip it. */
357: sym_len -= n;
358: fprintf(stderr,
359: "Assignment too long; skipping: %s\n", np);
360: return;
361: }
362: symbols = nsym; /* The realloc() worked. */
363: /* Copy the new symbol in place. */
364: cp = &(symbols[sym_len - (n + sizeof('\0'))]);
365: strncpy(cp, np, n);
366: cp[n] = '\0';
367:
368: nnls += 1; /* Move up to next empty SYMENT. */
369: np += n; /* Move on to next token. */
370: }
371:
372:
373: /*
374: * If there is a '+' is has served its purpose by dropping us
375: * out of the for loop above. Ignore it now.
376: */
377: if (*np == '+')
378: np += 1;
379: /* Fetch a possible literal number. */
380: pl[i].p_rval = myatol(np);
381: }
382: tail:
383: return;
384: }
385:
386: /*
387: * Modify the contents of /dev/kmem to match the array of patch
388: * structures pl[]. The argument 'n' is the number of entries in pl[]
389: * that should be processed.
390: */
391: void
392: setkmem(n)
393: int n;
394: {
395: int fdlo, fdhi;
396: register int i;
397: char *symname; /* Name of symbol in LHS being patched. */
398:
399: /* Open up live memory for patching. */
400: if (peek) {
401: if ((fdlo=open("/dev/kmem", O_RDONLY)) < 0) {
402: fprintf(stderr, "Cannot open /dev/kmem for reading.\n");
403: return;
404: }
405: if ((fdhi=open("/dev/kmemhi", O_RDONLY)) < 0) {
406: fprintf(stderr, "Cannot open /dev/kmemhi for reading.\n");
407: return;
408: }
409: } else {
410: if ((fdlo=open("/dev/kmem", O_RDWR)) < 0) {
411: fprintf(stderr, "Cannot open /dev/kmem.\n");
412: return;
413: }
414: if ((fdhi=open("/dev/kmemhi", O_RDWR)) < 0) {
415: fprintf(stderr, "Cannot open /dev/kmemhi.\n");
416: return;
417: }
418: }
419:
420: /* Walk through pl[] blasting the new values into live memory. */
421: for (i = 0; i < n; i += 1) {
422: int seekOffset = pl[i].p_lval;
423: symname = &(symbols[pl[i].p_lvnp->n_offset - sizeof(long)]);
424:
425: if ((seekOffset & 0x80000000) == 0) {
426: if(lseek(fdlo, seekOffset, 0) != -1L) {
427: if (patch(fdlo, &pl[i], "/dev/kmem",
428: symname) < 0)
429: fprintf(stderr,
430: "Write error in /dev/kmem\n");
431: } else
432: fprintf(stderr, "Seek error in /dev/kmem\n");
433: } else {
434: if(lseek(fdhi, seekOffset-0x80000000, 0) != -1L) {
435: if (patch(fdhi, &pl[i], "/dev/kmemhi",
436: symname) < 0)
437: fprintf(stderr,
438: "Write error in /dev/kmemhi\n");
439: } else
440: fprintf(stderr, "Seek error in /dev/kmemhi\n");
441: }
442: }
443: close(fdlo);
444: close(fdhi);
445: }
446:
447:
448: /*
449: * Modify the file attached to descriptor 'fd' to match the single patch
450: * structure 'p'. The file descriptor should already be lseek()'d to
451: * the correct place.
452: * Returns 0 on success, -1 otherwise. errno will be set on error.
453: */
454: int
455: patch(fd, p, file, sym)
456: int fd;
457: PLIST *p;
458: /* These two args are only for information. */
459: char *file; /* Name of the file being patched. */
460: char *sym; /* Name of the LHS symbol being patched. */
461: {
462: register char *bp;
463: register int nc;
464: union {
465: char p_char;
466: short p_short;
467: int p_int;
468: long p_long;
469: } old_val;
470:
471: bp = &p->p_val;
472: switch (p->p_type) {
473: case 'c': nc = sizeof(char); break;
474: case 's': nc = sizeof(short); break;
475: case 'i': nc = sizeof(int); break;
476: case 'l': nc = sizeof(long); break;
477: }
478:
479: if (verbose || peek) {
480: old_val.p_long = 0; /* Zero the whole buffer. */
481:
482: if (read(fd, &old_val, nc) != nc) {
483: fprintf(stderr, "Can't read old value.\n");
484: } else {
485:
486: printf("%s: ", file);
487:
488: if (verbose) printf("old value of ");
489:
490: printf("%s: ", sym);
491: switch (p->p_type) {
492: case 'c': printf("0x%02x", old_val.p_char); break;
493: case 's': printf("0x%04x", old_val.p_short); break;
494: case 'i': printf("0x%08x", old_val.p_int); break;
495: case 'l': printf("0x%08x", old_val.p_long); break;
496: } /* switch */
497:
498: printf("\n");
499:
500: if (!peek) { /* If only peeking, there is no new value. */
501: printf("%s: new value: ", file);
502: switch (p->p_type) {
503: case 'c': printf("0x%02x", p->p_val.p_char);
504: break;
505: case 's': printf("0x%04x", p->p_val.p_short);
506: break;
507: case 'i': printf("0x%08x", p->p_val.p_int);
508: break;
509: case 'l': printf("0x%08x", p->p_val.p_long);
510: break;
511: } /* switch */
512:
513: printf("\n");
514: } /* if (verbose) */
515:
516: /* Go back for the write. */
517: lseek(fd, (long) (-nc), 1);
518: } /* if (read...) */
519:
520: } /* if (verbose || peek) */
521:
522: if (peek) {
523: if (verbose) {
524: printf("Just peeking, no write.\n");
525: }
526: } else if (write(fd, bp, nc) != nc) {
527: return (-1);
528: }
529: return (0);
530: }
531:
532: /**
533: *
534: * long
535: * myatol( s ) -- Ascii to Long integer conversion.
536: * char * s;
537: *
538: * Input: s = pointer to string containing a numeric prefix.
539: *
540: * Action: Parse input string.
541: * Parse optional leading sign character '-'.
542: * Parse optional numeric base specification '0', '0o', and '0x'.
543: * Parse following numeric digits.
544: *
545: * Return: Long integer value.
546: *
547: * Notes: Numeric parsing terminates on first non-digit.
548: */
549: long
550: myatol( s )
551: register char * s;
552: {
553: register int base;
554: register int sign;
555: auto long valu;
556:
557: /*
558: * Check for leading negative sign.
559: */
560: sign = 1;
561: if ( *s == '-' ) {
562: sign = -1;
563: s++;
564: }
565:
566: /*
567: * Check for base specification.
568: */
569: base = 10;
570: if ( *s == '0' ) {
571: switch ( *++s ) {
572: case 'x': base = 16; ++s; break;
573: case 'o': base = 8; ++s; break;
574: default: base = 8;
575: }
576: }
577:
578: for ( valu = 0L; *s != '\0'; s++ ) {
579:
580: /*
581: * Decimal digit.
582: */
583: if ( ('0' <= *s) && (*s <= '9') ) {
584: valu *= base;
585: valu += *s - '0';
586: }
587:
588: /*
589: * Upper case hex digit.
590: */
591: else if ( (base == 16) && ('A' <= *s) && (*s <= 'F') ) {
592: valu *= base;
593: valu += *s - ('A' - 10);
594: }
595:
596: /*
597: * Lower case Hex digit.
598: */
599: else if ( (base == 16) && ('a' <= *s) && (*s <= 'f') ) {
600: valu *= base;
601: valu += *s - ('a' - 10);
602: }
603:
604: /*
605: * Not a digit.
606: */
607: else
608: break;
609: }
610:
611: if ( sign < 0 )
612: valu = -valu;
613:
614: return valu;
615: }
616:
617: /*
618: * Print out an usage message.
619: */
620: void
621: usage(verbose)
622: int verbose;
623: {
624: fprintf(stderr, short_helpmessage);
625: if (verbose) {
626: fprintf(stderr, helpmessage);
627: }
628: exit(1);
629: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.