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