VirtualBox

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

Last change on this file since 39078 was 39078, checked in by vboxsync, 13 years ago

VMM: -Wunused-parameter

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 35.8 KB
Line 
1/* $Id: DBGFAddrSpace.cpp 39078 2011-10-21 14:18:22Z vboxsync $ */
2/** @file
3 * DBGF - Debugger Facility, Address Space Management.
4 */
5
6/*
7 * Copyright (C) 2008 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/pdmapi.h>
42#include <VBox/vmm/mm.h>
43#include "DBGFInternal.h"
44#include <VBox/vmm/vm.h>
45#include <VBox/err.h>
46#include <VBox/log.h>
47
48#include <iprt/asm.h>
49#include <iprt/assert.h>
50#include <iprt/ctype.h>
51#include <iprt/env.h>
52#include <iprt/path.h>
53#include <iprt/param.h>
54
55
56/*******************************************************************************
57* Structures and Typedefs *
58*******************************************************************************/
59/**
60 * Address space database node.
61 */
62typedef struct DBGFASDBNODE
63{
64 /** The node core for DBGF::AsHandleTree, the key is the address space handle. */
65 AVLPVNODECORE HandleCore;
66 /** The node core for DBGF::AsPidTree, the key is the process id. */
67 AVLU32NODECORE PidCore;
68 /** The node core for DBGF::AsNameSpace, the string is the address space name. */
69 RTSTRSPACECORE NameCore;
70
71} DBGFASDBNODE;
72/** Pointer to an address space database node. */
73typedef DBGFASDBNODE *PDBGFASDBNODE;
74
75
76/**
77 * For dbgfR3AsLoadImageOpenData and dbgfR3AsLoadMapOpenData.
78 */
79typedef struct DBGFR3ASLOADOPENDATA
80{
81 const char *pszModName;
82 RTGCUINTPTR uSubtrahend;
83 uint32_t fFlags;
84 RTDBGMOD hMod;
85} DBGFR3ASLOADOPENDATA;
86
87/**
88 * Callback for dbgfR3AsSearchPath and dbgfR3AsSearchEnvPath.
89 *
90 * @returns VBox status code. If success, then the search is completed.
91 * @param pszFilename The file name under evaluation.
92 * @param pvUser The user argument.
93 */
94typedef int FNDBGFR3ASSEARCHOPEN(const char *pszFilename, void *pvUser);
95/** Pointer to a FNDBGFR3ASSEARCHOPEN. */
96typedef FNDBGFR3ASSEARCHOPEN *PFNDBGFR3ASSEARCHOPEN;
97
98
99/*******************************************************************************
100* Defined Constants And Macros *
101*******************************************************************************/
102/** Locks the address space database for writing. */
103#define DBGF_AS_DB_LOCK_WRITE(pVM) \
104 do { \
105 int rcSem = RTSemRWRequestWrite((pVM)->dbgf.s.hAsDbLock, RT_INDEFINITE_WAIT); \
106 AssertRC(rcSem); \
107 } while (0)
108
109/** Unlocks the address space database after writing. */
110#define DBGF_AS_DB_UNLOCK_WRITE(pVM) \
111 do { \
112 int rcSem = RTSemRWReleaseWrite((pVM)->dbgf.s.hAsDbLock); \
113 AssertRC(rcSem); \
114 } while (0)
115
116/** Locks the address space database for reading. */
117#define DBGF_AS_DB_LOCK_READ(pVM) \
118 do { \
119 int rcSem = RTSemRWRequestRead((pVM)->dbgf.s.hAsDbLock, RT_INDEFINITE_WAIT); \
120 AssertRC(rcSem); \
121 } while (0)
122
123/** Unlocks the address space database after reading. */
124#define DBGF_AS_DB_UNLOCK_READ(pVM) \
125 do { \
126 int rcSem = RTSemRWReleaseRead((pVM)->dbgf.s.hAsDbLock); \
127 AssertRC(rcSem); \
128 } while (0)
129
130
131
132/**
133 * Initializes the address space parts of DBGF.
134 *
135 * @returns VBox status code.
136 * @param pVM The VM handle.
137 */
138int dbgfR3AsInit(PVM pVM)
139{
140 /*
141 * Create the semaphore.
142 */
143 int rc = RTSemRWCreate(&pVM->dbgf.s.hAsDbLock);
144 AssertRCReturn(rc, rc);
145
146 /*
147 * Create the standard address spaces.
148 */
149 RTDBGAS hDbgAs;
150 rc = RTDbgAsCreate(&hDbgAs, 0, RTGCPTR_MAX, "Global");
151 AssertRCReturn(rc, rc);
152 rc = DBGFR3AsAdd(pVM, hDbgAs, NIL_RTPROCESS);
153 AssertRCReturn(rc, rc);
154 RTDbgAsRetain(hDbgAs);
155 pVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_GLOBAL)] = hDbgAs;
156
157 RTDbgAsRetain(hDbgAs);
158 pVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_KERNEL)] = hDbgAs;
159
160 rc = RTDbgAsCreate(&hDbgAs, 0, RTGCPHYS_MAX, "Physical");
161 AssertRCReturn(rc, rc);
162 rc = DBGFR3AsAdd(pVM, hDbgAs, NIL_RTPROCESS);
163 AssertRCReturn(rc, rc);
164 RTDbgAsRetain(hDbgAs);
165 pVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_PHYS)] = hDbgAs;
166
167 rc = RTDbgAsCreate(&hDbgAs, 0, RTRCPTR_MAX, "HyperRawMode");
168 AssertRCReturn(rc, rc);
169 rc = DBGFR3AsAdd(pVM, hDbgAs, NIL_RTPROCESS);
170 AssertRCReturn(rc, rc);
171 RTDbgAsRetain(hDbgAs);
172 pVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC)] = hDbgAs;
173 RTDbgAsRetain(hDbgAs);
174 pVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC_AND_GC_GLOBAL)] = hDbgAs;
175
176 rc = RTDbgAsCreate(&hDbgAs, 0, RTR0PTR_MAX, "HyperRing0");
177 AssertRCReturn(rc, rc);
178 rc = DBGFR3AsAdd(pVM, hDbgAs, NIL_RTPROCESS);
179 AssertRCReturn(rc, rc);
180 RTDbgAsRetain(hDbgAs);
181 pVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_R0)] = hDbgAs;
182
183 return VINF_SUCCESS;
184}
185
186
187/**
188 * Callback used by dbgfR3AsTerm / RTAvlPVDestroy to release an address space.
189 *
190 * @returns 0.
191 * @param pNode The address space database node.
192 * @param pvIgnore NULL.
193 */
194static DECLCALLBACK(int) dbgfR3AsTermDestroyNode(PAVLPVNODECORE pNode, void *pvIgnore)
195{
196 PDBGFASDBNODE pDbNode = (PDBGFASDBNODE)pNode;
197 RTDbgAsRelease((RTDBGAS)pDbNode->HandleCore.Key);
198 pDbNode->HandleCore.Key = NIL_RTDBGAS;
199 /* Don't bother freeing it here as MM will free it soon and MM is much at
200 it when doing it wholesale instead of piecemeal. */
201 NOREF(pvIgnore);
202 return 0;
203}
204
205
206/**
207 * Terminates the address space parts of DBGF.
208 *
209 * @param pVM The VM handle.
210 */
211void dbgfR3AsTerm(PVM pVM)
212{
213 /*
214 * Create the semaphore.
215 */
216 int rc = RTSemRWDestroy(pVM->dbgf.s.hAsDbLock);
217 AssertRC(rc);
218 pVM->dbgf.s.hAsDbLock = NIL_RTSEMRW;
219
220 /*
221 * Release all the address spaces.
222 */
223 RTAvlPVDestroy(&pVM->dbgf.s.AsHandleTree, dbgfR3AsTermDestroyNode, NULL);
224 for (size_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.ahAsAliases); i++)
225 {
226 RTDbgAsRelease(pVM->dbgf.s.ahAsAliases[i]);
227 pVM->dbgf.s.ahAsAliases[i] = NIL_RTDBGAS;
228 }
229}
230
231
232/**
233 * Relocates the RC address space.
234 *
235 * @param pVM The VM handle.
236 * @param offDelta The relocation delta.
237 */
238void dbgfR3AsRelocate(PVM pVM, RTGCUINTPTR offDelta)
239{
240 /** @todo */
241 NOREF(pVM); NOREF(offDelta);
242}
243
244
245/**
246 * Adds the address space to the database.
247 *
248 * @returns VBox status code.
249 * @param pVM The VM handle.
250 * @param hDbgAs The address space handle. The reference of the
251 * caller will NOT be consumed.
252 * @param ProcId The process id or NIL_RTPROCESS.
253 */
254VMMR3DECL(int) DBGFR3AsAdd(PVM pVM, RTDBGAS hDbgAs, RTPROCESS ProcId)
255{
256 /*
257 * Input validation.
258 */
259 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
260 const char *pszName = RTDbgAsName(hDbgAs);
261 if (!pszName)
262 return VERR_INVALID_HANDLE;
263 uint32_t cRefs = RTDbgAsRetain(hDbgAs);
264 if (cRefs == UINT32_MAX)
265 return VERR_INVALID_HANDLE;
266
267 /*
268 * Allocate a tracking node.
269 */
270 int rc = VERR_NO_MEMORY;
271 PDBGFASDBNODE pDbNode = (PDBGFASDBNODE)MMR3HeapAlloc(pVM, MM_TAG_DBGF_AS, sizeof(*pDbNode));
272 if (pDbNode)
273 {
274 pDbNode->HandleCore.Key = hDbgAs;
275 pDbNode->PidCore.Key = ProcId;
276 pDbNode->NameCore.pszString = pszName;
277 pDbNode->NameCore.cchString = strlen(pszName);
278 DBGF_AS_DB_LOCK_WRITE(pVM);
279 if (RTStrSpaceInsert(&pVM->dbgf.s.AsNameSpace, &pDbNode->NameCore))
280 {
281 if (RTAvlPVInsert(&pVM->dbgf.s.AsHandleTree, &pDbNode->HandleCore))
282 {
283 DBGF_AS_DB_UNLOCK_WRITE(pVM);
284 return VINF_SUCCESS;
285 }
286
287 /* bail out */
288 RTStrSpaceRemove(&pVM->dbgf.s.AsNameSpace, pszName);
289 }
290 DBGF_AS_DB_UNLOCK_WRITE(pVM);
291 MMR3HeapFree(pDbNode);
292 }
293 RTDbgAsRelease(hDbgAs);
294 return rc;
295}
296
297
298/**
299 * Delete an address space from the database.
300 *
301 * The address space must not be engaged as any of the standard aliases.
302 *
303 * @returns VBox status code.
304 * @retval VERR_SHARING_VIOLATION if in use as an alias.
305 * @retval VERR_NOT_FOUND if not found in the address space database.
306 *
307 * @param pVM The VM handle.
308 * @param hDbgAs The address space handle. Aliases are not allowed.
309 */
310VMMR3DECL(int) DBGFR3AsDelete(PVM pVM, RTDBGAS hDbgAs)
311{
312 /*
313 * Input validation. Retain the address space so it can be released outside
314 * the lock as well as validated.
315 */
316 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
317 if (hDbgAs == NIL_RTDBGAS)
318 return VINF_SUCCESS;
319 uint32_t cRefs = RTDbgAsRetain(hDbgAs);
320 if (cRefs == UINT32_MAX)
321 return VERR_INVALID_HANDLE;
322 RTDbgAsRelease(hDbgAs);
323
324 DBGF_AS_DB_LOCK_WRITE(pVM);
325
326 /*
327 * You cannot delete any of the aliases.
328 */
329 for (size_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.ahAsAliases); i++)
330 if (pVM->dbgf.s.ahAsAliases[i] == hDbgAs)
331 {
332 DBGF_AS_DB_UNLOCK_WRITE(pVM);
333 return VERR_SHARING_VIOLATION;
334 }
335
336 /*
337 * Ok, try remove it from the database.
338 */
339 PDBGFASDBNODE pDbNode = (PDBGFASDBNODE)RTAvlPVRemove(&pVM->dbgf.s.AsHandleTree, hDbgAs);
340 if (!pDbNode)
341 {
342 DBGF_AS_DB_UNLOCK_WRITE(pVM);
343 return VERR_NOT_FOUND;
344 }
345 RTStrSpaceRemove(&pVM->dbgf.s.AsNameSpace, pDbNode->NameCore.pszString);
346 if (pDbNode->PidCore.Key != NIL_RTPROCESS)
347 RTAvlU32Remove(&pVM->dbgf.s.AsPidTree, pDbNode->PidCore.Key);
348
349 DBGF_AS_DB_UNLOCK_WRITE(pVM);
350
351 /*
352 * Free the resources.
353 */
354 RTDbgAsRelease(hDbgAs);
355 MMR3HeapFree(pDbNode);
356
357 return VINF_SUCCESS;
358}
359
360
361/**
362 * Changes an alias to point to a new address space.
363 *
364 * Not all the aliases can be changed, currently it's only DBGF_AS_GLOBAL
365 * and DBGF_AS_KERNEL.
366 *
367 * @returns VBox status code.
368 * @param pVM The VM handle.
369 * @param hAlias The alias to change.
370 * @param hAliasFor The address space hAlias should be an alias for.
371 * This can be an alias. The caller's reference to
372 * this address space will NOT be consumed.
373 */
374VMMR3DECL(int) DBGFR3AsSetAlias(PVM pVM, RTDBGAS hAlias, RTDBGAS hAliasFor)
375{
376 /*
377 * Input validation.
378 */
379 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
380 AssertMsgReturn(DBGF_AS_IS_ALIAS(hAlias), ("%p\n", hAlias), VERR_INVALID_PARAMETER);
381 AssertMsgReturn(!DBGF_AS_IS_FIXED_ALIAS(hAlias), ("%p\n", hAlias), VERR_INVALID_PARAMETER);
382 RTDBGAS hRealAliasFor = DBGFR3AsResolveAndRetain(pVM, hAliasFor);
383 if (hRealAliasFor == NIL_RTDBGAS)
384 return VERR_INVALID_HANDLE;
385
386 /*
387 * Make sure the handle has is already in the database.
388 */
389 int rc = VERR_NOT_FOUND;
390 DBGF_AS_DB_LOCK_WRITE(pVM);
391 if (RTAvlPVGet(&pVM->dbgf.s.AsHandleTree, hRealAliasFor))
392 {
393 /*
394 * Update the alias table and release the current address space.
395 */
396 RTDBGAS hAsOld;
397 ASMAtomicXchgHandle(&pVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(hAlias)], hRealAliasFor, &hAsOld);
398 uint32_t cRefs = RTDbgAsRelease(hAsOld);
399 Assert(cRefs > 0); Assert(cRefs != UINT32_MAX); NOREF(cRefs);
400 rc = VINF_SUCCESS;
401 }
402 DBGF_AS_DB_UNLOCK_WRITE(pVM);
403
404 return rc;
405}
406
407
408/**
409 * @callback_method_impl{FNPDMR3ENUM}
410 */
411static DECLCALLBACK(int) dbgfR3AsLazyPopulateR0Callback(PVM pVM, const char *pszFilename, const char *pszName,
412 RTUINTPTR ImageBase, size_t cbImage, bool fRC, void *pvArg)
413{
414 NOREF(pVM); NOREF(cbImage);
415
416 /* Only ring-0 modules. */
417 if (!fRC)
418 {
419 RTDBGMOD hDbgMod;
420 int rc = RTDbgModCreateFromImage(&hDbgMod, pszFilename, pszName, 0 /*fFlags*/);
421 if (RT_SUCCESS(rc))
422 {
423 rc = RTDbgAsModuleLink((RTDBGAS)pvArg, hDbgMod, ImageBase, 0 /*fFlags*/);
424 if (RT_FAILURE(rc))
425 LogRel(("DBGF: Failed to link module \"%s\" into DBGF_AS_R0 at %RTptr: %Rrc\n",
426 pszName, ImageBase, rc));
427 }
428 else
429 LogRel(("DBGF: RTDbgModCreateFromImage failed with rc=%Rrc for module \"%s\" (%s)\n",
430 rc, pszName, pszFilename));
431 }
432 return VINF_SUCCESS;
433}
434
435
436/**
437 * Lazily populates the specified address space.
438 *
439 * @param pVM The VM handle.
440 * @param hAlias The alias.
441 */
442static void dbgfR3AsLazyPopulate(PVM pVM, RTDBGAS hAlias)
443{
444 DBGF_AS_DB_LOCK_WRITE(pVM);
445 uintptr_t iAlias = DBGF_AS_ALIAS_2_INDEX(hAlias);
446 if (!pVM->dbgf.s.afAsAliasPopuplated[iAlias])
447 {
448 RTDBGAS hAs = pVM->dbgf.s.ahAsAliases[iAlias];
449 if (hAlias == DBGF_AS_R0)
450 PDMR3LdrEnumModules(pVM, dbgfR3AsLazyPopulateR0Callback, hAs);
451 /** @todo what do we do about DBGF_AS_RC? */
452
453 pVM->dbgf.s.afAsAliasPopuplated[iAlias] = true;
454 }
455 DBGF_AS_DB_UNLOCK_WRITE(pVM);
456}
457
458
459/**
460 * Resolves the address space handle into a real handle if it's an alias.
461 *
462 * @returns Real address space handle. NIL_RTDBGAS if invalid handle.
463 *
464 * @param pVM The VM handle.
465 * @param hAlias The possibly address space alias.
466 *
467 * @remarks Doesn't take any locks.
468 */
469VMMR3DECL(RTDBGAS) DBGFR3AsResolve(PVM pVM, RTDBGAS hAlias)
470{
471 VM_ASSERT_VALID_EXT_RETURN(pVM, NULL);
472 AssertCompileNS(NIL_RTDBGAS == (RTDBGAS)0);
473
474 uintptr_t iAlias = DBGF_AS_ALIAS_2_INDEX(hAlias);
475 if (iAlias < DBGF_AS_COUNT)
476 ASMAtomicReadHandle(&pVM->dbgf.s.ahAsAliases[iAlias], &hAlias);
477 return hAlias;
478}
479
480
481/**
482 * Resolves the address space handle into a real handle if it's an alias,
483 * and retains whatever it is.
484 *
485 * @returns Real address space handle. NIL_RTDBGAS if invalid handle.
486 *
487 * @param pVM The VM handle.
488 * @param hAlias The possibly address space alias.
489 */
490VMMR3DECL(RTDBGAS) DBGFR3AsResolveAndRetain(PVM pVM, RTDBGAS hAlias)
491{
492 VM_ASSERT_VALID_EXT_RETURN(pVM, NULL);
493 AssertCompileNS(NIL_RTDBGAS == (RTDBGAS)0);
494
495 uint32_t cRefs;
496 uintptr_t iAlias = DBGF_AS_ALIAS_2_INDEX(hAlias);
497 if (iAlias < DBGF_AS_COUNT)
498 {
499 if (DBGF_AS_IS_FIXED_ALIAS(hAlias))
500 {
501 /* Perform lazy address space population. */
502 if (!pVM->dbgf.s.afAsAliasPopuplated[iAlias])
503 dbgfR3AsLazyPopulate(pVM, hAlias);
504
505 /* Won't ever change, no need to grab the lock. */
506 hAlias = pVM->dbgf.s.ahAsAliases[iAlias];
507 cRefs = RTDbgAsRetain(hAlias);
508 }
509 else
510 {
511 /* May change, grab the lock so we can read it safely. */
512 DBGF_AS_DB_LOCK_READ(pVM);
513 hAlias = pVM->dbgf.s.ahAsAliases[iAlias];
514 cRefs = RTDbgAsRetain(hAlias);
515 DBGF_AS_DB_UNLOCK_READ(pVM);
516 }
517 }
518 else
519 /* Not an alias, just retain it. */
520 cRefs = RTDbgAsRetain(hAlias);
521
522 return cRefs != UINT32_MAX ? hAlias : NIL_RTDBGAS;
523}
524
525
526/**
527 * Query an address space by name.
528 *
529 * @returns Retained address space handle if found, NIL_RTDBGAS if not.
530 *
531 * @param pVM The VM handle.
532 * @param pszName The name.
533 */
534VMMR3DECL(RTDBGAS) DBGFR3AsQueryByName(PVM pVM, const char *pszName)
535{
536 /*
537 * Validate the input.
538 */
539 VM_ASSERT_VALID_EXT_RETURN(pVM, NIL_RTDBGAS);
540 AssertPtrReturn(pszName, NIL_RTDBGAS);
541 AssertReturn(*pszName, NIL_RTDBGAS);
542
543 /*
544 * Look it up in the string space and retain the result.
545 */
546 RTDBGAS hDbgAs = NIL_RTDBGAS;
547 DBGF_AS_DB_LOCK_READ(pVM);
548
549 PRTSTRSPACECORE pNode = RTStrSpaceGet(&pVM->dbgf.s.AsNameSpace, pszName);
550 if (pNode)
551 {
552 PDBGFASDBNODE pDbNode = RT_FROM_MEMBER(pNode, DBGFASDBNODE, NameCore);
553 hDbgAs = (RTDBGAS)pDbNode->HandleCore.Key;
554 uint32_t cRefs = RTDbgAsRetain(hDbgAs);
555 if (RT_UNLIKELY(cRefs == UINT32_MAX))
556 hDbgAs = NIL_RTDBGAS;
557 }
558 DBGF_AS_DB_UNLOCK_READ(pVM);
559
560 return hDbgAs;
561}
562
563
564/**
565 * Query an address space by process ID.
566 *
567 * @returns Retained address space handle if found, NIL_RTDBGAS if not.
568 *
569 * @param pVM The VM handle.
570 * @param ProcId The process ID.
571 */
572VMMR3DECL(RTDBGAS) DBGFR3AsQueryByPid(PVM pVM, RTPROCESS ProcId)
573{
574 /*
575 * Validate the input.
576 */
577 VM_ASSERT_VALID_EXT_RETURN(pVM, NIL_RTDBGAS);
578 AssertReturn(ProcId != NIL_RTPROCESS, NIL_RTDBGAS);
579
580 /*
581 * Look it up in the PID tree and retain the result.
582 */
583 RTDBGAS hDbgAs = NIL_RTDBGAS;
584 DBGF_AS_DB_LOCK_READ(pVM);
585
586 PAVLU32NODECORE pNode = RTAvlU32Get(&pVM->dbgf.s.AsPidTree, ProcId);
587 if (pNode)
588 {
589 PDBGFASDBNODE pDbNode = RT_FROM_MEMBER(pNode, DBGFASDBNODE, PidCore);
590 hDbgAs = (RTDBGAS)pDbNode->HandleCore.Key;
591 uint32_t cRefs = RTDbgAsRetain(hDbgAs);
592 if (RT_UNLIKELY(cRefs == UINT32_MAX))
593 hDbgAs = NIL_RTDBGAS;
594 }
595 DBGF_AS_DB_UNLOCK_READ(pVM);
596
597 return hDbgAs;
598}
599
600
601/**
602 * Searches for the file in the path.
603 *
604 * The file is first tested without any path modification, then we walk the path
605 * looking in each directory.
606 *
607 * @returns VBox status code.
608 * @param pszFilename The file to search for.
609 * @param pszPath The search path.
610 * @param pfnOpen The open callback function.
611 * @param pvUser User argument for the callback.
612 */
613static int dbgfR3AsSearchPath(const char *pszFilename, const char *pszPath, PFNDBGFR3ASSEARCHOPEN pfnOpen, void *pvUser)
614{
615 char szFound[RTPATH_MAX];
616
617 /* Check the filename length. */
618 size_t const cchFilename = strlen(pszFilename);
619 if (cchFilename >= sizeof(szFound))
620 return VERR_FILENAME_TOO_LONG;
621 const char *pszName = RTPathFilename(pszFilename);
622 if (!pszName)
623 return VERR_IS_A_DIRECTORY;
624 size_t const cchName = strlen(pszName);
625
626 /*
627 * Try default location first.
628 */
629 memcpy(szFound, pszFilename, cchFilename + 1);
630 int rc = pfnOpen(szFound, pvUser);
631 if (RT_SUCCESS(rc))
632 return rc;
633
634 /*
635 * Walk the search path.
636 */
637 const char *psz = pszPath;
638 while (*psz)
639 {
640 /* Skip leading blanks - no directories with leading spaces, thank you. */
641 while (RT_C_IS_BLANK(*psz))
642 psz++;
643
644 /* Find the end of this element. */
645 const char *pszNext;
646 const char *pszEnd = strchr(psz, ';');
647 if (!pszEnd)
648 pszEnd = pszNext = strchr(psz, '\0');
649 else
650 pszNext = pszEnd + 1;
651 if (pszEnd != psz)
652 {
653 size_t const cch = pszEnd - psz;
654 if (cch + 1 + cchName < sizeof(szFound))
655 {
656 /** @todo RTPathCompose, RTPathComposeN(). This code isn't right
657 * for 'E:' on DOS systems. It may also create unwanted double slashes. */
658 memcpy(szFound, psz, cch);
659 szFound[cch] = '/';
660 memcpy(szFound + cch + 1, pszName, cchName + 1);
661 int rc2 = pfnOpen(szFound, pvUser);
662 if (RT_SUCCESS(rc2))
663 return rc2;
664 if ( rc2 != rc
665 && ( rc == VERR_FILE_NOT_FOUND
666 || rc == VERR_OPEN_FAILED))
667 rc = rc2;
668 }
669 }
670
671 /* advance */
672 psz = pszNext;
673 }
674
675 /*
676 * Walk the path once again, this time do a depth search.
677 */
678 /** @todo do a depth search using the specified path. */
679
680 /* failed */
681 return rc;
682}
683
684
685/**
686 * Same as dbgfR3AsSearchEnv, except that the path is taken from the environment.
687 *
688 * It the environment variable doesn't exist, the current directory is searched instead.
689 *
690 * @returns VBox status code.
691 * @param pszFilename The filename.
692 * @param pszEnvVar The environment variable name.
693 * @param pfnOpen The open callback function.
694 * @param pvUser User argument for the callback.
695 */
696static int dbgfR3AsSearchEnvPath(const char *pszFilename, const char *pszEnvVar, PFNDBGFR3ASSEARCHOPEN pfnOpen, void *pvUser)
697{
698 int rc;
699 char *pszPath = RTEnvDupEx(RTENV_DEFAULT, pszEnvVar);
700 if (pszPath)
701 {
702 rc = dbgfR3AsSearchPath(pszFilename, pszPath, pfnOpen, pvUser);
703 RTStrFree(pszPath);
704 }
705 else
706 rc = dbgfR3AsSearchPath(pszFilename, ".", pfnOpen, pvUser);
707 return rc;
708}
709
710
711/**
712 * Callback function used by DBGFR3AsLoadImage.
713 *
714 * @returns VBox status code.
715 * @param pszFilename The filename under evaluation.
716 * @param pvUser Use arguments (DBGFR3ASLOADOPENDATA).
717 */
718static DECLCALLBACK(int) dbgfR3AsLoadImageOpen(const char *pszFilename, void *pvUser)
719{
720 DBGFR3ASLOADOPENDATA *pData = (DBGFR3ASLOADOPENDATA *)pvUser;
721 return RTDbgModCreateFromImage(&pData->hMod, pszFilename, pData->pszModName, pData->fFlags);
722}
723
724
725/**
726 * Load symbols from an executable module into the specified address space.
727 *
728 * If an module exist at the specified address it will be replaced by this
729 * call, otherwise a new module is created.
730 *
731 * @returns VBox status code.
732 *
733 * @param pVM The VM handle.
734 * @param hDbgAs The address space.
735 * @param pszFilename The filename of the executable module.
736 * @param pszModName The module name. If NULL, then then the file name
737 * base is used (no extension or nothing).
738 * @param pModAddress The load address of the module.
739 * @param iModSeg The segment to load, pass NIL_RTDBGSEGIDX to load
740 * the whole image.
741 * @param fFlags Flags reserved for future extensions, must be 0.
742 */
743VMMR3DECL(int) DBGFR3AsLoadImage(PVM pVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags)
744{
745 /*
746 * Validate input
747 */
748 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
749 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
750 AssertReturn(DBGFR3AddrIsValid(pVM, pModAddress), VERR_INVALID_PARAMETER);
751 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER);
752 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pVM, hDbgAs);
753 if (hRealAS == NIL_RTDBGAS)
754 return VERR_INVALID_HANDLE;
755
756 /*
757 * Do the work.
758 */
759 DBGFR3ASLOADOPENDATA Data;
760 Data.pszModName = pszModName;
761 Data.uSubtrahend = 0;
762 Data.fFlags = 0;
763 Data.hMod = NIL_RTDBGMOD;
764 int rc = dbgfR3AsSearchEnvPath(pszFilename, "VBOXDBG_IMAGE_PATH", dbgfR3AsLoadImageOpen, &Data);
765 if (RT_FAILURE(rc))
766 rc = dbgfR3AsSearchEnvPath(pszFilename, "VBOXDBG_PATH", dbgfR3AsLoadImageOpen, &Data);
767 if (RT_SUCCESS(rc))
768 {
769 rc = DBGFR3AsLinkModule(pVM, hRealAS, Data.hMod, pModAddress, iModSeg, 0);
770 if (RT_FAILURE(rc))
771 RTDbgModRelease(Data.hMod);
772 }
773
774 RTDbgAsRelease(hRealAS);
775 return rc;
776}
777
778
779/**
780 * Callback function used by DBGFR3AsLoadMap.
781 *
782 * @returns VBox status code.
783 * @param pszFilename The filename under evaluation.
784 * @param pvUser Use arguments (DBGFR3ASLOADOPENDATA).
785 */
786static DECLCALLBACK(int) dbgfR3AsLoadMapOpen(const char *pszFilename, void *pvUser)
787{
788 DBGFR3ASLOADOPENDATA *pData = (DBGFR3ASLOADOPENDATA *)pvUser;
789 return RTDbgModCreateFromMap(&pData->hMod, pszFilename, pData->pszModName, pData->uSubtrahend, pData->fFlags);
790}
791
792
793/**
794 * Load symbols from a map file into a module at the specified address space.
795 *
796 * If an module exist at the specified address it will be replaced by this
797 * call, otherwise a new module is created.
798 *
799 * @returns VBox status code.
800 *
801 * @param pVM The VM handle.
802 * @param hDbgAs The address space.
803 * @param pszFilename The map file.
804 * @param pszModName The module name. If NULL, then then the file name
805 * base is used (no extension or nothing).
806 * @param pModAddress The load address of the module.
807 * @param iModSeg The segment to load, pass NIL_RTDBGSEGIDX to load
808 * the whole image.
809 * @param uSubtrahend Value to to subtract from the symbols in the map
810 * file. This is useful for the linux System.map and
811 * /proc/kallsyms.
812 * @param fFlags Flags reserved for future extensions, must be 0.
813 */
814VMMR3DECL(int) DBGFR3AsLoadMap(PVM pVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName,
815 PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, RTGCUINTPTR uSubtrahend, uint32_t fFlags)
816{
817 /*
818 * Validate input
819 */
820 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
821 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
822 AssertReturn(DBGFR3AddrIsValid(pVM, pModAddress), VERR_INVALID_PARAMETER);
823 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER);
824 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pVM, hDbgAs);
825 if (hRealAS == NIL_RTDBGAS)
826 return VERR_INVALID_HANDLE;
827
828 /*
829 * Do the work.
830 */
831 DBGFR3ASLOADOPENDATA Data;
832 Data.pszModName = pszModName;
833 Data.uSubtrahend = uSubtrahend;
834 Data.fFlags = 0;
835 Data.hMod = NIL_RTDBGMOD;
836 int rc = dbgfR3AsSearchEnvPath(pszFilename, "VBOXDBG_MAP_PATH", dbgfR3AsLoadMapOpen, &Data);
837 if (RT_FAILURE(rc))
838 rc = dbgfR3AsSearchEnvPath(pszFilename, "VBOXDBG_PATH", dbgfR3AsLoadMapOpen, &Data);
839 if (RT_SUCCESS(rc))
840 {
841 rc = DBGFR3AsLinkModule(pVM, hRealAS, Data.hMod, pModAddress, iModSeg, 0);
842 if (RT_FAILURE(rc))
843 RTDbgModRelease(Data.hMod);
844 }
845
846 RTDbgAsRelease(hRealAS);
847 return rc;
848}
849
850
851/**
852 * Wrapper around RTDbgAsModuleLink, RTDbgAsModuleLinkSeg and DBGFR3AsResolve.
853 *
854 * @returns VBox status code.
855 * @param pVM The VM handle.
856 * @param hDbgAs The address space handle.
857 * @param hMod The module handle.
858 * @param pModAddress The link address.
859 * @param iModSeg The segment to link, NIL_RTDBGSEGIDX for the entire image.
860 * @param fFlags Flags to pass to the link functions, see RTDBGASLINK_FLAGS_*.
861 */
862VMMR3DECL(int) DBGFR3AsLinkModule(PVM pVM, RTDBGAS hDbgAs, RTDBGMOD hMod, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags)
863{
864 /*
865 * Input validation.
866 */
867 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
868 AssertReturn(DBGFR3AddrIsValid(pVM, pModAddress), VERR_INVALID_PARAMETER);
869 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pVM, hDbgAs);
870 if (hRealAS == NIL_RTDBGAS)
871 return VERR_INVALID_HANDLE;
872
873 /*
874 * Do the job.
875 */
876 int rc;
877 if (iModSeg == NIL_RTDBGSEGIDX)
878 rc = RTDbgAsModuleLink(hRealAS, hMod, pModAddress->FlatPtr, fFlags);
879 else
880 rc = RTDbgAsModuleLinkSeg(hRealAS, hMod, iModSeg, pModAddress->FlatPtr, fFlags);
881
882 RTDbgAsRelease(hRealAS);
883 return rc;
884}
885
886
887/**
888 * Adds the module name to the symbol name.
889 *
890 * @param pSymbol The symbol info (in/out).
891 * @param hMod The module handle.
892 */
893static void dbgfR3AsSymbolJoinNames(PRTDBGSYMBOL pSymbol, RTDBGMOD hMod)
894{
895 /* Figure the lengths, adjust them if the result is too long. */
896 const char *pszModName = RTDbgModName(hMod);
897 size_t cchModName = strlen(pszModName);
898 size_t cchSymbol = strlen(pSymbol->szName);
899 if (cchModName + 1 + cchSymbol >= sizeof(pSymbol->szName))
900 {
901 if (cchModName >= sizeof(pSymbol->szName) / 4)
902 cchModName = sizeof(pSymbol->szName) / 4;
903 if (cchModName + 1 + cchSymbol >= sizeof(pSymbol->szName))
904 cchSymbol = sizeof(pSymbol->szName) - cchModName - 2;
905 Assert(cchModName + 1 + cchSymbol < sizeof(pSymbol->szName));
906 }
907
908 /* Do the moving and copying. */
909 memmove(&pSymbol->szName[cchModName + 1], &pSymbol->szName[0], cchSymbol + 1);
910 memcpy(&pSymbol->szName[0], pszModName, cchModName);
911 pSymbol->szName[cchModName] = '!';
912}
913
914
915/** Temporary symbol conversion function. */
916static void dbgfR3AsSymbolConvert(PRTDBGSYMBOL pSymbol, PCDBGFSYMBOL pDbgfSym)
917{
918 pSymbol->offSeg = pSymbol->Value = pDbgfSym->Value;
919 pSymbol->cb = pDbgfSym->cb;
920 pSymbol->iSeg = 0;
921 pSymbol->fFlags = 0;
922 pSymbol->iOrdinal = UINT32_MAX;
923 strcpy(pSymbol->szName, pDbgfSym->szName);
924}
925
926
927/**
928 * Query a symbol by address.
929 *
930 * The returned symbol is the one we consider closes to the specified address.
931 *
932 * @returns VBox status code. See RTDbgAsSymbolByAddr.
933 *
934 * @param pVM The VM handle.
935 * @param hDbgAs The address space handle.
936 * @param pAddress The address to lookup.
937 * @param poffDisp Where to return the distance between the
938 * returned symbol and pAddress. Optional.
939 * @param pSymbol Where to return the symbol information.
940 * The returned symbol name will be prefixed by
941 * the module name as far as space allows.
942 * @param phMod Where to return the module handle. Optional.
943 */
944VMMR3DECL(int) DBGFR3AsSymbolByAddr(PVM pVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress,
945 PRTGCINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
946{
947 /*
948 * Implement the special address space aliases the lazy way.
949 */
950 if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL)
951 {
952 int rc = DBGFR3AsSymbolByAddr(pVM, DBGF_AS_RC, pAddress, poffDisp, pSymbol, phMod);
953 if (RT_FAILURE(rc))
954 rc = DBGFR3AsSymbolByAddr(pVM, DBGF_AS_GLOBAL, pAddress, poffDisp, pSymbol, phMod);
955 return rc;
956 }
957
958 /*
959 * Input validation.
960 */
961 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
962 AssertReturn(DBGFR3AddrIsValid(pVM, pAddress), VERR_INVALID_PARAMETER);
963 AssertPtrNullReturn(poffDisp, VERR_INVALID_POINTER);
964 AssertPtrReturn(pSymbol, VERR_INVALID_POINTER);
965 AssertPtrNullReturn(phMod, VERR_INVALID_POINTER);
966 if (poffDisp)
967 *poffDisp = 0;
968 if (phMod)
969 *phMod = NIL_RTDBGMOD;
970 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pVM, hDbgAs);
971 if (hRealAS == NIL_RTDBGAS)
972 return VERR_INVALID_HANDLE;
973
974 /*
975 * Do the lookup.
976 */
977 RTDBGMOD hMod;
978 int rc = RTDbgAsSymbolByAddr(hRealAS, pAddress->FlatPtr, poffDisp, pSymbol, &hMod);
979 if (RT_SUCCESS(rc))
980 {
981 dbgfR3AsSymbolJoinNames(pSymbol, hMod);
982 if (!phMod)
983 RTDbgModRelease(hMod);
984 }
985 /* Temporary conversions. */
986 else if (hDbgAs == DBGF_AS_GLOBAL)
987 {
988 DBGFSYMBOL DbgfSym;
989 rc = DBGFR3SymbolByAddr(pVM, pAddress->FlatPtr, poffDisp, &DbgfSym);
990 if (RT_SUCCESS(rc))
991 dbgfR3AsSymbolConvert(pSymbol, &DbgfSym);
992 }
993 else if (hDbgAs == DBGF_AS_R0)
994 {
995 RTR0PTR R0PtrMod;
996 char szNearSym[260];
997 RTR0PTR R0PtrNearSym;
998 RTR0PTR R0PtrNearSym2;
999 rc = PDMR3LdrQueryR0ModFromPC(pVM, pAddress->FlatPtr,
1000 pSymbol->szName, sizeof(pSymbol->szName) / 2, &R0PtrMod,
1001 &szNearSym[0], sizeof(szNearSym), &R0PtrNearSym,
1002 NULL, 0, &R0PtrNearSym2);
1003 if (RT_SUCCESS(rc))
1004 {
1005 pSymbol->offSeg = pSymbol->Value = R0PtrNearSym;
1006 pSymbol->cb = R0PtrNearSym2 > R0PtrNearSym ? R0PtrNearSym2 - R0PtrNearSym : 0;
1007 pSymbol->iSeg = 0;
1008 pSymbol->fFlags = 0;
1009 pSymbol->iOrdinal = UINT32_MAX;
1010 size_t offName = strlen(pSymbol->szName);
1011 pSymbol->szName[offName++] = '!';
1012 size_t cchNearSym = strlen(szNearSym);
1013 if (cchNearSym + offName >= sizeof(pSymbol->szName))
1014 cchNearSym = sizeof(pSymbol->szName) - offName - 1;
1015 strncpy(&pSymbol->szName[offName], szNearSym, cchNearSym);
1016 pSymbol->szName[offName + cchNearSym] = '\0';
1017 if (poffDisp)
1018 *poffDisp = pAddress->FlatPtr - pSymbol->Value;
1019 }
1020 }
1021
1022 return rc;
1023}
1024
1025
1026/**
1027 * Convenience function that combines RTDbgSymbolDup and DBGFR3AsSymbolByAddr.
1028 *
1029 * @returns Pointer to the symbol on success. This must be free using
1030 * RTDbgSymbolFree(). NULL is returned if not found or any error
1031 * occurs.
1032 *
1033 * @param pVM The VM handle.
1034 * @param hDbgAs See DBGFR3AsSymbolByAddr.
1035 * @param pAddress See DBGFR3AsSymbolByAddr.
1036 * @param poffDisp See DBGFR3AsSymbolByAddr.
1037 * @param phMod See DBGFR3AsSymbolByAddr.
1038 */
1039VMMR3DECL(PRTDBGSYMBOL) DBGFR3AsSymbolByAddrA(PVM pVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, PRTGCINTPTR poffDisp, PRTDBGMOD phMod)
1040{
1041 RTDBGSYMBOL SymInfo;
1042 int rc = DBGFR3AsSymbolByAddr(pVM, hDbgAs, pAddress, poffDisp, &SymInfo, phMod);
1043 if (RT_SUCCESS(rc))
1044 return RTDbgSymbolDup(&SymInfo);
1045 return NULL;
1046}
1047
1048
1049/**
1050 * Query a symbol by name.
1051 *
1052 * The symbol can be prefixed by a module name pattern to scope the search. The
1053 * pattern is a simple string pattern with '*' and '?' as wild chars. See
1054 * RTStrSimplePatternMatch().
1055 *
1056 * @returns VBox status code. See RTDbgAsSymbolByAddr.
1057 *
1058 * @param pVM The VM handle.
1059 * @param hDbgAs The address space handle.
1060 * @param pszSymbol The symbol to search for, maybe prefixed by a
1061 * module pattern.
1062 * @param pSymbol Where to return the symbol information.
1063 * The returned symbol name will be prefixed by
1064 * the module name as far as space allows.
1065 * @param phMod Where to return the module handle. Optional.
1066 */
1067VMMR3DECL(int) DBGFR3AsSymbolByName(PVM pVM, RTDBGAS hDbgAs, const char *pszSymbol,
1068 PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
1069{
1070 /*
1071 * Implement the special address space aliases the lazy way.
1072 */
1073 if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL)
1074 {
1075 int rc = DBGFR3AsSymbolByName(pVM, DBGF_AS_RC, pszSymbol, pSymbol, phMod);
1076 if (RT_FAILURE(rc))
1077 rc = DBGFR3AsSymbolByName(pVM, DBGF_AS_GLOBAL, pszSymbol, pSymbol, phMod);
1078 return rc;
1079 }
1080
1081 /*
1082 * Input validation.
1083 */
1084 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1085 AssertPtrReturn(pSymbol, VERR_INVALID_POINTER);
1086 AssertPtrNullReturn(phMod, VERR_INVALID_POINTER);
1087 if (phMod)
1088 *phMod = NIL_RTDBGMOD;
1089 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pVM, hDbgAs);
1090 if (hRealAS == NIL_RTDBGAS)
1091 return VERR_INVALID_HANDLE;
1092
1093
1094 /*
1095 * Do the lookup.
1096 */
1097 RTDBGMOD hMod;
1098 int rc = RTDbgAsSymbolByName(hRealAS, pszSymbol, pSymbol, &hMod);
1099 if (RT_SUCCESS(rc))
1100 {
1101 dbgfR3AsSymbolJoinNames(pSymbol, hMod);
1102 if (!phMod)
1103 RTDbgModRelease(hMod);
1104 }
1105 /* Temporary conversion. */
1106 else if (hDbgAs == DBGF_AS_GLOBAL)
1107 {
1108 DBGFSYMBOL DbgfSym;
1109 rc = DBGFR3SymbolByName(pVM, pszSymbol, &DbgfSym);
1110 if (RT_SUCCESS(rc))
1111 dbgfR3AsSymbolConvert(pSymbol, &DbgfSym);
1112 }
1113
1114 return rc;
1115}
1116
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