Logo Search packages:      
Sourcecode: virtualbox-ose version File versions

PATMInternal.h

Go to the documentation of this file.
/* $Id: PATMInternal.h 4071 2007-08-07 17:07:59Z vboxsync $ */
/** @file
 * PATM - Internal header file.
 */

/*
 * Copyright (C) 2006-2007 innotek GmbH
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License as published by the Free Software Foundation,
 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
 * distribution. VirtualBox OSE is distributed in the hope that it will
 * be useful, but WITHOUT ANY WARRANTY of any kind.
 */

#ifndef ___PATMInternal_h
#define ___PATMInternal_h

#include <VBox/cdefs.h>
#include <VBox/types.h>
#include <VBox/patm.h>
#include <VBox/stam.h>
#include <VBox/dis.h>
#include <iprt/avl.h>
#include <iprt/param.h>
#include <VBox/log.h>

#if !defined(IN_PATM_R3) && !defined(IN_PATM_R0) && !defined(IN_PATM_GC)
# error "Not in PATM! This is an internal header!"
#endif


#define PATM_SSM_VERSION                    53

/* Enable for call patching. */
#define PATM_ENABLE_CALL
#define PATCH_MEMORY_SIZE                  (2*1024*1024)
#define MAX_PATCH_SIZE                     (1024*4)

/*
 * Internal patch type flags (starts at BIT(11))
 */

#define PATMFL_CHECK_SIZE                   BIT64(11)
#define PATMFL_FOUND_PATCHEND               BIT64(12)
#define PATMFL_SINGLE_INSTRUCTION           BIT64(13)
#define PATMFL_SYSENTER_XP                  BIT64(14)
#define PATMFL_JUMP_CONFLICT                BIT64(15)
#define PATMFL_READ_ORIGINAL_BYTES          BIT64(16) /** opcode might have already been patched */
#define PATMFL_INT3_REPLACEMENT             BIT64(17)
#define PATMFL_SUPPORT_CALLS                BIT64(18)
#define PATMFL_SUPPORT_INDIRECT_CALLS       BIT64(19)
#define PATMFL_IDTHANDLER_WITHOUT_ENTRYPOINT BIT64(20) /** internal flag to avoid duplicate entrypoints */
#define PATMFL_INHIBIT_IRQS                 BIT64(21) /** temporary internal flag */
#define PATMFL_GENERATE_JUMPTOGUEST         BIT64(22) /** temporary internal flag */
#define PATMFL_RECOMPILE_NEXT               BIT64(23) /** for recompilation of the next instruction */
#define PATMFL_CODE_MONITORED               BIT64(24) /** code pages of guest monitored for self-modifying code. */
#define PATMFL_CALLABLE_AS_FUNCTION         BIT64(25) /** cli and pushf blocks can be used as callable functions. */
#define PATMFL_GLOBAL_FUNCTIONS             BIT64(26) /** fake patch for global patm functions. */
#define PATMFL_TRAMPOLINE                   BIT64(27) /** trampoline patch that clears PATM_INTERRUPTFLAG and jumps to patch destination */
#define PATMFL_GENERATE_SETPIF              BIT64(28) /** generate set PIF for the next instruction */
#define PATMFL_INSTR_HINT                   BIT64(29) /** Generate patch, but don't activate it. */
#define PATMFL_PATCHED_GUEST_CODE           BIT64(30) /** Patched guest code. */
#define PATMFL_MUST_INSTALL_PATCHJMP        BIT64(31) /** Need to patch guest code in order to activate patch. */
#define PATMFL_INT3_REPLACEMENT_BLOCK       BIT64(32) /** int 3 replacement block */
#define PATMFL_EXTERNAL_JUMP_INSIDE         BIT64(33) /** A trampoline patch was created that jumps to an instruction in the patch block */

#define SIZEOF_NEARJUMP8                   2 //opcode byte + 1 byte relative offset
#define SIZEOF_NEARJUMP16                  3 //opcode byte + 2 byte relative offset
#define SIZEOF_NEARJUMP32                  5 //opcode byte + 4 byte relative offset
#define SIZEOF_NEAR_COND_JUMP32            6 //0xF + opcode byte + 4 byte relative offset

#define MAX_INSTR_SIZE                     16

//Patch states
#define PATCH_REFUSED                     1
#define PATCH_DISABLED                    2
#define PATCH_ENABLED                     4
#define PATCH_UNUSABLE                    8
#define PATCH_DIRTY                       16
#define PATCH_DISABLE_PENDING             32


#define MAX_PATCH_TRAPS                    4
#define PATM_MAX_CALL_DEPTH                32
/* Maximum nr of writes before a patch is marked dirty. (disabled) */
#define PATM_MAX_CODE_WRITES               32
/* Maximum nr of invalid writes before a patch is disabled. */
#define PATM_MAX_INVALID_WRITES            16384

#define FIXUP_ABSOLUTE                     0
#define FIXUP_REL_JMPTOPATCH               1
#define FIXUP_REL_JMPTOGUEST               2

#define PATM_ILLEGAL_DESTINATION           0xDEADBEEF

/** Size of the instruction that's used for requests from patch code (currently only call) */
00100 #define PATM_ILLEGAL_INSTR_SIZE            2


/** No statistics counter index allocated just yet */
00104 #define PATM_STAT_INDEX_NONE                (uint32_t)-1
/** Dummy counter to handle overflows */
00106 #define PATM_STAT_INDEX_DUMMY               0
#define PATM_STAT_INDEX_IS_VALID(a)         (a != PATM_STAT_INDEX_DUMMY && a != PATM_STAT_INDEX_NONE)

#ifdef VBOX_WITH_STATISTICS
#define PATM_STAT_RUN_INC(pPatch)                                             \
        if (PATM_STAT_INDEX_IS_VALID((pPatch)->uPatchIdx))                \
            CTXSUFF(pVM->patm.s.pStats)[(pPatch)->uPatchIdx].u32A++;
#define PATM_STAT_FAULT_INC(pPatch)                                           \
        if (PATM_STAT_INDEX_IS_VALID((pPatch)->uPatchIdx))                \
            CTXSUFF(pVM->patm.s.pStats)[(pPatch)->uPatchIdx].u32B++;
#else
#define PATM_STAT_RUN_INC(pPatch)           do { } while (0)
#define PATM_STAT_FAULT_INC(pPatch)         do { } while (0)
#endif

/** Maximum number of stat counters. */
00122 #define PATM_STAT_MAX_COUNTERS              1024
/** Size of memory allocated for patch statistics. */
00124 #define PATM_STAT_MEMSIZE                   (PATM_STAT_MAX_COUNTERS*sizeof(STAMRATIOU32))


typedef struct
{
    /** The key is a HC virtual address. */
    AVLPVNODECORE   Core;

    uint32_t        uType;
    HCPTRTYPE(uint8_t *) pRelocPos;
    RTGCPTR         pSource;
    RTGCPTR         pDest;
} RELOCREC, *PRELOCREC;

typedef struct
{
    HCPTRTYPE(uint8_t *) pPatchLocStartHC;
    HCPTRTYPE(uint8_t *) pPatchLocEndHC;
    GCPTRTYPE(uint8_t *) pGuestLoc;
    uint32_t             opsize;
} P2GLOOKUPREC, *PP2GLOOKUPREC;

typedef struct
{
    /** The key is a pointer to a JUMPREC structure. */
    AVLPVNODECORE   Core;

    HCPTRTYPE(uint8_t *) pJumpHC;
    GCPTRTYPE(uint8_t *) pTargetGC;
    uint32_t            offDispl;
    uint32_t            opcode;
} JUMPREC, *PJUMPREC;

/**
 * Patch to guest lookup type (single or both direction)
 */
00160 typedef enum
{
    PATM_LOOKUP_PATCH2GUEST,    /* patch to guest */
    PATM_LOOKUP_BOTHDIR         /* guest to patch + patch to guest */
} PATM_LOOKUP_TYPE;

/**
 * Patch to guest address lookup record
 */
00169 typedef struct RECPATCHTOGUEST
{
    /** The key is an offset inside the patch memory block. */
00172     AVLU32NODECORE   Core;

    RTGCPTR          pOrgInstrGC;
    PATM_LOOKUP_TYPE enmType;
    bool             fDirty;
    bool             fJumpTarget;
    uint8_t          u8DirtyOpcode;  /* original opcode before writing 0xCC there to mark it dirty */
} RECPATCHTOGUEST, *PRECPATCHTOGUEST;

/**
 * Guest to patch address lookup record
 */
00184 typedef struct RECGUESTTOPATCH
{
    /** The key is a GC virtual address. */
00187     AVLGCPTRNODECORE    Core;

    /** Patch offset (relative to PATM::pPatchMemGC / PATM::pPatchMemHC). */
00190     uint32_t            PatchOffset;
} RECGUESTTOPATCH, *PRECGUESTTOPATCH;

/**
 * Temporary information used in ring 3 only; no need to waste memory in the patch record itself.
 */
00196 typedef struct
{
    /* Temporary tree for storing the addresses of illegal instructions. */
    HCPTRTYPE(PAVLPVNODECORE)   IllegalInstrTree;
    uint32_t                    nrIllegalInstr;

    int32_t                     nrJumps;
    uint32_t                    nrRetInstr;

    /* Temporary tree of encountered jumps. (debug only) */
    HCPTRTYPE(PAVLPVNODECORE)   DisasmJumpTree;

    int32_t                     nrCalls;

    /** Last original guest instruction pointer; used for disassmebly log. */
00211     RTGCPTR                     pLastDisasmInstrGC;

    /** Keeping track of multiple ret instructions. */
00214     RTGCPTR                     pPatchRetInstrGC;
    uint32_t                    uPatchRetParam1;
} PATCHINFOTEMP, *PPATCHINFOTEMP;

typedef struct _PATCHINFO
{
    uint32_t        uState;
    uint32_t        uOldState;
    uint32_t        uOpMode;

    GCPTRTYPE(uint8_t *)  pPrivInstrGC;    //GC pointer of privileged instruction
    HCPTRTYPE(uint8_t *)  pPrivInstrHC;    //HC pointer of privileged instruction
    uint8_t         aPrivInstr[MAX_INSTR_SIZE];
    uint32_t        cbPrivInstr;
    uint32_t        opcode;      //opcode for priv instr (OP_*)
    uint32_t        cbPatchJump; //patch jump size

    /* Only valid for PATMFL_JUMP_CONFLICT patches */
    RTGCPTR         pPatchJumpDestGC;

    RTGCUINTPTR     pPatchBlockOffset;
    uint32_t        cbPatchBlockSize;
    uint32_t        uCurPatchOffset;
#if HC_ARCH_BITS == 64
    uint32_t        Alignment0;         /**< Align flags correctly. */
#endif

    uint64_t        flags;

    /**
     * Lowest and highest patched GC instruction address. To optimize searches.
     */
    RTGCPTR                   pInstrGCLowest;
    RTGCPTR                   pInstrGCHighest;

    /* Tree of fixup records for the patch. */
    HCPTRTYPE(PAVLPVNODECORE) FixupTree;
    int32_t         nrFixups;

    /* Tree of jumps inside the generated patch code. */
    int32_t         nrJumpRecs;
    HCPTRTYPE(PAVLPVNODECORE) JumpTree;

    /**
     * Lookup trees for determining the corresponding guest address of an
     * instruction in the patch block.
     */
    HCPTRTYPE(PAVLU32NODECORE) Patch2GuestAddrTree;
    HCPTRTYPE(PAVLGCPTRNODECORE) Guest2PatchAddrTree;
    uint32_t                  nrPatch2GuestRecs;
#if HC_ARCH_BITS == 64
    uint32_t        Alignment1;
#endif

    // Cache record for PATMGCVirtToHCVirt
    P2GLOOKUPREC    cacheRec;

    /* Temporary information during patch creation. Don't waste hypervisor memory for this. */
    HCPTRTYPE(PPATCHINFOTEMP) pTempInfo;

    /* Count the number of writes to the corresponding guest code. */
    uint32_t        cCodeWrites;

    /* Count the number of invalid writes to pages monitored for the patch. */
    //some statistics to determine if we should keep this patch activated
    uint32_t        cTraps;

    uint32_t        cInvalidWrites;

    // Index into the uPatchRun and uPatchTrap arrays (0..MAX_PATCHES-1)
    uint32_t        uPatchIdx;

    /* First opcode byte, that's overwritten when a patch is marked dirty. */
    uint8_t         bDirtyOpcode;
    uint8_t         Alignment2[7];      /**< Align the structure size on a 8-byte boundrary. */
} PATCHINFO, *PPATCHINFO;

#define PATCHCODE_PTR_GC(pPatch)    (RTGCPTR)  (pVM->patm.s.pPatchMemGC + (pPatch)->pPatchBlockOffset)
#define PATCHCODE_PTR_HC(pPatch)    (uint8_t *)(pVM->patm.s.pPatchMemHC + (pPatch)->pPatchBlockOffset)

/**
 * Lookup record for patches
 */
00297 typedef struct PATMPATCHREC
{
    /** The key is a GC virtual address. */
00300     AVLOGCPTRNODECORE  Core;
    /** The key is a patch offset. */
00302     AVLOGCPTRNODECORE  CoreOffset;

    PATCHINFO  patch;
} PATMPATCHREC, *PPATMPATCHREC;

/** Increment for allocating room for pointer array */
00308 #define PATMPATCHPAGE_PREALLOC_INCREMENT        16

/**
 * Lookup record for patch pages
 */
00313 typedef struct PATMPATCHPAGE
{
    /** The key is a GC virtual address. */
00316     AVLOGCPTRNODECORE  Core;
    /** Region to monitor. */
00318     RTGCPTR            pLowestAddrGC;
    RTGCPTR            pHighestAddrGC;
    /** Number of patches for this page. */
00321     uint32_t           cCount;
    /** Maximum nr of pointers in the array. */
00323     uint32_t           cMaxPatches;
    /** Array of patch pointers for this page. */
    HCPTRTYPE(PPATCHINFO *) aPatch;
} PATMPATCHPAGE, *PPATMPATCHPAGE;

#define PATM_PATCHREC_FROM_COREOFFSET(a)  (PPATMPATCHREC)((uintptr_t)a - RT_OFFSETOF(PATMPATCHREC, CoreOffset))
#define PATM_PATCHREC_FROM_PATCHINFO(a)   (PPATMPATCHREC)((uintptr_t)a - RT_OFFSETOF(PATMPATCHREC, patch))

typedef struct PATMTREES
{
    /**
     * AVL tree with all patches (active or disabled) sorted by guest instruction address
     */
    AVLOGCPTRTREE           PatchTree;

    /**
     * AVL tree with all patches sorted by patch address (offset actually)
     */
    AVLOGCPTRTREE           PatchTreeByPatchAddr;

    /**
     * AVL tree with all pages which were (partly) patched
     */
    AVLOGCPTRTREE           PatchTreeByPage;

    uint32_t                align[1];
} PATMTREES, *PPATMTREES;

/**
 * PATM VM Instance data.
 * Changes to this must checked against the padding of the patm union in VM!
 */
00355 typedef struct PATM
{
    /** Offset to the VM structure.
     * See PATM2VM(). */
00359     RTINT                   offVM;

    GCPTRTYPE(uint8_t *)    pPatchMemGC;
    HCPTRTYPE(uint8_t *)    pPatchMemHC;
    uint32_t                cbPatchMem;
    uint32_t                offPatchMem;
    bool                    fOutOfMemory;

    int32_t                 deltaReloc;

    /* GC PATM state pointers */
    HCPTRTYPE(PPATMGCSTATE) pGCStateHC;
    GCPTRTYPE(PPATMGCSTATE) pGCStateGC;

    /** PATM stack page for call instruction execution. (2 parts: one for our private stack and one to store the original return address */
    GCPTRTYPE(RTGCPTR *)    pGCStackGC;
    HCPTRTYPE(RTGCPTR *)    pGCStackHC;

    /** GC pointer to CPUMCTX structure. */
    GCPTRTYPE(PCPUMCTX)     pCPUMCtxGC;

    /* GC statistics pointers */
    GCPTRTYPE(PSTAMRATIOU32) pStatsGC;
    HCPTRTYPE(PSTAMRATIOU32) pStatsHC;

    /* Current free index value (uPatchRun/uPatchTrap arrays). */
    uint32_t                uCurrentPatchIdx;

    /* Temporary counter for patch installation call depth. (in order not to go on forever) */
    uint32_t                ulCallDepth;

    /** Number of page lookup records. */
00391     uint32_t                cPageRecords;

    /**
     * Lowest and highest patched GC instruction addresses. To optimize searches.
     */
00396     RTGCPTR                   pPatchedInstrGCLowest;
    RTGCPTR                   pPatchedInstrGCHighest;

    /** Pointer to the patch tree for instructions replaced by 'int 3'. */
    GCPTRTYPE(PPATMTREES)   PatchLookupTreeGC;
    HCPTRTYPE(PPATMTREES)   PatchLookupTreeHC;

    /** Global PATM lookup and call function (used by call patches). */
00404     RTGCPTR                 pfnHelperCallGC;
    /** Global PATM return function (used by ret patches). */
00406     RTGCPTR                 pfnHelperRetGC;
    /** Global PATM jump function (used by indirect jmp patches). */
00408     RTGCPTR                 pfnHelperJumpGC;
    /** Global PATM return function (used by iret patches). */
00410     RTGCPTR                 pfnHelperIretGC;

    /** Fake patch record for global functions. */
    HCPTRTYPE(PPATMPATCHREC) pGlobalPatchRec;

    /** Pointer to original sysenter handler */
00416     RTGCPTR                 pfnSysEnterGC;
    /** Pointer to sysenter handler trampoline */
00418     RTGCPTR                 pfnSysEnterPatchGC;
    /** Sysenter patch index (for stats only) */
00420     uint32_t                uSysEnterPatchIdx;

    // GC address of fault in monitored page (set by PATMGCMonitorPage, used by PATMR3HandleMonitoredPage)
    RTGCPTR                 pvFaultMonitor;

    /* Temporary information for pending MMIO patch. Set in GC or R0 context. */
    struct
    {
        RTGCPHYS            GCPhys;
        RTGCPTR             pCachedData;
    } mmio;

    /* Temporary storage during load/save state */
    struct
    {
        HCPTRTYPE(PSSMHANDLE) pSSM;
        uint32_t            cPatches;
#if HC_ARCH_BITS == 64
        uint32_t            Alignment0; /**< Align the structure size on a 8-byte boundrary. */
#endif
    } savedstate;

    STAMCOUNTER             StatNrOpcodeRead;
    STAMCOUNTER             StatDisabled;
    STAMCOUNTER             StatUnusable;
    STAMCOUNTER             StatEnabled;
    STAMCOUNTER             StatInstalled;
    STAMCOUNTER             StatInstalledFunctionPatches;
    STAMCOUNTER             StatInstalledTrampoline;
    STAMCOUNTER             StatInstalledJump;
    STAMCOUNTER             StatInt3Callable;
    STAMCOUNTER             StatInt3BlockRun;
    STAMCOUNTER             StatOverwritten;
    STAMCOUNTER             StatFixedConflicts;
    STAMCOUNTER             StatFlushed;
    STAMCOUNTER             StatPageBoundaryCrossed;
    STAMCOUNTER             StatMonitored;
    STAMPROFILEADV          StatHandleTrap;
    STAMCOUNTER             StatSwitchBack;
    STAMCOUNTER             StatSwitchBackFail;
    STAMCOUNTER             StatPATMMemoryUsed;
    STAMCOUNTER             StatDuplicateREQSuccess;
    STAMCOUNTER             StatDuplicateREQFailed;
    STAMCOUNTER             StatDuplicateUseExisting;
    STAMCOUNTER             StatFunctionFound;
    STAMCOUNTER             StatFunctionNotFound;
    STAMPROFILEADV          StatPatchWrite;
    STAMPROFILEADV          StatPatchWriteDetect;
    STAMCOUNTER             StatDirty;
    STAMCOUNTER             StatPushTrap;
    STAMCOUNTER             StatPatchWriteInterpreted;
    STAMCOUNTER             StatPatchWriteInterpretedFailed;

    STAMCOUNTER             StatSysEnter;
    STAMCOUNTER             StatSysExit;
    STAMCOUNTER             StatEmulIret;
    STAMCOUNTER             StatEmulIretFailed;

    STAMCOUNTER             StatInstrDirty;
    STAMCOUNTER             StatInstrDirtyGood;
    STAMCOUNTER             StatInstrDirtyBad;

    STAMCOUNTER             StatPatchPageInserted;
    STAMCOUNTER             StatPatchPageRemoved;

    STAMCOUNTER             StatPatchRefreshSuccess;
    STAMCOUNTER             StatPatchRefreshFailed;

    STAMCOUNTER             StatGenRet;
    STAMCOUNTER             StatGenRetReused;
    STAMCOUNTER             StatGenJump;
    STAMCOUNTER             StatGenCall;
    STAMCOUNTER             StatGenPopf;

    STAMCOUNTER             StatCheckPendingIRQ;

    STAMCOUNTER             StatFunctionLookupReplace;
    STAMCOUNTER             StatFunctionLookupInsert;
    uint32_t                StatU32FunctionMaxSlotsUsed;
00499     uint32_t                Alignment0; /**< Align the structure size on a 8-byte boundrary. */
} PATM, *PPATM;


/**
 * Execute state save operation.
 *
 * @returns VBox status code.
 * @param   pVM             VM Handle.
 * @param   pSSM            SSM operation handle.
 */
DECLCALLBACK(int) patmr3Save(PVM pVM, PSSMHANDLE pSSM);


/**
 * Execute state load operation.
 *
 * @returns VBox status code.
 * @param   pVM             VM Handle.
 * @param   pSSM            SSM operation handle.
 * @param   u32Version      Data layout version.
 */
DECLCALLBACK(int) patmr3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version);

#ifdef IN_RING3
RTGCPTR patmPatchGCPtr2GuestGCPtr(PVM pVM, PPATCHINFO pPatch, GCPTRTYPE(uint8_t *) pPatchGC);
RTGCPTR patmGuestGCPtrToPatchGCPtr(PVM pVM, PPATCHINFO pPatch, GCPTRTYPE(uint8_t*) pInstrGC);
#endif

/* Add a patch to guest lookup record
 *
 * @param   pVM             The VM to operate on.
 * @param   pPatch          Patch structure ptr
 * @param   pPatchInstrHC   Guest context pointer to patch block
 * @param   pInstrGC        Guest context pointer to privileged instruction
 * @param   enmType         Lookup type
 * @param   fDirty          Dirty flag
 *
 */
void patmr3AddP2GLookupRecord(PVM pVM, PPATCHINFO pPatch, uint8_t *pPatchInstrHC, RTGCPTR pInstrGC, PATM_LOOKUP_TYPE enmType, bool fDirty=false);

/**
 * Insert page records for all guest pages that contain instructions that were recompiled for this patch
 *
 * @returns VBox status code.
 * @param   pVM         The VM to operate on.
 * @param   pPatch      Patch record
 */
int patmInsertPatchPages(PVM pVM, PPATCHINFO pPatch);

/**
 * Remove page records for all guest pages that contain instructions that were recompiled for this patch
 *
 * @returns VBox status code.
 * @param   pVM         The VM to operate on.
 * @param   pPatch      Patch record
 */
int patmRemovePatchPages(PVM pVM, PPATCHINFO pPatch);

/**
 * Returns the GC address of the corresponding patch statistics counter
 *
 * @returns Stat address
 * @param   pVM         The VM to operate on.
 * @param   pPatch      Patch structure
 */
RTGCPTR patmPatchQueryStatAddress(PVM pVM, PPATCHINFO pPatch);

/**
 * Remove patch for privileged instruction at specified location
 *
 * @returns VBox status code.
 * @param   pVM             The VM to operate on.
 * @param   pPatchRec       Patch record
 * @param   fForceRemove    Remove *all* patches
 */
int PATMRemovePatch(PVM pVM, PPATMPATCHREC pPatchRec, bool fForceRemove);

/**
 * Call for analysing the instructions following the privileged instr. for compliance with our heuristics
 *
 * @returns VBox status code.
 * @param   pVM         The VM to operate on.
 * @param   pCpu        CPU disassembly state
 * @param   pInstrHC    Guest context pointer to privileged instruction
 * @param   pCurInstrHC Guest context pointer to current instruction
 * @param   pUserData   User pointer
 *
 */
00588 typedef int (VBOXCALL *PFN_PATMR3ANALYSE)(PVM pVM, DISCPUSTATE *pCpu, GCPTRTYPE(uint8_t *) pInstrGC, GCPTRTYPE(uint8_t *) pCurInstrGC, void *pUserData);

/**
 * Install guest OS specific patch
 *
 * @returns VBox status code.
 * @param   pVM         The VM to operate on
 * @param   pCpu        Disassembly state of instruction.
 * @param   pInstrGC    GC Instruction pointer for instruction
 * @param   pInstrHC    GC Instruction pointer for instruction
 * @param   pPatchRec   Patch structure
 *
 */
int PATMInstallGuestSpecificPatch(PVM pVM, PDISCPUSTATE pCpu, RTGCPTR pInstrGC, uint8_t *pInstrHC, PPATMPATCHREC pPatchRec);

/**
 * Convert guest context address to host context pointer
 *
 * @returns VBox status code.
 * @param   pVM         The VM to operate on.
 * @param   pPatch      Patch block structure pointer
 * @param   pGCPtr      Guest context pointer
 *
 * @returns             Host context pointer or NULL in case of an error
 *
 */
HCPTRTYPE(uint8_t *) PATMGCVirtToHCVirt(PVM pVM, PPATCHINFO pPatch, GCPTRTYPE(uint8_t *) pGCPtr);


/**
 * Check if the instruction is patched as a duplicated function
 *
 * @returns patch record
 * @param   pVM         The VM to operate on.
 * @param   pInstrGC    Guest context point to the instruction
 *
 */
PATMDECL(PPATMPATCHREC) PATMQueryFunctionPatch(PVM pVM, RTGCPTR pInstrGC);


/**
 * Empty the specified tree (PV tree, MMR3 heap)
 *
 * @param   pVM             The VM to operate on.
 * @param   ppTree          Tree to empty
 */
void patmEmptyTree(PVM pVM, PPAVLPVNODECORE ppTree);


/**
 * Empty the specified tree (U32 tree, MMR3 heap)
 *
 * @param   pVM             The VM to operate on.
 * @param   ppTree          Tree to empty
 */
void patmEmptyTreeU32(PVM pVM, PPAVLU32NODECORE ppTree);


/**
 * Return the name of the patched instruction
 *
 * @returns instruction name
 *
 * @param   opcode      DIS instruction opcode
 * @param   fPatchFlags Patch flags
 */
PATMDECL(const char *) patmGetInstructionString(uint32_t opcode, uint32_t fPatchFlags);


/**
 * Read callback for disassembly function; supports reading bytes that cross a page boundary
 *
 * @returns VBox status code.
 * @param   pSrc        GC source pointer
 * @param   pDest       HC destination pointer
 * @param   size        Number of bytes to read
 * @param   dwUserdata  Callback specific user data (pCpu)
 *
 */
int32_t patmReadBytes(RTHCUINTPTR pSrc, uint8_t *pDest, uint32_t size, RTHCUINTPTR dwUserdata);


#ifndef IN_GC

#define PATMREAD_RAWCODE        1  /* read code as-is */
#define PATMREAD_ORGCODE        2  /* read original guest opcode bytes; not the patched bytes */
#define PATMREAD_NOCHECK        4  /* don't check for patch conflicts */

/*
 * Private structure used during disassembly
 */
typedef struct
{
    PVM           pVM;
    PPATCHINFO    pPatchInfo;
    HCPTRTYPE(uint8_t *) pInstrHC;
    RTGCPTR       pInstrGC;
    uint32_t      fReadFlags;
} PATMDISASM, *PPATMDISASM;

inline bool PATMR3DISInstr(PVM pVM, PPATCHINFO pPatch, DISCPUSTATE *pCpu, RTGCPTR InstrGC,
                           uint8_t *InstrHC, uint32_t *pOpsize, char *pszOutput,
                           uint32_t fReadFlags = PATMREAD_ORGCODE)
{
    PATMDISASM disinfo;
    disinfo.pVM    = pVM;
    disinfo.pPatchInfo = pPatch;
    disinfo.pInstrHC = InstrHC;
    disinfo.pInstrGC = InstrGC;
    disinfo.fReadFlags = fReadFlags;
    (pCpu)->pfnReadBytes  = patmReadBytes;
    (pCpu)->dwUserData[0] = (RTHCUINTPTR)&disinfo;
    return DISInstr(pCpu, InstrGC, 0, pOpsize, pszOutput);
}
#endif /* !IN_GC */

__BEGIN_DECLS
/**
 * #PF Virtual Handler callback for Guest access a page monitored by PATM
 *
 * @returns VBox status code (appropritate for trap handling and GC return).
 * @param   pVM         VM Handle.
 * @param   uErrorCode   CPU Error code.
 * @param   pRegFrame   Trap register frame.
 * @param   pvFault     The fault address (cr2).
 * @param   pvRange     The base address of the handled virtual range.
 * @param   offRange    The offset of the access into this range.
 *                      (If it's a EIP range this's the EIP, if not it's pvFault.)
 */
PATMGCDECL(int) PATMGCMonitorPage(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, void *pvFault, void *pvRange, uintptr_t offRange);

/**
 * Find patch for privileged instruction at specified location
 *
 * @returns Patch structure pointer if found; else NULL
 * @param   pVM           The VM to operate on.
 * @param   pInstr        Guest context point to instruction that might lie within 5 bytes of an existing patch jump
 * @param   fIncludeHints Include hinted patches or not
 *
 */
PPATCHINFO PATMFindActivePatchByEntrypoint(PVM pVM, RTGCPTR pInstrGC, bool fIncludeHints=false);

/**
 * Patch cli/sti pushf/popf instruction block at specified location
 *
 * @returns VBox status code.
 * @param   pVM         The VM to operate on.
 * @param   pInstrGC    Guest context point to privileged instruction
 * @param   pInstrHC    Host context point to privileged instruction
 * @param   uOpcode     Instruction opcodee
 * @param   uOpSize     Size of starting instruction
 * @param   pPatchRec   Patch record
 *
 * @note    returns failure if patching is not allowed or possible
 *
 */
PATMR3DECL(int) PATMR3PatchBlock(PVM pVM, RTGCPTR pInstrGC, HCPTRTYPE(uint8_t *) pInstrHC,
                                 uint32_t uOpcode, uint32_t uOpSize, PPATMPATCHREC pPatchRec);


/**
 * Replace an instruction with a breakpoint (0xCC), that is handled dynamically in the guest context.
 *
 * @returns VBox status code.
 * @param   pVM         The VM to operate on.
 * @param   pInstrGC    Guest context point to privileged instruction
 * @param   pInstrHC    Host context point to privileged instruction
 * @param   pCpu        Disassembly CPU structure ptr
 * @param   pPatch      Patch record
 *
 * @note    returns failure if patching is not allowed or possible
 *
 */
PATMR3DECL(int) PATMR3PatchInstrInt3(PVM pVM, RTGCPTR pInstrGC, HCPTRTYPE(uint8_t *) pInstrHC, DISCPUSTATE *pCpu, PPATCHINFO pPatch);

/**
 * Mark patch as dirty
 *
 * @returns VBox status code.
 * @param   pVM         The VM to operate on.
 * @param   pPatch      Patch record
 *
 * @note    returns failure if patching is not allowed or possible
 *
 */
PATMR3DECL(int) PATMR3MarkDirtyPatch(PVM pVM, PPATCHINFO pPatch);

/**
 * Calculate the branch destination
 *
 * @returns branch destination or 0 if failed
 * @param   pCpu            Disassembly state of instruction.
 * @param   pBranchInstrGC  GC pointer of branch instruction
 */
00782 inline RTGCPTR PATMResolveBranch(PDISCPUSTATE pCpu, RTGCPTR pBranchInstrGC)
{
    uint32_t disp;
    if (pCpu->param1.flags & USE_IMMEDIATE8_REL)
    {
        disp = (int32_t)(char)pCpu->param1.parval;
    }
    else
    if (pCpu->param1.flags & USE_IMMEDIATE16_REL)
    {
        disp = (int32_t)(uint16_t)pCpu->param1.parval;
    }
    else
    if (pCpu->param1.flags & USE_IMMEDIATE32_REL)
    {
        disp = (int32_t)pCpu->param1.parval;
    }
    else
    {
        Log(("We don't support far jumps here!! (%08X)\n", pCpu->param1.flags));
        return 0;
    }
#ifdef IN_GC
    return (RTGCPTR)((uint8_t *)pBranchInstrGC + pCpu->opsize + disp);
#else
    return pBranchInstrGC + pCpu->opsize + disp;
#endif
}

__END_DECLS

#ifdef DEBUG
int patmr3DisasmCallback(PVM pVM, DISCPUSTATE *pCpu, GCPTRTYPE(uint8_t *) pInstrGC, GCPTRTYPE(uint8_t *) pCurInstrGC, void *pUserData);
int patmr3DisasmCodeStream(PVM pVM, GCPTRTYPE(uint8_t *) pInstrGC, GCPTRTYPE(uint8_t *) pCurInstrGC, PFN_PATMR3ANALYSE pfnPATMR3Analyse, void *pUserData);
#endif

#endif

Generated by  Doxygen 1.6.0   Back to index