VirtualBox

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

Last change on this file since 74795 was 73397, checked in by vboxsync, 6 years ago

DBGF: Unwinding PE/AMD64, considered sketches for generic unwinding using unwind info.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use