📄 mipsuwnd.c
字号:
/*++
Copyright (c) 1997-2000 Microsoft Corporation. All rights reserved.
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
#if defined(MIPS16SUPPORT)
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) 13 // store 9 callee-saved regs, store RA, subtract saved-reg and arg area
// size from SP, subtract local var area size from SP, and return
// = 13 instructions.
// Address of instruction adjacent to _pc: +/- 4 for MIPS32, +/- 2 for MIPS16
#define MIPS_PREV_INSTR(_pc) ((_pc) - (4 >> ((_pc) & 1)))
#define MIPS_NEXT_INSTR(_pc) ((_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
enum {
OP_NOP = 0,
OP_ADD,
OP_ADDI,
OP_SUB,
OP_OR,
OP_MOVE,
OP_IMM,
OP_STORE,
OP_FSTORE,
OP_DSTORE,
};
// Interpreter operation structure
typedef struct Operation {
BYTE Opcode;
BYTE Rd;
BYTE Rs;
BYTE Rt;
ULONG Imm;
} OPERATION, *POPERATION;
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;
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;
}
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 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);
}
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;
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 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) {
Op->Rd = NOREG;
Op++;
}
break;
case ADDIU_OP:
Op->Rd = Op->Rt;
if (Op->Rs == Op->Rt) {
Op->Opcode = OP_ADDI;
Op++;
} else if (Op->Rs == ZERO) {
Op->Opcode = OP_IMM;
Op++;
}
break;
case ORI_OP:
Op->Opcode = OP_IMM;
Op->Imm &= 0xffff;
Op->Rd = Op->Rt;
if (Op->Rs == Op->Rt) {
// Look for matching LUI
if (NotFirst && (Op-1)->Opcode == OP_IMM && (Op-1)->Rd == Op->Rd) {
(Op-1)->Imm |= Op->Imm;
} else {
Op++;
}
} else if (Op->Rs == ZERO) {
Op++;
}
break;
case SPEC_OP:
switch (I32.r_format.Function) {
case OR_OP:
Op->Opcode = OP_OR;
goto spec;
case ADDU_OP:
Op->Opcode = OP_ADD;
spec:
if (Op->Rs == ZERO) {
Op->Opcode = OP_MOVE;
Op->Rs = Op->Rt;
Op++;
} else if (Op->Rt == ZERO) {
Op->Opcode = OP_MOVE;
Op++;
} else if (Op->Rs == Op->Rd) {
Op++;
} else if (Op->Rt == Op->Rd) {
Op->Rt = Op->Rs;
Op++;
}
break;
case SUBU_OP:
if (Op->Rs == Op->Rd) {
Op->Opcode = OP_SUB;
Op++;
}
break;
}
break;
case LUI_OP:
Op->Opcode = OP_IMM;
Op->Imm <<= 16;
Op->Rd = Op->Rt;
Op++;
break;
}
return Op;
}
INT
BuildOps (
IN OUT POPERATION Operations,
IN INT Max,
IN ULONG Address,
IN ULONG EndAddress)
/*++
Routine Description
This function constructs an interpreter operation list based upon the machine
instructions found between a start and end address.
The code is smart enough to handle a single level of calls, this is required
if prolog helpers are being used.
Arguments
Operations - A pointer to an interpreter operation array to receive the translated
instructions.
Max - Size of the operation array.
Address - The address of the first instruction.
EndAddress - The address of the last instruction.
Return Value:
The number of operations generated.
--*/
{
MIPS16_INSTRUCTION I16;
MIPS_INSTRUCTION I32;
ULONG RetAddress = (ULONG) -1;
ULONG Extend = (ULONG) -1;
ULONG PCAddress = Address;
POPERATION Op = Operations;
POPERATION LastOp = Operations + Max;
while (Address != EndAddress && Op < LastOp) {
if (Address & 1) {
// Get MIPS16 instruction
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -