VirtualBox

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

最後變更 在這個檔案從47825是 47825,由 vboxsync 提交於 12 年 前

VMMRC.debug is generally in RTPathAppPrivateNoArch, so add it to the debug info search path.

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

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