VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/dbg/dbgas.cpp@ 25645

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

IPRT,DoxyFile.Core: Mopped up the errors in the IPRT doxygen run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 54.5 KB
Line 
1/* $Id: dbgas.cpp 25645 2010-01-05 09:29:31Z vboxsync $ */
2/** @file
3 * IPRT - Debug Address Space.
4 */
5
6/*
7 * Copyright (C) 2009 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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include <iprt/dbg.h>
36#include "internal/iprt.h"
37
38#include <iprt/asm.h>
39#include <iprt/avl.h>
40#include <iprt/assert.h>
41#include <iprt/err.h>
42#include <iprt/mem.h>
43#include <iprt/param.h>
44#include <iprt/string.h>
45#include <iprt/semaphore.h>
46#include "internal/magics.h"
47
48
49/*******************************************************************************
50* Structures and Typedefs *
51*******************************************************************************/
52/** Pointer to a module table entry. */
53typedef struct RTDBGASMOD *PRTDBGASMOD;
54/** Pointer to an address space mapping node. */
55typedef struct RTDBGASMAP *PRTDBGASMAP;
56/** Pointer to a name head. */
57typedef struct RTDBGASNAME *PRTDBGASNAME;
58
59/**
60 * Module entry.
61 */
62typedef struct RTDBGASMOD
63{
64 /** Node core, the module handle is the key. */
65 AVLPVNODECORE Core;
66 /** Pointer to the first mapping of the module or a segment within it. */
67 PRTDBGASMAP pMapHead;
68 /** Pointer to the next module with an identical name. */
69 PRTDBGASMOD pNextName;
70 /** The index into RTDBGASINT::papModules. */
71 uint32_t iOrdinal;
72} RTDBGASMOD;
73
74/**
75 * An address space mapping, either of a full module or a segment.
76 */
77typedef struct RTDBGASMAP
78{
79 /** The AVL node core. Contains the address range. */
80 AVLRUINTPTRNODECORE Core;
81 /** Pointer to the next mapping of the module. */
82 PRTDBGASMAP pNext;
83 /** Pointer to the module. */
84 PRTDBGASMOD pMod;
85 /** Which segment in the module.
86 * This is NIL_RTDBGSEGIDX when the entire module is mapped. */
87 RTDBGSEGIDX iSeg;
88} RTDBGASMAP;
89
90/**
91 * Name in the address space.
92 */
93typedef struct RTDBGASNAME
94{
95 /** The string space node core.*/
96 RTSTRSPACECORE StrCore;
97 /** The list of nodes */
98 PRTDBGASMOD pHead;
99} RTDBGASNAME;
100
101/**
102 * Debug address space instance.
103 */
104typedef struct RTDBGASINT
105{
106 /** Magic value (RTDBGAS_MAGIC). */
107 uint32_t u32Magic;
108 /** The number of reference to this address space. */
109 uint32_t volatile cRefs;
110 /** Handle of the read-write lock. */
111 RTSEMRW hLock;
112 /** Number of modules in the module address space. */
113 uint32_t cModules;
114 /** Pointer to the module table.
115 * The valid array length is given by cModules. */
116 PRTDBGASMOD *papModules;
117 /** AVL tree translating module handles to module entries. */
118 AVLPVTREE ModTree;
119 /** AVL tree mapping addresses to modules. */
120 AVLRUINTPTRTREE MapTree;
121 /** Names of the modules in the name space. */
122 RTSTRSPACE NameSpace;
123 /** The first address the AS. */
124 RTUINTPTR FirstAddr;
125 /** The last address in the AS. */
126 RTUINTPTR LastAddr;
127 /** The name of the address space. (variable length) */
128 char szName[1];
129} RTDBGASINT;
130/** Pointer to an a debug address space instance. */
131typedef RTDBGASINT *PRTDBGASINT;
132
133
134/*******************************************************************************
135* Defined Constants And Macros *
136*******************************************************************************/
137/** Validates an address space handle and returns rc if not valid. */
138#define RTDBGAS_VALID_RETURN_RC(pDbgAs, rc) \
139 do { \
140 AssertPtrReturn((pDbgAs), (rc)); \
141 AssertReturn((pDbgAs)->u32Magic == RTDBGAS_MAGIC, (rc)); \
142 AssertReturn((pDbgAs)->cRefs > 0, (rc)); \
143 } while (0)
144
145/** Locks the address space for reading. */
146#define RTDBGAS_LOCK_READ(pDbgAs) \
147 do { \
148 int rcLock = RTSemRWRequestRead((pDbgAs)->hLock, RT_INDEFINITE_WAIT); \
149 AssertRC(rcLock); \
150 } while (0)
151
152/** Unlocks the address space after reading. */
153#define RTDBGAS_UNLOCK_READ(pDbgAs) \
154 do { \
155 int rcLock = RTSemRWReleaseRead((pDbgAs)->hLock); \
156 AssertRC(rcLock); \
157 } while (0)
158
159/** Locks the address space for writing. */
160#define RTDBGAS_LOCK_WRITE(pDbgAs) \
161 do { \
162 int rcLock = RTSemRWRequestWrite((pDbgAs)->hLock, RT_INDEFINITE_WAIT); \
163 AssertRC(rcLock); \
164 } while (0)
165
166/** Unlocks the address space after writing. */
167#define RTDBGAS_UNLOCK_WRITE(pDbgAs) \
168 do { \
169 int rcLock = RTSemRWReleaseWrite((pDbgAs)->hLock); \
170 AssertRC(rcLock); \
171 } while (0)
172
173
174/*******************************************************************************
175* Internal Functions *
176*******************************************************************************/
177static void rtDbgAsModuleUnlinkMod(PRTDBGASINT pDbgAs, PRTDBGASMOD pMod);
178static void rtDbgAsModuleUnlinkByMap(PRTDBGASINT pDbgAs, PRTDBGASMAP pMap);
179
180
181/**
182 * Creates an empty address space.
183 *
184 * @returns IPRT status code.
185 *
186 * @param phDbgAs Where to store the address space handle on success.
187 * @param FirstAddr The first address in the address space.
188 * @param LastAddr The last address in the address space.
189 * @param pszName The name of the address space.
190 */
191RTDECL(int) RTDbgAsCreate(PRTDBGAS phDbgAs, RTUINTPTR FirstAddr, RTUINTPTR LastAddr, const char *pszName)
192{
193 /*
194 * Input validation.
195 */
196 AssertPtrReturn(phDbgAs, VERR_INVALID_POINTER);
197 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
198 AssertReturn(FirstAddr < LastAddr, VERR_INVALID_PARAMETER);
199
200 /*
201 * Allocate memory for the instance data.
202 */
203 size_t cchName = strlen(pszName);
204 PRTDBGASINT pDbgAs = (PRTDBGASINT)RTMemAlloc(RT_OFFSETOF(RTDBGASINT, szName[cchName + 1]));
205 if (!pDbgAs)
206 return VERR_NO_MEMORY;
207
208 /* initalize it. */
209 pDbgAs->u32Magic = RTDBGAS_MAGIC;
210 pDbgAs->cRefs = 1;
211 pDbgAs->hLock = NIL_RTSEMRW;
212 pDbgAs->cModules = 0;
213 pDbgAs->papModules = NULL;
214 pDbgAs->ModTree = NULL;
215 pDbgAs->MapTree = NULL;
216 pDbgAs->NameSpace = NULL;
217 pDbgAs->FirstAddr = FirstAddr;
218 pDbgAs->LastAddr = LastAddr;
219 memcpy(pDbgAs->szName, pszName, cchName + 1);
220 int rc = RTSemRWCreate(&pDbgAs->hLock);
221 if (RT_SUCCESS(rc))
222 {
223 *phDbgAs = pDbgAs;
224 return VINF_SUCCESS;
225 }
226
227 pDbgAs->u32Magic = 0;
228 RTMemFree(pDbgAs);
229 return rc;
230}
231RT_EXPORT_SYMBOL(RTDbgAsCreate);
232
233
234/**
235 * Variant of RTDbgAsCreate that takes a name format string.
236 *
237 * @returns IPRT status code.
238 *
239 * @param phDbgAs Where to store the address space handle on success.
240 * @param FirstAddr The first address in the address space.
241 * @param LastAddr The last address in the address space.
242 * @param pszNameFmt The name format of the address space.
243 * @param va Format arguments.
244 */
245RTDECL(int) RTDbgAsCreateV(PRTDBGAS phDbgAs, RTUINTPTR FirstAddr, RTUINTPTR LastAddr, const char *pszNameFmt, va_list va)
246{
247 AssertPtrReturn(pszNameFmt, VERR_INVALID_POINTER);
248
249 char *pszName;
250 RTStrAPrintfV(&pszName, pszNameFmt, va);
251 if (!pszName)
252 return VERR_NO_MEMORY;
253
254 int rc = RTDbgAsCreate(phDbgAs, FirstAddr, LastAddr, pszName);
255
256 RTStrFree(pszName);
257 return rc;
258}
259RT_EXPORT_SYMBOL(RTDbgAsCreateV);
260
261
262/**
263 * Variant of RTDbgAsCreate that takes a name format string.
264 *
265 * @returns IPRT status code.
266 *
267 * @param phDbgAs Where to store the address space handle on success.
268 * @param FirstAddr The first address in the address space.
269 * @param LastAddr The last address in the address space.
270 * @param pszNameFmt The name format of the address space.
271 * @param ... Format arguments.
272 */
273RTDECL(int) RTDbgAsCreateF(PRTDBGAS phDbgAs, RTUINTPTR FirstAddr, RTUINTPTR LastAddr, const char *pszNameFmt, ...)
274{
275 va_list va;
276 va_start(va, pszNameFmt);
277 int rc = RTDbgAsCreateV(phDbgAs, FirstAddr, LastAddr, pszNameFmt, va);
278 va_end(va);
279 return rc;
280}
281RT_EXPORT_SYMBOL(RTDbgAsCreateF);
282
283
284/**
285 * Callback used by RTDbgAsDestroy to free all mapping nodes.
286 *
287 * @returns 0
288 * @param pNode The map node.
289 * @param pvUser NULL.
290 */
291static DECLCALLBACK(int) rtDbgAsDestroyMapCallback(PAVLRUINTPTRNODECORE pNode, void *pvUser)
292{
293 RTMemFree(pNode);
294 NOREF(pvUser);
295 return 0;
296}
297
298
299/**
300 * Callback used by RTDbgAsDestroy to free all name space nodes.
301 *
302 * @returns 0
303 * @param pStr The name node.
304 * @param pvUser NULL.
305 */
306static DECLCALLBACK(int) rtDbgAsDestroyNameCallback(PRTSTRSPACECORE pStr, void *pvUser)
307{
308 RTMemFree(pStr);
309 NOREF(pvUser);
310 return 0;
311}
312
313
314/**
315 * Destroys the address space.
316 *
317 * This means unlinking all the modules it currently contains, potentially
318 * causing some or all of them to be destroyed as they are managed by
319 * reference counting.
320 *
321 * @param pDbgAs The address space instance to be destroyed.
322 */
323static void rtDbgAsDestroy(PRTDBGASINT pDbgAs)
324{
325 /*
326 * Mark the address space invalid and release all the modules.
327 */
328 ASMAtomicWriteU32(&pDbgAs->u32Magic, ~RTDBGAS_MAGIC);
329
330 RTAvlrUIntPtrDestroy(&pDbgAs->MapTree, rtDbgAsDestroyMapCallback, NULL);
331 RTStrSpaceDestroy(&pDbgAs->NameSpace, rtDbgAsDestroyNameCallback, NULL);
332
333 uint32_t i = pDbgAs->cModules;
334 while (i-- > 0)
335 {
336 PRTDBGASMOD pMod = pDbgAs->papModules[i];
337 AssertPtr(pMod);
338 if (VALID_PTR(pMod))
339 {
340 Assert(pMod->iOrdinal == i);
341 RTDbgModRelease((RTDBGMOD)pMod->Core.Key);
342 pMod->Core.Key = NIL_RTDBGMOD;
343 pMod->iOrdinal = UINT32_MAX;
344 RTMemFree(pMod);
345 }
346 pDbgAs->papModules[i] = NULL;
347 }
348 RTMemFree(pDbgAs->papModules);
349 pDbgAs->papModules = NULL;
350
351 RTMemFree(pDbgAs);
352}
353
354
355/**
356 * Retains another reference to the address space.
357 *
358 * @returns New reference count, UINT32_MAX on invalid handle (asserted).
359 *
360 * @param hDbgAs The address space handle.
361 *
362 * @remarks Will not take any locks.
363 */
364RTDECL(uint32_t) RTDbgAsRetain(RTDBGAS hDbgAs)
365{
366 PRTDBGASINT pDbgAs = hDbgAs;
367 RTDBGAS_VALID_RETURN_RC(pDbgAs, UINT32_MAX);
368 return ASMAtomicIncU32(&pDbgAs->cRefs);
369}
370RT_EXPORT_SYMBOL(RTDbgAsRetain);
371
372
373/**
374 * Release a reference to the address space.
375 *
376 * When the reference count reaches zero, the address space is destroyed.
377 * That means unlinking all the modules it currently contains, potentially
378 * causing some or all of them to be destroyed as they are managed by
379 * reference counting.
380 *
381 * @returns New reference count, UINT32_MAX on invalid handle (asserted).
382 *
383 * @param hDbgAs The address space handle. The NIL handle is quietly
384 * ignored and 0 is returned.
385 *
386 * @remarks Will not take any locks.
387 */
388RTDECL(uint32_t) RTDbgAsRelease(RTDBGAS hDbgAs)
389{
390 if (hDbgAs == NIL_RTDBGAS)
391 return 0;
392 PRTDBGASINT pDbgAs = hDbgAs;
393 RTDBGAS_VALID_RETURN_RC(pDbgAs, UINT32_MAX);
394
395 uint32_t cRefs = ASMAtomicDecU32(&pDbgAs->cRefs);
396 if (!cRefs)
397 rtDbgAsDestroy(pDbgAs);
398 return cRefs;
399}
400RT_EXPORT_SYMBOL(RTDbgAsRelease);
401
402
403/**
404 * Gets the name of an address space.
405 *
406 * @returns read only address space name.
407 * NULL if hDbgAs is invalid.
408 *
409 * @param hDbgAs The address space handle.
410 *
411 * @remarks Will not take any locks.
412 */
413RTDECL(const char *) RTDbgAsName(RTDBGAS hDbgAs)
414{
415 PRTDBGASINT pDbgAs = hDbgAs;
416 RTDBGAS_VALID_RETURN_RC(pDbgAs, NULL);
417 return pDbgAs->szName;
418}
419RT_EXPORT_SYMBOL(RTDbgAsName);
420
421
422/**
423 * Gets the first address in an address space.
424 *
425 * @returns The address.
426 * 0 if hDbgAs is invalid.
427 *
428 * @param hDbgAs The address space handle.
429 *
430 * @remarks Will not take any locks.
431 */
432RTDECL(RTUINTPTR) RTDbgAsFirstAddr(RTDBGAS hDbgAs)
433{
434 PRTDBGASINT pDbgAs = hDbgAs;
435 RTDBGAS_VALID_RETURN_RC(pDbgAs, 0);
436 return pDbgAs->FirstAddr;
437}
438RT_EXPORT_SYMBOL(RTDbgAsFirstAddr);
439
440
441/**
442 * Gets the last address in an address space.
443 *
444 * @returns The address.
445 * 0 if hDbgAs is invalid.
446 *
447 * @param hDbgAs The address space handle.
448 *
449 * @remarks Will not take any locks.
450 */
451RTDECL(RTUINTPTR) RTDbgAsLastAddr(RTDBGAS hDbgAs)
452{
453 PRTDBGASINT pDbgAs = hDbgAs;
454 RTDBGAS_VALID_RETURN_RC(pDbgAs, 0);
455 return pDbgAs->LastAddr;
456}
457RT_EXPORT_SYMBOL(RTDbgAsLastAddr);
458
459/**
460 * Gets the number of modules in the address space.
461 *
462 * This can be used together with RTDbgAsModuleByIndex
463 * to enumerate the modules.
464 *
465 * @returns The number of modules.
466 *
467 * @param hDbgAs The address space handle.
468 *
469 * @remarks Will not take any locks.
470 */
471RTDECL(uint32_t) RTDbgAsModuleCount(RTDBGAS hDbgAs)
472{
473 PRTDBGASINT pDbgAs = hDbgAs;
474 RTDBGAS_VALID_RETURN_RC(pDbgAs, 0);
475 return pDbgAs->cModules;
476}
477RT_EXPORT_SYMBOL(RTDbgAsModuleCount);
478
479
480/**
481 * Common worker for RTDbgAsModuleLink and RTDbgAsModuleLinkSeg.
482 *
483 * @returns IPRT status.
484 * @param pDbgAs Pointer to the address space instance data.
485 * @param hDbgMod The module to link.
486 * @param iSeg The segment to link or NIL if all.
487 * @param Addr The address we're linking it at.
488 * @param cb The size of what we're linking.
489 * @param pszName The name of the module.
490 * @param fFlags See RTDBGASLINK_FLAGS_*.
491 *
492 * @remarks The caller must have locked the address space for writing.
493 */
494int rtDbgAsModuleLinkCommon(PRTDBGASINT pDbgAs, RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg,
495 RTUINTPTR Addr, RTUINTPTR cb, const char *pszName, uint32_t fFlags)
496{
497 /*
498 * Check that the requested space is undisputed.
499 */
500 for (;;)
501 {
502 PRTDBGASMAP pAdjMod = (PRTDBGASMAP)RTAvlrUIntPtrGetBestFit(&pDbgAs->MapTree, Addr, false /* fAbove */);
503 if ( pAdjMod
504 && pAdjMod->Core.KeyLast >= Addr)
505 {
506 if (!(fFlags & RTDBGASLINK_FLAGS_REPLACE))
507 return VERR_ADDRESS_CONFLICT;
508 rtDbgAsModuleUnlinkByMap(pDbgAs, pAdjMod);
509 continue;
510 }
511 pAdjMod = (PRTDBGASMAP)RTAvlrUIntPtrGetBestFit(&pDbgAs->MapTree, Addr, true /* fAbove */);
512 if ( pAdjMod
513 && pAdjMod->Core.Key <= Addr + cb - 1)
514 {
515 if (!(fFlags & RTDBGASLINK_FLAGS_REPLACE))
516 return VERR_ADDRESS_CONFLICT;
517 rtDbgAsModuleUnlinkByMap(pDbgAs, pAdjMod);
518 continue;
519 }
520 break;
521 }
522
523 /*
524 * First, create or find the module table entry.
525 */
526 PRTDBGASMOD pMod = (PRTDBGASMOD)RTAvlPVGet(&pDbgAs->ModTree, hDbgMod);
527 if (!pMod)
528 {
529 /*
530 * Ok, we need a new entry. Grow the table if necessary.
531 */
532 if (!(pDbgAs->cModules % 32))
533 {
534 void *pvNew = RTMemRealloc(pDbgAs->papModules, sizeof(pDbgAs->papModules[0]) * (pDbgAs->cModules + 32));
535 if (!pvNew)
536 return VERR_NO_MEMORY;
537 pDbgAs->papModules = (PRTDBGASMOD *)pvNew;
538 }
539 pMod = (PRTDBGASMOD)RTMemAlloc(sizeof(*pMod));
540 if (!pMod)
541 return VERR_NO_MEMORY;
542 pMod->Core.Key = hDbgMod;
543 pMod->pMapHead = NULL;
544 pMod->pNextName = NULL;
545 if (RT_UNLIKELY(!RTAvlPVInsert(&pDbgAs->ModTree, &pMod->Core)))
546 {
547 AssertFailed();
548 pDbgAs->cModules--;
549 RTMemFree(pMod);
550 return VERR_INTERNAL_ERROR;
551 }
552 pMod->iOrdinal = pDbgAs->cModules;
553 pDbgAs->papModules[pDbgAs->cModules] = pMod;
554 pDbgAs->cModules++;
555 RTDbgModRetain(hDbgMod);
556
557 /*
558 * Add it to the name space.
559 */
560 PRTDBGASNAME pName = (PRTDBGASNAME)RTStrSpaceGet(&pDbgAs->NameSpace, pszName);
561 if (!pName)
562 {
563 size_t cchName = strlen(pszName);
564 pName = (PRTDBGASNAME)RTMemAlloc(sizeof(*pName) + cchName + 1);
565 if (!pName)
566 {
567 RTDbgModRelease(hDbgMod);
568 pDbgAs->cModules--;
569 RTAvlPVRemove(&pDbgAs->ModTree, hDbgMod);
570 RTMemFree(pMod);
571 return VERR_NO_MEMORY;
572 }
573 pName->StrCore.cchString = cchName;
574 pName->StrCore.pszString = (char *)memcpy(pName + 1, pszName, cchName + 1);
575 pName->pHead = pMod;
576 if (!RTStrSpaceInsert(&pDbgAs->NameSpace, &pName->StrCore))
577 AssertFailed();
578 }
579 else
580 {
581 /* quick, but unfair. */
582 pMod->pNextName = pName->pHead;
583 pName->pHead = pMod;
584 }
585 }
586
587 /*
588 * Create a mapping node.
589 */
590 int rc;
591 PRTDBGASMAP pMap = (PRTDBGASMAP)RTMemAlloc(sizeof(*pMap));
592 if (pMap)
593 {
594 pMap->Core.Key = Addr;
595 pMap->Core.KeyLast = Addr + cb - 1;
596 pMap->pMod = pMod;
597 pMap->iSeg = iSeg;
598 if (RTAvlrUIntPtrInsert(&pDbgAs->MapTree, &pMap->Core))
599 {
600 PRTDBGASMAP *pp = &pMod->pMapHead;
601 while (*pp && (*pp)->Core.Key < Addr)
602 pp = &(*pp)->pNext;
603 pMap->pNext = *pp;
604 *pp = pMap;
605 return VINF_SUCCESS;
606 }
607
608 AssertFailed();
609 RTMemFree(pMap);
610 rc = VERR_ADDRESS_CONFLICT;
611 }
612 else
613 rc = VERR_NO_MEMORY;
614
615 /*
616 * Unlink the module if this was the only mapping.
617 */
618 if (!pMod->pMapHead)
619 rtDbgAsModuleUnlinkMod(pDbgAs, pMod);
620 return rc;
621}
622
623
624/**
625 * Links a module into the address space at the give address.
626 *
627 * The size of the mapping is determined using RTDbgModImageSize().
628 *
629 * @returns IPRT status code.
630 * @retval VERR_OUT_OF_RANGE if the specified address will put the module
631 * outside the address space.
632 * @retval VERR_ADDRESS_CONFLICT if the mapping clashes with existing mappings.
633 *
634 * @param hDbgAs The address space handle.
635 * @param hDbgMod The module handle of the module to be linked in.
636 * @param ImageAddr The address to link the module at.
637 * @param fFlags See RTDBGASLINK_FLAGS_*.
638 */
639RTDECL(int) RTDbgAsModuleLink(RTDBGAS hDbgAs, RTDBGMOD hDbgMod, RTUINTPTR ImageAddr, uint32_t fFlags)
640{
641 /*
642 * Validate input.
643 */
644 PRTDBGASINT pDbgAs = hDbgAs;
645 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
646 const char *pszName = RTDbgModName(hDbgMod);
647 if (!pszName)
648 return VERR_INVALID_HANDLE;
649 RTUINTPTR cb = RTDbgModImageSize(hDbgMod);
650 if (!cb)
651 return VERR_OUT_OF_RANGE;
652 if ( ImageAddr < pDbgAs->FirstAddr
653 || ImageAddr > pDbgAs->LastAddr
654 || ImageAddr + cb - 1 < pDbgAs->FirstAddr
655 || ImageAddr + cb - 1 > pDbgAs->LastAddr
656 || ImageAddr + cb - 1 < ImageAddr)
657 return VERR_OUT_OF_RANGE;
658 AssertReturn(!(fFlags & ~RTDBGASLINK_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
659
660 /*
661 * Invoke worker common with RTDbgAsModuleLinkSeg.
662 */
663 RTDBGAS_LOCK_WRITE(pDbgAs);
664 int rc = rtDbgAsModuleLinkCommon(pDbgAs, hDbgMod, NIL_RTDBGSEGIDX, ImageAddr, cb, pszName, fFlags);
665 RTDBGAS_UNLOCK_WRITE(pDbgAs);
666 return rc;
667}
668RT_EXPORT_SYMBOL(RTDbgAsModuleLink);
669
670
671/**
672 * Links a segment into the address space at the give address.
673 *
674 * The size of the mapping is determined using RTDbgModSegmentSize().
675 *
676 * @returns IPRT status code.
677 * @retval VERR_OUT_OF_RANGE if the specified address will put the module
678 * outside the address space.
679 * @retval VERR_ADDRESS_CONFLICT if the mapping clashes with existing mappings.
680 *
681 * @param hDbgAs The address space handle.
682 * @param hDbgMod The module handle.
683 * @param iSeg The segment number (0-based) of the segment to be
684 * linked in.
685 * @param SegAddr The address to link the segment at.
686 * @param fFlags See RTDBGASLINK_FLAGS_*.
687 */
688RTDECL(int) RTDbgAsModuleLinkSeg(RTDBGAS hDbgAs, RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR SegAddr, uint32_t fFlags)
689{
690 /*
691 * Validate input.
692 */
693 PRTDBGASINT pDbgAs = hDbgAs;
694 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
695 const char *pszName = RTDbgModName(hDbgMod);
696 if (!pszName)
697 return VERR_INVALID_HANDLE;
698 RTUINTPTR cb = RTDbgModSegmentSize(hDbgMod, iSeg);
699 if (!cb)
700 return VERR_OUT_OF_RANGE;
701 if ( SegAddr < pDbgAs->FirstAddr
702 || SegAddr > pDbgAs->LastAddr
703 || SegAddr + cb - 1 < pDbgAs->FirstAddr
704 || SegAddr + cb - 1 > pDbgAs->LastAddr
705 || SegAddr + cb - 1 < SegAddr)
706 return VERR_OUT_OF_RANGE;
707 AssertReturn(!(fFlags & ~RTDBGASLINK_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
708
709 /*
710 * Invoke worker common with RTDbgAsModuleLinkSeg.
711 */
712 RTDBGAS_LOCK_WRITE(pDbgAs);
713 int rc = rtDbgAsModuleLinkCommon(pDbgAs, hDbgMod, iSeg, SegAddr, cb, pszName, fFlags);
714 RTDBGAS_UNLOCK_WRITE(pDbgAs);
715 return rc;
716}
717RT_EXPORT_SYMBOL(RTDbgAsModuleLinkSeg);
718
719
720/**
721 * Worker for RTDbgAsModuleUnlink, RTDbgAsModuleUnlinkByAddr and rtDbgAsModuleLinkCommon.
722 *
723 * @param pDbgAs Pointer to the address space instance data.
724 * @param pMod The module to unlink.
725 *
726 * @remarks The caller must have locked the address space for writing.
727 */
728static void rtDbgAsModuleUnlinkMod(PRTDBGASINT pDbgAs, PRTDBGASMOD pMod)
729{
730 Assert(!pMod->pMapHead);
731
732 /*
733 * Unlink it from the name.
734 */
735 const char *pszName = RTDbgModName((RTDBGMOD)pMod->Core.Key);
736 PRTDBGASNAME pName = (PRTDBGASNAME)RTStrSpaceGet(&pDbgAs->NameSpace, pszName);
737 AssertReturnVoid(pName);
738
739 if (pName->pHead == pMod)
740 pName->pHead = pMod->pNextName;
741 else
742 for (PRTDBGASMOD pCur = pName->pHead; pCur; pCur = pCur->pNextName)
743 if (pCur->pNextName == pMod)
744 {
745 pCur->pNextName = pMod->pNextName;
746 break;
747 }
748 pMod->pNextName = NULL;
749
750 /*
751 * Free the name if this was the last reference to it.
752 */
753 if (!pName->pHead)
754 {
755 pName = (PRTDBGASNAME)RTStrSpaceRemove(&pDbgAs->NameSpace, pName->StrCore.pszString);
756 Assert(pName);
757 RTMemFree(pName);
758 }
759
760 /*
761 * Remove it from the module handle tree.
762 */
763 PAVLPVNODECORE pNode = RTAvlPVRemove(&pDbgAs->ModTree, pMod->Core.Key);
764 Assert(pNode == &pMod->Core);
765
766 /*
767 * Remove it from the module table by replacing it by the last entry.
768 */
769 pDbgAs->cModules--;
770 uint32_t iMod = pMod->iOrdinal;
771 Assert(iMod <= pDbgAs->cModules);
772 if (iMod != pDbgAs->cModules)
773 {
774 PRTDBGASMOD pTailMod = pDbgAs->papModules[pDbgAs->cModules];
775 pTailMod->iOrdinal = iMod;
776 pDbgAs->papModules[iMod] = pTailMod;
777 }
778 pMod->iOrdinal = UINT32_MAX;
779
780 /*
781 * Free it.
782 */
783 RTMemFree(pMod);
784}
785
786
787/**
788 * Worker for RTDbgAsModuleUnlink and RTDbgAsModuleUnlinkByAddr.
789 *
790 * @param pDbgAs Pointer to the address space instance data.
791 * @param pMap The map to unlink and free.
792 *
793 * @remarks The caller must have locked the address space for writing.
794 */
795static void rtDbgAsModuleUnlinkMap(PRTDBGASINT pDbgAs, PRTDBGASMAP pMap)
796{
797 /* remove from the tree */
798 PAVLRUINTPTRNODECORE pNode = RTAvlrUIntPtrRemove(&pDbgAs->MapTree, pMap->Core.Key);
799 Assert(pNode == &pMap->Core);
800
801 /* unlink */
802 PRTDBGASMOD pMod = pMap->pMod;
803 if (pMod->pMapHead == pMap)
804 pMod->pMapHead = pMap->pNext;
805 else
806 {
807 bool fFound = false;
808 for (PRTDBGASMAP pCur = pMod->pMapHead; pCur; pCur = pCur->pNext)
809 if (pCur->pNext == pMap)
810 {
811 pCur->pNext = pMap->pNext;
812 fFound = true;
813 break;
814 }
815 Assert(fFound);
816 }
817
818 /* free it */
819 pMap->Core.Key = pMap->Core.KeyLast = 0;
820 pMap->pNext = NULL;
821 pMap->pMod = NULL;
822 RTMemFree(pMap);
823}
824
825
826/**
827 * Worker for RTDbgAsModuleUnlinkByAddr and rtDbgAsModuleLinkCommon that
828 * unlinks a single mapping and releases the module if it's the last one.
829 *
830 * @param pDbgAs The address space instance.
831 * @param pMap The mapping to unlink.
832 *
833 * @remarks The caller must have locked the address space for writing.
834 */
835static void rtDbgAsModuleUnlinkByMap(PRTDBGASINT pDbgAs, PRTDBGASMAP pMap)
836{
837 /*
838 * Unlink it from the address space.
839 * Unlink the module as well if it's the last mapping it has.
840 */
841 PRTDBGASMOD pMod = pMap->pMod;
842 rtDbgAsModuleUnlinkMap(pDbgAs, pMap);
843 if (!pMod->pMapHead)
844 rtDbgAsModuleUnlinkMod(pDbgAs, pMod);
845}
846
847
848/**
849 * Unlinks all the mappings of a module from the address space.
850 *
851 * @returns IPRT status code.
852 * @retval VERR_NOT_FOUND if the module wasn't found.
853 *
854 * @param hDbgAs The address space handle.
855 * @param hDbgMod The module handle of the module to be unlinked.
856 */
857RTDECL(int) RTDbgAsModuleUnlink(RTDBGAS hDbgAs, RTDBGMOD hDbgMod)
858{
859 /*
860 * Validate input.
861 */
862 PRTDBGASINT pDbgAs = hDbgAs;
863 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
864 if (hDbgMod == NIL_RTDBGMOD)
865 return VINF_SUCCESS;
866
867 RTDBGAS_LOCK_WRITE(pDbgAs);
868 PRTDBGASMOD pMod = (PRTDBGASMOD)RTAvlPVGet(&pDbgAs->ModTree, hDbgMod);
869 if (!pMod)
870 {
871 RTDBGAS_UNLOCK_WRITE(pDbgAs);
872 return VERR_NOT_FOUND;
873 }
874
875 /*
876 * Unmap all everything and release the module.
877 */
878 while (pMod->pMapHead)
879 rtDbgAsModuleUnlinkMap(pDbgAs, pMod->pMapHead);
880 rtDbgAsModuleUnlinkMod(pDbgAs, pMod);
881
882 RTDBGAS_UNLOCK_WRITE(pDbgAs);
883 return VINF_SUCCESS;
884}
885RT_EXPORT_SYMBOL(RTDbgAsModuleUnlink);
886
887
888/**
889 * Unlinks the mapping at the specified address.
890 *
891 * @returns IPRT status code.
892 * @retval VERR_NOT_FOUND if no module or segment is mapped at that address.
893 *
894 * @param hDbgAs The address space handle.
895 * @param Addr The address within the mapping to be unlinked.
896 */
897RTDECL(int) RTDbgAsModuleUnlinkByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr)
898{
899 /*
900 * Validate input.
901 */
902 PRTDBGASINT pDbgAs = hDbgAs;
903 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
904
905 RTDBGAS_LOCK_WRITE(pDbgAs);
906 PRTDBGASMAP pMap = (PRTDBGASMAP)RTAvlrUIntPtrRangeGet(&pDbgAs->MapTree, Addr);
907 if (pMap)
908 {
909 RTDBGAS_UNLOCK_WRITE(pDbgAs);
910 return VERR_NOT_FOUND;
911 }
912
913 /*
914 * Hand it to
915 */
916 rtDbgAsModuleUnlinkByMap(pDbgAs, pMap);
917
918 RTDBGAS_UNLOCK_WRITE(pDbgAs);
919 return VINF_SUCCESS;
920}
921RT_EXPORT_SYMBOL(RTDbgAsModuleUnlinkByAddr);
922
923
924/**
925 * Get a the handle of a module in the address space by is index.
926 *
927 * @returns A retained handle to the specified module. The caller must release
928 * the returned reference.
929 * NIL_RTDBGMOD if invalid index or handle.
930 *
931 * @param hDbgAs The address space handle.
932 * @param iModule The index of the module to get.
933 *
934 * @remarks The module indexes may change after calls to RTDbgAsModuleLink,
935 * RTDbgAsModuleLinkSeg, RTDbgAsModuleUnlink and
936 * RTDbgAsModuleUnlinkByAddr.
937 */
938RTDECL(RTDBGMOD) RTDbgAsModuleByIndex(RTDBGAS hDbgAs, uint32_t iModule)
939{
940 /*
941 * Validate input.
942 */
943 PRTDBGASINT pDbgAs = hDbgAs;
944 RTDBGAS_VALID_RETURN_RC(pDbgAs, NIL_RTDBGMOD);
945
946 RTDBGAS_LOCK_READ(pDbgAs);
947 if (iModule >= pDbgAs->cModules)
948 {
949 RTDBGAS_UNLOCK_READ(pDbgAs);
950 return NIL_RTDBGMOD;
951 }
952
953 /*
954 * Get, retain and return it.
955 */
956 RTDBGMOD hMod = (RTDBGMOD)pDbgAs->papModules[iModule]->Core.Key;
957 RTDbgModRetain(hMod);
958
959 RTDBGAS_UNLOCK_READ(pDbgAs);
960 return hMod;
961}
962RT_EXPORT_SYMBOL(RTDbgAsModuleByIndex);
963
964
965/**
966 * Queries mapping module information by handle.
967 *
968 * @returns IPRT status code.
969 * @retval VERR_NOT_FOUND if no mapping was found at the specified address.
970 *
971 * @param hDbgAs The address space handle.
972 * @param Addr Address within the mapping of the module or segment.
973 * @param phMod Where to the return the retained module handle.
974 * Optional.
975 * @param pAddr Where to return the base address of the mapping.
976 * Optional.
977 * @param piSeg Where to return the segment index. This is set to
978 * NIL if the entire module is mapped as a single
979 * mapping. Optional.
980 */
981RTDECL(int) RTDbgAsModuleByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTDBGMOD phMod, PRTUINTPTR pAddr, PRTDBGSEGIDX piSeg)
982{
983 /*
984 * Validate input.
985 */
986 PRTDBGASINT pDbgAs = hDbgAs;
987 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
988
989 RTDBGAS_LOCK_READ(pDbgAs);
990 PRTDBGASMAP pMap = (PRTDBGASMAP)RTAvlrUIntPtrRangeGet(&pDbgAs->MapTree, Addr);
991 if (pMap)
992 {
993 RTDBGAS_UNLOCK_READ(pDbgAs);
994 return VERR_NOT_FOUND;
995 }
996
997 /*
998 * Set up the return values.
999 */
1000 if (phMod)
1001 {
1002 RTDBGMOD hMod = (RTDBGMOD)pMap->pMod->Core.Key;
1003 RTDbgModRetain(hMod);
1004 *phMod = hMod;
1005 }
1006 if (pAddr)
1007 *pAddr = pMap->Core.Key;
1008 if (piSeg)
1009 *piSeg = pMap->iSeg;
1010
1011 RTDBGAS_UNLOCK_READ(pDbgAs);
1012 return VINF_SUCCESS;
1013}
1014RT_EXPORT_SYMBOL(RTDbgAsModuleByAddr);
1015
1016
1017/**
1018 * Queries mapping module information by name.
1019 *
1020 * @returns IPRT status code.
1021 * @retval VERR_NOT_FOUND if no mapping was found at the specified address.
1022 * @retval VERR_OUT_OF_RANGE if the name index was out of range.
1023 *
1024 * @param hDbgAs The address space handle.
1025 * @param pszName The module name.
1026 * @param iName There can be more than one module by the same name
1027 * in an address space. This argument indicates which
1028 * is ment. (0 based)
1029 * @param phMod Where to the return the retained module handle.
1030 */
1031RTDECL(int) RTDbgAsModuleByName(RTDBGAS hDbgAs, const char *pszName, uint32_t iName, PRTDBGMOD phMod)
1032{
1033 /*
1034 * Validate input.
1035 */
1036 PRTDBGASINT pDbgAs = hDbgAs;
1037 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1038 AssertPtrReturn(phMod, VERR_INVALID_POINTER);
1039
1040 RTDBGAS_LOCK_READ(pDbgAs);
1041 PRTDBGASNAME pName = (PRTDBGASNAME)RTStrSpaceGet(&pDbgAs->NameSpace, pszName);
1042 if (!pName)
1043 {
1044 RTDBGAS_UNLOCK_READ(pDbgAs);
1045 return VERR_NOT_FOUND;
1046 }
1047
1048 PRTDBGASMOD pMod = pName->pHead;
1049 while (iName-- > 0)
1050 {
1051 pMod = pMod->pNextName;
1052 if (!pMod)
1053 {
1054 RTDBGAS_UNLOCK_READ(pDbgAs);
1055 return VERR_OUT_OF_RANGE;
1056 }
1057 }
1058
1059 /*
1060 * Get, retain and return it.
1061 */
1062 RTDBGMOD hMod = (RTDBGMOD)pMod->Core.Key;
1063 RTDbgModRetain(hMod);
1064 *phMod = hMod;
1065
1066 RTDBGAS_UNLOCK_READ(pDbgAs);
1067 return VINF_SUCCESS;
1068}
1069RT_EXPORT_SYMBOL(RTDbgAsModuleByName);
1070
1071
1072/**
1073 * Queries mapping information for a module given by index.
1074 *
1075 * @returns IRPT status code.
1076 * @retval VERR_INVALID_HANDLE if hDbgAs is invalid.
1077 * @retval VERR_OUT_OF_RANGE if the name index was out of range.
1078 * @retval VINF_BUFFER_OVERFLOW if the array is too small and the returned
1079 * information is incomplete.
1080 *
1081 * @param hDbgAs The address space handle.
1082 * @param iModule The index of the module to get.
1083 * @param paMappings Where to return the mapping information. The buffer
1084 * size is given by *pcMappings.
1085 * @param pcMappings IN: Size of the paMappings array. OUT: The number of
1086 * entries returned.
1087 * @param fFlags Flags for reserved for future use. MBZ.
1088 *
1089 * @remarks See remarks for RTDbgAsModuleByIndex regarding the volatility of the
1090 * iModule parameter.
1091 */
1092RTDECL(int) RTDbgAsModuleQueryMapByIndex(RTDBGAS hDbgAs, uint32_t iModule, PRTDBGASMAPINFO paMappings, uint32_t *pcMappings, uint32_t fFlags)
1093{
1094 /*
1095 * Validate input.
1096 */
1097 uint32_t const cMappings = *pcMappings;
1098 PRTDBGASINT pDbgAs = hDbgAs;
1099 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1100 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
1101
1102 RTDBGAS_LOCK_READ(pDbgAs);
1103 if (iModule >= pDbgAs->cModules)
1104 {
1105 RTDBGAS_UNLOCK_READ(pDbgAs);
1106 return VERR_OUT_OF_RANGE;
1107 }
1108
1109 /*
1110 * Copy the mapping information about the module.
1111 */
1112 int rc = VINF_SUCCESS;
1113 PRTDBGASMAP pMap = pDbgAs->papModules[iModule]->pMapHead;
1114 uint32_t cMaps = 0;
1115 while (pMap)
1116 {
1117 if (cMaps >= cMappings)
1118 {
1119 rc = VINF_BUFFER_OVERFLOW;
1120 break;
1121 }
1122 paMappings[cMaps].Address = pMap->Core.Key;
1123 paMappings[cMaps].iSeg = pMap->iSeg;
1124 cMaps++;
1125 pMap = pMap->pNext;
1126 }
1127
1128 RTDBGAS_UNLOCK_READ(pDbgAs);
1129 *pcMappings = cMaps;
1130 return rc;
1131}
1132RT_EXPORT_SYMBOL(RTDbgAsModuleQueryMapByIndex);
1133
1134
1135/**
1136 * Internal worker that looks up and retains a module.
1137 *
1138 * @returns Module handle, NIL_RTDBGMOD if not found.
1139 * @param pDbgAs The address space instance data.
1140 * @param Addr Address within the module.
1141 * @param piSeg where to return the segment index.
1142 * @param poffSeg Where to return the segment offset.
1143 * @param pMapAddr The mapping address (RTDBGASMAP::Core.Key).
1144 */
1145DECLINLINE(RTDBGMOD) rtDbgAsModuleByAddr(PRTDBGASINT pDbgAs, RTUINTPTR Addr, PRTDBGSEGIDX piSeg, PRTUINTPTR poffSeg, PRTUINTPTR pMapAddr)
1146{
1147 RTDBGMOD hMod = NIL_RTDBGMOD;
1148
1149 RTDBGAS_LOCK_READ(pDbgAs);
1150 PRTDBGASMAP pMap = (PRTDBGASMAP)RTAvlrUIntPtrRangeGet(&pDbgAs->MapTree, Addr);
1151 if (pMap)
1152 {
1153 hMod = (RTDBGMOD)pMap->pMod->Core.Key;
1154 RTDbgModRetain(hMod);
1155 *piSeg = pMap->iSeg != NIL_RTDBGSEGIDX ? pMap->iSeg : RTDBGSEGIDX_RVA;
1156 *poffSeg = Addr - pMap->Core.Key;
1157 if (pMapAddr)
1158 *pMapAddr = pMap->Core.Key;
1159 }
1160 RTDBGAS_UNLOCK_READ(pDbgAs);
1161
1162 return hMod;
1163}
1164
1165
1166/**
1167 * Adjusts the address to correspond to the mapping of the module/segment.
1168 *
1169 * @param pAddr The address to adjust (in/out).
1170 * @param iSeg The related segment.
1171 * @param hDbgMod The module handle.
1172 * @param MapAddr The mapping address.
1173 * @param iMapSeg The segment that's mapped, NIL_RTDBGSEGIDX or
1174 * RTDBGSEGIDX_RVA if the whole module is mapped here.
1175 */
1176DECLINLINE(void) rtDbgAsAdjustAddressByMapping(PRTUINTPTR pAddr, RTDBGSEGIDX iSeg,
1177 RTDBGMOD hDbgMod, RTUINTPTR MapAddr, RTDBGSEGIDX iMapSeg)
1178{
1179 if (iSeg == RTDBGSEGIDX_ABS)
1180 return;
1181
1182 if (iSeg == RTDBGSEGIDX_RVA)
1183 {
1184 if ( iMapSeg == RTDBGSEGIDX_RVA
1185 || iMapSeg == NIL_RTDBGSEGIDX)
1186 *pAddr += MapAddr;
1187 else
1188 {
1189 RTUINTPTR SegRva = RTDbgModSegmentRva(hDbgMod, iMapSeg);
1190 AssertReturnVoid(SegRva != RTUINTPTR_MAX);
1191 AssertMsg(SegRva <= *pAddr, ("SegRva=%RTptr *pAddr=%RTptr\n", SegRva, *pAddr));
1192 *pAddr += MapAddr - SegRva;
1193 }
1194 }
1195 else
1196 {
1197 if ( iMapSeg != RTDBGSEGIDX_RVA
1198 && iMapSeg != NIL_RTDBGSEGIDX)
1199 {
1200 Assert(iMapSeg == iSeg);
1201 *pAddr += MapAddr;
1202 }
1203 else
1204 {
1205 RTUINTPTR SegRva = RTDbgModSegmentRva(hDbgMod, iSeg);
1206 AssertReturnVoid(SegRva != RTUINTPTR_MAX);
1207 *pAddr += MapAddr + SegRva;
1208 }
1209 }
1210}
1211
1212
1213/**
1214 * Adjusts the symbol value to correspond to the mapping of the module/segment.
1215 *
1216 * @param pSymbol The returned symbol info.
1217 * @param hDbgMod The module handle.
1218 * @param MapAddr The mapping address.
1219 * @param iMapSeg The segment that's mapped, NIL_RTDBGSEGIDX if the
1220 * whole module is mapped here.
1221 */
1222DECLINLINE(void) rtDbgAsAdjustSymbolValue(PRTDBGSYMBOL pSymbol, RTDBGMOD hDbgMod, RTUINTPTR MapAddr, RTDBGSEGIDX iMapSeg)
1223{
1224 Assert(pSymbol->iSeg != NIL_RTDBGSEGIDX);
1225 Assert(pSymbol->offSeg == pSymbol->Value);
1226 rtDbgAsAdjustAddressByMapping(&pSymbol->Value, pSymbol->iSeg, hDbgMod, MapAddr, iMapSeg);
1227}
1228
1229
1230/**
1231 * Adjusts the line number address to correspond to the mapping of the module/segment.
1232 *
1233 * @param pLine The returned line number info.
1234 * @param hDbgMod The module handle.
1235 * @param MapAddr The mapping address.
1236 * @param iMapSeg The segment that's mapped, NIL_RTDBGSEGIDX if the
1237 * whole module is mapped here.
1238 */
1239DECLINLINE(void) rtDbgAsAdjustLineAddress(PRTDBGLINE pLine, RTDBGMOD hDbgMod, RTUINTPTR MapAddr, RTDBGSEGIDX iMapSeg)
1240{
1241 Assert(pLine->iSeg != NIL_RTDBGSEGIDX);
1242 Assert(pLine->offSeg == pLine->Address);
1243 rtDbgAsAdjustAddressByMapping(&pLine->Address, pLine->iSeg, hDbgMod, MapAddr, iMapSeg);
1244}
1245
1246
1247/**
1248 * Adds a symbol to a module in the address space.
1249 *
1250 * @returns IPRT status code. See RTDbgModSymbolAdd for more specific ones.
1251 * @retval VERR_INVALID_HANDLE if hDbgAs is invalid.
1252 * @retval VERR_NOT_FOUND if no module was found at the specified address.
1253 * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding
1254 * custom symbols.
1255 *
1256 * @param hDbgAs The address space handle.
1257 * @param pszSymbol The symbol name.
1258 * @param Addr The address of the symbol.
1259 * @param cb The size of the symbol.
1260 * @param fFlags Symbol flags.
1261 * @param piOrdinal Where to return the symbol ordinal on success. If
1262 * the interpreter doesn't do ordinals, this will be set to
1263 * UINT32_MAX. Optional
1264 */
1265RTDECL(int) RTDbgAsSymbolAdd(RTDBGAS hDbgAs, const char *pszSymbol, RTUINTPTR Addr, RTUINTPTR cb, uint32_t fFlags, uint32_t *piOrdinal)
1266{
1267 /*
1268 * Validate input and resolve the address.
1269 */
1270 PRTDBGASINT pDbgAs = hDbgAs;
1271 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1272
1273 RTDBGSEGIDX iSeg = NIL_RTDBGSEGIDX; /* shut up gcc */
1274 RTUINTPTR offSeg = 0;
1275 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, NULL);
1276 if (hMod == NIL_RTDBGMOD)
1277 return VERR_NOT_FOUND;
1278
1279 /*
1280 * Forward the call.
1281 */
1282 int rc = RTDbgModSymbolAdd(hMod, pszSymbol, iSeg, offSeg, cb, fFlags, piOrdinal);
1283 RTDbgModRelease(hMod);
1284 return rc;
1285}
1286RT_EXPORT_SYMBOL(RTDbgAsSymbolAdd);
1287
1288
1289/**
1290 * Query a symbol by address.
1291 *
1292 * @returns IPRT status code. See RTDbgModSymbolAddr for more specific ones.
1293 * @retval VERR_INVALID_HANDLE if hDbgAs is invalid.
1294 * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module.
1295 *
1296 * @param hDbgAs The address space handle.
1297 * @param Addr The address which closest symbol is requested.
1298 * @param poffDisp Where to return the distance between the symbol
1299 * and address. Optional.
1300 * @param pSymbol Where to return the symbol info.
1301 * @param phMod Where to return the module handle. Optional.
1302 */
1303RTDECL(int) RTDbgAsSymbolByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
1304{
1305 /*
1306 * Validate input and resolve the address.
1307 */
1308 PRTDBGASINT pDbgAs = hDbgAs;
1309 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1310
1311 RTDBGSEGIDX iSeg = NIL_RTDBGSEGIDX; /* shut up gcc */
1312 RTUINTPTR offSeg = 0;
1313 RTUINTPTR MapAddr = 0;
1314 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, &MapAddr);
1315 if (hMod == NIL_RTDBGMOD)
1316 {
1317 if (phMod)
1318 *phMod = NIL_RTDBGMOD;
1319 return VERR_NOT_FOUND;
1320 }
1321
1322 /*
1323 * Forward the call.
1324 */
1325 int rc = RTDbgModSymbolByAddr(hMod, iSeg, offSeg, poffDisp, pSymbol);
1326 if (RT_SUCCESS(rc))
1327 rtDbgAsAdjustSymbolValue(pSymbol, hMod, MapAddr, iSeg);
1328 if (phMod)
1329 *phMod = hMod;
1330 else
1331 RTDbgModRelease(hMod);
1332 return rc;
1333}
1334RT_EXPORT_SYMBOL(RTDbgAsSymbolByAddr);
1335
1336
1337/**
1338 * Query a symbol by address.
1339 *
1340 * @returns IPRT status code. See RTDbgModSymbolAddrA for more specific ones.
1341 * @retval VERR_INVALID_HANDLE if hDbgAs is invalid.
1342 * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module.
1343 *
1344 * @param hDbgAs The address space handle.
1345 * @param Addr The address which closest symbol is requested.
1346 * @param poffDisp Where to return the distance between the symbol
1347 * and address. Optional.
1348 * @param ppSymInfo Where to return the pointer to the allocated symbol
1349 * info. Always set. Free with RTDbgSymbolFree.
1350 * @param phMod Where to return the module handle. Optional.
1351 */
1352RTDECL(int) RTDbgAsSymbolByAddrA(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGSYMBOL *ppSymInfo, PRTDBGMOD phMod)
1353{
1354 /*
1355 * Validate input and resolve the address.
1356 */
1357 PRTDBGASINT pDbgAs = hDbgAs;
1358 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1359
1360 RTDBGSEGIDX iSeg = NIL_RTDBGSEGIDX;
1361 RTUINTPTR offSeg = 0;
1362 RTUINTPTR MapAddr = 0;
1363 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, &MapAddr);
1364 if (hMod == NIL_RTDBGMOD)
1365 {
1366 if (phMod)
1367 *phMod = NIL_RTDBGMOD;
1368 return VERR_NOT_FOUND;
1369 }
1370
1371 /*
1372 * Forward the call.
1373 */
1374 int rc = RTDbgModSymbolByAddrA(hMod, iSeg, offSeg, poffDisp, ppSymInfo);
1375 if (RT_SUCCESS(rc))
1376 rtDbgAsAdjustSymbolValue(*ppSymInfo, hMod, MapAddr, iSeg);
1377 if (phMod)
1378 *phMod = hMod;
1379 else
1380 RTDbgModRelease(hMod);
1381 return rc;
1382}
1383RT_EXPORT_SYMBOL(RTDbgAsSymbolByAddrA);
1384
1385
1386/**
1387 * Creates a snapshot of the module table on the temporary heap.
1388 *
1389 * The caller must release all the module handles before freeing the table
1390 * using RTMemTmpFree.
1391 *
1392 * @returns Module table snaphot.
1393 * @param pDbgAs The address space instance data.
1394 * @param pcModules Where to return the number of modules.
1395 */
1396DECLINLINE(PRTDBGMOD) rtDbgAsSnapshotModuleTable(PRTDBGASINT pDbgAs, uint32_t *pcModules)
1397{
1398 RTDBGAS_LOCK_READ(pDbgAs);
1399
1400 uint32_t iMod = *pcModules = pDbgAs->cModules;
1401 PRTDBGMOD pahModules = (PRTDBGMOD)RTMemTmpAlloc(sizeof(pahModules[0]) * RT_MAX(iMod, 1));
1402 if (pahModules)
1403 {
1404 while (iMod-- > 0)
1405 {
1406 RTDBGMOD hMod = (RTDBGMOD)pDbgAs->papModules[iMod]->Core.Key;
1407 pahModules[iMod] = hMod;
1408 RTDbgModRetain(hMod);
1409 }
1410 }
1411
1412 RTDBGAS_UNLOCK_READ(pDbgAs);
1413 return pahModules;
1414}
1415
1416
1417/**
1418 * Attempts to find a mapping of the specified symbol/module and
1419 * adjust it's Value field accordingly.
1420 *
1421 * @returns true / false success indicator.
1422 * @param pDbgAs The address space.
1423 * @param hDbgMod The module handle.
1424 * @param pSymbol The symbol info.
1425 */
1426static bool rtDbgAsFindMappingAndAdjustSymbolValue(PRTDBGASINT pDbgAs, RTDBGMOD hDbgMod, PRTDBGSYMBOL pSymbol)
1427{
1428 /*
1429 * Absolute segments needs no fixing.
1430 */
1431 RTDBGSEGIDX const iSeg = pSymbol->iSeg;
1432 if (iSeg == RTDBGSEGIDX_ABS)
1433 return true;
1434
1435 RTDBGAS_LOCK_READ(pDbgAs);
1436
1437 /*
1438 * Lookup up the module by it's handle and iterate the mappings looking for one
1439 * that either encompasses the entire module or the segment in question.
1440 */
1441 PRTDBGASMOD pMod = (PRTDBGASMOD)RTAvlPVGet(&pDbgAs->ModTree, hDbgMod);
1442 if (pMod)
1443 {
1444 for (PRTDBGASMAP pMap = pMod->pMapHead; pMap; pMap = pMap->pNext)
1445 {
1446 /* Exact segment match or full-mapping. */
1447 if ( iSeg == pMap->iSeg
1448 || pMap->iSeg == NIL_RTDBGSEGIDX)
1449 {
1450 RTUINTPTR MapAddr = pMap->Core.Key;
1451 RTDBGSEGIDX iMapSeg = pMap->iSeg;
1452
1453 RTDBGAS_UNLOCK_READ(pDbgAs);
1454 rtDbgAsAdjustSymbolValue(pSymbol, hDbgMod, MapAddr, iMapSeg);
1455 return true;
1456 }
1457
1458 /* Symbol uses RVA and the mapping doesn't, see if it's in the mapped segment. */
1459 if (iSeg == RTDBGSEGIDX_RVA)
1460 {
1461 Assert(pMap->iSeg != NIL_RTDBGSEGIDX);
1462 RTUINTPTR SegRva = RTDbgModSegmentRva(hDbgMod, pMap->iSeg);
1463 Assert(SegRva != RTUINTPTR_MAX);
1464 RTUINTPTR cbSeg = RTDbgModSegmentSize(hDbgMod, pMap->iSeg);
1465 if (SegRva - pSymbol->Value < cbSeg)
1466 {
1467 RTUINTPTR MapAddr = pMap->Core.Key;
1468 RTDBGSEGIDX iMapSeg = pMap->iSeg;
1469
1470 RTDBGAS_UNLOCK_READ(pDbgAs);
1471 rtDbgAsAdjustSymbolValue(pSymbol, hDbgMod, MapAddr, iMapSeg);
1472 return true;
1473 }
1474 }
1475 }
1476 }
1477 /* else: Unmapped while we were searching. */
1478
1479 RTDBGAS_UNLOCK_READ(pDbgAs);
1480 return false;
1481}
1482
1483
1484/**
1485 * Query a symbol by name.
1486 *
1487 * @returns IPRT status code.
1488 * @retval VERR_SYMBOL_NOT_FOUND if not found.
1489 *
1490 * @param hDbgAs The address space handle.
1491 * @param pszSymbol The symbol name. It is possible to limit the scope
1492 * of the search by prefixing the symbol with a module
1493 * name pattern followed by a bang (!) character.
1494 * RTStrSimplePatternNMatch is used for the matching.
1495 * @param pSymbol Where to return the symbol info.
1496 * @param phMod Where to return the module handle. Optional.
1497 */
1498RTDECL(int) RTDbgAsSymbolByName(RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
1499{
1500 /*
1501 * Validate input.
1502 */
1503 PRTDBGASINT pDbgAs = hDbgAs;
1504 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1505 AssertPtrReturn(pszSymbol, VERR_INVALID_POINTER);
1506 AssertPtrReturn(pSymbol, VERR_INVALID_POINTER);
1507
1508 /*
1509 * Look for module pattern.
1510 */
1511 const char *pachModPat = NULL;
1512 size_t cchModPat = 0;
1513 const char *pszBang = strchr(pszSymbol, '!');
1514 if (pszBang)
1515 {
1516 pachModPat = pszSymbol;
1517 cchModPat = pszBang - pszSymbol;
1518 pszSymbol = pszBang + 1;
1519 if (!*pszSymbol)
1520 return VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE;
1521 /* Note! Zero length module -> no pattern -> escape for symbol with '!'. */
1522 }
1523
1524 /*
1525 * Iterate the modules, looking for the symbol.
1526 */
1527 uint32_t cModules;
1528 PRTDBGMOD pahModules = rtDbgAsSnapshotModuleTable(pDbgAs, &cModules);
1529 if (!pahModules)
1530 return VERR_NO_TMP_MEMORY;
1531
1532 for (uint32_t i = 0; i < cModules; i++)
1533 {
1534 if ( cchModPat == 0
1535 || RTStrSimplePatternNMatch(pachModPat, cchModPat, RTDbgModName(pahModules[i]), RTSTR_MAX))
1536 {
1537 int rc = RTDbgModSymbolByName(pahModules[i], pszSymbol, pSymbol);
1538 if (RT_SUCCESS(rc))
1539 {
1540 if (rtDbgAsFindMappingAndAdjustSymbolValue(pDbgAs, pahModules[i], pSymbol))
1541 {
1542 if (phMod)
1543 RTDbgModRetain(*phMod = pahModules[i]);
1544 for (; i < cModules; i++)
1545 RTDbgModRelease(pahModules[i]);
1546 RTMemTmpFree(pahModules);
1547 return rc;
1548 }
1549 }
1550 }
1551 RTDbgModRelease(pahModules[i]);
1552 }
1553
1554 RTMemTmpFree(pahModules);
1555 return VERR_SYMBOL_NOT_FOUND;
1556}
1557RT_EXPORT_SYMBOL(RTDbgAsSymbolByName);
1558
1559
1560/**
1561 * Query a symbol by name, allocating the returned symbol structure.
1562 *
1563 * @returns IPRT status code.
1564 * @retval VERR_SYMBOL_NOT_FOUND if not found.
1565 *
1566 * @param hDbgAs The address space handle.
1567 * @param pszSymbol The symbol name. See RTDbgAsSymbolByName for more.
1568 * @param ppSymbol Where to return the pointer to the allocated
1569 * symbol info. Always set. Free with RTDbgSymbolFree.
1570 * @param phMod Where to return the module handle. Optional.
1571 */
1572RTDECL(int) RTDbgAsSymbolByNameA(RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL *ppSymbol, PRTDBGMOD phMod)
1573{
1574 /*
1575 * Validate input.
1576 */
1577 AssertPtrReturn(ppSymbol, VERR_INVALID_POINTER);
1578 *ppSymbol = NULL;
1579 PRTDBGASINT pDbgAs = hDbgAs;
1580 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1581 AssertPtrReturn(pszSymbol, VERR_INVALID_POINTER);
1582
1583 /*
1584 * Look for module pattern.
1585 */
1586 const char *pachModPat = NULL;
1587 size_t cchModPat = 0;
1588 const char *pszBang = strchr(pszSymbol, '!');
1589 if (pszBang)
1590 {
1591 pachModPat = pszSymbol;
1592 cchModPat = pszBang - pszSymbol;
1593 pszSymbol = pszBang + 1;
1594 if (!*pszSymbol)
1595 return VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE;
1596 /* Note! Zero length module -> no pattern -> escape for symbol with '!'. */
1597 }
1598
1599 /*
1600 * Iterate the modules, looking for the symbol.
1601 */
1602 uint32_t cModules;
1603 PRTDBGMOD pahModules = rtDbgAsSnapshotModuleTable(pDbgAs, &cModules);
1604 if (!pahModules)
1605 return VERR_NO_TMP_MEMORY;
1606
1607 for (uint32_t i = 0; i < cModules; i++)
1608 {
1609 if ( cchModPat == 0
1610 || RTStrSimplePatternNMatch(pachModPat, cchModPat, RTDbgModName(pahModules[i]), RTSTR_MAX))
1611 {
1612 int rc = RTDbgModSymbolByNameA(pahModules[i], pszSymbol, ppSymbol);
1613 if (RT_SUCCESS(rc))
1614 {
1615 if (rtDbgAsFindMappingAndAdjustSymbolValue(pDbgAs, pahModules[i], *ppSymbol))
1616 {
1617 if (phMod)
1618 RTDbgModRetain(*phMod = pahModules[i]);
1619 for (; i < cModules; i++)
1620 RTDbgModRelease(pahModules[i]);
1621 RTMemTmpFree(pahModules);
1622 return rc;
1623 }
1624 }
1625 }
1626 RTDbgModRelease(pahModules[i]);
1627 }
1628
1629 RTMemTmpFree(pahModules);
1630 return VERR_SYMBOL_NOT_FOUND;
1631}
1632RT_EXPORT_SYMBOL(RTDbgAsSymbolByNameA);
1633
1634
1635/**
1636 * Adds a line number to a module in the address space.
1637 *
1638 * @returns IPRT status code. See RTDbgModSymbolAdd for more specific ones.
1639 * @retval VERR_INVALID_HANDLE if hDbgAs is invalid.
1640 * @retval VERR_NOT_FOUND if no module was found at the specified address.
1641 * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding
1642 * custom symbols.
1643 *
1644 * @param hDbgAs The address space handle.
1645 * @param pszFile The file name.
1646 * @param uLineNo The line number.
1647 * @param Addr The address of the symbol.
1648 * @param piOrdinal Where to return the line number ordinal on success.
1649 * If the interpreter doesn't do ordinals, this will be
1650 * set to UINT32_MAX. Optional.
1651 */
1652RTDECL(int) RTDbgAsLineAdd(RTDBGAS hDbgAs, const char *pszFile, uint32_t uLineNo, RTUINTPTR Addr, uint32_t *piOrdinal)
1653{
1654 /*
1655 * Validate input and resolve the address.
1656 */
1657 PRTDBGASINT pDbgAs = hDbgAs;
1658 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1659
1660 RTDBGSEGIDX iSeg = NIL_RTDBGSEGIDX; /* shut up gcc */
1661 RTUINTPTR offSeg = 0; /* ditto */
1662 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, NULL);
1663 if (hMod == NIL_RTDBGMOD)
1664 return VERR_NOT_FOUND;
1665
1666 /*
1667 * Forward the call.
1668 */
1669 int rc = RTDbgModLineAdd(hMod, pszFile, uLineNo, iSeg, offSeg, piOrdinal);
1670 RTDbgModRelease(hMod);
1671 return rc;
1672}
1673RT_EXPORT_SYMBOL(RTDbgAsLineAdd);
1674
1675
1676/**
1677 * Query a line number by address.
1678 *
1679 * @returns IPRT status code. See RTDbgModSymbolAddrA for more specific ones.
1680 * @retval VERR_INVALID_HANDLE if hDbgAs is invalid.
1681 * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module.
1682 *
1683 * @param hDbgAs The address space handle.
1684 * @param Addr The address which closest symbol is requested.
1685 * @param poffDisp Where to return the distance between the line
1686 * number and address.
1687 * @param pLine Where to return the line number information.
1688 */
1689RTDECL(int) RTDbgAsLineByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE pLine)
1690{
1691 /*
1692 * Validate input and resolve the address.
1693 */
1694 PRTDBGASINT pDbgAs = hDbgAs;
1695 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1696
1697 RTDBGSEGIDX iSeg = NIL_RTDBGSEGIDX; /* shut up gcc */
1698 RTUINTPTR offSeg = 0;
1699 RTUINTPTR MapAddr = 0;
1700 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, &MapAddr);
1701 if (hMod == NIL_RTDBGMOD)
1702 return VERR_NOT_FOUND;
1703
1704 /*
1705 * Forward the call.
1706 */
1707 int rc = RTDbgModLineByAddr(hMod, iSeg, offSeg, poffDisp, pLine);
1708 if (RT_SUCCESS(rc))
1709 rtDbgAsAdjustLineAddress(pLine, hMod, MapAddr, iSeg);
1710 RTDbgModRelease(hMod);
1711 return rc;
1712}
1713RT_EXPORT_SYMBOL(RTDbgAsLineByAddr);
1714
1715
1716/**
1717 * Query a line number by address.
1718 *
1719 * @returns IPRT status code. See RTDbgModSymbolAddrA for more specific ones.
1720 * @retval VERR_INVALID_HANDLE if hDbgAs is invalid.
1721 * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module.
1722 *
1723 * @param hDbgAs The address space handle.
1724 * @param Addr The address which closest symbol is requested.
1725 * @param poffDisp Where to return the distance between the line
1726 * number and address.
1727 * @param ppLine Where to return the pointer to the allocated line
1728 * number info. Always set. Free with RTDbgLineFree.
1729 */
1730RTDECL(int) RTDbgAsLineByAddrA(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE *ppLine)
1731{
1732 /*
1733 * Validate input and resolve the address.
1734 */
1735 PRTDBGASINT pDbgAs = hDbgAs;
1736 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1737
1738 RTDBGSEGIDX iSeg = NIL_RTDBGSEGIDX; /* shut up gcc */
1739 RTUINTPTR offSeg = 0;
1740 RTUINTPTR MapAddr = 0;
1741 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, &MapAddr);
1742 if (hMod == NIL_RTDBGMOD)
1743 return VERR_NOT_FOUND;
1744
1745 /*
1746 * Forward the call.
1747 */
1748 int rc = RTDbgModLineByAddrA(hMod, iSeg, offSeg, poffDisp, ppLine);
1749 if (RT_SUCCESS(rc))
1750 rtDbgAsAdjustLineAddress(*ppLine, hMod, MapAddr, iSeg);
1751 RTDbgModRelease(hMod);
1752 return rc;
1753}
1754RT_EXPORT_SYMBOL(RTDbgAsLineByAddrA);
1755
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