VirtualBox

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

Last change on this file since 26522 was 25942, checked in by vboxsync, 15 years ago

*: RTEnv usage cleanup - avoid RTEnvGet() as it doesn't necessarily return UTF-8 encoded strings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 32.8 KB
Line 
1/* $Id: DBGFAddrSpace.cpp 25942 2010-01-20 17:26:22Z 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 int rc;
646 char *pszPath = RTEnvDupEx(RTENV_DEFAULT, pszEnvVar);
647 if (pszPath)
648 {
649 rc = dbgfR3AsSearchPath(pszFilename, pszPath, pfnOpen, pvUser);
650 RTStrFree(pszPath);
651 }
652 else
653 rc = dbgfR3AsSearchPath(pszFilename, ".", pfnOpen, pvUser);
654 return rc;
655}
656
657
658/**
659 * Callback function used by DBGFR3AsLoadImage.
660 *
661 * @returns VBox status code.
662 * @param pszFilename The filename under evaluation.
663 * @param pvUser Use arguments (DBGFR3ASLOADOPENDATA).
664 */
665static DECLCALLBACK(int) dbgfR3AsLoadImageOpen(const char *pszFilename, void *pvUser)
666{
667 DBGFR3ASLOADOPENDATA *pData = (DBGFR3ASLOADOPENDATA *)pvUser;
668 return RTDbgModCreateFromImage(&pData->hMod, pszFilename, pData->pszModName, pData->fFlags);
669}
670
671
672/**
673 * Load symbols from an executable module into the specified address space.
674 *
675 * If an module exist at the specified address it will be replaced by this
676 * call, otherwise a new module is created.
677 *
678 * @returns VBox status code.
679 *
680 * @param pVM The VM handle.
681 * @param hDbgAs The address space.
682 * @param pszFilename The filename of the executable module.
683 * @param pszModName The module name. If NULL, then then the file name
684 * base is used (no extension or nothing).
685 * @param pModAddress The load address of the module.
686 * @param iModSeg The segment to load, pass NIL_RTDBGSEGIDX to load
687 * the whole image.
688 * @param fFlags Flags reserved for future extensions, must be 0.
689 */
690VMMR3DECL(int) DBGFR3AsLoadImage(PVM pVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags)
691{
692 /*
693 * Validate input
694 */
695 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
696 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
697 AssertReturn(DBGFR3AddrIsValid(pVM, pModAddress), VERR_INVALID_PARAMETER);
698 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER);
699 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pVM, hDbgAs);
700 if (hRealAS == NIL_RTDBGAS)
701 return VERR_INVALID_HANDLE;
702
703 /*
704 * Do the work.
705 */
706 DBGFR3ASLOADOPENDATA Data;
707 Data.pszModName = pszModName;
708 Data.uSubtrahend = 0;
709 Data.fFlags = 0;
710 Data.hMod = NIL_RTDBGMOD;
711 int rc = dbgfR3AsSearchEnvPath(pszFilename, "VBOXDBG_IMAGE_PATH", dbgfR3AsLoadImageOpen, &Data);
712 if (RT_FAILURE(rc))
713 rc = dbgfR3AsSearchEnvPath(pszFilename, "VBOXDBG_PATH", dbgfR3AsLoadImageOpen, &Data);
714 if (RT_SUCCESS(rc))
715 {
716 rc = DBGFR3AsLinkModule(pVM, hRealAS, Data.hMod, pModAddress, iModSeg, 0);
717 if (RT_FAILURE(rc))
718 RTDbgModRelease(Data.hMod);
719 }
720
721 RTDbgAsRelease(hRealAS);
722 return rc;
723}
724
725
726/**
727 * Callback function used by DBGFR3AsLoadMap.
728 *
729 * @returns VBox status code.
730 * @param pszFilename The filename under evaluation.
731 * @param pvUser Use arguments (DBGFR3ASLOADOPENDATA).
732 */
733static DECLCALLBACK(int) dbgfR3AsLoadMapOpen(const char *pszFilename, void *pvUser)
734{
735 DBGFR3ASLOADOPENDATA *pData = (DBGFR3ASLOADOPENDATA *)pvUser;
736 return RTDbgModCreateFromMap(&pData->hMod, pszFilename, pData->pszModName, pData->uSubtrahend, pData->fFlags);
737}
738
739
740/**
741 * Load symbols from a map file into a module at the specified address space.
742 *
743 * If an module exist at the specified address it will be replaced by this
744 * call, otherwise a new module is created.
745 *
746 * @returns VBox status code.
747 *
748 * @param pVM The VM handle.
749 * @param hDbgAs The address space.
750 * @param pszFilename The map file.
751 * @param pszModName The module name. If NULL, then then the file name
752 * base is used (no extension or nothing).
753 * @param pModAddress The load address of the module.
754 * @param iModSeg The segment to load, pass NIL_RTDBGSEGIDX to load
755 * the whole image.
756 * @param uSubtrahend Value to to subtract from the symbols in the map
757 * file. This is useful for the linux System.map and
758 * /proc/kallsyms.
759 * @param fFlags Flags reserved for future extensions, must be 0.
760 */
761VMMR3DECL(int) DBGFR3AsLoadMap(PVM pVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName,
762 PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, RTGCUINTPTR uSubtrahend, uint32_t fFlags)
763{
764 /*
765 * Validate input
766 */
767 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
768 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
769 AssertReturn(DBGFR3AddrIsValid(pVM, pModAddress), VERR_INVALID_PARAMETER);
770 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER);
771 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pVM, hDbgAs);
772 if (hRealAS == NIL_RTDBGAS)
773 return VERR_INVALID_HANDLE;
774
775 /*
776 * Do the work.
777 */
778 DBGFR3ASLOADOPENDATA Data;
779 Data.pszModName = pszModName;
780 Data.uSubtrahend = uSubtrahend;
781 Data.fFlags = 0;
782 Data.hMod = NIL_RTDBGMOD;
783 int rc = dbgfR3AsSearchEnvPath(pszFilename, "VBOXDBG_MAP_PATH", dbgfR3AsLoadMapOpen, &Data);
784 if (RT_FAILURE(rc))
785 rc = dbgfR3AsSearchEnvPath(pszFilename, "VBOXDBG_PATH", dbgfR3AsLoadMapOpen, &Data);
786 if (RT_SUCCESS(rc))
787 {
788 rc = DBGFR3AsLinkModule(pVM, hRealAS, Data.hMod, pModAddress, iModSeg, 0);
789 if (RT_FAILURE(rc))
790 RTDbgModRelease(Data.hMod);
791 }
792
793 RTDbgAsRelease(hRealAS);
794 return rc;
795}
796
797
798/**
799 * Wrapper around RTDbgAsModuleLink, RTDbgAsModuleLinkSeg and DBGFR3AsResolve.
800 *
801 * @returns VBox status code.
802 * @param pVM The VM handle.
803 * @param hDbgAs The address space handle.
804 * @param hMod The module handle.
805 * @param pModAddress The link address.
806 * @param iModSeg The segment to link, NIL_RTDBGSEGIDX for the entire image.
807 * @param fFlags Flags to pass to the link functions, see RTDBGASLINK_FLAGS_*.
808 */
809VMMR3DECL(int) DBGFR3AsLinkModule(PVM pVM, RTDBGAS hDbgAs, RTDBGMOD hMod, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags)
810{
811 /*
812 * Input validation.
813 */
814 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
815 AssertReturn(DBGFR3AddrIsValid(pVM, pModAddress), VERR_INVALID_PARAMETER);
816 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pVM, hDbgAs);
817 if (hRealAS == NIL_RTDBGAS)
818 return VERR_INVALID_HANDLE;
819
820 /*
821 * Do the job.
822 */
823 int rc;
824 if (iModSeg == NIL_RTDBGSEGIDX)
825 rc = RTDbgAsModuleLink(hRealAS, hMod, pModAddress->FlatPtr, fFlags);
826 else
827 rc = RTDbgAsModuleLinkSeg(hRealAS, hMod, iModSeg, pModAddress->FlatPtr, fFlags);
828
829 RTDbgAsRelease(hRealAS);
830 return rc;
831}
832
833
834/**
835 * Adds the module name to the symbol name.
836 *
837 * @param pSymbol The symbol info (in/out).
838 * @param hMod The module handle.
839 */
840static void dbgfR3AsSymbolJoinNames(PRTDBGSYMBOL pSymbol, RTDBGMOD hMod)
841{
842 /* Figure the lengths, adjust them if the result is too long. */
843 const char *pszModName = RTDbgModName(hMod);
844 size_t cchModName = strlen(pszModName);
845 size_t cchSymbol = strlen(pSymbol->szName);
846 if (cchModName + 1 + cchSymbol >= sizeof(pSymbol->szName))
847 {
848 if (cchModName >= sizeof(pSymbol->szName) / 4)
849 cchModName = sizeof(pSymbol->szName) / 4;
850 if (cchModName + 1 + cchSymbol >= sizeof(pSymbol->szName))
851 cchSymbol = sizeof(pSymbol->szName) - cchModName - 2;
852 Assert(cchModName + 1 + cchSymbol < sizeof(pSymbol->szName));
853 }
854
855 /* Do the moving and copying. */
856 memmove(&pSymbol->szName[cchModName + 1], &pSymbol->szName[0], cchSymbol + 1);
857 memcpy(&pSymbol->szName[0], pszModName, cchModName);
858 pSymbol->szName[cchModName] = '!';
859}
860
861
862/** Temporary symbol conversion function. */
863static void dbgfR3AsSymbolConvert(PRTDBGSYMBOL pSymbol, PCDBGFSYMBOL pDbgfSym)
864{
865 pSymbol->offSeg = pSymbol->Value = pDbgfSym->Value;
866 pSymbol->cb = pDbgfSym->cb;
867 pSymbol->iSeg = 0;
868 pSymbol->fFlags = 0;
869 pSymbol->iOrdinal = UINT32_MAX;
870 strcpy(pSymbol->szName, pDbgfSym->szName);
871}
872
873
874/**
875 * Query a symbol by address.
876 *
877 * The returned symbol is the one we consider closes to the specified address.
878 *
879 * @returns VBox status code. See RTDbgAsSymbolByAddr.
880 *
881 * @param pVM The VM handle.
882 * @param hDbgAs The address space handle.
883 * @param pAddress The address to lookup.
884 * @param poffDisp Where to return the distance between the
885 * returned symbol and pAddress. Optional.
886 * @param pSymbol Where to return the symbol information.
887 * The returned symbol name will be prefixed by
888 * the module name as far as space allows.
889 * @param phMod Where to return the module handle. Optional.
890 */
891VMMR3DECL(int) DBGFR3AsSymbolByAddr(PVM pVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress,
892 PRTGCINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
893{
894 /*
895 * Implement the special address space aliases the lazy way.
896 */
897 if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL)
898 {
899 int rc = DBGFR3AsSymbolByAddr(pVM, DBGF_AS_RC, pAddress, poffDisp, pSymbol, phMod);
900 if (RT_FAILURE(rc))
901 rc = DBGFR3AsSymbolByAddr(pVM, DBGF_AS_GLOBAL, pAddress, poffDisp, pSymbol, phMod);
902 return rc;
903 }
904
905 /*
906 * Input validation.
907 */
908 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
909 AssertReturn(DBGFR3AddrIsValid(pVM, pAddress), VERR_INVALID_PARAMETER);
910 AssertPtrNullReturn(poffDisp, VERR_INVALID_POINTER);
911 AssertPtrReturn(pSymbol, VERR_INVALID_POINTER);
912 AssertPtrNullReturn(phMod, VERR_INVALID_POINTER);
913 if (poffDisp)
914 *poffDisp = 0;
915 if (phMod)
916 *phMod = NIL_RTDBGMOD;
917 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pVM, hDbgAs);
918 if (hRealAS == NIL_RTDBGAS)
919 return VERR_INVALID_HANDLE;
920
921 /*
922 * Do the lookup.
923 */
924 RTDBGMOD hMod;
925 int rc = RTDbgAsSymbolByAddr(hRealAS, pAddress->FlatPtr, poffDisp, pSymbol, &hMod);
926 if (RT_SUCCESS(rc))
927 {
928 dbgfR3AsSymbolJoinNames(pSymbol, hMod);
929 if (!phMod)
930 RTDbgModRelease(hMod);
931 }
932 /* Temporary conversion. */
933 else if (hDbgAs == DBGF_AS_GLOBAL)
934 {
935 DBGFSYMBOL DbgfSym;
936 rc = DBGFR3SymbolByAddr(pVM, pAddress->FlatPtr, poffDisp, &DbgfSym);
937 if (RT_SUCCESS(rc))
938 dbgfR3AsSymbolConvert(pSymbol, &DbgfSym);
939 }
940
941 return rc;
942}
943
944
945/**
946 * Convenience function that combines RTDbgSymbolDup and DBGFR3AsSymbolByAddr.
947 *
948 * @returns Pointer to the symbol on success. This must be free using
949 * RTDbgSymbolFree(). NULL is returned if not found or any error
950 * occurs.
951 *
952 * @param pVM The VM handle.
953 * @param hDbgAs See DBGFR3AsSymbolByAddr.
954 * @param pAddress See DBGFR3AsSymbolByAddr.
955 * @param poffDisp See DBGFR3AsSymbolByAddr.
956 * @param phMod See DBGFR3AsSymbolByAddr.
957 */
958VMMR3DECL(PRTDBGSYMBOL) DBGFR3AsSymbolByAddrA(PVM pVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, PRTGCINTPTR poffDisp, PRTDBGMOD phMod)
959{
960 RTDBGSYMBOL SymInfo;
961 int rc = DBGFR3AsSymbolByAddr(pVM, hDbgAs, pAddress, poffDisp, &SymInfo, phMod);
962 if (RT_SUCCESS(rc))
963 return RTDbgSymbolDup(&SymInfo);
964 return NULL;
965}
966
967
968/**
969 * Query a symbol by name.
970 *
971 * The symbol can be prefixed by a module name pattern to scope the search. The
972 * pattern is a simple string pattern with '*' and '?' as wild chars. See
973 * RTStrSimplePatternMatch().
974 *
975 * @returns VBox status code. See RTDbgAsSymbolByAddr.
976 *
977 * @param pVM The VM handle.
978 * @param hDbgAs The address space handle.
979 * @param pszSymbol The symbol to search for, maybe prefixed by a
980 * module pattern.
981 * @param pSymbol Where to return the symbol information.
982 * The returned symbol name will be prefixed by
983 * the module name as far as space allows.
984 * @param phMod Where to return the module handle. Optional.
985 */
986VMMR3DECL(int) DBGFR3AsSymbolByName(PVM pVM, RTDBGAS hDbgAs, const char *pszSymbol,
987 PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
988{
989 /*
990 * Implement the special address space aliases the lazy way.
991 */
992 if (hDbgAs == DBGF_AS_RC_AND_GC_GLOBAL)
993 {
994 int rc = DBGFR3AsSymbolByName(pVM, DBGF_AS_RC, pszSymbol, pSymbol, phMod);
995 if (RT_FAILURE(rc))
996 rc = DBGFR3AsSymbolByName(pVM, DBGF_AS_GLOBAL, pszSymbol, pSymbol, phMod);
997 return rc;
998 }
999
1000 /*
1001 * Input validation.
1002 */
1003 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1004 AssertPtrReturn(pSymbol, VERR_INVALID_POINTER);
1005 AssertPtrNullReturn(phMod, VERR_INVALID_POINTER);
1006 if (phMod)
1007 *phMod = NIL_RTDBGMOD;
1008 RTDBGAS hRealAS = DBGFR3AsResolveAndRetain(pVM, hDbgAs);
1009 if (hRealAS == NIL_RTDBGAS)
1010 return VERR_INVALID_HANDLE;
1011
1012
1013 /*
1014 * Do the lookup.
1015 */
1016 RTDBGMOD hMod;
1017 int rc = RTDbgAsSymbolByName(hRealAS, pszSymbol, pSymbol, &hMod);
1018 if (RT_SUCCESS(rc))
1019 {
1020 dbgfR3AsSymbolJoinNames(pSymbol, hMod);
1021 if (!phMod)
1022 RTDbgModRelease(hMod);
1023 }
1024 /* Temporary conversion. */
1025 else if (hDbgAs == DBGF_AS_GLOBAL)
1026 {
1027 DBGFSYMBOL DbgfSym;
1028 rc = DBGFR3SymbolByName(pVM, pszSymbol, &DbgfSym);
1029 if (RT_SUCCESS(rc))
1030 dbgfR3AsSymbolConvert(pSymbol, &DbgfSym);
1031 }
1032
1033 return rc;
1034}
1035
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