VirtualBox

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

Last change on this file since 102828 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette