VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/DBGFAddrSpace.cpp@ 94800

Last change on this file since 94800 was 93902, checked in by vboxsync, 3 years ago

VMM,Main,++: Removed VM_IS_RAW_MODE_ENABLED/VM_EXEC_ENGINE_RAW_MODE and added VM_IS_EXEC_ENGINE_IEM/VM_EXEC_ENGINE_IEM instead. In IMachineDebugger::getExecutionEngine VMExecutionEngine_RawMode was removed and VMExecutionEngine_Emulated added. Removed dead code and updated frontends accordingly. On darwin.arm64 HM now falls back on IEM execution since neither HM or NEM is availble there. [build fixes] bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 45.4 KB
Line 
1/* $Id: DBGFAddrSpace.cpp 93902 2022-02-23 15:42:16Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Address Space Management.
4 */
5
6/*
7 * Copyright (C) 2008-2022 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/** @page pg_dbgf_addr_space DBGFAddrSpace - Address Space Management
20 *
21 * What's an address space? It's mainly a convenient way of stuffing
22 * module segments and ad-hoc symbols together. It will also help out
23 * when the debugger gets extended to deal with user processes later.
24 *
25 * There are two standard address spaces that will always be present:
26 * - The physical address space.
27 * - The global virtual address space.
28 *
29 * Additional address spaces will be added and removed at runtime for
30 * guest processes. The global virtual address space will be used to
31 * track the kernel parts of the OS, or at least the bits of the kernel
32 * that is part of all address spaces (mac os x and 4G/4G patched linux).
33 *
34 */
35
36
37/*********************************************************************************************************************************
38* Header Files *
39*********************************************************************************************************************************/
40#define LOG_GROUP LOG_GROUP_DBGF
41#include <VBox/vmm/dbgf.h>
42#include <VBox/vmm/hm.h>
43#include <VBox/vmm/pdmapi.h>
44#include <VBox/vmm/mm.h>
45#include "DBGFInternal.h"
46#include <VBox/vmm/uvm.h>
47#include <VBox/vmm/vm.h>
48#include <VBox/err.h>
49#include <VBox/log.h>
50
51#include <iprt/asm.h>
52#include <iprt/assert.h>
53#include <iprt/ctype.h>
54#include <iprt/env.h>
55#include <iprt/mem.h>
56#include <iprt/path.h>
57#include <iprt/param.h>
58
59
60/*********************************************************************************************************************************
61* Structures and Typedefs *
62*********************************************************************************************************************************/
63/**
64 * Address space database node.
65 */
66typedef struct DBGFASDBNODE
67{
68 /** The node core for DBGF::AsHandleTree, the key is the address space handle. */
69 AVLPVNODECORE HandleCore;
70 /** The node core for DBGF::AsPidTree, the key is the process id. */
71 AVLU32NODECORE PidCore;
72 /** The node core for DBGF::AsNameSpace, the string is the address space name. */
73 RTSTRSPACECORE NameCore;
74
75} DBGFASDBNODE;
76/** Pointer to an address space database node. */
77typedef DBGFASDBNODE *PDBGFASDBNODE;
78
79
80/**
81 * For dbgfR3AsLoadImageOpenData and dbgfR3AsLoadMapOpenData.
82 */
83typedef struct DBGFR3ASLOADOPENDATA
84{
85 const char *pszModName;
86 RTGCUINTPTR uSubtrahend;
87 uint32_t fFlags;
88 RTDBGMOD hMod;
89} DBGFR3ASLOADOPENDATA;
90
91#if 0 /* unused */
92/**
93 * Callback for dbgfR3AsSearchPath and dbgfR3AsSearchEnvPath.
94 *
95 * @returns VBox status code. If success, then the search is completed.
96 * @param pszFilename The file name under evaluation.
97 * @param pvUser The user argument.
98 */
99typedef int FNDBGFR3ASSEARCHOPEN(const char *pszFilename, void *pvUser);
100/** Pointer to a FNDBGFR3ASSEARCHOPEN. */
101typedef FNDBGFR3ASSEARCHOPEN *PFNDBGFR3ASSEARCHOPEN;
102#endif
103
104
105/*********************************************************************************************************************************
106* Defined Constants And Macros *
107*********************************************************************************************************************************/
108/** Locks the address space database for writing. */
109#define DBGF_AS_DB_LOCK_WRITE(pUVM) \
110 do { \
111 int rcSem = RTSemRWRequestWrite((pUVM)->dbgf.s.hAsDbLock, RT_INDEFINITE_WAIT); \
112 AssertRC(rcSem); \
113 } while (0)
114
115/** Unlocks the address space database after writing. */
116#define DBGF_AS_DB_UNLOCK_WRITE(pUVM) \
117 do { \
118 int rcSem = RTSemRWReleaseWrite((pUVM)->dbgf.s.hAsDbLock); \
119 AssertRC(rcSem); \
120 } while (0)
121
122/** Locks the address space database for reading. */
123#define DBGF_AS_DB_LOCK_READ(pUVM) \
124 do { \
125 int rcSem = RTSemRWRequestRead((pUVM)->dbgf.s.hAsDbLock, RT_INDEFINITE_WAIT); \
126 AssertRC(rcSem); \
127 } while (0)
128
129/** Unlocks the address space database after reading. */
130#define DBGF_AS_DB_UNLOCK_READ(pUVM) \
131 do { \
132 int rcSem = RTSemRWReleaseRead((pUVM)->dbgf.s.hAsDbLock); \
133 AssertRC(rcSem); \
134 } while (0)
135
136
137
138/**
139 * Initializes the address space parts of DBGF.
140 *
141 * @returns VBox status code.
142 * @param pUVM The user mode VM handle.
143 */
144int dbgfR3AsInit(PUVM pUVM)
145{
146 Assert(pUVM->pVM);
147
148 /*
149 * Create the semaphore.
150 */
151 int rc = RTSemRWCreate(&pUVM->dbgf.s.hAsDbLock);
152 AssertRCReturn(rc, rc);
153
154 /*
155 * Create the debugging config instance and set it up, defaulting to
156 * deferred loading in order to keep things fast.
157 */
158 rc = RTDbgCfgCreate(&pUVM->dbgf.s.hDbgCfg, "VBOXDBG_", true /*fNativePaths*/);
159 AssertRCReturn(rc, rc);
160 rc = RTDbgCfgChangeUInt(pUVM->dbgf.s.hDbgCfg, RTDBGCFGPROP_FLAGS, RTDBGCFGOP_PREPEND,
161 RTDBGCFG_FLAGS_DEFERRED);
162 AssertRCReturn(rc, rc);
163
164 static struct
165 {
166 RTDBGCFGPROP enmProp;
167 const char *pszEnvName;
168 const char *pszCfgName;
169 } const s_aProps[] =
170 {
171 { RTDBGCFGPROP_FLAGS, "VBOXDBG_FLAGS", "Flags" },
172 { RTDBGCFGPROP_PATH, "VBOXDBG_PATH", "Path" },
173 { RTDBGCFGPROP_SUFFIXES, "VBOXDBG_SUFFIXES", "Suffixes" },
174 { RTDBGCFGPROP_SRC_PATH, "VBOXDBG_SRC_PATH", "SrcPath" },
175 };
176 PCFGMNODE pCfgDbgf = CFGMR3GetChild(CFGMR3GetRootU(pUVM), "/DBGF");
177 for (unsigned i = 0; i < RT_ELEMENTS(s_aProps); i++)
178 {
179 char szEnvValue[8192];
180 rc = RTEnvGetEx(RTENV_DEFAULT, s_aProps[i].pszEnvName, szEnvValue, sizeof(szEnvValue), NULL);
181 if (RT_SUCCESS(rc))
182 {
183 rc = RTDbgCfgChangeString(pUVM->dbgf.s.hDbgCfg, s_aProps[i].enmProp, RTDBGCFGOP_PREPEND, szEnvValue);
184 if (RT_FAILURE(rc))
185 return VMR3SetError(pUVM, rc, RT_SRC_POS,
186 "DBGF Config Error: %s=%s -> %Rrc", s_aProps[i].pszEnvName, szEnvValue, rc);
187 }
188 else if (rc != VERR_ENV_VAR_NOT_FOUND)
189 return VMR3SetError(pUVM, rc, RT_SRC_POS,
190 "DBGF Config Error: Error querying env.var. %s: %Rrc", s_aProps[i].pszEnvName, rc);
191
192 char *pszCfgValue;
193 rc = CFGMR3QueryStringAllocDef(pCfgDbgf, s_aProps[i].pszCfgName, &pszCfgValue, NULL);
194 if (RT_FAILURE(rc))
195 return VMR3SetError(pUVM, rc, RT_SRC_POS,
196 "DBGF Config Error: Querying /DBGF/%s -> %Rrc", s_aProps[i].pszCfgName, rc);
197 if (pszCfgValue)
198 {
199 rc = RTDbgCfgChangeString(pUVM->dbgf.s.hDbgCfg, s_aProps[i].enmProp, RTDBGCFGOP_PREPEND, pszCfgValue);
200 if (RT_FAILURE(rc))
201 return VMR3SetError(pUVM, rc, RT_SRC_POS,
202 "DBGF Config Error: /DBGF/%s=%s -> %Rrc", s_aProps[i].pszCfgName, pszCfgValue, rc);
203 MMR3HeapFree(pszCfgValue);
204 }
205 }
206
207 /*
208 * Prepend the NoArch and VBoxDbgSyms directories to the path.
209 */
210 char szPath[RTPATH_MAX];
211 rc = RTPathAppPrivateNoArch(szPath, sizeof(szPath));
212 AssertRCReturn(rc, rc);
213#ifdef RT_OS_DARWIN
214 rc = RTPathAppend(szPath, sizeof(szPath), "../Resources/VBoxDbgSyms/");
215#else
216 rc = RTDbgCfgChangeString(pUVM->dbgf.s.hDbgCfg, RTDBGCFGPROP_PATH, RTDBGCFGOP_PREPEND, szPath);
217 AssertRCReturn(rc, rc);
218
219 rc = RTPathAppend(szPath, sizeof(szPath), "VBoxDbgSyms/");
220#endif
221 AssertRCReturn(rc, rc);
222 rc = RTDbgCfgChangeString(pUVM->dbgf.s.hDbgCfg, RTDBGCFGPROP_PATH, RTDBGCFGOP_PREPEND, szPath);
223 AssertRCReturn(rc, rc);
224
225 /*
226 * Create the standard address spaces.
227 */
228 RTDBGAS hDbgAs;
229 rc = RTDbgAsCreate(&hDbgAs, 0, RTGCPTR_MAX, "Global");
230 AssertRCReturn(rc, rc);
231 rc = DBGFR3AsAdd(pUVM, hDbgAs, NIL_RTPROCESS);
232 AssertRCReturn(rc, rc);
233 pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_GLOBAL)] = hDbgAs;
234
235 RTDbgAsRetain(hDbgAs);
236 pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_KERNEL)] = hDbgAs;
237
238 rc = RTDbgAsCreate(&hDbgAs, 0, RTGCPHYS_MAX, "Physical");
239 AssertRCReturn(rc, rc);
240 rc = DBGFR3AsAdd(pUVM, hDbgAs, NIL_RTPROCESS);
241 AssertRCReturn(rc, rc);
242 pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_PHYS)] = hDbgAs;
243
244 rc = RTDbgAsCreate(&hDbgAs, 0, RTRCPTR_MAX, "HyperRawMode");
245 AssertRCReturn(rc, rc);
246 rc = DBGFR3AsAdd(pUVM, hDbgAs, NIL_RTPROCESS);
247 AssertRCReturn(rc, rc);
248 pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC)] = hDbgAs;
249 RTDbgAsRetain(hDbgAs);
250 pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC_AND_GC_GLOBAL)] = hDbgAs;
251
252 rc = RTDbgAsCreate(&hDbgAs, 0, RTR0PTR_MAX, "HyperRing0");
253 AssertRCReturn(rc, rc);
254 rc = DBGFR3AsAdd(pUVM, hDbgAs, NIL_RTPROCESS);
255 AssertRCReturn(rc, rc);
256 pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_R0)] = hDbgAs;
257
258 return VINF_SUCCESS;
259}
260
261
262/**
263 * Callback used by dbgfR3AsTerm / RTAvlPVDestroy to release an address space.
264 *
265 * @returns 0.
266 * @param pNode The address space database node.
267 * @param pvIgnore NULL.
268 */
269static DECLCALLBACK(int) dbgfR3AsTermDestroyNode(PAVLPVNODECORE pNode, void *pvIgnore)
270{
271 PDBGFASDBNODE pDbNode = (PDBGFASDBNODE)pNode;
272 RTDbgAsRelease((RTDBGAS)pDbNode->HandleCore.Key);
273 pDbNode->HandleCore.Key = NIL_RTDBGAS;
274 /* Don't bother freeing it here as MM will free it soon and MM is much at
275 it when doing it wholesale instead of piecemeal. */
276 NOREF(pvIgnore);
277 return 0;
278}
279
280
281/**
282 * Terminates the address space parts of DBGF.
283 *
284 * @param pUVM The user mode VM handle.
285 */
286void dbgfR3AsTerm(PUVM pUVM)
287{
288 /*
289 * Create the semaphore.
290 */
291 int rc = RTSemRWDestroy(pUVM->dbgf.s.hAsDbLock);
292 AssertRC(rc);
293 pUVM->dbgf.s.hAsDbLock = NIL_RTSEMRW;
294
295 /*
296 * Release all the address spaces.
297 */
298 RTAvlPVDestroy(&pUVM->dbgf.s.AsHandleTree, dbgfR3AsTermDestroyNode, NULL);
299 for (size_t i = 0; i < RT_ELEMENTS(pUVM->dbgf.s.ahAsAliases); i++)
300 {
301 RTDbgAsRelease(pUVM->dbgf.s.ahAsAliases[i]);
302 pUVM->dbgf.s.ahAsAliases[i] = NIL_RTDBGAS;
303 }
304
305 /*
306 * Release the reference to the debugging config.
307 */
308 rc = RTDbgCfgRelease(pUVM->dbgf.s.hDbgCfg);
309 AssertRC(rc);
310}
311
312
313/**
314 * Relocates the RC address space.
315 *
316 * @param pUVM The user mode VM handle.
317 * @param offDelta The relocation delta.
318 */
319void dbgfR3AsRelocate(PUVM pUVM, RTGCUINTPTR offDelta)
320{
321 /*
322 * We will relocate the raw-mode context modules by offDelta if they have
323 * been injected into the DBGF_AS_RC map.
324 */
325 if ( pUVM->dbgf.s.afAsAliasPopuplated[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC)]
326 && offDelta != 0)
327 {
328 RTDBGAS hAs = pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC)];
329
330 /* Take a snapshot of the modules as we might have overlapping
331 addresses between the previous and new mapping. */
332 RTDbgAsLockExcl(hAs);
333 uint32_t cModules = RTDbgAsModuleCount(hAs);
334 if (cModules > 0 && cModules < _4K)
335 {
336 struct DBGFASRELOCENTRY
337 {
338 RTDBGMOD hDbgMod;
339 RTRCPTR uOldAddr;
340 } *paEntries = (struct DBGFASRELOCENTRY *)RTMemTmpAllocZ(sizeof(paEntries[0]) * cModules);
341 if (paEntries)
342 {
343 /* Snapshot. */
344 for (uint32_t i = 0; i < cModules; i++)
345 {
346 paEntries[i].hDbgMod = RTDbgAsModuleByIndex(hAs, i);
347 AssertLogRelMsg(paEntries[i].hDbgMod != NIL_RTDBGMOD, ("iModule=%#x\n", i));
348
349 RTDBGASMAPINFO aMappings[1] = { { 0, 0 } };
350 uint32_t cMappings = 1;
351 int rc = RTDbgAsModuleQueryMapByIndex(hAs, i, &aMappings[0], &cMappings, 0 /*fFlags*/);
352 if (RT_SUCCESS(rc) && cMappings == 1 && aMappings[0].iSeg == NIL_RTDBGSEGIDX)
353 paEntries[i].uOldAddr = (RTRCPTR)aMappings[0].Address;
354 else
355 AssertLogRelMsgFailed(("iModule=%#x rc=%Rrc cMappings=%#x.\n", i, rc, cMappings));
356 }
357
358 /* Unlink them. */
359 for (uint32_t i = 0; i < cModules; i++)
360 {
361 int rc = RTDbgAsModuleUnlink(hAs, paEntries[i].hDbgMod);
362 AssertLogRelMsg(RT_SUCCESS(rc), ("iModule=%#x rc=%Rrc hDbgMod=%p\n", i, rc, paEntries[i].hDbgMod));
363 }
364
365 /* Link them at the new locations. */
366 for (uint32_t i = 0; i < cModules; i++)
367 {
368 RTRCPTR uNewAddr = paEntries[i].uOldAddr + offDelta;
369 int rc = RTDbgAsModuleLink(hAs, paEntries[i].hDbgMod, uNewAddr,
370 RTDBGASLINK_FLAGS_REPLACE);
371 AssertLogRelMsg(RT_SUCCESS(rc),
372 ("iModule=%#x rc=%Rrc hDbgMod=%p %RRv -> %RRv\n", i, rc, paEntries[i].hDbgMod,
373 paEntries[i].uOldAddr, uNewAddr));
374 RTDbgModRelease(paEntries[i].hDbgMod);
375 }
376
377 RTMemTmpFree(paEntries);
378 }
379 else
380 AssertLogRelMsgFailed(("No memory for %#x modules.\n", cModules));
381 }
382 else
383 AssertLogRelMsgFailed(("cModules=%#x\n", cModules));
384 RTDbgAsUnlockExcl(hAs);
385 }
386}
387
388
389/**
390 * Gets the IPRT debugging configuration handle (no refs retained).
391 *
392 * @returns Config handle or NIL_RTDBGCFG.
393 * @param pUVM The user mode VM handle.
394 */
395VMMR3DECL(RTDBGCFG) DBGFR3AsGetConfig(PUVM pUVM)
396{
397 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NIL_RTDBGCFG);
398 return pUVM->dbgf.s.hDbgCfg;
399}
400
401
402/**
403 * Adds the address space to the database.
404 *
405 * @returns VBox status code.
406 * @param pUVM The user mode VM handle.
407 * @param hDbgAs The address space handle. The reference of the caller
408 * will NOT be consumed.
409 * @param ProcId The process id or NIL_RTPROCESS.
410 */
411VMMR3DECL(int) DBGFR3AsAdd(PUVM pUVM, RTDBGAS hDbgAs, RTPROCESS ProcId)
412{
413 /*
414 * Input validation.
415 */
416 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
417 const char *pszName = RTDbgAsName(hDbgAs);
418 if (!pszName)
419 return VERR_INVALID_HANDLE;
420 uint32_t cRefs = RTDbgAsRetain(hDbgAs);
421 if (cRefs == UINT32_MAX)
422 return VERR_INVALID_HANDLE;
423
424 /*
425 * Allocate a tracking node.
426 */
427 int rc = VERR_NO_MEMORY;
428 PDBGFASDBNODE pDbNode = (PDBGFASDBNODE)MMR3HeapAllocU(pUVM, MM_TAG_DBGF_AS, sizeof(*pDbNode));
429 if (pDbNode)
430 {
431 pDbNode->HandleCore.Key = hDbgAs;
432 pDbNode->PidCore.Key = ProcId;
433 pDbNode->NameCore.pszString = pszName;
434 pDbNode->NameCore.cchString = strlen(pszName);
435 DBGF_AS_DB_LOCK_WRITE(pUVM);
436 if (RTStrSpaceInsert(&pUVM->dbgf.s.AsNameSpace, &pDbNode->NameCore))
437 {
438 if (RTAvlPVInsert(&pUVM->dbgf.s.AsHandleTree, &pDbNode->HandleCore))
439 {
440 DBGF_AS_DB_UNLOCK_WRITE(pUVM);
441 return VINF_SUCCESS;
442 }
443
444 /* bail out */
445 RTStrSpaceRemove(&pUVM->dbgf.s.AsNameSpace, pszName);
446 }
447 DBGF_AS_DB_UNLOCK_WRITE(pUVM);
448 MMR3HeapFree(pDbNode);
449 }
450 RTDbgAsRelease(hDbgAs);
451 return rc;
452}
453
454
455/**
456 * Delete an address space from the database.
457 *
458 * The address space must not be engaged as any of the standard aliases.
459 *
460 * @returns VBox status code.
461 * @retval VERR_SHARING_VIOLATION if in use as an alias.
462 * @retval VERR_NOT_FOUND if not found in the address space database.
463 *
464 * @param pUVM The user mode VM handle.
465 * @param hDbgAs The address space handle. Aliases are not allowed.
466 */
467VMMR3DECL(int) DBGFR3AsDelete(PUVM pUVM, RTDBGAS hDbgAs)
468{
469 /*
470 * Input validation. Retain the address space so it can be released outside
471 * the lock as well as validated.
472 */
473 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
474 if (hDbgAs == NIL_RTDBGAS)
475 return VINF_SUCCESS;
476 uint32_t cRefs = RTDbgAsRetain(hDbgAs);
477 if (cRefs == UINT32_MAX)
478 return VERR_INVALID_HANDLE;
479 RTDbgAsRelease(hDbgAs);
480
481 DBGF_AS_DB_LOCK_WRITE(pUVM);
482
483 /*
484 * You cannot delete any of the aliases.
485 */
486 for (size_t i = 0; i < RT_ELEMENTS(pUVM->dbgf.s.ahAsAliases); i++)
487 if (pUVM->dbgf.s.ahAsAliases[i] == hDbgAs)
488 {
489 DBGF_AS_DB_UNLOCK_WRITE(pUVM);
490 return VERR_SHARING_VIOLATION;
491 }
492
493 /*
494 * Ok, try remove it from the database.
495 */
496 PDBGFASDBNODE pDbNode = (PDBGFASDBNODE)RTAvlPVRemove(&pUVM->dbgf.s.AsHandleTree, hDbgAs);
497 if (!pDbNode)
498 {
499 DBGF_AS_DB_UNLOCK_WRITE(pUVM);
500 return VERR_NOT_FOUND;
501 }
502 RTStrSpaceRemove(&pUVM->dbgf.s.AsNameSpace, pDbNode->NameCore.pszString);
503 if (pDbNode->PidCore.Key != NIL_RTPROCESS)
504 RTAvlU32Remove(&pUVM->dbgf.s.AsPidTree, pDbNode->PidCore.Key);
505
506 DBGF_AS_DB_UNLOCK_WRITE(pUVM);
507
508 /*
509 * Free the resources.
510 */
511 RTDbgAsRelease(hDbgAs);
512 MMR3HeapFree(pDbNode);
513
514 return VINF_SUCCESS;
515}
516
517
518/**
519 * Changes an alias to point to a new address space.
520 *
521 * Not all the aliases can be changed, currently it's only DBGF_AS_GLOBAL
522 * and DBGF_AS_KERNEL.
523 *
524 * @returns VBox status code.
525 * @param pUVM The user mode VM handle.
526 * @param hAlias The alias to change.
527 * @param hAliasFor The address space hAlias should be an alias for. This
528 * can be an alias. The caller's reference to this address
529 * space will NOT be consumed.
530 */
531VMMR3DECL(int) DBGFR3AsSetAlias(PUVM pUVM, RTDBGAS hAlias, RTDBGAS hAliasFor)
532{
533 /*
534 * Input validation.
535 */
536 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
537 AssertMsgReturn(DBGF_AS_IS_ALIAS(hAlias), ("%p\n", hAlias), VERR_INVALID_PARAMETER);
538 AssertMsgReturn(!DBGF_AS_IS_FIXED_ALIAS(hAlias), ("%p\n", hAlias), VERR_INVALID_PARAMETER);
539 RTDBGAS hRealAliasFor = DBGFR3AsResolveAndRetain(pUVM, hAliasFor);
540 if (hRealAliasFor == NIL_RTDBGAS)
541 return VERR_INVALID_HANDLE;
542
543 /*
544 * Make sure the handle is already in the database.
545 */
546 int rc = VERR_NOT_FOUND;
547 DBGF_AS_DB_LOCK_WRITE(pUVM);
548 if (RTAvlPVGet(&pUVM->dbgf.s.AsHandleTree, hRealAliasFor))
549 {
550 /*
551 * Update the alias table and release the current address space.
552 */
553 RTDBGAS hAsOld;
554 ASMAtomicXchgHandle(&pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(hAlias)], hRealAliasFor, &hAsOld);
555 uint32_t cRefs = RTDbgAsRelease(hAsOld);
556 Assert(cRefs > 0); Assert(cRefs != UINT32_MAX); NOREF(cRefs);
557 rc = VINF_SUCCESS;
558 }
559 else
560 RTDbgAsRelease(hRealAliasFor);
561 DBGF_AS_DB_UNLOCK_WRITE(pUVM);
562
563 return rc;
564}
565
566
567/**
568 * @callback_method_impl{FNPDMR3ENUM}
569 */
570static DECLCALLBACK(int) dbgfR3AsLazyPopulateR0Callback(PVM pVM, const char *pszFilename, const char *pszName,
571 RTUINTPTR ImageBase, size_t cbImage, PDMLDRCTX enmCtx, void *pvArg)
572{
573 NOREF(pVM); NOREF(cbImage);
574
575 /* Only ring-0 modules. */
576 if (enmCtx == PDMLDRCTX_RING_0)
577 {
578 RTDBGMOD hDbgMod;
579 int rc = RTDbgModCreateFromImage(&hDbgMod, pszFilename, pszName, RTLDRARCH_HOST, pVM->pUVM->dbgf.s.hDbgCfg);
580 if (RT_SUCCESS(rc))
581 {
582 rc = RTDbgAsModuleLink((RTDBGAS)pvArg, hDbgMod, ImageBase, 0 /*fFlags*/);
583 if (RT_FAILURE(rc))
584 LogRel(("DBGF: Failed to link module \"%s\" into DBGF_AS_R0 at %RTptr: %Rrc\n",
585 pszName, ImageBase, rc));
586 }
587 else
588 LogRel(("DBGF: RTDbgModCreateFromImage failed with rc=%Rrc for module \"%s\" (%s)\n",
589 rc, pszName, pszFilename));
590 }
591 return VINF_SUCCESS;
592}
593
594
595#ifdef VBOX_WITH_RAW_MODE_KEEP
596/**
597 * @callback_method_impl{FNPDMR3ENUM}
598 */
599static DECLCALLBACK(int) dbgfR3AsLazyPopulateRCCallback(PVM pVM, const char *pszFilename, const char *pszName,
600 RTUINTPTR ImageBase, size_t cbImage, PDMLDRCTX enmCtx, void *pvArg)
601{
602 NOREF(pVM); NOREF(cbImage);
603
604 /* Only raw-mode modules. */
605 if (enmCtx == PDMLDRCTX_RAW_MODE)
606 {
607 RTDBGMOD hDbgMod;
608 int rc = RTDbgModCreateFromImage(&hDbgMod, pszFilename, pszName, RTLDRARCH_X86_32, pVM->pUVM->dbgf.s.hDbgCfg);
609 if (RT_SUCCESS(rc))
610 {
611 rc = RTDbgAsModuleLink((RTDBGAS)pvArg, hDbgMod, ImageBase, 0 /*fFlags*/);
612 if (RT_FAILURE(rc))
613 LogRel(("DBGF: Failed to link module \"%s\" into DBGF_AS_RC at %RTptr: %Rrc\n",
614 pszName, ImageBase, rc));
615 }
616 else
617 LogRel(("DBGF: RTDbgModCreateFromImage failed with rc=%Rrc for module \"%s\" (%s)\n",
618 rc, pszName, pszFilename));
619 }
620 return VINF_SUCCESS;
621}
622#endif /* VBOX_WITH_RAW_MODE_KEEP */
623
624
625/**
626 * Lazily populates the specified address space.
627 *
628 * @param pUVM The user mode VM handle.
629 * @param hAlias The alias.
630 */
631static void dbgfR3AsLazyPopulate(PUVM pUVM, RTDBGAS hAlias)
632{
633 DBGF_AS_DB_LOCK_WRITE(pUVM);
634 uintptr_t iAlias = DBGF_AS_ALIAS_2_INDEX(hAlias);
635 if (!pUVM->dbgf.s.afAsAliasPopuplated[iAlias])
636 {
637 RTDBGAS hDbgAs = pUVM->dbgf.s.ahAsAliases[iAlias];
638 if (hAlias == DBGF_AS_R0 && pUVM->pVM)
639 PDMR3LdrEnumModules(pUVM->pVM, dbgfR3AsLazyPopulateR0Callback, hDbgAs);
640#ifdef VBOX_WITH_RAW_MODE_KEEP /* needs fixing */
641 else if (hAlias == DBGF_AS_RC && pUVM->pVM && VM_IS_RAW_MODE_ENABLED(pUVM->pVM))
642 {
643 LogRel(("DBGF: Lazy init of RC address space\n"));
644 PDMR3LdrEnumModules(pUVM->pVM, dbgfR3AsLazyPopulateRCCallback, hDbgAs);
645 }
646#endif
647 else if (hAlias == DBGF_AS_PHYS && pUVM->pVM)
648 {
649 /** @todo Lazy load pc and vga bios symbols or the EFI stuff. */
650 }
651
652 pUVM->dbgf.s.afAsAliasPopuplated[iAlias] = true;
653 }
654 DBGF_AS_DB_UNLOCK_WRITE(pUVM);
655}
656
657
658/**
659 * Resolves the address space handle into a real handle if it's an alias.
660 *
661 * @returns Real address space handle. NIL_RTDBGAS if invalid handle.
662 *
663 * @param pUVM The user mode VM handle.
664 * @param hAlias The possibly address space alias.
665 *
666 * @remarks Doesn't take any locks.
667 */
668VMMR3DECL(RTDBGAS) DBGFR3AsResolve(PUVM pUVM, RTDBGAS hAlias)
669{
670 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
671 AssertCompileNS(NIL_RTDBGAS == (RTDBGAS)0);
672
673 uintptr_t iAlias = DBGF_AS_ALIAS_2_INDEX(hAlias);
674 if (iAlias < DBGF_AS_COUNT)
675 ASMAtomicReadHandle(&pUVM->dbgf.s.ahAsAliases[iAlias], &hAlias);
676 return hAlias;
677}
678
679
680/**
681 * Resolves the address space handle into a real handle if it's an alias,
682 * and retains whatever it is.
683 *
684 * @returns Real address space handle. NIL_RTDBGAS if invalid handle.
685 *
686 * @param pUVM The user mode VM handle.
687 * @param hAlias The possibly address space alias.
688 */
689VMMR3DECL(RTDBGAS) DBGFR3AsResolveAndRetain(PUVM pUVM, RTDBGAS hAlias)
690{
691 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
692 AssertCompileNS(NIL_RTDBGAS == (RTDBGAS)0);
693
694 uint32_t cRefs;
695 uintptr_t iAlias = DBGF_AS_ALIAS_2_INDEX(hAlias);
696 if (iAlias < DBGF_AS_COUNT)
697 {
698 if (DBGF_AS_IS_FIXED_ALIAS(hAlias))
699 {
700 /* Perform lazy address space population. */
701 if (!pUVM->dbgf.s.afAsAliasPopuplated[iAlias])
702 dbgfR3AsLazyPopulate(pUVM, hAlias);
703
704 /* Won't ever change, no need to grab the lock. */
705 hAlias = pUVM->dbgf.s.ahAsAliases[iAlias];
706 cRefs = RTDbgAsRetain(hAlias);
707 }
708 else
709 {
710 /* May change, grab the lock so we can read it safely. */
711 DBGF_AS_DB_LOCK_READ(pUVM);
712 hAlias = pUVM->dbgf.s.ahAsAliases[iAlias];
713 cRefs = RTDbgAsRetain(hAlias);
714 DBGF_AS_DB_UNLOCK_READ(pUVM);
715 }
716 }
717 else
718 /* Not an alias, just retain it. */
719 cRefs = RTDbgAsRetain(hAlias);
720
721 return cRefs != UINT32_MAX ? hAlias : NIL_RTDBGAS;
722}
723
724
725/**
726 * Query an address space by name.
727 *
728 * @returns Retained address space handle if found, NIL_RTDBGAS if not.
729 *
730 * @param pUVM The user mode VM handle.
731 * @param pszName The name.
732 */
733VMMR3DECL(RTDBGAS) DBGFR3AsQueryByName(PUVM pUVM, const char *pszName)
734{
735 /*
736 * Validate the input.
737 */
738 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NIL_RTDBGAS);
739 AssertPtrReturn(pszName, NIL_RTDBGAS);
740 AssertReturn(*pszName, NIL_RTDBGAS);
741
742 /*
743 * Look it up in the string space and retain the result.
744 */
745 RTDBGAS hDbgAs = NIL_RTDBGAS;
746 DBGF_AS_DB_LOCK_READ(pUVM);
747
748 PRTSTRSPACECORE pNode = RTStrSpaceGet(&pUVM->dbgf.s.AsNameSpace, pszName);
749 if (pNode)
750 {
751 PDBGFASDBNODE pDbNode = RT_FROM_MEMBER(pNode, DBGFASDBNODE, NameCore);
752 hDbgAs = (RTDBGAS)pDbNode->HandleCore.Key;
753 uint32_t cRefs = RTDbgAsRetain(hDbgAs);
754 if (RT_UNLIKELY(cRefs == UINT32_MAX))
755 hDbgAs = NIL_RTDBGAS;
756 }
757
758 DBGF_AS_DB_UNLOCK_READ(pUVM);
759 return hDbgAs;
760}
761
762
763/**
764 * Query an address space by process ID.
765 *
766 * @returns Retained address space handle if found, NIL_RTDBGAS if not.
767 *
768 * @param pUVM The user mode VM handle.
769 * @param ProcId The process ID.
770 */
771VMMR3DECL(RTDBGAS) DBGFR3AsQueryByPid(PUVM pUVM, RTPROCESS ProcId)
772{
773 /*
774 * Validate the input.
775 */
776 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NIL_RTDBGAS);
777 AssertReturn(ProcId != NIL_RTPROCESS, NIL_RTDBGAS);
778
779 /*
780 * Look it up in the PID tree and retain the result.
781 */
782 RTDBGAS hDbgAs = NIL_RTDBGAS;
783 DBGF_AS_DB_LOCK_READ(pUVM);
784
785 PAVLU32NODECORE pNode = RTAvlU32Get(&pUVM->dbgf.s.AsPidTree, ProcId);
786 if (pNode)
787 {
788 PDBGFASDBNODE pDbNode = RT_FROM_MEMBER(pNode, DBGFASDBNODE, PidCore);
789 hDbgAs = (RTDBGAS)pDbNode->HandleCore.Key;
790 uint32_t cRefs = RTDbgAsRetain(hDbgAs);
791 if (RT_UNLIKELY(cRefs == UINT32_MAX))
792 hDbgAs = NIL_RTDBGAS;
793 }
794 DBGF_AS_DB_UNLOCK_READ(pUVM);
795
796 return hDbgAs;
797}
798
799#if 0 /* unused */
800
801/**
802 * Searches for the file in the path.
803 *
804 * The file is first tested without any path modification, then we walk the path
805 * looking in each directory.
806 *
807 * @returns VBox status code.
808 * @param pszFilename The file to search for.
809 * @param pszPath The search path.
810 * @param pfnOpen The open callback function.
811 * @param pvUser User argument for the callback.
812 */
813static int dbgfR3AsSearchPath(const char *pszFilename, const char *pszPath, PFNDBGFR3ASSEARCHOPEN pfnOpen, void *pvUser)
814{
815 char szFound[RTPATH_MAX];
816
817 /* Check the filename length. */
818 size_t const cchFilename = strlen(pszFilename);
819 if (cchFilename >= sizeof(szFound))
820 return VERR_FILENAME_TOO_LONG;
821 const char *pszName = RTPathFilename(pszFilename);
822 if (!pszName)
823 return VERR_IS_A_DIRECTORY;
824 size_t const cchName = strlen(pszName);
825
826 /*
827 * Try default location first.
828 */
829 memcpy(szFound, pszFilename, cchFilename + 1);
830 int rc = pfnOpen(szFound, pvUser);
831 if (RT_SUCCESS(rc))
832 return rc;
833
834 /*
835 * Walk the search path.
836 */
837 const char *psz = pszPath;
838 while (*psz)
839 {
840 /* Skip leading blanks - no directories with leading spaces, thank you. */
841 while (RT_C_IS_BLANK(*psz))
842 psz++;
843
844 /* Find the end of this element. */
845 const char *pszNext;
846 const char *pszEnd = strchr(psz, ';');
847 if (!pszEnd)
848 pszEnd = pszNext = strchr(psz, '\0');
849 else
850 pszNext = pszEnd + 1;
851 if (pszEnd != psz)
852 {
853 size_t const cch = pszEnd - psz;
854 if (cch + 1 + cchName < sizeof(szFound))
855 {
856 /** @todo RTPathCompose, RTPathComposeN(). This code isn't right
857 * for 'E:' on DOS systems. It may also create unwanted double slashes. */
858 memcpy(szFound, psz, cch);
859 szFound[cch] = '/';
860 memcpy(szFound + cch + 1, pszName, cchName + 1);
861 int rc2 = pfnOpen(szFound, pvUser);
862 if (RT_SUCCESS(rc2))
863 return rc2;
864 if ( rc2 != rc
865 && ( rc == VERR_FILE_NOT_FOUND
866 || rc == VERR_OPEN_FAILED))
867 rc = rc2;
868 }
869 }
870
871 /* advance */
872 psz = pszNext;
873 }
874
875 /*
876 * Walk the path once again, this time do a depth search.
877 */
878 /** @todo do a depth search using the specified path. */
879
880 /* failed */
881 return rc;
882}
883
884
885/**
886 * Same as dbgfR3AsSearchEnv, except that the path is taken from the environment.
887 *
888 * If the environment variable doesn't exist, the current directory is searched
889 * instead.
890 *
891 * @returns VBox status code.
892 * @param pszFilename The filename.
893 * @param pszEnvVar The environment variable name.
894 * @param pfnOpen The open callback function.
895 * @param pvUser User argument for the callback.
896 */
897static int dbgfR3AsSearchEnvPath(const char *pszFilename, const char *pszEnvVar, PFNDBGFR3ASSEARCHOPEN pfnOpen, void *pvUser)
898{
899 int rc;
900 char *pszPath = RTEnvDupEx(RTENV_DEFAULT, pszEnvVar);
901 if (pszPath)
902 {
903 rc = dbgfR3AsSearchPath(pszFilename, pszPath, pfnOpen, pvUser);
904 RTStrFree(pszPath);
905 }
906 else
907 rc = dbgfR3AsSearchPath(pszFilename, ".", pfnOpen, pvUser);
908 return rc;
909}
910
911
912/**
913 * Same as dbgfR3AsSearchEnv, except that the path is taken from the DBGF config
914 * (CFGM).
915 *
916 * Nothing is done if the CFGM variable isn't set.
917 *
918 * @returns VBox status code.
919 * @param pUVM The user mode VM handle.
920 * @param pszFilename The filename.
921 * @param pszCfgValue The name of the config variable (under /DBGF/).
922 * @param pfnOpen The open callback function.
923 * @param pvUser User argument for the callback.
924 */
925static int dbgfR3AsSearchCfgPath(PUVM pUVM, const char *pszFilename, const char *pszCfgValue,
926 PFNDBGFR3ASSEARCHOPEN pfnOpen, void *pvUser)
927{
928 char *pszPath;
929 int rc = CFGMR3QueryStringAllocDef(CFGMR3GetChild(CFGMR3GetRootU(pUVM), "/DBGF"), pszCfgValue, &pszPath, NULL);
930 if (RT_FAILURE(rc))
931 return rc;
932 if (!pszPath)
933 return VERR_FILE_NOT_FOUND;
934 rc = dbgfR3AsSearchPath(pszFilename, pszPath, pfnOpen, pvUser);
935 MMR3HeapFree(pszPath);
936 return rc;
937}
938
939#endif /* unused */
940
941
942/**
943 * Load symbols from an executable module into the specified address space.
944 *
945 * If an module exist at the specified address it will be replaced by this
946 * call, otherwise a new module is created.
947 *
948 * @returns VBox status code.
949 *
950 * @param pUVM The user mode VM handle.
951 * @param hDbgAs The address space.
952 * @param pszFilename The filename of the executable module.
953 * @param pszModName The module name. If NULL, then then the file name
954 * base is used (no extension or nothing).
955 * @param enmArch The desired architecture, use RTLDRARCH_WHATEVER if
956 * it's not relevant or known.
957 * @param pModAddress The load address of the module.
958 * @param iModSeg The segment to load, pass NIL_RTDBGSEGIDX to load
959 * the whole image.
960 * @param fFlags For DBGFR3AsLinkModule, see RTDBGASLINK_FLAGS_*.
961 */
962VMMR3DECL(int) DBGFR3AsLoadImage(PUVM pUVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName, RTLDRARCH enmArch,
963 PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags)
964{
965 /*
966 * Validate input
967 */
968 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
969 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
970 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
971 AssertReturn(DBGFR3AddrIsValid(pUVM, pModAddress), VERR_INVALID_PARAMETER);
972 AssertReturn(!(fFlags & ~RTDBGASLINK_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
973 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
974 if (hRealAS == NIL_RTDBGAS)
975 return VERR_INVALID_HANDLE;
976
977 RTDBGMOD hDbgMod;
978 int rc = RTDbgModCreateFromImage(&hDbgMod, pszFilename, pszModName, enmArch, pUVM->dbgf.s.hDbgCfg);
979 if (RT_SUCCESS(rc))
980 {
981 rc = DBGFR3AsLinkModule(pUVM, hRealAS, hDbgMod, pModAddress, iModSeg, fFlags & RTDBGASLINK_FLAGS_VALID_MASK);
982 if (RT_FAILURE(rc))
983 RTDbgModRelease(hDbgMod);
984 }
985
986 RTDbgAsRelease(hRealAS);
987 return rc;
988}
989
990
991/**
992 * Load symbols from a map file into a module at the specified address space.
993 *
994 * If an module exist at the specified address it will be replaced by this
995 * call, otherwise a new module is created.
996 *
997 * @returns VBox status code.
998 *
999 * @param pUVM The user mode VM handle.
1000 * @param hDbgAs The address space.
1001 * @param pszFilename The map file.
1002 * @param pszModName The module name. If NULL, then then the file name
1003 * base is used (no extension or nothing).
1004 * @param pModAddress The load address of the module.
1005 * @param iModSeg The segment to load, pass NIL_RTDBGSEGIDX to load
1006 * the whole image.
1007 * @param uSubtrahend Value to to subtract from the symbols in the map
1008 * file. This is useful for the linux System.map and
1009 * /proc/kallsyms.
1010 * @param fFlags Flags reserved for future extensions, must be 0.
1011 */
1012VMMR3DECL(int) DBGFR3AsLoadMap(PUVM pUVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName,
1013 PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, RTGCUINTPTR uSubtrahend, uint32_t fFlags)
1014{
1015 /*
1016 * Validate input
1017 */
1018 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1019 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1020 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
1021 AssertReturn(DBGFR3AddrIsValid(pUVM, pModAddress), VERR_INVALID_PARAMETER);
1022 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER);
1023 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
1024 if (hRealAS == NIL_RTDBGAS)
1025 return VERR_INVALID_HANDLE;
1026
1027 RTDBGMOD hDbgMod;
1028 int rc = RTDbgModCreateFromMap(&hDbgMod, pszFilename, pszModName, uSubtrahend, pUVM->dbgf.s.hDbgCfg);
1029 if (RT_SUCCESS(rc))
1030 {
1031 rc = DBGFR3AsLinkModule(pUVM, hRealAS, hDbgMod, pModAddress, iModSeg, 0);
1032 if (RT_FAILURE(rc))
1033 RTDbgModRelease(hDbgMod);
1034 }
1035
1036 RTDbgAsRelease(hRealAS);
1037 return rc;
1038}
1039
1040
1041/**
1042 * Wrapper around RTDbgAsModuleLink, RTDbgAsModuleLinkSeg and DBGFR3AsResolve.
1043 *
1044 * @returns VBox status code.
1045 * @param pUVM The user mode VM handle.
1046 * @param hDbgAs The address space handle.
1047 * @param hMod The module handle.
1048 * @param pModAddress The link address.
1049 * @param iModSeg The segment to link, NIL_RTDBGSEGIDX for the entire image.
1050 * @param fFlags Flags to pass to the link functions, see RTDBGASLINK_FLAGS_*.
1051 */
1052VMMR3DECL(int) DBGFR3AsLinkModule(PUVM pUVM, RTDBGAS hDbgAs, RTDBGMOD hMod, PCDBGFADDRESS pModAddress,
1053 RTDBGSEGIDX iModSeg, uint32_t fFlags)
1054{
1055 /*
1056 * Input validation.
1057 */
1058 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1059 AssertReturn(DBGFR3AddrIsValid(pUVM, pModAddress), VERR_INVALID_PARAMETER);
1060 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
1061 if (hRealAS == NIL_RTDBGAS)
1062 return VERR_INVALID_HANDLE;
1063
1064 /*
1065 * Do the job.
1066 */
1067 int rc;
1068 if (iModSeg == NIL_RTDBGSEGIDX)
1069 rc = RTDbgAsModuleLink(hRealAS, hMod, pModAddress->FlatPtr, fFlags);
1070 else
1071 rc = RTDbgAsModuleLinkSeg(hRealAS, hMod, iModSeg, pModAddress->FlatPtr, fFlags);
1072
1073 RTDbgAsRelease(hRealAS);
1074 return rc;
1075}
1076
1077
1078/**
1079 * Wrapper around RTDbgAsModuleByName and RTDbgAsModuleUnlink.
1080 *
1081 * Unlinks all mappings matching the given module name.
1082 *
1083 * @returns VBox status code.
1084 * @param pUVM The user mode VM handle.
1085 * @param hDbgAs The address space handle.
1086 * @param pszModName The name of the module to unlink.
1087 */
1088VMMR3DECL(int) DBGFR3AsUnlinkModuleByName(PUVM pUVM, RTDBGAS hDbgAs, const char *pszModName)
1089{
1090 /*
1091 * Input validation.
1092 */
1093 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1094 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
1095 if (hRealAS == NIL_RTDBGAS)
1096 return VERR_INVALID_HANDLE;
1097
1098 /*
1099 * Do the job.
1100 */
1101 RTDBGMOD hMod;
1102 int rc = RTDbgAsModuleByName(hRealAS, pszModName, 0, &hMod);
1103 if (RT_SUCCESS(rc))
1104 {
1105 for (;;)
1106 {
1107 rc = RTDbgAsModuleUnlink(hRealAS, hMod);
1108 RTDbgModRelease(hMod);
1109 if (RT_FAILURE(rc))
1110 break;
1111 rc = RTDbgAsModuleByName(hRealAS, pszModName, 0, &hMod);
1112 if (RT_FAILURE_NP(rc))
1113 {
1114 if (rc == VERR_NOT_FOUND)
1115 rc = VINF_SUCCESS;
1116 break;
1117 }
1118 }
1119 }
1120
1121 RTDbgAsRelease(hRealAS);
1122 return rc;
1123}
1124
1125
1126/**
1127 * Adds the module name to the symbol name.
1128 *
1129 * @param pSymbol The symbol info (in/out).
1130 * @param hMod The module handle.
1131 */
1132static void dbgfR3AsSymbolJoinNames(PRTDBGSYMBOL pSymbol, RTDBGMOD hMod)
1133{
1134 /* Figure the lengths, adjust them if the result is too long. */
1135 const char *pszModName = RTDbgModName(hMod);
1136 size_t cchModName = strlen(pszModName);
1137 size_t cchSymbol = strlen(pSymbol->szName);
1138 if (cchModName + 1 + cchSymbol >= sizeof(pSymbol->szName))
1139 {
1140 if (cchModName >= sizeof(pSymbol->szName) / 4)
1141 cchModName = sizeof(pSymbol->szName) / 4;
1142 if (cchModName + 1 + cchSymbol >= sizeof(pSymbol->szName))
1143 cchSymbol = sizeof(pSymbol->szName) - cchModName - 2;
1144 Assert(cchModName + 1 + cchSymbol < sizeof(pSymbol->szName));
1145 }
1146
1147 /* Do the moving and copying. */
1148 memmove(&pSymbol->szName[cchModName + 1], &pSymbol->szName[0], cchSymbol + 1);
1149 memcpy(&pSymbol->szName[0], pszModName, cchModName);
1150 pSymbol->szName[cchModName] = '!';
1151}
1152
1153
1154/**
1155 * Query a symbol by address.
1156 *
1157 * The returned symbol is the one we consider closes to the specified address.
1158 *
1159 * @returns VBox status code. See RTDbgAsSymbolByAddr.
1160 *
1161 * @param pUVM The user mode VM handle.
1162 * @param hDbgAs The address space handle.
1163 * @param pAddress The address to lookup.
1164 * @param fFlags One of the RTDBGSYMADDR_FLAGS_XXX flags.
1165 * @param poffDisp Where to return the distance between the returned
1166 * symbol and pAddress. Optional.
1167 * @param pSymbol Where to return the symbol information. The returned
1168 * symbol name will be prefixed by the module name as
1169 * far as space allows.
1170 * @param phMod Where to return the module handle. Optional.
1171 */
1172VMMR3DECL(int) DBGFR3AsSymbolByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, uint32_t fFlags,
1173 PRTGCINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
1174{
1175 /*
1176 * Implement the special address space aliases the lazy way.
1177 */
1178 if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL)
1179 {
1180 int rc = DBGFR3AsSymbolByAddr(pUVM, DBGF_AS_RC, pAddress, fFlags, poffDisp, pSymbol, phMod);
1181 if (RT_FAILURE(rc))
1182 rc = DBGFR3AsSymbolByAddr(pUVM, DBGF_AS_GLOBAL, pAddress, fFlags, poffDisp, pSymbol, phMod);
1183 return rc;
1184 }
1185
1186 /*
1187 * Input validation.
1188 */
1189 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1190 AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER);
1191 AssertPtrNullReturn(poffDisp, VERR_INVALID_POINTER);
1192 AssertPtrReturn(pSymbol, VERR_INVALID_POINTER);
1193 AssertPtrNullReturn(phMod, VERR_INVALID_POINTER);
1194 if (poffDisp)
1195 *poffDisp = 0;
1196 if (phMod)
1197 *phMod = NIL_RTDBGMOD;
1198 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
1199 if (hRealAS == NIL_RTDBGAS)
1200 return VERR_INVALID_HANDLE;
1201
1202 /*
1203 * Do the lookup.
1204 */
1205 RTDBGMOD hMod;
1206 int rc = RTDbgAsSymbolByAddr(hRealAS, pAddress->FlatPtr, fFlags, poffDisp, pSymbol, &hMod);
1207 if (RT_SUCCESS(rc))
1208 {
1209 dbgfR3AsSymbolJoinNames(pSymbol, hMod);
1210 if (!phMod)
1211 RTDbgModRelease(hMod);
1212 else
1213 *phMod = hMod;
1214 }
1215
1216 RTDbgAsRelease(hRealAS);
1217 return rc;
1218}
1219
1220
1221/**
1222 * Convenience function that combines RTDbgSymbolDup and DBGFR3AsSymbolByAddr.
1223 *
1224 * @returns Pointer to the symbol on success. This must be free using
1225 * RTDbgSymbolFree(). NULL is returned if not found or any error
1226 * occurs.
1227 *
1228 * @param pUVM The user mode VM handle.
1229 * @param hDbgAs See DBGFR3AsSymbolByAddr.
1230 * @param pAddress See DBGFR3AsSymbolByAddr.
1231 * @param fFlags See DBGFR3AsSymbolByAddr.
1232 * @param poffDisp See DBGFR3AsSymbolByAddr.
1233 * @param phMod See DBGFR3AsSymbolByAddr.
1234 */
1235VMMR3DECL(PRTDBGSYMBOL) DBGFR3AsSymbolByAddrA(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, uint32_t fFlags,
1236 PRTGCINTPTR poffDisp, PRTDBGMOD phMod)
1237{
1238 RTDBGSYMBOL SymInfo;
1239 int rc = DBGFR3AsSymbolByAddr(pUVM, hDbgAs, pAddress, fFlags, poffDisp, &SymInfo, phMod);
1240 if (RT_SUCCESS(rc))
1241 return RTDbgSymbolDup(&SymInfo);
1242 return NULL;
1243}
1244
1245
1246/**
1247 * Query a symbol by name.
1248 *
1249 * The symbol can be prefixed by a module name pattern to scope the search. The
1250 * pattern is a simple string pattern with '*' and '?' as wild chars. See
1251 * RTStrSimplePatternMatch().
1252 *
1253 * @returns VBox status code. See RTDbgAsSymbolByAddr.
1254 *
1255 * @param pUVM The user mode VM handle.
1256 * @param hDbgAs The address space handle.
1257 * @param pszSymbol The symbol to search for, maybe prefixed by a
1258 * module pattern.
1259 * @param pSymbol Where to return the symbol information.
1260 * The returned symbol name will be prefixed by
1261 * the module name as far as space allows.
1262 * @param phMod Where to return the module handle. Optional.
1263 */
1264VMMR3DECL(int) DBGFR3AsSymbolByName(PUVM pUVM, RTDBGAS hDbgAs, const char *pszSymbol,
1265 PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
1266{
1267 /*
1268 * Implement the special address space aliases the lazy way.
1269 */
1270 if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL)
1271 {
1272 int rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_RC, pszSymbol, pSymbol, phMod);
1273 if (RT_FAILURE(rc))
1274 rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_GLOBAL, pszSymbol, pSymbol, phMod);
1275 return rc;
1276 }
1277
1278 /*
1279 * Input validation.
1280 */
1281 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1282 AssertPtrReturn(pSymbol, VERR_INVALID_POINTER);
1283 AssertPtrNullReturn(phMod, VERR_INVALID_POINTER);
1284 if (phMod)
1285 *phMod = NIL_RTDBGMOD;
1286 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
1287 if (hRealAS == NIL_RTDBGAS)
1288 return VERR_INVALID_HANDLE;
1289
1290
1291 /*
1292 * Do the lookup.
1293 */
1294 RTDBGMOD hMod;
1295 int rc = RTDbgAsSymbolByName(hRealAS, pszSymbol, pSymbol, &hMod);
1296 if (RT_SUCCESS(rc))
1297 {
1298 dbgfR3AsSymbolJoinNames(pSymbol, hMod);
1299 if (!phMod)
1300 RTDbgModRelease(hMod);
1301 }
1302
1303 RTDbgAsRelease(hRealAS);
1304 return rc;
1305}
1306
1307
1308VMMR3DECL(int) DBGFR3AsLineByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress,
1309 PRTGCINTPTR poffDisp, PRTDBGLINE pLine, PRTDBGMOD phMod)
1310{
1311 /*
1312 * Implement the special address space aliases the lazy way.
1313 */
1314 if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL)
1315 {
1316 int rc = DBGFR3AsLineByAddr(pUVM, DBGF_AS_RC, pAddress, poffDisp, pLine, phMod);
1317 if (RT_FAILURE(rc))
1318 rc = DBGFR3AsLineByAddr(pUVM, DBGF_AS_GLOBAL, pAddress, poffDisp, pLine, phMod);
1319 return rc;
1320 }
1321
1322 /*
1323 * Input validation.
1324 */
1325 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1326 AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER);
1327 AssertPtrNullReturn(poffDisp, VERR_INVALID_POINTER);
1328 AssertPtrReturn(pLine, VERR_INVALID_POINTER);
1329 AssertPtrNullReturn(phMod, VERR_INVALID_POINTER);
1330 if (poffDisp)
1331 *poffDisp = 0;
1332 if (phMod)
1333 *phMod = NIL_RTDBGMOD;
1334 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
1335 if (hRealAS == NIL_RTDBGAS)
1336 return VERR_INVALID_HANDLE;
1337
1338 /*
1339 * Do the lookup.
1340 */
1341 int rc = RTDbgAsLineByAddr(hRealAS, pAddress->FlatPtr, poffDisp, pLine, phMod);
1342
1343 RTDbgAsRelease(hRealAS);
1344 return rc;
1345}
1346
1347
1348VMMR3DECL(PRTDBGLINE) DBGFR3AsLineByAddrA(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress,
1349 PRTGCINTPTR poffDisp, PRTDBGMOD phMod)
1350{
1351 RTDBGLINE Line;
1352 int rc = DBGFR3AsLineByAddr(pUVM, hDbgAs, pAddress, poffDisp, &Line, phMod);
1353 if (RT_SUCCESS(rc))
1354 return RTDbgLineDup(&Line);
1355 return NULL;
1356}
1357
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