VirtualBox

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

Last change on this file since 80191 was 80191, checked in by vboxsync, 5 years ago

VMM/r3: Refactored VMCPU enumeration in preparation that aCpus will be replaced with a pointer array. Removed two raw-mode offset members from the CPUM and CPUMCPU sub-structures. bugref:9217 bugref:9517

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