VirtualBox

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

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

IPRT: RTDbg coding.

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