VirtualBox

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

Last change on this file since 29698 was 29250, checked in by vboxsync, 15 years ago

iprt/asm*.h: split out asm-math.h, don't include asm-*.h from asm.h, don't include asm.h from sup.h. Fixed a couple file headers.

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