VirtualBox

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

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

Runtime/common/dbg/dbgas.cpp: typo

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