VirtualBox

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

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

DBGF,DBGC,++: PVM -> PUVM. Some refactoring and cleanup as well.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 37.7 KB
Line 
1/* $Id: DBGFAddrSpace.cpp 44399 2013-01-27 21:12:53Z 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/pdmapi.h>
42#include <VBox/vmm/mm.h>
43#include "DBGFInternal.h"
44#include <VBox/vmm/uvm.h>
45#include <VBox/vmm/vm.h>
46#include <VBox/err.h>
47#include <VBox/log.h>
48
49#include <iprt/asm.h>
50#include <iprt/assert.h>
51#include <iprt/ctype.h>
52#include <iprt/env.h>
53#include <iprt/path.h>
54#include <iprt/param.h>
55
56
57/*******************************************************************************
58* Structures and Typedefs *
59*******************************************************************************/
60/**
61 * Address space database node.
62 */
63typedef struct DBGFASDBNODE
64{
65 /** The node core for DBGF::AsHandleTree, the key is the address space handle. */
66 AVLPVNODECORE HandleCore;
67 /** The node core for DBGF::AsPidTree, the key is the process id. */
68 AVLU32NODECORE PidCore;
69 /** The node core for DBGF::AsNameSpace, the string is the address space name. */
70 RTSTRSPACECORE NameCore;
71
72} DBGFASDBNODE;
73/** Pointer to an address space database node. */
74typedef DBGFASDBNODE *PDBGFASDBNODE;
75
76
77/**
78 * For dbgfR3AsLoadImageOpenData and dbgfR3AsLoadMapOpenData.
79 */
80typedef struct DBGFR3ASLOADOPENDATA
81{
82 const char *pszModName;
83 RTGCUINTPTR uSubtrahend;
84 uint32_t fFlags;
85 RTDBGMOD hMod;
86} DBGFR3ASLOADOPENDATA;
87
88/**
89 * Callback for dbgfR3AsSearchPath and dbgfR3AsSearchEnvPath.
90 *
91 * @returns VBox status code. If success, then the search is completed.
92 * @param pszFilename The file name under evaluation.
93 * @param pvUser The user argument.
94 */
95typedef int FNDBGFR3ASSEARCHOPEN(const char *pszFilename, void *pvUser);
96/** Pointer to a FNDBGFR3ASSEARCHOPEN. */
97typedef FNDBGFR3ASSEARCHOPEN *PFNDBGFR3ASSEARCHOPEN;
98
99
100/*******************************************************************************
101* Defined Constants And Macros *
102*******************************************************************************/
103/** Locks the address space database for writing. */
104#define DBGF_AS_DB_LOCK_WRITE(pUVM) \
105 do { \
106 int rcSem = RTSemRWRequestWrite((pUVM)->dbgf.s.hAsDbLock, RT_INDEFINITE_WAIT); \
107 AssertRC(rcSem); \
108 } while (0)
109
110/** Unlocks the address space database after writing. */
111#define DBGF_AS_DB_UNLOCK_WRITE(pUVM) \
112 do { \
113 int rcSem = RTSemRWReleaseWrite((pUVM)->dbgf.s.hAsDbLock); \
114 AssertRC(rcSem); \
115 } while (0)
116
117/** Locks the address space database for reading. */
118#define DBGF_AS_DB_LOCK_READ(pUVM) \
119 do { \
120 int rcSem = RTSemRWRequestRead((pUVM)->dbgf.s.hAsDbLock, RT_INDEFINITE_WAIT); \
121 AssertRC(rcSem); \
122 } while (0)
123
124/** Unlocks the address space database after reading. */
125#define DBGF_AS_DB_UNLOCK_READ(pUVM) \
126 do { \
127 int rcSem = RTSemRWReleaseRead((pUVM)->dbgf.s.hAsDbLock); \
128 AssertRC(rcSem); \
129 } while (0)
130
131
132
133/**
134 * Initializes the address space parts of DBGF.
135 *
136 * @returns VBox status code.
137 * @param pUVM The user mode VM handle.
138 */
139int dbgfR3AsInit(PUVM pUVM)
140{
141 /*
142 * Create the semaphore.
143 */
144 int rc = RTSemRWCreate(&pUVM->dbgf.s.hAsDbLock);
145 AssertRCReturn(rc, rc);
146
147 /*
148 * Create the standard address spaces.
149 */
150 RTDBGAS hDbgAs;
151 rc = RTDbgAsCreate(&hDbgAs, 0, RTGCPTR_MAX, "Global");
152 AssertRCReturn(rc, rc);
153 rc = DBGFR3AsAdd(pUVM, hDbgAs, NIL_RTPROCESS);
154 AssertRCReturn(rc, rc);
155 RTDbgAsRetain(hDbgAs);
156 pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_GLOBAL)] = hDbgAs;
157
158 RTDbgAsRetain(hDbgAs);
159 pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_KERNEL)] = hDbgAs;
160
161 rc = RTDbgAsCreate(&hDbgAs, 0, RTGCPHYS_MAX, "Physical");
162 AssertRCReturn(rc, rc);
163 rc = DBGFR3AsAdd(pUVM, hDbgAs, NIL_RTPROCESS);
164 AssertRCReturn(rc, rc);
165 RTDbgAsRetain(hDbgAs);
166 pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_PHYS)] = hDbgAs;
167
168 rc = RTDbgAsCreate(&hDbgAs, 0, RTRCPTR_MAX, "HyperRawMode");
169 AssertRCReturn(rc, rc);
170 rc = DBGFR3AsAdd(pUVM, hDbgAs, NIL_RTPROCESS);
171 AssertRCReturn(rc, rc);
172 RTDbgAsRetain(hDbgAs);
173 pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC)] = hDbgAs;
174 RTDbgAsRetain(hDbgAs);
175 pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC_AND_GC_GLOBAL)] = hDbgAs;
176
177 rc = RTDbgAsCreate(&hDbgAs, 0, RTR0PTR_MAX, "HyperRing0");
178 AssertRCReturn(rc, rc);
179 rc = DBGFR3AsAdd(pUVM, hDbgAs, NIL_RTPROCESS);
180 AssertRCReturn(rc, rc);
181 RTDbgAsRetain(hDbgAs);
182 pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_R0)] = hDbgAs;
183
184 return VINF_SUCCESS;
185}
186
187
188/**
189 * Callback used by dbgfR3AsTerm / RTAvlPVDestroy to release an address space.
190 *
191 * @returns 0.
192 * @param pNode The address space database node.
193 * @param pvIgnore NULL.
194 */
195static DECLCALLBACK(int) dbgfR3AsTermDestroyNode(PAVLPVNODECORE pNode, void *pvIgnore)
196{
197 PDBGFASDBNODE pDbNode = (PDBGFASDBNODE)pNode;
198 RTDbgAsRelease((RTDBGAS)pDbNode->HandleCore.Key);
199 pDbNode->HandleCore.Key = NIL_RTDBGAS;
200 /* Don't bother freeing it here as MM will free it soon and MM is much at
201 it when doing it wholesale instead of piecemeal. */
202 NOREF(pvIgnore);
203 return 0;
204}
205
206
207/**
208 * Terminates the address space parts of DBGF.
209 *
210 * @param pUVM The user mode VM handle.
211 */
212void dbgfR3AsTerm(PUVM pUVM)
213{
214 /*
215 * Create the semaphore.
216 */
217 int rc = RTSemRWDestroy(pUVM->dbgf.s.hAsDbLock);
218 AssertRC(rc);
219 pUVM->dbgf.s.hAsDbLock = NIL_RTSEMRW;
220
221 /*
222 * Release all the address spaces.
223 */
224 RTAvlPVDestroy(&pUVM->dbgf.s.AsHandleTree, dbgfR3AsTermDestroyNode, NULL);
225 for (size_t i = 0; i < RT_ELEMENTS(pUVM->dbgf.s.ahAsAliases); i++)
226 {
227 RTDbgAsRelease(pUVM->dbgf.s.ahAsAliases[i]);
228 pUVM->dbgf.s.ahAsAliases[i] = NIL_RTDBGAS;
229 }
230}
231
232
233/**
234 * Relocates the RC address space.
235 *
236 * @param pUVM The user mode VM handle.
237 * @param offDelta The relocation delta.
238 */
239void dbgfR3AsRelocate(PUVM pUVM, RTGCUINTPTR offDelta)
240{
241 /** @todo */
242 NOREF(pUVM); NOREF(offDelta);
243}
244
245
246/**
247 * Adds the address space to the database.
248 *
249 * @returns VBox status code.
250 * @param pUVM The user mode VM handle.
251 * @param hDbgAs The address space handle. The reference of the caller
252 * will NOT be consumed.
253 * @param ProcId The process id or NIL_RTPROCESS.
254 */
255VMMR3DECL(int) DBGFR3AsAdd(PUVM pUVM, RTDBGAS hDbgAs, RTPROCESS ProcId)
256{
257 /*
258 * Input validation.
259 */
260 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
261 const char *pszName = RTDbgAsName(hDbgAs);
262 if (!pszName)
263 return VERR_INVALID_HANDLE;
264 uint32_t cRefs = RTDbgAsRetain(hDbgAs);
265 if (cRefs == UINT32_MAX)
266 return VERR_INVALID_HANDLE;
267
268 /*
269 * Allocate a tracking node.
270 */
271 int rc = VERR_NO_MEMORY;
272 PDBGFASDBNODE pDbNode = (PDBGFASDBNODE)MMR3HeapAllocU(pUVM, MM_TAG_DBGF_AS, sizeof(*pDbNode));
273 if (pDbNode)
274 {
275 pDbNode->HandleCore.Key = hDbgAs;
276 pDbNode->PidCore.Key = ProcId;
277 pDbNode->NameCore.pszString = pszName;
278 pDbNode->NameCore.cchString = strlen(pszName);
279 DBGF_AS_DB_LOCK_WRITE(pUVM);
280 if (RTStrSpaceInsert(&pUVM->dbgf.s.AsNameSpace, &pDbNode->NameCore))
281 {
282 if (RTAvlPVInsert(&pUVM->dbgf.s.AsHandleTree, &pDbNode->HandleCore))
283 {
284 DBGF_AS_DB_UNLOCK_WRITE(pUVM);
285 return VINF_SUCCESS;
286 }
287
288 /* bail out */
289 RTStrSpaceRemove(&pUVM->dbgf.s.AsNameSpace, pszName);
290 }
291 DBGF_AS_DB_UNLOCK_WRITE(pUVM);
292 MMR3HeapFree(pDbNode);
293 }
294 RTDbgAsRelease(hDbgAs);
295 return rc;
296}
297
298
299/**
300 * Delete an address space from the database.
301 *
302 * The address space must not be engaged as any of the standard aliases.
303 *
304 * @returns VBox status code.
305 * @retval VERR_SHARING_VIOLATION if in use as an alias.
306 * @retval VERR_NOT_FOUND if not found in the address space database.
307 *
308 * @param pUVM The user mode VM handle.
309 * @param hDbgAs The address space handle. Aliases are not allowed.
310 */
311VMMR3DECL(int) DBGFR3AsDelete(PUVM pUVM, RTDBGAS hDbgAs)
312{
313 /*
314 * Input validation. Retain the address space so it can be released outside
315 * the lock as well as validated.
316 */
317 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
318 if (hDbgAs == NIL_RTDBGAS)
319 return VINF_SUCCESS;
320 uint32_t cRefs = RTDbgAsRetain(hDbgAs);
321 if (cRefs == UINT32_MAX)
322 return VERR_INVALID_HANDLE;
323 RTDbgAsRelease(hDbgAs);
324
325 DBGF_AS_DB_LOCK_WRITE(pUVM);
326
327 /*
328 * You cannot delete any of the aliases.
329 */
330 for (size_t i = 0; i < RT_ELEMENTS(pUVM->dbgf.s.ahAsAliases); i++)
331 if (pUVM->dbgf.s.ahAsAliases[i] == hDbgAs)
332 {
333 DBGF_AS_DB_UNLOCK_WRITE(pUVM);
334 return VERR_SHARING_VIOLATION;
335 }
336
337 /*
338 * Ok, try remove it from the database.
339 */
340 PDBGFASDBNODE pDbNode = (PDBGFASDBNODE)RTAvlPVRemove(&pUVM->dbgf.s.AsHandleTree, hDbgAs);
341 if (!pDbNode)
342 {
343 DBGF_AS_DB_UNLOCK_WRITE(pUVM);
344 return VERR_NOT_FOUND;
345 }
346 RTStrSpaceRemove(&pUVM->dbgf.s.AsNameSpace, pDbNode->NameCore.pszString);
347 if (pDbNode->PidCore.Key != NIL_RTPROCESS)
348 RTAvlU32Remove(&pUVM->dbgf.s.AsPidTree, pDbNode->PidCore.Key);
349
350 DBGF_AS_DB_UNLOCK_WRITE(pUVM);
351
352 /*
353 * Free the resources.
354 */
355 RTDbgAsRelease(hDbgAs);
356 MMR3HeapFree(pDbNode);
357
358 return VINF_SUCCESS;
359}
360
361
362/**
363 * Changes an alias to point to a new address space.
364 *
365 * Not all the aliases can be changed, currently it's only DBGF_AS_GLOBAL
366 * and DBGF_AS_KERNEL.
367 *
368 * @returns VBox status code.
369 * @param pUVM The user mode VM handle.
370 * @param hAlias The alias to change.
371 * @param hAliasFor The address space hAlias should be an alias for. This
372 * can be an alias. The caller's reference to this address
373 * space will NOT be consumed.
374 */
375VMMR3DECL(int) DBGFR3AsSetAlias(PUVM pUVM, RTDBGAS hAlias, RTDBGAS hAliasFor)
376{
377 /*
378 * Input validation.
379 */
380 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
381 AssertMsgReturn(DBGF_AS_IS_ALIAS(hAlias), ("%p\n", hAlias), VERR_INVALID_PARAMETER);
382 AssertMsgReturn(!DBGF_AS_IS_FIXED_ALIAS(hAlias), ("%p\n", hAlias), VERR_INVALID_PARAMETER);
383 RTDBGAS hRealAliasFor = DBGFR3AsResolveAndRetain(pUVM, hAliasFor);
384 if (hRealAliasFor == NIL_RTDBGAS)
385 return VERR_INVALID_HANDLE;
386
387 /*
388 * Make sure the handle has is already in the database.
389 */
390 int rc = VERR_NOT_FOUND;
391 DBGF_AS_DB_LOCK_WRITE(pUVM);
392 if (RTAvlPVGet(&pUVM->dbgf.s.AsHandleTree, hRealAliasFor))
393 {
394 /*
395 * Update the alias table and release the current address space.
396 */
397 RTDBGAS hAsOld;
398 ASMAtomicXchgHandle(&pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(hAlias)], hRealAliasFor, &hAsOld);
399 uint32_t cRefs = RTDbgAsRelease(hAsOld);
400 Assert(cRefs > 0); Assert(cRefs != UINT32_MAX); NOREF(cRefs);
401 rc = VINF_SUCCESS;
402 }
403 DBGF_AS_DB_UNLOCK_WRITE(pUVM);
404
405 return rc;
406}
407
408
409/**
410 * @callback_method_impl{FNPDMR3ENUM}
411 */
412static DECLCALLBACK(int) dbgfR3AsLazyPopulateR0Callback(PVM pVM, const char *pszFilename, const char *pszName,
413 RTUINTPTR ImageBase, size_t cbImage, bool fRC, void *pvArg)
414{
415 NOREF(pVM); NOREF(cbImage);
416
417 /* Only ring-0 modules. */
418 if (!fRC)
419 {
420 RTDBGMOD hDbgMod;
421 int rc = RTDbgModCreateFromImage(&hDbgMod, pszFilename, pszName, 0 /*fFlags*/);
422 if (RT_SUCCESS(rc))
423 {
424 rc = RTDbgAsModuleLink((RTDBGAS)pvArg, hDbgMod, ImageBase, 0 /*fFlags*/);
425 if (RT_FAILURE(rc))
426 LogRel(("DBGF: Failed to link module \"%s\" into DBGF_AS_R0 at %RTptr: %Rrc\n",
427 pszName, ImageBase, rc));
428 }
429 else
430 LogRel(("DBGF: RTDbgModCreateFromImage failed with rc=%Rrc for module \"%s\" (%s)\n",
431 rc, pszName, pszFilename));
432 }
433 return VINF_SUCCESS;
434}
435
436
437/**
438 * Lazily populates the specified address space.
439 *
440 * @param pUVM The user mode VM handle.
441 * @param hAlias The alias.
442 */
443static void dbgfR3AsLazyPopulate(PUVM pUVM, RTDBGAS hAlias)
444{
445 DBGF_AS_DB_LOCK_WRITE(pUVM);
446 uintptr_t iAlias = DBGF_AS_ALIAS_2_INDEX(hAlias);
447 if (!pUVM->dbgf.s.afAsAliasPopuplated[iAlias])
448 {
449 RTDBGAS hAs = pUVM->dbgf.s.ahAsAliases[iAlias];
450 if (hAlias == DBGF_AS_R0 && pUVM->pVM)
451 PDMR3LdrEnumModules(pUVM->pVM, dbgfR3AsLazyPopulateR0Callback, hAs);
452 /** @todo what do we do about DBGF_AS_RC? */
453
454 pUVM->dbgf.s.afAsAliasPopuplated[iAlias] = true;
455 }
456 DBGF_AS_DB_UNLOCK_WRITE(pUVM);
457}
458
459
460/**
461 * Resolves the address space handle into a real handle if it's an alias.
462 *
463 * @returns Real address space handle. NIL_RTDBGAS if invalid handle.
464 *
465 * @param pUVM The user mode VM handle.
466 * @param hAlias The possibly address space alias.
467 *
468 * @remarks Doesn't take any locks.
469 */
470VMMR3DECL(RTDBGAS) DBGFR3AsResolve(PUVM pUVM, RTDBGAS hAlias)
471{
472 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
473 AssertCompileNS(NIL_RTDBGAS == (RTDBGAS)0);
474
475 uintptr_t iAlias = DBGF_AS_ALIAS_2_INDEX(hAlias);
476 if (iAlias < DBGF_AS_COUNT)
477 ASMAtomicReadHandle(&pUVM->dbgf.s.ahAsAliases[iAlias], &hAlias);
478 return hAlias;
479}
480
481
482/**
483 * Resolves the address space handle into a real handle if it's an alias,
484 * and retains whatever it is.
485 *
486 * @returns Real address space handle. NIL_RTDBGAS if invalid handle.
487 *
488 * @param pUVM The user mode VM handle.
489 * @param hAlias The possibly address space alias.
490 */
491VMMR3DECL(RTDBGAS) DBGFR3AsResolveAndRetain(PUVM pUVM, RTDBGAS hAlias)
492{
493 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
494 AssertCompileNS(NIL_RTDBGAS == (RTDBGAS)0);
495
496 uint32_t cRefs;
497 uintptr_t iAlias = DBGF_AS_ALIAS_2_INDEX(hAlias);
498 if (iAlias < DBGF_AS_COUNT)
499 {
500 if (DBGF_AS_IS_FIXED_ALIAS(hAlias))
501 {
502 /* Perform lazy address space population. */
503 if (!pUVM->dbgf.s.afAsAliasPopuplated[iAlias])
504 dbgfR3AsLazyPopulate(pUVM, hAlias);
505
506 /* Won't ever change, no need to grab the lock. */
507 hAlias = pUVM->dbgf.s.ahAsAliases[iAlias];
508 cRefs = RTDbgAsRetain(hAlias);
509 }
510 else
511 {
512 /* May change, grab the lock so we can read it safely. */
513 DBGF_AS_DB_LOCK_READ(pUVM);
514 hAlias = pUVM->dbgf.s.ahAsAliases[iAlias];
515 cRefs = RTDbgAsRetain(hAlias);
516 DBGF_AS_DB_UNLOCK_READ(pUVM);
517 }
518 }
519 else
520 /* Not an alias, just retain it. */
521 cRefs = RTDbgAsRetain(hAlias);
522
523 return cRefs != UINT32_MAX ? hAlias : NIL_RTDBGAS;
524}
525
526
527/**
528 * Query an address space by name.
529 *
530 * @returns Retained address space handle if found, NIL_RTDBGAS if not.
531 *
532 * @param pUVM The user mode VM handle.
533 * @param pszName The name.
534 */
535VMMR3DECL(RTDBGAS) DBGFR3AsQueryByName(PUVM pUVM, const char *pszName)
536{
537 /*
538 * Validate the input.
539 */
540 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NIL_RTDBGAS);
541 AssertPtrReturn(pszName, NIL_RTDBGAS);
542 AssertReturn(*pszName, NIL_RTDBGAS);
543
544 /*
545 * Look it up in the string space and retain the result.
546 */
547 RTDBGAS hDbgAs = NIL_RTDBGAS;
548 DBGF_AS_DB_LOCK_READ(pUVM);
549
550 PRTSTRSPACECORE pNode = RTStrSpaceGet(&pUVM->dbgf.s.AsNameSpace, pszName);
551 if (pNode)
552 {
553 PDBGFASDBNODE pDbNode = RT_FROM_MEMBER(pNode, DBGFASDBNODE, NameCore);
554 hDbgAs = (RTDBGAS)pDbNode->HandleCore.Key;
555 uint32_t cRefs = RTDbgAsRetain(hDbgAs);
556 if (RT_UNLIKELY(cRefs == UINT32_MAX))
557 hDbgAs = NIL_RTDBGAS;
558 }
559
560 DBGF_AS_DB_UNLOCK_READ(pUVM);
561 return hDbgAs;
562}
563
564
565/**
566 * Query an address space by process ID.
567 *
568 * @returns Retained address space handle if found, NIL_RTDBGAS if not.
569 *
570 * @param pUVM The user mode VM handle.
571 * @param ProcId The process ID.
572 */
573VMMR3DECL(RTDBGAS) DBGFR3AsQueryByPid(PUVM pUVM, RTPROCESS ProcId)
574{
575 /*
576 * Validate the input.
577 */
578 UVM_ASSERT_VALID_EXT_RETURN(pUVM, NIL_RTDBGAS);
579 AssertReturn(ProcId != NIL_RTPROCESS, NIL_RTDBGAS);
580
581 /*
582 * Look it up in the PID tree and retain the result.
583 */
584 RTDBGAS hDbgAs = NIL_RTDBGAS;
585 DBGF_AS_DB_LOCK_READ(pUVM);
586
587 PAVLU32NODECORE pNode = RTAvlU32Get(&pUVM->dbgf.s.AsPidTree, ProcId);
588 if (pNode)
589 {
590 PDBGFASDBNODE pDbNode = RT_FROM_MEMBER(pNode, DBGFASDBNODE, PidCore);
591 hDbgAs = (RTDBGAS)pDbNode->HandleCore.Key;
592 uint32_t cRefs = RTDbgAsRetain(hDbgAs);
593 if (RT_UNLIKELY(cRefs == UINT32_MAX))
594 hDbgAs = NIL_RTDBGAS;
595 }
596 DBGF_AS_DB_UNLOCK_READ(pUVM);
597
598 return hDbgAs;
599}
600
601
602/**
603 * Searches for the file in the path.
604 *
605 * The file is first tested without any path modification, then we walk the path
606 * looking in each directory.
607 *
608 * @returns VBox status code.
609 * @param pszFilename The file to search for.
610 * @param pszPath The search path.
611 * @param pfnOpen The open callback function.
612 * @param pvUser User argument for the callback.
613 */
614static int dbgfR3AsSearchPath(const char *pszFilename, const char *pszPath, PFNDBGFR3ASSEARCHOPEN pfnOpen, void *pvUser)
615{
616 char szFound[RTPATH_MAX];
617
618 /* Check the filename length. */
619 size_t const cchFilename = strlen(pszFilename);
620 if (cchFilename >= sizeof(szFound))
621 return VERR_FILENAME_TOO_LONG;
622 const char *pszName = RTPathFilename(pszFilename);
623 if (!pszName)
624 return VERR_IS_A_DIRECTORY;
625 size_t const cchName = strlen(pszName);
626
627 /*
628 * Try default location first.
629 */
630 memcpy(szFound, pszFilename, cchFilename + 1);
631 int rc = pfnOpen(szFound, pvUser);
632 if (RT_SUCCESS(rc))
633 return rc;
634
635 /*
636 * Walk the search path.
637 */
638 const char *psz = pszPath;
639 while (*psz)
640 {
641 /* Skip leading blanks - no directories with leading spaces, thank you. */
642 while (RT_C_IS_BLANK(*psz))
643 psz++;
644
645 /* Find the end of this element. */
646 const char *pszNext;
647 const char *pszEnd = strchr(psz, ';');
648 if (!pszEnd)
649 pszEnd = pszNext = strchr(psz, '\0');
650 else
651 pszNext = pszEnd + 1;
652 if (pszEnd != psz)
653 {
654 size_t const cch = pszEnd - psz;
655 if (cch + 1 + cchName < sizeof(szFound))
656 {
657 /** @todo RTPathCompose, RTPathComposeN(). This code isn't right
658 * for 'E:' on DOS systems. It may also create unwanted double slashes. */
659 memcpy(szFound, psz, cch);
660 szFound[cch] = '/';
661 memcpy(szFound + cch + 1, pszName, cchName + 1);
662 int rc2 = pfnOpen(szFound, pvUser);
663 if (RT_SUCCESS(rc2))
664 return rc2;
665 if ( rc2 != rc
666 && ( rc == VERR_FILE_NOT_FOUND
667 || rc == VERR_OPEN_FAILED))
668 rc = rc2;
669 }
670 }
671
672 /* advance */
673 psz = pszNext;
674 }
675
676 /*
677 * Walk the path once again, this time do a depth search.
678 */
679 /** @todo do a depth search using the specified path. */
680
681 /* failed */
682 return rc;
683}
684
685
686/**
687 * Same as dbgfR3AsSearchEnv, except that the path is taken from the environment.
688 *
689 * If the environment variable doesn't exist, the current directory is searched
690 * instead.
691 *
692 * @returns VBox status code.
693 * @param pszFilename The filename.
694 * @param pszEnvVar The environment variable name.
695 * @param pfnOpen The open callback function.
696 * @param pvUser User argument for the callback.
697 */
698static int dbgfR3AsSearchEnvPath(const char *pszFilename, const char *pszEnvVar, PFNDBGFR3ASSEARCHOPEN pfnOpen, void *pvUser)
699{
700 int rc;
701 char *pszPath = RTEnvDupEx(RTENV_DEFAULT, pszEnvVar);
702 if (pszPath)
703 {
704 rc = dbgfR3AsSearchPath(pszFilename, pszPath, pfnOpen, pvUser);
705 RTStrFree(pszPath);
706 }
707 else
708 rc = dbgfR3AsSearchPath(pszFilename, ".", pfnOpen, pvUser);
709 return rc;
710}
711
712
713/**
714 * Same as dbgfR3AsSearchEnv, except that the path is taken from the DBGF config
715 * (CFGM).
716 *
717 * Nothing is done if the CFGM variable isn't set.
718 *
719 * @returns VBox status code.
720 * @param pUVM The user mode VM handle.
721 * @param pszFilename The filename.
722 * @param pszCfgValue The name of the config variable (under /DBGF/).
723 * @param pfnOpen The open callback function.
724 * @param pvUser User argument for the callback.
725 */
726static int dbgfR3AsSearchCfgPath(PUVM pUVM, const char *pszFilename, const char *pszCfgValue,
727 PFNDBGFR3ASSEARCHOPEN pfnOpen, void *pvUser)
728{
729 char *pszPath;
730 int rc = CFGMR3QueryStringAllocDef(CFGMR3GetChild(CFGMR3GetRootU(pUVM), "/DBGF"), pszCfgValue, &pszPath, NULL);
731 if (RT_FAILURE(rc))
732 return rc;
733 if (!pszPath)
734 return VERR_FILE_NOT_FOUND;
735 rc = dbgfR3AsSearchPath(pszFilename, pszPath, pfnOpen, pvUser);
736 MMR3HeapFree(pszPath);
737 return rc;
738}
739
740
741/**
742 * Callback function used by DBGFR3AsLoadImage.
743 *
744 * @returns VBox status code.
745 * @param pszFilename The filename under evaluation.
746 * @param pvUser Use arguments (DBGFR3ASLOADOPENDATA).
747 */
748static DECLCALLBACK(int) dbgfR3AsLoadImageOpen(const char *pszFilename, void *pvUser)
749{
750 DBGFR3ASLOADOPENDATA *pData = (DBGFR3ASLOADOPENDATA *)pvUser;
751 return RTDbgModCreateFromImage(&pData->hMod, pszFilename, pData->pszModName, pData->fFlags);
752}
753
754
755/**
756 * Load symbols from an executable module into the specified address space.
757 *
758 * If an module exist at the specified address it will be replaced by this
759 * call, otherwise a new module is created.
760 *
761 * @returns VBox status code.
762 *
763 * @param pUVM The user mode VM handle.
764 * @param hDbgAs The address space.
765 * @param pszFilename The filename of the executable module.
766 * @param pszModName The module name. If NULL, then then the file name
767 * base is used (no extension or nothing).
768 * @param pModAddress The load address of the module.
769 * @param iModSeg The segment to load, pass NIL_RTDBGSEGIDX to load
770 * the whole image.
771 * @param fFlags Flags reserved for future extensions, must be 0.
772 */
773VMMR3DECL(int) DBGFR3AsLoadImage(PUVM pUVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags)
774{
775 /*
776 * Validate input
777 */
778 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
779 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
780 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
781 AssertReturn(DBGFR3AddrIsValid(pUVM, pModAddress), VERR_INVALID_PARAMETER);
782 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER);
783 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
784 if (hRealAS == NIL_RTDBGAS)
785 return VERR_INVALID_HANDLE;
786
787 /*
788 * Do the work.
789 */
790 DBGFR3ASLOADOPENDATA Data;
791 Data.pszModName = pszModName;
792 Data.uSubtrahend = 0;
793 Data.fFlags = 0;
794 Data.hMod = NIL_RTDBGMOD;
795 int rc = dbgfR3AsSearchCfgPath(pUVM, pszFilename, "ImagePath", dbgfR3AsLoadImageOpen, &Data);
796 if (RT_FAILURE(rc))
797 rc = dbgfR3AsSearchEnvPath(pszFilename, "VBOXDBG_IMAGE_PATH", dbgfR3AsLoadImageOpen, &Data);
798 if (RT_FAILURE(rc))
799 rc = dbgfR3AsSearchCfgPath(pUVM, pszFilename, "Path", dbgfR3AsLoadImageOpen, &Data);
800 if (RT_FAILURE(rc))
801 rc = dbgfR3AsSearchEnvPath(pszFilename, "VBOXDBG_PATH", dbgfR3AsLoadImageOpen, &Data);
802 if (RT_SUCCESS(rc))
803 {
804 rc = DBGFR3AsLinkModule(pUVM, hRealAS, Data.hMod, pModAddress, iModSeg, 0);
805 if (RT_FAILURE(rc))
806 RTDbgModRelease(Data.hMod);
807 }
808
809 RTDbgAsRelease(hRealAS);
810 return rc;
811}
812
813
814/**
815 * Callback function used by DBGFR3AsLoadMap.
816 *
817 * @returns VBox status code.
818 * @param pszFilename The filename under evaluation.
819 * @param pvUser Use arguments (DBGFR3ASLOADOPENDATA).
820 */
821static DECLCALLBACK(int) dbgfR3AsLoadMapOpen(const char *pszFilename, void *pvUser)
822{
823 DBGFR3ASLOADOPENDATA *pData = (DBGFR3ASLOADOPENDATA *)pvUser;
824 return RTDbgModCreateFromMap(&pData->hMod, pszFilename, pData->pszModName, pData->uSubtrahend, pData->fFlags);
825}
826
827
828/**
829 * Load symbols from a map file into a module at the specified address space.
830 *
831 * If an module exist at the specified address it will be replaced by this
832 * call, otherwise a new module is created.
833 *
834 * @returns VBox status code.
835 *
836 * @param pUVM The user mode VM handle.
837 * @param hDbgAs The address space.
838 * @param pszFilename The map file.
839 * @param pszModName The module name. If NULL, then then the file name
840 * base is used (no extension or nothing).
841 * @param pModAddress The load address of the module.
842 * @param iModSeg The segment to load, pass NIL_RTDBGSEGIDX to load
843 * the whole image.
844 * @param uSubtrahend Value to to subtract from the symbols in the map
845 * file. This is useful for the linux System.map and
846 * /proc/kallsyms.
847 * @param fFlags Flags reserved for future extensions, must be 0.
848 */
849VMMR3DECL(int) DBGFR3AsLoadMap(PUVM pUVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName,
850 PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, RTGCUINTPTR uSubtrahend, uint32_t fFlags)
851{
852 /*
853 * Validate input
854 */
855 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
856 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
857 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
858 AssertReturn(DBGFR3AddrIsValid(pUVM, pModAddress), VERR_INVALID_PARAMETER);
859 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER);
860 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
861 if (hRealAS == NIL_RTDBGAS)
862 return VERR_INVALID_HANDLE;
863
864 /*
865 * Do the work.
866 */
867 DBGFR3ASLOADOPENDATA Data;
868 Data.pszModName = pszModName;
869 Data.uSubtrahend = uSubtrahend;
870 Data.fFlags = 0;
871 Data.hMod = NIL_RTDBGMOD;
872 int rc = dbgfR3AsSearchCfgPath(pUVM, pszFilename, "MapPath", dbgfR3AsLoadMapOpen, &Data);
873 if (RT_FAILURE(rc))
874 rc = dbgfR3AsSearchEnvPath(pszFilename, "VBOXDBG_MAP_PATH", dbgfR3AsLoadMapOpen, &Data);
875 if (RT_FAILURE(rc))
876 rc = dbgfR3AsSearchCfgPath(pUVM, pszFilename, "Path", dbgfR3AsLoadMapOpen, &Data);
877 if (RT_FAILURE(rc))
878 rc = dbgfR3AsSearchEnvPath(pszFilename, "VBOXDBG_PATH", dbgfR3AsLoadMapOpen, &Data);
879 if (RT_SUCCESS(rc))
880 {
881 rc = DBGFR3AsLinkModule(pUVM, hRealAS, Data.hMod, pModAddress, iModSeg, 0);
882 if (RT_FAILURE(rc))
883 RTDbgModRelease(Data.hMod);
884 }
885
886 RTDbgAsRelease(hRealAS);
887 return rc;
888}
889
890
891/**
892 * Wrapper around RTDbgAsModuleLink, RTDbgAsModuleLinkSeg and DBGFR3AsResolve.
893 *
894 * @returns VBox status code.
895 * @param pUVM The user mode VM handle.
896 * @param hDbgAs The address space handle.
897 * @param hMod The module handle.
898 * @param pModAddress The link address.
899 * @param iModSeg The segment to link, NIL_RTDBGSEGIDX for the entire image.
900 * @param fFlags Flags to pass to the link functions, see RTDBGASLINK_FLAGS_*.
901 */
902VMMR3DECL(int) DBGFR3AsLinkModule(PUVM pUVM, RTDBGAS hDbgAs, RTDBGMOD hMod, PCDBGFADDRESS pModAddress,
903 RTDBGSEGIDX iModSeg, uint32_t fFlags)
904{
905 /*
906 * Input validation.
907 */
908 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
909 AssertReturn(DBGFR3AddrIsValid(pUVM, pModAddress), VERR_INVALID_PARAMETER);
910 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
911 if (hRealAS == NIL_RTDBGAS)
912 return VERR_INVALID_HANDLE;
913
914 /*
915 * Do the job.
916 */
917 int rc;
918 if (iModSeg == NIL_RTDBGSEGIDX)
919 rc = RTDbgAsModuleLink(hRealAS, hMod, pModAddress->FlatPtr, fFlags);
920 else
921 rc = RTDbgAsModuleLinkSeg(hRealAS, hMod, iModSeg, pModAddress->FlatPtr, fFlags);
922
923 RTDbgAsRelease(hRealAS);
924 return rc;
925}
926
927
928/**
929 * Adds the module name to the symbol name.
930 *
931 * @param pSymbol The symbol info (in/out).
932 * @param hMod The module handle.
933 */
934static void dbgfR3AsSymbolJoinNames(PRTDBGSYMBOL pSymbol, RTDBGMOD hMod)
935{
936 /* Figure the lengths, adjust them if the result is too long. */
937 const char *pszModName = RTDbgModName(hMod);
938 size_t cchModName = strlen(pszModName);
939 size_t cchSymbol = strlen(pSymbol->szName);
940 if (cchModName + 1 + cchSymbol >= sizeof(pSymbol->szName))
941 {
942 if (cchModName >= sizeof(pSymbol->szName) / 4)
943 cchModName = sizeof(pSymbol->szName) / 4;
944 if (cchModName + 1 + cchSymbol >= sizeof(pSymbol->szName))
945 cchSymbol = sizeof(pSymbol->szName) - cchModName - 2;
946 Assert(cchModName + 1 + cchSymbol < sizeof(pSymbol->szName));
947 }
948
949 /* Do the moving and copying. */
950 memmove(&pSymbol->szName[cchModName + 1], &pSymbol->szName[0], cchSymbol + 1);
951 memcpy(&pSymbol->szName[0], pszModName, cchModName);
952 pSymbol->szName[cchModName] = '!';
953}
954
955
956/** Temporary symbol conversion function. */
957static void dbgfR3AsSymbolConvert(PRTDBGSYMBOL pSymbol, PCDBGFSYMBOL pDbgfSym)
958{
959 pSymbol->offSeg = pSymbol->Value = pDbgfSym->Value;
960 pSymbol->cb = pDbgfSym->cb;
961 pSymbol->iSeg = 0;
962 pSymbol->fFlags = 0;
963 pSymbol->iOrdinal = UINT32_MAX;
964 strcpy(pSymbol->szName, pDbgfSym->szName);
965}
966
967
968/**
969 * Query a symbol by address.
970 *
971 * The returned symbol is the one we consider closes to the specified address.
972 *
973 * @returns VBox status code. See RTDbgAsSymbolByAddr.
974 *
975 * @param pUVM The user mode VM handle.
976 * @param hDbgAs The address space handle.
977 * @param pAddress The address to lookup.
978 * @param poffDisp Where to return the distance between the returned
979 * symbol and pAddress. Optional.
980 * @param pSymbol Where to return the symbol information. The returned
981 * symbol name will be prefixed by the module name as
982 * far as space allows.
983 * @param phMod Where to return the module handle. Optional.
984 */
985VMMR3DECL(int) DBGFR3AsSymbolByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress,
986 PRTGCINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
987{
988 /*
989 * Implement the special address space aliases the lazy way.
990 */
991 if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL)
992 {
993 int rc = DBGFR3AsSymbolByAddr(pUVM, DBGF_AS_RC, pAddress, poffDisp, pSymbol, phMod);
994 if (RT_FAILURE(rc))
995 rc = DBGFR3AsSymbolByAddr(pUVM, DBGF_AS_GLOBAL, pAddress, poffDisp, pSymbol, phMod);
996 return rc;
997 }
998
999 /*
1000 * Input validation.
1001 */
1002 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1003 AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER);
1004 AssertPtrNullReturn(poffDisp, VERR_INVALID_POINTER);
1005 AssertPtrReturn(pSymbol, VERR_INVALID_POINTER);
1006 AssertPtrNullReturn(phMod, VERR_INVALID_POINTER);
1007 if (poffDisp)
1008 *poffDisp = 0;
1009 if (phMod)
1010 *phMod = NIL_RTDBGMOD;
1011 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
1012 if (hRealAS == NIL_RTDBGAS)
1013 return VERR_INVALID_HANDLE;
1014
1015 /*
1016 * Do the lookup.
1017 */
1018 RTDBGMOD hMod;
1019 int rc = RTDbgAsSymbolByAddr(hRealAS, pAddress->FlatPtr, RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL, poffDisp, pSymbol, &hMod);
1020 if (RT_SUCCESS(rc))
1021 {
1022 dbgfR3AsSymbolJoinNames(pSymbol, hMod);
1023 if (!phMod)
1024 RTDbgModRelease(hMod);
1025 }
1026 /* Temporary conversions. */
1027 else if (hDbgAs == DBGF_AS_GLOBAL)
1028 {
1029 DBGFSYMBOL DbgfSym;
1030 rc = DBGFR3SymbolByAddr(pUVM->pVM, pAddress->FlatPtr, poffDisp, &DbgfSym);
1031 if (RT_SUCCESS(rc))
1032 dbgfR3AsSymbolConvert(pSymbol, &DbgfSym);
1033 }
1034 else if (hDbgAs == DBGF_AS_R0)
1035 {
1036 RTR0PTR R0PtrMod;
1037 char szNearSym[260];
1038 RTR0PTR R0PtrNearSym;
1039 RTR0PTR R0PtrNearSym2;
1040 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
1041 rc = PDMR3LdrQueryR0ModFromPC(pUVM->pVM, pAddress->FlatPtr,
1042 pSymbol->szName, sizeof(pSymbol->szName) / 2, &R0PtrMod,
1043 &szNearSym[0], sizeof(szNearSym), &R0PtrNearSym,
1044 NULL, 0, &R0PtrNearSym2);
1045 if (RT_SUCCESS(rc))
1046 {
1047 pSymbol->offSeg = pSymbol->Value = R0PtrNearSym;
1048 pSymbol->cb = R0PtrNearSym2 > R0PtrNearSym ? R0PtrNearSym2 - R0PtrNearSym : 0;
1049 pSymbol->iSeg = 0;
1050 pSymbol->fFlags = 0;
1051 pSymbol->iOrdinal = UINT32_MAX;
1052 size_t offName = strlen(pSymbol->szName);
1053 pSymbol->szName[offName++] = '!';
1054 size_t cchNearSym = strlen(szNearSym);
1055 if (cchNearSym + offName >= sizeof(pSymbol->szName))
1056 cchNearSym = sizeof(pSymbol->szName) - offName - 1;
1057 strncpy(&pSymbol->szName[offName], szNearSym, cchNearSym);
1058 pSymbol->szName[offName + cchNearSym] = '\0';
1059 if (poffDisp)
1060 *poffDisp = pAddress->FlatPtr - pSymbol->Value;
1061 }
1062 }
1063
1064 return rc;
1065}
1066
1067
1068/**
1069 * Convenience function that combines RTDbgSymbolDup and DBGFR3AsSymbolByAddr.
1070 *
1071 * @returns Pointer to the symbol on success. This must be free using
1072 * RTDbgSymbolFree(). NULL is returned if not found or any error
1073 * occurs.
1074 *
1075 * @param pUVM The user mode VM handle.
1076 * @param hDbgAs See DBGFR3AsSymbolByAddr.
1077 * @param pAddress See DBGFR3AsSymbolByAddr.
1078 * @param poffDisp See DBGFR3AsSymbolByAddr.
1079 * @param phMod See DBGFR3AsSymbolByAddr.
1080 */
1081VMMR3DECL(PRTDBGSYMBOL) DBGFR3AsSymbolByAddrA(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, PRTGCINTPTR poffDisp, PRTDBGMOD phMod)
1082{
1083 RTDBGSYMBOL SymInfo;
1084 int rc = DBGFR3AsSymbolByAddr(pUVM, hDbgAs, pAddress, poffDisp, &SymInfo, phMod);
1085 if (RT_SUCCESS(rc))
1086 return RTDbgSymbolDup(&SymInfo);
1087 return NULL;
1088}
1089
1090
1091/**
1092 * Query a symbol by name.
1093 *
1094 * The symbol can be prefixed by a module name pattern to scope the search. The
1095 * pattern is a simple string pattern with '*' and '?' as wild chars. See
1096 * RTStrSimplePatternMatch().
1097 *
1098 * @returns VBox status code. See RTDbgAsSymbolByAddr.
1099 *
1100 * @param pUVM The user mode VM handle.
1101 * @param hDbgAs The address space handle.
1102 * @param pszSymbol The symbol to search for, maybe prefixed by a
1103 * module pattern.
1104 * @param pSymbol Where to return the symbol information.
1105 * The returned symbol name will be prefixed by
1106 * the module name as far as space allows.
1107 * @param phMod Where to return the module handle. Optional.
1108 */
1109VMMR3DECL(int) DBGFR3AsSymbolByName(PUVM pUVM, RTDBGAS hDbgAs, const char *pszSymbol,
1110 PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
1111{
1112 /*
1113 * Implement the special address space aliases the lazy way.
1114 */
1115 if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL)
1116 {
1117 int rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_RC, pszSymbol, pSymbol, phMod);
1118 if (RT_FAILURE(rc))
1119 rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_GLOBAL, pszSymbol, pSymbol, phMod);
1120 return rc;
1121 }
1122
1123 /*
1124 * Input validation.
1125 */
1126 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1127 AssertPtrReturn(pSymbol, VERR_INVALID_POINTER);
1128 AssertPtrNullReturn(phMod, VERR_INVALID_POINTER);
1129 if (phMod)
1130 *phMod = NIL_RTDBGMOD;
1131 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
1132 if (hRealAS == NIL_RTDBGAS)
1133 return VERR_INVALID_HANDLE;
1134
1135
1136 /*
1137 * Do the lookup.
1138 */
1139 RTDBGMOD hMod;
1140 int rc = RTDbgAsSymbolByName(hRealAS, pszSymbol, pSymbol, &hMod);
1141 if (RT_SUCCESS(rc))
1142 {
1143 dbgfR3AsSymbolJoinNames(pSymbol, hMod);
1144 if (!phMod)
1145 RTDbgModRelease(hMod);
1146 }
1147 /* Temporary conversion. */
1148 else if (hDbgAs == DBGF_AS_GLOBAL)
1149 {
1150 DBGFSYMBOL DbgfSym;
1151 rc = DBGFR3SymbolByName(pUVM->pVM, pszSymbol, &DbgfSym);
1152 if (RT_SUCCESS(rc))
1153 dbgfR3AsSymbolConvert(pSymbol, &DbgfSym);
1154 }
1155
1156 return rc;
1157}
1158
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