VirtualBox

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

Last change on this file since 50653 was 50407, checked in by vboxsync, 10 years ago

duh

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

© 2023 Oracle
ContactPrivacy policyTerms of Use