VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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