VirtualBox

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

Last change on this file since 62490 was 62478, checked in by vboxsync, 8 years ago

(C) 2016

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