VirtualBox

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

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

VMM,INTNET: Addressing unused variable warnings.

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