?? vunwind.c
字號:
/*++
Copyright (c) 1993-2000 Microsoft Corporation. All rights reserved.
Module Name:
vunwind.c
Abstract:
This module contains the instruction classifying and virtual
unwinding routines for structured exception handling on PowerPC.
Virtual Unwind was moved to this file from exdsptch.c so that it
can be used directly in the kernel debugger.
--*/
#include "kernel.h"
typedef double *PDOUBLE;
#define READ_ULONG(addr,dest) ((dest) = (*(PULONG)(addr)))
#define READ_DOUBLE(addr,dest) ((dest) = (*(PDOUBLE)(addr)))
#if 0 ///ifdef _IMAGEHLP_SOURCE_
#define FUNCTION_ENTRY_IS_IMAGE_STYLE
#define NOT_IMAGEHLP(E)
#else
#define NOT_IMAGEHLP(E) E
#endif
extern PRUNTIME_FUNCTION NKLookupFunctionEntry(
IN PPROCESS pProc,
IN ULONG ControlPc,
PRUNTIME_FUNCTION prf);
//
// The `ClassifyInstruction' function returns an enum that identifies
// the type of processing needed for an instruction.
//
typedef enum _INSTR_CLASS {
InstrIgnore, // Do not process
InstrMFLR, // Move from Link Register
InstrMFCR, // Move from Condition Register
InstrSTW, // Store word
InstrSTWU, // Store word with update
InstrSTWUr12, // Store word with update during UnwindR12
InstrSTFD, // Store float double
InstrMR, // Move register
InstrMRr12, // Move register during UnwindR12
InstrMRfwd, // Move register during UnwindForward
InstrADDIr12, // Add immediate during UnwindR12
InstrADDIfwd, // Add immediate during UnwindForward
InstrSaveCode, // Branch and link to GPR or FPR saving millicode
InstrRestoreCode, // Branch to GPR or FPR saving millicode
InstrGlue, // Branch or Branch and link to glue code
InstrBLR, // Branch to Link Register
InstrSetEstablisher // Special instruction used to set establisher frame
} INSTR_CLASS;
//
// If `ClassifyInstruction' returns `InstrSaveCode' or `InstrRestoreCode',
// the following information is completed.
//
typedef struct _MILLICODE_INFO {
ULONG TargetPc; // Millicode entry point
PRUNTIME_FUNCTION FunctionEntry; // Millicode function table entry
RUNTIME_FUNCTION FETemp; // storage to hold FE if using compressed PData
} MILLICODE_INFO, *PMILLICODE_INFO;
//
// `ClassifyInstruction' interprets the instruction based on the intent.
//
typedef enum _UNWIND_INTENT {
UnwindForward, // Performing a forward execution
UnwindR12, // Performing a reverse execution to get r.12
UnwindReverse, // Performing a reverse execution
UnwindReverseR12 // Performing a reverse execution allowing r.12
} UNWIND_INTENT;
//
// The simulated execution by `RtlVirtualUnwind' is controlled by this
// data type.
//
typedef struct _ITERATOR {
ULONG BeginPc; // Address of first instruction to simulate
ULONG EndPc; // Address after the last instruction to simulate
LONG Increment; // Simulation direction
UNWIND_INTENT Intent; // Simulation intent
} ITERATOR, *PITERATOR;
#define GPR1 1 // GPR 1 in an RA, RB, RT, etc. field
#define GPR2 2 // GPR 2 in an RA, RB, RT, etc. field
#define GPR12 12 // GPR 12 in an RA, RB, RT, etc. field
#define LINKREG 0x100 // Link Reg in a MFSPR instruction
static INSTR_CLASS
ClassifyInstruction (PPC_INSTRUCTION *I,
UNWIND_INTENT Intent,
ULONG Pc,
PMILLICODE_INFO Info)
/*++
Routine description:
This function inspects the instruction identified by the "Pc"
argument and determines what sort of processing is needed in order
to simulate its execution. Some instructions can be safely
ignored altogether, in which case "InstrIgnore" is returned. For
others, a value is returned indicating what kind of instruction
was found. The interpreation depends on the value of "Intent".
Arguments:
I - Address of a struct containing the instruction to be examined.
Intent - Type of unwinding being performed.
Pc - Address of the instruction, used for computing relative branch
addresses.
Info - Address to store a description of the register save/restore
millicode.
Return value:
One of the enum values defined above is returned.
--*/
{
// Unique value combining an opcode and an UNWIND_INTENT value.
#define OP_INTENT(OP,INTENT) ((OP) << 2 | (INTENT))
switch (OP_INTENT (I->Primary_Op, Intent)) {
//
// Store word: recognize "stw r.n, disp(r.1)". Allow a base of
// r.12 if we have computed its value.
//
case OP_INTENT (STW_OP, UnwindReverseR12):
if (I->Dform_RA == GPR12)
return InstrSTW;
// fall thru
case OP_INTENT (STW_OP, UnwindReverse):
if (I->Dform_RA == GPR1)
return InstrSTW;
break;
//
// Load word: recognize "lwz r.n, disp(r.x)" in epilogue millicode.
//
case OP_INTENT (LWZ_OP, UnwindForward):
return InstrSTW;
//
// Store word with update: recognize "stwu r.1, r.1, disp"
//
case OP_INTENT (STWU_OP, UnwindReverse):
case OP_INTENT (STWU_OP, UnwindReverseR12):
case OP_INTENT (STWU_OP, UnwindR12):
if (I->Dform_RS == GPR1 &&
I->Dform_RA == GPR1)
return (Intent == UnwindR12 ? InstrSTWUr12 : InstrSTWU);
break;
//
// Store float double: recognize "stfd f.n, disp(r.1)". Allow a
// base of r.12 if we have computed its value.
//
case OP_INTENT (STFD_OP, UnwindReverseR12):
if (I->Dform_RA == GPR12)
return InstrSTFD;
// fall thru
case OP_INTENT (STFD_OP, UnwindReverse):
if (I->Dform_RA == GPR1)
return InstrSTFD;
break;
//
// Load float double: recognize "lfd f.n, disp(r.x)"
//
case OP_INTENT (LFD_OP, UnwindForward):
return InstrSTFD;
//
// Add immediate: recognize "addi r.12, r.1, delta"
//
case OP_INTENT (ADDI_OP, UnwindR12):
if (I->Dform_RS == GPR12 &&
I->Dform_RA == GPR1)
return InstrADDIr12;
break;
case OP_INTENT (ADDI_OP, UnwindForward):
return InstrADDIfwd;
//
// Branch (long form): recognize "bl[a] saveregs"and "b[a] restregs"
//
case OP_INTENT (B_OP, UnwindReverse):
//
// Compute branch target address, allowing for branch-relative
// and branch-absolute.
//
Pc = ((LONG)(I->Iform_LI) << 2) + (I->Iform_AA ? 0 : Pc);
//
// Determine whether the target address is part of a register
// save or register restore sequence or is a direct branch out
// by checking it's function table entry.
//
if ((Info->FunctionEntry = NKLookupFunctionEntry(pCurProc, Pc, &Info->FETemp)) != NULL
&& Info->FunctionEntry->ExceptionHandler == 0) {
Info->TargetPc = Pc;
switch ((ULONG)Info->FunctionEntry->HandlerData) {
case 1:
if (I->Iform_LK)
return InstrSaveCode;
break;
case 2:
if (!I->Iform_LK)
return InstrRestoreCode;
break;
case 3:
return InstrGlue;
}
}
break; // unrecognized entry point
//
// Extended ops -- primary opcode 19
//
case OP_INTENT (X19_OP, UnwindForward):
//
// BLR: recognized "bclr 20,0".
//
if (I->Long == RETURN_INSTR)
return InstrBLR;
break;
case OP_INTENT (X19_OP, UnwindR12):
case OP_INTENT (X19_OP, UnwindReverse):
case OP_INTENT (X19_OP, UnwindReverseR12):
//
// RFI: this instruction is used in special kernel fake prologues
// to indicate that the establisher frame address should be
// updated using the current value of sp.
//
if (I->Xform_XO == RFI_OP)
return InstrSetEstablisher;
break;
//
// Extended ops -- primary opcode 31
//
case OP_INTENT (X31_OP, UnwindForward):
case OP_INTENT (X31_OP, UnwindR12):
case OP_INTENT (X31_OP, UnwindReverse):
case OP_INTENT (X31_OP, UnwindReverseR12):
switch (OP_INTENT (I->Xform_XO, Intent)) {
//
// OR register: recognize "or r.x, r.y, r.y" as move-reg
//
case OP_INTENT (OR_OP, UnwindReverse):
if (I->Xform_RS == I->Xform_RB)
return InstrMR;
break;
case OP_INTENT (OR_OP, UnwindForward):
if (I->Xform_RS == I->Xform_RB)
return InstrMRfwd;
break;
//
// Store word with update indexed: recognize "stwux r.1, r.1, r.x"
//
case OP_INTENT (STWUX_OP, UnwindReverse):
case OP_INTENT (STWUX_OP, UnwindReverseR12):
case OP_INTENT (STWUX_OP, UnwindR12):
if (I->Xform_RS == GPR1 && I->Xform_RA == GPR1)
return (Intent == UnwindR12 ? InstrSTWUr12 : InstrSTWU);
break;
//
// Move to/from special-purpose reg: recognize "mflr", "mtlr"
//
case OP_INTENT (MFSPR_OP, UnwindReverse):
case OP_INTENT (MTSPR_OP, UnwindForward):
if (I->XFXform_spr == LINKREG)
return InstrMFLR;
break;
//
// Move from Condition Register: "mfcr r.x"
//
case OP_INTENT (MFCR_OP, UnwindReverse):
case OP_INTENT (MFCR_OP, UnwindReverseR12):
return InstrMFCR;
//
// Move to Condition Register: "mtcrf 255,r.x"
//
case OP_INTENT (MTCRF_OP, UnwindForward):
if (I->XFXform_FXM == 255)
return InstrMFCR;
break;
default: // unrecognized
break;
}
default: // unrecognized
break;
}
//
// Instruction not recognized; just ignore it and carry on
//
return InstrIgnore;
#undef OP_INTENT
}
ULONG
RtlVirtualUnwind(
IN ULONG ControlPc,
IN PRUNTIME_FUNCTION FunctionEntry,
IN OUT PCONTEXT ContextRecord,
OUT PBOOLEAN InFunction,
OUT PULONG EstablisherFrame)
/*++
Routine Description:
This function virtually unwinds the specfified function by executing its
prologue code backwards.
If the function is a leaf function, then the address where control left
the previous frame is obtained from the context record. If the function
is a nested function, but not an exception or interrupt frame, then the
prologue code is executed backwards and the address where control left
the previous frame is obtained from the updated context record.
If the function is register save millicode, it is treated as a leaf
function. If the function is register restore millicode, the remaining
body is executed forwards and the address where control left the
previous frame is obtained from the final blr instruction.
If the function was called via glue code and is not that glue code,
the prologe of the glue code is executed backwards in addition to the
above actions.
Otherwise, an exception or interrupt entry to the system is being
unwound and a specially coded prologue restores the return address
twice. Once from the fault instruction address and once from the saved
return address register. The first restore is returned as the function
value and the second restore is place in the updated context record.
If a context pointers record is specified, then the address where each
nonvolatile registers is restored from is recorded in the appropriate
element of the context pointers record.
Arguments:
ControlPc - Supplies the address where control left the specified
function.
FunctionEntry - Supplies the address of the function table entry for the
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -