VirtualBox

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

Last change on this file since 57358 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

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