VirtualBox

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

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 56.3 KB
Line 
1/* $Id: dbgas.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * IPRT - Debug Address Space.
4 */
5
6/*
7 * Copyright (C) 2009-2022 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_UOFFSETOF_DYN(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 (RT_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 RTSemRWDestroy(pDbgAs->hLock);
345 pDbgAs->hLock = NIL_RTSEMRW;
346 RTMemFree(pDbgAs->papModules);
347 pDbgAs->papModules = NULL;
348
349 RTMemFree(pDbgAs);
350}
351
352
353/**
354 * Retains another reference to the address space.
355 *
356 * @returns New reference count, UINT32_MAX on invalid handle (asserted).
357 *
358 * @param hDbgAs The address space handle.
359 *
360 * @remarks Will not take any locks.
361 */
362RTDECL(uint32_t) RTDbgAsRetain(RTDBGAS hDbgAs)
363{
364 PRTDBGASINT pDbgAs = hDbgAs;
365 RTDBGAS_VALID_RETURN_RC(pDbgAs, UINT32_MAX);
366 return ASMAtomicIncU32(&pDbgAs->cRefs);
367}
368RT_EXPORT_SYMBOL(RTDbgAsRetain);
369
370
371/**
372 * Release a reference to the address space.
373 *
374 * When the reference count reaches zero, the address space is destroyed.
375 * That means unlinking all the modules it currently contains, potentially
376 * causing some or all of them to be destroyed as they are managed by
377 * reference counting.
378 *
379 * @returns New reference count, UINT32_MAX on invalid handle (asserted).
380 *
381 * @param hDbgAs The address space handle. The NIL handle is quietly
382 * ignored and 0 is returned.
383 *
384 * @remarks Will not take any locks.
385 */
386RTDECL(uint32_t) RTDbgAsRelease(RTDBGAS hDbgAs)
387{
388 if (hDbgAs == NIL_RTDBGAS)
389 return 0;
390 PRTDBGASINT pDbgAs = hDbgAs;
391 RTDBGAS_VALID_RETURN_RC(pDbgAs, UINT32_MAX);
392
393 uint32_t cRefs = ASMAtomicDecU32(&pDbgAs->cRefs);
394 if (!cRefs)
395 rtDbgAsDestroy(pDbgAs);
396 return cRefs;
397}
398RT_EXPORT_SYMBOL(RTDbgAsRelease);
399
400
401RTDECL(int) RTDbgAsLockExcl(RTDBGAS hDbgAs)
402{
403 PRTDBGASINT pDbgAs = hDbgAs;
404 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
405 RTDBGAS_LOCK_WRITE(pDbgAs);
406 return VINF_SUCCESS;
407}
408RT_EXPORT_SYMBOL(RTDbgAsLockExcl);
409
410
411RTDECL(int) RTDbgAsUnlockExcl(RTDBGAS hDbgAs)
412{
413 PRTDBGASINT pDbgAs = hDbgAs;
414 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
415 RTDBGAS_UNLOCK_WRITE(pDbgAs);
416 return VINF_SUCCESS;
417}
418RT_EXPORT_SYMBOL(RTDbgAsUnlockExcl);
419
420
421/**
422 * Gets the name of an address space.
423 *
424 * @returns read only address space name.
425 * NULL if hDbgAs is invalid.
426 *
427 * @param hDbgAs The address space handle.
428 *
429 * @remarks Will not take any locks.
430 */
431RTDECL(const char *) RTDbgAsName(RTDBGAS hDbgAs)
432{
433 PRTDBGASINT pDbgAs = hDbgAs;
434 RTDBGAS_VALID_RETURN_RC(pDbgAs, NULL);
435 return pDbgAs->szName;
436}
437RT_EXPORT_SYMBOL(RTDbgAsName);
438
439
440/**
441 * Gets the first address in an address space.
442 *
443 * @returns The address.
444 * 0 if hDbgAs is invalid.
445 *
446 * @param hDbgAs The address space handle.
447 *
448 * @remarks Will not take any locks.
449 */
450RTDECL(RTUINTPTR) RTDbgAsFirstAddr(RTDBGAS hDbgAs)
451{
452 PRTDBGASINT pDbgAs = hDbgAs;
453 RTDBGAS_VALID_RETURN_RC(pDbgAs, 0);
454 return pDbgAs->FirstAddr;
455}
456RT_EXPORT_SYMBOL(RTDbgAsFirstAddr);
457
458
459/**
460 * Gets the last address in an address space.
461 *
462 * @returns The address.
463 * 0 if hDbgAs is invalid.
464 *
465 * @param hDbgAs The address space handle.
466 *
467 * @remarks Will not take any locks.
468 */
469RTDECL(RTUINTPTR) RTDbgAsLastAddr(RTDBGAS hDbgAs)
470{
471 PRTDBGASINT pDbgAs = hDbgAs;
472 RTDBGAS_VALID_RETURN_RC(pDbgAs, 0);
473 return pDbgAs->LastAddr;
474}
475RT_EXPORT_SYMBOL(RTDbgAsLastAddr);
476
477/**
478 * Gets the number of modules in the address space.
479 *
480 * This can be used together with RTDbgAsModuleByIndex
481 * to enumerate the modules.
482 *
483 * @returns The number of modules.
484 *
485 * @param hDbgAs The address space handle.
486 *
487 * @remarks Will not take any locks.
488 */
489RTDECL(uint32_t) RTDbgAsModuleCount(RTDBGAS hDbgAs)
490{
491 PRTDBGASINT pDbgAs = hDbgAs;
492 RTDBGAS_VALID_RETURN_RC(pDbgAs, 0);
493 return pDbgAs->cModules;
494}
495RT_EXPORT_SYMBOL(RTDbgAsModuleCount);
496
497
498/**
499 * Common worker for RTDbgAsModuleLink and RTDbgAsModuleLinkSeg.
500 *
501 * @returns IPRT status code.
502 * @param pDbgAs Pointer to the address space instance data.
503 * @param hDbgMod The module to link.
504 * @param iSeg The segment to link or NIL if all.
505 * @param Addr The address we're linking it at.
506 * @param cb The size of what we're linking.
507 * @param pszName The name of the module.
508 * @param fFlags See RTDBGASLINK_FLAGS_*.
509 *
510 * @remarks The caller must have locked the address space for writing.
511 */
512int rtDbgAsModuleLinkCommon(PRTDBGASINT pDbgAs, RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg,
513 RTUINTPTR Addr, RTUINTPTR cb, const char *pszName, uint32_t fFlags)
514{
515 /*
516 * Check that the requested space is undisputed.
517 */
518 for (;;)
519 {
520 PRTDBGASMAP pAdjMod = (PRTDBGASMAP)RTAvlrUIntPtrGetBestFit(&pDbgAs->MapTree, Addr, false /* fAbove */);
521 if ( pAdjMod
522 && pAdjMod->Core.KeyLast >= Addr)
523 {
524 if (!(fFlags & RTDBGASLINK_FLAGS_REPLACE))
525 return VERR_ADDRESS_CONFLICT;
526 rtDbgAsModuleUnlinkByMap(pDbgAs, pAdjMod);
527 continue;
528 }
529 pAdjMod = (PRTDBGASMAP)RTAvlrUIntPtrGetBestFit(&pDbgAs->MapTree, Addr, true /* fAbove */);
530 if ( pAdjMod
531 && pAdjMod->Core.Key <= Addr + cb - 1)
532 {
533 if (!(fFlags & RTDBGASLINK_FLAGS_REPLACE))
534 return VERR_ADDRESS_CONFLICT;
535 rtDbgAsModuleUnlinkByMap(pDbgAs, pAdjMod);
536 continue;
537 }
538 break;
539 }
540
541 /*
542 * First, create or find the module table entry.
543 */
544 PRTDBGASMOD pMod = (PRTDBGASMOD)RTAvlPVGet(&pDbgAs->ModTree, hDbgMod);
545 if (!pMod)
546 {
547 /*
548 * Ok, we need a new entry. Grow the table if necessary.
549 */
550 if (!(pDbgAs->cModules % 32))
551 {
552 void *pvNew = RTMemRealloc(pDbgAs->papModules, sizeof(pDbgAs->papModules[0]) * (pDbgAs->cModules + 32));
553 if (!pvNew)
554 return VERR_NO_MEMORY;
555 pDbgAs->papModules = (PRTDBGASMOD *)pvNew;
556 }
557 pMod = (PRTDBGASMOD)RTMemAlloc(sizeof(*pMod));
558 if (!pMod)
559 return VERR_NO_MEMORY;
560 pMod->Core.Key = hDbgMod;
561 pMod->pMapHead = NULL;
562 pMod->pNextName = NULL;
563 if (RT_UNLIKELY(!RTAvlPVInsert(&pDbgAs->ModTree, &pMod->Core)))
564 {
565 AssertFailed();
566 pDbgAs->cModules--;
567 RTMemFree(pMod);
568 return VERR_INTERNAL_ERROR;
569 }
570 pMod->iOrdinal = pDbgAs->cModules;
571 pDbgAs->papModules[pDbgAs->cModules] = pMod;
572 pDbgAs->cModules++;
573 RTDbgModRetain(hDbgMod);
574
575 /*
576 * Add it to the name space.
577 */
578 PRTDBGASNAME pName = (PRTDBGASNAME)RTStrSpaceGet(&pDbgAs->NameSpace, pszName);
579 if (!pName)
580 {
581 size_t cchName = strlen(pszName);
582 pName = (PRTDBGASNAME)RTMemAlloc(sizeof(*pName) + cchName + 1);
583 if (!pName)
584 {
585 RTDbgModRelease(hDbgMod);
586 pDbgAs->cModules--;
587 RTAvlPVRemove(&pDbgAs->ModTree, hDbgMod);
588 RTMemFree(pMod);
589 return VERR_NO_MEMORY;
590 }
591 pName->StrCore.cchString = cchName;
592 pName->StrCore.pszString = (char *)memcpy(pName + 1, pszName, cchName + 1);
593 pName->pHead = pMod;
594 if (!RTStrSpaceInsert(&pDbgAs->NameSpace, &pName->StrCore))
595 AssertFailed();
596 }
597 else
598 {
599 /* quick, but unfair. */
600 pMod->pNextName = pName->pHead;
601 pName->pHead = pMod;
602 }
603 }
604
605 /*
606 * Create a mapping node.
607 */
608 int rc;
609 PRTDBGASMAP pMap = (PRTDBGASMAP)RTMemAlloc(sizeof(*pMap));
610 if (pMap)
611 {
612 pMap->Core.Key = Addr;
613 pMap->Core.KeyLast = Addr + cb - 1;
614 pMap->pMod = pMod;
615 pMap->iSeg = iSeg;
616 if (RTAvlrUIntPtrInsert(&pDbgAs->MapTree, &pMap->Core))
617 {
618 PRTDBGASMAP *pp = &pMod->pMapHead;
619 while (*pp && (*pp)->Core.Key < Addr)
620 pp = &(*pp)->pNext;
621 pMap->pNext = *pp;
622 *pp = pMap;
623 return VINF_SUCCESS;
624 }
625
626 AssertFailed();
627 RTMemFree(pMap);
628 rc = VERR_ADDRESS_CONFLICT;
629 }
630 else
631 rc = VERR_NO_MEMORY;
632
633 /*
634 * Unlink the module if this was the only mapping.
635 */
636 if (!pMod->pMapHead)
637 rtDbgAsModuleUnlinkMod(pDbgAs, pMod);
638 return rc;
639}
640
641
642/**
643 * Links a module into the address space at the give address.
644 *
645 * The size of the mapping is determined using RTDbgModImageSize().
646 *
647 * @returns IPRT status code.
648 * @retval VERR_OUT_OF_RANGE if the specified address will put the module
649 * outside the address space.
650 * @retval VERR_ADDRESS_CONFLICT if the mapping clashes with existing mappings.
651 *
652 * @param hDbgAs The address space handle.
653 * @param hDbgMod The module handle of the module to be linked in.
654 * @param ImageAddr The address to link the module at.
655 * @param fFlags See RTDBGASLINK_FLAGS_*.
656 */
657RTDECL(int) RTDbgAsModuleLink(RTDBGAS hDbgAs, RTDBGMOD hDbgMod, RTUINTPTR ImageAddr, uint32_t fFlags)
658{
659 /*
660 * Validate input.
661 */
662 PRTDBGASINT pDbgAs = hDbgAs;
663 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
664 const char *pszName = RTDbgModName(hDbgMod);
665 if (!pszName)
666 return VERR_INVALID_HANDLE;
667 RTUINTPTR cb = RTDbgModImageSize(hDbgMod);
668 if (!cb)
669 return VERR_OUT_OF_RANGE;
670 if ( ImageAddr < pDbgAs->FirstAddr
671 || ImageAddr > pDbgAs->LastAddr
672 || ImageAddr + cb - 1 < pDbgAs->FirstAddr
673 || ImageAddr + cb - 1 > pDbgAs->LastAddr
674 || ImageAddr + cb - 1 < ImageAddr)
675 return VERR_OUT_OF_RANGE;
676 AssertReturn(!(fFlags & ~RTDBGASLINK_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
677
678 /*
679 * Invoke worker common with RTDbgAsModuleLinkSeg.
680 */
681 RTDBGAS_LOCK_WRITE(pDbgAs);
682 int rc = rtDbgAsModuleLinkCommon(pDbgAs, hDbgMod, NIL_RTDBGSEGIDX, ImageAddr, cb, pszName, fFlags);
683 RTDBGAS_UNLOCK_WRITE(pDbgAs);
684 return rc;
685}
686RT_EXPORT_SYMBOL(RTDbgAsModuleLink);
687
688
689/**
690 * Links a segment into the address space at the give address.
691 *
692 * The size of the mapping is determined using RTDbgModSegmentSize().
693 *
694 * @returns IPRT status code.
695 * @retval VERR_OUT_OF_RANGE if the specified address will put the module
696 * outside the address space.
697 * @retval VERR_ADDRESS_CONFLICT if the mapping clashes with existing mappings.
698 *
699 * @param hDbgAs The address space handle.
700 * @param hDbgMod The module handle.
701 * @param iSeg The segment number (0-based) of the segment to be
702 * linked in.
703 * @param SegAddr The address to link the segment at.
704 * @param fFlags See RTDBGASLINK_FLAGS_*.
705 */
706RTDECL(int) RTDbgAsModuleLinkSeg(RTDBGAS hDbgAs, RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR SegAddr, uint32_t fFlags)
707{
708 /*
709 * Validate input.
710 */
711 PRTDBGASINT pDbgAs = hDbgAs;
712 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
713 const char *pszName = RTDbgModName(hDbgMod);
714 if (!pszName)
715 return VERR_INVALID_HANDLE;
716 RTUINTPTR cb = RTDbgModSegmentSize(hDbgMod, iSeg);
717 if (!cb)
718 return VERR_OUT_OF_RANGE;
719 if ( SegAddr < pDbgAs->FirstAddr
720 || SegAddr > pDbgAs->LastAddr
721 || SegAddr + cb - 1 < pDbgAs->FirstAddr
722 || SegAddr + cb - 1 > pDbgAs->LastAddr
723 || SegAddr + cb - 1 < SegAddr)
724 return VERR_OUT_OF_RANGE;
725 AssertReturn(!(fFlags & ~RTDBGASLINK_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
726
727 /*
728 * Invoke worker common with RTDbgAsModuleLinkSeg.
729 */
730 RTDBGAS_LOCK_WRITE(pDbgAs);
731 int rc = rtDbgAsModuleLinkCommon(pDbgAs, hDbgMod, iSeg, SegAddr, cb, pszName, fFlags);
732 RTDBGAS_UNLOCK_WRITE(pDbgAs);
733 return rc;
734}
735RT_EXPORT_SYMBOL(RTDbgAsModuleLinkSeg);
736
737
738/**
739 * Worker for RTDbgAsModuleUnlink, RTDbgAsModuleUnlinkByAddr and rtDbgAsModuleLinkCommon.
740 *
741 * @param pDbgAs Pointer to the address space instance data.
742 * @param pMod The module to unlink.
743 *
744 * @remarks The caller must have locked the address space for writing.
745 */
746static void rtDbgAsModuleUnlinkMod(PRTDBGASINT pDbgAs, PRTDBGASMOD pMod)
747{
748 Assert(!pMod->pMapHead);
749
750 /*
751 * Unlink it from the name.
752 */
753 const char *pszName = RTDbgModName((RTDBGMOD)pMod->Core.Key);
754 PRTDBGASNAME pName = (PRTDBGASNAME)RTStrSpaceGet(&pDbgAs->NameSpace, pszName);
755 AssertReturnVoid(pName);
756
757 if (pName->pHead == pMod)
758 pName->pHead = pMod->pNextName;
759 else
760 for (PRTDBGASMOD pCur = pName->pHead; pCur; pCur = pCur->pNextName)
761 if (pCur->pNextName == pMod)
762 {
763 pCur->pNextName = pMod->pNextName;
764 break;
765 }
766 pMod->pNextName = NULL;
767
768 /*
769 * Free the name if this was the last reference to it.
770 */
771 if (!pName->pHead)
772 {
773 pName = (PRTDBGASNAME)RTStrSpaceRemove(&pDbgAs->NameSpace, pName->StrCore.pszString);
774 Assert(pName);
775 RTMemFree(pName);
776 }
777
778 /*
779 * Remove it from the module handle tree.
780 */
781 PAVLPVNODECORE pNode = RTAvlPVRemove(&pDbgAs->ModTree, pMod->Core.Key);
782 Assert(pNode == &pMod->Core); NOREF(pNode);
783
784 /*
785 * Remove it from the module table by replacing it by the last entry.
786 */
787 pDbgAs->cModules--;
788 uint32_t iMod = pMod->iOrdinal;
789 Assert(iMod <= pDbgAs->cModules);
790 if (iMod != pDbgAs->cModules)
791 {
792 PRTDBGASMOD pTailMod = pDbgAs->papModules[pDbgAs->cModules];
793 pTailMod->iOrdinal = iMod;
794 pDbgAs->papModules[iMod] = pTailMod;
795 }
796 pMod->iOrdinal = UINT32_MAX;
797
798 /*
799 * Free it.
800 */
801 RTMemFree(pMod);
802}
803
804
805/**
806 * Worker for RTDbgAsModuleUnlink and RTDbgAsModuleUnlinkByAddr.
807 *
808 * @param pDbgAs Pointer to the address space instance data.
809 * @param pMap The map to unlink and free.
810 *
811 * @remarks The caller must have locked the address space for writing.
812 */
813static void rtDbgAsModuleUnlinkMap(PRTDBGASINT pDbgAs, PRTDBGASMAP pMap)
814{
815 /* remove from the tree */
816 PAVLRUINTPTRNODECORE pNode = RTAvlrUIntPtrRemove(&pDbgAs->MapTree, pMap->Core.Key);
817 Assert(pNode == &pMap->Core); NOREF(pNode);
818
819 /* unlink */
820 PRTDBGASMOD pMod = pMap->pMod;
821 if (pMod->pMapHead == pMap)
822 pMod->pMapHead = pMap->pNext;
823 else
824 {
825 bool fFound = false;
826 for (PRTDBGASMAP pCur = pMod->pMapHead; pCur; pCur = pCur->pNext)
827 if (pCur->pNext == pMap)
828 {
829 pCur->pNext = pMap->pNext;
830 fFound = true;
831 break;
832 }
833 Assert(fFound);
834 }
835
836 /* free it */
837 pMap->Core.Key = pMap->Core.KeyLast = 0;
838 pMap->pNext = NULL;
839 pMap->pMod = NULL;
840 RTMemFree(pMap);
841}
842
843
844/**
845 * Worker for RTDbgAsModuleUnlinkByAddr and rtDbgAsModuleLinkCommon that
846 * unlinks a single mapping and releases the module if it's the last one.
847 *
848 * @param pDbgAs The address space instance.
849 * @param pMap The mapping to unlink.
850 *
851 * @remarks The caller must have locked the address space for writing.
852 */
853static void rtDbgAsModuleUnlinkByMap(PRTDBGASINT pDbgAs, PRTDBGASMAP pMap)
854{
855 /*
856 * Unlink it from the address space.
857 * Unlink the module as well if it's the last mapping it has.
858 */
859 PRTDBGASMOD pMod = pMap->pMod;
860 rtDbgAsModuleUnlinkMap(pDbgAs, pMap);
861 if (!pMod->pMapHead)
862 rtDbgAsModuleUnlinkMod(pDbgAs, pMod);
863}
864
865
866/**
867 * Unlinks all the mappings of a module from the address space.
868 *
869 * @returns IPRT status code.
870 * @retval VERR_NOT_FOUND if the module wasn't found.
871 *
872 * @param hDbgAs The address space handle.
873 * @param hDbgMod The module handle of the module to be unlinked.
874 */
875RTDECL(int) RTDbgAsModuleUnlink(RTDBGAS hDbgAs, RTDBGMOD hDbgMod)
876{
877 /*
878 * Validate input.
879 */
880 PRTDBGASINT pDbgAs = hDbgAs;
881 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
882 if (hDbgMod == NIL_RTDBGMOD)
883 return VINF_SUCCESS;
884
885 RTDBGAS_LOCK_WRITE(pDbgAs);
886 PRTDBGASMOD pMod = (PRTDBGASMOD)RTAvlPVGet(&pDbgAs->ModTree, hDbgMod);
887 if (!pMod)
888 {
889 RTDBGAS_UNLOCK_WRITE(pDbgAs);
890 return VERR_NOT_FOUND;
891 }
892
893 /*
894 * Unmap all everything and release the module.
895 */
896 while (pMod->pMapHead)
897 rtDbgAsModuleUnlinkMap(pDbgAs, pMod->pMapHead);
898 rtDbgAsModuleUnlinkMod(pDbgAs, pMod);
899
900 RTDBGAS_UNLOCK_WRITE(pDbgAs);
901 return VINF_SUCCESS;
902}
903RT_EXPORT_SYMBOL(RTDbgAsModuleUnlink);
904
905
906/**
907 * Unlinks the mapping at the specified address.
908 *
909 * @returns IPRT status code.
910 * @retval VERR_NOT_FOUND if no module or segment is mapped at that address.
911 *
912 * @param hDbgAs The address space handle.
913 * @param Addr The address within the mapping to be unlinked.
914 */
915RTDECL(int) RTDbgAsModuleUnlinkByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr)
916{
917 /*
918 * Validate input.
919 */
920 PRTDBGASINT pDbgAs = hDbgAs;
921 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
922
923 RTDBGAS_LOCK_WRITE(pDbgAs);
924 PRTDBGASMAP pMap = (PRTDBGASMAP)RTAvlrUIntPtrRangeGet(&pDbgAs->MapTree, Addr);
925 if (!pMap)
926 {
927 RTDBGAS_UNLOCK_WRITE(pDbgAs);
928 return VERR_NOT_FOUND;
929 }
930
931 /*
932 * Hand it to
933 */
934 rtDbgAsModuleUnlinkByMap(pDbgAs, pMap);
935
936 RTDBGAS_UNLOCK_WRITE(pDbgAs);
937 return VINF_SUCCESS;
938}
939RT_EXPORT_SYMBOL(RTDbgAsModuleUnlinkByAddr);
940
941
942/**
943 * Get a the handle of a module in the address space by is index.
944 *
945 * @returns A retained handle to the specified module. The caller must release
946 * the returned reference.
947 * NIL_RTDBGMOD if invalid index or handle.
948 *
949 * @param hDbgAs The address space handle.
950 * @param iModule The index of the module to get.
951 *
952 * @remarks The module indexes may change after calls to RTDbgAsModuleLink,
953 * RTDbgAsModuleLinkSeg, RTDbgAsModuleUnlink and
954 * RTDbgAsModuleUnlinkByAddr.
955 */
956RTDECL(RTDBGMOD) RTDbgAsModuleByIndex(RTDBGAS hDbgAs, uint32_t iModule)
957{
958 /*
959 * Validate input.
960 */
961 PRTDBGASINT pDbgAs = hDbgAs;
962 RTDBGAS_VALID_RETURN_RC(pDbgAs, NIL_RTDBGMOD);
963
964 RTDBGAS_LOCK_READ(pDbgAs);
965 if (iModule >= pDbgAs->cModules)
966 {
967 RTDBGAS_UNLOCK_READ(pDbgAs);
968 return NIL_RTDBGMOD;
969 }
970
971 /*
972 * Get, retain and return it.
973 */
974 RTDBGMOD hMod = (RTDBGMOD)pDbgAs->papModules[iModule]->Core.Key;
975 RTDbgModRetain(hMod);
976
977 RTDBGAS_UNLOCK_READ(pDbgAs);
978 return hMod;
979}
980RT_EXPORT_SYMBOL(RTDbgAsModuleByIndex);
981
982
983/**
984 * Queries mapping module information by handle.
985 *
986 * @returns IPRT status code.
987 * @retval VERR_NOT_FOUND if no mapping was found at the specified address.
988 *
989 * @param hDbgAs The address space handle.
990 * @param Addr Address within the mapping of the module or segment.
991 * @param phMod Where to the return the retained module handle.
992 * Optional.
993 * @param pAddr Where to return the base address of the mapping.
994 * Optional.
995 * @param piSeg Where to return the segment index. This is set to
996 * NIL if the entire module is mapped as a single
997 * mapping. Optional.
998 */
999RTDECL(int) RTDbgAsModuleByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTDBGMOD phMod, PRTUINTPTR pAddr, PRTDBGSEGIDX piSeg)
1000{
1001 /*
1002 * Validate input.
1003 */
1004 PRTDBGASINT pDbgAs = hDbgAs;
1005 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1006
1007 RTDBGAS_LOCK_READ(pDbgAs);
1008 PRTDBGASMAP pMap = (PRTDBGASMAP)RTAvlrUIntPtrRangeGet(&pDbgAs->MapTree, Addr);
1009 if (!pMap)
1010 {
1011 RTDBGAS_UNLOCK_READ(pDbgAs);
1012 return VERR_NOT_FOUND;
1013 }
1014
1015 /*
1016 * Set up the return values.
1017 */
1018 if (phMod)
1019 {
1020 RTDBGMOD hMod = (RTDBGMOD)pMap->pMod->Core.Key;
1021 RTDbgModRetain(hMod);
1022 *phMod = hMod;
1023 }
1024 if (pAddr)
1025 *pAddr = pMap->Core.Key;
1026 if (piSeg)
1027 *piSeg = pMap->iSeg;
1028
1029 RTDBGAS_UNLOCK_READ(pDbgAs);
1030 return VINF_SUCCESS;
1031}
1032RT_EXPORT_SYMBOL(RTDbgAsModuleByAddr);
1033
1034
1035/**
1036 * Queries mapping module information by name.
1037 *
1038 * @returns IPRT status code.
1039 * @retval VERR_NOT_FOUND if no mapping was found at the specified address.
1040 * @retval VERR_OUT_OF_RANGE if the name index was out of range.
1041 *
1042 * @param hDbgAs The address space handle.
1043 * @param pszName The module name.
1044 * @param iName There can be more than one module by the same name
1045 * in an address space. This argument indicates which
1046 * is meant. (0 based)
1047 * @param phMod Where to the return the retained module handle.
1048 */
1049RTDECL(int) RTDbgAsModuleByName(RTDBGAS hDbgAs, const char *pszName, uint32_t iName, PRTDBGMOD phMod)
1050{
1051 /*
1052 * Validate input.
1053 */
1054 PRTDBGASINT pDbgAs = hDbgAs;
1055 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1056 AssertPtrReturn(phMod, VERR_INVALID_POINTER);
1057
1058 RTDBGAS_LOCK_READ(pDbgAs);
1059 PRTDBGASNAME pName = (PRTDBGASNAME)RTStrSpaceGet(&pDbgAs->NameSpace, pszName);
1060 if (!pName)
1061 {
1062 RTDBGAS_UNLOCK_READ(pDbgAs);
1063 return VERR_NOT_FOUND;
1064 }
1065
1066 PRTDBGASMOD pMod = pName->pHead;
1067 while (iName-- > 0)
1068 {
1069 pMod = pMod->pNextName;
1070 if (!pMod)
1071 {
1072 RTDBGAS_UNLOCK_READ(pDbgAs);
1073 return VERR_OUT_OF_RANGE;
1074 }
1075 }
1076
1077 /*
1078 * Get, retain and return it.
1079 */
1080 RTDBGMOD hMod = (RTDBGMOD)pMod->Core.Key;
1081 RTDbgModRetain(hMod);
1082 *phMod = hMod;
1083
1084 RTDBGAS_UNLOCK_READ(pDbgAs);
1085 return VINF_SUCCESS;
1086}
1087RT_EXPORT_SYMBOL(RTDbgAsModuleByName);
1088
1089
1090/**
1091 * Queries mapping information for a module given by index.
1092 *
1093 * @returns IRPT status code.
1094 * @retval VERR_INVALID_HANDLE if hDbgAs is invalid.
1095 * @retval VERR_OUT_OF_RANGE if the name index was out of range.
1096 * @retval VINF_BUFFER_OVERFLOW if the array is too small and the returned
1097 * information is incomplete.
1098 *
1099 * @param hDbgAs The address space handle.
1100 * @param iModule The index of the module to get.
1101 * @param paMappings Where to return the mapping information. The buffer
1102 * size is given by *pcMappings.
1103 * @param pcMappings IN: Size of the paMappings array. OUT: The number of
1104 * entries returned.
1105 * @param fFlags Flags for reserved for future use. MBZ.
1106 *
1107 * @remarks See remarks for RTDbgAsModuleByIndex regarding the volatility of the
1108 * iModule parameter.
1109 */
1110RTDECL(int) RTDbgAsModuleQueryMapByIndex(RTDBGAS hDbgAs, uint32_t iModule, PRTDBGASMAPINFO paMappings, uint32_t *pcMappings, uint32_t fFlags)
1111{
1112 /*
1113 * Validate input.
1114 */
1115 uint32_t const cMappings = *pcMappings;
1116 PRTDBGASINT pDbgAs = hDbgAs;
1117 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1118 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
1119
1120 RTDBGAS_LOCK_READ(pDbgAs);
1121 if (iModule >= pDbgAs->cModules)
1122 {
1123 RTDBGAS_UNLOCK_READ(pDbgAs);
1124 return VERR_OUT_OF_RANGE;
1125 }
1126
1127 /*
1128 * Copy the mapping information about the module.
1129 */
1130 int rc = VINF_SUCCESS;
1131 PRTDBGASMAP pMap = pDbgAs->papModules[iModule]->pMapHead;
1132 uint32_t cMaps = 0;
1133 while (pMap)
1134 {
1135 if (cMaps >= cMappings)
1136 {
1137 rc = VINF_BUFFER_OVERFLOW;
1138 break;
1139 }
1140 paMappings[cMaps].Address = pMap->Core.Key;
1141 paMappings[cMaps].iSeg = pMap->iSeg;
1142 cMaps++;
1143 pMap = pMap->pNext;
1144 }
1145
1146 RTDBGAS_UNLOCK_READ(pDbgAs);
1147 *pcMappings = cMaps;
1148 return rc;
1149}
1150RT_EXPORT_SYMBOL(RTDbgAsModuleQueryMapByIndex);
1151
1152
1153/**
1154 * Internal worker that looks up and retains a module.
1155 *
1156 * @returns Module handle, NIL_RTDBGMOD if not found.
1157 * @param pDbgAs The address space instance data.
1158 * @param Addr Address within the module.
1159 * @param piSeg where to return the segment index.
1160 * @param poffSeg Where to return the segment offset.
1161 * @param pMapAddr The mapping address (RTDBGASMAP::Core.Key).
1162 */
1163DECLINLINE(RTDBGMOD) rtDbgAsModuleByAddr(PRTDBGASINT pDbgAs, RTUINTPTR Addr, PRTDBGSEGIDX piSeg, PRTUINTPTR poffSeg, PRTUINTPTR pMapAddr)
1164{
1165 RTDBGMOD hMod = NIL_RTDBGMOD;
1166
1167 RTDBGAS_LOCK_READ(pDbgAs);
1168 PRTDBGASMAP pMap = (PRTDBGASMAP)RTAvlrUIntPtrRangeGet(&pDbgAs->MapTree, Addr);
1169 if (pMap)
1170 {
1171 hMod = (RTDBGMOD)pMap->pMod->Core.Key;
1172 RTDbgModRetain(hMod);
1173 *piSeg = pMap->iSeg != NIL_RTDBGSEGIDX ? pMap->iSeg : RTDBGSEGIDX_RVA;
1174 *poffSeg = Addr - pMap->Core.Key;
1175 if (pMapAddr)
1176 *pMapAddr = pMap->Core.Key;
1177 }
1178 RTDBGAS_UNLOCK_READ(pDbgAs);
1179
1180 return hMod;
1181}
1182
1183
1184/**
1185 * Adjusts the address to correspond to the mapping of the module/segment.
1186 *
1187 * @param pAddr The address to adjust (in/out).
1188 * @param iSeg The related segment.
1189 * @param hDbgMod The module handle.
1190 * @param MapAddr The mapping address.
1191 * @param iMapSeg The segment that's mapped, NIL_RTDBGSEGIDX or
1192 * RTDBGSEGIDX_RVA if the whole module is mapped here.
1193 */
1194DECLINLINE(void) rtDbgAsAdjustAddressByMapping(PRTUINTPTR pAddr, RTDBGSEGIDX iSeg,
1195 RTDBGMOD hDbgMod, RTUINTPTR MapAddr, RTDBGSEGIDX iMapSeg)
1196{
1197 if (iSeg == RTDBGSEGIDX_ABS)
1198 return;
1199
1200 if (iSeg == RTDBGSEGIDX_RVA)
1201 {
1202 if ( iMapSeg == RTDBGSEGIDX_RVA
1203 || iMapSeg == NIL_RTDBGSEGIDX)
1204 *pAddr += MapAddr;
1205 else
1206 {
1207 RTUINTPTR SegRva = RTDbgModSegmentRva(hDbgMod, iMapSeg);
1208 AssertReturnVoid(SegRva != RTUINTPTR_MAX);
1209 AssertMsg(SegRva <= *pAddr, ("SegRva=%RTptr *pAddr=%RTptr\n", SegRva, *pAddr));
1210 *pAddr += MapAddr - SegRva;
1211 }
1212 }
1213 else
1214 {
1215 if ( iMapSeg != RTDBGSEGIDX_RVA
1216 && iMapSeg != NIL_RTDBGSEGIDX)
1217 {
1218 Assert(iMapSeg == iSeg);
1219 *pAddr += MapAddr;
1220 }
1221 else
1222 {
1223 RTUINTPTR SegRva = RTDbgModSegmentRva(hDbgMod, iSeg);
1224 AssertReturnVoid(SegRva != RTUINTPTR_MAX);
1225 *pAddr += MapAddr + SegRva;
1226 }
1227 }
1228}
1229
1230
1231/**
1232 * Adjusts the symbol value to correspond to the mapping of the module/segment.
1233 *
1234 * @param pSymbol The returned symbol info.
1235 * @param hDbgMod The module handle.
1236 * @param MapAddr The mapping address.
1237 * @param iMapSeg The segment that's mapped, NIL_RTDBGSEGIDX if the
1238 * whole module is mapped here.
1239 */
1240DECLINLINE(void) rtDbgAsAdjustSymbolValue(PRTDBGSYMBOL pSymbol, RTDBGMOD hDbgMod, RTUINTPTR MapAddr, RTDBGSEGIDX iMapSeg)
1241{
1242 Assert(pSymbol->iSeg != NIL_RTDBGSEGIDX);
1243 Assert(pSymbol->offSeg == pSymbol->Value);
1244 rtDbgAsAdjustAddressByMapping(&pSymbol->Value, pSymbol->iSeg, hDbgMod, MapAddr, iMapSeg);
1245}
1246
1247
1248/**
1249 * Adjusts the line number address to correspond to the mapping of the module/segment.
1250 *
1251 * @param pLine The returned line number info.
1252 * @param hDbgMod The module handle.
1253 * @param MapAddr The mapping address.
1254 * @param iMapSeg The segment that's mapped, NIL_RTDBGSEGIDX if the
1255 * whole module is mapped here.
1256 */
1257DECLINLINE(void) rtDbgAsAdjustLineAddress(PRTDBGLINE pLine, RTDBGMOD hDbgMod, RTUINTPTR MapAddr, RTDBGSEGIDX iMapSeg)
1258{
1259 Assert(pLine->iSeg != NIL_RTDBGSEGIDX);
1260 Assert(pLine->offSeg == pLine->Address);
1261 rtDbgAsAdjustAddressByMapping(&pLine->Address, pLine->iSeg, hDbgMod, MapAddr, iMapSeg);
1262}
1263
1264
1265/**
1266 * Adds a symbol to a module in the address space.
1267 *
1268 * @returns IPRT status code. See RTDbgModSymbolAdd for more specific ones.
1269 * @retval VERR_INVALID_HANDLE if hDbgAs is invalid.
1270 * @retval VERR_NOT_FOUND if no module was found at the specified address.
1271 * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding
1272 * custom symbols.
1273 *
1274 * @param hDbgAs The address space handle.
1275 * @param pszSymbol The symbol name.
1276 * @param Addr The address of the symbol.
1277 * @param cb The size of the symbol.
1278 * @param fFlags Symbol flags, RTDBGSYMBOLADD_F_XXX.
1279 * @param piOrdinal Where to return the symbol ordinal on success. If
1280 * the interpreter doesn't do ordinals, this will be set to
1281 * UINT32_MAX. Optional
1282 */
1283RTDECL(int) RTDbgAsSymbolAdd(RTDBGAS hDbgAs, const char *pszSymbol, RTUINTPTR Addr, RTUINTPTR cb, uint32_t fFlags, uint32_t *piOrdinal)
1284{
1285 /*
1286 * Validate input and resolve the address.
1287 */
1288 PRTDBGASINT pDbgAs = hDbgAs;
1289 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1290
1291 RTDBGSEGIDX iSeg = NIL_RTDBGSEGIDX; /* shut up gcc */
1292 RTUINTPTR offSeg = 0;
1293 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, NULL);
1294 if (hMod == NIL_RTDBGMOD)
1295 return VERR_NOT_FOUND;
1296
1297 /*
1298 * Forward the call.
1299 */
1300 int rc = RTDbgModSymbolAdd(hMod, pszSymbol, iSeg, offSeg, cb, fFlags, piOrdinal);
1301 RTDbgModRelease(hMod);
1302 return rc;
1303}
1304RT_EXPORT_SYMBOL(RTDbgAsSymbolAdd);
1305
1306
1307/**
1308 * Creates a snapshot of the module table on the temporary heap.
1309 *
1310 * The caller must release all the module handles before freeing the table
1311 * using RTMemTmpFree.
1312 *
1313 * @returns Module table snaphot.
1314 * @param pDbgAs The address space instance data.
1315 * @param pcModules Where to return the number of modules.
1316 */
1317static PRTDBGMOD rtDbgAsSnapshotModuleTable(PRTDBGASINT pDbgAs, uint32_t *pcModules)
1318{
1319 RTDBGAS_LOCK_READ(pDbgAs);
1320
1321 uint32_t iMod = *pcModules = pDbgAs->cModules;
1322 PRTDBGMOD pahModules = (PRTDBGMOD)RTMemTmpAlloc(sizeof(pahModules[0]) * RT_MAX(iMod, 1));
1323 if (pahModules)
1324 {
1325 while (iMod-- > 0)
1326 {
1327 RTDBGMOD hMod = (RTDBGMOD)pDbgAs->papModules[iMod]->Core.Key;
1328 pahModules[iMod] = hMod;
1329 RTDbgModRetain(hMod);
1330 }
1331 }
1332
1333 RTDBGAS_UNLOCK_READ(pDbgAs);
1334 return pahModules;
1335}
1336
1337
1338/**
1339 * Query a symbol by address.
1340 *
1341 * @returns IPRT status code. See RTDbgModSymbolAddr for more specific ones.
1342 * @retval VERR_INVALID_HANDLE if hDbgAs is invalid.
1343 * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module.
1344 * @retval VERR_INVALID_PARAMETER if incorrect flags.
1345 *
1346 * @param hDbgAs The address space handle.
1347 * @param Addr The address which closest symbol is requested.
1348 * @param fFlags Symbol search flags, see RTDBGSYMADDR_FLAGS_XXX.
1349 * @param poffDisp Where to return the distance between the symbol and
1350 * address. Optional.
1351 * @param pSymbol Where to return the symbol info.
1352 * @param phMod Where to return the module handle. Optional.
1353 */
1354RTDECL(int) RTDbgAsSymbolByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, uint32_t fFlags,
1355 PRTINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
1356{
1357 /*
1358 * Validate input and resolve the address.
1359 */
1360 PRTDBGASINT pDbgAs = hDbgAs;
1361 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1362 if (phMod)
1363 *phMod = NIL_RTDBGMOD;
1364
1365 RTDBGSEGIDX iSeg = NIL_RTDBGSEGIDX; /* shut up gcc */
1366 RTUINTPTR offSeg = 0;
1367 RTUINTPTR MapAddr = 0;
1368 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, &MapAddr);
1369 if (hMod == NIL_RTDBGMOD)
1370 {
1371 /*
1372 * Check for absolute symbols. Requires iterating all modules.
1373 */
1374 if (fFlags & RTDBGSYMADDR_FLAGS_SKIP_ABS)
1375 return VERR_NOT_FOUND;
1376
1377 uint32_t cModules;
1378 PRTDBGMOD pahModules = rtDbgAsSnapshotModuleTable(pDbgAs, &cModules);
1379 if (!pahModules)
1380 return VERR_NO_TMP_MEMORY;
1381
1382 int rc;
1383 RTINTPTR offBestDisp = RTINTPTR_MAX;
1384 uint32_t iBest = UINT32_MAX;
1385 for (uint32_t i = 0; i < cModules; i++)
1386 {
1387 RTINTPTR offDisp;
1388 rc = RTDbgModSymbolByAddr(pahModules[i], RTDBGSEGIDX_ABS, Addr, fFlags, &offDisp, pSymbol);
1389 if (RT_SUCCESS(rc) && RT_ABS(offDisp) < offBestDisp)
1390 {
1391 offBestDisp = RT_ABS(offDisp);
1392 iBest = i;
1393 }
1394 }
1395
1396 if (iBest == UINT32_MAX)
1397 rc = VERR_NOT_FOUND;
1398 else
1399 {
1400 hMod = pahModules[iBest];
1401 rc = RTDbgModSymbolByAddr(hMod, RTDBGSEGIDX_ABS, Addr, fFlags, poffDisp, pSymbol);
1402 if (RT_SUCCESS(rc))
1403 {
1404 rtDbgAsAdjustSymbolValue(pSymbol, hMod, MapAddr, iSeg);
1405 if (phMod)
1406 RTDbgModRetain(*phMod = hMod);
1407 }
1408 }
1409
1410 for (uint32_t i = 0; i < cModules; i++)
1411 RTDbgModRelease(pahModules[i]);
1412 RTMemTmpFree(pahModules);
1413 return rc;
1414 }
1415
1416 /*
1417 * Forward the call.
1418 */
1419 int rc = RTDbgModSymbolByAddr(hMod, iSeg, offSeg, fFlags, poffDisp, pSymbol);
1420 if (RT_SUCCESS(rc))
1421 rtDbgAsAdjustSymbolValue(pSymbol, hMod, MapAddr, iSeg);
1422 if (phMod)
1423 *phMod = hMod;
1424 else
1425 RTDbgModRelease(hMod);
1426 return rc;
1427}
1428RT_EXPORT_SYMBOL(RTDbgAsSymbolByAddr);
1429
1430
1431/**
1432 * Query a symbol by address.
1433 *
1434 * @returns IPRT status code. See RTDbgModSymbolAddrA for more specific ones.
1435 * @retval VERR_INVALID_HANDLE if hDbgAs is invalid.
1436 * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module.
1437 * @retval VERR_INVALID_PARAMETER if incorrect flags.
1438 *
1439 * @param hDbgAs The address space handle.
1440 * @param Addr The address which closest symbol is requested.
1441 * @param fFlags Symbol search flags, see RTDBGSYMADDR_FLAGS_XXX.
1442 * @param poffDisp Where to return the distance between the symbol
1443 * and address. Optional.
1444 * @param ppSymInfo Where to return the pointer to the allocated symbol
1445 * info. Always set. Free with RTDbgSymbolFree.
1446 * @param phMod Where to return the module handle. Optional.
1447 */
1448RTDECL(int) RTDbgAsSymbolByAddrA(RTDBGAS hDbgAs, RTUINTPTR Addr, uint32_t fFlags,
1449 PRTINTPTR poffDisp, PRTDBGSYMBOL *ppSymInfo, PRTDBGMOD phMod)
1450{
1451 /*
1452 * Validate input and resolve the address.
1453 */
1454 PRTDBGASINT pDbgAs = hDbgAs;
1455 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1456
1457 RTDBGSEGIDX iSeg = NIL_RTDBGSEGIDX;
1458 RTUINTPTR offSeg = 0;
1459 RTUINTPTR MapAddr = 0;
1460 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, &MapAddr);
1461 if (hMod == NIL_RTDBGMOD)
1462 {
1463 if (phMod)
1464 *phMod = NIL_RTDBGMOD;
1465 return VERR_NOT_FOUND;
1466 }
1467
1468 /*
1469 * Forward the call.
1470 */
1471 int rc = RTDbgModSymbolByAddrA(hMod, iSeg, offSeg, fFlags, poffDisp, ppSymInfo);
1472 if (RT_SUCCESS(rc))
1473 rtDbgAsAdjustSymbolValue(*ppSymInfo, hMod, MapAddr, iSeg);
1474 if (phMod)
1475 *phMod = hMod;
1476 else
1477 RTDbgModRelease(hMod);
1478 return rc;
1479}
1480RT_EXPORT_SYMBOL(RTDbgAsSymbolByAddrA);
1481
1482
1483/**
1484 * Attempts to find a mapping of the specified symbol/module and
1485 * adjust it's Value field accordingly.
1486 *
1487 * @returns true / false success indicator.
1488 * @param pDbgAs The address space.
1489 * @param hDbgMod The module handle.
1490 * @param pSymbol The symbol info.
1491 */
1492static bool rtDbgAsFindMappingAndAdjustSymbolValue(PRTDBGASINT pDbgAs, RTDBGMOD hDbgMod, PRTDBGSYMBOL pSymbol)
1493{
1494 /*
1495 * Absolute segments needs no fixing.
1496 */
1497 RTDBGSEGIDX const iSeg = pSymbol->iSeg;
1498 if (iSeg == RTDBGSEGIDX_ABS)
1499 return true;
1500
1501 RTDBGAS_LOCK_READ(pDbgAs);
1502
1503 /*
1504 * Lookup up the module by it's handle and iterate the mappings looking for one
1505 * that either encompasses the entire module or the segment in question.
1506 */
1507 PRTDBGASMOD pMod = (PRTDBGASMOD)RTAvlPVGet(&pDbgAs->ModTree, hDbgMod);
1508 if (pMod)
1509 {
1510 for (PRTDBGASMAP pMap = pMod->pMapHead; pMap; pMap = pMap->pNext)
1511 {
1512 /* Exact segment match or full-mapping. */
1513 if ( iSeg == pMap->iSeg
1514 || pMap->iSeg == NIL_RTDBGSEGIDX)
1515 {
1516 RTUINTPTR MapAddr = pMap->Core.Key;
1517 RTDBGSEGIDX iMapSeg = pMap->iSeg;
1518
1519 RTDBGAS_UNLOCK_READ(pDbgAs);
1520 rtDbgAsAdjustSymbolValue(pSymbol, hDbgMod, MapAddr, iMapSeg);
1521 return true;
1522 }
1523
1524 /* Symbol uses RVA and the mapping doesn't, see if it's in the mapped segment. */
1525 if (iSeg == RTDBGSEGIDX_RVA)
1526 {
1527 Assert(pMap->iSeg != NIL_RTDBGSEGIDX);
1528 RTUINTPTR SegRva = RTDbgModSegmentRva(hDbgMod, pMap->iSeg);
1529 Assert(SegRva != RTUINTPTR_MAX);
1530 RTUINTPTR cbSeg = RTDbgModSegmentSize(hDbgMod, pMap->iSeg);
1531 if (SegRva - pSymbol->Value < cbSeg)
1532 {
1533 RTUINTPTR MapAddr = pMap->Core.Key;
1534 RTDBGSEGIDX iMapSeg = pMap->iSeg;
1535
1536 RTDBGAS_UNLOCK_READ(pDbgAs);
1537 rtDbgAsAdjustSymbolValue(pSymbol, hDbgMod, MapAddr, iMapSeg);
1538 return true;
1539 }
1540 }
1541 }
1542 }
1543 /* else: Unmapped while we were searching. */
1544
1545 RTDBGAS_UNLOCK_READ(pDbgAs);
1546 return false;
1547}
1548
1549
1550/**
1551 * Query a symbol by name.
1552 *
1553 * @returns IPRT status code.
1554 * @retval VERR_SYMBOL_NOT_FOUND if not found.
1555 *
1556 * @param hDbgAs The address space handle.
1557 * @param pszSymbol The symbol name. It is possible to limit the scope
1558 * of the search by prefixing the symbol with a module
1559 * name pattern followed by a bang (!) character.
1560 * RTStrSimplePatternNMatch is used for the matching.
1561 * @param pSymbol Where to return the symbol info.
1562 * @param phMod Where to return the module handle. Optional.
1563 */
1564RTDECL(int) RTDbgAsSymbolByName(RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
1565{
1566 /*
1567 * Validate input.
1568 */
1569 PRTDBGASINT pDbgAs = hDbgAs;
1570 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1571 AssertPtrReturn(pszSymbol, VERR_INVALID_POINTER);
1572 AssertPtrReturn(pSymbol, VERR_INVALID_POINTER);
1573
1574 /*
1575 * Look for module pattern.
1576 */
1577 const char *pachModPat = NULL;
1578 size_t cchModPat = 0;
1579 const char *pszBang = strchr(pszSymbol, '!');
1580 if (pszBang)
1581 {
1582 pachModPat = pszSymbol;
1583 cchModPat = pszBang - pszSymbol;
1584 pszSymbol = pszBang + 1;
1585 if (!*pszSymbol)
1586 return VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE;
1587 /* Note! Zero length module -> no pattern -> escape for symbol with '!'. */
1588 }
1589
1590 /*
1591 * Iterate the modules, looking for the symbol.
1592 */
1593 uint32_t cModules;
1594 PRTDBGMOD pahModules = rtDbgAsSnapshotModuleTable(pDbgAs, &cModules);
1595 if (!pahModules)
1596 return VERR_NO_TMP_MEMORY;
1597
1598 for (uint32_t i = 0; i < cModules; i++)
1599 {
1600 if ( cchModPat == 0
1601 || RTStrSimplePatternNMatch(pachModPat, cchModPat, RTDbgModName(pahModules[i]), RTSTR_MAX))
1602 {
1603 int rc = RTDbgModSymbolByName(pahModules[i], pszSymbol, pSymbol);
1604 if (RT_SUCCESS(rc))
1605 {
1606 if (rtDbgAsFindMappingAndAdjustSymbolValue(pDbgAs, pahModules[i], pSymbol))
1607 {
1608 if (phMod)
1609 RTDbgModRetain(*phMod = pahModules[i]);
1610 for (; i < cModules; i++)
1611 RTDbgModRelease(pahModules[i]);
1612 RTMemTmpFree(pahModules);
1613 return rc;
1614 }
1615 }
1616 }
1617 RTDbgModRelease(pahModules[i]);
1618 }
1619
1620 RTMemTmpFree(pahModules);
1621 return VERR_SYMBOL_NOT_FOUND;
1622}
1623RT_EXPORT_SYMBOL(RTDbgAsSymbolByName);
1624
1625
1626/**
1627 * Query a symbol by name, allocating the returned symbol structure.
1628 *
1629 * @returns IPRT status code.
1630 * @retval VERR_SYMBOL_NOT_FOUND if not found.
1631 *
1632 * @param hDbgAs The address space handle.
1633 * @param pszSymbol The symbol name. See RTDbgAsSymbolByName for more.
1634 * @param ppSymbol Where to return the pointer to the allocated
1635 * symbol info. Always set. Free with RTDbgSymbolFree.
1636 * @param phMod Where to return the module handle. Optional.
1637 */
1638RTDECL(int) RTDbgAsSymbolByNameA(RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL *ppSymbol, PRTDBGMOD phMod)
1639{
1640 /*
1641 * Validate input.
1642 */
1643 AssertPtrReturn(ppSymbol, VERR_INVALID_POINTER);
1644 *ppSymbol = NULL;
1645 PRTDBGASINT pDbgAs = hDbgAs;
1646 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1647 AssertPtrReturn(pszSymbol, VERR_INVALID_POINTER);
1648
1649 /*
1650 * Look for module pattern.
1651 */
1652 const char *pachModPat = NULL;
1653 size_t cchModPat = 0;
1654 const char *pszBang = strchr(pszSymbol, '!');
1655 if (pszBang)
1656 {
1657 pachModPat = pszSymbol;
1658 cchModPat = pszBang - pszSymbol;
1659 pszSymbol = pszBang + 1;
1660 if (!*pszSymbol)
1661 return VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE;
1662 /* Note! Zero length module -> no pattern -> escape for symbol with '!'. */
1663 }
1664
1665 /*
1666 * Iterate the modules, looking for the symbol.
1667 */
1668 uint32_t cModules;
1669 PRTDBGMOD pahModules = rtDbgAsSnapshotModuleTable(pDbgAs, &cModules);
1670 if (!pahModules)
1671 return VERR_NO_TMP_MEMORY;
1672
1673 for (uint32_t i = 0; i < cModules; i++)
1674 {
1675 if ( cchModPat == 0
1676 || RTStrSimplePatternNMatch(pachModPat, cchModPat, RTDbgModName(pahModules[i]), RTSTR_MAX))
1677 {
1678 int rc = RTDbgModSymbolByNameA(pahModules[i], pszSymbol, ppSymbol);
1679 if (RT_SUCCESS(rc))
1680 {
1681 if (rtDbgAsFindMappingAndAdjustSymbolValue(pDbgAs, pahModules[i], *ppSymbol))
1682 {
1683 if (phMod)
1684 RTDbgModRetain(*phMod = pahModules[i]);
1685 for (; i < cModules; i++)
1686 RTDbgModRelease(pahModules[i]);
1687 RTMemTmpFree(pahModules);
1688 return rc;
1689 }
1690 }
1691 }
1692 RTDbgModRelease(pahModules[i]);
1693 }
1694
1695 RTMemTmpFree(pahModules);
1696 return VERR_SYMBOL_NOT_FOUND;
1697}
1698RT_EXPORT_SYMBOL(RTDbgAsSymbolByNameA);
1699
1700
1701/**
1702 * Adds a line number to a module in the address space.
1703 *
1704 * @returns IPRT status code. See RTDbgModSymbolAdd for more specific ones.
1705 * @retval VERR_INVALID_HANDLE if hDbgAs is invalid.
1706 * @retval VERR_NOT_FOUND if no module was found at the specified address.
1707 * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding
1708 * custom symbols.
1709 *
1710 * @param hDbgAs The address space handle.
1711 * @param pszFile The file name.
1712 * @param uLineNo The line number.
1713 * @param Addr The address of the symbol.
1714 * @param piOrdinal Where to return the line number ordinal on success.
1715 * If the interpreter doesn't do ordinals, this will be
1716 * set to UINT32_MAX. Optional.
1717 */
1718RTDECL(int) RTDbgAsLineAdd(RTDBGAS hDbgAs, const char *pszFile, uint32_t uLineNo, RTUINTPTR Addr, uint32_t *piOrdinal)
1719{
1720 /*
1721 * Validate input and resolve the address.
1722 */
1723 PRTDBGASINT pDbgAs = hDbgAs;
1724 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1725
1726 RTDBGSEGIDX iSeg = NIL_RTDBGSEGIDX; /* shut up gcc */
1727 RTUINTPTR offSeg = 0; /* ditto */
1728 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, NULL);
1729 if (hMod == NIL_RTDBGMOD)
1730 return VERR_NOT_FOUND;
1731
1732 /*
1733 * Forward the call.
1734 */
1735 int rc = RTDbgModLineAdd(hMod, pszFile, uLineNo, iSeg, offSeg, piOrdinal);
1736 RTDbgModRelease(hMod);
1737 return rc;
1738}
1739RT_EXPORT_SYMBOL(RTDbgAsLineAdd);
1740
1741
1742RTDECL(int) RTDbgAsLineByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE pLine, PRTDBGMOD phMod)
1743{
1744 /*
1745 * Validate input and resolve the address.
1746 */
1747 PRTDBGASINT pDbgAs = hDbgAs;
1748 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1749
1750 RTDBGSEGIDX iSeg = NIL_RTDBGSEGIDX; /* shut up gcc */
1751 RTUINTPTR offSeg = 0;
1752 RTUINTPTR MapAddr = 0;
1753 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, &MapAddr);
1754 if (hMod == NIL_RTDBGMOD)
1755 return VERR_NOT_FOUND;
1756
1757 /*
1758 * Forward the call.
1759 */
1760 int rc = RTDbgModLineByAddr(hMod, iSeg, offSeg, poffDisp, pLine);
1761 if (RT_SUCCESS(rc))
1762 {
1763 rtDbgAsAdjustLineAddress(pLine, hMod, MapAddr, iSeg);
1764 if (phMod)
1765 *phMod = hMod;
1766 else
1767 RTDbgModRelease(hMod);
1768 }
1769 else
1770 RTDbgModRelease(hMod);
1771 return rc;
1772}
1773RT_EXPORT_SYMBOL(RTDbgAsLineByAddr);
1774
1775
1776RTDECL(int) RTDbgAsLineByAddrA(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE *ppLine, PRTDBGMOD phMod)
1777{
1778 /*
1779 * Validate input and resolve the address.
1780 */
1781 PRTDBGASINT pDbgAs = hDbgAs;
1782 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1783
1784 RTDBGSEGIDX iSeg = NIL_RTDBGSEGIDX; /* shut up gcc */
1785 RTUINTPTR offSeg = 0;
1786 RTUINTPTR MapAddr = 0;
1787 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, &MapAddr);
1788 if (hMod == NIL_RTDBGMOD)
1789 return VERR_NOT_FOUND;
1790
1791 /*
1792 * Forward the call.
1793 */
1794 int rc = RTDbgModLineByAddrA(hMod, iSeg, offSeg, poffDisp, ppLine);
1795 if (RT_SUCCESS(rc))
1796 {
1797 rtDbgAsAdjustLineAddress(*ppLine, hMod, MapAddr, iSeg);
1798 if (phMod)
1799 *phMod = hMod;
1800 else
1801 RTDbgModRelease(hMod);
1802 }
1803 else
1804 RTDbgModRelease(hMod);
1805 return rc;
1806}
1807RT_EXPORT_SYMBOL(RTDbgAsLineByAddrA);
1808
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