VirtualBox

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

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

Install bios symbol files in bin/VBoxDbgSyms/ and make DBGF look there.

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