VirtualBox

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

Last change on this file since 33995 was 30257, checked in by vboxsync, 15 years ago

2x use AssertCompileNS.

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