📄 thmunwnd.c
字号:
/*++ Copyright (c) 1997-2000 Microsoft Corporation. All rights reserved.Module Name: thmunwnd.cAbstract: This module implements the unwinding of Thumb mode procedure call frames for exception processing.--*/#include "kernel.h"#include "arminst.h"#include <stdlib.h>extern BOOL ReadMemory(void *src, void *dest, int length); // unwind.cULONGThumbVirtualUnwind( IN ULONG ControlPc, IN PRUNTIME_FUNCTION FunctionEntry, IN OUT PCONTEXT Context, OUT PBOOLEAN InFunction, OUT PULONG EstablisherFrame )/*++Routine Description: This is the Thumb specific implementation of RtlVirtualUnwindArguments: See RtlVirtualUnwindReturn Value: See RtlVirtualUnwind--*/{ THUMBI instr; ARMI instrA; PULONG RegPtr; PULONG SrcPtr, DestPtr; ULONG SpAdjReg, SpAdjVal; ULONG BlOffs; ULONG BeginAddress; ULONG RegBit; ULONG Data; #if 0 NKDbgPrintfW(L"Unwind: Pc=%8.8x Begin=%8.8x PrologEnd=%8.8x End=%8.8x\r\n", ControlPc, FunctionEntry->BeginAddress, FunctionEntry->PrologEndAddress, FunctionEntry->EndAddress);#endif *InFunction = FALSE; if (FunctionEntry->PrologEndAddress-FunctionEntry->BeginAddress == 0) { // No prolog. *EstablisherFrame = Context->Sp; return Context->Lr - 4; } // // Check to see if we're already in the prolog. // if ( ControlPc >= FunctionEntry->PrologEndAddress ){ *InFunction = TRUE; ControlPc = FunctionEntry->PrologEndAddress - 2; } // // Reverse execute starting with the last instruction in the prolog // that has been executed. // ControlPc &= ~0x01; // Clear Thumb bit BeginAddress = FunctionEntry->BeginAddress & ~0x01; SpAdjVal = 0; // No SP Sequence while ( ControlPc >= BeginAddress ){ if ( !ReadMemory((PVOID)ControlPc, &instr, sizeof(instr)) ){ return ControlPc; } if ( ThumbPushInst(instr.instruction) ){ // // Push zero or more GPRs or the Link Register. The GPRs to // push are specified in an eight bit register mask. The L bit // specifies that the LR is to be pushed. // RegPtr = &Context->R0; for ( RegBit = 0x01; RegBit < 0x100; RegBit <<= 1 ){ if ( instr.push.reglist & RegBit ){ if ( !ReadMemory((PVOID)Context->Sp, RegPtr, 4) ){ return(ControlPc); } Context->Sp += 4; DEBUGMSG(ZONE_SEH, (L"Push R%d = 0x%x. Sp=0x%x\r\n", RegPtr-&Context->R0, *RegPtr, Context->Sp)); } RegPtr ++; } if ( instr.push.r == 1 ){ if ( !ReadMemory((PVOID)Context->Sp, &Context->Lr, 4) ){ return(ControlPc); } Context->Sp += 4; DEBUGMSG(ZONE_SEH, (L"Push LR = 0x%x. Sp=0x%x\r\n", Context->Lr, Context->Sp)); } } else if ( ThumbAdjSPInst(instr.instruction) ){ // // Adjust the stack pointer by adding or subtracting a scaled // 7-bit immediate (immediate is shifted by 2 bits) // if ( instr.adjsp.s ){ // Reverse execute Context->Sp += instr.adjsp.immed << 2; } else { Context->Sp -= instr.adjsp.immed << 2; } DEBUGMSG(ZONE_SEH, (L"SP += 0x%02x == 0x%x\r\n", instr.adjsp.immed << 2, Context->Sp)); } else if ( ThumbAddSPInst(instr.instruction) ){ // // If the stack frame size exceeds 508 bytes a sequence of // instructions is used to load the stack frame size into a // register and then update the stack pointer. // If an Add Hi instruction is found which updates the stack // pointer, record the source register until the unwind reaches // the load instruction which sets the source register. // SpAdjReg = instr.spcdataproc.rm; SpAdjVal = 1; DEBUGMSG(ZONE_SEH, (L"Add Sp Instruction: Source Reg = R%d\r\n", instr.spcdataproc.rm)); } else if ( ThumbMovHiInst(instr.instruction) ){ // // Move Register Rm -> Rd. // // One or both registers are high registers, as specified // by H1 (Rd) and H2 (Rm) // RegPtr = &Context->R0; SrcPtr = &RegPtr[instr.spcdataproc.rm + (instr.spcdataproc.H2 * 8)]; DestPtr = &RegPtr[instr.spcdataproc.rd + (instr.spcdataproc.H1*8)]; DEBUGMSG(ZONE_SEH, (L"Move Hi: R%d (0x%08x) -> R%d (0x%08x)\r\n", DestPtr-RegPtr, *DestPtr, SrcPtr-RegPtr, *SrcPtr)); *SrcPtr = *DestPtr; // Reverse Execute } else if ( ThumbLdrPCInst(instr.instruction) ){ // // Load from Literal Pool into register. This instruction is // used in the prologue for functions with large stack frames. // The stack frame size is loaded from the literal pool before // being used to update the stack pointer. // if ( SpAdjVal != 0 && (instr.ldrpc.rd == SpAdjReg) ){ SrcPtr = (PULONG)((ControlPc & ~0x03) + 4 + (instr.ldrpc.offset * 4)); if ( !ReadMemory((PVOID)SrcPtr, &Data, 4) ){ return(ControlPc); } Context->Sp -= (Data * SpAdjVal); // Reverse Execute Add inst. SpAdjVal = 0; // No SP adjust sequence } DEBUGMSG(ZONE_SEH, (L"Load Literal: Addr=0x%08x Val=0x%x\r\n", SrcPtr, Data)); } else if ( ThumbNegInst(instr.instruction) ){ // // The instruction sequence to create a large stack frame may // include a negate instruction. If detected, update the SpAdjVal // variable: // if ( SpAdjVal != 0 && (instr.dataproc.rd == SpAdjReg) ){ SpAdjVal = -1; } DEBUGMSG(ZONE_SEH, (L"Negate Instruction: rm=R%d rd=%d\r\n", instr.dataproc.rm, instr.dataproc.rd)); } else if ( ThumbBlPrefInst(instr.instruction) ){ // // The first instruction of a BL sequence has been found. update // the BlOffs value which was initialized in the ThumbBlInst case. // Only calls to register save millicode routines are valid within // the prologue. Register save routines have the form: // // bx pc ; Thumb instruction // nop ; Thumb instruction // stm sp!, {reglist} ; ARM instruction // bx lr ; ARM instruction // // The following code loads the instruction at the function // destination address plus four bytes and verifies that a store // multiple instruction exists at that location. If not, this is // a bad function call and unwinding stops. Otherwise the store // multiple instruction is unwound // BlOffs += (instr.bl.offset << 12) + 4; if ( BlOffs & (0x01 << 22) ){ BlOffs |= 0xFF800000; // sign extend the offset } DEBUGMSG(ZONE_SEH, (L"BL Instruction: Destination=0x%08x\r\n", ControlPc+BlOffs)); // verify stmdb sp!, {reglist}: BlOffs += 4; if ( !ReadMemory((PVOID)(ControlPc+BlOffs), &instrA, 4) || (instrA.instruction & 0xFFFF0000) != 0xE92D0000 ){ return(ControlPc); } DEBUGMSG(ZONE_SEH, (L"Register Save Instruction @%08x = 0x%08x\r\n", ControlPc+BlOffs, instrA.instruction)); RegPtr = &Context->R0; for ( RegBit = 0x01; RegBit < 0x10000; RegBit <<= 1 ){ if ( instrA.ldm.reglist & RegBit ){ if ( !ReadMemory((PVOID)Context->Sp, RegPtr, 4) ){ return(ControlPc); } Context->Sp += 4; DEBUGMSG(ZONE_SEH, (L" Save R%d = 0x%x. Sp=0x%x\r\n", RegPtr-&Context->R0, *RegPtr, Context->Sp)); } RegPtr ++; } } else if ( ThumbBlInst(instr.instruction) ){ BlOffs = instr.bl.offset << 1; DEBUGMSG(ZONE_SEH, (L"BL Instruction: offset=0x%03x\r\n", instr.bl.offset)); } else if ( ThumbBxInst(instr.instruction) ){ NKDbgPrintfW(L"BX Instruction: ControlPc=0x%x instr=0x%x\r\n", ControlPc, instr.instruction); } else { DEBUGMSG(ZONE_SEH, (L"Unknown Prolog Instruction Ignored. ControlPc=0x%08x Inst=0x%04x\r\n", ControlPc, instr.instruction)); } ControlPc -= sizeof(instr); } *EstablisherFrame = Context->Sp; return Context->Lr - 4; // Address of calling instruction}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -