?? 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
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -