VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/dbg/dbgmod.cpp@ 46072

Last change on this file since 46072 was 46070, checked in by vboxsync, 12 years ago

RTDbgCfg,++: Compressed server files and other fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 65.7 KB
Line 
1/* $Id: dbgmod.cpp 46070 2013-05-14 15:21:57Z vboxsync $ */
2/** @file
3 * IPRT - Debug Module Interpreter.
4 */
5
6/*
7 * Copyright (C) 2009-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#define LOG_GROUP RTLOGGROUP_DBG
32#include <iprt/dbg.h>
33#include "internal/iprt.h"
34
35#include <iprt/asm.h>
36#include <iprt/assert.h>
37#include <iprt/avl.h>
38#include <iprt/err.h>
39#include <iprt/initterm.h>
40#include <iprt/log.h>
41#include <iprt/mem.h>
42#include <iprt/once.h>
43#include <iprt/param.h>
44#include <iprt/path.h>
45#include <iprt/semaphore.h>
46#include <iprt/strcache.h>
47#include <iprt/string.h>
48#include "internal/dbgmod.h"
49#include "internal/magics.h"
50
51
52/*******************************************************************************
53* Structures and Typedefs *
54*******************************************************************************/
55/** Debug info interpreter registration record. */
56typedef struct RTDBGMODREGDBG
57{
58 /** Pointer to the next record. */
59 struct RTDBGMODREGDBG *pNext;
60 /** Pointer to the virtual function table for the interpreter. */
61 PCRTDBGMODVTDBG pVt;
62 /** Usage counter. */
63 uint32_t volatile cUsers;
64} RTDBGMODREGDBG;
65typedef RTDBGMODREGDBG *PRTDBGMODREGDBG;
66
67/** Image interpreter registration record. */
68typedef struct RTDBGMODREGIMG
69{
70 /** Pointer to the next record. */
71 struct RTDBGMODREGIMG *pNext;
72 /** Pointer to the virtual function table for the interpreter. */
73 PCRTDBGMODVTIMG pVt;
74 /** Usage counter. */
75 uint32_t volatile cUsers;
76} RTDBGMODREGIMG;
77typedef RTDBGMODREGIMG *PRTDBGMODREGIMG;
78
79
80/*******************************************************************************
81* Defined Constants And Macros *
82*******************************************************************************/
83/** Validates a debug module handle and returns rc if not valid. */
84#define RTDBGMOD_VALID_RETURN_RC(pDbgMod, rc) \
85 do { \
86 AssertPtrReturn((pDbgMod), (rc)); \
87 AssertReturn((pDbgMod)->u32Magic == RTDBGMOD_MAGIC, (rc)); \
88 AssertReturn((pDbgMod)->cRefs > 0, (rc)); \
89 } while (0)
90
91/** Locks the debug module. */
92#define RTDBGMOD_LOCK(pDbgMod) \
93 do { \
94 int rcLock = RTCritSectEnter(&(pDbgMod)->CritSect); \
95 AssertRC(rcLock); \
96 } while (0)
97
98/** Unlocks the debug module. */
99#define RTDBGMOD_UNLOCK(pDbgMod) \
100 do { \
101 int rcLock = RTCritSectLeave(&(pDbgMod)->CritSect); \
102 AssertRC(rcLock); \
103 } while (0)
104
105
106/*******************************************************************************
107* Global Variables *
108*******************************************************************************/
109/** Init once object for lazy registration of the built-in image and debug
110 * info interpreters. */
111static RTONCE g_rtDbgModOnce = RTONCE_INITIALIZER;
112/** Read/Write semaphore protecting the list of registered interpreters. */
113static RTSEMRW g_hDbgModRWSem = NIL_RTSEMRW;
114/** List of registered image interpreters. */
115static PRTDBGMODREGIMG g_pImgHead;
116/** List of registered debug infor interpreters. */
117static PRTDBGMODREGDBG g_pDbgHead;
118/** String cache for the debug info interpreters.
119 * RTSTRCACHE is thread safe. */
120DECLHIDDEN(RTSTRCACHE) g_hDbgModStrCache = NIL_RTSTRCACHE;
121
122
123
124/**
125 * Cleanup debug info interpreter globals.
126 *
127 * @param enmReason The cause of the termination.
128 * @param iStatus The meaning of this depends on enmReason.
129 * @param pvUser User argument, unused.
130 */
131static DECLCALLBACK(void) rtDbgModTermCallback(RTTERMREASON enmReason, int32_t iStatus, void *pvUser)
132{
133 NOREF(iStatus); NOREF(pvUser);
134 if (enmReason == RTTERMREASON_UNLOAD)
135 {
136 RTSemRWDestroy(g_hDbgModRWSem);
137 g_hDbgModRWSem = NIL_RTSEMRW;
138
139 RTStrCacheDestroy(g_hDbgModStrCache);
140 g_hDbgModStrCache = NIL_RTSTRCACHE;
141
142 PRTDBGMODREGDBG pDbg = g_pDbgHead;
143 g_pDbgHead = NULL;
144 while (pDbg)
145 {
146 PRTDBGMODREGDBG pNext = pDbg->pNext;
147 AssertMsg(pDbg->cUsers == 0, ("%#x %s\n", pDbg->cUsers, pDbg->pVt->pszName));
148 RTMemFree(pDbg);
149 pDbg = pNext;
150 }
151
152 PRTDBGMODREGIMG pImg = g_pImgHead;
153 g_pImgHead = NULL;
154 while (pImg)
155 {
156 PRTDBGMODREGIMG pNext = pImg->pNext;
157 AssertMsg(pImg->cUsers == 0, ("%#x %s\n", pImg->cUsers, pImg->pVt->pszName));
158 RTMemFree(pImg);
159 pImg = pNext;
160 }
161 }
162}
163
164
165/**
166 * Internal worker for register a debug interpreter.
167 *
168 * Called while owning the write lock or when locking isn't required.
169 *
170 * @returns IPRT status code.
171 * @retval VERR_NO_MEMORY
172 * @retval VERR_ALREADY_EXISTS
173 *
174 * @param pVt The virtual function table of the debug
175 * module interpreter.
176 */
177static int rtDbgModDebugInterpreterRegister(PCRTDBGMODVTDBG pVt)
178{
179 /*
180 * Search or duplicate registration.
181 */
182 PRTDBGMODREGDBG pPrev = NULL;
183 for (PRTDBGMODREGDBG pCur = g_pDbgHead; pCur; pCur = pCur->pNext)
184 {
185 if (pCur->pVt == pVt)
186 return VERR_ALREADY_EXISTS;
187 if (!strcmp(pCur->pVt->pszName, pVt->pszName))
188 return VERR_ALREADY_EXISTS;
189 pPrev = pCur;
190 }
191
192 /*
193 * Create a new record and add it to the end of the list.
194 */
195 PRTDBGMODREGDBG pReg = (PRTDBGMODREGDBG)RTMemAlloc(sizeof(*pReg));
196 if (!pReg)
197 return VERR_NO_MEMORY;
198 pReg->pVt = pVt;
199 pReg->cUsers = 0;
200 pReg->pNext = NULL;
201 if (pPrev)
202 pPrev->pNext = pReg;
203 else
204 g_pDbgHead = pReg;
205 return VINF_SUCCESS;
206}
207
208
209/**
210 * Internal worker for register a image interpreter.
211 *
212 * Called while owning the write lock or when locking isn't required.
213 *
214 * @returns IPRT status code.
215 * @retval VERR_NO_MEMORY
216 * @retval VERR_ALREADY_EXISTS
217 *
218 * @param pVt The virtual function table of the image
219 * interpreter.
220 */
221static int rtDbgModImageInterpreterRegister(PCRTDBGMODVTIMG pVt)
222{
223 /*
224 * Search or duplicate registration.
225 */
226 PRTDBGMODREGIMG pPrev = NULL;
227 for (PRTDBGMODREGIMG pCur = g_pImgHead; pCur; pCur = pCur->pNext)
228 {
229 if (pCur->pVt == pVt)
230 return VERR_ALREADY_EXISTS;
231 if (!strcmp(pCur->pVt->pszName, pVt->pszName))
232 return VERR_ALREADY_EXISTS;
233 pPrev = pCur;
234 }
235
236 /*
237 * Create a new record and add it to the end of the list.
238 */
239 PRTDBGMODREGIMG pReg = (PRTDBGMODREGIMG)RTMemAlloc(sizeof(*pReg));
240 if (!pReg)
241 return VERR_NO_MEMORY;
242 pReg->pVt = pVt;
243 pReg->cUsers = 0;
244 pReg->pNext = NULL;
245 if (pPrev)
246 pPrev->pNext = pReg;
247 else
248 g_pImgHead = pReg;
249 return VINF_SUCCESS;
250}
251
252
253/**
254 * Do-once callback that initializes the read/write semaphore and registers
255 * the built-in interpreters.
256 *
257 * @returns IPRT status code.
258 * @param pvUser NULL.
259 */
260static DECLCALLBACK(int) rtDbgModInitOnce(void *pvUser)
261{
262 NOREF(pvUser);
263
264 /*
265 * Create the semaphore and string cache.
266 */
267 int rc = RTSemRWCreate(&g_hDbgModRWSem);
268 AssertRCReturn(rc, rc);
269
270 rc = RTStrCacheCreate(&g_hDbgModStrCache, "RTDBGMOD");
271 if (RT_SUCCESS(rc))
272 {
273 /*
274 * Register the interpreters.
275 */
276 rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgNm);
277 if (RT_SUCCESS(rc))
278 rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgDwarf);
279#ifdef RT_OS_WINDOWS
280 if (RT_SUCCESS(rc))
281 rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgDbgHelp);
282#endif
283 if (RT_SUCCESS(rc))
284 rc = rtDbgModImageInterpreterRegister(&g_rtDbgModVtImgLdr);
285 if (RT_SUCCESS(rc))
286 {
287 /*
288 * Finally, register the IPRT cleanup callback.
289 */
290 rc = RTTermRegisterCallback(rtDbgModTermCallback, NULL);
291 if (RT_SUCCESS(rc))
292 return VINF_SUCCESS;
293
294 /* bail out: use the termination callback. */
295 }
296 }
297 else
298 g_hDbgModStrCache = NIL_RTSTRCACHE;
299 rtDbgModTermCallback(RTTERMREASON_UNLOAD, 0, NULL);
300 return rc;
301}
302
303
304DECLINLINE(int) rtDbgModLazyInit(void)
305{
306 return RTOnce(&g_rtDbgModOnce, rtDbgModInitOnce, NULL);
307}
308
309
310/**
311 * Creates a module based on the default debug info container.
312 *
313 * This can be used to manually load a module and its symbol. The primary user
314 * group is the debug info interpreters, which use this API to create an
315 * efficient debug info container behind the scenes and forward all queries to
316 * it once the info has been loaded.
317 *
318 * @returns IPRT status code.
319 *
320 * @param phDbgMod Where to return the module handle.
321 * @param pszName The name of the module (mandatory).
322 * @param cbSeg The size of initial segment. If zero, segments will
323 * have to be added manually using RTDbgModSegmentAdd.
324 * @param fFlags Flags reserved for future extensions, MBZ for now.
325 */
326RTDECL(int) RTDbgModCreate(PRTDBGMOD phDbgMod, const char *pszName, RTUINTPTR cbSeg, uint32_t fFlags)
327{
328 /*
329 * Input validation and lazy initialization.
330 */
331 AssertPtrReturn(phDbgMod, VERR_INVALID_POINTER);
332 *phDbgMod = NIL_RTDBGMOD;
333 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
334 AssertReturn(*pszName, VERR_INVALID_PARAMETER);
335 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER);
336
337 int rc = rtDbgModLazyInit();
338 if (RT_FAILURE(rc))
339 return rc;
340
341 /*
342 * Allocate a new module instance.
343 */
344 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgMod));
345 if (!pDbgMod)
346 return VERR_NO_MEMORY;
347 pDbgMod->u32Magic = RTDBGMOD_MAGIC;
348 pDbgMod->cRefs = 1;
349 rc = RTCritSectInit(&pDbgMod->CritSect);
350 if (RT_SUCCESS(rc))
351 {
352 pDbgMod->pszName = RTStrCacheEnter(g_hDbgModStrCache, pszName);
353 if (pDbgMod->pszName)
354 {
355 rc = rtDbgModContainerCreate(pDbgMod, cbSeg);
356 if (RT_SUCCESS(rc))
357 {
358 *phDbgMod = pDbgMod;
359 return rc;
360 }
361 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
362 }
363 RTCritSectDelete(&pDbgMod->CritSect);
364 }
365
366 RTMemFree(pDbgMod);
367 return rc;
368}
369RT_EXPORT_SYMBOL(RTDbgModCreate);
370
371
372RTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, RTDBGCFG hDbgCfg)
373{
374 /*
375 * Input validation and lazy initialization.
376 */
377 AssertPtrReturn(phDbgMod, VERR_INVALID_POINTER);
378 *phDbgMod = NIL_RTDBGMOD;
379 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
380 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
381 AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
382
383 int rc = rtDbgModLazyInit();
384 if (RT_FAILURE(rc))
385 return rc;
386
387 if (!pszName)
388 pszName = RTPathFilename(pszFilename);
389
390 /*
391 * Allocate a new module instance.
392 */
393 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgMod));
394 if (!pDbgMod)
395 return VERR_NO_MEMORY;
396 pDbgMod->u32Magic = RTDBGMOD_MAGIC;
397 pDbgMod->cRefs = 1;
398 rc = RTCritSectInit(&pDbgMod->CritSect);
399 if (RT_SUCCESS(rc))
400 {
401 pDbgMod->pszName = RTStrCacheEnter(g_hDbgModStrCache, pszName);
402 if (pDbgMod->pszName)
403 {
404 pDbgMod->pszImgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
405 if (pDbgMod->pszImgFile)
406 {
407 /*
408 * Find an image reader which groks the file.
409 */
410 rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
411 if (RT_SUCCESS(rc))
412 {
413 rc = VERR_DBG_NO_MATCHING_INTERPRETER;
414 PRTDBGMODREGIMG pImg;
415 for (pImg = g_pImgHead; pImg; pImg = pImg->pNext)
416 {
417 pDbgMod->pImgVt = pImg->pVt;
418 pDbgMod->pvImgPriv = NULL;
419 rc = pImg->pVt->pfnTryOpen(pDbgMod);
420 if (RT_SUCCESS(rc))
421 {
422 /*
423 * Find a debug info interpreter.
424 */
425 rc = VERR_DBG_NO_MATCHING_INTERPRETER;
426 for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
427 {
428 pDbgMod->pDbgVt = pDbg->pVt;
429 pDbgMod->pvDbgPriv = NULL;
430 rc = pDbg->pVt->pfnTryOpen(pDbgMod);
431 if (RT_SUCCESS(rc))
432 {
433 /*
434 * That's it!
435 */
436 ASMAtomicIncU32(&pDbg->cUsers);
437 ASMAtomicIncU32(&pImg->cUsers);
438 RTSemRWReleaseRead(g_hDbgModRWSem);
439
440 *phDbgMod = pDbgMod;
441 return rc;
442 }
443 }
444
445 /*
446 * Image detected, but found no debug info we were
447 * able to understand.
448 */
449 /** @todo Fall back on exported symbols! */
450 pDbgMod->pImgVt->pfnClose(pDbgMod);
451 break;
452 }
453 }
454
455 /*
456 * Could it be a file containing raw debug info?
457 */
458 if (!pImg)
459 {
460 pDbgMod->pImgVt = NULL;
461 pDbgMod->pvImgPriv = NULL;
462 pDbgMod->pszDbgFile = pDbgMod->pszImgFile;
463 pDbgMod->pszImgFile = NULL;
464
465 for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
466 {
467 pDbgMod->pDbgVt = pDbg->pVt;
468 pDbgMod->pvDbgPriv = NULL;
469 rc = pDbg->pVt->pfnTryOpen(pDbgMod);
470 if (RT_SUCCESS(rc))
471 {
472 /*
473 * That's it!
474 */
475 ASMAtomicIncU32(&pDbg->cUsers);
476 RTSemRWReleaseRead(g_hDbgModRWSem);
477
478 *phDbgMod = pDbgMod;
479 return rc;
480 }
481 }
482
483 pDbgMod->pszImgFile = pDbgMod->pszDbgFile;
484 pDbgMod->pszDbgFile = NULL;
485 }
486
487 /* bail out */
488 RTSemRWReleaseRead(g_hDbgModRWSem);
489 }
490 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
491 }
492 else
493 rc = VERR_NO_STR_MEMORY;
494 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
495 }
496 else
497 rc = VERR_NO_STR_MEMORY;
498 RTCritSectDelete(&pDbgMod->CritSect);
499 }
500
501 RTMemFree(pDbgMod);
502 return rc;
503}
504RT_EXPORT_SYMBOL(RTDbgModCreateFromImage);
505
506
507
508RTDECL(int) RTDbgModCreateFromMap(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName,
509 RTUINTPTR uSubtrahend, RTDBGCFG hDbgCfg)
510{
511 /*
512 * Input validation and lazy initialization.
513 */
514 AssertPtrReturn(phDbgMod, VERR_INVALID_POINTER);
515 *phDbgMod = NIL_RTDBGMOD;
516 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
517 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
518 AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
519 AssertReturn(uSubtrahend == 0, VERR_NOT_IMPLEMENTED); /** @todo implement uSubtrahend. */
520
521 int rc = rtDbgModLazyInit();
522 if (RT_FAILURE(rc))
523 return rc;
524
525 if (!pszName)
526 pszName = RTPathFilename(pszFilename);
527
528 /*
529 * Allocate a new module instance.
530 */
531 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgMod));
532 if (!pDbgMod)
533 return VERR_NO_MEMORY;
534 pDbgMod->u32Magic = RTDBGMOD_MAGIC;
535 pDbgMod->cRefs = 1;
536 rc = RTCritSectInit(&pDbgMod->CritSect);
537 if (RT_SUCCESS(rc))
538 {
539 pDbgMod->pszName = RTStrCacheEnter(g_hDbgModStrCache, pszName);
540 if (pDbgMod->pszName)
541 {
542 pDbgMod->pszDbgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
543 if (pDbgMod->pszDbgFile)
544 {
545 /*
546 * Try the map file readers.
547 */
548 rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
549 if (RT_SUCCESS(rc))
550 {
551 rc = VERR_DBG_NO_MATCHING_INTERPRETER;
552 for (PRTDBGMODREGDBG pCur = g_pDbgHead; pCur; pCur = pCur->pNext)
553 {
554 if (pCur->pVt->fSupports & RT_DBGTYPE_MAP)
555 {
556 pDbgMod->pDbgVt = pCur->pVt;
557 pDbgMod->pvDbgPriv = NULL;
558 rc = pCur->pVt->pfnTryOpen(pDbgMod);
559 if (RT_SUCCESS(rc))
560 {
561 ASMAtomicIncU32(&pCur->cUsers);
562 RTSemRWReleaseRead(g_hDbgModRWSem);
563
564 *phDbgMod = pDbgMod;
565 return rc;
566 }
567 }
568 }
569
570 /* bail out */
571 RTSemRWReleaseRead(g_hDbgModRWSem);
572 }
573 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
574 }
575 else
576 rc = VERR_NO_STR_MEMORY;
577 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszDbgFile);
578 }
579 else
580 rc = VERR_NO_STR_MEMORY;
581 RTCritSectDelete(&pDbgMod->CritSect);
582 }
583
584 RTMemFree(pDbgMod);
585 return rc;
586}
587RT_EXPORT_SYMBOL(RTDbgModCreateFromMap);
588
589
590
591
592/*
593 *
594 * P E I M A G E
595 * P E I M A G E
596 * P E I M A G E
597 *
598 */
599
600
601/**
602 * Opens debug information for an image.
603 *
604 * @returns IPRT status code
605 * @param pDbgMod The debug module structure.
606 *
607 * @note This will generally not look for debug info stored in external
608 * files. rtDbgModFromPeImageExtDbgInfoCallback can help with that.
609 */
610static int rtDbgModOpenDebugInfoInsideImage(PRTDBGMODINT pDbgMod)
611{
612 AssertReturn(!pDbgMod->pDbgVt, VERR_DBG_MOD_IPE);
613 AssertReturn(pDbgMod->pImgVt, VERR_DBG_MOD_IPE);
614
615 int rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
616 if (RT_SUCCESS(rc))
617 {
618 for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
619 {
620 pDbgMod->pDbgVt = pDbg->pVt;
621 pDbgMod->pvDbgPriv = NULL;
622 rc = pDbg->pVt->pfnTryOpen(pDbgMod);
623 if (RT_SUCCESS(rc))
624 {
625 /*
626 * That's it!
627 */
628 ASMAtomicIncU32(&pDbg->cUsers);
629 RTSemRWReleaseRead(g_hDbgModRWSem);
630 return VINF_SUCCESS;
631 }
632 pDbgMod->pDbgVt = NULL;
633 Assert(pDbgMod->pvDbgPriv == NULL);
634 }
635 RTSemRWReleaseRead(g_hDbgModRWSem);
636 }
637
638 return VERR_DBG_NO_MATCHING_INTERPRETER;
639}
640
641
642/** @callback_method_impl{FNRTDBGCFGOPEN} */
643static DECLCALLBACK(int) rtDbgModExtDbgInfoOpenCallback(RTDBGCFG hDbgCfg, const char *pszFilename, void *pvUser1, void *pvUser2)
644{
645 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)pvUser1;
646 PCRTLDRDBGINFO pDbgInfo = (PCRTLDRDBGINFO)pvUser2;
647 NOREF(pDbgInfo); /** @todo consider a more direct search for a interpreter. */
648
649 Assert(!pDbgMod->pDbgVt);
650 Assert(!pDbgMod->pvDbgPriv);
651 Assert(!pDbgMod->pszDbgFile);
652
653 /*
654 * Set the debug file name and try possible interpreters.
655 */
656 pDbgMod->pszDbgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
657
658 int rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
659 if (RT_SUCCESS(rc))
660 {
661 for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
662 {
663 pDbgMod->pDbgVt = pDbg->pVt;
664 pDbgMod->pvDbgPriv = NULL;
665 rc = pDbg->pVt->pfnTryOpen(pDbgMod);
666 if (RT_SUCCESS(rc))
667 {
668 /*
669 * Got it!
670 */
671 ASMAtomicIncU32(&pDbg->cUsers);
672 RTSemRWReleaseRead(g_hDbgModRWSem);
673 return VINF_CALLBACK_RETURN;
674 }
675 pDbgMod->pDbgVt = NULL;
676 Assert(pDbgMod->pvDbgPriv == NULL);
677 }
678 }
679
680 /* No joy. */
681 RTSemRWReleaseRead(g_hDbgModRWSem);
682 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszDbgFile);
683 pDbgMod->pszDbgFile = NULL;
684 return rc;
685}
686
687
688/**
689 * Argument package used by rtDbgModOpenDebugInfoExternalToImage.
690 */
691typedef struct RTDBGMODOPENDIETI
692{
693 PRTDBGMODINT pDbgMod;
694 RTDBGCFG hDbgCfg;
695} RTDBGMODOPENDIETI;
696
697
698/** @callback_method_impl{FNRTLDRENUMDBG} */
699static DECLCALLBACK(int)
700rtDbgModOpenDebugInfoExternalToImageCallback(RTLDRMOD hLdrMod, PCRTLDRDBGINFO pDbgInfo, void *pvUser)
701{
702 if (!pDbgInfo->pszExtFile)
703 return VINF_SUCCESS;
704
705 int rc;
706 RTDBGMODOPENDIETI *pArgs = (RTDBGMODOPENDIETI *)pvUser;
707 switch (pDbgInfo->enmType)
708 {
709 case RTLDRDBGINFOTYPE_CODEVIEW_PDB70:
710 rc = RTDbgCfgOpenPdb70(pArgs->hDbgCfg, pDbgInfo->pszExtFile,
711 &pDbgInfo->u.Pdb70.Uuid,
712 pDbgInfo->u.Pdb70.uAge,
713 rtDbgModExtDbgInfoOpenCallback, pArgs->pDbgMod, (void *)pDbgInfo);
714 break;
715
716 case RTLDRDBGINFOTYPE_CODEVIEW_PDB20:
717 rc = RTDbgCfgOpenPdb20(pArgs->hDbgCfg, pDbgInfo->pszExtFile,
718 pDbgInfo->u.Pdb20.cbImage,
719 pDbgInfo->u.Pdb20.uTimestamp,
720 pDbgInfo->u.Pdb20.uAge,
721 rtDbgModExtDbgInfoOpenCallback, pArgs->pDbgMod, (void *)pDbgInfo);
722 break;
723
724 case RTLDRDBGINFOTYPE_CODEVIEW_DBG:
725 rc = RTDbgCfgOpenDbg(pArgs->hDbgCfg, pDbgInfo->pszExtFile,
726 pDbgInfo->u.Dbg.cbImage,
727 pDbgInfo->u.Dbg.uTimestamp,
728 rtDbgModExtDbgInfoOpenCallback, pArgs->pDbgMod, (void *)pDbgInfo);
729 break;
730
731 case RTLDRDBGINFOTYPE_DWARF_DWO:
732 rc = RTDbgCfgOpenDwo(pArgs->hDbgCfg, pDbgInfo->pszExtFile,
733 pDbgInfo->u.Dwo.uCrc32,
734 rtDbgModExtDbgInfoOpenCallback, pArgs->pDbgMod, (void *)pDbgInfo);
735 break;
736
737 default:
738 Log(("rtDbgModOpenDebugInfoExternalToImageCallback: Don't know how to handle enmType=%d and pszFileExt=%s\n",
739 pDbgInfo->enmType, pDbgInfo->pszExtFile));
740 return VERR_DBG_TODO;
741 }
742 if (RT_SUCCESS(rc))
743 {
744 LogFlow(("RTDbgMod: Successfully opened external debug info '%s' for '%s'\n",
745 pArgs->pDbgMod->pszDbgFile, pArgs->pDbgMod->pszImgFile));
746 return VINF_CALLBACK_RETURN;
747 }
748 Log(("rtDbgModOpenDebugInfoExternalToImageCallback: '%s' (enmType=%d) for '%s' -> %Rrc\n",
749 pDbgInfo->pszExtFile, pDbgInfo->enmType, pArgs->pDbgMod->pszImgFile, rc));
750 return rc;
751}
752
753
754/**
755 * Opens debug info listed in the image that is stored in a separate file.
756 *
757 * @returns IPRT status code
758 * @param pDbgMod The debug module.
759 * @param hDbgCfg The debug config. Can be NIL.
760 */
761static int rtDbgModOpenDebugInfoExternalToImage(PRTDBGMODINT pDbgMod, RTDBGCFG hDbgCfg)
762{
763 RTDBGMODOPENDIETI Args;
764 Args.pDbgMod = pDbgMod;
765 Args.hDbgCfg = hDbgCfg;
766 int rc = pDbgMod->pImgVt->pfnEnumDbgInfo(pDbgMod, rtDbgModOpenDebugInfoExternalToImageCallback, &Args);
767 if (RT_SUCCESS(rc) && pDbgMod->pDbgVt)
768 return VINF_SUCCESS;
769 return VERR_NOT_FOUND;
770}
771
772
773
774/** @callback_method_impl{FNRTDBGCFGOPEN} */
775static DECLCALLBACK(int) rtDbgModFromPeImageOpenCallback(RTDBGCFG hDbgCfg, const char *pszFilename, void *pvUser1, void *pvUser2)
776{
777 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)pvUser1;
778 PRTDBGMODDEFERRED pDeferred = (PRTDBGMODDEFERRED)pvUser2;
779 LogFlow(("rtDbgModFromPeImageOpenCallback: %s\n", pszFilename));
780
781 Assert(pDbgMod->pImgVt == NULL);
782 Assert(pDbgMod->pvImgPriv == NULL);
783 Assert(pDbgMod->pDbgVt == NULL);
784 Assert(pDbgMod->pvDbgPriv == NULL);
785
786 /*
787 * Replace the image file name while probing it.
788 */
789 const char *pszNewImgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
790 if (!pszNewImgFile)
791 return VERR_NO_STR_MEMORY;
792 const char *pszOldImgFile = pDbgMod->pszImgFile;
793 pDbgMod->pszImgFile = pszNewImgFile;
794
795 /*
796 * Find an image reader which groks the file.
797 */
798 int rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
799 if (RT_SUCCESS(rc))
800 {
801 rc = VERR_DBG_NO_MATCHING_INTERPRETER;
802 PRTDBGMODREGIMG pImg;
803 for (pImg = g_pImgHead; pImg; pImg = pImg->pNext)
804 {
805 pDbgMod->pImgVt = pImg->pVt;
806 pDbgMod->pvImgPriv = NULL;
807 rc = pImg->pVt->pfnTryOpen(pDbgMod);
808 if (RT_SUCCESS(rc))
809 break;
810 pDbgMod->pImgVt = NULL;
811 Assert(pDbgMod->pvImgPriv == NULL);
812 }
813 RTSemRWReleaseRead(g_hDbgModRWSem);
814 if (RT_SUCCESS(rc))
815 {
816 /*
817 * Check the deferred info.
818 */
819 RTUINTPTR cbImage = pDbgMod->pImgVt->pfnImageSize(pDbgMod);
820 if ( pDeferred->cbImage == 0
821 || pDeferred->cbImage == cbImage)
822 {
823 uint32_t uTimestamp = pDeferred->u.PeImage.uTimestamp; /** @todo add method for getting the timestamp. */
824 if ( pDeferred->u.PeImage.uTimestamp == 0
825 || pDeferred->u.PeImage.uTimestamp == uTimestamp)
826 {
827 Log(("RTDbgMod: Found matching PE image '%s'\n", pszFilename));
828
829 /*
830 * We found the executable image we need, now go find any
831 * debug info associated with it. For PE images, this is
832 * generally found in an external file, so we do a sweep
833 * for that first.
834 *
835 * Then try open debug inside the module, and finally
836 * falling back on exports.
837 */
838 rc = rtDbgModOpenDebugInfoExternalToImage(pDbgMod, pDeferred->hDbgCfg);
839 if (RT_FAILURE(rc))
840 rc = rtDbgModOpenDebugInfoInsideImage(pDbgMod);
841 if (RT_FAILURE(rc))
842 rc = rtDbgModCreateForExports(pDbgMod);
843 if (RT_SUCCESS(rc))
844 {
845 RTStrCacheRelease(g_hDbgModStrCache, pszOldImgFile);
846 return VINF_CALLBACK_RETURN;
847 }
848
849 /* Something bad happened, just give up. */
850 Log(("rtDbgModFromPeImageOpenCallback: rtDbgModCreateForExports failed: %Rrc\n", rc));
851 }
852 else
853 {
854 LogFlow(("rtDbgModFromPeImageOpenCallback: uTimestamp mismatch (found %#x, expected %#x) - %s\n",
855 uTimestamp, pDeferred->u.PeImage.uTimestamp, pszFilename));
856 rc = VERR_DBG_FILE_MISMATCH;
857 }
858 }
859 else
860 {
861 LogFlow(("rtDbgModFromPeImageOpenCallback: cbImage mismatch (found %#x, expected %#x) - %s\n",
862 cbImage, pDeferred->cbImage, pszFilename));
863 rc = VERR_DBG_FILE_MISMATCH;
864 }
865
866 pDbgMod->pImgVt->pfnClose(pDbgMod);
867 pDbgMod->pImgVt = NULL;
868 pDbgMod->pvImgPriv = NULL;
869 }
870 else
871 LogFlow(("rtDbgModFromPeImageOpenCallback: Failed %Rrc - %s\n", rc, pszFilename));
872 }
873
874 /* Restore image name. */
875 pDbgMod->pszImgFile = pszOldImgFile;
876 RTStrCacheRelease(g_hDbgModStrCache, pszNewImgFile);
877 return rc;
878}
879
880
881/** @callback_method_impl{FNRTDBGMODDEFERRED} */
882static DECLCALLBACK(int) rtDbgModFromPeImageDeferredCallback(PRTDBGMODINT pDbgMod, PRTDBGMODDEFERRED pDeferred)
883{
884 int rc;
885
886 Assert(pDbgMod->pszImgFile);
887 if (pDeferred->hDbgCfg != NIL_RTDBGCFG)
888 rc = RTDbgCfgOpenPeImage(pDeferred->hDbgCfg, pDbgMod->pszImgFile,
889 pDeferred->cbImage, pDeferred->u.PeImage.uTimestamp,
890 rtDbgModFromPeImageOpenCallback, pDbgMod, pDeferred);
891 else
892 rc = rtDbgModFromPeImageOpenCallback(NIL_RTDBGCFG, pDbgMod->pszImgFile, pDbgMod, pDeferred);
893
894 return rc;
895}
896
897
898RTDECL(int) RTDbgModCreateFromPeImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, uint32_t cbImage,
899 uint32_t uTimestamp, RTDBGCFG hDbgCfg)
900{
901 /*
902 * Input validation and lazy initialization.
903 */
904 AssertPtrReturn(phDbgMod, VERR_INVALID_POINTER);
905 *phDbgMod = NIL_RTDBGMOD;
906 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
907 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
908 if (!pszName)
909 pszName = RTPathFilename(pszFilename);
910 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
911
912 int rc = rtDbgModLazyInit();
913 if (RT_FAILURE(rc))
914 return rc;
915
916 uint64_t fDbgCfg = 0;
917 if (hDbgCfg)
918 {
919 rc = RTDbgCfgQueryUInt(hDbgCfg, RTDBGCFGPROP_FLAGS, &fDbgCfg);
920 AssertRCReturn(rc, rc);
921 }
922
923 /*
924 * Allocate a new module instance.
925 */
926 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgMod));
927 if (!pDbgMod)
928 return VERR_NO_MEMORY;
929 pDbgMod->u32Magic = RTDBGMOD_MAGIC;
930 pDbgMod->cRefs = 1;
931 rc = RTCritSectInit(&pDbgMod->CritSect);
932 if (RT_SUCCESS(rc))
933 {
934 pDbgMod->pszName = RTStrCacheEnter(g_hDbgModStrCache, pszName);
935 if (pDbgMod->pszName)
936 {
937 pDbgMod->pszImgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
938 if (pDbgMod->pszImgFile)
939 {
940 /*
941 * Do it now or procrastinate?
942 */
943 if (!(fDbgCfg & RTDBGCFG_FLAGS_DEFERRED) || !cbImage)
944 {
945 RTDBGMODDEFERRED Deferred;
946 Deferred.cbImage = cbImage;
947 Deferred.hDbgCfg = hDbgCfg;
948 Deferred.u.PeImage.uTimestamp = uTimestamp;
949 rc = rtDbgModFromPeImageDeferredCallback(pDbgMod, &Deferred);
950 }
951 else
952 {
953 PRTDBGMODDEFERRED pDeferred;
954 rc = rtDbgModDeferredCreate(pDbgMod, rtDbgModFromPeImageDeferredCallback, cbImage, hDbgCfg, &pDeferred);
955 if (RT_SUCCESS(rc))
956 pDeferred->u.PeImage.uTimestamp = uTimestamp;
957 }
958 if (RT_SUCCESS(rc))
959 {
960 *phDbgMod = pDbgMod;
961 return VINF_SUCCESS;
962 }
963
964 /* bail out */
965 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
966 }
967 else
968 rc = VERR_NO_STR_MEMORY;
969 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
970 }
971 else
972 rc = VERR_NO_STR_MEMORY;
973 RTCritSectDelete(&pDbgMod->CritSect);
974 }
975
976 RTMemFree(pDbgMod);
977 return rc;
978}
979RT_EXPORT_SYMBOL(RTDbgModCreateFromImage);
980
981
982/**
983 * Destroys an module after the reference count has reached zero.
984 *
985 * @param pDbgMod The module instance.
986 */
987static void rtDbgModDestroy(PRTDBGMODINT pDbgMod)
988{
989 /*
990 * Close the debug info interpreter first, then the image interpret.
991 */
992 RTCritSectEnter(&pDbgMod->CritSect); /* paranoia */
993
994 if (pDbgMod->pDbgVt)
995 {
996 pDbgMod->pDbgVt->pfnClose(pDbgMod);
997 pDbgMod->pDbgVt = NULL;
998 pDbgMod->pvDbgPriv = NULL;
999 }
1000
1001 if (pDbgMod->pImgVt)
1002 {
1003 pDbgMod->pImgVt->pfnClose(pDbgMod);
1004 pDbgMod->pImgVt = NULL;
1005 pDbgMod->pvImgPriv = NULL;
1006 }
1007
1008 /*
1009 * Free the resources.
1010 */
1011 ASMAtomicWriteU32(&pDbgMod->u32Magic, ~RTDBGMOD_MAGIC);
1012 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
1013 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
1014 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszDbgFile);
1015 RTCritSectLeave(&pDbgMod->CritSect); /* paranoia */
1016 RTCritSectDelete(&pDbgMod->CritSect);
1017 RTMemFree(pDbgMod);
1018}
1019
1020
1021/**
1022 * Retains another reference to the module.
1023 *
1024 * @returns New reference count, UINT32_MAX on invalid handle (asserted).
1025 *
1026 * @param hDbgMod The module handle.
1027 *
1028 * @remarks Will not take any locks.
1029 */
1030RTDECL(uint32_t) RTDbgModRetain(RTDBGMOD hDbgMod)
1031{
1032 PRTDBGMODINT pDbgMod = hDbgMod;
1033 RTDBGMOD_VALID_RETURN_RC(pDbgMod, UINT32_MAX);
1034 return ASMAtomicIncU32(&pDbgMod->cRefs);
1035}
1036RT_EXPORT_SYMBOL(RTDbgModRetain);
1037
1038
1039/**
1040 * Release a reference to the module.
1041 *
1042 * When the reference count reaches zero, the module is destroyed.
1043 *
1044 * @returns New reference count, UINT32_MAX on invalid handle (asserted).
1045 *
1046 * @param hDbgMod The module handle. The NIL handle is quietly ignored
1047 * and 0 is returned.
1048 *
1049 * @remarks Will not take any locks.
1050 */
1051RTDECL(uint32_t) RTDbgModRelease(RTDBGMOD hDbgMod)
1052{
1053 if (hDbgMod == NIL_RTDBGMOD)
1054 return 0;
1055 PRTDBGMODINT pDbgMod = hDbgMod;
1056 RTDBGMOD_VALID_RETURN_RC(pDbgMod, UINT32_MAX);
1057
1058 uint32_t cRefs = ASMAtomicDecU32(&pDbgMod->cRefs);
1059 if (!cRefs)
1060 rtDbgModDestroy(pDbgMod);
1061 return cRefs;
1062}
1063RT_EXPORT_SYMBOL(RTDbgModRelease);
1064
1065
1066/**
1067 * Gets the module name.
1068 *
1069 * @returns Pointer to a read only string containing the name.
1070 *
1071 * @param hDbgMod The module handle.
1072 */
1073RTDECL(const char *) RTDbgModName(RTDBGMOD hDbgMod)
1074{
1075 PRTDBGMODINT pDbgMod = hDbgMod;
1076 RTDBGMOD_VALID_RETURN_RC(pDbgMod, NULL);
1077 return pDbgMod->pszName;
1078}
1079RT_EXPORT_SYMBOL(RTDbgModName);
1080
1081
1082/**
1083 * Converts an image relative address to a segment:offset address.
1084 *
1085 * @returns Segment index on success.
1086 * NIL_RTDBGSEGIDX is returned if the module handle or the RVA are
1087 * invalid.
1088 *
1089 * @param hDbgMod The module handle.
1090 * @param uRva The image relative address to convert.
1091 * @param poffSeg Where to return the segment offset. Optional.
1092 */
1093RTDECL(RTDBGSEGIDX) RTDbgModRvaToSegOff(RTDBGMOD hDbgMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
1094{
1095 PRTDBGMODINT pDbgMod = hDbgMod;
1096 RTDBGMOD_VALID_RETURN_RC(pDbgMod, NIL_RTDBGSEGIDX);
1097 RTDBGMOD_LOCK(pDbgMod);
1098
1099 RTDBGSEGIDX iSeg = pDbgMod->pDbgVt->pfnRvaToSegOff(pDbgMod, uRva, poffSeg);
1100
1101 RTDBGMOD_UNLOCK(pDbgMod);
1102 return iSeg;
1103}
1104RT_EXPORT_SYMBOL(RTDbgModRvaToSegOff);
1105
1106
1107/**
1108 * Image size when mapped if segments are mapped adjacently.
1109 *
1110 * For ELF, PE, and Mach-O images this is (usually) a natural query, for LX and
1111 * NE and such it's a bit odder and the answer may not make much sense for them.
1112 *
1113 * @returns Image mapped size.
1114 * RTUINTPTR_MAX is returned if the handle is invalid.
1115 *
1116 * @param hDbgMod The module handle.
1117 */
1118RTDECL(RTUINTPTR) RTDbgModImageSize(RTDBGMOD hDbgMod)
1119{
1120 PRTDBGMODINT pDbgMod = hDbgMod;
1121 RTDBGMOD_VALID_RETURN_RC(pDbgMod, RTUINTPTR_MAX);
1122 RTDBGMOD_LOCK(pDbgMod);
1123
1124 RTUINTPTR cbImage = pDbgMod->pDbgVt->pfnImageSize(pDbgMod);
1125
1126 RTDBGMOD_UNLOCK(pDbgMod);
1127 return cbImage;
1128}
1129RT_EXPORT_SYMBOL(RTDbgModImageSize);
1130
1131
1132/**
1133 * Gets the module tag value if any.
1134 *
1135 * @returns The tag. 0 if hDbgMod is invalid.
1136 *
1137 * @param hDbgMod The module handle.
1138 */
1139RTDECL(uint64_t) RTDbgModGetTag(RTDBGMOD hDbgMod)
1140{
1141 PRTDBGMODINT pDbgMod = hDbgMod;
1142 RTDBGMOD_VALID_RETURN_RC(pDbgMod, 0);
1143 return pDbgMod->uTag;
1144}
1145RT_EXPORT_SYMBOL(RTDbgModGetTag);
1146
1147
1148/**
1149 * Tags or untags the module.
1150 *
1151 * @returns IPRT status code.
1152 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1153 *
1154 * @param hDbgMod The module handle.
1155 * @param uTag The tag value. The convention is that 0 is no tag
1156 * and any other value means it's tagged. It's adviced
1157 * to use some kind of unique number like an address
1158 * (global or string cache for instance) to avoid
1159 * collisions with other users
1160 */
1161RTDECL(int) RTDbgModSetTag(RTDBGMOD hDbgMod, uint64_t uTag)
1162{
1163 PRTDBGMODINT pDbgMod = hDbgMod;
1164 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1165 RTDBGMOD_LOCK(pDbgMod);
1166
1167 pDbgMod->uTag = uTag;
1168
1169 RTDBGMOD_UNLOCK(pDbgMod);
1170 return VINF_SUCCESS;
1171}
1172RT_EXPORT_SYMBOL(RTDbgModSetTag);
1173
1174
1175/**
1176 * Adds a segment to the module. Optional feature.
1177 *
1178 * This method is intended used for manually constructing debug info for a
1179 * module. The main usage is from other debug info interpreters that want to
1180 * avoid writing a debug info database and instead uses the standard container
1181 * behind the scenes.
1182 *
1183 * @returns IPRT status code.
1184 * @retval VERR_NOT_SUPPORTED if this feature isn't support by the debug info
1185 * interpreter. This is a common return code.
1186 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1187 * @retval VERR_DBG_ADDRESS_WRAP if uRva+cb wraps around.
1188 * @retval VERR_DBG_SEGMENT_NAME_OUT_OF_RANGE if pszName is too short or long.
1189 * @retval VERR_INVALID_PARAMETER if fFlags contains undefined flags.
1190 * @retval VERR_DBG_SPECIAL_SEGMENT if *piSeg is a special segment.
1191 * @retval VERR_DBG_INVALID_SEGMENT_INDEX if *piSeg doesn't meet expectations.
1192 *
1193 * @param hDbgMod The module handle.
1194 * @param uRva The image relative address of the segment.
1195 * @param cb The size of the segment.
1196 * @param pszName The segment name. Does not normally need to be
1197 * unique, although this is somewhat up to the
1198 * debug interpreter to decide.
1199 * @param fFlags Segment flags. Reserved for future used, MBZ.
1200 * @param piSeg The segment index or NIL_RTDBGSEGIDX on input.
1201 * The assigned segment index on successful return.
1202 * Optional.
1203 */
1204RTDECL(int) RTDbgModSegmentAdd(RTDBGMOD hDbgMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName,
1205 uint32_t fFlags, PRTDBGSEGIDX piSeg)
1206{
1207 /*
1208 * Validate input.
1209 */
1210 PRTDBGMODINT pDbgMod = hDbgMod;
1211 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1212 AssertMsgReturn(uRva + cb >= uRva, ("uRva=%RTptr cb=%RTptr\n", uRva, cb), VERR_DBG_ADDRESS_WRAP);
1213 Assert(*pszName);
1214 size_t cchName = strlen(pszName);
1215 AssertReturn(cchName > 0, VERR_DBG_SEGMENT_NAME_OUT_OF_RANGE);
1216 AssertReturn(cchName < RTDBG_SEGMENT_NAME_LENGTH, VERR_DBG_SEGMENT_NAME_OUT_OF_RANGE);
1217 AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
1218 AssertPtrNull(piSeg);
1219 AssertMsgReturn(!piSeg || *piSeg == NIL_RTDBGSEGIDX || *piSeg <= RTDBGSEGIDX_LAST, ("%#x\n", *piSeg), VERR_DBG_SPECIAL_SEGMENT);
1220
1221 /*
1222 * Do the deed.
1223 */
1224 RTDBGMOD_LOCK(pDbgMod);
1225 int rc = pDbgMod->pDbgVt->pfnSegmentAdd(pDbgMod, uRva, cb, pszName, cchName, fFlags, piSeg);
1226 RTDBGMOD_UNLOCK(pDbgMod);
1227
1228 return rc;
1229
1230}
1231RT_EXPORT_SYMBOL(RTDbgModSegmentAdd);
1232
1233
1234/**
1235 * Gets the number of segments in the module.
1236 *
1237 * This is can be used to determine the range which can be passed to
1238 * RTDbgModSegmentByIndex and derivatives.
1239 *
1240 * @returns The segment relative address.
1241 * NIL_RTDBGSEGIDX if the handle is invalid.
1242 *
1243 * @param hDbgMod The module handle.
1244 */
1245RTDECL(RTDBGSEGIDX) RTDbgModSegmentCount(RTDBGMOD hDbgMod)
1246{
1247 PRTDBGMODINT pDbgMod = hDbgMod;
1248 RTDBGMOD_VALID_RETURN_RC(pDbgMod, NIL_RTDBGSEGIDX);
1249 RTDBGMOD_LOCK(pDbgMod);
1250
1251 RTDBGSEGIDX cSegs = pDbgMod->pDbgVt->pfnSegmentCount(pDbgMod);
1252
1253 RTDBGMOD_UNLOCK(pDbgMod);
1254 return cSegs;
1255}
1256RT_EXPORT_SYMBOL(RTDbgModSegmentCount);
1257
1258
1259/**
1260 * Query information about a segment.
1261 *
1262 * This can be used together with RTDbgModSegmentCount to enumerate segments.
1263 * The index starts a 0 and stops one below RTDbgModSegmentCount.
1264 *
1265 * @returns IPRT status code.
1266 * @retval VERR_DBG_INVALID_SEGMENT_INDEX if iSeg is too high.
1267 * @retval VERR_DBG_SPECIAL_SEGMENT if iSeg indicates a special segment.
1268 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1269 *
1270 * @param hDbgMod The module handle.
1271 * @param iSeg The segment index. No special segments.
1272 * @param pSegInfo Where to return the segment info. The
1273 * RTDBGSEGMENT::Address member will be set to
1274 * RTUINTPTR_MAX or the load address used at link time.
1275 */
1276RTDECL(int) RTDbgModSegmentByIndex(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
1277{
1278 AssertMsgReturn(iSeg <= RTDBGSEGIDX_LAST, ("%#x\n", iSeg), VERR_DBG_SPECIAL_SEGMENT);
1279 PRTDBGMODINT pDbgMod = hDbgMod;
1280 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1281 RTDBGMOD_LOCK(pDbgMod);
1282
1283 int rc = pDbgMod->pDbgVt->pfnSegmentByIndex(pDbgMod, iSeg, pSegInfo);
1284
1285 RTDBGMOD_UNLOCK(pDbgMod);
1286 return rc;
1287}
1288RT_EXPORT_SYMBOL(RTDbgModSegmentByIndex);
1289
1290
1291/**
1292 * Gets the size of a segment.
1293 *
1294 * This is a just a wrapper around RTDbgModSegmentByIndex.
1295 *
1296 * @returns The segment size.
1297 * RTUINTPTR_MAX is returned if either the handle and segment index are
1298 * invalid.
1299 *
1300 * @param hDbgMod The module handle.
1301 * @param iSeg The segment index. RTDBGSEGIDX_ABS is not allowed.
1302 * If RTDBGSEGIDX_RVA is used, the functions returns
1303 * the same value as RTDbgModImageSize.
1304 */
1305RTDECL(RTUINTPTR) RTDbgModSegmentSize(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg)
1306{
1307 if (iSeg == RTDBGSEGIDX_RVA)
1308 return RTDbgModImageSize(hDbgMod);
1309 RTDBGSEGMENT SegInfo;
1310 int rc = RTDbgModSegmentByIndex(hDbgMod, iSeg, &SegInfo);
1311 return RT_SUCCESS(rc) ? SegInfo.cb : RTUINTPTR_MAX;
1312}
1313RT_EXPORT_SYMBOL(RTDbgModSegmentSize);
1314
1315
1316/**
1317 * Gets the image relative address of a segment.
1318 *
1319 * This is a just a wrapper around RTDbgModSegmentByIndex.
1320 *
1321 * @returns The segment relative address.
1322 * RTUINTPTR_MAX is returned if either the handle and segment index are
1323 * invalid.
1324 *
1325 * @param hDbgMod The module handle.
1326 * @param iSeg The segment index. No special segment indexes
1327 * allowed (asserted).
1328 */
1329RTDECL(RTUINTPTR) RTDbgModSegmentRva(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg)
1330{
1331 RTDBGSEGMENT SegInfo;
1332 int rc = RTDbgModSegmentByIndex(hDbgMod, iSeg, &SegInfo);
1333 return RT_SUCCESS(rc) ? SegInfo.uRva : RTUINTPTR_MAX;
1334}
1335RT_EXPORT_SYMBOL(RTDbgModSegmentRva);
1336
1337
1338/**
1339 * Adds a line number to the module.
1340 *
1341 * @returns IPRT status code.
1342 * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding
1343 * custom symbols. This is a common place occurrence.
1344 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1345 * @retval VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE if the symbol name is too long or
1346 * short.
1347 * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and
1348 * it's not inside any of the segments defined by the module.
1349 * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
1350 * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
1351 * end of the segment.
1352 * @retval VERR_DBG_ADDRESS_WRAP if off+cb wraps around.
1353 * @retval VERR_INVALID_PARAMETER if the symbol flags sets undefined bits.
1354 *
1355 * @param hDbgMod The module handle.
1356 * @param pszSymbol The symbol name.
1357 * @param iSeg The segment index.
1358 * @param off The segment offset.
1359 * @param cb The size of the symbol. Can be zero, although this
1360 * may depend somewhat on the debug interpreter.
1361 * @param fFlags Symbol flags. Reserved for the future, MBZ.
1362 * @param piOrdinal Where to return the symbol ordinal on success. If
1363 * the interpreter doesn't do ordinals, this will be set to
1364 * UINT32_MAX. Optional.
1365 */
1366RTDECL(int) RTDbgModSymbolAdd(RTDBGMOD hDbgMod, const char *pszSymbol, RTDBGSEGIDX iSeg, RTUINTPTR off,
1367 RTUINTPTR cb, uint32_t fFlags, uint32_t *piOrdinal)
1368{
1369 /*
1370 * Validate input.
1371 */
1372 PRTDBGMODINT pDbgMod = hDbgMod;
1373 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1374 AssertPtr(pszSymbol);
1375 size_t cchSymbol = strlen(pszSymbol);
1376 AssertReturn(cchSymbol, VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE);
1377 AssertReturn(cchSymbol < RTDBG_SYMBOL_NAME_LENGTH, VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE);
1378 AssertMsgReturn( iSeg <= RTDBGSEGIDX_LAST
1379 || ( iSeg >= RTDBGSEGIDX_SPECIAL_FIRST
1380 && iSeg <= RTDBGSEGIDX_SPECIAL_LAST),
1381 ("%#x\n", iSeg),
1382 VERR_DBG_INVALID_SEGMENT_INDEX);
1383 AssertMsgReturn(off + cb >= off, ("off=%RTptr cb=%RTptr\n", off, cb), VERR_DBG_ADDRESS_WRAP);
1384 AssertReturn(!fFlags, VERR_INVALID_PARAMETER); /* currently reserved. */
1385
1386 RTDBGMOD_LOCK(pDbgMod);
1387
1388 /*
1389 * Convert RVAs.
1390 */
1391 if (iSeg == RTDBGSEGIDX_RVA)
1392 {
1393 iSeg = pDbgMod->pDbgVt->pfnRvaToSegOff(pDbgMod, off, &off);
1394 if (iSeg == NIL_RTDBGSEGIDX)
1395 {
1396 RTDBGMOD_UNLOCK(pDbgMod);
1397 return VERR_DBG_INVALID_RVA;
1398 }
1399 }
1400
1401 /*
1402 * Get down to business.
1403 */
1404 int rc = pDbgMod->pDbgVt->pfnSymbolAdd(pDbgMod, pszSymbol, cchSymbol, iSeg, off, cb, fFlags, piOrdinal);
1405
1406 RTDBGMOD_UNLOCK(pDbgMod);
1407 return rc;
1408}
1409RT_EXPORT_SYMBOL(RTDbgModSymbolAdd);
1410
1411
1412/**
1413 * Gets the symbol count.
1414 *
1415 * This can be used together wtih RTDbgModSymbolByOrdinal or
1416 * RTDbgModSymbolByOrdinalA to enumerate all the symbols.
1417 *
1418 * @returns The number of symbols in the module.
1419 * UINT32_MAX is returned if the module handle is invalid or some other
1420 * error occurs.
1421 *
1422 * @param hDbgMod The module handle.
1423 */
1424RTDECL(uint32_t) RTDbgModSymbolCount(RTDBGMOD hDbgMod)
1425{
1426 PRTDBGMODINT pDbgMod = hDbgMod;
1427 RTDBGMOD_VALID_RETURN_RC(pDbgMod, UINT32_MAX);
1428 RTDBGMOD_LOCK(pDbgMod);
1429
1430 uint32_t cSymbols = pDbgMod->pDbgVt->pfnSymbolCount(pDbgMod);
1431
1432 RTDBGMOD_UNLOCK(pDbgMod);
1433 return cSymbols;
1434}
1435RT_EXPORT_SYMBOL(RTDbgModSymbolCount);
1436
1437
1438/**
1439 * Queries symbol information by ordinal number.
1440 *
1441 * @returns IPRT status code.
1442 * @retval VERR_SYMBOL_NOT_FOUND if there is no symbol at the given number.
1443 * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols.
1444 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1445 * @retval VERR_NOT_SUPPORTED if lookup by ordinal is not supported.
1446 *
1447 * @param hDbgMod The module handle.
1448 * @param iOrdinal The symbol ordinal number. 0-based. The highest
1449 * number is RTDbgModSymbolCount() - 1.
1450 * @param pSymInfo Where to store the symbol information.
1451 */
1452RTDECL(int) RTDbgModSymbolByOrdinal(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
1453{
1454 PRTDBGMODINT pDbgMod = hDbgMod;
1455 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1456 RTDBGMOD_LOCK(pDbgMod);
1457
1458 int rc = pDbgMod->pDbgVt->pfnSymbolByOrdinal(pDbgMod, iOrdinal, pSymInfo);
1459
1460 RTDBGMOD_UNLOCK(pDbgMod);
1461 return rc;
1462}
1463RT_EXPORT_SYMBOL(RTDbgModSymbolByOrdinal);
1464
1465
1466/**
1467 * Queries symbol information by ordinal number.
1468 *
1469 * @returns IPRT status code.
1470 * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols.
1471 * @retval VERR_NOT_SUPPORTED if lookup by ordinal is not supported.
1472 * @retval VERR_SYMBOL_NOT_FOUND if there is no symbol at the given number.
1473 * @retval VERR_NO_MEMORY if RTDbgSymbolAlloc fails.
1474 *
1475 * @param hDbgMod The module handle.
1476 * @param iOrdinal The symbol ordinal number. 0-based. The highest
1477 * number is RTDbgModSymbolCount() - 1.
1478 * @param ppSymInfo Where to store the pointer to the returned
1479 * symbol information. Always set. Free with
1480 * RTDbgSymbolFree.
1481 */
1482RTDECL(int) RTDbgModSymbolByOrdinalA(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGSYMBOL *ppSymInfo)
1483{
1484 AssertPtr(ppSymInfo);
1485 *ppSymInfo = NULL;
1486
1487 PRTDBGSYMBOL pSymInfo = RTDbgSymbolAlloc();
1488 if (!pSymInfo)
1489 return VERR_NO_MEMORY;
1490
1491 int rc = RTDbgModSymbolByOrdinal(hDbgMod, iOrdinal, pSymInfo);
1492
1493 if (RT_SUCCESS(rc))
1494 *ppSymInfo = pSymInfo;
1495 else
1496 RTDbgSymbolFree(pSymInfo);
1497 return rc;
1498}
1499RT_EXPORT_SYMBOL(RTDbgModSymbolByOrdinalA);
1500
1501
1502/**
1503 * Queries symbol information by address.
1504 *
1505 * The returned symbol is what the debug info interpreter considers the symbol
1506 * most applicable to the specified address. This usually means a symbol with an
1507 * address equal or lower than the requested.
1508 *
1509 * @returns IPRT status code.
1510 * @retval VERR_SYMBOL_NOT_FOUND if no suitable symbol was found.
1511 * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols.
1512 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1513 * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and
1514 * it's not inside any of the segments defined by the module.
1515 * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
1516 * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
1517 * end of the segment.
1518 * @retval VERR_INVALID_PARAMETER if incorrect flags.
1519 *
1520 * @param hDbgMod The module handle.
1521 * @param iSeg The segment number.
1522 * @param off The offset into the segment.
1523 * @param fFlags Symbol search flags, see RTDBGSYMADDR_FLAGS_XXX.
1524 * @param poffDisp Where to store the distance between the
1525 * specified address and the returned symbol.
1526 * Optional.
1527 * @param pSymInfo Where to store the symbol information.
1528 */
1529RTDECL(int) RTDbgModSymbolByAddr(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
1530 PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
1531{
1532 /*
1533 * Validate input.
1534 */
1535 PRTDBGMODINT pDbgMod = hDbgMod;
1536 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1537 AssertPtrNull(poffDisp);
1538 AssertPtr(pSymInfo);
1539 AssertReturn(!(fFlags & ~RTDBGSYMADDR_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
1540
1541 RTDBGMOD_LOCK(pDbgMod);
1542
1543 /*
1544 * Convert RVAs.
1545 */
1546 if (iSeg == RTDBGSEGIDX_RVA)
1547 {
1548 iSeg = pDbgMod->pDbgVt->pfnRvaToSegOff(pDbgMod, off, &off);
1549 if (iSeg == NIL_RTDBGSEGIDX)
1550 {
1551 RTDBGMOD_UNLOCK(pDbgMod);
1552 return VERR_DBG_INVALID_RVA;
1553 }
1554 }
1555
1556 /*
1557 * Get down to business.
1558 */
1559 int rc = pDbgMod->pDbgVt->pfnSymbolByAddr(pDbgMod, iSeg, off, fFlags, poffDisp, pSymInfo);
1560
1561 RTDBGMOD_UNLOCK(pDbgMod);
1562 return rc;
1563}
1564RT_EXPORT_SYMBOL(RTDbgModSymbolByAddr);
1565
1566
1567/**
1568 * Queries symbol information by address.
1569 *
1570 * The returned symbol is what the debug info interpreter considers the symbol
1571 * most applicable to the specified address. This usually means a symbol with an
1572 * address equal or lower than the requested.
1573 *
1574 * @returns IPRT status code.
1575 * @retval VERR_SYMBOL_NOT_FOUND if no suitable symbol was found.
1576 * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols.
1577 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1578 * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and
1579 * it's not inside any of the segments defined by the module.
1580 * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
1581 * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
1582 * end of the segment.
1583 * @retval VERR_NO_MEMORY if RTDbgSymbolAlloc fails.
1584 * @retval VERR_INVALID_PARAMETER if incorrect flags.
1585 *
1586 * @param hDbgMod The module handle.
1587 * @param iSeg The segment index.
1588 * @param off The offset into the segment.
1589 * @param fFlags Symbol search flags, see RTDBGSYMADDR_FLAGS_XXX.
1590 * @param poffDisp Where to store the distance between the
1591 * specified address and the returned symbol. Optional.
1592 * @param ppSymInfo Where to store the pointer to the returned
1593 * symbol information. Always set. Free with
1594 * RTDbgSymbolFree.
1595 */
1596RTDECL(int) RTDbgModSymbolByAddrA(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
1597 PRTINTPTR poffDisp, PRTDBGSYMBOL *ppSymInfo)
1598{
1599 AssertPtr(ppSymInfo);
1600 *ppSymInfo = NULL;
1601
1602 PRTDBGSYMBOL pSymInfo = RTDbgSymbolAlloc();
1603 if (!pSymInfo)
1604 return VERR_NO_MEMORY;
1605
1606 int rc = RTDbgModSymbolByAddr(hDbgMod, iSeg, off, fFlags, poffDisp, pSymInfo);
1607
1608 if (RT_SUCCESS(rc))
1609 *ppSymInfo = pSymInfo;
1610 else
1611 RTDbgSymbolFree(pSymInfo);
1612 return rc;
1613}
1614RT_EXPORT_SYMBOL(RTDbgModSymbolByAddrA);
1615
1616
1617/**
1618 * Queries symbol information by symbol name.
1619 *
1620 * @returns IPRT status code.
1621 * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols.
1622 * @retval VERR_SYMBOL_NOT_FOUND if no suitable symbol was found.
1623 * @retval VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE if the symbol name is too long or
1624 * short.
1625 *
1626 * @param hDbgMod The module handle.
1627 * @param pszSymbol The symbol name.
1628 * @param pSymInfo Where to store the symbol information.
1629 */
1630RTDECL(int) RTDbgModSymbolByName(RTDBGMOD hDbgMod, const char *pszSymbol, PRTDBGSYMBOL pSymInfo)
1631{
1632 /*
1633 * Validate input.
1634 */
1635 PRTDBGMODINT pDbgMod = hDbgMod;
1636 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1637 AssertPtr(pszSymbol);
1638 size_t cchSymbol = strlen(pszSymbol);
1639 AssertReturn(cchSymbol, VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE);
1640 AssertReturn(cchSymbol < RTDBG_SYMBOL_NAME_LENGTH, VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE);
1641 AssertPtr(pSymInfo);
1642
1643 /*
1644 * Make the query.
1645 */
1646 RTDBGMOD_LOCK(pDbgMod);
1647 int rc = pDbgMod->pDbgVt->pfnSymbolByName(pDbgMod, pszSymbol, cchSymbol, pSymInfo);
1648 RTDBGMOD_UNLOCK(pDbgMod);
1649
1650 return rc;
1651}
1652RT_EXPORT_SYMBOL(RTDbgModSymbolByName);
1653
1654
1655/**
1656 * Queries symbol information by symbol name.
1657 *
1658 * @returns IPRT status code.
1659 * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols.
1660 * @retval VERR_SYMBOL_NOT_FOUND if no suitable symbol was found.
1661 * @retval VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE if the symbol name is too long or
1662 * short.
1663 * @retval VERR_NO_MEMORY if RTDbgSymbolAlloc fails.
1664 *
1665 * @param hDbgMod The module handle.
1666 * @param pszSymbol The symbol name.
1667 * @param ppSymInfo Where to store the pointer to the returned
1668 * symbol information. Always set. Free with
1669 * RTDbgSymbolFree.
1670 */
1671RTDECL(int) RTDbgModSymbolByNameA(RTDBGMOD hDbgMod, const char *pszSymbol, PRTDBGSYMBOL *ppSymInfo)
1672{
1673 AssertPtr(ppSymInfo);
1674 *ppSymInfo = NULL;
1675
1676 PRTDBGSYMBOL pSymInfo = RTDbgSymbolAlloc();
1677 if (!pSymInfo)
1678 return VERR_NO_MEMORY;
1679
1680 int rc = RTDbgModSymbolByName(hDbgMod, pszSymbol, pSymInfo);
1681
1682 if (RT_SUCCESS(rc))
1683 *ppSymInfo = pSymInfo;
1684 else
1685 RTDbgSymbolFree(pSymInfo);
1686 return rc;
1687}
1688RT_EXPORT_SYMBOL(RTDbgModSymbolByNameA);
1689
1690
1691/**
1692 * Adds a line number to the module.
1693 *
1694 * @returns IPRT status code.
1695 * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding
1696 * custom symbols. This should be consider a normal response.
1697 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1698 * @retval VERR_DBG_FILE_NAME_OUT_OF_RANGE if the file name is too longer or
1699 * empty.
1700 * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and
1701 * it's not inside any of the segments defined by the module.
1702 * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
1703 * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
1704 * end of the segment.
1705 * @retval VERR_INVALID_PARAMETER if the line number flags sets undefined bits.
1706 *
1707 * @param hDbgMod The module handle.
1708 * @param pszFile The file name.
1709 * @param uLineNo The line number.
1710 * @param iSeg The segment index.
1711 * @param off The segment offset.
1712 * @param piOrdinal Where to return the line number ordinal on
1713 * success. If the interpreter doesn't do ordinals,
1714 * this will be set to UINT32_MAX. Optional.
1715 */
1716RTDECL(int) RTDbgModLineAdd(RTDBGMOD hDbgMod, const char *pszFile, uint32_t uLineNo,
1717 RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t *piOrdinal)
1718{
1719 /*
1720 * Validate input.
1721 */
1722 PRTDBGMODINT pDbgMod = hDbgMod;
1723 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1724 AssertPtr(pszFile);
1725 size_t cchFile = strlen(pszFile);
1726 AssertReturn(cchFile, VERR_DBG_FILE_NAME_OUT_OF_RANGE);
1727 AssertReturn(cchFile < RTDBG_FILE_NAME_LENGTH, VERR_DBG_FILE_NAME_OUT_OF_RANGE);
1728 AssertMsgReturn( iSeg <= RTDBGSEGIDX_LAST
1729 || iSeg == RTDBGSEGIDX_RVA,
1730 ("%#x\n", iSeg),
1731 VERR_DBG_INVALID_SEGMENT_INDEX);
1732 AssertReturn(uLineNo > 0 && uLineNo < UINT32_MAX, VERR_INVALID_PARAMETER);
1733
1734 RTDBGMOD_LOCK(pDbgMod);
1735
1736 /*
1737 * Convert RVAs.
1738 */
1739 if (iSeg == RTDBGSEGIDX_RVA)
1740 {
1741 iSeg = pDbgMod->pDbgVt->pfnRvaToSegOff(pDbgMod, off, &off);
1742 if (iSeg == NIL_RTDBGSEGIDX)
1743 {
1744 RTDBGMOD_UNLOCK(pDbgMod);
1745 return VERR_DBG_INVALID_RVA;
1746 }
1747 }
1748
1749 /*
1750 * Get down to business.
1751 */
1752 int rc = pDbgMod->pDbgVt->pfnLineAdd(pDbgMod, pszFile, cchFile, uLineNo, iSeg, off, piOrdinal);
1753
1754 RTDBGMOD_UNLOCK(pDbgMod);
1755 return rc;
1756}
1757RT_EXPORT_SYMBOL(RTDbgModLineAdd);
1758
1759
1760/**
1761 * Gets the line number count.
1762 *
1763 * This can be used together wtih RTDbgModLineByOrdinal or RTDbgModSymbolByLineA
1764 * to enumerate all the line number information.
1765 *
1766 * @returns The number of line numbers in the module.
1767 * UINT32_MAX is returned if the module handle is invalid or some other
1768 * error occurs.
1769 *
1770 * @param hDbgMod The module handle.
1771 */
1772RTDECL(uint32_t) RTDbgModLineCount(RTDBGMOD hDbgMod)
1773{
1774 PRTDBGMODINT pDbgMod = hDbgMod;
1775 RTDBGMOD_VALID_RETURN_RC(pDbgMod, UINT32_MAX);
1776 RTDBGMOD_LOCK(pDbgMod);
1777
1778 uint32_t cLineNumbers = pDbgMod->pDbgVt->pfnLineCount(pDbgMod);
1779
1780 RTDBGMOD_UNLOCK(pDbgMod);
1781 return cLineNumbers;
1782}
1783RT_EXPORT_SYMBOL(RTDbgModLineCount);
1784
1785
1786/**
1787 * Queries line number information by ordinal number.
1788 *
1789 * This can be used to enumerate the line numbers for the module. Use
1790 * RTDbgModLineCount() to figure the end of the ordinals.
1791 *
1792 * @returns IPRT status code.
1793 * @retval VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers.
1794 * @retval VERR_DBG_LINE_NOT_FOUND if there is no line number with that
1795 * ordinal.
1796 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1797
1798 * @param hDbgMod The module handle.
1799 * @param iOrdinal The line number ordinal number.
1800 * @param pLineInfo Where to store the information about the line
1801 * number.
1802 */
1803RTDECL(int) RTDbgModLineByOrdinal(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
1804{
1805 PRTDBGMODINT pDbgMod = hDbgMod;
1806 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1807 RTDBGMOD_LOCK(pDbgMod);
1808
1809 int rc = pDbgMod->pDbgVt->pfnLineByOrdinal(pDbgMod, iOrdinal, pLineInfo);
1810
1811 RTDBGMOD_UNLOCK(pDbgMod);
1812 return rc;
1813}
1814RT_EXPORT_SYMBOL(RTDbgModLineByOrdinal);
1815
1816
1817/**
1818 * Queries line number information by ordinal number.
1819 *
1820 * This can be used to enumerate the line numbers for the module. Use
1821 * RTDbgModLineCount() to figure the end of the ordinals.
1822 *
1823 * @returns IPRT status code.
1824 * @retval VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers.
1825 * @retval VERR_DBG_LINE_NOT_FOUND if there is no line number with that
1826 * ordinal.
1827 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1828 * @retval VERR_NO_MEMORY if RTDbgLineAlloc fails.
1829 *
1830 * @param hDbgMod The module handle.
1831 * @param iOrdinal The line number ordinal number.
1832 * @param ppLineInfo Where to store the pointer to the returned line
1833 * number information. Always set. Free with
1834 * RTDbgLineFree.
1835 */
1836RTDECL(int) RTDbgModLineByOrdinalA(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGLINE *ppLineInfo)
1837{
1838 AssertPtr(ppLineInfo);
1839 *ppLineInfo = NULL;
1840
1841 PRTDBGLINE pLineInfo = RTDbgLineAlloc();
1842 if (!pLineInfo)
1843 return VERR_NO_MEMORY;
1844
1845 int rc = RTDbgModLineByOrdinal(hDbgMod, iOrdinal, pLineInfo);
1846
1847 if (RT_SUCCESS(rc))
1848 *ppLineInfo = pLineInfo;
1849 else
1850 RTDbgLineFree(pLineInfo);
1851 return rc;
1852}
1853RT_EXPORT_SYMBOL(RTDbgModLineByOrdinalA);
1854
1855
1856/**
1857 * Queries line number information by address.
1858 *
1859 * The returned line number is what the debug info interpreter considers the
1860 * one most applicable to the specified address. This usually means a line
1861 * number with an address equal or lower than the requested.
1862 *
1863 * @returns IPRT status code.
1864 * @retval VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers.
1865 * @retval VERR_DBG_LINE_NOT_FOUND if no suitable line number was found.
1866 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1867 * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and
1868 * it's not inside any of the segments defined by the module.
1869 * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
1870 * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
1871 * end of the segment.
1872 *
1873 * @param hDbgMod The module handle.
1874 * @param iSeg The segment number.
1875 * @param off The offset into the segment.
1876 * @param poffDisp Where to store the distance between the
1877 * specified address and the returned symbol.
1878 * Optional.
1879 * @param pLineInfo Where to store the line number information.
1880 */
1881RTDECL(int) RTDbgModLineByAddr(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
1882{
1883 /*
1884 * Validate input.
1885 */
1886 PRTDBGMODINT pDbgMod = hDbgMod;
1887 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1888 AssertPtrNull(poffDisp);
1889 AssertPtr(pLineInfo);
1890
1891 RTDBGMOD_LOCK(pDbgMod);
1892
1893 /*
1894 * Convert RVAs.
1895 */
1896 if (iSeg == RTDBGSEGIDX_RVA)
1897 {
1898 iSeg = pDbgMod->pDbgVt->pfnRvaToSegOff(pDbgMod, off, &off);
1899 if (iSeg == NIL_RTDBGSEGIDX)
1900 {
1901 RTDBGMOD_UNLOCK(pDbgMod);
1902 return VERR_DBG_INVALID_RVA;
1903 }
1904 }
1905
1906 int rc = pDbgMod->pDbgVt->pfnLineByAddr(pDbgMod, iSeg, off, poffDisp, pLineInfo);
1907
1908 RTDBGMOD_UNLOCK(pDbgMod);
1909 return rc;
1910}
1911RT_EXPORT_SYMBOL(RTDbgModLineByAddr);
1912
1913
1914/**
1915 * Queries line number information by address.
1916 *
1917 * The returned line number is what the debug info interpreter considers the
1918 * one most applicable to the specified address. This usually means a line
1919 * number with an address equal or lower than the requested.
1920 *
1921 * @returns IPRT status code.
1922 * @retval VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers.
1923 * @retval VERR_DBG_LINE_NOT_FOUND if no suitable line number was found.
1924 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1925 * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and
1926 * it's not inside any of the segments defined by the module.
1927 * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
1928 * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
1929 * end of the segment.
1930 * @retval VERR_NO_MEMORY if RTDbgLineAlloc fails.
1931 *
1932 * @param hDbgMod The module handle.
1933 * @param iSeg The segment number.
1934 * @param off The offset into the segment.
1935 * @param poffDisp Where to store the distance between the
1936 * specified address and the returned symbol.
1937 * Optional.
1938 * @param ppLineInfo Where to store the pointer to the returned line
1939 * number information. Always set. Free with
1940 * RTDbgLineFree.
1941 */
1942RTDECL(int) RTDbgModLineByAddrA(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTINTPTR poffDisp, PRTDBGLINE *ppLineInfo)
1943{
1944 AssertPtr(ppLineInfo);
1945 *ppLineInfo = NULL;
1946
1947 PRTDBGLINE pLineInfo = RTDbgLineAlloc();
1948 if (!pLineInfo)
1949 return VERR_NO_MEMORY;
1950
1951 int rc = RTDbgModLineByAddr(hDbgMod, iSeg, off, poffDisp, pLineInfo);
1952
1953 if (RT_SUCCESS(rc))
1954 *ppLineInfo = pLineInfo;
1955 else
1956 RTDbgLineFree(pLineInfo);
1957 return rc;
1958}
1959RT_EXPORT_SYMBOL(RTDbgModLineByAddrA);
1960
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