⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shunwind.c

📁 WinCE5.0部分核心源码
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// 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:
//      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




//------------------------------------------------------------------------------
//  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
RtlVirtualUnwind(
    IN ULONG ControlPc,
    IN PRUNTIME_FUNCTION FunctionEntry,
    IN OUT PCONTEXT ContextRecord,
    OUT PBOOLEAN InFunction,
    OUT PULONG EstablisherFrame,
    IN PPROCESS pprc
    )
{
    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;
    ULONG            pcOfst = ControlPc - (ULONG) ZeroPtr (ControlPc);
    ULONG            BeginAddress = FunctionEntry->BeginAddress;
    ULONG            PrologEndAddress = FunctionEntry->PrologEndAddress;

    IntegerRegister = &ContextRecord->R0;
    NextPc = ContextRecord->PR - 2;
    *InFunction = FALSE;

    // map slot 0 address to the process
    if (BeginAddress < (1 << VA_SECTION)) {
        BeginAddress += pcOfst;
        PrologEndAddress += pcOfst;
    }
    
#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;

        // TRAPA #1
        // Could a user insert a breakpoint in the delay slot of a function return?
        // And would we support such a bold move? Yes and Yes.
        if ((Instruction.instr5.opcode == 0xc3) &&
                (Instruction.instr5.imm_disp == 0x01)) {
            (*KDSanitize)((BYTE*)&Instruction, (void*)ControlPc, sizeof(Instruction), FALSE);
        }

        // 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 < BeginAddress) ||
            (ControlPc >= PrologEndAddress)) {
        *InFunction = TRUE;
        ControlPc = 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 > BeginAddress) {
        ControlPc -= 2;
        Instruction = *(PSH3IW)ControlPc;

        // TRAPA #1
        // Replace any breakpoints in the prolog with the instructions they replaced
        if ((Instruction.instr5.opcode == 0xc3) &&
                (Instruction.instr5.imm_disp == 0x01)) {
            (*KDSanitize)((BYTE*)&Instruction, (void*)ControlPc, sizeof(Instruction), FALSE);
        }

        // MOV #imm,Rn

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -