VirtualBox

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

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

RTDbg: Some adjustments and fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.1 KB
Line 
1/* $Id: dbgas.cpp 21110 2009-07-01 01:02:58Z 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 * @param phMod Where to return the module handle. Optional.
1186 */
1187RTDECL(int) RTDbgAsSymbolByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
1188{
1189 /*
1190 * Validate input and resolve the address.
1191 */
1192 PRTDBGASINT pDbgAs = hDbgAs;
1193 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1194
1195 RTDBGSEGIDX iSeg;
1196 RTUINTPTR offSeg;
1197 RTUINTPTR MapAddr;
1198 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, &MapAddr);
1199 if (hMod == NIL_RTDBGMOD)
1200 {
1201 if (phMod)
1202 *phMod = NIL_RTDBGMOD;
1203 return VERR_NOT_FOUND;
1204 }
1205
1206 /*
1207 * Forward the call.
1208 */
1209 int rc = RTDbgModSymbolByAddr(hMod, iSeg, offSeg, poffDisp, pSymbol);
1210 if (RT_SUCCESS(rc))
1211 rtDbgAsAdjustSymbolValue(pSymbol, hMod, MapAddr, iSeg);
1212 if (phMod)
1213 *phMod = hMod;
1214 else
1215 RTDbgModRelease(hMod);
1216 return rc;
1217}
1218
1219
1220/**
1221 * Query a symbol by address.
1222 *
1223 * @returns IPRT status code. See RTDbgModSymbolAddrA for more specific ones.
1224 * @retval VERR_INVALID_HANDLE if hDbgAs is invalid.
1225 * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module.
1226 *
1227 * @param hDbgAs The address space handle.
1228 * @param Addr The address which closest symbol is requested.
1229 * @param poffDisp Where to return the distance between the symbol
1230 * and address. Optional.
1231 * @param ppSymbol Where to return the pointer to the allocated
1232 * symbol info. Always set. Free with RTDbgSymbolFree.
1233 * @param phMod Where to return the module handle. Optional.
1234 */
1235RTDECL(int) RTDbgAsSymbolByAddrA(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGSYMBOL *ppSymbol, PRTDBGMOD phMod)
1236{
1237 /*
1238 * Validate input and resolve the address.
1239 */
1240 PRTDBGASINT pDbgAs = hDbgAs;
1241 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1242
1243 RTDBGSEGIDX iSeg;
1244 RTUINTPTR offSeg;
1245 RTUINTPTR MapAddr;
1246 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, &MapAddr);
1247 if (hMod == NIL_RTDBGMOD)
1248 {
1249 if (phMod)
1250 *phMod = NIL_RTDBGMOD;
1251 return VERR_NOT_FOUND;
1252 }
1253
1254 /*
1255 * Forward the call.
1256 */
1257 int rc = RTDbgModSymbolByAddrA(hMod, iSeg, offSeg, poffDisp, ppSymbol);
1258 if (RT_SUCCESS(rc))
1259 rtDbgAsAdjustSymbolValue(*ppSymbol, hMod, MapAddr, iSeg);
1260 if (phMod)
1261 *phMod = hMod;
1262 else
1263 RTDbgModRelease(hMod);
1264 return rc;
1265}
1266
1267
1268/**
1269 * Creates a snapshot of the module table on the temporary heap.
1270 *
1271 * The caller must release all the module handles before freeing the table
1272 * using RTMemTmpFree.
1273 *
1274 * @returns Module table snaphot.
1275 * @param pDbgAs The address space instance data.
1276 * @param pcModules Where to return the number of modules.
1277 */
1278DECLINLINE(PRTDBGMOD) rtDbgAsSnapshotModuleTable(PRTDBGASINT pDbgAs, uint32_t *pcModules)
1279{
1280 RTDBGAS_LOCK_READ(pDbgAs);
1281
1282 uint32_t iMod = *pcModules = pDbgAs->cModules;
1283 PRTDBGMOD paModules = (PRTDBGMOD)RTMemTmpAlloc(sizeof(paModules[0]) * RT_MAX(iMod, 1));
1284 if (paModules)
1285 {
1286 while (iMod-- > 0)
1287 {
1288 RTDBGMOD hMod = (RTDBGMOD)pDbgAs->paModules[iMod].Core.Key;
1289 paModules[iMod] = hMod;
1290 RTDbgModRetain(hMod);
1291 }
1292 }
1293
1294 RTDBGAS_UNLOCK_READ(pDbgAs);
1295 return paModules;
1296}
1297
1298
1299/**
1300 * Attempts to find a mapping of the specified symbol/module and
1301 * adjust it's Value field accordingly.
1302 *
1303 * @returns true / false success indicator.
1304 * @param pDbgAs The address space.
1305 * @param hDbgMod The module handle.
1306 * @param pSymbol The symbol info.
1307 */
1308static bool rtDbgAsFindMappingAndAdjustSymbolValue(PRTDBGASINT pDbgAs, RTDBGMOD hDbgMod, PRTDBGSYMBOL pSymbol)
1309{
1310 /*
1311 * Absolute segments needs no fixing.
1312 */
1313 RTDBGSEGIDX const iSeg = pSymbol->iSeg;
1314 if (iSeg)
1315 return true;
1316
1317 RTDBGAS_LOCK_READ(pDbgAs);
1318
1319 /*
1320 * Lookup up the module by it's handle and iterate the mappings looking for one
1321 * that either encompasses the entire module or the segment in question.
1322 */
1323 PRTDBGASMOD pMod = (PRTDBGASMOD)RTAvlPVGet(&pDbgAs->ModTree, hDbgMod);
1324 if (pMod)
1325 {
1326 for (PRTDBGASMAP pMap = pMod->pMapHead; pMap; pMap = pMap->pNext)
1327 {
1328 /* Exact segment match or full-mapping. */
1329 if ( iSeg == pMap->iSeg
1330 || pMap->iSeg == NIL_RTDBGSEGIDX)
1331 {
1332 RTUINTPTR MapAddr = pMap->Core.Key;
1333 RTDBGSEGIDX iMapSeg = pMap->iSeg;
1334
1335 RTDBGAS_UNLOCK_READ(pDbgAs);
1336 rtDbgAsAdjustSymbolValue(pSymbol, hDbgMod, MapAddr, iMapSeg);
1337 return true;
1338 }
1339
1340 /* Symbol uses RVA and the mapping doesn't, see if it's in the mapped segment. */
1341 if (iSeg == RTDBGSEGIDX_RVA)
1342 {
1343 Assert(pMap->iSeg != NIL_RTDBGSEGIDX);
1344 RTUINTPTR SegRva = RTDbgModSegmentRva(hDbgMod, pMap->iSeg);
1345 Assert(SegRva != RTUINTPTR_MAX);
1346 RTUINTPTR cbSeg = RTDbgModSegmentSize(hDbgMod, pMap->iSeg);
1347 if (SegRva - pSymbol->Value < cbSeg)
1348 {
1349 RTUINTPTR MapAddr = pMap->Core.Key;
1350 RTDBGSEGIDX iMapSeg = pMap->iSeg;
1351
1352 RTDBGAS_UNLOCK_READ(pDbgAs);
1353 rtDbgAsAdjustSymbolValue(pSymbol, hDbgMod, MapAddr, iMapSeg);
1354 return true;
1355 }
1356 }
1357 }
1358 }
1359 /* else: Unmapped while we were searching. */
1360
1361 RTDBGAS_UNLOCK_READ(pDbgAs);
1362 return false;
1363}
1364
1365
1366/**
1367 * Query a symbol by name.
1368 *
1369 * @returns IPRT status code.
1370 * @retval VERR_SYMBOL_NOT_FOUND if not found.
1371 *
1372 * @param hDbgAs The address space handle.
1373 * @param pszSymbol The symbol name. It is possible to limit the scope
1374 * of the search by prefixing the symbol with a module
1375 * name pattern followed by a bang (!) character.
1376 * RTStrSimplePatternNMatch is used for the matching.
1377 * @param pSymbol Where to return the symbol info.
1378 * @param phMod Where to return the module handle. Optional.
1379 */
1380RTDECL(int) RTDbgAsSymbolByName(RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod)
1381{
1382 /*
1383 * Validate input.
1384 */
1385 PRTDBGASINT pDbgAs = hDbgAs;
1386 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1387 AssertPtrReturn(pszSymbol, VERR_INVALID_POINTER);
1388 AssertPtrReturn(pSymbol, VERR_INVALID_POINTER);
1389
1390 /*
1391 * Look for module pattern.
1392 */
1393 const char *pachModPat = NULL;
1394 size_t cchModPat = 0;
1395 const char *pszBang = strchr(pszSymbol, '!');
1396 if (pszBang)
1397 {
1398 pachModPat = pszSymbol;
1399 cchModPat = pszBang - pszSymbol;
1400 pszSymbol = pszBang + 1;
1401 if (!*pszSymbol)
1402 return VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE;
1403 /* Note! Zero length module -> no pattern -> escape for symbol with '!'. */
1404 }
1405
1406 /*
1407 * Iterate the modules, looking for the symbol.
1408 */
1409 uint32_t cModules;
1410 PRTDBGMOD paModules = rtDbgAsSnapshotModuleTable(pDbgAs, &cModules);
1411 if (!paModules)
1412 return VERR_NO_TMP_MEMORY;
1413
1414 for (uint32_t i = 0; i < cModules; i++)
1415 {
1416 if ( cchModPat == 0
1417 || RTStrSimplePatternNMatch(pachModPat, cchModPat, RTDbgModName(paModules[i]), RTSTR_MAX))
1418 {
1419 int rc = RTDbgModSymbolByName(paModules[i], pszSymbol, pSymbol);
1420 if (RT_SUCCESS(rc))
1421 {
1422 if (rtDbgAsFindMappingAndAdjustSymbolValue(pDbgAs, paModules[i], pSymbol))
1423 {
1424 if (phMod)
1425 RTDbgModRetain(*phMod = paModules[i]);
1426 for (; i < cModules; i++)
1427 RTDbgModRelease(paModules[i]);
1428 RTMemTmpFree(paModules);
1429 return rc;
1430 }
1431 }
1432 }
1433 RTDbgModRelease(paModules[i]);
1434 }
1435
1436 RTMemTmpFree(paModules);
1437 return VERR_SYMBOL_NOT_FOUND;
1438}
1439
1440
1441/**
1442 * Query a symbol by name, allocating the returned symbol structure.
1443 *
1444 * @returns IPRT status code.
1445 * @retval VERR_SYMBOL_NOT_FOUND if not found.
1446 *
1447 * @param hDbgAs The address space handle.
1448 * @param pszSymbol The symbol name. See RTDbgAsSymbolByName for more.
1449 * @param ppSymbol Where to return the pointer to the allocated
1450 * symbol info. Always set. Free with RTDbgSymbolFree.
1451 * @param phMod Where to return the module handle. Optional.
1452 */
1453RTDECL(int) RTDbgAsSymbolByNameA(RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL *ppSymbol, PRTDBGMOD phMod)
1454{
1455 /*
1456 * Validate input.
1457 */
1458 AssertPtrReturn(ppSymbol, VERR_INVALID_POINTER);
1459 *ppSymbol = NULL;
1460 PRTDBGASINT pDbgAs = hDbgAs;
1461 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1462 AssertPtrReturn(pszSymbol, VERR_INVALID_POINTER);
1463
1464 /*
1465 * Look for module pattern.
1466 */
1467 const char *pachModPat = NULL;
1468 size_t cchModPat = 0;
1469 const char *pszBang = strchr(pszSymbol, '!');
1470 if (pszBang)
1471 {
1472 pachModPat = pszSymbol;
1473 cchModPat = pszBang - pszSymbol;
1474 pszSymbol = pszBang + 1;
1475 if (!*pszSymbol)
1476 return VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE;
1477 /* Note! Zero length module -> no pattern -> escape for symbol with '!'. */
1478 }
1479
1480 /*
1481 * Iterate the modules, looking for the symbol.
1482 */
1483 uint32_t cModules;
1484 PRTDBGMOD paModules = rtDbgAsSnapshotModuleTable(pDbgAs, &cModules);
1485 if (!paModules)
1486 return VERR_NO_TMP_MEMORY;
1487
1488 for (uint32_t i = 0; i < cModules; i++)
1489 {
1490 if ( cchModPat == 0
1491 || RTStrSimplePatternNMatch(pachModPat, cchModPat, RTDbgModName(paModules[i]), RTSTR_MAX))
1492 {
1493 int rc = RTDbgModSymbolByNameA(paModules[i], pszSymbol, ppSymbol);
1494 if (RT_SUCCESS(rc))
1495 {
1496 if (rtDbgAsFindMappingAndAdjustSymbolValue(pDbgAs, paModules[i], *ppSymbol))
1497 {
1498 if (phMod)
1499 RTDbgModRetain(*phMod = paModules[i]);
1500 for (; i < cModules; i++)
1501 RTDbgModRelease(paModules[i]);
1502 RTMemTmpFree(paModules);
1503 return rc;
1504 }
1505 }
1506 }
1507 RTDbgModRelease(paModules[i]);
1508 }
1509
1510 RTMemTmpFree(paModules);
1511 return VERR_SYMBOL_NOT_FOUND;
1512}
1513
1514
1515/**
1516 * Adds a line number to a module in the address space.
1517 *
1518 * @returns IPRT status code. See RTDbgModSymbolAdd for more specific ones.
1519 * @retval VERR_INVALID_HANDLE if hDbgAs is invalid.
1520 * @retval VERR_NOT_FOUND if no module was found at the specified address.
1521 * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding
1522 * custom symbols.
1523 *
1524 * @param hDbgAs The address space handle.
1525 * @param pszFile The file name.
1526 * @param uLineNo The line number.
1527 * @param Addr The address of the symbol.
1528 * @param piOrdinal Where to return the line number ordinal on success.
1529 * If the interpreter doesn't do ordinals, this will be
1530 * set to UINT32_MAX. Optional.
1531 */
1532RTDECL(int) RTDbgAsLineAdd(RTDBGAS hDbgAs, const char *pszFile, uint32_t uLineNo, RTUINTPTR Addr, uint32_t *piOrdinal)
1533{
1534 /*
1535 * Validate input and resolve the address.
1536 */
1537 PRTDBGASINT pDbgAs = hDbgAs;
1538 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1539
1540 RTDBGSEGIDX iSeg;
1541 RTUINTPTR offSeg;
1542 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, NULL);
1543 if (hMod == NIL_RTDBGMOD)
1544 return VERR_NOT_FOUND;
1545
1546 /*
1547 * Forward the call.
1548 */
1549 int rc = RTDbgModLineAdd(hMod, pszFile, uLineNo, iSeg, offSeg, piOrdinal);
1550 RTDbgModRelease(hMod);
1551 return rc;
1552}
1553
1554
1555/**
1556 * Query a line number by address.
1557 *
1558 * @returns IPRT status code. See RTDbgModSymbolAddrA for more specific ones.
1559 * @retval VERR_INVALID_HANDLE if hDbgAs is invalid.
1560 * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module.
1561 *
1562 * @param hDbgAs The address space handle.
1563 * @param Addr The address which closest symbol is requested.
1564 * @param poffDisp Where to return the distance between the line
1565 * number and address.
1566 * @param pLine Where to return the line number information.
1567 */
1568RTDECL(int) RTDbgAsLineByAddr(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE pLine)
1569{
1570 /*
1571 * Validate input and resolve the address.
1572 */
1573 PRTDBGASINT pDbgAs = hDbgAs;
1574 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1575
1576 RTDBGSEGIDX iSeg;
1577 RTUINTPTR offSeg;
1578 RTUINTPTR MapAddr;
1579 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, &MapAddr);
1580 if (hMod == NIL_RTDBGMOD)
1581 return VERR_NOT_FOUND;
1582
1583 /*
1584 * Forward the call.
1585 */
1586 int rc = RTDbgModLineByAddr(hMod, iSeg, offSeg, poffDisp, pLine);
1587 if (RT_SUCCESS(rc))
1588 rtDbgAsAdjustLineAddress(pLine, hMod, MapAddr, iSeg);
1589 RTDbgModRelease(hMod);
1590 return rc;
1591}
1592
1593
1594/**
1595 * Query a line number by address.
1596 *
1597 * @returns IPRT status code. See RTDbgModSymbolAddrA for more specific ones.
1598 * @retval VERR_INVALID_HANDLE if hDbgAs is invalid.
1599 * @retval VERR_NOT_FOUND if the address couldn't be mapped to a module.
1600 *
1601 * @param hDbgAs The address space handle.
1602 * @param Addr The address which closest symbol is requested.
1603 * @param poffDisp Where to return the distance between the line
1604 * number and address.
1605 * @param ppLine Where to return the pointer to the allocated line
1606 * number info. Always set. Free with RTDbgLineFree.
1607 */
1608RTDECL(int) RTDbgAsLineByAddrA(RTDBGAS hDbgAs, RTUINTPTR Addr, PRTINTPTR poffDisp, PRTDBGLINE *ppLine)
1609{
1610 /*
1611 * Validate input and resolve the address.
1612 */
1613 PRTDBGASINT pDbgAs = hDbgAs;
1614 RTDBGAS_VALID_RETURN_RC(pDbgAs, VERR_INVALID_HANDLE);
1615
1616 RTDBGSEGIDX iSeg;
1617 RTUINTPTR offSeg;
1618 RTUINTPTR MapAddr;
1619 RTDBGMOD hMod = rtDbgAsModuleByAddr(pDbgAs, Addr, &iSeg, &offSeg, &MapAddr);
1620 if (hMod == NIL_RTDBGMOD)
1621 return VERR_NOT_FOUND;
1622
1623 /*
1624 * Forward the call.
1625 */
1626 int rc = RTDbgModLineByAddrA(hMod, iSeg, offSeg, poffDisp, ppLine);
1627 if (RT_SUCCESS(rc))
1628 rtDbgAsAdjustLineAddress(*ppLine, hMod, MapAddr, iSeg);
1629 RTDbgModRelease(hMod);
1630 return rc;
1631}
1632
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