VirtualBox

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

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

Added a RTDbgMod reader that employs DbgHelp.dll.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 65.0 KB
Line 
1/* $Id: dbgmod.cpp 46048 2013-05-14 07:44:30Z 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 * Find an image reader which groks the file.
788 */
789 int rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
790 if (RT_SUCCESS(rc))
791 {
792 rc = VERR_DBG_NO_MATCHING_INTERPRETER;
793 PRTDBGMODREGIMG pImg;
794 for (pImg = g_pImgHead; pImg; pImg = pImg->pNext)
795 {
796 pDbgMod->pImgVt = pImg->pVt;
797 pDbgMod->pvImgPriv = NULL;
798 rc = pImg->pVt->pfnTryOpen(pDbgMod);
799 if (RT_SUCCESS(rc))
800 break;
801 pDbgMod->pImgVt = NULL;
802 Assert(pDbgMod->pvImgPriv == NULL);
803 }
804 }
805 RTSemRWReleaseRead(g_hDbgModRWSem);
806 if (RT_FAILURE(rc))
807 {
808 LogFlow(("rtDbgModFromPeImageOpenCallback: Failed %Rrc - %s\n", rc, pszFilename));
809 return rc;
810 }
811
812 /*
813 * Check the deferred info.
814 */
815 RTUINTPTR cbImage = pDbgMod->pImgVt->pfnImageSize(pDbgMod);
816 if ( pDeferred->cbImage == 0
817 || pDeferred->cbImage == cbImage)
818 {
819 uint32_t uTimestamp = pDeferred->u.PeImage.uTimestamp; /** @todo add method for getting the timestamp. */
820 if ( pDeferred->u.PeImage.uTimestamp == 0
821 || pDeferred->u.PeImage.uTimestamp == uTimestamp)
822 {
823 Log(("RTDbgMod: Found matching PE image '%s'\n", pszFilename));
824
825 /*
826 * We found the executable image we need, now go find any debug
827 * info associated with it. For PE images, this is generally
828 * found in an external file, so we do a sweep for that first.
829 */
830 rc = rtDbgModOpenDebugInfoExternalToImage(pDbgMod, pDeferred->hDbgCfg);
831 if (RT_SUCCESS(rc))
832 return VINF_CALLBACK_RETURN;
833
834 /*
835 * Try open debug info inside the module, falling back on exports.
836 */
837 rc = rtDbgModOpenDebugInfoInsideImage(pDbgMod);
838 if (RT_SUCCESS(rc))
839 return VINF_CALLBACK_RETURN;
840 /** @todo search for external files that could contain more useful info, like
841 * .map files?? No? */
842 rc = rtDbgModCreateForExports(pDbgMod);
843 if (RT_SUCCESS(rc))
844 return VINF_CALLBACK_RETURN;
845
846 /* Something bad happened, just give up. */
847 Log(("rtDbgModFromPeImageOpenCallback: rtDbgModCreateForExports failed: %Rrc\n", rc));
848 }
849 else
850 {
851 LogFlow(("rtDbgModFromPeImageOpenCallback: uTimestamp mismatch (found %#x, expected %#x) - %s\n",
852 uTimestamp, pDeferred->u.PeImage.uTimestamp, pszFilename));
853 rc = VERR_DBG_FILE_MISMATCH;
854 }
855 }
856 else
857 {
858 LogFlow(("rtDbgModFromPeImageOpenCallback: cbImage mismatch (found %#x, expected %#x) - %s\n",
859 cbImage, pDeferred->cbImage, pszFilename));
860 rc = VERR_DBG_FILE_MISMATCH;
861 }
862
863 pDbgMod->pImgVt->pfnClose(pDbgMod);
864 pDbgMod->pImgVt = NULL;
865 pDbgMod->pvImgPriv = NULL;
866
867 return rc;
868}
869
870
871/** @callback_method_impl{FNRTDBGMODDEFERRED} */
872static DECLCALLBACK(int) rtDbgModFromPeImageDeferredCallback(PRTDBGMODINT pDbgMod, PRTDBGMODDEFERRED pDeferred)
873{
874 int rc;
875
876 Assert(pDbgMod->pszImgFile);
877 if (pDeferred->hDbgCfg != NIL_RTDBGCFG)
878 rc = RTDbgCfgOpenPeImage(pDeferred->hDbgCfg, pDbgMod->pszImgFile,
879 pDeferred->cbImage, pDeferred->u.PeImage.uTimestamp,
880 rtDbgModFromPeImageOpenCallback, pDbgMod, pDeferred);
881 else
882 rc = rtDbgModFromPeImageOpenCallback(NIL_RTDBGCFG, pDbgMod->pszImgFile, pDbgMod, pDeferred);
883
884 return rc;
885}
886
887
888RTDECL(int) RTDbgModCreateFromPeImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, uint32_t cbImage,
889 uint32_t uTimestamp, RTDBGCFG hDbgCfg)
890{
891 /*
892 * Input validation and lazy initialization.
893 */
894 AssertPtrReturn(phDbgMod, VERR_INVALID_POINTER);
895 *phDbgMod = NIL_RTDBGMOD;
896 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
897 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
898 if (!pszName)
899 pszName = RTPathFilename(pszFilename);
900 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
901
902 int rc = rtDbgModLazyInit();
903 if (RT_FAILURE(rc))
904 return rc;
905
906 uint64_t fDbgCfg = 0;
907 if (hDbgCfg)
908 {
909 rc = RTDbgCfgQueryUInt(hDbgCfg, RTDBGCFGPROP_FLAGS, &fDbgCfg);
910 AssertRCReturn(rc, rc);
911 }
912
913 /*
914 * Allocate a new module instance.
915 */
916 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgMod));
917 if (!pDbgMod)
918 return VERR_NO_MEMORY;
919 pDbgMod->u32Magic = RTDBGMOD_MAGIC;
920 pDbgMod->cRefs = 1;
921 rc = RTCritSectInit(&pDbgMod->CritSect);
922 if (RT_SUCCESS(rc))
923 {
924 pDbgMod->pszName = RTStrCacheEnter(g_hDbgModStrCache, pszName);
925 if (pDbgMod->pszName)
926 {
927 pDbgMod->pszImgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
928 if (pDbgMod->pszImgFile)
929 {
930 /*
931 * Do it now or procrastinate?
932 */
933 if (!(fDbgCfg & RTDBGCFG_FLAGS_DEFERRED) || !cbImage)
934 {
935 RTDBGMODDEFERRED Deferred;
936 Deferred.cbImage = cbImage;
937 Deferred.hDbgCfg = hDbgCfg;
938 Deferred.u.PeImage.uTimestamp = uTimestamp;
939 rc = rtDbgModFromPeImageDeferredCallback(pDbgMod, &Deferred);
940 }
941 else
942 {
943 PRTDBGMODDEFERRED pDeferred;
944 rc = rtDbgModDeferredCreate(pDbgMod, rtDbgModFromPeImageDeferredCallback, cbImage, hDbgCfg, &pDeferred);
945 if (RT_SUCCESS(rc))
946 pDeferred->u.PeImage.uTimestamp = uTimestamp;
947 }
948 if (RT_SUCCESS(rc))
949 {
950 *phDbgMod = pDbgMod;
951 return VINF_SUCCESS;
952 }
953
954 /* bail out */
955 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
956 }
957 else
958 rc = VERR_NO_STR_MEMORY;
959 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
960 }
961 else
962 rc = VERR_NO_STR_MEMORY;
963 RTCritSectDelete(&pDbgMod->CritSect);
964 }
965
966 RTMemFree(pDbgMod);
967 return rc;
968}
969RT_EXPORT_SYMBOL(RTDbgModCreateFromImage);
970
971
972/**
973 * Destroys an module after the reference count has reached zero.
974 *
975 * @param pDbgMod The module instance.
976 */
977static void rtDbgModDestroy(PRTDBGMODINT pDbgMod)
978{
979 /*
980 * Close the debug info interpreter first, then the image interpret.
981 */
982 RTCritSectEnter(&pDbgMod->CritSect); /* paranoia */
983
984 if (pDbgMod->pDbgVt)
985 {
986 pDbgMod->pDbgVt->pfnClose(pDbgMod);
987 pDbgMod->pDbgVt = NULL;
988 pDbgMod->pvDbgPriv = NULL;
989 }
990
991 if (pDbgMod->pImgVt)
992 {
993 pDbgMod->pImgVt->pfnClose(pDbgMod);
994 pDbgMod->pImgVt = NULL;
995 pDbgMod->pvImgPriv = NULL;
996 }
997
998 /*
999 * Free the resources.
1000 */
1001 ASMAtomicWriteU32(&pDbgMod->u32Magic, ~RTDBGMOD_MAGIC);
1002 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
1003 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
1004 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszDbgFile);
1005 RTCritSectLeave(&pDbgMod->CritSect); /* paranoia */
1006 RTCritSectDelete(&pDbgMod->CritSect);
1007 RTMemFree(pDbgMod);
1008}
1009
1010
1011/**
1012 * Retains another reference to the module.
1013 *
1014 * @returns New reference count, UINT32_MAX on invalid handle (asserted).
1015 *
1016 * @param hDbgMod The module handle.
1017 *
1018 * @remarks Will not take any locks.
1019 */
1020RTDECL(uint32_t) RTDbgModRetain(RTDBGMOD hDbgMod)
1021{
1022 PRTDBGMODINT pDbgMod = hDbgMod;
1023 RTDBGMOD_VALID_RETURN_RC(pDbgMod, UINT32_MAX);
1024 return ASMAtomicIncU32(&pDbgMod->cRefs);
1025}
1026RT_EXPORT_SYMBOL(RTDbgModRetain);
1027
1028
1029/**
1030 * Release a reference to the module.
1031 *
1032 * When the reference count reaches zero, the module is destroyed.
1033 *
1034 * @returns New reference count, UINT32_MAX on invalid handle (asserted).
1035 *
1036 * @param hDbgMod The module handle. The NIL handle is quietly ignored
1037 * and 0 is returned.
1038 *
1039 * @remarks Will not take any locks.
1040 */
1041RTDECL(uint32_t) RTDbgModRelease(RTDBGMOD hDbgMod)
1042{
1043 if (hDbgMod == NIL_RTDBGMOD)
1044 return 0;
1045 PRTDBGMODINT pDbgMod = hDbgMod;
1046 RTDBGMOD_VALID_RETURN_RC(pDbgMod, UINT32_MAX);
1047
1048 uint32_t cRefs = ASMAtomicDecU32(&pDbgMod->cRefs);
1049 if (!cRefs)
1050 rtDbgModDestroy(pDbgMod);
1051 return cRefs;
1052}
1053RT_EXPORT_SYMBOL(RTDbgModRelease);
1054
1055
1056/**
1057 * Gets the module name.
1058 *
1059 * @returns Pointer to a read only string containing the name.
1060 *
1061 * @param hDbgMod The module handle.
1062 */
1063RTDECL(const char *) RTDbgModName(RTDBGMOD hDbgMod)
1064{
1065 PRTDBGMODINT pDbgMod = hDbgMod;
1066 RTDBGMOD_VALID_RETURN_RC(pDbgMod, NULL);
1067 return pDbgMod->pszName;
1068}
1069RT_EXPORT_SYMBOL(RTDbgModName);
1070
1071
1072/**
1073 * Converts an image relative address to a segment:offset address.
1074 *
1075 * @returns Segment index on success.
1076 * NIL_RTDBGSEGIDX is returned if the module handle or the RVA are
1077 * invalid.
1078 *
1079 * @param hDbgMod The module handle.
1080 * @param uRva The image relative address to convert.
1081 * @param poffSeg Where to return the segment offset. Optional.
1082 */
1083RTDECL(RTDBGSEGIDX) RTDbgModRvaToSegOff(RTDBGMOD hDbgMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
1084{
1085 PRTDBGMODINT pDbgMod = hDbgMod;
1086 RTDBGMOD_VALID_RETURN_RC(pDbgMod, NIL_RTDBGSEGIDX);
1087 RTDBGMOD_LOCK(pDbgMod);
1088
1089 RTDBGSEGIDX iSeg = pDbgMod->pDbgVt->pfnRvaToSegOff(pDbgMod, uRva, poffSeg);
1090
1091 RTDBGMOD_UNLOCK(pDbgMod);
1092 return iSeg;
1093}
1094RT_EXPORT_SYMBOL(RTDbgModRvaToSegOff);
1095
1096
1097/**
1098 * Image size when mapped if segments are mapped adjacently.
1099 *
1100 * For ELF, PE, and Mach-O images this is (usually) a natural query, for LX and
1101 * NE and such it's a bit odder and the answer may not make much sense for them.
1102 *
1103 * @returns Image mapped size.
1104 * RTUINTPTR_MAX is returned if the handle is invalid.
1105 *
1106 * @param hDbgMod The module handle.
1107 */
1108RTDECL(RTUINTPTR) RTDbgModImageSize(RTDBGMOD hDbgMod)
1109{
1110 PRTDBGMODINT pDbgMod = hDbgMod;
1111 RTDBGMOD_VALID_RETURN_RC(pDbgMod, RTUINTPTR_MAX);
1112 RTDBGMOD_LOCK(pDbgMod);
1113
1114 RTUINTPTR cbImage = pDbgMod->pDbgVt->pfnImageSize(pDbgMod);
1115
1116 RTDBGMOD_UNLOCK(pDbgMod);
1117 return cbImage;
1118}
1119RT_EXPORT_SYMBOL(RTDbgModImageSize);
1120
1121
1122/**
1123 * Gets the module tag value if any.
1124 *
1125 * @returns The tag. 0 if hDbgMod is invalid.
1126 *
1127 * @param hDbgMod The module handle.
1128 */
1129RTDECL(uint64_t) RTDbgModGetTag(RTDBGMOD hDbgMod)
1130{
1131 PRTDBGMODINT pDbgMod = hDbgMod;
1132 RTDBGMOD_VALID_RETURN_RC(pDbgMod, 0);
1133 return pDbgMod->uTag;
1134}
1135RT_EXPORT_SYMBOL(RTDbgModGetTag);
1136
1137
1138/**
1139 * Tags or untags the module.
1140 *
1141 * @returns IPRT status code.
1142 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1143 *
1144 * @param hDbgMod The module handle.
1145 * @param uTag The tag value. The convention is that 0 is no tag
1146 * and any other value means it's tagged. It's adviced
1147 * to use some kind of unique number like an address
1148 * (global or string cache for instance) to avoid
1149 * collisions with other users
1150 */
1151RTDECL(int) RTDbgModSetTag(RTDBGMOD hDbgMod, uint64_t uTag)
1152{
1153 PRTDBGMODINT pDbgMod = hDbgMod;
1154 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1155 RTDBGMOD_LOCK(pDbgMod);
1156
1157 pDbgMod->uTag = uTag;
1158
1159 RTDBGMOD_UNLOCK(pDbgMod);
1160 return VINF_SUCCESS;
1161}
1162RT_EXPORT_SYMBOL(RTDbgModSetTag);
1163
1164
1165/**
1166 * Adds a segment to the module. Optional feature.
1167 *
1168 * This method is intended used for manually constructing debug info for a
1169 * module. The main usage is from other debug info interpreters that want to
1170 * avoid writing a debug info database and instead uses the standard container
1171 * behind the scenes.
1172 *
1173 * @returns IPRT status code.
1174 * @retval VERR_NOT_SUPPORTED if this feature isn't support by the debug info
1175 * interpreter. This is a common return code.
1176 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1177 * @retval VERR_DBG_ADDRESS_WRAP if uRva+cb wraps around.
1178 * @retval VERR_DBG_SEGMENT_NAME_OUT_OF_RANGE if pszName is too short or long.
1179 * @retval VERR_INVALID_PARAMETER if fFlags contains undefined flags.
1180 * @retval VERR_DBG_SPECIAL_SEGMENT if *piSeg is a special segment.
1181 * @retval VERR_DBG_INVALID_SEGMENT_INDEX if *piSeg doesn't meet expectations.
1182 *
1183 * @param hDbgMod The module handle.
1184 * @param uRva The image relative address of the segment.
1185 * @param cb The size of the segment.
1186 * @param pszName The segment name. Does not normally need to be
1187 * unique, although this is somewhat up to the
1188 * debug interpreter to decide.
1189 * @param fFlags Segment flags. Reserved for future used, MBZ.
1190 * @param piSeg The segment index or NIL_RTDBGSEGIDX on input.
1191 * The assigned segment index on successful return.
1192 * Optional.
1193 */
1194RTDECL(int) RTDbgModSegmentAdd(RTDBGMOD hDbgMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName,
1195 uint32_t fFlags, PRTDBGSEGIDX piSeg)
1196{
1197 /*
1198 * Validate input.
1199 */
1200 PRTDBGMODINT pDbgMod = hDbgMod;
1201 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1202 AssertMsgReturn(uRva + cb >= uRva, ("uRva=%RTptr cb=%RTptr\n", uRva, cb), VERR_DBG_ADDRESS_WRAP);
1203 Assert(*pszName);
1204 size_t cchName = strlen(pszName);
1205 AssertReturn(cchName > 0, VERR_DBG_SEGMENT_NAME_OUT_OF_RANGE);
1206 AssertReturn(cchName < RTDBG_SEGMENT_NAME_LENGTH, VERR_DBG_SEGMENT_NAME_OUT_OF_RANGE);
1207 AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
1208 AssertPtrNull(piSeg);
1209 AssertMsgReturn(!piSeg || *piSeg == NIL_RTDBGSEGIDX || *piSeg <= RTDBGSEGIDX_LAST, ("%#x\n", *piSeg), VERR_DBG_SPECIAL_SEGMENT);
1210
1211 /*
1212 * Do the deed.
1213 */
1214 RTDBGMOD_LOCK(pDbgMod);
1215 int rc = pDbgMod->pDbgVt->pfnSegmentAdd(pDbgMod, uRva, cb, pszName, cchName, fFlags, piSeg);
1216 RTDBGMOD_UNLOCK(pDbgMod);
1217
1218 return rc;
1219
1220}
1221RT_EXPORT_SYMBOL(RTDbgModSegmentAdd);
1222
1223
1224/**
1225 * Gets the number of segments in the module.
1226 *
1227 * This is can be used to determine the range which can be passed to
1228 * RTDbgModSegmentByIndex and derivatives.
1229 *
1230 * @returns The segment relative address.
1231 * NIL_RTDBGSEGIDX if the handle is invalid.
1232 *
1233 * @param hDbgMod The module handle.
1234 */
1235RTDECL(RTDBGSEGIDX) RTDbgModSegmentCount(RTDBGMOD hDbgMod)
1236{
1237 PRTDBGMODINT pDbgMod = hDbgMod;
1238 RTDBGMOD_VALID_RETURN_RC(pDbgMod, NIL_RTDBGSEGIDX);
1239 RTDBGMOD_LOCK(pDbgMod);
1240
1241 RTDBGSEGIDX cSegs = pDbgMod->pDbgVt->pfnSegmentCount(pDbgMod);
1242
1243 RTDBGMOD_UNLOCK(pDbgMod);
1244 return cSegs;
1245}
1246RT_EXPORT_SYMBOL(RTDbgModSegmentCount);
1247
1248
1249/**
1250 * Query information about a segment.
1251 *
1252 * This can be used together with RTDbgModSegmentCount to enumerate segments.
1253 * The index starts a 0 and stops one below RTDbgModSegmentCount.
1254 *
1255 * @returns IPRT status code.
1256 * @retval VERR_DBG_INVALID_SEGMENT_INDEX if iSeg is too high.
1257 * @retval VERR_DBG_SPECIAL_SEGMENT if iSeg indicates a special segment.
1258 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1259 *
1260 * @param hDbgMod The module handle.
1261 * @param iSeg The segment index. No special segments.
1262 * @param pSegInfo Where to return the segment info. The
1263 * RTDBGSEGMENT::Address member will be set to
1264 * RTUINTPTR_MAX or the load address used at link time.
1265 */
1266RTDECL(int) RTDbgModSegmentByIndex(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
1267{
1268 AssertMsgReturn(iSeg <= RTDBGSEGIDX_LAST, ("%#x\n", iSeg), VERR_DBG_SPECIAL_SEGMENT);
1269 PRTDBGMODINT pDbgMod = hDbgMod;
1270 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1271 RTDBGMOD_LOCK(pDbgMod);
1272
1273 int rc = pDbgMod->pDbgVt->pfnSegmentByIndex(pDbgMod, iSeg, pSegInfo);
1274
1275 RTDBGMOD_UNLOCK(pDbgMod);
1276 return rc;
1277}
1278RT_EXPORT_SYMBOL(RTDbgModSegmentByIndex);
1279
1280
1281/**
1282 * Gets the size of a segment.
1283 *
1284 * This is a just a wrapper around RTDbgModSegmentByIndex.
1285 *
1286 * @returns The segment size.
1287 * RTUINTPTR_MAX is returned if either the handle and segment index are
1288 * invalid.
1289 *
1290 * @param hDbgMod The module handle.
1291 * @param iSeg The segment index. RTDBGSEGIDX_ABS is not allowed.
1292 * If RTDBGSEGIDX_RVA is used, the functions returns
1293 * the same value as RTDbgModImageSize.
1294 */
1295RTDECL(RTUINTPTR) RTDbgModSegmentSize(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg)
1296{
1297 if (iSeg == RTDBGSEGIDX_RVA)
1298 return RTDbgModImageSize(hDbgMod);
1299 RTDBGSEGMENT SegInfo;
1300 int rc = RTDbgModSegmentByIndex(hDbgMod, iSeg, &SegInfo);
1301 return RT_SUCCESS(rc) ? SegInfo.cb : RTUINTPTR_MAX;
1302}
1303RT_EXPORT_SYMBOL(RTDbgModSegmentSize);
1304
1305
1306/**
1307 * Gets the image relative address of a segment.
1308 *
1309 * This is a just a wrapper around RTDbgModSegmentByIndex.
1310 *
1311 * @returns The segment relative address.
1312 * RTUINTPTR_MAX is returned if either the handle and segment index are
1313 * invalid.
1314 *
1315 * @param hDbgMod The module handle.
1316 * @param iSeg The segment index. No special segment indexes
1317 * allowed (asserted).
1318 */
1319RTDECL(RTUINTPTR) RTDbgModSegmentRva(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg)
1320{
1321 RTDBGSEGMENT SegInfo;
1322 int rc = RTDbgModSegmentByIndex(hDbgMod, iSeg, &SegInfo);
1323 return RT_SUCCESS(rc) ? SegInfo.uRva : RTUINTPTR_MAX;
1324}
1325RT_EXPORT_SYMBOL(RTDbgModSegmentRva);
1326
1327
1328/**
1329 * Adds a line number to the module.
1330 *
1331 * @returns IPRT status code.
1332 * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding
1333 * custom symbols. This is a common place occurrence.
1334 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1335 * @retval VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE if the symbol name is too long or
1336 * short.
1337 * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and
1338 * it's not inside any of the segments defined by the module.
1339 * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
1340 * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
1341 * end of the segment.
1342 * @retval VERR_DBG_ADDRESS_WRAP if off+cb wraps around.
1343 * @retval VERR_INVALID_PARAMETER if the symbol flags sets undefined bits.
1344 *
1345 * @param hDbgMod The module handle.
1346 * @param pszSymbol The symbol name.
1347 * @param iSeg The segment index.
1348 * @param off The segment offset.
1349 * @param cb The size of the symbol. Can be zero, although this
1350 * may depend somewhat on the debug interpreter.
1351 * @param fFlags Symbol flags. Reserved for the future, MBZ.
1352 * @param piOrdinal Where to return the symbol ordinal on success. If
1353 * the interpreter doesn't do ordinals, this will be set to
1354 * UINT32_MAX. Optional.
1355 */
1356RTDECL(int) RTDbgModSymbolAdd(RTDBGMOD hDbgMod, const char *pszSymbol, RTDBGSEGIDX iSeg, RTUINTPTR off,
1357 RTUINTPTR cb, uint32_t fFlags, uint32_t *piOrdinal)
1358{
1359 /*
1360 * Validate input.
1361 */
1362 PRTDBGMODINT pDbgMod = hDbgMod;
1363 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1364 AssertPtr(pszSymbol);
1365 size_t cchSymbol = strlen(pszSymbol);
1366 AssertReturn(cchSymbol, VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE);
1367 AssertReturn(cchSymbol < RTDBG_SYMBOL_NAME_LENGTH, VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE);
1368 AssertMsgReturn( iSeg <= RTDBGSEGIDX_LAST
1369 || ( iSeg >= RTDBGSEGIDX_SPECIAL_FIRST
1370 && iSeg <= RTDBGSEGIDX_SPECIAL_LAST),
1371 ("%#x\n", iSeg),
1372 VERR_DBG_INVALID_SEGMENT_INDEX);
1373 AssertMsgReturn(off + cb >= off, ("off=%RTptr cb=%RTptr\n", off, cb), VERR_DBG_ADDRESS_WRAP);
1374 AssertReturn(!fFlags, VERR_INVALID_PARAMETER); /* currently reserved. */
1375
1376 RTDBGMOD_LOCK(pDbgMod);
1377
1378 /*
1379 * Convert RVAs.
1380 */
1381 if (iSeg == RTDBGSEGIDX_RVA)
1382 {
1383 iSeg = pDbgMod->pDbgVt->pfnRvaToSegOff(pDbgMod, off, &off);
1384 if (iSeg == NIL_RTDBGSEGIDX)
1385 {
1386 RTDBGMOD_UNLOCK(pDbgMod);
1387 return VERR_DBG_INVALID_RVA;
1388 }
1389 }
1390
1391 /*
1392 * Get down to business.
1393 */
1394 int rc = pDbgMod->pDbgVt->pfnSymbolAdd(pDbgMod, pszSymbol, cchSymbol, iSeg, off, cb, fFlags, piOrdinal);
1395
1396 RTDBGMOD_UNLOCK(pDbgMod);
1397 return rc;
1398}
1399RT_EXPORT_SYMBOL(RTDbgModSymbolAdd);
1400
1401
1402/**
1403 * Gets the symbol count.
1404 *
1405 * This can be used together wtih RTDbgModSymbolByOrdinal or
1406 * RTDbgModSymbolByOrdinalA to enumerate all the symbols.
1407 *
1408 * @returns The number of symbols in the module.
1409 * UINT32_MAX is returned if the module handle is invalid or some other
1410 * error occurs.
1411 *
1412 * @param hDbgMod The module handle.
1413 */
1414RTDECL(uint32_t) RTDbgModSymbolCount(RTDBGMOD hDbgMod)
1415{
1416 PRTDBGMODINT pDbgMod = hDbgMod;
1417 RTDBGMOD_VALID_RETURN_RC(pDbgMod, UINT32_MAX);
1418 RTDBGMOD_LOCK(pDbgMod);
1419
1420 uint32_t cSymbols = pDbgMod->pDbgVt->pfnSymbolCount(pDbgMod);
1421
1422 RTDBGMOD_UNLOCK(pDbgMod);
1423 return cSymbols;
1424}
1425RT_EXPORT_SYMBOL(RTDbgModSymbolCount);
1426
1427
1428/**
1429 * Queries symbol information by ordinal number.
1430 *
1431 * @returns IPRT status code.
1432 * @retval VERR_SYMBOL_NOT_FOUND if there is no symbol at the given number.
1433 * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols.
1434 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1435 * @retval VERR_NOT_SUPPORTED if lookup by ordinal is not supported.
1436 *
1437 * @param hDbgMod The module handle.
1438 * @param iOrdinal The symbol ordinal number. 0-based. The highest
1439 * number is RTDbgModSymbolCount() - 1.
1440 * @param pSymInfo Where to store the symbol information.
1441 */
1442RTDECL(int) RTDbgModSymbolByOrdinal(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
1443{
1444 PRTDBGMODINT pDbgMod = hDbgMod;
1445 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1446 RTDBGMOD_LOCK(pDbgMod);
1447
1448 int rc = pDbgMod->pDbgVt->pfnSymbolByOrdinal(pDbgMod, iOrdinal, pSymInfo);
1449
1450 RTDBGMOD_UNLOCK(pDbgMod);
1451 return rc;
1452}
1453RT_EXPORT_SYMBOL(RTDbgModSymbolByOrdinal);
1454
1455
1456/**
1457 * Queries symbol information by ordinal number.
1458 *
1459 * @returns IPRT status code.
1460 * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols.
1461 * @retval VERR_NOT_SUPPORTED if lookup by ordinal is not supported.
1462 * @retval VERR_SYMBOL_NOT_FOUND if there is no symbol at the given number.
1463 * @retval VERR_NO_MEMORY if RTDbgSymbolAlloc fails.
1464 *
1465 * @param hDbgMod The module handle.
1466 * @param iOrdinal The symbol ordinal number. 0-based. The highest
1467 * number is RTDbgModSymbolCount() - 1.
1468 * @param ppSymInfo Where to store the pointer to the returned
1469 * symbol information. Always set. Free with
1470 * RTDbgSymbolFree.
1471 */
1472RTDECL(int) RTDbgModSymbolByOrdinalA(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGSYMBOL *ppSymInfo)
1473{
1474 AssertPtr(ppSymInfo);
1475 *ppSymInfo = NULL;
1476
1477 PRTDBGSYMBOL pSymInfo = RTDbgSymbolAlloc();
1478 if (!pSymInfo)
1479 return VERR_NO_MEMORY;
1480
1481 int rc = RTDbgModSymbolByOrdinal(hDbgMod, iOrdinal, pSymInfo);
1482
1483 if (RT_SUCCESS(rc))
1484 *ppSymInfo = pSymInfo;
1485 else
1486 RTDbgSymbolFree(pSymInfo);
1487 return rc;
1488}
1489RT_EXPORT_SYMBOL(RTDbgModSymbolByOrdinalA);
1490
1491
1492/**
1493 * Queries symbol information by address.
1494 *
1495 * The returned symbol is what the debug info interpreter considers the symbol
1496 * most applicable to the specified address. This usually means a symbol with an
1497 * address equal or lower than the requested.
1498 *
1499 * @returns IPRT status code.
1500 * @retval VERR_SYMBOL_NOT_FOUND if no suitable symbol was found.
1501 * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols.
1502 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1503 * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and
1504 * it's not inside any of the segments defined by the module.
1505 * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
1506 * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
1507 * end of the segment.
1508 * @retval VERR_INVALID_PARAMETER if incorrect flags.
1509 *
1510 * @param hDbgMod The module handle.
1511 * @param iSeg The segment number.
1512 * @param off The offset into the segment.
1513 * @param fFlags Symbol search flags, see RTDBGSYMADDR_FLAGS_XXX.
1514 * @param poffDisp Where to store the distance between the
1515 * specified address and the returned symbol.
1516 * Optional.
1517 * @param pSymInfo Where to store the symbol information.
1518 */
1519RTDECL(int) RTDbgModSymbolByAddr(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
1520 PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
1521{
1522 /*
1523 * Validate input.
1524 */
1525 PRTDBGMODINT pDbgMod = hDbgMod;
1526 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1527 AssertPtrNull(poffDisp);
1528 AssertPtr(pSymInfo);
1529 AssertReturn(!(fFlags & ~RTDBGSYMADDR_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
1530
1531 RTDBGMOD_LOCK(pDbgMod);
1532
1533 /*
1534 * Convert RVAs.
1535 */
1536 if (iSeg == RTDBGSEGIDX_RVA)
1537 {
1538 iSeg = pDbgMod->pDbgVt->pfnRvaToSegOff(pDbgMod, off, &off);
1539 if (iSeg == NIL_RTDBGSEGIDX)
1540 {
1541 RTDBGMOD_UNLOCK(pDbgMod);
1542 return VERR_DBG_INVALID_RVA;
1543 }
1544 }
1545
1546 /*
1547 * Get down to business.
1548 */
1549 int rc = pDbgMod->pDbgVt->pfnSymbolByAddr(pDbgMod, iSeg, off, fFlags, poffDisp, pSymInfo);
1550
1551 RTDBGMOD_UNLOCK(pDbgMod);
1552 return rc;
1553}
1554RT_EXPORT_SYMBOL(RTDbgModSymbolByAddr);
1555
1556
1557/**
1558 * Queries symbol information by address.
1559 *
1560 * The returned symbol is what the debug info interpreter considers the symbol
1561 * most applicable to the specified address. This usually means a symbol with an
1562 * address equal or lower than the requested.
1563 *
1564 * @returns IPRT status code.
1565 * @retval VERR_SYMBOL_NOT_FOUND if no suitable symbol was found.
1566 * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols.
1567 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1568 * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and
1569 * it's not inside any of the segments defined by the module.
1570 * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
1571 * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
1572 * end of the segment.
1573 * @retval VERR_NO_MEMORY if RTDbgSymbolAlloc fails.
1574 * @retval VERR_INVALID_PARAMETER if incorrect flags.
1575 *
1576 * @param hDbgMod The module handle.
1577 * @param iSeg The segment index.
1578 * @param off The offset into the segment.
1579 * @param fFlags Symbol search flags, see RTDBGSYMADDR_FLAGS_XXX.
1580 * @param poffDisp Where to store the distance between the
1581 * specified address and the returned symbol. Optional.
1582 * @param ppSymInfo Where to store the pointer to the returned
1583 * symbol information. Always set. Free with
1584 * RTDbgSymbolFree.
1585 */
1586RTDECL(int) RTDbgModSymbolByAddrA(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
1587 PRTINTPTR poffDisp, PRTDBGSYMBOL *ppSymInfo)
1588{
1589 AssertPtr(ppSymInfo);
1590 *ppSymInfo = NULL;
1591
1592 PRTDBGSYMBOL pSymInfo = RTDbgSymbolAlloc();
1593 if (!pSymInfo)
1594 return VERR_NO_MEMORY;
1595
1596 int rc = RTDbgModSymbolByAddr(hDbgMod, iSeg, off, fFlags, poffDisp, pSymInfo);
1597
1598 if (RT_SUCCESS(rc))
1599 *ppSymInfo = pSymInfo;
1600 else
1601 RTDbgSymbolFree(pSymInfo);
1602 return rc;
1603}
1604RT_EXPORT_SYMBOL(RTDbgModSymbolByAddrA);
1605
1606
1607/**
1608 * Queries symbol information by symbol name.
1609 *
1610 * @returns IPRT status code.
1611 * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols.
1612 * @retval VERR_SYMBOL_NOT_FOUND if no suitable symbol was found.
1613 * @retval VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE if the symbol name is too long or
1614 * short.
1615 *
1616 * @param hDbgMod The module handle.
1617 * @param pszSymbol The symbol name.
1618 * @param pSymInfo Where to store the symbol information.
1619 */
1620RTDECL(int) RTDbgModSymbolByName(RTDBGMOD hDbgMod, const char *pszSymbol, PRTDBGSYMBOL pSymInfo)
1621{
1622 /*
1623 * Validate input.
1624 */
1625 PRTDBGMODINT pDbgMod = hDbgMod;
1626 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1627 AssertPtr(pszSymbol);
1628 size_t cchSymbol = strlen(pszSymbol);
1629 AssertReturn(cchSymbol, VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE);
1630 AssertReturn(cchSymbol < RTDBG_SYMBOL_NAME_LENGTH, VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE);
1631 AssertPtr(pSymInfo);
1632
1633 /*
1634 * Make the query.
1635 */
1636 RTDBGMOD_LOCK(pDbgMod);
1637 int rc = pDbgMod->pDbgVt->pfnSymbolByName(pDbgMod, pszSymbol, cchSymbol, pSymInfo);
1638 RTDBGMOD_UNLOCK(pDbgMod);
1639
1640 return rc;
1641}
1642RT_EXPORT_SYMBOL(RTDbgModSymbolByName);
1643
1644
1645/**
1646 * Queries symbol information by symbol name.
1647 *
1648 * @returns IPRT status code.
1649 * @retval VERR_DBG_NO_SYMBOLS if there aren't any symbols.
1650 * @retval VERR_SYMBOL_NOT_FOUND if no suitable symbol was found.
1651 * @retval VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE if the symbol name is too long or
1652 * short.
1653 * @retval VERR_NO_MEMORY if RTDbgSymbolAlloc fails.
1654 *
1655 * @param hDbgMod The module handle.
1656 * @param pszSymbol The symbol name.
1657 * @param ppSymInfo Where to store the pointer to the returned
1658 * symbol information. Always set. Free with
1659 * RTDbgSymbolFree.
1660 */
1661RTDECL(int) RTDbgModSymbolByNameA(RTDBGMOD hDbgMod, const char *pszSymbol, PRTDBGSYMBOL *ppSymInfo)
1662{
1663 AssertPtr(ppSymInfo);
1664 *ppSymInfo = NULL;
1665
1666 PRTDBGSYMBOL pSymInfo = RTDbgSymbolAlloc();
1667 if (!pSymInfo)
1668 return VERR_NO_MEMORY;
1669
1670 int rc = RTDbgModSymbolByName(hDbgMod, pszSymbol, pSymInfo);
1671
1672 if (RT_SUCCESS(rc))
1673 *ppSymInfo = pSymInfo;
1674 else
1675 RTDbgSymbolFree(pSymInfo);
1676 return rc;
1677}
1678RT_EXPORT_SYMBOL(RTDbgModSymbolByNameA);
1679
1680
1681/**
1682 * Adds a line number to the module.
1683 *
1684 * @returns IPRT status code.
1685 * @retval VERR_NOT_SUPPORTED if the module interpret doesn't support adding
1686 * custom symbols. This should be consider a normal response.
1687 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1688 * @retval VERR_DBG_FILE_NAME_OUT_OF_RANGE if the file name is too longer or
1689 * empty.
1690 * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and
1691 * it's not inside any of the segments defined by the module.
1692 * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
1693 * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
1694 * end of the segment.
1695 * @retval VERR_INVALID_PARAMETER if the line number flags sets undefined bits.
1696 *
1697 * @param hDbgMod The module handle.
1698 * @param pszFile The file name.
1699 * @param uLineNo The line number.
1700 * @param iSeg The segment index.
1701 * @param off The segment offset.
1702 * @param piOrdinal Where to return the line number ordinal on
1703 * success. If the interpreter doesn't do ordinals,
1704 * this will be set to UINT32_MAX. Optional.
1705 */
1706RTDECL(int) RTDbgModLineAdd(RTDBGMOD hDbgMod, const char *pszFile, uint32_t uLineNo,
1707 RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t *piOrdinal)
1708{
1709 /*
1710 * Validate input.
1711 */
1712 PRTDBGMODINT pDbgMod = hDbgMod;
1713 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1714 AssertPtr(pszFile);
1715 size_t cchFile = strlen(pszFile);
1716 AssertReturn(cchFile, VERR_DBG_FILE_NAME_OUT_OF_RANGE);
1717 AssertReturn(cchFile < RTDBG_FILE_NAME_LENGTH, VERR_DBG_FILE_NAME_OUT_OF_RANGE);
1718 AssertMsgReturn( iSeg <= RTDBGSEGIDX_LAST
1719 || iSeg == RTDBGSEGIDX_RVA,
1720 ("%#x\n", iSeg),
1721 VERR_DBG_INVALID_SEGMENT_INDEX);
1722 AssertReturn(uLineNo > 0 && uLineNo < UINT32_MAX, VERR_INVALID_PARAMETER);
1723
1724 RTDBGMOD_LOCK(pDbgMod);
1725
1726 /*
1727 * Convert RVAs.
1728 */
1729 if (iSeg == RTDBGSEGIDX_RVA)
1730 {
1731 iSeg = pDbgMod->pDbgVt->pfnRvaToSegOff(pDbgMod, off, &off);
1732 if (iSeg == NIL_RTDBGSEGIDX)
1733 {
1734 RTDBGMOD_UNLOCK(pDbgMod);
1735 return VERR_DBG_INVALID_RVA;
1736 }
1737 }
1738
1739 /*
1740 * Get down to business.
1741 */
1742 int rc = pDbgMod->pDbgVt->pfnLineAdd(pDbgMod, pszFile, cchFile, uLineNo, iSeg, off, piOrdinal);
1743
1744 RTDBGMOD_UNLOCK(pDbgMod);
1745 return rc;
1746}
1747RT_EXPORT_SYMBOL(RTDbgModLineAdd);
1748
1749
1750/**
1751 * Gets the line number count.
1752 *
1753 * This can be used together wtih RTDbgModLineByOrdinal or RTDbgModSymbolByLineA
1754 * to enumerate all the line number information.
1755 *
1756 * @returns The number of line numbers in the module.
1757 * UINT32_MAX is returned if the module handle is invalid or some other
1758 * error occurs.
1759 *
1760 * @param hDbgMod The module handle.
1761 */
1762RTDECL(uint32_t) RTDbgModLineCount(RTDBGMOD hDbgMod)
1763{
1764 PRTDBGMODINT pDbgMod = hDbgMod;
1765 RTDBGMOD_VALID_RETURN_RC(pDbgMod, UINT32_MAX);
1766 RTDBGMOD_LOCK(pDbgMod);
1767
1768 uint32_t cLineNumbers = pDbgMod->pDbgVt->pfnLineCount(pDbgMod);
1769
1770 RTDBGMOD_UNLOCK(pDbgMod);
1771 return cLineNumbers;
1772}
1773RT_EXPORT_SYMBOL(RTDbgModLineCount);
1774
1775
1776/**
1777 * Queries line number information by ordinal number.
1778 *
1779 * This can be used to enumerate the line numbers for the module. Use
1780 * RTDbgModLineCount() to figure the end of the ordinals.
1781 *
1782 * @returns IPRT status code.
1783 * @retval VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers.
1784 * @retval VERR_DBG_LINE_NOT_FOUND if there is no line number with that
1785 * ordinal.
1786 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1787
1788 * @param hDbgMod The module handle.
1789 * @param iOrdinal The line number ordinal number.
1790 * @param pLineInfo Where to store the information about the line
1791 * number.
1792 */
1793RTDECL(int) RTDbgModLineByOrdinal(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
1794{
1795 PRTDBGMODINT pDbgMod = hDbgMod;
1796 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1797 RTDBGMOD_LOCK(pDbgMod);
1798
1799 int rc = pDbgMod->pDbgVt->pfnLineByOrdinal(pDbgMod, iOrdinal, pLineInfo);
1800
1801 RTDBGMOD_UNLOCK(pDbgMod);
1802 return rc;
1803}
1804RT_EXPORT_SYMBOL(RTDbgModLineByOrdinal);
1805
1806
1807/**
1808 * Queries line number information by ordinal number.
1809 *
1810 * This can be used to enumerate the line numbers for the module. Use
1811 * RTDbgModLineCount() to figure the end of the ordinals.
1812 *
1813 * @returns IPRT status code.
1814 * @retval VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers.
1815 * @retval VERR_DBG_LINE_NOT_FOUND if there is no line number with that
1816 * ordinal.
1817 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1818 * @retval VERR_NO_MEMORY if RTDbgLineAlloc fails.
1819 *
1820 * @param hDbgMod The module handle.
1821 * @param iOrdinal The line number ordinal number.
1822 * @param ppLineInfo Where to store the pointer to the returned line
1823 * number information. Always set. Free with
1824 * RTDbgLineFree.
1825 */
1826RTDECL(int) RTDbgModLineByOrdinalA(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGLINE *ppLineInfo)
1827{
1828 AssertPtr(ppLineInfo);
1829 *ppLineInfo = NULL;
1830
1831 PRTDBGLINE pLineInfo = RTDbgLineAlloc();
1832 if (!pLineInfo)
1833 return VERR_NO_MEMORY;
1834
1835 int rc = RTDbgModLineByOrdinal(hDbgMod, iOrdinal, pLineInfo);
1836
1837 if (RT_SUCCESS(rc))
1838 *ppLineInfo = pLineInfo;
1839 else
1840 RTDbgLineFree(pLineInfo);
1841 return rc;
1842}
1843RT_EXPORT_SYMBOL(RTDbgModLineByOrdinalA);
1844
1845
1846/**
1847 * Queries line number information by address.
1848 *
1849 * The returned line number is what the debug info interpreter considers the
1850 * one most applicable to the specified address. This usually means a line
1851 * number with an address equal or lower than the requested.
1852 *
1853 * @returns IPRT status code.
1854 * @retval VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers.
1855 * @retval VERR_DBG_LINE_NOT_FOUND if no suitable line number was found.
1856 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1857 * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and
1858 * it's not inside any of the segments defined by the module.
1859 * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
1860 * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
1861 * end of the segment.
1862 *
1863 * @param hDbgMod The module handle.
1864 * @param iSeg The segment number.
1865 * @param off The offset into the segment.
1866 * @param poffDisp Where to store the distance between the
1867 * specified address and the returned symbol.
1868 * Optional.
1869 * @param pLineInfo Where to store the line number information.
1870 */
1871RTDECL(int) RTDbgModLineByAddr(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
1872{
1873 /*
1874 * Validate input.
1875 */
1876 PRTDBGMODINT pDbgMod = hDbgMod;
1877 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1878 AssertPtrNull(poffDisp);
1879 AssertPtr(pLineInfo);
1880
1881 RTDBGMOD_LOCK(pDbgMod);
1882
1883 /*
1884 * Convert RVAs.
1885 */
1886 if (iSeg == RTDBGSEGIDX_RVA)
1887 {
1888 iSeg = pDbgMod->pDbgVt->pfnRvaToSegOff(pDbgMod, off, &off);
1889 if (iSeg == NIL_RTDBGSEGIDX)
1890 {
1891 RTDBGMOD_UNLOCK(pDbgMod);
1892 return VERR_DBG_INVALID_RVA;
1893 }
1894 }
1895
1896 int rc = pDbgMod->pDbgVt->pfnLineByAddr(pDbgMod, iSeg, off, poffDisp, pLineInfo);
1897
1898 RTDBGMOD_UNLOCK(pDbgMod);
1899 return rc;
1900}
1901RT_EXPORT_SYMBOL(RTDbgModLineByAddr);
1902
1903
1904/**
1905 * Queries line number information by address.
1906 *
1907 * The returned line number is what the debug info interpreter considers the
1908 * one most applicable to the specified address. This usually means a line
1909 * number with an address equal or lower than the requested.
1910 *
1911 * @returns IPRT status code.
1912 * @retval VERR_DBG_NO_LINE_NUMBERS if there aren't any line numbers.
1913 * @retval VERR_DBG_LINE_NOT_FOUND if no suitable line number was found.
1914 * @retval VERR_INVALID_HANDLE if hDbgMod is invalid.
1915 * @retval VERR_DBG_INVALID_RVA if an image relative address is specified and
1916 * it's not inside any of the segments defined by the module.
1917 * @retval VERR_DBG_INVALID_SEGMENT_INDEX if the segment index isn't valid.
1918 * @retval VERR_DBG_INVALID_SEGMENT_OFFSET if the segment offset is beyond the
1919 * end of the segment.
1920 * @retval VERR_NO_MEMORY if RTDbgLineAlloc fails.
1921 *
1922 * @param hDbgMod The module handle.
1923 * @param iSeg The segment number.
1924 * @param off The offset into the segment.
1925 * @param poffDisp Where to store the distance between the
1926 * specified address and the returned symbol.
1927 * Optional.
1928 * @param ppLineInfo Where to store the pointer to the returned line
1929 * number information. Always set. Free with
1930 * RTDbgLineFree.
1931 */
1932RTDECL(int) RTDbgModLineByAddrA(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTINTPTR poffDisp, PRTDBGLINE *ppLineInfo)
1933{
1934 AssertPtr(ppLineInfo);
1935 *ppLineInfo = NULL;
1936
1937 PRTDBGLINE pLineInfo = RTDbgLineAlloc();
1938 if (!pLineInfo)
1939 return VERR_NO_MEMORY;
1940
1941 int rc = RTDbgModLineByAddr(hDbgMod, iSeg, off, poffDisp, pLineInfo);
1942
1943 if (RT_SUCCESS(rc))
1944 *ppLineInfo = pLineInfo;
1945 else
1946 RTDbgLineFree(pLineInfo);
1947 return rc;
1948}
1949RT_EXPORT_SYMBOL(RTDbgModLineByAddrA);
1950
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette