📄 shunwind.c
字号:
/*++
Copyright (c) 1997-2000 Microsoft Corporation. All rights reserved.
Module Name:
shunwind.c
Abstract:
This module implements the unwinding of procedure call frames for
exception processing on Hitachi SH-3 & SH-4.
--*/
#include "kernel.h"
#include "shxinst.h"
#define sp 0xf /* register 15 */
// The saved registers are the permanent general registers (ie. those
// that get restored in the epilog)
#define SAVED_INTEGER_MASK 0x0000ff00 /* saved integer registers */
#define IS_REGISTER_SAVED(Register) ((SAVED_INTEGER_MASK >> Register) & 1L)
#if SH4
#define SAVED_FLOATING_MASK 0x0000f000 /* saved floating pt registers */
#define IS_FLOAT_REGISTER_SAVED(Register) \
((SAVED_FLOATING_MASK >> Register) & 1L)
#define FR_MASK 0x00200000 /* masks FR bit in fpscr */
#define SZ_MASK 0x00100000 /* masks SZ bit in fpscr */
#define PR_MASK 0x00080000 /* masks PR bit in fpscr */
#endif
ULONG
RtlVirtualUnwind(
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.
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
specified function.
ContextRecord - Supplies the address of a context record.
InFunction - Supplies a pointer to a variable that receives whether the
control PC is within the current function.
EstablisherFrame - Supplies a pointer to a variable that receives the
the establisher frame pointer value.
ContextPointers - Supplies an optional pointer to a context pointers
record.
Return Value:
The address where control left the previous frame is returned as the
function value.
--*/
{
ULONG Address;
ULONG TemporaryValue;
ULONG TemporaryRegister;
SH3IW Instruction;
USHORT instrProlog;
PULONG IntegerRegister;
#if SH4
PULONG FloatingRegister;
#endif
ULONG NextPc;
ULONG Offset;
ULONG Rm;
ULONG Rn;
LONG PendingValue;
BOOL PendingAdd;
ULONG PendingSource;
ULONG PendingTarget;
IntegerRegister = &ContextRecord->R0;
NextPc = ContextRecord->PR - 2;
*InFunction = FALSE;
#if SH4
// We assume FR bit always 0 in prolog.
FloatingRegister = ContextRecord->FRegs;
#endif
// If we are at the end of the function, and the delay slot instruction
// is one of the following, then just execute the instruction...
// MOV Rm,sp
// ADD Rm,sp
// ADD #imm,sp
// MOV.L @sp+,Rn
// For SH4:
// FSCHG
// FMOV.S @sp+,FRn
// There is no need reverse execute the prolog, because the epilog has
// already taken care of restoring all the other permanent registers.
instrProlog = *(PUSHORT)ControlPc;
if (instrProlog == RTS) {
ControlPc += 2;
Instruction = *(PSH3IW)ControlPc;
// MOV Rm,sp
if ((Instruction.instr3.opcode == 0x6) &&
(Instruction.instr3.ext_disp == 0x3)) {
Rm = Instruction.instr3.regM;
Rn = Instruction.instr3.regN;
if (Rn == sp)
IntegerRegister[sp] = IntegerRegister[Rm];
}
// ADD Rm,sp
else if ((Instruction.instr3.opcode == 0x3) &&
(Instruction.instr3.ext_disp == 0xc)) {
Rm = Instruction.instr3.regM;
Rn = Instruction.instr3.regN;
if (Rn == sp)
IntegerRegister[sp] += IntegerRegister[Rm];
}
// ADD #imm,sp
//
// Note: the offset added to sp will always be positive...
else if (Instruction.instr2.opcode == 0x7) {
Rn = Instruction.instr2.reg;
Offset = Instruction.instr2.imm_disp;
if (Rn == sp)
IntegerRegister[sp] += Offset;
}
// MOV.L @sp+,Rn
else if ((Instruction.instr3.opcode == 0x6) &&
(Instruction.instr3.ext_disp == 0x6)) {
Rm = Instruction.instr3.regM;
Rn = Instruction.instr3.regN;
if ((Rm == sp) && IS_REGISTER_SAVED(Rn)) {
IntegerRegister[Rn] = *(PULONG)IntegerRegister[sp];
IntegerRegister[sp] += 4;
}
}
#if SH4
// FMOV.S @sp+, FRn
else if ((Instruction.instr3.opcode == 0xf) &&
(Instruction.instr3.ext_disp == 0x9) &&
(Instruction.instr3.regM == sp)) {
Rn = Instruction.instr3.regN;
if (IS_FLOAT_REGISTER_SAVED(Rn)) {
FloatingRegister[Rn] = *(PULONG)IntegerRegister[sp];
IntegerRegister[sp] += 4;
}
}
// FSCHG
else if (Instruction.instr6.opcode == 0xf3fd) {
ContextRecord->Fpscr ^= SZ_MASK; // toggle the SZ bit
}
#endif
*EstablisherFrame = ContextRecord->R15;
return NextPc;
}
#if SH4
// Always expect FR and PR bits to be 0 throughout the prolog
ContextRecord->Fpscr &= ~(FR_MASK | PR_MASK);
#endif
// If the address where control left the specified function is outside
// the limits of the prologue, then the control PC is considered to be
// within the function and the control address is set to the end of
// the prologue. Otherwise, the control PC is not considered to be
// within the function (i.e., it is within the prologue).
if ((ControlPc < FunctionEntry->BeginAddress) ||
(ControlPc >= FunctionEntry->PrologEndAddress)) {
*InFunction = TRUE;
ControlPc = FunctionEntry->PrologEndAddress;
#if SH4
// Always expect SZ bit to be 0 at end of prolog
ContextRecord->Fpscr &= ~(SZ_MASK);
#endif
}
// Scan backward through the prologue and reload callee registers that
// were stored.
//
// Cannot initialize holding registers to 0 because that is a valid
// register value...
PendingSource = (ULONG)-1;
TemporaryRegister = (ULONG)-1;
while (ControlPc > FunctionEntry->BeginAddress) {
ControlPc -= 2;
Instruction = *(PSH3IW)ControlPc;
// MOV #imm,Rn
if (Instruction.instr2.opcode == 0xe) {
Rn = Instruction.instr2.reg;
if (Rn == PendingSource) {
PendingValue = (signed char)Instruction.instr2.imm_disp;
if (PendingAdd) {
PendingValue = -PendingValue;
}
IntegerRegister[PendingTarget] += PendingValue;
}
}
// MOV Rm,Rn
else if ((Instruction.instr3.opcode == 0x6) &&
(Instruction.instr3.ext_disp == 0x3)) {
Rm = Instruction.instr3.regM;
Rn = Instruction.instr3.regN;
IntegerRegister[Rm] = IntegerRegister[Rn];
}
// MOV.L Rm,@-sp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -