VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/PATMAll.cpp@ 46543

Last change on this file since 46543 was 46165, checked in by vboxsync, 11 years ago

Made dSYM-bundle loading work as well as line numbers in the stack traces (when possible).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 21.0 KB
Line 
1/* $Id: PATMAll.cpp 46165 2013-05-19 19:07:50Z vboxsync $ */
2/** @file
3 * PATM - The Patch Manager, all contexts.
4 */
5
6/*
7 * Copyright (C) 2006-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_PATM
22#include <VBox/vmm/patm.h>
23#include <VBox/vmm/cpum.h>
24#include <VBox/vmm/em.h>
25#include <VBox/vmm/hm.h>
26#include <VBox/vmm/selm.h>
27#include <VBox/vmm/mm.h>
28#include "PATMInternal.h"
29#include <VBox/vmm/vm.h>
30#include <VBox/vmm/vmm.h>
31#include "PATMA.h"
32
33#include <VBox/dis.h>
34#include <VBox/disopcode.h>
35#include <VBox/err.h>
36#include <VBox/log.h>
37#include <iprt/assert.h>
38
39
40/**
41 * Load virtualized flags.
42 *
43 * This function is called from CPUMRawEnter(). It doesn't have to update the
44 * IF and IOPL eflags bits, the caller will enforce those to set and 0 respectively.
45 *
46 * @param pVM Pointer to the VM.
47 * @param pCtxCore The cpu context core.
48 * @see pg_raw
49 */
50VMM_INT_DECL(void) PATMRawEnter(PVM pVM, PCPUMCTXCORE pCtxCore)
51{
52 Assert(!HMIsEnabled(pVM));
53
54 /*
55 * Currently we don't bother to check whether PATM is enabled or not.
56 * For all cases where it isn't, IOPL will be safe and IF will be set.
57 */
58 uint32_t efl = pCtxCore->eflags.u32;
59 CTXSUFF(pVM->patm.s.pGCState)->uVMFlags = efl & PATM_VIRTUAL_FLAGS_MASK;
60
61 AssertMsg((efl & X86_EFL_IF) || PATMShouldUseRawMode(pVM, (RTRCPTR)pCtxCore->eip),
62 ("X86_EFL_IF is clear and PATM is disabled! (eip=%RRv eflags=%08x fPATM=%d pPATMGC=%RRv-%RRv\n",
63 pCtxCore->eip, pCtxCore->eflags.u32, PATMIsEnabled(pVM), pVM->patm.s.pPatchMemGC,
64 pVM->patm.s.pPatchMemGC + pVM->patm.s.cbPatchMem));
65
66 AssertReleaseMsg(CTXSUFF(pVM->patm.s.pGCState)->fPIF || PATMIsPatchGCAddr(pVM, pCtxCore->eip),
67 ("fPIF=%d eip=%RRv\n", pVM->patm.s.CTXSUFF(pGCState)->fPIF, pCtxCore->eip));
68
69 efl &= ~PATM_VIRTUAL_FLAGS_MASK;
70 efl |= X86_EFL_IF;
71 pCtxCore->eflags.u32 = efl;
72
73#ifdef IN_RING3
74# ifdef PATM_EMULATE_SYSENTER
75 PCPUMCTX pCtx;
76
77 /* Check if the sysenter handler has changed. */
78 pCtx = CPUMQueryGuestCtxPtr(pVM);
79 if ( pCtx->SysEnter.cs != 0
80 && pCtx->SysEnter.eip != 0
81 )
82 {
83 if (pVM->patm.s.pfnSysEnterGC != (RTRCPTR)pCtx->SysEnter.eip)
84 {
85 pVM->patm.s.pfnSysEnterPatchGC = 0;
86 pVM->patm.s.pfnSysEnterGC = 0;
87
88 Log2(("PATMRawEnter: installing sysenter patch for %RRv\n", pCtx->SysEnter.eip));
89 pVM->patm.s.pfnSysEnterPatchGC = PATMR3QueryPatchGCPtr(pVM, pCtx->SysEnter.eip);
90 if (pVM->patm.s.pfnSysEnterPatchGC == 0)
91 {
92 rc = PATMR3InstallPatch(pVM, pCtx->SysEnter.eip, PATMFL_SYSENTER | PATMFL_CODE32);
93 if (rc == VINF_SUCCESS)
94 {
95 pVM->patm.s.pfnSysEnterPatchGC = PATMR3QueryPatchGCPtr(pVM, pCtx->SysEnter.eip);
96 pVM->patm.s.pfnSysEnterGC = (RTRCPTR)pCtx->SysEnter.eip;
97 Assert(pVM->patm.s.pfnSysEnterPatchGC);
98 }
99 }
100 else
101 pVM->patm.s.pfnSysEnterGC = (RTRCPTR)pCtx->SysEnter.eip;
102 }
103 }
104 else
105 {
106 pVM->patm.s.pfnSysEnterPatchGC = 0;
107 pVM->patm.s.pfnSysEnterGC = 0;
108 }
109# endif /* PATM_EMULATE_SYSENTER */
110#endif
111}
112
113
114/**
115 * Restores virtualized flags.
116 *
117 * This function is called from CPUMRawLeave(). It will update the eflags register.
118 *
119 ** @note Only here we are allowed to switch back to guest code (without a special reason such as a trap in patch code)!!
120 *
121 * @param pVM Pointer to the VM.
122 * @param pCtxCore The cpu context core.
123 * @param rawRC Raw mode return code
124 * @see @ref pg_raw
125 */
126VMM_INT_DECL(void) PATMRawLeave(PVM pVM, PCPUMCTXCORE pCtxCore, int rawRC)
127{
128 Assert(!HMIsEnabled(pVM));
129 bool fPatchCode = PATMIsPatchGCAddr(pVM, pCtxCore->eip);
130
131 /*
132 * We will only be called if PATMRawEnter was previously called.
133 */
134 uint32_t efl = pCtxCore->eflags.u32;
135 efl = (efl & ~PATM_VIRTUAL_FLAGS_MASK) | (CTXSUFF(pVM->patm.s.pGCState)->uVMFlags & PATM_VIRTUAL_FLAGS_MASK);
136 pCtxCore->eflags.u32 = efl;
137 CTXSUFF(pVM->patm.s.pGCState)->uVMFlags = X86_EFL_IF;
138
139 AssertReleaseMsg((efl & X86_EFL_IF) || fPatchCode || rawRC == VINF_PATM_PENDING_IRQ_AFTER_IRET || RT_FAILURE(rawRC), ("Inconsistent state at %RRv rc=%Rrc\n", pCtxCore->eip, rawRC));
140 AssertReleaseMsg(CTXSUFF(pVM->patm.s.pGCState)->fPIF || fPatchCode || RT_FAILURE(rawRC), ("fPIF=%d eip=%RRv rc=%Rrc\n", CTXSUFF(pVM->patm.s.pGCState)->fPIF, pCtxCore->eip, rawRC));
141
142#ifdef IN_RING3
143 if ( (efl & X86_EFL_IF)
144 && fPatchCode)
145 {
146 if ( rawRC < VINF_PATM_LEAVE_RC_FIRST
147 || rawRC > VINF_PATM_LEAVE_RC_LAST)
148 {
149 /*
150 * Golden rules:
151 * - Don't interrupt special patch streams that replace special instructions
152 * - Don't break instruction fusing (sti, pop ss, mov ss)
153 * - Don't go back to an instruction that has been overwritten by a patch jump
154 * - Don't interrupt an idt handler on entry (1st instruction); technically incorrect
155 *
156 */
157 if (CTXSUFF(pVM->patm.s.pGCState)->fPIF == 1) /* consistent patch instruction state */
158 {
159 PATMTRANSSTATE enmState;
160 RTRCPTR pOrgInstrGC = PATMR3PatchToGCPtr(pVM, pCtxCore->eip, &enmState);
161
162 AssertRelease(pOrgInstrGC);
163
164 Assert(enmState != PATMTRANS_OVERWRITTEN);
165 if (enmState == PATMTRANS_SAFE)
166 {
167 Assert(!patmFindActivePatchByEntrypoint(pVM, pOrgInstrGC));
168 Log(("Switchback from %RRv to %RRv (Psp=%x)\n", pCtxCore->eip, pOrgInstrGC, CTXSUFF(pVM->patm.s.pGCState)->Psp));
169 STAM_COUNTER_INC(&pVM->patm.s.StatSwitchBack);
170 pCtxCore->eip = pOrgInstrGC;
171 fPatchCode = false; /* to reset the stack ptr */
172
173 CTXSUFF(pVM->patm.s.pGCState)->GCPtrInhibitInterrupts = 0; /* reset this pointer; safe otherwise the state would be PATMTRANS_INHIBITIRQ */
174 }
175 else
176 {
177 LogFlow(("Patch address %RRv can't be interrupted (state=%d)!\n", pCtxCore->eip, enmState));
178 STAM_COUNTER_INC(&pVM->patm.s.StatSwitchBackFail);
179 }
180 }
181 else
182 {
183 LogFlow(("Patch address %RRv can't be interrupted (fPIF=%d)!\n", pCtxCore->eip, CTXSUFF(pVM->patm.s.pGCState)->fPIF));
184 STAM_COUNTER_INC(&pVM->patm.s.StatSwitchBackFail);
185 }
186 }
187 }
188#else /* !IN_RING3 */
189 /*
190 * When leaving raw-mode state while IN_RC, it's generally for interpreting
191 * a single original guest instruction.
192 */
193 AssertMsg(!fPatchCode, ("eip=%RRv\n", pCtxCore->eip));
194#endif /* !IN_RING3 */
195
196 if (!fPatchCode)
197 {
198 if (CTXSUFF(pVM->patm.s.pGCState)->GCPtrInhibitInterrupts == (RTRCPTR)pCtxCore->eip)
199 {
200 EMSetInhibitInterruptsPC(VMMGetCpu0(pVM), pCtxCore->eip);
201 }
202 CTXSUFF(pVM->patm.s.pGCState)->GCPtrInhibitInterrupts = 0;
203
204 /* Reset the stack pointer to the top of the stack. */
205#ifdef DEBUG
206 if (CTXSUFF(pVM->patm.s.pGCState)->Psp != PATM_STACK_SIZE)
207 {
208 LogFlow(("PATMRawLeave: Reset PATM stack (Psp = %x)\n", CTXSUFF(pVM->patm.s.pGCState)->Psp));
209 }
210#endif
211 CTXSUFF(pVM->patm.s.pGCState)->Psp = PATM_STACK_SIZE;
212 }
213}
214
215/**
216 * Get the EFLAGS.
217 * This is a worker for CPUMRawGetEFlags().
218 *
219 * @returns The eflags.
220 * @param pVM Pointer to the VM.
221 * @param pCtxCore The context core.
222 */
223VMM_INT_DECL(uint32_t) PATMRawGetEFlags(PVM pVM, PCCPUMCTXCORE pCtxCore)
224{
225 Assert(!HMIsEnabled(pVM));
226 uint32_t efl = pCtxCore->eflags.u32;
227 efl &= ~PATM_VIRTUAL_FLAGS_MASK;
228 efl |= pVM->patm.s.CTXSUFF(pGCState)->uVMFlags & PATM_VIRTUAL_FLAGS_MASK;
229 return efl;
230}
231
232/**
233 * Updates the EFLAGS.
234 * This is a worker for CPUMRawSetEFlags().
235 *
236 * @param pVM Pointer to the VM.
237 * @param pCtxCore The context core.
238 * @param efl The new EFLAGS value.
239 */
240VMM_INT_DECL(void) PATMRawSetEFlags(PVM pVM, PCPUMCTXCORE pCtxCore, uint32_t efl)
241{
242 Assert(!HMIsEnabled(pVM));
243 pVM->patm.s.CTXSUFF(pGCState)->uVMFlags = efl & PATM_VIRTUAL_FLAGS_MASK;
244 efl &= ~PATM_VIRTUAL_FLAGS_MASK;
245 efl |= X86_EFL_IF;
246 pCtxCore->eflags.u32 = efl;
247}
248
249/**
250 * Check if we must use raw mode (patch code being executed)
251 *
252 * @param pVM Pointer to the VM.
253 * @param pAddrGC Guest context address
254 */
255VMM_INT_DECL(bool) PATMShouldUseRawMode(PVM pVM, RTRCPTR pAddrGC)
256{
257 return ( PATMIsEnabled(pVM)
258 && ((pAddrGC >= (RTRCPTR)pVM->patm.s.pPatchMemGC && pAddrGC < (RTRCPTR)((RTRCUINTPTR)pVM->patm.s.pPatchMemGC + pVM->patm.s.cbPatchMem)))) ? true : false;
259}
260
261/**
262 * Returns the guest context pointer and size of the GC context structure
263 *
264 * @returns VBox status code.
265 * @param pVM Pointer to the VM.
266 */
267VMM_INT_DECL(RCPTRTYPE(PPATMGCSTATE)) PATMGetGCState(PVM pVM)
268{
269 AssertReturn(!HMIsEnabled(pVM), NIL_RTRCPTR);
270 return pVM->patm.s.pGCStateGC;
271}
272
273/**
274 * Checks whether the GC address is part of our patch region
275 *
276 * @returns VBox status code.
277 * @param pVM Pointer to the VM.
278 * @param pAddrGC Guest context address
279 * @internal
280 */
281VMMDECL(bool) PATMIsPatchGCAddr(PVM pVM, RTRCUINTPTR pAddrGC)
282{
283 return (PATMIsEnabled(pVM) && pAddrGC - (RTRCUINTPTR)pVM->patm.s.pPatchMemGC < pVM->patm.s.cbPatchMem) ? true : false;
284}
285
286/**
287 * Set parameters for pending MMIO patch operation
288 *
289 * @returns VBox status code.
290 * @param pDevIns Device instance.
291 * @param GCPhys MMIO physical address
292 * @param pCachedData GC pointer to cached data
293 */
294VMM_INT_DECL(int) PATMSetMMIOPatchInfo(PVM pVM, RTGCPHYS GCPhys, RTRCPTR pCachedData)
295{
296 if (!HMIsEnabled(pVM))
297 {
298 pVM->patm.s.mmio.GCPhys = GCPhys;
299 pVM->patm.s.mmio.pCachedData = (RTRCPTR)pCachedData;
300 }
301
302 return VINF_SUCCESS;
303}
304
305/**
306 * Checks if the interrupt flag is enabled or not.
307 *
308 * @returns true if it's enabled.
309 * @returns false if it's disabled.
310 *
311 * @param pVM Pointer to the VM.
312 * @todo CPUM should wrap this, EM.cpp shouldn't call us.
313 */
314VMM_INT_DECL(bool) PATMAreInterruptsEnabled(PVM pVM)
315{
316 PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(VMMGetCpu(pVM));
317
318 return PATMAreInterruptsEnabledByCtxCore(pVM, CPUMCTX2CORE(pCtx));
319}
320
321/**
322 * Checks if the interrupt flag is enabled or not.
323 *
324 * @returns true if it's enabled.
325 * @returns false if it's disabled.
326 *
327 * @param pVM Pointer to the VM.
328 * @param pCtxCore CPU context
329 * @todo CPUM should wrap this, EM.cpp shouldn't call us.
330 */
331VMM_INT_DECL(bool) PATMAreInterruptsEnabledByCtxCore(PVM pVM, PCPUMCTXCORE pCtxCore)
332{
333 if (PATMIsEnabled(pVM))
334 {
335 Assert(!HMIsEnabled(pVM));
336 if (PATMIsPatchGCAddr(pVM, pCtxCore->eip))
337 return false;
338 }
339 return !!(pCtxCore->eflags.u32 & X86_EFL_IF);
340}
341
342/**
343 * Check if the instruction is patched as a duplicated function
344 *
345 * @returns patch record
346 * @param pVM Pointer to the VM.
347 * @param pInstrGC Guest context point to the instruction
348 *
349 */
350PPATMPATCHREC patmQueryFunctionPatch(PVM pVM, RTRCPTR pInstrGC)
351{
352 PPATMPATCHREC pRec;
353
354 AssertCompile(sizeof(AVLOU32KEY) == sizeof(pInstrGC));
355 pRec = (PPATMPATCHREC)RTAvloU32Get(&CTXSUFF(pVM->patm.s.PatchLookupTree)->PatchTree, (AVLOU32KEY)pInstrGC);
356 if ( pRec
357 && (pRec->patch.uState == PATCH_ENABLED)
358 && (pRec->patch.flags & (PATMFL_DUPLICATE_FUNCTION|PATMFL_CALLABLE_AS_FUNCTION))
359 )
360 return pRec;
361 return 0;
362}
363
364/**
365 * Checks if the int 3 was caused by a patched instruction
366 *
367 * @returns VBox status
368 *
369 * @param pVM Pointer to the VM.
370 * @param pInstrGC Instruction pointer
371 * @param pOpcode Original instruction opcode (out, optional)
372 * @param pSize Original instruction size (out, optional)
373 */
374VMM_INT_DECL(bool) PATMIsInt3Patch(PVM pVM, RTRCPTR pInstrGC, uint32_t *pOpcode, uint32_t *pSize)
375{
376 PPATMPATCHREC pRec;
377 Assert(!HMIsEnabled(pVM));
378
379 pRec = (PPATMPATCHREC)RTAvloU32Get(&CTXSUFF(pVM->patm.s.PatchLookupTree)->PatchTree, (AVLOU32KEY)pInstrGC);
380 if ( pRec
381 && (pRec->patch.uState == PATCH_ENABLED)
382 && (pRec->patch.flags & (PATMFL_INT3_REPLACEMENT|PATMFL_INT3_REPLACEMENT_BLOCK))
383 )
384 {
385 if (pOpcode) *pOpcode = pRec->patch.opcode;
386 if (pSize) *pSize = pRec->patch.cbPrivInstr;
387 return true;
388 }
389 return false;
390}
391
392/**
393 * Emulate sysenter, sysexit and syscall instructions
394 *
395 * @returns VBox status
396 *
397 * @param pVM Pointer to the VM.
398 * @param pCtxCore The relevant core context.
399 * @param pCpu Disassembly context
400 */
401VMMDECL(int) PATMSysCall(PVM pVM, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu)
402{
403 PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(VMMGetCpu0(pVM));
404 AssertReturn(!HMIsEnabled(pVM), VERR_PATM_HM_IPE);
405
406 if (pCpu->pCurInstr->uOpcode == OP_SYSENTER)
407 {
408 if ( pCtx->SysEnter.cs == 0
409 || pRegFrame->eflags.Bits.u1VM
410 || (pRegFrame->cs.Sel & X86_SEL_RPL) != 3
411 || pVM->patm.s.pfnSysEnterPatchGC == 0
412 || pVM->patm.s.pfnSysEnterGC != (RTRCPTR)(RTRCUINTPTR)pCtx->SysEnter.eip
413 || !(PATMRawGetEFlags(pVM, pRegFrame) & X86_EFL_IF))
414 goto end;
415
416 Log2(("PATMSysCall: sysenter from %RRv to %RRv\n", pRegFrame->eip, pVM->patm.s.pfnSysEnterPatchGC));
417 /** @todo the base and limit are forced to 0 & 4G-1 resp. We assume the selector is wide open here. */
418 /** @note The Intel manual suggests that the OS is responsible for this. */
419 pRegFrame->cs.Sel = (pCtx->SysEnter.cs & ~X86_SEL_RPL) | 1;
420 pRegFrame->eip = /** @todo ugly conversion! */(uint32_t)pVM->patm.s.pfnSysEnterPatchGC;
421 pRegFrame->ss.Sel = pRegFrame->cs.Sel + 8; /* SysEnter.cs + 8 */
422 pRegFrame->esp = pCtx->SysEnter.esp;
423 pRegFrame->eflags.u32 &= ~(X86_EFL_VM | X86_EFL_RF);
424 pRegFrame->eflags.u32 |= X86_EFL_IF;
425
426 /* Turn off interrupts. */
427 pVM->patm.s.CTXSUFF(pGCState)->uVMFlags &= ~X86_EFL_IF;
428
429 STAM_COUNTER_INC(&pVM->patm.s.StatSysEnter);
430
431 return VINF_SUCCESS;
432 }
433 if (pCpu->pCurInstr->uOpcode == OP_SYSEXIT)
434 {
435 if ( pCtx->SysEnter.cs == 0
436 || (pRegFrame->cs.Sel & X86_SEL_RPL) != 1
437 || pRegFrame->eflags.Bits.u1VM
438 || !(PATMRawGetEFlags(pVM, pRegFrame) & X86_EFL_IF))
439 goto end;
440
441 Log2(("PATMSysCall: sysexit from %RRv to %RRv\n", pRegFrame->eip, pRegFrame->edx));
442
443 pRegFrame->cs.Sel = ((pCtx->SysEnter.cs + 16) & ~X86_SEL_RPL) | 3;
444 pRegFrame->eip = pRegFrame->edx;
445 pRegFrame->ss.Sel = pRegFrame->cs.Sel + 8; /* SysEnter.cs + 24 */
446 pRegFrame->esp = pRegFrame->ecx;
447
448 STAM_COUNTER_INC(&pVM->patm.s.StatSysExit);
449
450 return VINF_SUCCESS;
451 }
452 if (pCpu->pCurInstr->uOpcode == OP_SYSCALL)
453 {
454 /** @todo implement syscall */
455 }
456 else
457 if (pCpu->pCurInstr->uOpcode == OP_SYSRET)
458 {
459 /** @todo implement sysret */
460 }
461
462end:
463 return VINF_EM_RAW_RING_SWITCH;
464}
465
466/**
467 * Adds branch pair to the lookup cache of the particular branch instruction
468 *
469 * @returns VBox status
470 * @param pVM Pointer to the VM.
471 * @param pJumpTableGC Pointer to branch instruction lookup cache
472 * @param pBranchTarget Original branch target
473 * @param pRelBranchPatch Relative duplicated function address
474 */
475int patmAddBranchToLookupCache(PVM pVM, RTRCPTR pJumpTableGC, RTRCPTR pBranchTarget, RTRCUINTPTR pRelBranchPatch)
476{
477 PPATCHJUMPTABLE pJumpTable;
478
479 Log(("PATMAddBranchToLookupCache: Adding (%RRv->%RRv (%RRv)) to table %RRv\n", pBranchTarget, pRelBranchPatch + pVM->patm.s.pPatchMemGC, pRelBranchPatch, pJumpTableGC));
480
481 AssertReturn(PATMIsPatchGCAddr(pVM, (RTRCUINTPTR)pJumpTableGC), VERR_INVALID_PARAMETER);
482
483#ifdef IN_RC
484 pJumpTable = (PPATCHJUMPTABLE) pJumpTableGC;
485#else
486 pJumpTable = (PPATCHJUMPTABLE) (pJumpTableGC - pVM->patm.s.pPatchMemGC + pVM->patm.s.pPatchMemHC);
487#endif
488 Log(("Nr addresses = %d, insert pos = %d\n", pJumpTable->cAddresses, pJumpTable->ulInsertPos));
489 if (pJumpTable->cAddresses < pJumpTable->nrSlots)
490 {
491 uint32_t i;
492
493 for (i=0;i<pJumpTable->nrSlots;i++)
494 {
495 if (pJumpTable->Slot[i].pInstrGC == 0)
496 {
497 pJumpTable->Slot[i].pInstrGC = pBranchTarget;
498 /* Relative address - eases relocation */
499 pJumpTable->Slot[i].pRelPatchGC = pRelBranchPatch;
500 pJumpTable->cAddresses++;
501 break;
502 }
503 }
504 AssertReturn(i < pJumpTable->nrSlots, VERR_INTERNAL_ERROR);
505#ifdef VBOX_WITH_STATISTICS
506 STAM_COUNTER_INC(&pVM->patm.s.StatFunctionLookupInsert);
507 if (pVM->patm.s.StatU32FunctionMaxSlotsUsed < i)
508 pVM->patm.s.StatU32FunctionMaxSlotsUsed = i + 1;
509#endif
510 }
511 else
512 {
513 /* Replace an old entry. */
514 /** @todo replacement strategy isn't really bright. change to something better if required. */
515 Assert(pJumpTable->ulInsertPos < pJumpTable->nrSlots);
516 Assert((pJumpTable->nrSlots & 1) == 0);
517
518 pJumpTable->ulInsertPos &= (pJumpTable->nrSlots-1);
519 pJumpTable->Slot[pJumpTable->ulInsertPos].pInstrGC = pBranchTarget;
520 /* Relative address - eases relocation */
521 pJumpTable->Slot[pJumpTable->ulInsertPos].pRelPatchGC = pRelBranchPatch;
522
523 pJumpTable->ulInsertPos = (pJumpTable->ulInsertPos+1) & (pJumpTable->nrSlots-1);
524
525 STAM_COUNTER_INC(&pVM->patm.s.StatFunctionLookupReplace);
526 }
527
528 return VINF_SUCCESS;
529}
530
531
532#if defined(VBOX_WITH_STATISTICS) || defined(LOG_ENABLED)
533/**
534 * Return the name of the patched instruction
535 *
536 * @returns instruction name
537 *
538 * @param opcode DIS instruction opcode
539 * @param fPatchFlags Patch flags
540 */
541const char *patmGetInstructionString(uint32_t opcode, uint32_t fPatchFlags)
542{
543 const char *pszInstr = NULL;
544
545 switch (opcode)
546 {
547 case OP_CLI:
548 pszInstr = "cli";
549 break;
550 case OP_PUSHF:
551 pszInstr = "pushf";
552 break;
553 case OP_POPF:
554 pszInstr = "popf";
555 break;
556 case OP_STR:
557 pszInstr = "str";
558 break;
559 case OP_LSL:
560 pszInstr = "lsl";
561 break;
562 case OP_LAR:
563 pszInstr = "lar";
564 break;
565 case OP_SGDT:
566 pszInstr = "sgdt";
567 break;
568 case OP_SLDT:
569 pszInstr = "sldt";
570 break;
571 case OP_SIDT:
572 pszInstr = "sidt";
573 break;
574 case OP_SMSW:
575 pszInstr = "smsw";
576 break;
577 case OP_VERW:
578 pszInstr = "verw";
579 break;
580 case OP_VERR:
581 pszInstr = "verr";
582 break;
583 case OP_CPUID:
584 pszInstr = "cpuid";
585 break;
586 case OP_JMP:
587 pszInstr = "jmp";
588 break;
589 case OP_JO:
590 pszInstr = "jo";
591 break;
592 case OP_JNO:
593 pszInstr = "jno";
594 break;
595 case OP_JC:
596 pszInstr = "jc";
597 break;
598 case OP_JNC:
599 pszInstr = "jnc";
600 break;
601 case OP_JE:
602 pszInstr = "je";
603 break;
604 case OP_JNE:
605 pszInstr = "jne";
606 break;
607 case OP_JBE:
608 pszInstr = "jbe";
609 break;
610 case OP_JNBE:
611 pszInstr = "jnbe";
612 break;
613 case OP_JS:
614 pszInstr = "js";
615 break;
616 case OP_JNS:
617 pszInstr = "jns";
618 break;
619 case OP_JP:
620 pszInstr = "jp";
621 break;
622 case OP_JNP:
623 pszInstr = "jnp";
624 break;
625 case OP_JL:
626 pszInstr = "jl";
627 break;
628 case OP_JNL:
629 pszInstr = "jnl";
630 break;
631 case OP_JLE:
632 pszInstr = "jle";
633 break;
634 case OP_JNLE:
635 pszInstr = "jnle";
636 break;
637 case OP_JECXZ:
638 pszInstr = "jecxz";
639 break;
640 case OP_LOOP:
641 pszInstr = "loop";
642 break;
643 case OP_LOOPNE:
644 pszInstr = "loopne";
645 break;
646 case OP_LOOPE:
647 pszInstr = "loope";
648 break;
649 case OP_MOV:
650 if (fPatchFlags & PATMFL_IDTHANDLER)
651 pszInstr = "mov (Int/Trap Handler)";
652 else
653 pszInstr = "mov (cs)";
654 break;
655 case OP_SYSENTER:
656 pszInstr = "sysenter";
657 break;
658 case OP_PUSH:
659 pszInstr = "push (cs)";
660 break;
661 case OP_CALL:
662 pszInstr = "call";
663 break;
664 case OP_IRET:
665 pszInstr = "iret";
666 break;
667 }
668 return pszInstr;
669}
670#endif
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette