|
|
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.