VirtualBox

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

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

Missing file, reverting 85830.

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