VirtualBox

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

Last change on this file since 42640 was 41965, checked in by vboxsync, 13 years ago

VMM: ran scm. Mostly svn:keywords changes (adding Revision).

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