|
|
1.1 root 1: static char sccsid[] = "@(#)single.c 2.8";
2:
3: #include "cdb.h"
4:
5:
6: extern char vsbArgsChild[]; /* defined in pt.c */
7:
8: export int vcBadMax; /* most instructions we single step without symbols */
9:
10: typedef struct { /* the assertion descriptor */
11: char *sbCheck; /* points to command list for this check */
12: ASE as; /* state of THIS assertion check */
13: }
14: ADR, *pADR;
15: #define cbADR sizeof(ADR)
16:
17: pADR vrgAd; /* the list of assertions */
18: ADRT vpcLast;
19: export int viadMac, viadMax;
20: export FLAGT vfRunAssert; /* see IbpFNewChild */
21: export ASE vas; /* state of the assertions as a whole */
22:
23:
24:
25: /* A D R F S T A C K F I X */
26:
27: export ADRT AdrFStackFix(adr)
28: ADRT adr;
29: {
30: /* given an address immediately after a procedure call, step over any
31: * stack fix-up instructions
32: */
33: #ifdef ONYX
34: int inst;
35: #define INCR15_INST 0xa900
36: inst = GetWord(adr, spaceText);
37: if ((inst & 0xff00) == INCR15_INST)
38: adr += 2;
39: #endif
40: #ifdef TAHOE
41: /* TAHOE has no stack fix stuff, it's all done by the callee */
42: #endif
43: #ifdef VAX
44: /* vax has no stack fix stuff, it's all done by the callee */
45: #endif
46: #ifdef M68000
47: short inst;
48:
49: #define TST_INST 0x4a5f
50: #define TSTL_INST 0x4a9f
51: #define CMPML_INST 0xbf8f
52: #define ADDW_INST 0xdefc
53: #define ADDQ_INST 0x500f
54: #define ADDN_INST 0x504f
55:
56: GetBlock(adr, spaceText, &inst, 2);
57: if ( (inst == TST_INST)
58: OR (inst == TSTL_INST)
59: OR (inst == CMPML_INST)
60: OR ((inst & 0xf13f) == ADDQ_INST))
61: adr += 2;
62: else if ((inst & 0xf1ff) == ADDN_INST)
63: adr += 4;
64: #endif
65: return(adr);
66: } /* AdrFStackFix */
67:
68:
69: /* A D R F P R E A M B L E */
70:
71: local ADRT AdrFPreamble(adr)
72: ADRT adr;
73: {
74: /* given the first address in a procedure, return the address of the
75: * first `real' instruction - ie. after the csav0 or the brb whatever
76: */
77: #ifdef ONYX
78: int inst;
79:
80: #define LDK_INST 0xbd00
81: #define LD_INST 0x2100
82: inst = GetWord(adr, spaceText) & 0xff00; /* high byte of 1st instruction */
83: /* we want to skip over stack set up stuff */
84: adr += (inst == LDK_INST) ? 6 : (inst == LD_INST) ? 8 : 4;
85: #endif
86: #ifdef TAHOE
87: int inst, specifier;
88:
89: #define BRB_INST 0x11 /* Guess they are the only ones after mask */
90: #define BRW_INST 0x13
91: #define JMP_INST 0x71
92: #define SUBL3_INST 0x3c
93: inst = GetByte(adr, spaceText) & 0xff; /* instruction */
94: specifier = GetByte((char *)adr + 1, spaceText) & 0xff; /* operand spec */
95: /* we want to skip over stack set up stuff */
96: switch (inst) {
97: case BRB_INST:
98: adr += 2;
99: break;
100: case BRW_INST:
101: adr += 3;
102: break;
103: case JMP_INST:
104: adr += 6;
105: break;
106: case SUBL3_INST:
107: if (specifier <= 63) adr += 4 ;
108: else switch (specifier) {
109: case 0x88:
110: adr += 5;
111: break;
112: case 0x89:
113: adr += 6;
114: break;
115: case 0x8f:
116: adr += 8;
117: break;
118: }
119: break;
120: default:
121: printf("CDB problem - unexpected instruction (0x%0x) at procedure begining\n", inst);
122: }
123: #endif
124:
125: #ifdef VAX
126: int inst;
127:
128: #define BRB_INST 0x11
129: #define BRW_INST 0x31
130: #define JMP_INST 0x17
131: #define SUBL2_INST 0xc2
132: inst = GetByte(adr, spaceText) & 0xff; /* instruction */
133: /* we want to skip over stack set up stuff */
134: if (inst == BRB_INST)
135: adr += 2;
136: else if (inst == BRW_INST)
137: adr += 3;
138: else if (inst == SUBL2_INST)
139: adr += 7;
140: else
141: adr += 4;
142: #endif
143: #ifdef M68000
144: int ipd, iln, ifd, slop;
145:
146: ipd = IpdFAdr(adr);
147: if (ipd != ipdNil) {
148: IfdLnFAdr(adr, vrgPd[ipd].isym+1, &ifd, &iln, &slop);
149: #ifdef SUN
150: iln++; /* first line number is connected with preamble */
151: #endif
152: adr = AdrFIfdLn(ifd, iln);
153: } /* if */
154: #endif
155: return(adr);
156: } /* AdrFPreamble */
157:
158:
159: /* F A T C A L L */
160:
161: local FLAGT FAtCall(adr)
162: ADRT adr;
163: {
164: short inst;
165: /* return true or false based on whether the instruction at adr
166: * is a procedure call of any kind.
167: */
168: inst = 0;
169: #ifdef ONYX
170: #define CALL_INST 0x5f00
171: #define cbInsMax 2
172: GetBlock(adr, spaceText, (ADRT)&inst, cbInsMax);
173: return(inst == CALL_INST);
174: #endif
175:
176: #ifdef TAHOE
177: #define CALLS_INST 0xbf
178: #define CALLG_INST 0xfe
179: GetBlock(adr, spaceText, ((char *)&inst)+1, 1);
180: return((inst == CALLS_INST) OR (inst == CALLG_INST));
181: #endif
182:
183: #ifdef VAX
184: #define CALLS_INST 0xfb /* arguments are on the stack */
185: #define CALLG_INST 0xfa /* arguments are elsewhere */
186: GetBlock(adr, spaceText, &inst, 1);
187: return((inst == CALLS_INST) OR (inst == CALLG_INST));
188: #endif
189:
190: #ifdef M68000
191: #define JSR_INST 0x4e80
192: #define BSR_INST 0x6100
193: #define cbInsMax 2
194:
195: GetBlock(adr, spaceText, (ADRT)&inst, cbInsMax);
196: return(((inst & 0xff00) == BSR_INST) OR ((inst & 0xffc0) == JSR_INST));
197: #endif
198: } /* FAtCall */
199:
200:
201: /* R E T F S P */
202:
203: local ADRT RetFSp(sp)
204: ADRT sp;
205: {
206: /* given the stack pointer immediately after a procedure call,
207: * return the return address
208: */
209: #ifdef TAHOE
210: /* We know that the argument here is realy 'fp', not 'sp'. */
211: return(GetWord(sp-8, spaceData)); /* get return */
212: #endif
213: #ifdef VAX
214: return(GetWord(sp+16, spaceData)); /* get return */
215: #endif
216: #ifdef ONYX
217: return(GetWord(sp, spaceData)); /* get return */
218: #endif
219: #ifdef M68000
220: return(GetWord(sp, spaceData)); /* get return */
221: #endif
222: } /* RetFSp */
223:
224:
225: /* R E T F F P */
226:
227: local ADRT RetFFp(fp)
228: ADRT fp;
229: {
230: ADRT ap, pc;
231: /* given a frame pointer, return the return address */
232: NextFrame(&fp, &ap, &pc);
233: return(pc); /* get return */
234: } /* RetFFp */
235:
236:
237: /* I B P F S I N G L E */
238:
239: export int IbpFSingle(fBigStep, fQuiet)
240: FLAGT fBigStep, fQuiet;
241: {
242: int cBad, ibp, ifd, ln, slop;
243: ADRT adr;
244:
245: if (vpid == pidNil) {
246: /* we have no process, create one! */
247: IbpFNewChild(vsbArgsChild);
248: PrintPos(vpc, (fQuiet) ? fmtNil : fmtProc+fmtLn+fmtPrint);
249: return(vibp);
250: } /* if */
251:
252: /* the idea here is to loop until we get someplace interesting. This
253: * usually means at an address that translates EXACTLY (slop == 0) to
254: * a known line number.
255: */
256: cBad = 0; /* to count instructions in the twilight zone */
257: slop = -1; /* just to get us into loop first time */
258: while (slop != 0) {
259: ibp = ibpNil;
260: if (FAtCall(vpc)) { /* at proc call */
261: /* follow the call - this way we don't have to deal with N ways
262: * to compute callee's address.
263: */
264: ibp = IbpFRun(ptSingle);
265: if (ibp != ibpNil)
266: return(ibp); /* a REAL breakpoint */
267: if (!fBigStep) {
268: if (IpdFAdr(vpc) != ipdNil) {
269: adr = AdrFPreamble(vpc); /* allows for intro code */
270: ibp = IbpFAdr(adr, 0, sbNil); /* temp BP after intro */
271: ibp = IbpFRun(ptResume);
272: break; /* go to the stuff at end of this procedure */
273: } /* if */
274: /* if we get here, then the proc call goes to the
275: * twilight zone - fall into fBigStep code
276: */
277: } /* if */
278: #ifdef TAHOE
279: adr = AdrFStackFix(RetFSp(vfp));
280: #else
281: adr = AdrFStackFix(RetFSp(vsp));
282: #endif
283: ibp = IbpFAdr(adr, 0, sbNil); /* temp BP at return */
284: ibp = IbpFRun(ptResume);
285: }
286: else { /* NOT at a procedure call */
287: if ((ibp = IbpFRun(ptSingle)) != ibpNil)
288: return(ibp); /* a REAL breakpoint, so it MUST be kosher! */
289: if (IpdFAdr(vpc) != ipdNil) {
290: cBad = 0;
291: }
292: else {
293: /* we are in a file without good symbols */
294: /* KLUDGE! There is a problem here.
295: * Some trips to boony land are short, like the switch code
296: * for Onyx, some are MUCH longer, like the printf code.
297: * What we do is go along with the joke for up to
298: * vcBadMax `bad' instructions. If we don't see daylight, we
299: * set an up level break from the (hopefully good) return
300: * address. There are NO GUARANTEES that this is correct,
301: * but it seems to work MOST of the time.
302: */
303: if (++cBad >= vcBadMax) {
304: /* set uplevel break and wait for it to come home */
305: adr = RetFFp(vfp); /* get return */
306: ibp = IbpFAdr(adr, 0, sbNil);
307: ibp = IbpFRun(ptResume);
308: } /* if */
309: slop = -1;
310: } /* if */
311: } /* if */
312: if ( (ibp != ibpNil) OR (vpid == pidNil) )
313: return(ibp);
314: if (cBad == 0)
315: IfdLnFAdr(vpc, isym0, &ifd, &ln, &slop);
316: } /* while */
317:
318: if ((vpid != pidNil) AND (ibp == ibpNil))
319: PrintPos(vpc, (fQuiet) ? fmtNil : fmtProc+fmtLn+fmtPrint);
320: return(ibp);
321: } /* IbpFSingle */
322:
323:
324: /* these routines maintain the list of assertions.
325: * since the presence of even ONE assertion forces the
326: * child process to singlestep, they should only be used
327: * when your back is against the wall e.g. someone is stepping
328: * on a global and you don't know who!
329: */
330:
331:
332: /* I N I T A S S E R T */
333:
334: export void InitAssert()
335: {
336: viadMac = 0;
337: vrgAd = (pADR) malloc(viadMax * cbADR);
338: vcbTot += viadMax * cbADR;
339: vas = asActive;
340: } /* InitAssert */
341:
342:
343: /* L I S T A S S E R T */
344:
345: export void ListAssert()
346: {
347: int i;
348:
349: if (viadMac == 0)
350: UError("No assertions");
351: printf("Assertions in general are %s\n\n",
352: (vas == asActive) ? "ACTIVE" : "SUSPENDED");
353: for (i=0; i < viadMac; i++) {
354: printf("%2d: %s %s\n", i,
355: (vrgAd[i].as==asActive) ? "Active" : "Suspended", vrgAd[i].sbCheck);
356: } /* for */
357: } /* ListAssert */
358:
359:
360: /* A D D A S S E R T */
361:
362: export void AddAssert(sbCheck)
363: char *sbCheck;
364: {
365: int cb, iad;
366:
367: if (viadMac >= viadMax)
368: UError("Too many assertions");
369: iad = viadMac++;
370: cb = strlen(sbCheck);
371: vrgAd[iad].sbCheck = malloc(cb+1); /* room for null */
372: vcbTot += cb + 1;
373: strcpy(vrgAd[iad].sbCheck, sbCheck);
374: vrgAd[iad].sbCheck[cb] = chNull;
375: vrgAd[iad].as = asActive;
376: printf("Assertion %d: Active \"%s\"\n", iad, vrgAd[iad].sbCheck);
377: vas = asActive;
378: printf("Assertions are ACTIVE");
379: } /* AddAssert */
380:
381:
382: /* M O D A S S E R T */
383:
384: export void ModAssert(iad, as)
385: int iad;
386: ASE as;
387: {
388: if (iad < 0 OR iad >= viadMac)
389: UError("Bad assertion number: %d", iad);
390: vrgAd[iad].as = as;
391: if (as == asNil) {
392: free(vrgAd[iad].sbCheck);
393: vrgAd[iad] = vrgAd[viadMac-1]; /* fold it back on itself */
394: viadMac--;
395: }
396: if (vas == asSuspended)
397: return;
398: for (iad = 0; iad < viadMac; iad++)
399: if (vrgAd[iad].as == asActive)
400: return;
401: printf("Assertions are ACTIVE");
402: vas = asSuspended;
403: } /* ModAssert */
404:
405:
406: /* F D O A S S E R T */
407:
408: export void FDoAssert(pt)
409: int pt;
410: {
411: int iad;
412: long cnt;
413:
414: vfRunAssert = false; /* so we are not recursive entered from IbpFRun */
415: PushCmd(vsbCmd); /* save what we are doing */
416: for (cnt=(pt==ptSingle) ? 1 : -1;cnt != 0; --cnt) {
417: /* we do the assertions BEFORE the line is executed */
418: for(iad=0; iad < viadMac; iad++) {
419: if ((vrgAd[iad].as == asActive)
420: AND (FDoCommand(vrgAd[iad].sbCheck, false))) {
421: /* we hit an 'x' (exit) command - stop the parade! */
422: printf("\nHit on assertion %d: \"%s\"\n",
423: iad, vrgAd[iad].sbCheck);
424: printf("Last line executed was:\n");
425: PrintPos(vpcLast, fmtFile+fmtProc+fmtLn+fmtPrint+fmtSave);
426: printf("Next line to execute is:\n");
427: PrintPos(vpc, fmtFile+fmtProc+fmtLn+fmtPrint);
428: vfRunAssert = true;
429: return(true);
430: } /* if */
431: } /* for */
432: vpcLast = vpc; /* remember where the current line is */
433: /* step the process one statement's worth */
434: if (ibpNil != IbpFSingle(false, true)) {
435: vfRunAssert = true;
436: return(false);
437: } /* if */
438: } /* for */
439: PrintPos(vpc, fmtNil); /* restore our context */
440: vfRunAssert = true;
441: return(false);
442: } /* FDoAssert */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.