📄 vunwind.c
字号:
specified function or NULL if the function is a leaf function. ContextRecord - Supplies the address of a context record. InFunction - Supplies a pointer to a variable that receives whether the control PC is within the current function. EstablisherFrame - Supplies a pointer to a variable that receives the the establisher frame pointer value.Return Value: The address where control left the previous frame is returned as the function value. --*/{ ITERATOR Iterator[8]; PITERATOR Piterator; ULONG Address; PDOUBLE FloatingRegister; PPC_INSTRUCTION I; PULONG IntegerRegister; ULONG NextPc, Pc; BOOLEAN RestoredLr = FALSE; BOOLEAN RestoredSp = FALSE; BOOLEAN ComputedSp = FALSE; ULONG Rt; MILLICODE_INFO Info; INSTR_CLASS InstrClass; ULONG EstablisherFrameValue; // // Set the base address of the integer and floating register arrays. // FloatingRegister = &ContextRecord->Fpr0; IntegerRegister = &ContextRecord->Gpr0; // // If the function is a leaf function, perform the default unwinding // action and check to see if the function was called via glue. // if (FunctionEntry == NULL) { // // Set point at which control left the previous routine. // return( ContextRecord->Lr - 4 ); } // // Set initial values for EstablisherFrame and Offset. // (this may need more careful planning IBMPLJ). // NOT_IMAGEHLP (*EstablisherFrame = EstablisherFrameValue = ContextRecord->Gpr1); READ_ULONG (ControlPc, I.Long); if (I.Long == RETURN_INSTR) { // // If the instruction at the point where control left the specified // function is a return, then any saved registers have been restored // and the control PC is not considered to be in the function // (i.e., in an epilogue). // NOT_IMAGEHLP(*InFunction = FALSE); return( ContextRecord->Lr ); } InstrClass = ClassifyInstruction(&I, UnwindReverse, ControlPc, &Info); if (InstrClass == InstrRestoreCode) { // // If the instruction at the point where control left the // specified function is a branch to register restore // millicode, the state is restored by simulating the // execution of the restore millicode. The control PC is in // an epilogue. // Iterator[0].BeginPc = Info.TargetPc; Iterator[0].EndPc = Info.FunctionEntry->EndAddress; Iterator[0].Increment = 4; Iterator[0].Intent = UnwindForward; NOT_IMAGEHLP(*InFunction = FALSE); } else if (FunctionEntry->ExceptionHandler == 0 && (ULONG)FunctionEntry->HandlerData == 2) { // // If the address is in register restore millicode, the state // is restored by completing the execution of the restore // millicode. The control PC is in an epilogue. // Iterator[0].BeginPc = ControlPc; Iterator[0].EndPc = FunctionEntry->EndAddress; Iterator[0].Increment = 4; Iterator[0].Intent = UnwindForward; NOT_IMAGEHLP(*InFunction = FALSE); } else { // // If the address where control left the specified function is // outside the limits of the prologue, then the control PC is // considered to be within the function and the control // address is set to the end of the prologue. Otherwise, the // control PC is not considered to be within the function // (i.e., in the prologue). // Iterator[0].EndPc = FunctionEntry->BeginAddress - 4; Iterator[0].Increment = -4; Iterator[0].Intent = UnwindReverse; if (ControlPc < FunctionEntry->BeginAddress || ControlPc >= (FunctionEntry->PrologEndAddress & ~3)) { NOT_IMAGEHLP(*InFunction = TRUE); Iterator[0].BeginPc = ((FunctionEntry->PrologEndAddress & ~3) - 4); } else { NOT_IMAGEHLP(*InFunction = FALSE); Iterator[0].BeginPc = ControlPc - 4; } } // // Scan through the given instructions and reload callee registers // as indicated. // NextPc = ContextRecord->Lr - 4; for (Piterator = Iterator; Piterator >= Iterator; Piterator--) { for (Pc = Piterator->BeginPc; Pc != Piterator->EndPc; Pc += Piterator->Increment) { READ_ULONG (Pc, I.Long); Address = IntegerRegister[I.Dform_RA] + I.Dform_D; Rt = I.Dform_RT; switch (ClassifyInstruction (&I, Piterator->Intent, Pc, &Info)) { // // Move from Link Register (save LR in a GPR) // // In the usual case, the link register gets set by a call // instruction so the PC value should point to the // instruction that sets the link register. In an interrupt // or exception frame, the link register and PC value are // independent. By convention, fake prologues for these // frames store the link register twice: once to the link // register location, once to the faulting PC location. // // If this is the first time that RA is being restored, // then set the address of where control left the previous // frame. Otherwise, this is an interrupt or exception and // the return PC should be biased by 4 and the link register // value should be updated. // case InstrMFLR: ContextRecord->Lr = IntegerRegister[Rt]; if ( RestoredLr == FALSE ) { NextPc = ContextRecord->Lr - 4; RestoredLr = TRUE; } else { NextPc += 4; } continue; // Next PC // // Branch to Link Register (forward execution). // case InstrBLR: NextPc = ContextRecord->Lr - 4; break; // Terminate simulation--start next iterator. // // Move from Condition Register (save CR in a GPR) // case InstrMFCR: ContextRecord->Cr = IntegerRegister[Rt]; continue; // Next PC // // Store word (save a GPR) // case InstrSTW: // // Even though a stw r.sp, xxxx in general is an invalid // proloque instruction there are places in the kernel // fake prologues (KiExceptionExit) where we must use this, // so handle it. // READ_ULONG (Address, IntegerRegister[Rt]); // Check for an SP update if ( Rt == GPR1 ) RestoredSp = TRUE; continue; // Next PC // // Store word with update, Store word with update indexed // (buy stack frame, updating stack pointer and link // cell in storage) // case InstrSTWU: // STWU should only be used for updating SP DEBUGCHK(I.Dform_RT == GPR1); DEBUGCHK(I.Dform_RA == GPR1); // Do not update SP twice. CaptureContext is an example of // a prolog where only the last sp update (the first one the // unwinder encounters) should be unwound. if ( RestoredSp == FALSE ) { Address = IntegerRegister[GPR1]; READ_ULONG(Address,IntegerRegister[GPR1]); *EstablisherFrame = ContextRecord->Gpr1; EstablisherFrameValue = ContextRecord->Gpr1; RestoredSp = TRUE; } continue; // Next PC // // Store floating point double (save an FPR) // case InstrSTFD: READ_DOUBLE (Address, FloatingRegister[Rt]); continue; // Next PC // // Move register. Certain forms are ignored based on the intent. // case InstrMR: IntegerRegister[Rt] = IntegerRegister[I.Xform_RA]; continue; // Next PC case InstrMRfwd: IntegerRegister[I.Xform_RA] = IntegerRegister[Rt]; continue; // Next PC // // Add immediate. Certain forms are ignored based on the intent. // case InstrADDIfwd: IntegerRegister[Rt] = Address; continue; // Next PC case InstrADDIr12: if (!ComputedSp) { // No intervening instruction changes r.1, so compute // addi r.12,r.1,N instead of addi r.12,r.12,N. IntegerRegister[Rt] = IntegerRegister[GPR1]; } IntegerRegister[Rt] += I.Dform_SI; break; // Terminate search--start next iterator. // // Store with update while searching for the value of r.12 // case InstrSTWUr12: ComputedSp = TRUE; Address = IntegerRegister[GPR1]; READ_ULONG(Address,IntegerRegister[GPR12]); continue; // Next PC // // A call to a register save millicode. // case InstrSaveCode: // // Push an iterator to incorporate the actions of the // millicode. // Piterator++; Piterator->BeginPc = Info.FunctionEntry->EndAddress - 4; Piterator->EndPc = Info.TargetPc - 4; Piterator->Increment = -4; Piterator->Intent = UnwindReverseR12; // // Push an iterator to determine the current value of r.12 // Piterator++; Piterator->BeginPc = Pc - 4; Piterator->EndPc = Piterator[-2].EndPc; Piterator->Increment = -4; Piterator->Intent = UnwindR12; ComputedSp = FALSE; // // Update the start of the original iterator so it can later // resume where it left off. // Piterator[-2].BeginPc = Pc - 4; Piterator++; break; // Start the next iterator. // // A branch was encountered in the prologue to a routine // identified as glue code. This should only happen from // fake prologues such as those in the system exception // handler. // // We handle it by pushing an iterator to incorporate // the actions of the glue code prologue. // case InstrGlue: // // Check that we don't nest too deeply. Verify that // we can push this iterator and the iterators for a // glue sequence. There's no need to make this check // elsewhere because B_OP is only recognized during // UnwindReverse. Returing zero is the only error action // we have. // if (Piterator - Iterator + 4 > sizeof (Iterator) / sizeof (Iterator[0])) return 0; // // Push an iterator to incorporate the actions of the glue // code's prologue. Check that we don't nest too deeply. // Verify that we can push this iterator and the iterators // for a glue sequence. // Piterator++; Piterator->BeginPc = (Info.FunctionEntry->PrologEndAddress & ~3) - 4; Piterator->EndPc = Info.FunctionEntry->BeginAddress - 4; Piterator->Increment = -4; Piterator->Intent = UnwindReverse; // // Update the start of the original iterator so it can later // resume where it left off. // Piterator[-1].BeginPc = Pc - 4; Piterator++; break; // Start the next iterator. // // Special "set establisher" instruction (rfi). // // Kernel fake prologues that can't use stwu (KiExceptionExit, // KiAlternateExit) use an rfi instruction to tell the // unwinder to update the establisher frame pointer using // the current value of sp. // case InstrSetEstablisher: NOT_IMAGEHLP (*EstablisherFrame = EstablisherFrameValue = ContextRecord->Gpr1); continue; // Next PC // // None of the above. Just ignore the instruction. It // is presumed to be non-prologue code that has been // merged into the prologue for scheduling purposes. It // may also be improper code in a register save/restore // millicode routine or unimportant code when // determining the value of r.12. // case InstrIgnore: default: continue; // Next PC } break; // Start the next iterator. } // end foreach Pc } // end foreach Iterator return NextPc;}#undef NOT_IMAGEHLP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -