VirtualBox

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

Last change on this file since 28800 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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

© 2023 Oracle
ContactPrivacy policyTerms of Use