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

📄 unwind.c

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

Abstract:
    This module implements the unwinding of procedure call frames for
    exception processing.
--*/

#include "kernel.h"
#include "arminst.h"
#include <stdlib.h>

extern
ULONG
ThumbVirtualUnwind(
                   IN ULONG ControlPc,
                   IN PRUNTIME_FUNCTION FunctionEntry,
                   IN OUT PCONTEXT Context,
                   OUT PBOOLEAN InFunction,
                   OUT PULONG EstablisherFrame
                  );
//
// Prototypes for local functions:
//
BOOL CheckConditionCodes(ULONG CPSR, DWORD instr);
BOOL UnwindLoadMultiple(ARMI instr, PULONG Register);
void UnwindDataProcess(ARMI instr, PULONG Register);
BOOL UnwindLoadI(ARMI instr, PULONG Register);
ULONG ArmVirtualUnwind(IN ULONG ControlPc,
                       IN PRUNTIME_FUNCTION FunctionEntry,
                       IN OUT PCONTEXT Context,
                       OUT PBOOLEAN InFunction,
                       OUT PULONG EstablisherFrame );


//------------------------------------------------------------------------------
//  
//  Routine Description:
//      The function reads the user process's memory for the unwinder.  The
//      access is protected via try/except.
//  
//  Arguments:
//  
//      src - ptr to source data
//      dest - ptr to destination buffer
//      length - number of bytes to copy
//  
//  Return Value:
//  
//      TRUE - if able to access memory OK
//      FALSE - if exception while accessing user memory
//  
//------------------------------------------------------------------------------
BOOL 
ReadMemory(
    void *src,
    void *dest,
    int length
    )
{
    __try {

        memcpy(dest, src, length);
        return TRUE;

    } __except (1) {
    }
    return FALSE;
}


//------------------------------------------------------------------------------
//  
//  Routine Description:
//      The function reads the user process's memory for the unwinder.  The
//      access is protected via try/except.  The returned memory is "santized",
//      all debugger inserted breakpoints are restored to the original instruction.
//  
//  Arguments:
//  
//      src - ptr to source data
//      dest - ptr to destination buffer
//      length - number of bytes to copy
//  
//  Return Value:
//  
//      TRUE - if able to access memory OK
//      FALSE - if exception while accessing user memory
//  
//------------------------------------------------------------------------------
BOOL 
ReadMemorySanitized(
    void *src,
    void *dest,
    int length
    )
{
    if (ReadMemory(src, dest, length)) {
        (*KDSanitize)((BYTE *)dest, src, length, FALSE);
        return TRUE;
    }
    return FALSE;
}


//------------------------------------------------------------------------------
//
//  Routine Description:
//      This function virtually unwinds the specfified function by executing its
//      prologue code backwards (or its epilog forward).
//  
//      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 special instruction in the prologue indicates the fault instruction
//      address.
//  
//  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.
//  
//  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 Context,
    OUT PBOOLEAN InFunction,
    OUT PULONG EstablisherFrame,
    IN PPROCESS pprc
    )
{
    //
    //  This function is simply a passthrough which dispatches to the correct
    //  unwinder for the processor mode at the current unwind point.
    //

    if (ControlPc & 0x01) {                    // Thumb Mode
        return ThumbVirtualUnwind(ControlPc,
                                  FunctionEntry,
                                  Context,
                                  InFunction,
                                  EstablisherFrame
                                  );

    }

    return ArmVirtualUnwind(ControlPc,
                            FunctionEntry,
                            Context,
                            InFunction,
                            EstablisherFrame
                            );
}



//------------------------------------------------------------------------------
//  
//  Routine Description:
//  
//      This is the ARM specific implementation of RtlVirtualUnwind
//  
//  Arguments:
//  
//      See RtlVirtualUnwind
//  
//  Return Value:
//  
//      See RtlVirtualUnwind
//  
//------------------------------------------------------------------------------
ULONG
ArmVirtualUnwind(
    IN ULONG ControlPc,
    IN PRUNTIME_FUNCTION FunctionEntry,
    IN OUT PCONTEXT Context,
    OUT PBOOLEAN InFunction,
    OUT PULONG EstablisherFrame
    )
{
    ULONG   Address;
    LONG    cb;
    DWORD   NextPc;
    BOOLEAN HaveExceptionPc;
    BOOLEAN ExecutingEpilog;
    LONG    i,j;
    ARMI    instr, instr2;
    ARMI    Prolog[15];
    PULONG  Register;
    ULONG   pcOfst = ControlPc - (ULONG) ZeroPtr (ControlPc);
    ULONG   BeginAddress = FunctionEntry->BeginAddress;
    ULONG   PrologEndAddress = FunctionEntry->PrologEndAddress;

    
    // NOTE:  When unwinding the call stack, we assume that all instructions
    // in the prolog have the condition code "Always execute."  This is not
    // necessarily true for the epilog.

    DEBUGMSG(ZONE_SEH, (TEXT("Unwind: Pc=%8.8x Begin=%8.8x PrologEnd=%8.8x End=%8.8x\r\n"),
        ControlPc, BeginAddress, PrologEndAddress,
        FunctionEntry->EndAddress));

    Register = &Context->R0;
    *InFunction = FALSE;
    
    if (PrologEndAddress == BeginAddress) {
        // No prolog.
        *EstablisherFrame = Register[13];
        return Register[14] - 4;
    }

    // map slot 0 address to the process
    if (BeginAddress < (1 << VA_SECTION)) {
        BeginAddress += pcOfst;
        PrologEndAddress += pcOfst;
    }
    
    // First check to see if we are in the epilog.  If so, forward execution
    // through the end of the epilog is required.  Epilogs are composed of the
    // following:
    //
    // An ldmdb which uses the frame pointer, R11, as the base and updates
    // the PC.
    //
    // -or-
    //
    // A stack unlink (ADD R13, x) if necessary, followed by an ldmia which
    // updates the PC or a single mov instruction to copy the link register
    // to the PC
    //
    // -or-
    //
    // An ldmia which updates the link register, followed by a regular
    // branch instruction.  (This is an optimization when the last instruction
    // before a return is a call.)
    //
    // A routine may also have an empty epilog.  (The last instruction is to
    // branch to another routine, and it doesn't modify any permanent
    // registers.)  But, in this case, we would also have an empty prolog.
    //
    // If we are in an epilog, and the condition codes dictate that the
    // instructions should not be executed, treat this as not an epilog at all.
    
    if (ControlPc >= PrologEndAddress) {
        DWORD   EpilogPc = ControlPc;
        DEBUGMSG(ZONE_SEH, (TEXT("Checking epilog @%8.8x\r\n"), EpilogPc));
        // Check the condition code of the first instruction. If it won't be
        // executed, don't bother checking what type of instruction it is.
        if (!ReadMemorySanitized((PVOID)EpilogPc, &instr, 4))
            return ControlPc;
        
        ExecutingEpilog = CheckConditionCodes(Register[16], instr.instruction);
        while (ExecutingEpilog) {
            if (!ReadMemorySanitized((PVOID)EpilogPc, &instr, 4))
                return ControlPc;

            DEBUGMSG(ZONE_SEH, (TEXT("executing epilog @%8.8x\r\n"), EpilogPc));

            // Test for these instructions:
            //      ADD R13, X - stack unlink
            //
            //      MOV PC, LR - return
            //
            //      LDMIA or LDMDB including PC - update registers and return
            //      (SP)   (FP)
            //
            //      LDMIA including LR, followed by a branch
            //          Update registers and branch. (In our case, return.)
            //
            //      A branch preceded by an LDMIA including LR
            //          Copy the LR to the PC to get the call stack
            
            if ((instr.instruction & ADD_SP_MASK) == ADD_SP_INSTR) {
                UnwindDataProcess(instr, Register);
                
            } else if ((instr.instruction & MOV_PC_LR_MASK) == MOV_PC_LR) {
                instr.dataproc.rd = 14; // don't damage Pc value for Unwinder
                UnwindDataProcess(instr, Register);
                *EstablisherFrame = Register[13];
                return Register[14] - 4;
                
            } else if ((instr.instruction & LDM_PC_MASK) == LDM_PC_INSTR) {
                ulong SavePc = Register[15];
                if (!UnwindLoadMultiple(instr, Register))
                    return ControlPc;
                ControlPc = Register[15];
                Register[15] = SavePc;
                *EstablisherFrame = Register[13];
                return ControlPc - 4;
                
            } else if ((instr.instruction & LDM_LR_MASK) == LDM_LR_INSTR) {

⌨️ 快捷键说明

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