📄 unwind.c
字号:
if (!ReadMemorySanitized((PVOID)(EpilogPc+4), &instr2, 4))
return ControlPc;
if ((instr2.instruction & B_BL_MASK) == B_INSTR ||
(instr2.instruction & BX_MASK) == BX_INSTR) {
if (!UnwindLoadMultiple(instr, Register))
return ControlPc;
*EstablisherFrame = Register[13];
return Register[14] - 4;
} else
ExecutingEpilog = FALSE;
} else
ExecutingEpilog = FALSE;
EpilogPc += 4;
}
}
// We were not in the epilog. Load in the prolog, and reverse execute it.
cb = PrologEndAddress - BeginAddress;
if (cb > sizeof(Prolog)) {
ASSERT(FALSE); // prolog too large
return ControlPc;
}
//
// Thumb assembly functions which switch to ARM via "bx pc" will have
// the low bit of the BeginAddress set. Align the BeginAddress
//
Address = BeginAddress & ~0x03;
// Read the prolog and restore debugger inserted break instructions to
// real instruction
DEBUGMSG(ZONE_SEH, (TEXT("Reading Prolog @%8.8x\r\n"), Address));
if (!ReadMemorySanitized((PVOID)Address, (PVOID)Prolog, cb))
return ControlPc;
// Check to see if we're already in the prolog.
if (ControlPc < PrologEndAddress)
cb = ControlPc - BeginAddress;
else
*InFunction = TRUE;
*EstablisherFrame = Register[13];
HaveExceptionPc = FALSE;
// Reverse execute starting with the last instruction in the prolog
// that has been executed.
for (i = cb/4 - 1 ; i >= 0 ; --i) {
// Test for these instructions:
//
// SUB SP, X - stack allocation
//
// MOV X, SP - save stack value
//
// STMDB R13, {PC} - special instruction in fake prolog
//
// STMDB - save incoming registers
//
// MOV R11, X or
// ADD R11, X or
// SUB R11, X - FP (frame pointer) setup
//
if ((Prolog[i].instruction & MOV_SP_MASK) == MOV_SP_INSTR) {
Register[13] = Register[Prolog[i].dataproc.rd];
} else if ((Prolog[i].instruction & SUB_SP_MASK) == SUB_SP_INSTR) {
//
// ldr r12, [pc, #Immed]
// sub sp, sp, r12
//
// This is a stack link. Unlink the stack.
DEBUGMSG(ZONE_SEH, (TEXT("%d: stack link instr.\r\n"), i));
if (Prolog[i].dataproc.bits != 0x1 && Prolog[i].dpshi.rm == 0xc) {
// Look for an LDR instruction above this one.
j = i - 1;
while (j >= 0 && (Prolog[j].instruction & LDR_MASK) != LDR_PC_INSTR)
j--;
if (j < 0) {
ASSERT(FALSE); // This should never happen
return ControlPc;
}
// Get the address of the ldr instruction + 8 + the offset
Address = j*4 + BeginAddress + Prolog[j].ldr.offset + 8;
// R12 is the value at that location.
if (!ReadMemory((PVOID)Address, (PVOID)&Register[12], 4))
return ControlPc;
}
// Change the subtract to an add, and execute the instruction
Prolog[i].dataproc.opcode = OP_ADD;
UnwindDataProcess(Prolog[i], Register);
} else if ((Prolog[i].instruction & ADD_SP_MASK) == ADD_SP_INSTR) {
//
// ldr r12, [pc, #Immed]
// add sp, sp, r12
//
// This is a stack link. Unlink the stack.
DEBUGMSG(ZONE_SEH, (TEXT("%d: stack link instr.\r\n"), i));
if (Prolog[i].dataproc.bits != 0x1 && Prolog[i].dpshi.rm == 0xc) {
// Look for an LDR instruction above this one.
j = i - 1;
while (j >= 0 && (Prolog[j].instruction & LDR_MASK) != LDR_PC_INSTR)
j--;
if (j < 0) {
ASSERT(FALSE); // This should never happen
return ControlPc;
}
// Get the address of the ldr instruction + 8 + the offset
Address = j*4 + BeginAddress + Prolog[j].ldr.offset + 8;
// R12 is the value at that location.
if (!ReadMemory((PVOID)Address, (PVOID)&Register[12], 4))
return ControlPc;
}
// Change the subtract to an add, and execute the instruction
Prolog[i].dataproc.opcode = OP_SUB;
UnwindDataProcess(Prolog[i], Register);
} else if ((Prolog[i].instruction & STM_PC_MASK) == STM_PC_INSTR) {
//
// STMDB R13!, { PC }
//
// This is an instruction that will not appear in a real prolog
// (or probably anywhere else). It is used as a marker in a fake
// prolog as described below.
//
// 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, the fake prolog for these frames (see
// CaptureContext in armtrap.s) contains the STMDB instruction
// shown above to lead the unwinder to the faulting PC location.
//
if (!ReadMemory((PULONG)Register[13], &NextPc, 4))
return ControlPc;
Register[13] += 4;
HaveExceptionPc = TRUE;
}
else if ((Prolog[i].instruction & STM_MASK) == STM_INSTR) {
//
// Invert the Load, Increment and Before bits:
//
Prolog[i].instruction ^= 0x01900000;
if (!UnwindLoadMultiple(Prolog[i], Register))
return ControlPc;
} else if ((Prolog[i].instruction & STRI_LR_SPU_MASK)
== STRI_LR_SPU_INSTR) {
// Store of the link register that updates the stack as a base
// register must be reverse executed to restore LR and SP
// to their values on entry. This type of prolog is generated
// for finally funclets.
///NKDbgPrintfW(L"%d: STRI for mask=%4.4x.\r\n", i, Prolog[i].ldr.offset);
//
// Invert the Load, Increment and Before bits:
//
Prolog[i].instruction ^= 0x01900000;
if (!UnwindLoadI(Prolog[i], Register))
return ControlPc;
} else if ((Prolog[i].instruction & ARM_MRS_MASK) == ARM_MRS_INSTR) {
//
// An "MRS rd, cpsr" instruction exists in CaptureContext to
// preserve the Psr register when unwinding out of system calls.
//
Context->Psr = Register[Prolog[i].mrs.rd];
} else if ((Prolog[i].instruction & ADD_FP_MASK) == ADD_FP_INSTR
|| (Prolog[i].instruction & SUB_FP_MASK) == SUB_FP_INSTR
|| (Prolog[i].instruction & MOV_FP_MASK) == MOV_FP_INSTR) {
// We know that as of this instruction, r11 is a valid frame
// pointer. Therefore, it contains the stack value immediately
// before the STM that set up the stack frame. So, we scan
// backward to find the STM, pretend it was a STM using r11 as the
// base register with no update, and reverse-execute it.
j = i - 1;
while (j >= 0 && (Prolog[j].instruction & STM_MASK) != STM_INSTR)
j--;
if ( j >= 0 ){
// Tweak the instruction so it will be reverse-executed
// correctly. A convenient side-effect of this is that it
// prevents it from being recognized as a STM when we continue
// reverse-executing, which is good because we don't want to do it
// again.
Prolog[j].ldm.l = TRUE;
Prolog[j].ldm.rn = 11;
Prolog[j].ldm.w = FALSE;
if (!UnwindLoadMultiple(Prolog[j], Register))
return ControlPc;
}
}
}
// The continuation address is contained in the link register.
*EstablisherFrame = Register[13];
if (!HaveExceptionPc)
NextPc = Register[14] - 4;
return NextPc;
}
//------------------------------------------------------------------------------
//
// Routine Description:
// This function executes an ARM data processing instruction using the
// current register set. It automatically updates the destination register.
//
// Arguments:
// instr The ARM 32-bit instruction
//
// Register Pointer to the ARM integer registers.
//
// Return Value:
// None.
//
//------------------------------------------------------------------------------
VOID
UnwindDataProcess(
ARMI instr,
PULONG Register
)
{
ULONG Op1, Op2;
ULONG Cflag = (Register[16] & 0x20000000L) == 0x20000000L; // CPSR
ULONG shift;
// We are checking for all addressing modes and op codes, even though
// the prolog and epilog don't use them all right now. In the future,
// more instructions and addressing modes may be added.
//
// Figure out the addressing mode (there are 11 of them), and get the
// operands.
Op1 = Register[instr.dataproc.rn];
if (instr.dataproc.bits == 0x1) {
// Immediate addressing - Type 1
Op2 = _lrotr(instr.dpi.immediate, instr.dpi.rotate * 2);
} else {
// Register addressing - start by getting the value of Rm.
Op2 = Register[instr.dpshi.rm];
if (instr.dprre.bits == 0x6) {
// Rotate right with extended - Type 11
Op2 = (Cflag << 31) | (Op2 >> 1);
} else if (instr.dataproc.operand2 & 0x10) {
// Register shifts. Types 4, 6, 8, and 10
//
// Get the shift value from the least-significant byte of the
// shift register.
shift = Register[instr.dpshr.rs] & 0xFF;
switch(instr.dpshr.bits) {
case 0x1: // 4 Logical shift left by register
if (shift >= 32)
Op2 = 0;
else
Op2 = Op2 << shift;
break;
case 0x3: // 6 Logical shift right by register
if (shift >= 32)
Op2 = 0;
else
Op2 = Op2 >> shift;
break;
case 0x5: // 8 Arithmetic shift right by register
if (shift >= 32) {
if (Op2 & 0x80000000)
Op2 = 0xffffffff;
else
Op2 = 0;
} else
Op2 = (LONG)Op2 >> shift;
break;
case 0x7: // 10 Rotate right by register
if ((shift & 0xf) != 0)
Op2 = _lrotl(Op2, shift);
default:
break;
}
} else {
// Immediate shifts. Types 2, 3, 5, 7, and 9
//
// Get the shift value from the instruction.
shift = instr.dpshi.shift;
switch(instr.dpshi.bits) {
case 0x0: // 2,3 Register, Logical shift left by immediate
if (shift != 0)
Op2 = Op2 << shift;
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -