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