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