VirtualBox

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

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

IPRT,HostDrv,AddDrv: Export public IPRT symbols for the linux kernel (pain).

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