VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/PATMR3Dbg.cpp@ 46159

Last change on this file since 46159 was 46159, checked in by vboxsync, 12 years ago

Patch manager support in the disassembler, making the 'u' command in the debugger always show unpatched instruction and annoate those instructions which have patches associated with them (in any state).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.1 KB
Line 
1/* $Id: PATMR3Dbg.cpp 46159 2013-05-18 19:56:08Z vboxsync $ */
2/** @file
3 * PATM - Dynamic Guest OS Patching Manager, Debugger Related Parts.
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/dbgf.h>
24#include <VBox/vmm/hm.h>
25#include "PATMInternal.h"
26#include "PATMA.h"
27#include <VBox/vmm/vm.h>
28#include <VBox/err.h>
29#include <VBox/log.h>
30
31#include <iprt/assert.h>
32#include <iprt/dbg.h>
33#include <iprt/string.h>
34
35
36/*******************************************************************************
37* Defined Constants And Macros *
38*******************************************************************************/
39/** Adds a structure member to a debug (pseudo) module as a symbol. */
40#define ADD_MEMBER(a_hDbgMod, a_Struct, a_Member, a_pszName) \
41 do { \
42 rc = RTDbgModSymbolAdd(hDbgMod, a_pszName, 0 /*iSeg*/, RT_OFFSETOF(a_Struct, a_Member), \
43 RT_SIZEOFMEMB(a_Struct, a_Member), 0 /*fFlags*/, NULL /*piOrdinal*/); \
44 AssertRC(rc); \
45 } while (0)
46
47/** Adds a structure member to a debug (pseudo) module as a symbol. */
48#define ADD_FUNC(a_hDbgMod, a_BaseRCPtr, a_FuncRCPtr, a_cbFunc, a_pszName) \
49 do { \
50 int rcAddFunc = RTDbgModSymbolAdd(hDbgMod, a_pszName, 0 /*iSeg*/, \
51 (RTRCUINTPTR)a_FuncRCPtr - (RTRCUINTPTR)(a_BaseRCPtr), \
52 a_cbFunc, 0 /*fFlags*/, NULL /*piOrdinal*/); \
53 AssertRC(rcAddFunc); \
54 } while (0)
55
56
57
58/**
59 * Called by PATMR3Init.
60 *
61 * @param pVM The cross context VM structure.
62 */
63void patmR3DbgInit(PVM pVM)
64{
65 pVM->patm.s.hDbgModPatchMem = NIL_RTDBGMOD;
66}
67
68
69/**
70 * Called by PATMR3Term.
71 *
72 * @param pVM The cross context VM structure.
73 */
74void patmR3DbgTerm(PVM pVM)
75{
76 if (pVM->patm.s.hDbgModPatchMem != NIL_RTDBGMOD)
77 {
78 RTDbgModRelease(pVM->patm.s.hDbgModPatchMem);
79 pVM->patm.s.hDbgModPatchMem = NIL_RTDBGMOD;
80 }
81}
82
83
84/**
85 * Called by when the patch memory is reinitialized.
86 *
87 * @param pVM The cross context VM structure.
88 */
89void patmR3DbgReset(PVM pVM)
90{
91 if (pVM->patm.s.hDbgModPatchMem != NIL_RTDBGMOD)
92 {
93 RTDbgModRemoveAll(pVM->patm.s.hDbgModPatchMem, true);
94 }
95}
96
97
98static size_t patmR3DbgDescribePatchAsSymbol(PPATMPATCHREC pPatchRec, char *pszName, size_t cbLeft)
99{
100 char * const pszNameStart = pszName;
101#define ADD_SZ(a_sz) \
102 do { \
103 if (cbLeft >= sizeof(a_sz)) \
104 { \
105 memcpy(pszName, a_sz, sizeof(a_sz)); \
106 pszName += sizeof(a_sz) - 1; \
107 cbLeft -= sizeof(a_sz) - 1;\
108 }\
109 } while (0)
110
111 /* Start the name off with the address of the guest code. */
112 size_t cch = RTStrPrintf(pszName, cbLeft, "Patch_%#08x", pPatchRec->patch.pPrivInstrGC);
113 cbLeft -= cch;
114 pszName += cch;
115
116 /* Append flags. */
117 uint64_t fFlags = pPatchRec->patch.flags;
118 if (fFlags & PATMFL_INTHANDLER)
119 ADD_SZ("_IntHandler");
120 if (fFlags & PATMFL_SYSENTER)
121 ADD_SZ("_SysEnter");
122 if (fFlags & PATMFL_GUEST_SPECIFIC)
123 ADD_SZ("_GuestSpecific");
124 if (fFlags & PATMFL_USER_MODE)
125 ADD_SZ("_UserMode");
126 if (fFlags & PATMFL_IDTHANDLER)
127 ADD_SZ("_IdtHnd");
128 if (fFlags & PATMFL_TRAPHANDLER)
129 ADD_SZ("_TrapHnd");
130 if (fFlags & PATMFL_DUPLICATE_FUNCTION)
131 ADD_SZ("_DupFunc");
132 if (fFlags & PATMFL_REPLACE_FUNCTION_CALL)
133 ADD_SZ("_ReplFunc");
134 if (fFlags & PATMFL_TRAPHANDLER_WITH_ERRORCODE)
135 ADD_SZ("_TrapHndErrCd");
136 if (fFlags & PATMFL_MMIO_ACCESS)
137 ADD_SZ("_MmioAccess");
138 if (fFlags & PATMFL_SYSENTER_XP)
139 ADD_SZ("_SysEnterXP");
140 if (fFlags & PATMFL_INT3_REPLACEMENT)
141 ADD_SZ("_Int3Repl");
142 if (fFlags & PATMFL_SUPPORT_CALLS)
143 ADD_SZ("_SupCalls");
144 if (fFlags & PATMFL_SUPPORT_INDIRECT_CALLS)
145 ADD_SZ("_SupIndirCalls");
146 if (fFlags & PATMFL_IDTHANDLER_WITHOUT_ENTRYPOINT)
147 ADD_SZ("_IdtHandlerWE");
148 if (fFlags & PATMFL_INHIBIT_IRQS)
149 ADD_SZ("_InhibitIrqs");
150 if (fFlags & PATMFL_RECOMPILE_NEXT)
151 ADD_SZ("_RecompileNext");
152 if (fFlags & PATMFL_CALLABLE_AS_FUNCTION)
153 ADD_SZ("_Callable");
154 if (fFlags & PATMFL_TRAMPOLINE)
155 ADD_SZ("_Trampoline");
156 if (fFlags & PATMFL_PATCHED_GUEST_CODE)
157 ADD_SZ("_PatchedGuestCode");
158 if (fFlags & PATMFL_MUST_INSTALL_PATCHJMP)
159 ADD_SZ("_MustInstallPatchJmp");
160 if (fFlags & PATMFL_INT3_REPLACEMENT_BLOCK)
161 ADD_SZ("_Int3ReplBlock");
162 if (fFlags & PATMFL_EXTERNAL_JUMP_INSIDE)
163 ADD_SZ("_ExtJmp");
164 if (fFlags & PATMFL_CODE_REFERENCED)
165 ADD_SZ("_CodeRefed");
166
167 return pszName - pszNameStart;
168}
169
170
171/**
172 * Called when a new patch is added or when first populating the address space.
173 *
174 * @param pVM The cross context VM structure.
175 * @param pPatchRec The patch record.
176 */
177void patmR3DbgAddPatch(PVM pVM, PPATMPATCHREC pPatchRec)
178{
179 if ( pVM->patm.s.hDbgModPatchMem != NIL_RTDBGMOD
180 && pPatchRec->patch.pPatchBlockOffset > 0
181 && !(pPatchRec->patch.flags & PATMFL_GLOBAL_FUNCTIONS))
182 {
183 /** @todo find a cheap way of checking whether we've already added the patch.
184 * Using a flag would be nice, except I don't want to consider saved
185 * state considerations right now (I don't recall if we're still
186 * depending on structure layout there or not). */
187 char szName[256];
188 size_t off = patmR3DbgDescribePatchAsSymbol(pPatchRec, szName, sizeof(szName));
189
190 /* If we have a symbol near the guest address, append that. */
191 if (off + 8 <= sizeof(szName))
192 {
193 DBGFSYMBOL Symbol;
194 RTGCINTPTR offDisp;
195
196 int rc = DBGFR3SymbolByAddr(pVM, pPatchRec->patch.pPrivInstrGC, &offDisp, &Symbol);
197 if (RT_SUCCESS(rc))
198 {
199 szName[off++] = '_';
200 szName[off++] = '_';
201 RTStrCopy(&szName[off], sizeof(szName) - off, Symbol.szName);
202 }
203 }
204
205 /* Add it (may fail due to enable/disable patches). */
206 RTDbgModSymbolAdd(pVM->patm.s.hDbgModPatchMem, szName, 0 /*iSeg*/,
207 pPatchRec->patch.pPatchBlockOffset,
208 pPatchRec->patch.cbPatchBlockSize,
209 0 /*fFlags*/, NULL /*piOrdinal*/);
210 }
211}
212
213
214/**
215 * Enumeration callback used by patmR3DbgAddPatches
216 *
217 * @returns 0 (continue enum)
218 * @param pNode The patch record node.
219 * @param pvUser The cross context VM structure.
220 */
221static DECLCALLBACK(int) patmR3DbgAddPatchCallback(PAVLOU32NODECORE pNode, void *pvUser)
222{
223 patmR3DbgAddPatch((PVM)pvUser, (PPATMPATCHREC)pNode);
224 return 0;
225}
226
227
228/**
229 * Populates an empty "patches" (hDbgModPatchMem) module with patch symbols.
230 *
231 * @param pVM The cross context VM structure.
232 * @param hDbgMod The debug module handle.
233 */
234static void patmR3DbgAddPatches(PVM pVM, RTDBGMOD hDbgMod)
235{
236 /*
237 * Global functions.
238 */
239 ADD_FUNC(hDbgMod, pVM->patm.s.pPatchMemGC, pVM->patm.s.pfnHelperCallGC, PATMLookupAndCallRecord.size, "PATMLookupAndCall");
240 ADD_FUNC(hDbgMod, pVM->patm.s.pPatchMemGC, pVM->patm.s.pfnHelperRetGC, PATMRetFunctionRecord.size, "PATMRetFunction");
241 ADD_FUNC(hDbgMod, pVM->patm.s.pPatchMemGC, pVM->patm.s.pfnHelperJumpGC, PATMLookupAndJumpRecord.size, "PATMLookupAndJump");
242 ADD_FUNC(hDbgMod, pVM->patm.s.pPatchMemGC, pVM->patm.s.pfnHelperIretGC, PATMIretFunctionRecord.size, "PATMIretFunction");
243
244 /*
245 * The patches.
246 */
247 RTAvloU32DoWithAll(&pVM->patm.s.PatchLookupTreeHC->PatchTree, true /*fFromLeft*/, patmR3DbgAddPatchCallback, pVM);
248}
249
250
251/**
252 * Populate DBGF_AS_RC with PATM symbols.
253 *
254 * Called by dbgfR3AsLazyPopulate when DBGF_AS_RC or DBGF_AS_RC_AND_GC_GLOBAL is
255 * accessed for the first time.
256 *
257 * @param pVM The cross context VM structure.
258 * @param hDbgAs The DBGF_AS_RC address space handle.
259 */
260VMMR3_INT_DECL(void) PATMR3DbgPopulateAddrSpace(PVM pVM, RTDBGAS hDbgAs)
261{
262 AssertReturnVoid(!HMIsEnabled(pVM));
263
264 /*
265 * Add a fake debug module for the PATMGCSTATE structure.
266 */
267 RTDBGMOD hDbgMod;
268 int rc = RTDbgModCreate(&hDbgMod, "patmgcstate", sizeof(PATMGCSTATE), 0 /*fFlags*/);
269 if (RT_SUCCESS(rc))
270 {
271 ADD_MEMBER(hDbgMod, PATMGCSTATE, uVMFlags, "uVMFlags");
272 ADD_MEMBER(hDbgMod, PATMGCSTATE, uPendingAction, "uPendingAction");
273 ADD_MEMBER(hDbgMod, PATMGCSTATE, uPatchCalls, "uPatchCalls");
274 ADD_MEMBER(hDbgMod, PATMGCSTATE, uScratch, "uScratch");
275 ADD_MEMBER(hDbgMod, PATMGCSTATE, uIretEFlags, "uIretEFlags");
276 ADD_MEMBER(hDbgMod, PATMGCSTATE, uIretCS, "uIretCS");
277 ADD_MEMBER(hDbgMod, PATMGCSTATE, uIretEIP, "uIretEIP");
278 ADD_MEMBER(hDbgMod, PATMGCSTATE, Psp, "Psp");
279 ADD_MEMBER(hDbgMod, PATMGCSTATE, fPIF, "fPIF");
280 ADD_MEMBER(hDbgMod, PATMGCSTATE, GCPtrInhibitInterrupts, "GCPtrInhibitInterrupts");
281 ADD_MEMBER(hDbgMod, PATMGCSTATE, GCCallPatchTargetAddr, "GCCallPatchTargetAddr");
282 ADD_MEMBER(hDbgMod, PATMGCSTATE, GCCallReturnAddr, "GCCallReturnAddr");
283 ADD_MEMBER(hDbgMod, PATMGCSTATE, Restore.uEAX, "Restore.uEAX");
284 ADD_MEMBER(hDbgMod, PATMGCSTATE, Restore.uECX, "Restore.uECX");
285 ADD_MEMBER(hDbgMod, PATMGCSTATE, Restore.uEDI, "Restore.uEDI");
286 ADD_MEMBER(hDbgMod, PATMGCSTATE, Restore.eFlags, "Restore.eFlags");
287 ADD_MEMBER(hDbgMod, PATMGCSTATE, Restore.uFlags, "Restore.uFlags");
288
289 rc = RTDbgAsModuleLink(hDbgAs, hDbgMod, pVM->patm.s.pGCStateGC, 0 /*fFlags/*/);
290 AssertLogRelRC(rc);
291 RTDbgModRelease(hDbgMod);
292 }
293
294 /*
295 * Add a fake debug module for the patches.
296 */
297 rc = RTDbgModCreate(&hDbgMod, "patches", pVM->patm.s.cbPatchMem, 0 /*fFlags*/);
298 if (RT_SUCCESS(rc))
299 {
300 pVM->patm.s.hDbgModPatchMem = hDbgMod;
301 patmR3DbgAddPatches(pVM, hDbgMod);
302
303 rc = RTDbgAsModuleLink(hDbgAs, hDbgMod, pVM->patm.s.pPatchMemGC, 0 /*fFlags/*/);
304 AssertLogRelRC(rc);
305 }
306}
307
308
309/**
310 * Annotates an instruction if patched.
311 *
312 * @param pVM The VM handle.
313 * @param RCPtr The instruction address.
314 * @param cbInstr The instruction length.
315 * @param pszBuf The output buffer. This will be an empty string
316 * if the instruction wasn't patched. If it's
317 * patched, it will hold a symbol-like string
318 * describing the patch.
319 * @param cbBuf The size of the output buffer.
320 */
321VMMR3_INT_DECL(void) PATMR3DbgAnnotatePatchedInstruction(PVM pVM, RTRCPTR RCPtr, uint8_t cbInstr, char *pszBuf, size_t cbBuf)
322{
323 /*
324 * Always zero the buffer.
325 */
326 AssertReturnVoid(cbBuf > 0);
327 *pszBuf = '\0';
328
329 /*
330 * Drop out immediately if it cannot be a patched instruction.
331 */
332 if (!PATMIsEnabled(pVM))
333 return;
334 if ( RCPtr < pVM->patm.s.pPatchedInstrGCLowest
335 || RCPtr > pVM->patm.s.pPatchedInstrGCHighest)
336 return;
337
338 /*
339 * Look for a patch record covering any part of the instruction.
340 *
341 * The first query results in a patched less or equal to RCPtr. While the
342 * second results in one that's greater than RCPtr.
343 */
344 PPATMPATCHREC pPatchRec;
345 pPatchRec = (PPATMPATCHREC)RTAvloU32GetBestFit(&pVM->patm.s.PatchLookupTreeHC->PatchTree, RCPtr, false /*fFromAbove*/);
346 if ( !pPatchRec
347 || RCPtr - pPatchRec->patch.pPrivInstrGC > pPatchRec->patch.cbPrivInstr)
348 {
349 pPatchRec = (PPATMPATCHREC)RTAvloU32GetBestFit(&pVM->patm.s.PatchLookupTreeHC->PatchTree, RCPtr, true /*fFromAbove*/);
350 if ( !pPatchRec
351 || (RTRCPTR)(RCPtr + cbInstr) < pPatchRec->patch.pPrivInstrGC )
352 return;
353 }
354
355 /*
356 * Lazy bird uses the symbol name generation code for describing the patch.
357 */
358 size_t off = patmR3DbgDescribePatchAsSymbol(pPatchRec, pszBuf, cbBuf);
359 if (off + 1 < cbBuf)
360 {
361 const char *pszState;
362 switch (pPatchRec->patch.uState)
363 {
364 case PATCH_REFUSED: pszState = "Refused"; break;
365 case PATCH_DISABLED: pszState = "Disabled"; break;
366 case PATCH_ENABLED: pszState = "Enabled"; break;
367 case PATCH_UNUSABLE: pszState = "Unusable"; break;
368 case PATCH_DIRTY: pszState = "Dirty"; break;
369 case PATCH_DISABLE_PENDING: pszState = "DisablePending"; break;
370 default: pszState = "State???"; AssertFailed(); break;
371 }
372
373 if (pPatchRec->patch.cbPatchBlockSize > 0)
374 off += RTStrPrintf(&pszBuf[off], cbBuf - off, " - %s (%u b) - %#x LB %#x",
375 pszState, pPatchRec->patch.cbPatchJump,
376 pPatchRec->patch.pPatchBlockOffset + pVM->patm.s.pPatchMemGC,
377 pPatchRec->patch.cbPatchBlockSize);
378 else
379 off += RTStrPrintf(&pszBuf[off], cbBuf - off, " - %s (%u b)", pszState, pPatchRec->patch.cbPatchJump);
380 }
381
382}
383
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