VirtualBox

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

Last change on this file since 76553 was 76553, checked in by vboxsync, 5 years ago

scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use