VirtualBox

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

Last change on this file since 24912 was 22112, checked in by vboxsync, 15 years ago

DBGF,REM,Diggers: Converted more of the code dealing with debug symbol to use the DBGFR3As API. Not prefect yet, but we're slowly getting there.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use