📄 mipsuwnd.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*++
Module Name:
mipsuwnd.c
Abstract:
This module implements the unwinding of procedure call frames for
exception processing on MIPS processors.
--*/
#include "kernel.h"
// Define stack register and zero register numbers.
#define RA 0x1f // integer register 31
#define SP 0x1d // integer register 29
#define ZERO 0x0 // integer register 0
#define NOREG -1 // invalid register number
extern PRUNTIME_FUNCTION NKLookupFunctionEntry(PPROCESS, ULONG, PRUNTIME_FUNCTION);
// Maximum number of instructions encoded by block with given start and end addresses
#define BYTES_TO_OPCOUNT(_begin, _end) (((_end) - (_begin)) >> (2 >> ((_end) & 1)))
// Op count of longest prologue helper function called from the current mode
#define MIPS_PROLHELPER_OPCOUNT(_pc) 14 // store 9 callee-saved regs, store RA, subtract saved-reg and arg area
// size from SP, subtract local var area size from SP, return, and return
// delay slot = 14 instructions.
// Address of instruction adjacent to _pc: +/- 4 for MIPS32, +/- 2 for MIPS16
#define MIPS_PREV_INSTR(_pc) (ULONG)((_pc) - (4 >> ((_pc) & 1)))
#define MIPS_NEXT_INSTR(_pc) (ULONG)((_pc) + (4 >> ((_pc) & 1)))
// MIPS16->MIPS32 register encoding conversion
#define FIX_MIPS16_REG(r) (((r) < 2) ? (r)+16 : (r))
// MIPS16 MOV32R register encoding
#define FIX_MOV32R_REG(r) (((r) >> 2) | (((r) & 0x3) << 3))
#define UNFIX_MOV32R_REG(r) (((r) << 2) | (((r) & 0x18) >> 3))
// MIPS16 instruction tests
#define IS_MIPS16_MOV32RSP(i) (((i) & 0xfff8) == ((I8_OP16 << 11) | (MOV32R_OP16 << 8) | (UNFIX_MOV32R_REG (SP) << 3)))
#define IS_MIPS16_ADDIUSP(i) (((i) & 0xff00) == ((I8_OP16 << 11) | (ADJSP_OP16 << 8)))
#define IS_MIPS16_JR(i) (((i) & 0xf8ff) == ((RR_OP16 << 11) | JR_OP16))
#define IS_MIPS16_JRRA(i) ((i) == ((RR_OP16 << 11) | (0x1 << 5) | JR_OP16))
#define IS_MIPS16_RETURN(i) (IS_MIPS16_JR(i) || IS_MIPS16_JRRA(i))
// MIPS32 instruction tests
#define IS_MIPS32_ADDIUSP(i) (((i) & 0xffff0000) == ((ADDIU_OP << 26) | (SP << 16) | (SP << 21)))
#define IS_MIPS32_ADDUSP(i) (((i) & 0xffe0ffff) == ((SPEC_OP << 26) | ADDU_OP | (SP << 11) | (SP << 21)))
#define IS_MIPS32_RETURN(i) ((i) == JUMP_RA)
// Interpreter opcodes
typedef enum Opcode {
OP_NOP = 0,
OP_ADD,
OP_ADDI,
OP_SUB,
OP_OR,
OP_MOVE,
OP_IMM,
OP_STORE,
OP_STORE64,
OP_FSTORE,
OP_DSTORE,
} OPCODE;
// Register names
typedef enum RegName {
none = NOREG,
zero = ZERO,
at,
v0, v1,
a0, a1, a2, a3,
t0, t1, t2, t3, t4, t5, t6, t7,
s0, s1, s2, s3, s4, s5, s6, s7,
t8, t9,
k0, k1,
gp,
sp,
s8,
ra
} REGNAME;
// Interpreter operation structure
typedef struct Operation {
OPCODE Opcode:CHAR_BIT;
REGNAME Rd:CHAR_BIT;
REGNAME Rs:CHAR_BIT;
REGNAME Rt:CHAR_BIT;
REG_TYPE Imm;
} OPERATION, *POPERATION;
static BOOL
IsScratchReg (
IN REGNAME regName)
/*++
Routine Description
Returns TRUE if the given register is used as a scratch register in the
prologue.
Arguments
regName - register index in question.
--*/
{
switch (regName)
{
case at:
case v0:
case v1:
case t0:
case t1:
case t2:
case t3:
case t4:
case t5:
case t6:
case t7:
case t8:
case t9:
return TRUE;
}
return FALSE;
}
static POPERATION
BuildSimpleOp16 (
IN OUT POPERATION Op,
IN ULONG Address,
IN ULONG PCAddress,
IN ULONG Extend)
/*++
Routine Description
This function converts a MIPS16 instruction at the specified address into the
equivalent interpreter instruction.
Arguments
Op - A pointer to an interpreter operation structure to receive the translated
opcode.
Address - The address of the MIPS16 instruction.
PCAddress - The PC value at execution time (PCAddress != Address when the
instruction is being executed in a delay slot).
Extend - The value of a previous EXTEND opcode immediate field. Set to -1
if the instruction is not extended.
--*/
{
MIPS16_INSTRUCTION Instruction;
ULONG UImm8, UImm5, SImm8;
Instruction.Short = *(PUSHORT) Address;
// Replace any break instruction introduced in the prolog
// by the debugger with its original instruction
if (Instruction.rr_format.Function == BREAK_OP16 &&
Instruction.rr_format.Opcode == RR_OP16) {
(*KDSanitize)((BYTE *)&Instruction.Short, (void *)(Address),
sizeof(Instruction.Short), FALSE);
}
UImm8 = Instruction.ri_format.Immediate << 2;
UImm5 = Instruction.rri_format.Immediate << 2;
SImm8 = Instruction.rsi_format.Simmediate;
if (Extend != (ULONG) -1) {
SImm8 = UImm8 = UImm5 = Extend | Instruction.rri_format.Immediate;
}
Op->Opcode = OP_NOP;
Op->Rt = Op->Rs = Op->Rd = NOREG;
switch (Instruction.i_format.Opcode) {
case LI_OP16:
Op->Opcode = OP_IMM;
Op->Rd = FIX_MIPS16_REG (Instruction.ri_format.Rx);
Op->Imm = Instruction.ri_format.Immediate;
if (Extend != (ULONG) -1) {
Op->Imm = (Extend | Instruction.rri_format.Immediate) & 0xFFFF;
}
break;
case SW_OP16:
Op->Opcode = OP_STORE;
Op->Rs = FIX_MIPS16_REG (Instruction.rri_format.Rx);
Op->Rt = FIX_MIPS16_REG (Instruction.rri_format.Ry);
Op->Imm = UImm5;
break;
case SWSP_OP16:
Op->Opcode = OP_STORE;
Op->Rs = SP;
Op->Rt = FIX_MIPS16_REG (Instruction.ri_format.Rx);
Op->Imm = UImm8;
break;
case LWPC_OP16:
Op->Opcode = OP_IMM;
Op->Rd = FIX_MIPS16_REG (Instruction.ri_format.Rx);
Op->Imm = *(PULONG) ((PCAddress & ~3) + UImm8);
break;
case ADDIU8_OP16:
Op->Opcode = OP_ADDI;
Op->Rs = Op->Rd = FIX_MIPS16_REG (Instruction.ri_format.Rx);
Op->Imm = SImm8;
break;
case ADDIUSP_OP16:
Op->Opcode = OP_ADDI;
Op->Rd = FIX_MIPS16_REG (Instruction.ri_format.Rx);
Op->Rs = SP;
Op->Imm = UImm8;
break;
case RRR_OP16:
Op->Rd = FIX_MIPS16_REG (Instruction.rrr_format.Rz);
Op->Rs = FIX_MIPS16_REG (Instruction.rrr_format.Rx);
Op->Rt = FIX_MIPS16_REG (Instruction.rrr_format.Ry);
if (Op->Rs != Op->Rd) break;
switch (Instruction.rrr_format.Function) {
case SUBU_OP16:
Op->Opcode = OP_SUB;
break;
case ADDU_OP16:
Op->Opcode = OP_ADD;
break;
}
break;
case I8_OP16:
switch (Instruction.i8_format.Function) {
case SWRASP_OP16:
Op->Opcode = OP_STORE;
Op->Rs = SP;
Op->Rt = RA;
Op->Imm = UImm8;
break;
case ADJSP_OP16:
Op->Opcode = OP_ADDI;
Op->Rs = Op->Rd = SP;
Op->Imm = SImm8;
if (Extend == (ULONG) -1) {
Op->Imm = SImm8 << 3;
}
break;
case MOV32R_OP16:
Op->Opcode = OP_MOVE;
Op->Rd = FIX_MOV32R_REG (Instruction.mov32r_format.R32);
Op->Rs = FIX_MIPS16_REG (Instruction.mov32r_format.Rz);
break;
case MOVR32_OP16:
Op->Opcode = OP_MOVE;
Op->Rd = FIX_MIPS16_REG (Instruction.movr32_format.Ry);
Op->Rs = (BYTE) Instruction.movr32_format.R32;
break;
}
break;
default:
break;
}
return Op + (Op->Opcode != OP_NOP);
}
static POPERATION
BuildSimpleOp32 (
IN OUT POPERATION Op,
IN ULONG Address,
IN BOOLEAN NotFirst)
/*++
Routine Description
This function converts a MIPS32 instruction at the specified address into the
equivalent interpreter instruction. It will attempt to compress LUI-ORI pairs
into a single OP_IMM operation.
Arguments
Op - A pointer to an interpreter operation structure to receive the translated
opcode.
Address - The address of the MIPS32 instruction.
NotFirst - True if this is not the first Op in the list, to tell LUI-ORI
compression to look at the previous operation at Op-1.
--*/
{
MIPS_INSTRUCTION I32;
I32.Long = *(PULONG) Address;
// Replace any break instruction introduced in the prolog
// by the debugger with its original instruction
if (I32.r_format.Function == BREAK_OP &&
I32.r_format.Opcode == SPEC_OP) {
(*KDSanitize)((BYTE *)&I32.Long, (void *)Address, sizeof(I32.Long), FALSE);
}
Op->Rs = (BYTE) I32.i_format.Rs;
Op->Rt = (BYTE) I32.i_format.Rt;
Op->Rd = (BYTE) I32.r_format.Rd;
Op->Imm = I32.i_format.Simmediate;
switch (I32.i_format.Opcode) {
case SD_OP:
Op->Opcode = OP_STORE64;
goto store;
case SW_OP:
Op->Opcode = OP_STORE;
goto store;
case SWC1_OP:
Op->Opcode = OP_FSTORE;
goto store;
case SDC1_OP:
Op->Opcode = OP_DSTORE;
store:
if (Op->Rs == SP) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -