|
|
1.1 ! root 1: /* ! 2: * trace2.c ! 3: * ! 4: * The information contained herein is a trade secret of Mark Williams ! 5: * Company, and is confidential information. It is provided under a ! 6: * license agreement, and may be copied or disclosed only under the ! 7: * terms of that agreement. Any reproduction or disclosure of this ! 8: * material without the express written authorization of Mark Williams ! 9: * Company or persuant to the license agreement is unlawful. ! 10: * ! 11: * COHERENT Version 2.3.35 ! 12: * Copyright (c) 1982, 1983, 1984. ! 13: * An unpublished work by Mark Williams Company, Chicago. ! 14: * All rights reserved. ! 15: */ ! 16: ! 17: #include <stdio.h> ! 18: #include <ctype.h> ! 19: #include <errno.h> ! 20: #include <l.out.h> ! 21: #include <sys/ptrace.h> ! 22: #include <sys/timeout.h> ! 23: #include <sys/uproc.h> ! 24: #include <signal.h> ! 25: #include "trace.h" ! 26: #include "i8086.h" ! 27: ! 28: /* ! 29: * Talk to the user and try to solve his problems. ! 30: */ ! 31: process() ! 32: { ! 33: register BPT *bp; ! 34: /* register */ int n; ! 35: register int nibflag; ! 36: register int bptflag; ! 37: register caddr_t pc; ! 38: register caddr_t fp; ! 39: register int f; ! 40: ! 41: int pcmd; ! 42: char ans[10]; ! 43: ! 44: /* ! 45: * Reverse-engineered pseudocode, minus global variable garbage. ! 46: * ! 47: * forever: ! 48: * execute(":x\n") <= Preload interpreter stack. ! 49: * (Will come back after traced process traps, e.g. after ":e".) ! 50: * forever: ! 51: * See if at call instruction. ! 52: * Install breakpoints, except at current instruction. ! 53: * See if current instruction is a breakpoint opcode. ! 54: * Start up traced process, full speed or single step. ! 55: * Report any error from ptrace call. ! 56: * Wait for traced process. ! 57: * Fetch registers and signal received from traced process. ! 58: * Replace breakpoints with instructions. ! 59: * If signal to child was not SIGTRAP ! 60: * display message ! 61: * execute(":f\n:x\n"); ! 62: * continue inner loop ! 63: * Back up instruction pointer to start of the breakpoint. ! 64: * If single stepping ! 65: * Execute single step command string (sinp). ! 66: * If last single step in count ! 67: * execute(":x\n") ! 68: * end forever ! 69: * end forever ! 70: * ! 71: */ ! 72: top: ! 73: bptflag = 0; ! 74: execute(":x\n"); ! 75: for (;;) { ! 76: /* ! 77: * Initialize flags. ! 78: */ ! 79: bitflag = 0; ! 80: nibflag = 0; ! 81: bp = 0; ! 82: ! 83: /* ! 84: * If in single step mode, set up for single step. ! 85: * If in SCONT mode, change to SCSET mode at call instruction. ! 86: */ ! 87: if (sinmode!=SNULL && sinmode!=SWAIT) { ! 88: bitflag = 1; ! 89: if (sinmode == SCONT) ! 90: setcont(); ! 91: } ! 92: ! 93: /* ! 94: * Place all breakpoints. ! 95: */ ! 96: if (reg.valid) ! 97: pc = getpc(); ! 98: ! 99: for (n=NBPT, bp=&bpt[0]; n--; bp++) { ! 100: /* skip unused breakpoints */ ! 101: if (bp->b_flag == 0) ! 102: continue; ! 103: ! 104: /* fetch instruction at breakpoint address */ ! 105: add = bp->b_badd; ! 106: if (getb(ISEG, bp->b_bins, sizeof(BIN)) == 0) { ! 107: printb(bp->b_badd); ! 108: goto err; ! 109: } ! 110: ! 111: /* don't install breakpoint at current instruction */ ! 112: if (reg.valid && bptflag && bp->b_badd==pc) { ! 113: bitflag = 1; ! 114: continue; ! 115: } ! 116: ! 117: /* put in a breakpoint */ ! 118: add = bp->b_badd; ! 119: fprintf(stderr, "replacing breakpoint at eip=%x\n", add); ! 120: if (putb(ISEG, bin, sizeof(BIN)) == 0) { ! 121: printb(bp->b_badd); ! 122: goto err; ! 123: } ! 124: } ! 125: bptflag = 0; ! 126: ! 127: /* ! 128: * Set flags and call machine dependent restore routine. ! 129: * Set "nibflag" if instruction at EIP is BRK. ! 130: */ ! 131: if (reg.valid && testbpt(pc)) ! 132: nibflag = 1; ! 133: ! 134: /* ! 135: * restret() looks at bitflag and returns 1 if bitflag set. ! 136: * This is bogus. ! 137: * Mainly, restret() undoes the current breakpoint ! 138: * if it is done at a system call. ! 139: * This is probably unnecessary. ! 140: */ ! 141: #if 0 ! 142: if (restret() == 0) ! 143: goto err; ! 144: #endif ! 145: ! 146: /* ! 147: * Start up the child. ! 148: */ ! 149: errno = 0; ! 150: switch (sinmode) { ! 151: case SNULL: ! 152: case SWAIT: ! 153: pcmd = PTRACE_RESUME; ! 154: break; ! 155: case SCSET: ! 156: case SCONT: ! 157: case SSTEP: ! 158: pcmd = PTRACE_SSTEP; ! 159: break; ! 160: } ! 161: ptrace(pcmd, pid, 1, 0); ! 162: if (errno) { ! 163: perror("ptrace"); ! 164: goto err; ! 165: } ! 166: if (waitc() == 0) ! 167: goto err; ! 168: ! 169: #if 0 ! 170: /* whatever this is, it looks unnecessary. */ ! 171: if (trapint() == 0) ! 172: goto err; ! 173: #endif ! 174: ! 175: /* ! 176: * Copy registers into ureg, and thence to r. ! 177: * Why are there two register sets? I don't know - hws ! 178: */ ! 179: if (setregs() == 0) ! 180: goto err; ! 181: ! 182: /* ! 183: * Set f to the signal number sent to the traced process ! 184: * and global "trapstr" to its name. ! 185: */ ! 186: if ((f=settrap()) == 0) ! 187: goto err; ! 188: ! 189: /* ! 190: * Replace breakpoints with instructions. ! 191: */ ! 192: fprintf(stderr, "Replace breakpoints with instructions\n"); ! 193: for (n=NBPT, bp=bpt; n--; bp++) { ! 194: if (bp->b_flag == 0) ! 195: continue; ! 196: add = bp->b_badd; ! 197: if (putb(ISEG, bp->b_bins, sizeof(BIN)) == 0) { ! 198: printb(bp->b_badd); ! 199: goto err; ! 200: } ! 201: } ! 202: ! 203: /* ! 204: * If latest signal to traced process was not SIGTRAP, ! 205: * tell the user, then accept input. ! 206: */ ! 207: if (f != SIGTRAP) { ! 208: fprintf(stderr, ! 209: "Traced process did not stop at a breakpoint\n"); ! 210: execute(":f\n:x\n"); ! 211: continue; ! 212: } ! 213: ! 214: /* ! 215: * Find the breakpoint we are at. ! 216: * Back up pc to start of the breakpoint. ! 217: */ ! 218: bp = 0; ! 219: pc = getpc() - sizeof(BIN); ! 220: if (bitflag==0 || nibflag) { ! 221: for (n=NBPT, bp=&bpt[0]; n--; bp++) { ! 222: if (bp->b_flag == 0) ! 223: continue; ! 224: if (bp->b_badd != pc) ! 225: continue; ! 226: fprintf(stderr, "found bp at %x\n", pc); ! 227: setpc((caddr_t)pc); ! 228: bptflag = 1; ! 229: break; ! 230: } ! 231: if (bp==&bpt[NBPT]) { ! 232: bp = 0; ! 233: } ! 234: } ! 235: ! 236: /* ! 237: * If in single step mode, execute command. ! 238: */ ! 239: switch (sinmode) { ! 240: case SCSET: ! 241: fprintf(stderr, "sinmode=SCSET\n"); ! 242: break; ! 243: case SNULL: ! 244: fprintf(stderr, "sinmode=SNULL\n"); ! 245: break; ! 246: case SWAIT: ! 247: fprintf(stderr, "sinmode=SWAIT\n"); ! 248: break; ! 249: case SCONT: ! 250: fprintf(stderr, "sinmode=SCONT\n"); ! 251: break; ! 252: case SSTEP: ! 253: fprintf(stderr, "sinmode=SSTEP\n"); ! 254: break; ! 255: } ! 256: switch (sinmode) { ! 257: case SSTEP: ! 258: case SCONT: ! 259: execute(sinp); ! 260: if (--sindecr == 0) ! 261: execute(":x\n"); ! 262: continue; ! 263: case SCSET: ! 264: for (n=0; n<NBPT; n++) ! 265: bpt[n].b_flag &= ~BSIN; ! 266: sinmode = SWAIT; ! 267: /* put a BSIN breakpoint at the return address */ ! 268: intcont(); ! 269: break; ! 270: } ! 271: ! 272: /* ! 273: * If we got an unexpected trace trap or unknown ! 274: * breakpoint, we handle it here. ! 275: */ ! 276: if (bp == NULL) { ! 277: if (bitflag==0 || nibflag) { ! 278: fprintf(stderr, ! 279: "Unexpected trace trap or breakpoint\n"); ! 280: execute(":f\n:x\n"); ! 281: } ! 282: continue; ! 283: } ! 284: ! 285: /* ! 286: * Single step breakpoints have highest priority. ! 287: */ ! 288: fp = getfp(); ! 289: if (bp->b_flag & BSIN) { ! 290: if (bp->b_sfpt==0 || bp->b_sfpt==fp) { ! 291: bp->b_flag &= ~BSIN; ! 292: if (sinmode == SWAIT) { ! 293: fprintf(stderr, "SCWAIT->SCONT??\n"); ! 294: sinmode = SCONT; ! 295: execute(sinp); ! 296: if (--sindecr == 0) ! 297: execute(":x\n"); ! 298: continue; ! 299: } ! 300: } ! 301: } ! 302: ! 303: /* ! 304: * Return breakpoints are next. ! 305: */ ! 306: if (bp->b_flag & BRET) { ! 307: if (fp == bp->b_rfpt) { ! 308: bp->b_flag &= ~BRET; ! 309: execute(bp->b_rcom); ! 310: continue; ! 311: } ! 312: } ! 313: ! 314: /* ! 315: * Your conventional everyday ordinary breakpoint. ! 316: */ ! 317: if (bp->b_flag & BBPT) { ! 318: execute(bp->b_bcom); ! 319: continue; ! 320: } ! 321: } ! 322: ! 323: /* ! 324: * Something is terribly wrong. Kill off our child, ! 325: * and generally reset everything to the start. ! 326: */ ! 327: err: ! 328: killc(); ! 329: reslout(); ! 330: bptinit(); ! 331: goto top; ! 332: } ! 333: ! 334: /* ! 335: * Given a command line in `miscbuf', parse the command line, kill the ! 336: * current child and start up a new one. 0 is returned on success, 1 ! 337: * on failure. ! 338: */ ! 339: runfile() ! 340: { ! 341: register char *bp, *cp; ! 342: register int c; ! 343: char *ifn, *ofn, *argl[ARGSIZE]; ! 344: int qflag, aflag, n; ! 345: ! 346: killc(); ! 347: if (objflag == 0) { ! 348: printe("No executable"); ! 349: return 1; ! 350: } ! 351: ifn = NULL; ! 352: ofn = NULL; ! 353: qflag = 0; ! 354: aflag = 0; ! 355: n = 0; ! 356: bp = miscbuf; ! 357: cp = miscbuf; ! 358: c = *bp++; ! 359: while (c != '\n') { ! 360: switch (c) { ! 361: case '<': ! 362: ifn = cp; ! 363: c = *bp++; ! 364: break; ! 365: case '>': ! 366: ofn = cp; ! 367: if ((c=*bp++) == '>') { ! 368: aflag = 1; ! 369: c = *bp++; ! 370: } ! 371: break; ! 372: default: ! 373: if (n >= ARGSIZE-1) { ! 374: printe("Too many arguments"); ! 375: return 1; ! 376: } ! 377: argl[n++] = cp; ! 378: } ! 379: while (qflag || !isascii(c) || !isspace(c)) { ! 380: if (c == '\n') ! 381: break; ! 382: if (c == '"') { ! 383: qflag ^= 1; ! 384: c = *bp++; ! 385: continue; ! 386: } ! 387: if (c == '\\') { ! 388: if ((c=*bp++) == '\n') { ! 389: printe("Syntax error"); ! 390: return 1; ! 391: } ! 392: } ! 393: *cp++ = c; ! 394: c = *bp++; ! 395: } ! 396: if (qflag) { ! 397: printe("Missing \""); ! 398: return 1; ! 399: } ! 400: *cp++ = '\0'; ! 401: if (c == '\n') ! 402: break; ! 403: while (isascii(c) && isspace(c)) ! 404: c = *bp++; ! 405: } ! 406: if (n == 0) ! 407: argl[n++] = lfn; ! 408: argl[n] = NULL; ! 409: if (startup(argl, ifn, ofn, aflag) == 0) ! 410: return 1; ! 411: return 0; ! 412: } ! 413: ! 414: /* ! 415: * Start execution of the child. `argv' is the argument list, `ifnp' is ! 416: * the name of the input file, `ofnp' is the name of the output file and ! 417: * `appf' tells us whether the output file is opened for append or write. ! 418: */ ! 419: startup(argv, ifnp, ofnp, appf) ! 420: char **argv; ! 421: char *ifnp; ! 422: char *ofnp; ! 423: { ! 424: register int n; ! 425: ! 426: if ((pid=fork()) < 0) { ! 427: printr("Cannot fork"); ! 428: return 0; ! 429: } ! 430: if (pid == 0) { ! 431: if (ifnp != NULL) { ! 432: if ((n=open(ifnp, 0)) < 0) ! 433: panic("Cannot open %s", ifnp); ! 434: dup2(n, 0); ! 435: close(n); ! 436: } ! 437: if (ofnp != NULL) { ! 438: n = -1; ! 439: if (appf) { ! 440: if ((n=open(ofnp, 1)) >= 0) ! 441: lseek(n, 0L, 2); ! 442: } ! 443: if (n < 0) { ! 444: if ((n=creat(ofnp, 0644)) < 0) ! 445: panic("%s: cannot create", ofnp); ! 446: } ! 447: dup2(n, 1); ! 448: close(n); ! 449: } ! 450: ptrace(PTRACE_SETUP, 0, NULL, 0); ! 451: execv(lfn, argv); ! 452: exit (1); ! 453: } ! 454: if (waitc() == 0) ! 455: return 0; ! 456: clramap(); ! 457: DSPACE = setsmap(NULL, (off_t)0, (off_t)LI, (off_t)0, ! 458: getp, putp, DSEG); ! 459: ISPACE = setsmap(NULL, (off_t)0, (off_t)LI, (off_t)0, ! 460: getp, putp, ISEG); ! 461: USPACE = setsmap(NULL, (off_t)0, (off_t)UPASIZE, (off_t)0, ! 462: getp, putp, USEG); ! 463: excflag = 1; ! 464: regflag = 1; ! 465: return 1; ! 466: } ! 467: ! 468: /* ! 469: * Given a newly started child, find out necessary information. ! 470: */ ! 471: shiftup() ! 472: { ! 473: if (trapint() == 0) ! 474: return 0; ! 475: if (setregs() == 0) ! 476: return 0; ! 477: return settrap(); ! 478: } ! 479: ! 480: /* ! 481: * Kill off our child. ! 482: */ ! 483: killc() ! 484: { ! 485: if (excflag) { ! 486: ptrace(PTRACE_TERM, pid, 0, 0); ! 487: waitc(); ! 488: } ! 489: excflag = 0; ! 490: regflag = 0; ! 491: trapstr = NULL; ! 492: reg.valid = 0; ! 493: } ! 494: ! 495: /* ! 496: * Wait for the traced process to stop. ! 497: */ ! 498: waitc() ! 499: { ! 500: register int p; ! 501: int s; ! 502: extern errno; ! 503: ! 504: while ((p=wait(&s)) != pid) { ! 505: if (p >= 0) { ! 506: printr("Adopted a child %d", p); ! 507: continue; ! 508: } ! 509: if (intflag == 0) { ! 510: excflag = 0; ! 511: printr("Nonexistent child"); ! 512: return 0; ! 513: } ! 514: intflag = 0; ! 515: } ! 516: if ((s&0xff) != 0x7f) { ! 517: excflag = 0; ! 518: printr("Child process terminated (%x)", (s>>8)&0xff ); ! 519: return 0; ! 520: } ! 521: return 1; ! 522: } ! 523: ! 524: ! 525: /****************************************************************************** ! 526: * ! 527: * Note some #defines in these include files interferes with ! 528: * items in preceeding include files. Hence the strange ! 529: * program order. ! 530: * ! 531: ******************************************************************************/ ! 532: ! 533: #include <coff.h> ! 534: ! 535: /* ! 536: * Reset segmentation for an coff or l.out format. ! 537: */ ! 538: reslout() ! 539: { ! 540: FILEHDR coffh; ! 541: struct ldheader ldh; ! 542: ! 543: clramap(); ! 544: objflag = 0; ! 545: ! 546: fseek(lfp, (long)0, 0); ! 547: if (fread(&coffh, sizeof(coffh), 1, lfp) != 1) { ! 548: printr("Can't read object file"); ! 549: return 0; ! 550: } ! 551: ! 552: if (coffh.f_magic == C_386_MAGIC) { ! 553: #if 0 ! 554: /* get entry point from optional coff header */ ! 555: struct aouthdr opth; ! 556: ! 557: reg.r_ip = 0xA8; ! 558: if (coffh.f_opthdr >= sizeof(struct aouthdr)) { ! 559: if (fread(&opth, sizeof(struct aouthdr), 1, lfp) == 1) ! 560: reg.r_ip = opth.entry; ! 561: } ! 562: #endif ! 563: objflag = 1; ! 564: setcoffseg(lfp, &coffh); ! 565: return 1; ! 566: } else { ! 567: fseek(lfp, (long)0, 0); ! 568: if (fread(&ldh, sizeof(ldh), 1, lfp) != 1) { ! 569: printr("Can't read object file"); ! 570: return 0; ! 571: } ! 572: canlout(&ldh); ! 573: if (ldh.l_magic != L_MAGIC) { ! 574: printr("not an object file"); ! 575: return 0; ! 576: } ! 577: objflag = 1; ! 578: setaseg(&ldh); ! 579: return 1; ! 580: } ! 581: } ! 582: ! 583: /* end of trace2.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.