VirtualBox

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

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

VMMRC.debug is generally in RTPathAppPrivateNoArch, so add it to the debug info search path.

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