VirtualBox

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

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

DBGF: Added DBGFR3AsUnlinkModuleByName and extended DBGFR3AsLoadImage with a enmArch parameter for mac os x debugging.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 44.7 KB
Line 
1/* $Id: DBGFAddrSpace.cpp 48694 2013-09-26 00:19:41Z 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 enmArch The desired architecture, use RTLDRARCH_WHATEVER if
943 * it's not relevant or known.
944 * @param pModAddress The load address of the module.
945 * @param iModSeg The segment to load, pass NIL_RTDBGSEGIDX to load
946 * the whole image.
947 * @param fFlags Flags reserved for future extensions, must be 0.
948 */
949VMMR3DECL(int) DBGFR3AsLoadImage(PUVM pUVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName, RTLDRARCH enmArch,
950 PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags)
951{
952 /*
953 * Validate input
954 */
955 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
956 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
957 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
958 AssertReturn(DBGFR3AddrIsValid(pUVM, pModAddress), VERR_INVALID_PARAMETER);
959 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER);
960 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
961 if (hRealAS == NIL_RTDBGAS)
962 return VERR_INVALID_HANDLE;
963
964 RTDBGMOD hDbgMod;
965 int rc = RTDbgModCreateFromImage(&hDbgMod, pszFilename, pszModName, enmArch, pUVM->dbgf.s.hDbgCfg);
966 if (RT_SUCCESS(rc))
967 {
968 rc = DBGFR3AsLinkModule(pUVM, hRealAS, hDbgMod, pModAddress, iModSeg, 0);
969 if (RT_FAILURE(rc))
970 RTDbgModRelease(hDbgMod);
971 }
972
973 RTDbgAsRelease(hRealAS);
974 return rc;
975}
976
977
978/**
979 * Load symbols from a map file into a module at the specified address space.
980 *
981 * If an module exist at the specified address it will be replaced by this
982 * call, otherwise a new module is created.
983 *
984 * @returns VBox status code.
985 *
986 * @param pUVM The user mode VM handle.
987 * @param hDbgAs The address space.
988 * @param pszFilename The map file.
989 * @param pszModName The module name. If NULL, then then the file name
990 * base is used (no extension or nothing).
991 * @param pModAddress The load address of the module.
992 * @param iModSeg The segment to load, pass NIL_RTDBGSEGIDX to load
993 * the whole image.
994 * @param uSubtrahend Value to to subtract from the symbols in the map
995 * file. This is useful for the linux System.map and
996 * /proc/kallsyms.
997 * @param fFlags Flags reserved for future extensions, must be 0.
998 */
999VMMR3DECL(int) DBGFR3AsLoadMap(PUVM pUVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName,
1000 PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, RTGCUINTPTR uSubtrahend, uint32_t fFlags)
1001{
1002 /*
1003 * Validate input
1004 */
1005 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1006 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1007 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
1008 AssertReturn(DBGFR3AddrIsValid(pUVM, pModAddress), VERR_INVALID_PARAMETER);
1009 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER);
1010 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
1011 if (hRealAS == NIL_RTDBGAS)
1012 return VERR_INVALID_HANDLE;
1013
1014 RTDBGMOD hDbgMod;
1015 int rc = RTDbgModCreateFromMap(&hDbgMod, pszFilename, pszModName, uSubtrahend, pUVM->dbgf.s.hDbgCfg);
1016 if (RT_SUCCESS(rc))
1017 {
1018 rc = DBGFR3AsLinkModule(pUVM, hRealAS, hDbgMod, pModAddress, iModSeg, 0);
1019 if (RT_FAILURE(rc))
1020 RTDbgModRelease(hDbgMod);
1021 }
1022
1023 RTDbgAsRelease(hRealAS);
1024 return rc;
1025}
1026
1027
1028/**
1029 * Wrapper around RTDbgAsModuleLink, RTDbgAsModuleLinkSeg and DBGFR3AsResolve.
1030 *
1031 * @returns VBox status code.
1032 * @param pUVM The user mode VM handle.
1033 * @param hDbgAs The address space handle.
1034 * @param hMod The module handle.
1035 * @param pModAddress The link address.
1036 * @param iModSeg The segment to link, NIL_RTDBGSEGIDX for the entire image.
1037 * @param fFlags Flags to pass to the link functions, see RTDBGASLINK_FLAGS_*.
1038 */
1039VMMR3DECL(int) DBGFR3AsLinkModule(PUVM pUVM, RTDBGAS hDbgAs, RTDBGMOD hMod, PCDBGFADDRESS pModAddress,
1040 RTDBGSEGIDX iModSeg, uint32_t fFlags)
1041{
1042 /*
1043 * Input validation.
1044 */
1045 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1046 AssertReturn(DBGFR3AddrIsValid(pUVM, pModAddress), VERR_INVALID_PARAMETER);
1047 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
1048 if (hRealAS == NIL_RTDBGAS)
1049 return VERR_INVALID_HANDLE;
1050
1051 /*
1052 * Do the job.
1053 */
1054 int rc;
1055 if (iModSeg == NIL_RTDBGSEGIDX)
1056 rc = RTDbgAsModuleLink(hRealAS, hMod, pModAddress->FlatPtr, fFlags);
1057 else
1058 rc = RTDbgAsModuleLinkSeg(hRealAS, hMod, iModSeg, pModAddress->FlatPtr, fFlags);
1059
1060 RTDbgAsRelease(hRealAS);
1061 return rc;
1062}
1063
1064
1065/**
1066 * Wrapper around RTDbgAsModuleByName and RTDbgAsModuleUnlink.
1067 *
1068 * Unlinks all mappings matching the given module name.
1069 *
1070 * @returns VBox status code.
1071 * @param pUVM The user mode VM handle.
1072 * @param hDbgAs The address space handle.
1073 * @param pszModName The name of the module to unlink.
1074 */
1075VMMR3DECL(int) DBGFR3AsUnlinkModuleByName(PUVM pUVM, RTDBGAS hDbgAs, const char *pszModName)
1076{
1077 /*
1078 * Input validation.
1079 */
1080 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1081 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
1082 if (hRealAS == NIL_RTDBGAS)
1083 return VERR_INVALID_HANDLE;
1084
1085 /*
1086 * Do the job.
1087 */
1088 RTDBGMOD hMod;
1089 int rc = RTDbgAsModuleByName(hRealAS, pszModName, 0, &hMod);
1090 if (RT_SUCCESS(rc))
1091 {
1092 for (;;)
1093 {
1094 rc = RTDbgAsModuleUnlink(hRealAS, hMod);
1095 RTDbgModRelease(hMod);
1096 if (RT_FAILURE(rc))
1097 break;
1098 rc = RTDbgAsModuleByName(hRealAS, pszModName, 0, &hMod);
1099 if (RT_FAILURE_NP(rc))
1100 {
1101 if (rc == VERR_NOT_FOUND)
1102 rc = VINF_SUCCESS;
1103 break;
1104 }
1105 }
1106 }
1107
1108 RTDbgAsRelease(hRealAS);
1109 return rc;
1110}
1111
1112
1113/**
1114 * Adds the module name to the symbol name.
1115 *
1116 * @param pSymbol The symbol info (in/out).
1117 * @param hMod The module handle.
1118 */
1119static void dbgfR3AsSymbolJoinNames(PRTDBGSYMBOL pSymbol, RTDBGMOD hMod)
1120{
1121 /* Figure the lengths, adjust them if the result is too long. */
1122 const char *pszModName = RTDbgModName(hMod);
1123 size_t cchModName = strlen(pszModName);
1124 size_t cchSymbol = strlen(pSymbol->szName);
1125 if (cchModName + 1 + cchSymbol >= sizeof(pSymbol->szName))
1126 {
1127 if (cchModName >= sizeof(pSymbol->szName) / 4)
1128 cchModName = sizeof(pSymbol->szName) / 4;
1129 if (cchModName + 1 + cchSymbol >= sizeof(pSymbol->szName))
1130 cchSymbol = sizeof(pSymbol->szName) - cchModName - 2;
1131 Assert(cchModName + 1 + cchSymbol < sizeof(pSymbol->szName));
1132 }
1133
1134 /* Do the moving and copying. */
1135 memmove(&pSymbol->szName[cchModName + 1], &pSymbol->szName[0], cchSymbol + 1);
1136 memcpy(&pSymbol->szName[0], pszModName, cchModName);
1137 pSymbol->szName[cchModName] = '!';
1138}
1139
1140
1141/** Temporary symbol conversion function. */
1142static void dbgfR3AsSymbolConvert(PRTDBGSYMBOL pSymbol, PCDBGFSYMBOL pDbgfSym)
1143{
1144 pSymbol->offSeg = pSymbol->Value = pDbgfSym->Value;
1145 pSymbol->cb = pDbgfSym->cb;
1146 pSymbol->iSeg = 0;
1147 pSymbol->fFlags = 0;
1148 pSymbol->iOrdinal = UINT32_MAX;
1149 strcpy(pSymbol->szName, pDbgfSym->szName);
1150}
1151
1152
1153/**
1154 * Query a symbol by address.
1155 *
1156 * The returned symbol is the one we consider closes to the specified address.
1157 *
1158 * @returns VBox status code. See RTDbgAsSymbolByAddr.
1159 *
1160 * @param pUVM The user mode VM handle.
1161 * @param hDbgAs The address space handle.
1162 * @param pAddress The address to lookup.
1163 * @param fFlags One of the RTDBGSYMADDR_FLAGS_XXX flags.
1164 * @param poffDisp Where to return the distance between the returned
1165 * symbol and pAddress. Optional.
1166 * @param pSymbol Where to return the symbol information. The returned
1167 * symbol name will be prefixed by the module name as
1168 * far as space allows.
1169 * @param phMod Where to return the module handle. Optional.
1170 */
1171VMMR3DECL(int) DBGFR3AsSymbolByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, uint32_t fFlags,
1172 PRTGCINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
1173{
1174 /*
1175 * Implement the special address space aliases the lazy way.
1176 */
1177 if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL)
1178 {
1179 int rc = DBGFR3AsSymbolByAddr(pUVM, DBGF_AS_RC, pAddress, fFlags, poffDisp, pSymbol, phMod);
1180 if (RT_FAILURE(rc))
1181 rc = DBGFR3AsSymbolByAddr(pUVM, DBGF_AS_GLOBAL, pAddress, fFlags, poffDisp, pSymbol, phMod);
1182 return rc;
1183 }
1184
1185 /*
1186 * Input validation.
1187 */
1188 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1189 AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER);
1190 AssertPtrNullReturn(poffDisp, VERR_INVALID_POINTER);
1191 AssertPtrReturn(pSymbol, VERR_INVALID_POINTER);
1192 AssertPtrNullReturn(phMod, VERR_INVALID_POINTER);
1193 if (poffDisp)
1194 *poffDisp = 0;
1195 if (phMod)
1196 *phMod = NIL_RTDBGMOD;
1197 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
1198 if (hRealAS == NIL_RTDBGAS)
1199 return VERR_INVALID_HANDLE;
1200
1201 /*
1202 * Do the lookup.
1203 */
1204 RTDBGMOD hMod;
1205 int rc = RTDbgAsSymbolByAddr(hRealAS, pAddress->FlatPtr, fFlags, poffDisp, pSymbol, &hMod);
1206 if (RT_SUCCESS(rc))
1207 {
1208 dbgfR3AsSymbolJoinNames(pSymbol, hMod);
1209 if (!phMod)
1210 RTDbgModRelease(hMod);
1211 }
1212
1213 return rc;
1214}
1215
1216
1217/**
1218 * Convenience function that combines RTDbgSymbolDup and DBGFR3AsSymbolByAddr.
1219 *
1220 * @returns Pointer to the symbol on success. This must be free using
1221 * RTDbgSymbolFree(). NULL is returned if not found or any error
1222 * occurs.
1223 *
1224 * @param pUVM The user mode VM handle.
1225 * @param hDbgAs See DBGFR3AsSymbolByAddr.
1226 * @param pAddress See DBGFR3AsSymbolByAddr.
1227 * @param fFlags See DBGFR3AsSymbolByAddr.
1228 * @param poffDisp See DBGFR3AsSymbolByAddr.
1229 * @param phMod See DBGFR3AsSymbolByAddr.
1230 */
1231VMMR3DECL(PRTDBGSYMBOL) DBGFR3AsSymbolByAddrA(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, uint32_t fFlags,
1232 PRTGCINTPTR poffDisp, PRTDBGMOD phMod)
1233{
1234 RTDBGSYMBOL SymInfo;
1235 int rc = DBGFR3AsSymbolByAddr(pUVM, hDbgAs, pAddress, fFlags, poffDisp, &SymInfo, phMod);
1236 if (RT_SUCCESS(rc))
1237 return RTDbgSymbolDup(&SymInfo);
1238 return NULL;
1239}
1240
1241
1242/**
1243 * Query a symbol by name.
1244 *
1245 * The symbol can be prefixed by a module name pattern to scope the search. The
1246 * pattern is a simple string pattern with '*' and '?' as wild chars. See
1247 * RTStrSimplePatternMatch().
1248 *
1249 * @returns VBox status code. See RTDbgAsSymbolByAddr.
1250 *
1251 * @param pUVM The user mode VM handle.
1252 * @param hDbgAs The address space handle.
1253 * @param pszSymbol The symbol to search for, maybe prefixed by a
1254 * module pattern.
1255 * @param pSymbol Where to return the symbol information.
1256 * The returned symbol name will be prefixed by
1257 * the module name as far as space allows.
1258 * @param phMod Where to return the module handle. Optional.
1259 */
1260VMMR3DECL(int) DBGFR3AsSymbolByName(PUVM pUVM, RTDBGAS hDbgAs, const char *pszSymbol,
1261 PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
1262{
1263 /*
1264 * Implement the special address space aliases the lazy way.
1265 */
1266 if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL)
1267 {
1268 int rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_RC, pszSymbol, pSymbol, phMod);
1269 if (RT_FAILURE(rc))
1270 rc = DBGFR3AsSymbolByName(pUVM, DBGF_AS_GLOBAL, pszSymbol, pSymbol, phMod);
1271 return rc;
1272 }
1273
1274 /*
1275 * Input validation.
1276 */
1277 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1278 AssertPtrReturn(pSymbol, VERR_INVALID_POINTER);
1279 AssertPtrNullReturn(phMod, VERR_INVALID_POINTER);
1280 if (phMod)
1281 *phMod = NIL_RTDBGMOD;
1282 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
1283 if (hRealAS == NIL_RTDBGAS)
1284 return VERR_INVALID_HANDLE;
1285
1286
1287 /*
1288 * Do the lookup.
1289 */
1290 RTDBGMOD hMod;
1291 int rc = RTDbgAsSymbolByName(hRealAS, pszSymbol, pSymbol, &hMod);
1292 if (RT_SUCCESS(rc))
1293 {
1294 dbgfR3AsSymbolJoinNames(pSymbol, hMod);
1295 if (!phMod)
1296 RTDbgModRelease(hMod);
1297 }
1298
1299 return rc;
1300}
1301
1302
1303VMMR3DECL(int) DBGFR3AsLineByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress,
1304 PRTGCINTPTR poffDisp, PRTDBGLINE pLine, PRTDBGMOD phMod)
1305{
1306 /*
1307 * Implement the special address space aliases the lazy way.
1308 */
1309 if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL)
1310 {
1311 int rc = DBGFR3AsLineByAddr(pUVM, DBGF_AS_RC, pAddress, poffDisp, pLine, phMod);
1312 if (RT_FAILURE(rc))
1313 rc = DBGFR3AsLineByAddr(pUVM, DBGF_AS_GLOBAL, pAddress, poffDisp, pLine, phMod);
1314 return rc;
1315 }
1316
1317 /*
1318 * Input validation.
1319 */
1320 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1321 AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER);
1322 AssertPtrNullReturn(poffDisp, VERR_INVALID_POINTER);
1323 AssertPtrReturn(pLine, VERR_INVALID_POINTER);
1324 AssertPtrNullReturn(phMod, VERR_INVALID_POINTER);
1325 if (poffDisp)
1326 *poffDisp = 0;
1327 if (phMod)
1328 *phMod = NIL_RTDBGMOD;
1329 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pUVM, hDbgAs);
1330 if (hRealAS == NIL_RTDBGAS)
1331 return VERR_INVALID_HANDLE;
1332
1333 /*
1334 * Do the lookup.
1335 */
1336 return RTDbgAsLineByAddr(hRealAS, pAddress->FlatPtr, poffDisp, pLine, phMod);
1337}
1338
1339
1340VMMR3DECL(PRTDBGLINE) DBGFR3AsLineByAddrA(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress,
1341 PRTGCINTPTR poffDisp, PRTDBGMOD phMod)
1342{
1343 RTDBGLINE Line;
1344 int rc = DBGFR3AsLineByAddr(pUVM, hDbgAs, pAddress, poffDisp, &Line, phMod);
1345 if (RT_SUCCESS(rc))
1346 return RTDbgLineDup(&Line);
1347 return NULL;
1348}
1349
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