📄 vunwind.c
字号:
/*++Copyright (c) 1993-2000 Microsoft Corporation. All rights reserved.Module Name: vunwind.cAbstract: 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#endifextern 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 instructionstatic INSTR_CLASSClassifyInstruction (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}ULONGRtlVirtualUnwind( 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -