|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1993 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: walk.c ! 8: ! 9: Abstract: ! 10: ! 11: This file provides support for stack walking. ! 12: ! 13: Author: ! 14: ! 15: Miche Baker-Harvey (v-michbh) 1-May-1993 (ported from ntsd) ! 16: ! 17: Environment: ! 18: ! 19: User Mode ! 20: ! 21: --*/ ! 22: ! 23: #include <windows.h> ! 24: ! 25: #include <stdlib.h> ! 26: #include <stdio.h> ! 27: #include <string.h> ! 28: ! 29: #include "drwatson.h" ! 30: #include "proto.h" ! 31: ! 32: #include <alphaops.h> ! 33: #include "disasm.h" ! 34: ! 35: DWORD VirtualUnwind (PDEBUGPACKET, DWORD, PRUNTIME_FUNCTION, PCONTEXT); ! 36: ! 37: ALPHA_INSTRUCTION disinstr; ! 38: ! 39: #define DPRINT(a,b) ! 40: ! 41: BOOL ! 42: StackWalkInit( PSTACKWALK pstk, ! 43: PDEBUGPACKET dp) ! 44: { ! 45: pstk->pc = dp->tctx->context.Fir; ! 46: pstk->frame = dp->tctx->context.IntSp; ! 47: pstk->params[0] = dp->tctx->context.IntA0; ! 48: pstk->params[1] = dp->tctx->context.IntA1; ! 49: pstk->params[2] = dp->tctx->context.IntA2; ! 50: pstk->params[3] = dp->tctx->context.IntA3; ! 51: ! 52: return TRUE; ! 53: } /* ProcessStackWalkInitCmd() */ ! 54: ! 55: BOOL ! 56: StackWalkNext( PSTACKWALK pstk, ! 57: PDEBUGPACKET dp) ! 58: { ! 59: DWORD fir; ! 60: LONG begin=0, end, test; ! 61: PRUNTIME_FUNCTION rf; ! 62: CONTEXT context; ! 63: DWORD dwRa; ! 64: DWORD cb; ! 65: PMODULEINFO mi; ! 66: ! 67: fir = pstk->pc; ! 68: ! 69: mi = GetModuleForPC( dp, fir ); ! 70: if (mi == NULL) { ! 71: return FALSE; ! 72: } ! 73: ! 74: // ! 75: // Do a binary search to determine which function contains this FIR ! 76: // ! 77: ! 78: ! 79: for(end=mi->dwEntries,test=(begin+end)/2; begin<=end; test=(begin+end)/2) { ! 80: if (fir<mi->pExceptionData[test].BeginAddress) { ! 81: end = test-1; ! 82: } ! 83: else ! 84: if (fir>=mi->pExceptionData[test].EndAddress) { ! 85: begin = test+1; ! 86: } ! 87: else { ! 88: break; ! 89: } ! 90: } ! 91: ! 92: // ! 93: // No function was found to include this FIR ! 94: // Therefore this is a leaf function ! 95: // ! 96: ! 97: if (begin>end) { ! 98: dp->tctx->stackBase = dp->tctx->context.IntSp; ! 99: dp->tctx->stackRA = dp->tctx->context.IntRa; ! 100: ! 101: pstk->frame = dp->tctx->context.IntSp; ! 102: pstk->pc = dp->tctx->context.IntRa; ! 103: // ! 104: // MBH - bugbug ! 105: // This is hopeless: the arguments aren't normally homed on ALPHA ! 106: // ! 107: if (!ReadProcessMemory( dp->hProcess, ! 108: (LPVOID)pstk->frame, ! 109: (LPVOID)pstk->params, ! 110: 12, ! 111: NULL ! 112: )) { ! 113: pstk->params[0] = ! 114: pstk->params[1] = ! 115: pstk->params[2] = 0; ! 116: } ! 117: return TRUE; ! 118: ! 119: } ! 120: ! 121: ! 122: // ! 123: // Virtually unwind the stack to determine base and caller ! 124: // ! 125: ! 126: context = dp->tctx->context; ! 127: context.IntSp = pstk->frame; ! 128: ! 129: dwRa = VirtualUnwind(dp, fir, &mi->pExceptionData[test], &context); ! 130: ! 131: // ! 132: // The Ra value coming out of mainCRTStartup is set by some RTL ! 133: // routines to be "1"; return out of mainCRTStartup is actually ! 134: // done through Jump/Unwind, so this serves to cause an error if ! 135: // someone actually does a return. That's why we check here for ! 136: // dwRa == 1 - this happens when in the frame for CRTStartup. ! 137: // ! 138: // We test for (1-4) because on ALPHA, the value returned by ! 139: // VirtualUnwind is the value to be passed to the next call to ! 140: // VirtualUnwind, which is NOT the same as the Ra - it's sometimes ! 141: // decremented by four - this gives the faulting instruction - ! 142: // in particular, we want the fault instruction so we can get the ! 143: // correct scope in the case of an exception. ! 144: // ! 145: ! 146: if (((dp->tctx->stackBase == context.IntSp) && (dwRa == dp->tctx->stackRA)) || ! 147: (dwRa == (1) ) || ! 148: (dwRa == (1-4) ) || ! 149: (dwRa == 0) ) { ! 150: return FALSE; ! 151: ! 152: } ! 153: ! 154: dp->tctx->stackBase = context.IntSp; ! 155: dp->tctx->stackRA = dwRa; ! 156: ! 157: pstk->frame = context.IntSp; ! 158: pstk->pc = dwRa; ! 159: ! 160: if (!ReadProcessMemory( dp->hProcess, ! 161: (LPVOID)pstk->frame, ! 162: (LPVOID)pstk->params, ! 163: 12, ! 164: NULL ! 165: )) { ! 166: pstk->params[0] = ! 167: pstk->params[1] = ! 168: pstk->params[2] = 0; ! 169: } ! 170: ! 171: return TRUE; ! 172: } ! 173: ! 174: // ! 175: // MBH - beginning of new VirtualUnwind code ! 176: ! 177: ! 178: ! 179: #ifdef DBG ! 180: ! 181: ULONG RtlDebugFlags = 0; ! 182: #define RTL_DBG_VIRTUAL_UNWIND 1 ! 183: #define RTL_DBG_VIRTUAL_UNWIND_DETAIL 2 ! 184: ! 185: // ! 186: // Define an array of symbolic names for the integer registers. ! 187: // ! 188: ! 189: PCHAR RtlpIntegerRegisterNames[32] = { ! 190: "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", // 0 - 7 ! 191: "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp", // 8 - 15 ! 192: "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", // 16 - 23 ! 193: "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero", // 24 - 31 ! 194: }; ! 195: ! 196: // ! 197: // This function disassembles the instruction at the given address. It is ! 198: // only used for debugging and recognizes only those few instructions that ! 199: // are relevant during reverse execution of the prologue by virtual unwind. ! 200: // ! 201: ! 202: VOID ! 203: _RtlpDebugDisassemble ( ! 204: IN ULONG ControlPc, ! 205: IN PCONTEXT ContextRecord ! 206: ) ! 207: { ! 208: UCHAR Comments[50]; ! 209: PULONG FloatingRegister; ! 210: // PUQUAD FloatingRegister; ! 211: ULONG Function; ! 212: ULONG Hint; ! 213: ULONG Literal8; ! 214: ALPHA_INSTRUCTION Instruction; ! 215: // PUQUAD IntegerRegister; ! 216: PULONG IntegerRegister; ! 217: LONG Offset16; ! 218: UCHAR Operands[20]; ! 219: ULONG Opcode; ! 220: PCHAR OpName; ! 221: ULONG Ra; ! 222: ULONG Rb; ! 223: ULONG Rc; ! 224: PCHAR RaName; ! 225: PCHAR RbName; ! 226: PCHAR RcName; ! 227: ! 228: if (RtlDebugFlags & RTL_DBG_VIRTUAL_UNWIND_DETAIL) { ! 229: Instruction.Long = *((PULONG)ControlPc); ! 230: Hint = Instruction.Jump.Hint; ! 231: Literal8 = Instruction.OpLit.Literal; ! 232: Offset16 = Instruction.Memory.MemDisp; ! 233: Opcode = Instruction.Memory.Opcode; ! 234: Ra = Instruction.OpReg.Ra; ! 235: RaName = RtlpIntegerRegisterNames[Ra]; ! 236: Rb = Instruction.OpReg.Rb; ! 237: RbName = RtlpIntegerRegisterNames[Rb]; ! 238: Rc = Instruction.OpReg.Rc; ! 239: RcName = RtlpIntegerRegisterNames[Rc]; ! 240: ! 241: IntegerRegister = &ContextRecord->IntV0; ! 242: FloatingRegister = &ContextRecord->FltF0; ! 243: ! 244: OpName = NULL; ! 245: switch (Opcode) { ! 246: case JMP_OP : ! 247: if (Instruction.Jump.Function == RET_FUNC) { ! 248: OpName = "ret"; ! 249: sprintf(Operands, "%s, (%s), %04lx", RaName, RbName, Hint); ! 250: sprintf(Comments, "%s = %Lx", RbName, IntegerRegister[Rb]); ! 251: } ! 252: break; ! 253: ! 254: case LDAH_OP : ! 255: case LDA_OP : ! 256: case STQ_OP : ! 257: if (Opcode == LDA_OP) { ! 258: OpName = "lda"; ! 259: ! 260: } else if (Opcode == LDAH_OP) { ! 261: OpName = "ldah"; ! 262: ! 263: } else if (Opcode == STQ_OP) { ! 264: OpName = "stq"; ! 265: } ! 266: sprintf(Operands, "%s, $%d(%s)", RaName, Offset16, RbName); ! 267: sprintf(Comments, "%s = %Lx", RaName, IntegerRegister[Ra]); ! 268: break; ! 269: ! 270: case ARITH_OP : ! 271: case BIT_OP : ! 272: Function = Instruction.OpReg.Function; ! 273: if ((Opcode == ARITH_OP) && (Function == ADDQ_FUNC)) { ! 274: OpName = "addq"; ! 275: ! 276: } else if ((Opcode == ARITH_OP) && (Function == SUBQ_FUNC)) { ! 277: OpName = "subq"; ! 278: ! 279: } else if ((Opcode == BIT_OP) && (Function == BIS_FUNC)) { ! 280: OpName = "bis"; ! 281: ! 282: } else { ! 283: break; ! 284: } ! 285: if (Instruction.OpReg.RbvType == RBV_REGISTER_FORMAT) { ! 286: sprintf(Operands, "%s, %s, %s", RaName, RbName, RcName); ! 287: ! 288: } else { ! 289: sprintf(Operands, "%s, $%d, %s", RaName, Literal8, RcName); ! 290: } ! 291: sprintf(Comments, "%s = %Lx", RcName, IntegerRegister[Rc]); ! 292: break; ! 293: ! 294: case FPOP_OP : ! 295: if (Instruction.FpOp.Function == CPYS_FUNC) { ! 296: OpName = "cpys"; ! 297: sprintf(Operands, "f%d, f%d, f%d", Ra, Rb, Rc); ! 298: sprintf(Comments, "f%d = %Lx", Rc, FloatingRegister[Rc]); ! 299: } ! 300: break; ! 301: ! 302: case STT_OP : ! 303: OpName = "stt"; ! 304: sprintf(Operands, "f%d, $%d(%s)", Ra, Offset16, RbName); ! 305: sprintf(Comments, "f%d = %Lx", Ra, FloatingRegister[Ra]); ! 306: break; ! 307: } ! 308: if (OpName == NULL) { ! 309: OpName = "???"; ! 310: sprintf(Operands, "..."); ! 311: sprintf(Comments, "Unknown to virtual unwind."); ! 312: } ! 313: DbgPrint(" %08lx: %08lx %-5s %-16s // %s\n", ! 314: ControlPc, Instruction.Long, OpName, Operands, Comments); ! 315: } ! 316: return; ! 317: } ! 318: ! 319: #define _RtlpFoundTrapFrame(NextPc) \ ! 320: if (RtlDebugFlags & RTL_DBG_VIRTUAL_UNWIND) { \ ! 321: DbgPrint(" *** Looks like a trap frame (fake prologue), Fir = %lx\n", \ ! 322: NextPc); \ ! 323: } ! 324: ! 325: ! 326: #else ! 327: ! 328: #define _RtlpDebugDisassemble(ControlPc, ContextRecord) ! 329: #define _RtlpFoundTrapFrame(NextPc) ! 330: ! 331: #endif ! 332: ! 333: ! 334: /*++ ! 335: ! 336: Routine Description: ! 337: ! 338: Read longword at addr into value. ! 339: ! 340: Arguments: ! 341: ! 342: addr - address at which to read ! 343: value - where to put the result ! 344: ! 345: ! 346: --*/ ! 347: ! 348: BOOLEAN ! 349: LocalDoMemoryRead(PDEBUGPACKET dp, ULONG addr, PULONG pvalue) ! 350: { ! 351: ULONG cb; ! 352: ! 353: if (!ReadProcessMemory(dp->hProcess, ! 354: (LPVOID)addr, ! 355: (LPVOID)pvalue, ! 356: sizeof(*pvalue), ! 357: &cb)) { ! 358: DPRINT(1, ("LocalDoMemoryRead: Can't read at %08x\n", addr)); ! 359: return(FALSE); ! 360: } ! 361: if (cb != sizeof(*pvalue)) { ! 362: DPRINT(1, ("LocalDoMemoryRead: Count wrong at %08x\n", addr)); ! 363: return(FALSE); ! 364: } ! 365: return(TRUE); ! 366: } ! 367: ! 368: // ! 369: // MBH - this value is redefined in windbg common code to be IntSp. ! 370: // ! 371: #define SP_REG 30 ! 372: ! 373: ! 374: DWORD ! 375: VirtualUnwind ( ! 376: PDEBUGPACKET dp, ! 377: DWORD ControlPc, ! 378: PRUNTIME_FUNCTION FunctionEntry, ! 379: PCONTEXT ContextRecord ! 380: ) ! 381: ! 382: /*++ ! 383: ! 384: Routine Description: ! 385: ! 386: This function virtually unwinds the specified function by executing its ! 387: prologue code backwards. Given the current context and the instructions ! 388: that preserve registers in the prologue, it is possible to recreate the ! 389: nonvolatile context at the point the function was called. ! 390: ! 391: If the function is a leaf function, then the address where control left ! 392: the previous frame is obtained from the context record. If the function ! 393: is a nested function, but not an exception or interrupt frame, then the ! 394: prologue code is executed backwards and the address where control left ! 395: the previous frame is obtained from the updated context record. ! 396: ! 397: Otherwise, an exception or interrupt entry to the system is being unwound ! 398: and a specially coded prologue restores the return address twice. Once ! 399: from the fault instruction address and once from the saved return address ! 400: register. The first restore is returned as the function value and the ! 401: second restore is placed in the updated context record. ! 402: ! 403: During the unwind, the virtual and real frame pointers for the function ! 404: are calculated and returned in the given frame pointers structure. ! 405: ! 406: If a context pointers record is specified, then the address where each ! 407: register is restored from is recorded in the appropriate element of the ! 408: context pointers record. ! 409: ! 410: Arguments: ! 411: ! 412: ControlPc - Supplies the address where control left the specified ! 413: function. ! 414: ! 415: FunctionEntry - Supplies the address of the function table entry for the ! 416: specified function. ! 417: ! 418: ContextRecord - Supplies the address of a context record. ! 419: ! 420: ! 421: Return Value: ! 422: ! 423: The address where control left the previous frame is returned as the ! 424: function value. ! 425: ! 426: Implementation Notes: ! 427: ! 428: N.B. "where control left" is not the "return address" of the call in the ! 429: previous frame. For normal frames, NextPc points to the last instruction ! 430: that completed in the previous frame (the JSR/BSR). The difference between ! 431: NextPc and NextPc + 4 (return address) is important for correct behavior ! 432: in boundary cases of exception addresses and scope tables. ! 433: ! 434: For exception and interrupt frames, NextPc is obtained from the trap frame ! 435: contination address (Fir). For faults and synchronous traps, NextPc is both ! 436: the last instruction to execute in the previous frame and the next ! 437: instruction to execute if the function were to return. For asynchronous ! 438: traps, NextPc is the continuation address. It is the responsibility of the ! 439: compiler to insert TRAPB instructions to insure asynchronous traps do not ! 440: occur outside the scope from the instruction(s) that caused them. ! 441: ! 442: N.B. in this and other files where RtlVirtualUnwind is used, the variable ! 443: named NextPc is perhaps more accurately, LastPc - the last PC value in ! 444: the previous frame, or CallPc - the address of the call instruction, or ! 445: ControlPc - the address where control left the previous frame. Instead ! 446: think of NextPc as the next PC to use in another call to virtual unwind. ! 447: ! 448: The Alpha version of virtual unwind is similar in design, but slightly ! 449: more complex than the Mips version. This is because Alpha compilers ! 450: are given more flexibility to optimize generated code and instruction ! 451: sequences, including within procedure prologues. And also because of ! 452: compiler design issues, the function must manage both virtual and real ! 453: frame pointers. ! 454: ! 455: Version Information: This version was taken from exdspatch.c@v37 (Feb 1993) ! 456: ! 457: --*/ ! 458: ! 459: { ! 460: ! 461: ULONG Address; ! 462: ULONG DecrementOffset; ! 463: ULONG DecrementRegister; ! 464: ALPHA_INSTRUCTION FollowingInstruction; ! 465: // PUQUAD FloatingRegister; ! 466: PULONG FloatingRegister; ! 467: ULONG FrameSize; ! 468: ULONG Function; ! 469: ALPHA_INSTRUCTION Instruction; ! 470: // PUQUAD IntegerRegister; ! 471: PULONG IntegerRegister; ! 472: ULONG Literal8; ! 473: ULONG NextPc; ! 474: LONG Offset16; ! 475: ULONG Opcode; ! 476: ULONG Ra; ! 477: ULONG Rb; ! 478: ULONG Rc; ! 479: BOOLEAN RestoredRa; ! 480: BOOLEAN RestoredSp; ! 481: ! 482: #ifdef DBG ! 483: if (RtlDebugFlags & RTL_DBG_VIRTUAL_UNWIND) { ! 484: DbgPrint("\nRtlVirtualUnwind(ControlPc = %lx, FunctionEntry = %lx,) sp = %lx\n", ! 485: ControlPc, FunctionEntry, ContextRecord->IntSp); ! 486: } ! 487: #endif ! 488: #ifdef DBG ! 489: if ((FunctionEntry == NULL) || (ControlPc & 0x3) || ! 490: (FunctionEntry->BeginAddress >= FunctionEntry->EndAddress) || ! 491: (FunctionEntry->PrologEndAddress < FunctionEntry->BeginAddress) || ! 492: (FunctionEntry->PrologEndAddress >= FunctionEntry->EndAddress)) { ! 493: DbgPrint("\n****** Warning - invalid PC or function table entry (virtual unwind).\n"); ! 494: return ControlPc; ! 495: } ! 496: #endif ! 497: // ! 498: // Set the base address of the integer and floating register arrays within ! 499: // the context record. Each set of 32 registers is known to be contiguous. ! 500: // ! 501: ! 502: // MBH - assuming that quad values are together in context. ! 503: // Do we really need 64 bit values? ! 504: ! 505: IntegerRegister = &ContextRecord->IntV0; ! 506: FloatingRegister = &ContextRecord->FltF0; ! 507: ! 508: // ! 509: // Handle the epilogue case where the next instruction is a return. ! 510: // ! 511: // Exception handlers cannot be called if the ControlPc is within the ! 512: // epilogue because exception handlers expect to operate with a current ! 513: // stack frame. The value of SP is not current within the epilogue. ! 514: // ! 515: ! 516: //MBH ! 517: if (! LocalDoMemoryRead(dp, ControlPc, &Instruction.Long)) { ! 518: return(0); ! 519: } ! 520: ! 521: // Instruction.Long = *((PULONG)ControlPc); ! 522: //MBH ! 523: if (IS_RETURN_0001_INSTRUCTION(Instruction.Long)) { ! 524: Rb = Instruction.Jump.Rb; ! 525: NextPc = (ULONG)IntegerRegister[Rb] - 4; ! 526: ! 527: // ! 528: // The instruction at the point where control left the specified ! 529: // function is a return, so any saved registers have already been ! 530: // restored, and the stack pointer has already been adjusted. The ! 531: // stack does not need to be unwound in this case and the saved ! 532: // return address register is returned as the function value. ! 533: // ! 534: // In fact, reverse execution of the prologue is not possible in ! 535: // this case: the stack pointer has already been incremented and ! 536: // so, for this frame, neither a valid stack pointer nor frame ! 537: // pointer exists from which to begin reverse execution of the ! 538: // prologue. In addition, the integrity of any data on the stack ! 539: // below the stack pointer is never guaranteed (due to interrupts ! 540: // and exceptions). ! 541: // ! 542: // The epilogue instruction sequence is: ! 543: // ! 544: // ==> ret zero, (Ra), 1 // return ! 545: // or ! 546: // ! 547: // mov ra, Rx // save return address ! 548: // ... ! 549: // ==> ret zero, (Rx), 1 // return ! 550: // ! 551: ! 552: // EstablisherFrame->Real = 0; ! 553: // EstablisherFrame->Virtual = (ULONG)ContextRecord->IntSp; ! 554: // *InFunction = FALSE; ! 555: _RtlpDebugDisassemble(ControlPc, ContextRecord); ! 556: // _RtlpVirtualUnwindExit(NextPc, ContextRecord); ! 557: return NextPc; ! 558: } ! 559: ! 560: // ! 561: // Handle the epilogue case where the next two instructions are a stack ! 562: // frame deallocation and a return. ! 563: // ! 564: ! 565: // MBH ! 566: if (!LocalDoMemoryRead(dp, ! 567: ControlPc+4, ! 568: &FollowingInstruction.Long)) ! 569: return (0); ! 570: ! 571: // FollowingInstruction.Long = *((PULONG)(ControlPc + 4)); ! 572: // MBH ! 573: if (IS_RETURN_0001_INSTRUCTION(FollowingInstruction.Long)) { ! 574: Rb = FollowingInstruction.Jump.Rb; ! 575: NextPc = (ULONG)IntegerRegister[Rb] - 4; ! 576: ! 577: // ! 578: // The second instruction following the point where control ! 579: // left the specified function is a return. If the instruction ! 580: // before the return is a stack increment instruction, then all ! 581: // saved registers have already been restored except for SP. ! 582: // The value of the stack pointer register cannot be recovered ! 583: // through reverse execution of the prologue because in order ! 584: // to begin reverse execution either the stack pointer or the ! 585: // frame pointer (if any) must still be valid. ! 586: // ! 587: // Instead, the effect that the stack increment instruction ! 588: // would have had on the context is manually applied to the ! 589: // current context. This is forward execution of the epilogue ! 590: // rather than reverse execution of the prologue. ! 591: // ! 592: // In an epilogue, as in a prologue, the stack pointer is always ! 593: // adjusted with a single instruction: either an immediate-value ! 594: // (lda) or a register-value (addq) add instruction. ! 595: // ! 596: ! 597: Function = Instruction.OpReg.Function; ! 598: Offset16 = Instruction.Memory.MemDisp; ! 599: Opcode = Instruction.OpReg.Opcode; ! 600: Ra = Instruction.OpReg.Ra; ! 601: Rb = Instruction.OpReg.Rb; ! 602: Rc = Instruction.OpReg.Rc; ! 603: ! 604: if ((Opcode == LDA_OP) && (Ra == SP_REG)) { ! 605: ! 606: // ! 607: // Load Address instruction. ! 608: // ! 609: // Since the destination (Ra) register is SP, an immediate- ! 610: // value stack deallocation operation is being performed. The ! 611: // displacement value should be added to SP. The displacement ! 612: // value is assumed to be positive. The amount of stack ! 613: // deallocation possible using this instruction ranges from ! 614: // 16 to 32752 (32768 - 16) bytes. The base register (Rb) is ! 615: // usually SP, but may be another register. ! 616: // ! 617: // The epilogue instruction sequence is: ! 618: // ! 619: // ==> lda sp, +N(sp) // deallocate stack frame ! 620: // ret zero, (ra) // return ! 621: // or ! 622: // ! 623: // ==> lda sp, +N(Rx) // restore SP and deallocate frame ! 624: // ret zero, (ra) // return ! 625: // ! 626: ! 627: ContextRecord->IntSp = Offset16 + IntegerRegister[Rb]; ! 628: // EstablisherFrame->Real = 0; ! 629: // EstablisherFrame->Virtual = (ULONG)ContextRecord->IntSp; ! 630: // *InFunction = FALSE; ! 631: _RtlpDebugDisassemble(ControlPc, ContextRecord); ! 632: _RtlpDebugDisassemble(ControlPc + 4, ContextRecord); ! 633: // _RtlpVirtualUnwindExit(NextPc, ContextRecord); ! 634: return NextPc; ! 635: ! 636: } else if ((Opcode == ARITH_OP) && (Function == ADDQ_FUNC) && ! 637: (Rc == SP_REG) && ! 638: (Instruction.OpReg.RbvType == RBV_REGISTER_FORMAT)) { ! 639: ! 640: // ! 641: // Add Quadword instruction. ! 642: // ! 643: // Since both source operands are registers, and the ! 644: // destination register is SP, a register-value stack ! 645: // deallocation is being performed. The value of the two ! 646: // source registers should be added and this is the new ! 647: // value of SP. One of the source registers is usually SP, ! 648: // but may be another register. ! 649: // ! 650: // The epilogue instruction sequence is: ! 651: // ! 652: // ldiq Rx, N // set [large] frame size ! 653: // ... ! 654: // ==> addq sp, Rx, sp // deallocate stack frame ! 655: // ret zero, (ra) // return ! 656: // or ! 657: // ! 658: // ==> addq Rx, Ry, sp // restore SP and deallocate frame ! 659: // ret zero, (ra) // return ! 660: // ! 661: ! 662: ContextRecord->IntSp = IntegerRegister[Ra] + IntegerRegister[Rb]; ! 663: // EstablisherFrame->Real = 0; ! 664: // EstablisherFrame->Virtual = (ULONG)ContextRecord->IntSp; ! 665: // *InFunction = FALSE; ! 666: _RtlpDebugDisassemble(ControlPc, ContextRecord); ! 667: _RtlpDebugDisassemble(ControlPc + 4, ContextRecord); ! 668: // _RtlpVirtualUnwindExit(NextPc, ContextRecord); ! 669: return NextPc; ! 670: } ! 671: } ! 672: ! 673: // ! 674: // By default set the frame pointers to the current value of SP. ! 675: // ! 676: // When a procedure is called, the value of SP before the stack ! 677: // allocation instruction is the virtual frame pointer. When reverse ! 678: // executing instructions in the prologue, the value of SP before the ! 679: // stack allocation instruction is encountered is the real frame ! 680: // pointer. This is the current value of SP unless the procedure uses ! 681: // a frame pointer (e.g., FP_REG). ! 682: // ! 683: ! 684: // EstablisherFrame->Real = (ULONG)ContextRecord->IntSp; ! 685: // EstablisherFrame->Virtual = (ULONG)ContextRecord->IntSp; ! 686: ! 687: // ! 688: // If the address where control left the specified function is beyond ! 689: // the end of the prologue, then the control PC is considered to be ! 690: // within the function and the control address is set to the end of ! 691: // the prologue. Otherwise, the control PC is not considered to be ! 692: // within the function (i.e., the prologue). ! 693: // ! 694: // N.B. PrologEndAddress is equal to BeginAddress for a leaf function. ! 695: // ! 696: // The low-order two bits of PrologEndAddress are reserved for the IEEE ! 697: // exception mode and so must be masked out. ! 698: // ! 699: ! 700: if ((ControlPc < FunctionEntry->BeginAddress) || ! 701: (ControlPc >= FunctionEntry->PrologEndAddress)) { ! 702: // *InFunction = TRUE; ! 703: ControlPc = (FunctionEntry->PrologEndAddress & (~0x3)); ! 704: ! 705: } else { ! 706: // *InFunction = FALSE; ! 707: } ! 708: ! 709: // ! 710: // Scan backward through the prologue to reload callee saved registers ! 711: // that were stored or copied and to increment the stack pointer if it ! 712: // was decremented. ! 713: // ! 714: ! 715: DecrementRegister = ZERO_REG; ! 716: NextPc = (ULONG)ContextRecord->IntRa - 4; ! 717: RestoredRa = FALSE; ! 718: RestoredSp = FALSE; ! 719: while (ControlPc > FunctionEntry->BeginAddress) { ! 720: ! 721: // ! 722: // Get instruction value, decode fields, case on opcode value, and ! 723: // reverse register store and stack decrement operations. ! 724: // N.B. The location of Opcode, Ra, Rb, and Rc is the same across ! 725: // all opcode formats. The same is not true for Function. ! 726: // ! 727: ! 728: ControlPc -= 4; ! 729: //MBH ! 730: if (!LocalDoMemoryRead(dp, ControlPc, &Instruction.Long)) { ! 731: return(0); ! 732: } ! 733: // Instruction.Long = *((PULONG)ControlPc); ! 734: //MBH ! 735: Function = Instruction.OpReg.Function; ! 736: Literal8 = Instruction.OpLit.Literal; ! 737: Offset16 = Instruction.Memory.MemDisp; ! 738: Opcode = Instruction.OpReg.Opcode; ! 739: Ra = Instruction.OpReg.Ra; ! 740: Rb = Instruction.OpReg.Rb; ! 741: Rc = Instruction.OpReg.Rc; ! 742: ! 743: // ! 744: // Compare against each instruction type that will affect the context ! 745: // and that is allowed in a prologue. Any other instructions found ! 746: // in the prologue will be ignored since they are assumed to have no ! 747: // effect on the context. ! 748: // ! 749: ! 750: switch (Opcode) { ! 751: ! 752: case STQ_OP : ! 753: ! 754: // ! 755: // Store Quad instruction. ! 756: // ! 757: // If the base register is SP, then reload the source register ! 758: // value from the value stored on the stack. ! 759: // ! 760: // The prologue instruction sequence is: ! 761: // ! 762: // ==> stq Rx, N(sp) // save integer register Rx ! 763: // ! 764: ! 765: if ((Rb == SP_REG) && (Ra != ZERO_REG)) { ! 766: ! 767: // ! 768: // Reload the register by retrieving the value previously ! 769: // stored on the stack. ! 770: // ! 771: ! 772: Address = Offset16 + ContextRecord->IntSp; ! 773: // MBH ! 774: if (!LocalDoMemoryRead(dp, ! 775: Address, ! 776: &IntegerRegister[Ra])) { ! 777: return(0); ! 778: } ! 779: // IntegerRegister[Ra] = *((PULONG)Address); ! 780: // MBH ! 781: ! 782: // ! 783: // If the destination register is RA and this is the first ! 784: // time that RA is being restored, then set the address of ! 785: // where control left the previous frame. Otherwise, if this ! 786: // is the second time RA is being restored, then the first ! 787: // one was an interrupt or exception address and the return ! 788: // PC should not have been biased by 4. ! 789: // ! 790: ! 791: if (Ra == RA_REG) { ! 792: if (RestoredRa == FALSE) { ! 793: NextPc = (ULONG)ContextRecord->IntRa - 4; ! 794: RestoredRa = TRUE; ! 795: ! 796: } else { ! 797: NextPc += 4; ! 798: _RtlpFoundTrapFrame(NextPc); ! 799: } ! 800: ! 801: // ! 802: // Otherwise, if the destination register is SP and this is ! 803: // the first time that SP is being restored, then set the ! 804: // establisher frame pointers. ! 805: // ! 806: ! 807: } else if ((Ra == SP_REG) && (RestoredSp == FALSE)) { ! 808: RestoredSp = TRUE; ! 809: } ! 810: ! 811: // ! 812: // If a context pointer record is specified, then record ! 813: // the address where the destination register contents ! 814: // are stored. ! 815: // ! 816: ! 817: _RtlpDebugDisassemble(ControlPc, ContextRecord); ! 818: } ! 819: break; ! 820: ! 821: case LDAH_OP : ! 822: Offset16 <<= 16; ! 823: ! 824: case LDA_OP : ! 825: ! 826: // ! 827: // Load Address High, Load Address instruction. ! 828: // ! 829: // There are several cases where the lda and/or ldah instructions ! 830: // are used: one to decrement the stack pointer directly, and the ! 831: // others to load immediate values into another register and that ! 832: // register is then used to decrement the stack pointer. ! 833: // ! 834: // In the examples below, as a single instructions or as a pair, ! 835: // a lda may be substituted for a ldah and visa-versa. ! 836: // ! 837: ! 838: if (Ra == SP_REG) { ! 839: if (Rb == SP_REG) { ! 840: ! 841: // ! 842: // If both the destination (Ra) and base (Rb) registers ! 843: // are SP, then a standard stack allocation was performed ! 844: // and the negated displacement value is the stack frame ! 845: // size. The amount of stack allocation possible using ! 846: // the lda instruction ranges from 16 to 32768 bytes and ! 847: // the amount of stack allocation possible using the ldah ! 848: // instruction ranges from 65536 to 2GB in multiples of ! 849: // 65536 bytes. It is rare for the ldah instruction to be ! 850: // used in this manner. ! 851: // ! 852: // The prologue instruction sequence is: ! 853: // ! 854: // ==> lda sp, -N(sp) // allocate stack frame ! 855: // ! 856: ! 857: FrameSize = -Offset16; ! 858: goto StackAllocation; ! 859: ! 860: } else { ! 861: ! 862: // ! 863: // The destination register is SP and the base register ! 864: // is not SP, so this instruction must be the second ! 865: // half of an instruction pair to allocate a large size ! 866: // (>32768 bytes) stack frame. Save the displacement value ! 867: // as the partial decrement value and postpone adjusting ! 868: // the value of SP until the first instruction of the pair ! 869: // is encountered. ! 870: // ! 871: // The prologue instruction sequence is: ! 872: // ! 873: // ldah Rx, -N(sp) // prepare new SP (upper) ! 874: // ==> lda sp, sN(Rx) // allocate stack frame ! 875: // ! 876: ! 877: DecrementRegister = Rb; ! 878: DecrementOffset = Offset16; ! 879: _RtlpDebugDisassemble(ControlPc, ContextRecord); ! 880: } ! 881: ! 882: } else if (Ra == DecrementRegister) { ! 883: if (Rb == DecrementRegister) { ! 884: ! 885: // ! 886: // Both the destination and base registers are the ! 887: // decrement register, so this instruction exists as the ! 888: // second half of a two instruction pair to load a ! 889: // 31-bit immediate value into the decrement register. ! 890: // Save the displacement value as the partial decrement ! 891: // value. ! 892: // ! 893: // The prologue instruction sequence is: ! 894: // ! 895: // ldah Rx, +N(zero) // set frame size (upper) ! 896: // ==> lda Rx, sN(Rx) // set frame size (+lower) ! 897: // ... ! 898: // subq sp, Rx, sp // allocate stack frame ! 899: // ! 900: ! 901: DecrementOffset += Offset16; ! 902: _RtlpDebugDisassemble(ControlPc, ContextRecord); ! 903: ! 904: } else if (Rb == ZERO_REG) { ! 905: ! 906: // ! 907: // The destination register is the decrement register and ! 908: // the base register is zero, so this instruction exists ! 909: // to load an immediate value into the decrement register. ! 910: // The stack frame size is the new displacement value added ! 911: // to the previous displacement value, if any. ! 912: // ! 913: // The prologue instruction sequence is: ! 914: // ! 915: // ==> lda Rx, +N(zero) // set frame size ! 916: // ... ! 917: // subq sp, Rx, sp // allocate stack frame ! 918: // or ! 919: // ! 920: // ==> ldah Rx, +N(zero) // set frame size (upper) ! 921: // lda Rx, sN(Rx) // set frame size (+lower) ! 922: // ... ! 923: // subq sp, Rx, sp // allocate stack frame ! 924: // ! 925: ! 926: FrameSize = (Offset16 + DecrementOffset); ! 927: goto StackAllocation; ! 928: ! 929: } else if (Rb == SP_REG) { ! 930: ! 931: // ! 932: // The destination (Ra) register is SP and the base (Rb) ! 933: // register is the decrement register, so a two ! 934: // instruction, large size (>32768 bytes) stack frame ! 935: // allocation was performed. Add the new displacement ! 936: // value to the previous displacement value. The negated ! 937: // displacement value is the stack frame size. ! 938: // ! 939: // The prologue instruction sequence is: ! 940: // ! 941: // ==> ldah Rx, -N(sp) // prepare new SP (upper) ! 942: // lda sp, sN(Rx) // allocate stack frame ! 943: // ! 944: ! 945: FrameSize = -(Offset16 + (LONG)DecrementOffset); ! 946: goto StackAllocation; ! 947: } ! 948: } ! 949: break; ! 950: ! 951: case ARITH_OP : ! 952: ! 953: if ((Function == ADDQ_FUNC) && ! 954: (Instruction.OpReg.RbvType != RBV_REGISTER_FORMAT)) { ! 955: ! 956: // ! 957: // Add Quadword (immediate) instruction. ! 958: // ! 959: // If the first source register is zero, and the second ! 960: // operand is a literal, and the destination register is ! 961: // the decrement register, then the instruction exists ! 962: // to load an unsigned immediate value less than 256 into ! 963: // the decrement register. The immediate value is the stack ! 964: // frame size. ! 965: // ! 966: // The prologue instruction sequence is: ! 967: // ! 968: // ==> addq zero, N, Rx // set frame size ! 969: // ... ! 970: // subq sp, Rx, sp // allocate stack frame ! 971: // ! 972: ! 973: if ((Ra == ZERO_REG) && (Rc == DecrementRegister)) { ! 974: FrameSize = Literal8; ! 975: goto StackAllocation; ! 976: } ! 977: ! 978: } else if ((Function == SUBQ_FUNC) && ! 979: (Instruction.OpReg.RbvType == RBV_REGISTER_FORMAT)) { ! 980: ! 981: // ! 982: // Subtract Quadword (register) instruction. ! 983: // ! 984: // If both source operands are registers and the first ! 985: // source (minuend) register and the destination ! 986: // (difference) register are both SP, then a register value ! 987: // stack allocation was performed and the second source ! 988: // (subtrahend) register value will be added to SP when its ! 989: // value is known. Until that time save the register number of ! 990: // this decrement register. ! 991: // ! 992: // The prologue instruction sequence is: ! 993: // ! 994: // ldiq Rx, N // set frame size ! 995: // ... ! 996: // ==> subq sp, Rx, sp // allocate stack frame ! 997: // ! 998: ! 999: if ((Ra == SP_REG) && (Rc == SP_REG)) { ! 1000: DecrementRegister = Rb; ! 1001: DecrementOffset = 0; ! 1002: _RtlpDebugDisassemble(ControlPc, ContextRecord); ! 1003: } ! 1004: } ! 1005: break; ! 1006: ! 1007: case BIT_OP : ! 1008: ! 1009: // ! 1010: // If the second operand is a register the bit set instruction ! 1011: // may be a register move instruction, otherwise if the second ! 1012: // operand is a literal, the bit set instruction may be a load ! 1013: // immediate value instruction. ! 1014: // ! 1015: ! 1016: if ((Function == BIS_FUNC) && (Rc != ZERO_REG)) { ! 1017: if (Instruction.OpReg.RbvType == RBV_REGISTER_FORMAT) { ! 1018: ! 1019: // ! 1020: // Bit Set (register move) instruction. ! 1021: // ! 1022: // If both source registers are the same register, or ! 1023: // one of the source registers is zero, then this is a ! 1024: // register move operation. Restore the value of the ! 1025: // source register by copying the current destination ! 1026: // register value back to the source register. ! 1027: // ! 1028: // The prologue instruction sequence is: ! 1029: // ! 1030: // ==> bis Rx, Rx, Ry // copy register Rx ! 1031: // or ! 1032: // ! 1033: // ==> bis Rx, zero, Ry // copy register Rx ! 1034: // or ! 1035: // ! 1036: // ==> bis zero, Rx, Ry // copy register Rx ! 1037: // ! 1038: ! 1039: if (Ra == ZERO_REG) { ! 1040: ! 1041: // ! 1042: // Map the third case above to the first case. ! 1043: // ! 1044: ! 1045: Ra = Rb; ! 1046: ! 1047: } else if (Rb == ZERO_REG) { ! 1048: ! 1049: // ! 1050: // Map the second case above to the first case. ! 1051: // ! 1052: ! 1053: Rb = Ra; ! 1054: } ! 1055: ! 1056: if ((Ra == Rb) && (Ra != ZERO_REG)) { ! 1057: IntegerRegister[Ra] = IntegerRegister[Rc]; ! 1058: ! 1059: ! 1060: // ! 1061: // If the destination register is RA and this is the ! 1062: // first time that RA is being restored, then set the ! 1063: // address of where control left the previous frame. ! 1064: // Otherwise, if this is the second time RA is being ! 1065: // restored, then the first one was an interrupt or ! 1066: // exception address and the return PC should not ! 1067: // have been biased by 4. ! 1068: // ! 1069: ! 1070: if (Ra == RA_REG) { ! 1071: if (RestoredRa == FALSE) { ! 1072: NextPc = (ULONG)ContextRecord->IntRa - 4; ! 1073: RestoredRa = TRUE; ! 1074: ! 1075: } else { ! 1076: NextPc += 4; ! 1077: _RtlpFoundTrapFrame(NextPc); ! 1078: } ! 1079: } ! 1080: ! 1081: // ! 1082: // If the source register is SP and this is the first ! 1083: // time SP is set, then this is a frame pointer set ! 1084: // instruction. Reset the frame pointers to this new ! 1085: // value of SP. ! 1086: // ! 1087: ! 1088: if ((Ra == SP_REG) && (RestoredSp == FALSE)) { ! 1089: // EstablisherFrame->Virtual = (ULONG)ContextRecord->IntSp; ! 1090: // EstablisherFrame->Real = (ULONG)ContextRecord->IntSp; ! 1091: RestoredSp = TRUE; ! 1092: } ! 1093: _RtlpDebugDisassemble(ControlPc, ContextRecord); ! 1094: } ! 1095: ! 1096: } else { ! 1097: ! 1098: // ! 1099: // Bit Set (load immediate) instruction. ! 1100: // ! 1101: // If the first source register is zero, and the second ! 1102: // operand is a literal, and the destination register is ! 1103: // the decrement register, then this instruction exists ! 1104: // to load an unsigned immediate value less than 256 into ! 1105: // the decrement register. The decrement register value is ! 1106: // the stack frame size. ! 1107: // ! 1108: // The prologue instruction sequence is: ! 1109: // ! 1110: // ==> bis zero, N, Rx // set frame size ! 1111: // ... ! 1112: // subq sp, Rx, sp // allocate stack frame ! 1113: // ! 1114: ! 1115: if ((Ra == ZERO_REG) && (Rc == DecrementRegister)) { ! 1116: FrameSize = Literal8; ! 1117: StackAllocation: ! 1118: // ! 1119: // Add the frame size to SP to reverse the stack frame ! 1120: // allocation, leave the real frame pointer as is, set ! 1121: // the virtual frame pointer with the updated SP value, ! 1122: // and clear the decrement register. ! 1123: // ! 1124: ! 1125: ContextRecord->IntSp += FrameSize; ! 1126: // EstablisherFrame->Virtual = (ULONG)ContextRecord->IntSp; ! 1127: DecrementRegister = ZERO_REG; ! 1128: _RtlpDebugDisassemble(ControlPc, ContextRecord); ! 1129: } ! 1130: } ! 1131: } ! 1132: break; ! 1133: ! 1134: case STT_OP : ! 1135: ! 1136: // ! 1137: // Store T-Floating (quadword integer) instruction. ! 1138: // ! 1139: // If the base register is SP, then reload the source register ! 1140: // value from the value stored on the stack. ! 1141: // ! 1142: // The prologue instruction sequence is: ! 1143: // ! 1144: // ==> stt Fx, N(sp) // save floating register Fx ! 1145: // ! 1146: ! 1147: if ((Rb == SP_REG) && (Ra != FZERO_REG)) { ! 1148: ! 1149: // ! 1150: // Reload the register by retrieving the value previously ! 1151: // stored on the stack. ! 1152: // ! 1153: ! 1154: Address = Offset16 + ContextRecord->IntSp; ! 1155: // MBH ! 1156: if (!LocalDoMemoryRead(dp, ! 1157: Address, ! 1158: &FloatingRegister[Ra])) { ! 1159: return(0); ! 1160: } ! 1161: // FloatingRegister[Ra] = *((PUQUAD)Address); ! 1162: // MBH ! 1163: ! 1164: // ! 1165: // If a context pointer record is specified, then record ! 1166: // the address where the destination register contents are ! 1167: // stored. ! 1168: // ! 1169: ! 1170: _RtlpDebugDisassemble(ControlPc, ContextRecord); ! 1171: } ! 1172: break; ! 1173: ! 1174: case FPOP_OP : ! 1175: ! 1176: // ! 1177: // N.B. The floating operate function field is not the same as ! 1178: // the integer operate nor the jump function fields. ! 1179: // ! 1180: ! 1181: if (Instruction.FpOp.Function == CPYS_FUNC) { ! 1182: ! 1183: // ! 1184: // Copy Sign (floating-point move) instruction. ! 1185: // ! 1186: // If both source registers are the same register, then this is ! 1187: // a floating-point register move operation. Restore the value ! 1188: // of the source register by copying the current destination ! 1189: // register value to the source register. ! 1190: // ! 1191: // The prologue instruction sequence is: ! 1192: // ! 1193: // ==> cpys Fx, Fx, Fy // copy floating register Fx ! 1194: // ! 1195: ! 1196: if ((Ra == Rb) && (Ra != FZERO_REG)) { ! 1197: FloatingRegister[Ra] = FloatingRegister[Rc]; ! 1198: _RtlpDebugDisassemble(ControlPc, ContextRecord); ! 1199: } ! 1200: } ! 1201: ! 1202: default : ! 1203: break; ! 1204: } ! 1205: } ! 1206: ! 1207: // _RtlpVirtualUnwindExit(NextPc, ContextRecord); ! 1208: return NextPc; ! 1209: } ! 1210: ! 1211: ! 1212: ! 1213: ! 1214:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.