VirtualBox

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

Last change on this file since 73375 was 73375, checked in by vboxsync, 6 years ago

IPRT: Added RTLDRPROP_UNWIND_INFO to RTLdrQueryPropEx. Added RTDbgModImageQueryProp, RTDbgModImageGetArch, and RTDbgModImageGetFormat.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 70.0 KB
Line 
1/* $Id: dbgmod.cpp 73375 2018-07-27 07:59:25Z vboxsync $ */
2/** @file
3 * IPRT - Debug Module Interpreter.
4 */
5
6/*
7 * Copyright (C) 2009-2017 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/alloca.h>
36#include <iprt/asm.h>
37#include <iprt/assert.h>
38#include <iprt/avl.h>
39#include <iprt/err.h>
40#include <iprt/initterm.h>
41#include <iprt/log.h>
42#include <iprt/mem.h>
43#include <iprt/once.h>
44#include <iprt/param.h>
45#include <iprt/path.h>
46#include <iprt/semaphore.h>
47#include <iprt/strcache.h>
48#include <iprt/string.h>
49#include <iprt/uuid.h>
50#include "internal/dbgmod.h"
51#include "internal/magics.h"
52
53
54/*********************************************************************************************************************************
55* Structures and Typedefs *
56*********************************************************************************************************************************/
57/** Debug info interpreter registration record. */
58typedef struct RTDBGMODREGDBG
59{
60 /** Pointer to the next record. */
61 struct RTDBGMODREGDBG *pNext;
62 /** Pointer to the virtual function table for the interpreter. */
63 PCRTDBGMODVTDBG pVt;
64 /** Usage counter. */
65 uint32_t volatile cUsers;
66} RTDBGMODREGDBG;
67typedef RTDBGMODREGDBG *PRTDBGMODREGDBG;
68
69/** Image interpreter registration record. */
70typedef struct RTDBGMODREGIMG
71{
72 /** Pointer to the next record. */
73 struct RTDBGMODREGIMG *pNext;
74 /** Pointer to the virtual function table for the interpreter. */
75 PCRTDBGMODVTIMG pVt;
76 /** Usage counter. */
77 uint32_t volatile cUsers;
78} RTDBGMODREGIMG;
79typedef RTDBGMODREGIMG *PRTDBGMODREGIMG;
80
81
82/*********************************************************************************************************************************
83* Defined Constants And Macros *
84*********************************************************************************************************************************/
85/** Validates a debug module handle and returns rc if not valid. */
86#define RTDBGMOD_VALID_RETURN_RC(pDbgMod, rc) \
87 do { \
88 AssertPtrReturn((pDbgMod), (rc)); \
89 AssertReturn((pDbgMod)->u32Magic == RTDBGMOD_MAGIC, (rc)); \
90 AssertReturn((pDbgMod)->cRefs > 0, (rc)); \
91 } while (0)
92
93/** Locks the debug module. */
94#define RTDBGMOD_LOCK(pDbgMod) \
95 do { \
96 int rcLock = RTCritSectEnter(&(pDbgMod)->CritSect); \
97 AssertRC(rcLock); \
98 } while (0)
99
100/** Unlocks the debug module. */
101#define RTDBGMOD_UNLOCK(pDbgMod) \
102 do { \
103 int rcLock = RTCritSectLeave(&(pDbgMod)->CritSect); \
104 AssertRC(rcLock); \
105 } while (0)
106
107
108/*********************************************************************************************************************************
109* Global Variables *
110*********************************************************************************************************************************/
111/** Init once object for lazy registration of the built-in image and debug
112 * info interpreters. */
113static RTONCE g_rtDbgModOnce = RTONCE_INITIALIZER;
114/** Read/Write semaphore protecting the list of registered interpreters. */
115static RTSEMRW g_hDbgModRWSem = NIL_RTSEMRW;
116/** List of registered image interpreters. */
117static PRTDBGMODREGIMG g_pImgHead;
118/** List of registered debug infor interpreters. */
119static PRTDBGMODREGDBG g_pDbgHead;
120/** String cache for the debug info interpreters.
121 * RTSTRCACHE is thread safe. */
122DECLHIDDEN(RTSTRCACHE) g_hDbgModStrCache = NIL_RTSTRCACHE;
123
124
125
126
127
128/**
129 * Cleanup debug info interpreter globals.
130 *
131 * @param enmReason The cause of the termination.
132 * @param iStatus The meaning of this depends on enmReason.
133 * @param pvUser User argument, unused.
134 */
135static DECLCALLBACK(void) rtDbgModTermCallback(RTTERMREASON enmReason, int32_t iStatus, void *pvUser)
136{
137 NOREF(iStatus); NOREF(pvUser);
138 if (enmReason == RTTERMREASON_UNLOAD)
139 {
140 RTSemRWDestroy(g_hDbgModRWSem);
141 g_hDbgModRWSem = NIL_RTSEMRW;
142
143 RTStrCacheDestroy(g_hDbgModStrCache);
144 g_hDbgModStrCache = NIL_RTSTRCACHE;
145
146 PRTDBGMODREGDBG pDbg = g_pDbgHead;
147 g_pDbgHead = NULL;
148 while (pDbg)
149 {
150 PRTDBGMODREGDBG pNext = pDbg->pNext;
151 AssertMsg(pDbg->cUsers == 0, ("%#x %s\n", pDbg->cUsers, pDbg->pVt->pszName));
152 RTMemFree(pDbg);
153 pDbg = pNext;
154 }
155
156 PRTDBGMODREGIMG pImg = g_pImgHead;
157 g_pImgHead = NULL;
158 while (pImg)
159 {
160 PRTDBGMODREGIMG pNext = pImg->pNext;
161 AssertMsg(pImg->cUsers == 0, ("%#x %s\n", pImg->cUsers, pImg->pVt->pszName));
162 RTMemFree(pImg);
163 pImg = pNext;
164 }
165 }
166}
167
168
169/**
170 * Internal worker for register a debug interpreter.
171 *
172 * Called while owning the write lock or when locking isn't required.
173 *
174 * @returns IPRT status code.
175 * @retval VERR_NO_MEMORY
176 * @retval VERR_ALREADY_EXISTS
177 *
178 * @param pVt The virtual function table of the debug
179 * module interpreter.
180 */
181static int rtDbgModDebugInterpreterRegister(PCRTDBGMODVTDBG pVt)
182{
183 /*
184 * Search or duplicate registration.
185 */
186 PRTDBGMODREGDBG pPrev = NULL;
187 for (PRTDBGMODREGDBG pCur = g_pDbgHead; pCur; pCur = pCur->pNext)
188 {
189 if (pCur->pVt == pVt)
190 return VERR_ALREADY_EXISTS;
191 if (!strcmp(pCur->pVt->pszName, pVt->pszName))
192 return VERR_ALREADY_EXISTS;
193 pPrev = pCur;
194 }
195
196 /*
197 * Create a new record and add it to the end of the list.
198 */
199 PRTDBGMODREGDBG pReg = (PRTDBGMODREGDBG)RTMemAlloc(sizeof(*pReg));
200 if (!pReg)
201 return VERR_NO_MEMORY;
202 pReg->pVt = pVt;
203 pReg->cUsers = 0;
204 pReg->pNext = NULL;
205 if (pPrev)
206 pPrev->pNext = pReg;
207 else
208 g_pDbgHead = pReg;
209 return VINF_SUCCESS;
210}
211
212
213/**
214 * Internal worker for register a image interpreter.
215 *
216 * Called while owning the write lock or when locking isn't required.
217 *
218 * @returns IPRT status code.
219 * @retval VERR_NO_MEMORY
220 * @retval VERR_ALREADY_EXISTS
221 *
222 * @param pVt The virtual function table of the image
223 * interpreter.
224 */
225static int rtDbgModImageInterpreterRegister(PCRTDBGMODVTIMG pVt)
226{
227 /*
228 * Search or duplicate registration.
229 */
230 PRTDBGMODREGIMG pPrev = NULL;
231 for (PRTDBGMODREGIMG pCur = g_pImgHead; pCur; pCur = pCur->pNext)
232 {
233 if (pCur->pVt == pVt)
234 return VERR_ALREADY_EXISTS;
235 if (!strcmp(pCur->pVt->pszName, pVt->pszName))
236 return VERR_ALREADY_EXISTS;
237 pPrev = pCur;
238 }
239
240 /*
241 * Create a new record and add it to the end of the list.
242 */
243 PRTDBGMODREGIMG pReg = (PRTDBGMODREGIMG)RTMemAlloc(sizeof(*pReg));
244 if (!pReg)
245 return VERR_NO_MEMORY;
246 pReg->pVt = pVt;
247 pReg->cUsers = 0;
248 pReg->pNext = NULL;
249 if (pPrev)
250 pPrev->pNext = pReg;
251 else
252 g_pImgHead = pReg;
253 return VINF_SUCCESS;
254}
255
256
257/**
258 * Do-once callback that initializes the read/write semaphore and registers
259 * the built-in interpreters.
260 *
261 * @returns IPRT status code.
262 * @param pvUser NULL.
263 */
264static DECLCALLBACK(int) rtDbgModInitOnce(void *pvUser)
265{
266 NOREF(pvUser);
267
268 /*
269 * Create the semaphore and string cache.
270 */
271 int rc = RTSemRWCreate(&g_hDbgModRWSem);
272 AssertRCReturn(rc, rc);
273
274 rc = RTStrCacheCreate(&g_hDbgModStrCache, "RTDBGMOD");
275 if (RT_SUCCESS(rc))
276 {
277 /*
278 * Register the interpreters.
279 */
280 rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgNm);
281 if (RT_SUCCESS(rc))
282 rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgDwarf);
283 if (RT_SUCCESS(rc))
284 rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgCodeView);
285#ifdef RT_OS_WINDOWS
286 if (RT_SUCCESS(rc))
287 rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgDbgHelp);
288#endif
289 if (RT_SUCCESS(rc))
290 rc = rtDbgModImageInterpreterRegister(&g_rtDbgModVtImgLdr);
291 if (RT_SUCCESS(rc))
292 {
293 /*
294 * Finally, register the IPRT cleanup callback.
295 */
296 rc = RTTermRegisterCallback(rtDbgModTermCallback, NULL);
297 if (RT_SUCCESS(rc))
298 return VINF_SUCCESS;
299
300 /* bail out: use the termination callback. */
301 }
302 }
303 else
304 g_hDbgModStrCache = NIL_RTSTRCACHE;
305 rtDbgModTermCallback(RTTERMREASON_UNLOAD, 0, NULL);
306 return rc;
307}
308
309
310/**
311 * Performs lazy init of our global variables.
312 * @returns IPRT status code.
313 */
314DECLINLINE(int) rtDbgModLazyInit(void)
315{
316 return RTOnce(&g_rtDbgModOnce, rtDbgModInitOnce, NULL);
317}
318
319
320RTDECL(int) RTDbgModCreate(PRTDBGMOD phDbgMod, const char *pszName, RTUINTPTR cbSeg, uint32_t fFlags)
321{
322 /*
323 * Input validation and lazy initialization.
324 */
325 AssertPtrReturn(phDbgMod, VERR_INVALID_POINTER);
326 *phDbgMod = NIL_RTDBGMOD;
327 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
328 AssertReturn(*pszName, VERR_INVALID_PARAMETER);
329 AssertReturn(fFlags == 0 || fFlags == RTDBGMOD_F_NOT_DEFERRED, VERR_INVALID_PARAMETER);
330
331 int rc = rtDbgModLazyInit();
332 if (RT_FAILURE(rc))
333 return rc;
334
335 /*
336 * Allocate a new module instance.
337 */
338 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgMod));
339 if (!pDbgMod)
340 return VERR_NO_MEMORY;
341 pDbgMod->u32Magic = RTDBGMOD_MAGIC;
342 pDbgMod->cRefs = 1;
343 rc = RTCritSectInit(&pDbgMod->CritSect);
344 if (RT_SUCCESS(rc))
345 {
346 pDbgMod->pszImgFileSpecified = RTStrCacheEnter(g_hDbgModStrCache, pszName);
347 pDbgMod->pszName = RTStrCacheEnterLower(g_hDbgModStrCache, RTPathFilenameEx(pszName, RTPATH_STR_F_STYLE_DOS));
348 if (pDbgMod->pszName)
349 {
350 rc = rtDbgModContainerCreate(pDbgMod, cbSeg);
351 if (RT_SUCCESS(rc))
352 {
353 *phDbgMod = pDbgMod;
354 return rc;
355 }
356 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
357 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
358 }
359 RTCritSectDelete(&pDbgMod->CritSect);
360 }
361
362 RTMemFree(pDbgMod);
363 return rc;
364}
365RT_EXPORT_SYMBOL(RTDbgModCreate);
366
367
368RTDECL(int) RTDbgModCreateFromMap(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName,
369 RTUINTPTR uSubtrahend, RTDBGCFG hDbgCfg)
370{
371 RT_NOREF_PV(hDbgCfg);
372
373 /*
374 * Input validation and lazy initialization.
375 */
376 AssertPtrReturn(phDbgMod, VERR_INVALID_POINTER);
377 *phDbgMod = NIL_RTDBGMOD;
378 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
379 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
380 AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
381 AssertReturn(uSubtrahend == 0, VERR_NOT_IMPLEMENTED); /** @todo implement uSubtrahend. */
382
383 int rc = rtDbgModLazyInit();
384 if (RT_FAILURE(rc))
385 return rc;
386
387 if (!pszName)
388 pszName = RTPathFilenameEx(pszFilename, RTPATH_STR_F_STYLE_DOS);
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 = RTStrCacheEnterLower(g_hDbgModStrCache, pszName);
402 if (pDbgMod->pszName)
403 {
404 pDbgMod->pszDbgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
405 if (pDbgMod->pszDbgFile)
406 {
407 /*
408 * Try the map file readers.
409 */
410 rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
411 if (RT_SUCCESS(rc))
412 {
413 rc = VERR_DBG_NO_MATCHING_INTERPRETER;
414 for (PRTDBGMODREGDBG pCur = g_pDbgHead; pCur; pCur = pCur->pNext)
415 {
416 if (pCur->pVt->fSupports & RT_DBGTYPE_MAP)
417 {
418 pDbgMod->pDbgVt = pCur->pVt;
419 pDbgMod->pvDbgPriv = NULL;
420 rc = pCur->pVt->pfnTryOpen(pDbgMod, RTLDRARCH_WHATEVER);
421 if (RT_SUCCESS(rc))
422 {
423 ASMAtomicIncU32(&pCur->cUsers);
424 RTSemRWReleaseRead(g_hDbgModRWSem);
425
426 *phDbgMod = pDbgMod;
427 return rc;
428 }
429 }
430 }
431
432 /* bail out */
433 RTSemRWReleaseRead(g_hDbgModRWSem);
434 }
435 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
436 }
437 else
438 rc = VERR_NO_STR_MEMORY;
439 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszDbgFile);
440 }
441 else
442 rc = VERR_NO_STR_MEMORY;
443 RTCritSectDelete(&pDbgMod->CritSect);
444 }
445
446 RTMemFree(pDbgMod);
447 return rc;
448}
449RT_EXPORT_SYMBOL(RTDbgModCreateFromMap);
450
451
452
453/*
454 *
455 * E x e c u t a b l e I m a g e F i l e s
456 * E x e c u t a b l e I m a g e F i l e s
457 * E x e c u t a b l e I m a g e F i l e s
458 *
459 */
460
461
462/**
463 * Opens debug information for an image.
464 *
465 * @returns IPRT status code
466 * @param pDbgMod The debug module structure.
467 *
468 * @note This will generally not look for debug info stored in external
469 * files. rtDbgModFromPeImageExtDbgInfoCallback can help with that.
470 */
471static int rtDbgModOpenDebugInfoInsideImage(PRTDBGMODINT pDbgMod)
472{
473 AssertReturn(!pDbgMod->pDbgVt, VERR_DBG_MOD_IPE);
474 AssertReturn(pDbgMod->pImgVt, VERR_DBG_MOD_IPE);
475
476 int rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
477 if (RT_SUCCESS(rc))
478 {
479 for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
480 {
481 pDbgMod->pDbgVt = pDbg->pVt;
482 pDbgMod->pvDbgPriv = NULL;
483 rc = pDbg->pVt->pfnTryOpen(pDbgMod, pDbgMod->pImgVt->pfnGetArch(pDbgMod));
484 if (RT_SUCCESS(rc))
485 {
486 /*
487 * That's it!
488 */
489 ASMAtomicIncU32(&pDbg->cUsers);
490 RTSemRWReleaseRead(g_hDbgModRWSem);
491 return VINF_SUCCESS;
492 }
493
494 pDbgMod->pDbgVt = NULL;
495 Assert(pDbgMod->pvDbgPriv == NULL);
496 }
497 RTSemRWReleaseRead(g_hDbgModRWSem);
498 }
499
500 return VERR_DBG_NO_MATCHING_INTERPRETER;
501}
502
503
504/** @callback_method_impl{FNRTDBGCFGOPEN} */
505static DECLCALLBACK(int) rtDbgModExtDbgInfoOpenCallback(RTDBGCFG hDbgCfg, const char *pszFilename, void *pvUser1, void *pvUser2)
506{
507 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)pvUser1;
508 PCRTLDRDBGINFO pDbgInfo = (PCRTLDRDBGINFO)pvUser2;
509 RT_NOREF_PV(pDbgInfo); /** @todo consider a more direct search for a interpreter. */
510 RT_NOREF_PV(hDbgCfg);
511
512 Assert(!pDbgMod->pDbgVt);
513 Assert(!pDbgMod->pvDbgPriv);
514 Assert(!pDbgMod->pszDbgFile);
515 Assert(pDbgMod->pImgVt);
516
517 /*
518 * Set the debug file name and try possible interpreters.
519 */
520 pDbgMod->pszDbgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
521
522 int rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
523 if (RT_SUCCESS(rc))
524 {
525 for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
526 {
527 pDbgMod->pDbgVt = pDbg->pVt;
528 pDbgMod->pvDbgPriv = NULL;
529 rc = pDbg->pVt->pfnTryOpen(pDbgMod, pDbgMod->pImgVt->pfnGetArch(pDbgMod));
530 if (RT_SUCCESS(rc))
531 {
532 /*
533 * Got it!
534 */
535 ASMAtomicIncU32(&pDbg->cUsers);
536 RTSemRWReleaseRead(g_hDbgModRWSem);
537 return VINF_CALLBACK_RETURN;
538 }
539
540 pDbgMod->pDbgVt = NULL;
541 Assert(pDbgMod->pvDbgPriv == NULL);
542 }
543 RTSemRWReleaseRead(g_hDbgModRWSem);
544 }
545
546 /* No joy. */
547 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszDbgFile);
548 pDbgMod->pszDbgFile = NULL;
549 return rc;
550}
551
552
553/**
554 * Argument package used by rtDbgModOpenDebugInfoExternalToImage.
555 */
556typedef struct RTDBGMODOPENDIETI
557{
558 PRTDBGMODINT pDbgMod;
559 RTDBGCFG hDbgCfg;
560} RTDBGMODOPENDIETI;
561
562
563/** @callback_method_impl{FNRTLDRENUMDBG} */
564static DECLCALLBACK(int)
565rtDbgModOpenDebugInfoExternalToImageCallback(RTLDRMOD hLdrMod, PCRTLDRDBGINFO pDbgInfo, void *pvUser)
566{
567 RTDBGMODOPENDIETI *pArgs = (RTDBGMODOPENDIETI *)pvUser;
568 RT_NOREF_PV(hLdrMod);
569
570 Assert(pDbgInfo->enmType > RTLDRDBGINFOTYPE_INVALID && pDbgInfo->enmType < RTLDRDBGINFOTYPE_END);
571 const char *pszExtFile = pDbgInfo->pszExtFile;
572 if (!pszExtFile)
573 {
574 /*
575 * If a external debug type comes without a file name, calculate a
576 * likely debug filename for it. (Hack for NT4 drivers.)
577 */
578 const char *pszExt = NULL;
579 if (pDbgInfo->enmType == RTLDRDBGINFOTYPE_CODEVIEW_DBG)
580 pszExt = ".dbg";
581 else if ( pDbgInfo->enmType == RTLDRDBGINFOTYPE_CODEVIEW_PDB20
582 || pDbgInfo->enmType == RTLDRDBGINFOTYPE_CODEVIEW_PDB70)
583 pszExt = ".pdb";
584 if (pszExt && pArgs->pDbgMod->pszName)
585 {
586 size_t cchName = strlen(pArgs->pDbgMod->pszName);
587 char *psz = (char *)alloca(cchName + strlen(pszExt) + 1);
588 if (psz)
589 {
590 memcpy(psz, pArgs->pDbgMod->pszName, cchName + 1);
591 RTPathStripSuffix(psz);
592 pszExtFile = strcat(psz, pszExt);
593 }
594 }
595
596 if (!pszExtFile)
597 {
598 Log2(("rtDbgModOpenDebugInfoExternalToImageCallback: enmType=%d\n", pDbgInfo->enmType));
599 return VINF_SUCCESS;
600 }
601 }
602
603 /*
604 * Switch on type and call the appropriate search function.
605 */
606 int rc;
607 switch (pDbgInfo->enmType)
608 {
609 case RTLDRDBGINFOTYPE_CODEVIEW_PDB70:
610 rc = RTDbgCfgOpenPdb70(pArgs->hDbgCfg, pszExtFile,
611 &pDbgInfo->u.Pdb70.Uuid,
612 pDbgInfo->u.Pdb70.uAge,
613 rtDbgModExtDbgInfoOpenCallback, pArgs->pDbgMod, (void *)pDbgInfo);
614 break;
615
616 case RTLDRDBGINFOTYPE_CODEVIEW_PDB20:
617 rc = RTDbgCfgOpenPdb20(pArgs->hDbgCfg, pszExtFile,
618 pDbgInfo->u.Pdb20.cbImage,
619 pDbgInfo->u.Pdb20.uTimestamp,
620 pDbgInfo->u.Pdb20.uAge,
621 rtDbgModExtDbgInfoOpenCallback, pArgs->pDbgMod, (void *)pDbgInfo);
622 break;
623
624 case RTLDRDBGINFOTYPE_CODEVIEW_DBG:
625 rc = RTDbgCfgOpenDbg(pArgs->hDbgCfg, pszExtFile,
626 pDbgInfo->u.Dbg.cbImage,
627 pDbgInfo->u.Dbg.uTimestamp,
628 rtDbgModExtDbgInfoOpenCallback, pArgs->pDbgMod, (void *)pDbgInfo);
629 break;
630
631 case RTLDRDBGINFOTYPE_DWARF_DWO:
632 rc = RTDbgCfgOpenDwo(pArgs->hDbgCfg, pszExtFile,
633 pDbgInfo->u.Dwo.uCrc32,
634 rtDbgModExtDbgInfoOpenCallback, pArgs->pDbgMod, (void *)pDbgInfo);
635 break;
636
637 default:
638 Log(("rtDbgModOpenDebugInfoExternalToImageCallback: Don't know how to handle enmType=%d and pszFileExt=%s\n",
639 pDbgInfo->enmType, pszExtFile));
640 return VERR_DBG_TODO;
641 }
642 if (RT_SUCCESS(rc))
643 {
644 LogFlow(("RTDbgMod: Successfully opened external debug info '%s' for '%s'\n",
645 pArgs->pDbgMod->pszDbgFile, pArgs->pDbgMod->pszImgFile));
646 return VINF_CALLBACK_RETURN;
647 }
648 Log(("rtDbgModOpenDebugInfoExternalToImageCallback: '%s' (enmType=%d) for '%s' -> %Rrc\n",
649 pszExtFile, pDbgInfo->enmType, pArgs->pDbgMod->pszImgFile, rc));
650 return rc;
651}
652
653
654/**
655 * Opens debug info listed in the image that is stored in a separate file.
656 *
657 * @returns IPRT status code
658 * @param pDbgMod The debug module.
659 * @param hDbgCfg The debug config. Can be NIL.
660 */
661static int rtDbgModOpenDebugInfoExternalToImage(PRTDBGMODINT pDbgMod, RTDBGCFG hDbgCfg)
662{
663 Assert(!pDbgMod->pDbgVt);
664
665 RTDBGMODOPENDIETI Args;
666 Args.pDbgMod = pDbgMod;
667 Args.hDbgCfg = hDbgCfg;
668 int rc = pDbgMod->pImgVt->pfnEnumDbgInfo(pDbgMod, rtDbgModOpenDebugInfoExternalToImageCallback, &Args);
669 if (RT_SUCCESS(rc) && pDbgMod->pDbgVt)
670 return VINF_SUCCESS;
671
672 LogFlow(("rtDbgModOpenDebugInfoExternalToImage: rc=%Rrc\n", rc));
673 return VERR_NOT_FOUND;
674}
675
676
677/** @callback_method_impl{FNRTDBGCFGOPEN} */
678static DECLCALLBACK(int) rtDbgModExtDbgInfoOpenCallback2(RTDBGCFG hDbgCfg, const char *pszFilename, void *pvUser1, void *pvUser2)
679{
680 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)pvUser1;
681 RT_NOREF_PV(pvUser2); /** @todo image matching string or smth. */
682 RT_NOREF_PV(hDbgCfg);
683
684 Assert(!pDbgMod->pDbgVt);
685 Assert(!pDbgMod->pvDbgPriv);
686 Assert(!pDbgMod->pszDbgFile);
687 Assert(pDbgMod->pImgVt);
688
689 /*
690 * Set the debug file name and try possible interpreters.
691 */
692 pDbgMod->pszDbgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
693
694 int rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
695 if (RT_SUCCESS(rc))
696 {
697 for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
698 {
699 pDbgMod->pDbgVt = pDbg->pVt;
700 pDbgMod->pvDbgPriv = NULL;
701 rc = pDbg->pVt->pfnTryOpen(pDbgMod, pDbgMod->pImgVt->pfnGetArch(pDbgMod));
702 if (RT_SUCCESS(rc))
703 {
704 /*
705 * Got it!
706 */
707 ASMAtomicIncU32(&pDbg->cUsers);
708 RTSemRWReleaseRead(g_hDbgModRWSem);
709 return VINF_CALLBACK_RETURN;
710 }
711 pDbgMod->pDbgVt = NULL;
712 Assert(pDbgMod->pvDbgPriv == NULL);
713 }
714 }
715
716 /* No joy. */
717 RTSemRWReleaseRead(g_hDbgModRWSem);
718 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszDbgFile);
719 pDbgMod->pszDbgFile = NULL;
720 return rc;
721}
722
723
724/**
725 * Opens external debug info that is not listed in the image.
726 *
727 * @returns IPRT status code
728 * @param pDbgMod The debug module.
729 * @param hDbgCfg The debug config. Can be NIL.
730 */
731static int rtDbgModOpenDebugInfoExternalToImage2(PRTDBGMODINT pDbgMod, RTDBGCFG hDbgCfg)
732{
733 int rc;
734 Assert(!pDbgMod->pDbgVt);
735 Assert(pDbgMod->pImgVt);
736
737 /*
738 * Figure out what to search for based on the image format.
739 */
740 const char *pszzExts = NULL;
741 RTLDRFMT enmFmt = pDbgMod->pImgVt->pfnGetFormat(pDbgMod);
742 switch (enmFmt)
743 {
744 case RTLDRFMT_MACHO:
745 {
746 RTUUID Uuid;
747 PRTUUID pUuid = &Uuid;
748 rc = pDbgMod->pImgVt->pfnQueryProp(pDbgMod, RTLDRPROP_UUID, &Uuid, sizeof(Uuid), NULL);
749 if (RT_FAILURE(rc))
750 pUuid = NULL;
751
752 rc = RTDbgCfgOpenDsymBundle(hDbgCfg, pDbgMod->pszImgFile, pUuid,
753 rtDbgModExtDbgInfoOpenCallback2, pDbgMod, NULL /*pvUser2*/);
754 if (RT_SUCCESS(rc))
755 return VINF_SUCCESS;
756 break;
757 }
758
759#if 0 /* Will be links in the image if these apply. .map readers for PE or ELF we don't have. */
760 case RTLDRFMT_ELF:
761 pszzExts = ".debug\0.dwo\0";
762 break;
763 case RTLDRFMT_PE:
764 pszzExts = ".map\0";
765 break;
766#endif
767#if 0 /* Haven't implemented .sym or .map file readers for OS/2 yet. */
768 case RTLDRFMT_LX:
769 pszzExts = ".sym\0.map\0";
770 break;
771#endif
772 default:
773 rc = VERR_NOT_IMPLEMENTED;
774 break;
775 }
776
777 NOREF(pszzExts);
778#if 0 /* Later */
779 if (pszzExts)
780 {
781
782 }
783#endif
784
785 LogFlow(("rtDbgModOpenDebugInfoExternalToImage2: rc=%Rrc\n", rc));
786 return VERR_NOT_FOUND;
787}
788
789
790RTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName,
791 RTLDRARCH enmArch, RTDBGCFG hDbgCfg)
792{
793 /*
794 * Input validation and lazy initialization.
795 */
796 AssertPtrReturn(phDbgMod, VERR_INVALID_POINTER);
797 *phDbgMod = NIL_RTDBGMOD;
798 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
799 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
800 AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
801 AssertReturn(enmArch > RTLDRARCH_INVALID && enmArch < RTLDRARCH_END, VERR_INVALID_PARAMETER);
802
803 int rc = rtDbgModLazyInit();
804 if (RT_FAILURE(rc))
805 return rc;
806
807 if (!pszName)
808 pszName = RTPathFilenameEx(pszFilename, RTPATH_STR_F_STYLE_DOS);
809
810 /*
811 * Allocate a new module instance.
812 */
813 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgMod));
814 if (!pDbgMod)
815 return VERR_NO_MEMORY;
816 pDbgMod->u32Magic = RTDBGMOD_MAGIC;
817 pDbgMod->cRefs = 1;
818 rc = RTCritSectInit(&pDbgMod->CritSect);
819 if (RT_SUCCESS(rc))
820 {
821 pDbgMod->pszName = RTStrCacheEnterLower(g_hDbgModStrCache, pszName);
822 if (pDbgMod->pszName)
823 {
824 pDbgMod->pszImgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
825 if (pDbgMod->pszImgFile)
826 {
827 RTStrCacheRetain(pDbgMod->pszImgFile);
828 pDbgMod->pszImgFileSpecified = pDbgMod->pszImgFile;
829
830 /*
831 * Find an image reader which groks the file.
832 */
833 rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
834 if (RT_SUCCESS(rc))
835 {
836 rc = VERR_DBG_NO_MATCHING_INTERPRETER;
837 PRTDBGMODREGIMG pImg;
838 for (pImg = g_pImgHead; pImg; pImg = pImg->pNext)
839 {
840 pDbgMod->pImgVt = pImg->pVt;
841 pDbgMod->pvImgPriv = NULL;
842 /** @todo need to specify some arch stuff here. */
843 rc = pImg->pVt->pfnTryOpen(pDbgMod, enmArch);
844 if (RT_SUCCESS(rc))
845 {
846 /*
847 * Image detected, but found no debug info we were
848 * able to understand.
849 */
850 /** @todo some generic way of matching image and debug info, flexible signature
851 * of some kind. Apple uses UUIDs, microsoft uses a UUID+age or a
852 * size+timestamp, and GNU a CRC32 (last time I checked). */
853 rc = rtDbgModOpenDebugInfoExternalToImage(pDbgMod, hDbgCfg);
854 if (RT_FAILURE(rc))
855 rc = rtDbgModOpenDebugInfoInsideImage(pDbgMod);
856 if (RT_FAILURE(rc))
857 rc = rtDbgModOpenDebugInfoExternalToImage2(pDbgMod, hDbgCfg);
858 if (RT_FAILURE(rc))
859 rc = rtDbgModCreateForExports(pDbgMod);
860 if (RT_SUCCESS(rc))
861 {
862 /*
863 * We're done!
864 */
865 ASMAtomicIncU32(&pImg->cUsers);
866 RTSemRWReleaseRead(g_hDbgModRWSem);
867
868 *phDbgMod = pDbgMod;
869 return VINF_SUCCESS;
870 }
871
872 /* Failed, close up the shop. */
873 pDbgMod->pImgVt->pfnClose(pDbgMod);
874 pDbgMod->pImgVt = NULL;
875 pDbgMod->pvImgPriv = NULL;
876 break;
877 }
878 }
879
880 /*
881 * Could it be a file containing raw debug info?
882 */
883 if (!pImg)
884 {
885 pDbgMod->pImgVt = NULL;
886 pDbgMod->pvImgPriv = NULL;
887 pDbgMod->pszDbgFile = pDbgMod->pszImgFile;
888 pDbgMod->pszImgFile = NULL;
889
890 for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
891 {
892 pDbgMod->pDbgVt = pDbg->pVt;
893 pDbgMod->pvDbgPriv = NULL;
894 rc = pDbg->pVt->pfnTryOpen(pDbgMod, enmArch);
895 if (RT_SUCCESS(rc))
896 {
897 /*
898 * That's it!
899 */
900 ASMAtomicIncU32(&pDbg->cUsers);
901 RTSemRWReleaseRead(g_hDbgModRWSem);
902
903 *phDbgMod = pDbgMod;
904 return rc;
905 }
906 }
907
908 pDbgMod->pszImgFile = pDbgMod->pszDbgFile;
909 pDbgMod->pszDbgFile = NULL;
910 }
911
912 /* bail out */
913 RTSemRWReleaseRead(g_hDbgModRWSem);
914 }
915 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFileSpecified);
916 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
917 }
918 else
919 rc = VERR_NO_STR_MEMORY;
920 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
921 }
922 else
923 rc = VERR_NO_STR_MEMORY;
924 RTCritSectDelete(&pDbgMod->CritSect);
925 }
926
927 RTMemFree(pDbgMod);
928 return rc;
929}
930RT_EXPORT_SYMBOL(RTDbgModCreateFromImage);
931
932
933
934
935
936/*
937 *
938 * P E I M A G E
939 * P E I M A G E
940 * P E I M A G E
941 *
942 */
943
944
945
946/** @callback_method_impl{FNRTDBGCFGOPEN} */
947static DECLCALLBACK(int) rtDbgModFromPeImageOpenCallback(RTDBGCFG hDbgCfg, const char *pszFilename, void *pvUser1, void *pvUser2)
948{
949 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)pvUser1;
950 PRTDBGMODDEFERRED pDeferred = (PRTDBGMODDEFERRED)pvUser2;
951 LogFlow(("rtDbgModFromPeImageOpenCallback: %s\n", pszFilename));
952 RT_NOREF_PV(hDbgCfg);
953
954 Assert(pDbgMod->pImgVt == NULL);
955 Assert(pDbgMod->pvImgPriv == NULL);
956 Assert(pDbgMod->pDbgVt == NULL);
957 Assert(pDbgMod->pvDbgPriv == NULL);
958
959 /*
960 * Replace the image file name while probing it.
961 */
962 const char *pszNewImgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
963 if (!pszNewImgFile)
964 return VERR_NO_STR_MEMORY;
965 const char *pszOldImgFile = pDbgMod->pszImgFile;
966 pDbgMod->pszImgFile = pszNewImgFile;
967
968 /*
969 * Find an image reader which groks the file.
970 */
971 int rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
972 if (RT_SUCCESS(rc))
973 {
974 rc = VERR_DBG_NO_MATCHING_INTERPRETER;
975 PRTDBGMODREGIMG pImg;
976 for (pImg = g_pImgHead; pImg; pImg = pImg->pNext)
977 {
978 pDbgMod->pImgVt = pImg->pVt;
979 pDbgMod->pvImgPriv = NULL;
980 rc = pImg->pVt->pfnTryOpen(pDbgMod, RTLDRARCH_WHATEVER);
981 if (RT_SUCCESS(rc))
982 break;
983 pDbgMod->pImgVt = NULL;
984 Assert(pDbgMod->pvImgPriv == NULL);
985 }
986 RTSemRWReleaseRead(g_hDbgModRWSem);
987 if (RT_SUCCESS(rc))
988 {
989 /*
990 * Check the deferred info.
991 */
992 RTUINTPTR cbImage = pDbgMod->pImgVt->pfnImageSize(pDbgMod);
993 if ( pDeferred->cbImage == 0
994 || pDeferred->cbImage == cbImage)
995 {
996 uint32_t uTimestamp = pDeferred->u.PeImage.uTimestamp; /** @todo add method for getting the timestamp. */
997 if ( pDeferred->u.PeImage.uTimestamp == 0
998 || pDeferred->u.PeImage.uTimestamp == uTimestamp)
999 {
1000 Log(("RTDbgMod: Found matching PE image '%s'\n", pszFilename));
1001
1002 /*
1003 * We found the executable image we need, now go find any
1004 * debug info associated with it. For PE images, this is
1005 * generally found in an external file, so we do a sweep
1006 * for that first.
1007 *
1008 * Then try open debug inside the module, and finally
1009 * falling back on exports.
1010 */
1011 rc = rtDbgModOpenDebugInfoExternalToImage(pDbgMod, pDeferred->hDbgCfg);
1012 if (RT_FAILURE(rc))
1013 rc = rtDbgModOpenDebugInfoInsideImage(pDbgMod);
1014 if (RT_FAILURE(rc))
1015 rc = rtDbgModCreateForExports(pDbgMod);
1016 if (RT_SUCCESS(rc))
1017 {
1018 RTStrCacheRelease(g_hDbgModStrCache, pszOldImgFile);
1019 return VINF_CALLBACK_RETURN;
1020 }
1021
1022 /* Something bad happened, just give up. */
1023 Log(("rtDbgModFromPeImageOpenCallback: rtDbgModCreateForExports failed: %Rrc\n", rc));
1024 }
1025 else
1026 {
1027 LogFlow(("rtDbgModFromPeImageOpenCallback: uTimestamp mismatch (found %#x, expected %#x) - %s\n",
1028 uTimestamp, pDeferred->u.PeImage.uTimestamp, pszFilename));
1029 rc = VERR_DBG_FILE_MISMATCH;
1030 }
1031 }
1032 else
1033 {
1034 LogFlow(("rtDbgModFromPeImageOpenCallback: cbImage mismatch (found %#x, expected %#x) - %s\n",
1035 cbImage, pDeferred->cbImage, pszFilename));
1036 rc = VERR_DBG_FILE_MISMATCH;
1037 }
1038
1039 pDbgMod->pImgVt->pfnClose(pDbgMod);
1040 pDbgMod->pImgVt = NULL;
1041 pDbgMod->pvImgPriv = NULL;
1042 }
1043 else
1044 LogFlow(("rtDbgModFromPeImageOpenCallback: Failed %Rrc - %s\n", rc, pszFilename));
1045 }
1046
1047 /* Restore image name. */
1048 pDbgMod->pszImgFile = pszOldImgFile;
1049 RTStrCacheRelease(g_hDbgModStrCache, pszNewImgFile);
1050 return rc;
1051}
1052
1053
1054/** @callback_method_impl{FNRTDBGMODDEFERRED} */
1055static DECLCALLBACK(int) rtDbgModFromPeImageDeferredCallback(PRTDBGMODINT pDbgMod, PRTDBGMODDEFERRED pDeferred)
1056{
1057 int rc;
1058
1059 Assert(pDbgMod->pszImgFile);
1060 if (!pDbgMod->pImgVt)
1061 rc = RTDbgCfgOpenPeImage(pDeferred->hDbgCfg, pDbgMod->pszImgFile,
1062 pDeferred->cbImage, pDeferred->u.PeImage.uTimestamp,
1063 rtDbgModFromPeImageOpenCallback, pDbgMod, pDeferred);
1064 else
1065 {
1066 rc = rtDbgModOpenDebugInfoExternalToImage(pDbgMod, pDeferred->hDbgCfg);
1067 if (RT_FAILURE(rc))
1068 rc = rtDbgModOpenDebugInfoInsideImage(pDbgMod);
1069 if (RT_FAILURE(rc))
1070 rc = rtDbgModCreateForExports(pDbgMod);
1071 }
1072 return rc;
1073}
1074
1075
1076RTDECL(int) RTDbgModCreateFromPeImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName,
1077 PRTLDRMOD phLdrMod, uint32_t cbImage, uint32_t uTimestamp, RTDBGCFG hDbgCfg)
1078{
1079 /*
1080 * Input validation and lazy initialization.
1081 */
1082 AssertPtrReturn(phDbgMod, VERR_INVALID_POINTER);
1083 *phDbgMod = NIL_RTDBGMOD;
1084 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1085 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
1086 if (!pszName)
1087 pszName = RTPathFilenameEx(pszFilename, RTPATH_STR_F_STYLE_DOS);
1088 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
1089 AssertPtrNullReturn(phLdrMod, VERR_INVALID_POINTER);
1090 RTLDRMOD hLdrMod = phLdrMod ? *phLdrMod : NIL_RTLDRMOD;
1091 AssertReturn(hLdrMod == NIL_RTLDRMOD || RTLdrSize(hLdrMod) != ~(size_t)0, VERR_INVALID_HANDLE);
1092
1093 int rc = rtDbgModLazyInit();
1094 if (RT_FAILURE(rc))
1095 return rc;
1096
1097 uint64_t fDbgCfg = 0;
1098 if (hDbgCfg)
1099 {
1100 rc = RTDbgCfgQueryUInt(hDbgCfg, RTDBGCFGPROP_FLAGS, &fDbgCfg);
1101 AssertRCReturn(rc, rc);
1102 }
1103
1104 /*
1105 * Allocate a new module instance.
1106 */
1107 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgMod));
1108 if (!pDbgMod)
1109 return VERR_NO_MEMORY;
1110 pDbgMod->u32Magic = RTDBGMOD_MAGIC;
1111 pDbgMod->cRefs = 1;
1112 rc = RTCritSectInit(&pDbgMod->CritSect);
1113 if (RT_SUCCESS(rc))
1114 {
1115 pDbgMod->pszName = RTStrCacheEnterLower(g_hDbgModStrCache, pszName);
1116 if (pDbgMod->pszName)
1117 {
1118 pDbgMod->pszImgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
1119 if (pDbgMod->pszImgFile)
1120 {
1121 RTStrCacheRetain(pDbgMod->pszImgFile);
1122 pDbgMod->pszImgFileSpecified = pDbgMod->pszImgFile;
1123
1124 /*
1125 * If we have a loader module, we must instantiate the loader
1126 * side of things regardless of the deferred setting.
1127 */
1128 if (hLdrMod != NIL_RTLDRMOD)
1129 {
1130 if (!cbImage)
1131 cbImage = (uint32_t)RTLdrSize(hLdrMod);
1132 pDbgMod->pImgVt = &g_rtDbgModVtImgLdr;
1133
1134 rc = rtDbgModLdrOpenFromHandle(pDbgMod, hLdrMod);
1135 }
1136 if (RT_SUCCESS(rc))
1137 {
1138 /* We now own the loader handle, so clear the caller variable. */
1139 if (phLdrMod)
1140 *phLdrMod = NIL_RTLDRMOD;
1141
1142 /*
1143 * Do it now or procrastinate?
1144 */
1145 if (!(fDbgCfg & RTDBGCFG_FLAGS_DEFERRED) || !cbImage)
1146 {
1147 RTDBGMODDEFERRED Deferred;
1148 Deferred.cbImage = cbImage;
1149 Deferred.hDbgCfg = hDbgCfg;
1150 Deferred.u.PeImage.uTimestamp = uTimestamp;
1151 rc = rtDbgModFromPeImageDeferredCallback(pDbgMod, &Deferred);
1152 }
1153 else
1154 {
1155 PRTDBGMODDEFERRED pDeferred;
1156 rc = rtDbgModDeferredCreate(pDbgMod, rtDbgModFromPeImageDeferredCallback, cbImage, hDbgCfg, 0,
1157 &pDeferred);
1158 if (RT_SUCCESS(rc))
1159 pDeferred->u.PeImage.uTimestamp = uTimestamp;
1160 }
1161 if (RT_SUCCESS(rc))
1162 {
1163 *phDbgMod = pDbgMod;
1164 return VINF_SUCCESS;
1165 }
1166
1167 /* Failed, bail out. */
1168 if (hLdrMod != NIL_RTLDRMOD)
1169 {
1170 Assert(pDbgMod->pImgVt);
1171 pDbgMod->pImgVt->pfnClose(pDbgMod);
1172 }
1173 }
1174 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
1175 }
1176 else
1177 rc = VERR_NO_STR_MEMORY;
1178 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFileSpecified);
1179 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
1180 }
1181 else
1182 rc = VERR_NO_STR_MEMORY;
1183 RTCritSectDelete(&pDbgMod->CritSect);
1184 }
1185
1186 RTMemFree(pDbgMod);
1187 return rc;
1188}
1189RT_EXPORT_SYMBOL(RTDbgModCreateFromPeImage);
1190
1191
1192
1193
1194/*
1195 *
1196 * M a c h - O I M A G E
1197 * M a c h - O I M A G E
1198 * M a c h - O I M A G E
1199 *
1200 */
1201
1202
1203/**
1204 * Argument package used when opening Mach-O images and .dSYMs files.
1205 */
1206typedef struct RTDBGMODMACHOARGS
1207{
1208 /** For use more internal use in file locator callbacks. */
1209 RTLDRARCH enmArch;
1210 /** For use more internal use in file locator callbacks. */
1211 PCRTUUID pUuid;
1212 /** For use more internal use in file locator callbacks. */
1213 bool fOpenImage;
1214} RTDBGMODMACHOARGS;
1215/** Pointer to a const segment package. */
1216typedef RTDBGMODMACHOARGS const *PCRTDBGMODMACHOARGS;
1217
1218
1219
1220/** @callback_method_impl{FNRTDBGCFGOPEN} */
1221static DECLCALLBACK(int)
1222rtDbgModFromMachOImageOpenDsymMachOCallback(RTDBGCFG hDbgCfg, const char *pszFilename, void *pvUser1, void *pvUser2)
1223{
1224 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)pvUser1;
1225 PCRTDBGMODMACHOARGS pArgs = (PCRTDBGMODMACHOARGS)pvUser2;
1226 RT_NOREF_PV(hDbgCfg);
1227
1228 Assert(!pDbgMod->pDbgVt);
1229 Assert(!pDbgMod->pvDbgPriv);
1230 Assert(!pDbgMod->pszDbgFile);
1231 Assert(!pDbgMod->pImgVt);
1232 Assert(!pDbgMod->pvDbgPriv);
1233 Assert(pDbgMod->pszImgFile);
1234 Assert(pDbgMod->pszImgFileSpecified);
1235
1236 const char *pszImgFileOrg = pDbgMod->pszImgFile;
1237 pDbgMod->pszImgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
1238 if (!pDbgMod->pszImgFile)
1239 return VERR_NO_STR_MEMORY;
1240 RTStrCacheRetain(pDbgMod->pszImgFile);
1241 pDbgMod->pszDbgFile = pDbgMod->pszImgFile;
1242
1243 /*
1244 * Try image interpreters as the dwarf file inside the dSYM bundle is a
1245 * Mach-O file with dwarf debug sections insides it and no code or data.
1246 */
1247 int rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
1248 if (RT_SUCCESS(rc))
1249 {
1250 rc = VERR_DBG_NO_MATCHING_INTERPRETER;
1251 PRTDBGMODREGIMG pImg;
1252 for (pImg = g_pImgHead; pImg; pImg = pImg->pNext)
1253 {
1254 pDbgMod->pImgVt = pImg->pVt;
1255 pDbgMod->pvImgPriv = NULL;
1256 rc = pImg->pVt->pfnTryOpen(pDbgMod, pArgs->enmArch);
1257 if (RT_SUCCESS(rc))
1258 break;
1259 pDbgMod->pImgVt = NULL;
1260 Assert(pDbgMod->pvImgPriv == NULL);
1261 }
1262
1263 if (RT_SUCCESS(rc))
1264 {
1265 /*
1266 * Check the UUID if one was given.
1267 */
1268 if (pArgs->pUuid)
1269 {
1270 RTUUID UuidOpened;
1271 rc = pDbgMod->pImgVt->pfnQueryProp(pDbgMod, RTLDRPROP_UUID, &UuidOpened, sizeof(UuidOpened), NULL);
1272 if (RT_SUCCESS(rc))
1273 {
1274 if (RTUuidCompare(&UuidOpened, pArgs->pUuid) != 0)
1275 rc = VERR_DBG_FILE_MISMATCH;
1276 }
1277 else if (rc == VERR_NOT_FOUND || rc == VERR_NOT_IMPLEMENTED)
1278 rc = VERR_DBG_FILE_MISMATCH;
1279 }
1280 if (RT_SUCCESS(rc))
1281 {
1282 /*
1283 * Pass it to the DWARF reader(s). Careful to restrict this or
1284 * the dbghelp wrapper may end up being overly helpful.
1285 */
1286 for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
1287 {
1288 if (pDbg->pVt->fSupports & (RT_DBGTYPE_DWARF | RT_DBGTYPE_STABS | RT_DBGTYPE_WATCOM))
1289
1290 {
1291 pDbgMod->pDbgVt = pDbg->pVt;
1292 pDbgMod->pvDbgPriv = NULL;
1293 rc = pDbg->pVt->pfnTryOpen(pDbgMod, pDbgMod->pImgVt->pfnGetArch(pDbgMod));
1294 if (RT_SUCCESS(rc))
1295 {
1296 /*
1297 * Got it!
1298 */
1299 ASMAtomicIncU32(&pDbg->cUsers);
1300 RTSemRWReleaseRead(g_hDbgModRWSem);
1301 RTStrCacheRelease(g_hDbgModStrCache, pszImgFileOrg);
1302 return VINF_CALLBACK_RETURN;
1303 }
1304 pDbgMod->pDbgVt = NULL;
1305 Assert(pDbgMod->pvDbgPriv == NULL);
1306 }
1307 }
1308
1309 /*
1310 * Likely fallback for when opening image.
1311 */
1312 if (pArgs->fOpenImage)
1313 {
1314 rc = rtDbgModCreateForExports(pDbgMod);
1315 if (RT_SUCCESS(rc))
1316 {
1317 /*
1318 * Done.
1319 */
1320 RTSemRWReleaseRead(g_hDbgModRWSem);
1321 RTStrCacheRelease(g_hDbgModStrCache, pszImgFileOrg);
1322 return VINF_CALLBACK_RETURN;
1323 }
1324 }
1325 }
1326
1327 pDbgMod->pImgVt->pfnClose(pDbgMod);
1328 pDbgMod->pImgVt = NULL;
1329 pDbgMod->pvImgPriv = NULL;
1330 }
1331 }
1332
1333 /* No joy. */
1334 RTSemRWReleaseRead(g_hDbgModRWSem);
1335 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
1336 pDbgMod->pszImgFile = pszImgFileOrg;
1337 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszDbgFile);
1338 pDbgMod->pszDbgFile = NULL;
1339 return rc;
1340}
1341
1342
1343static int rtDbgModFromMachOImageWorker(PRTDBGMODINT pDbgMod, RTLDRARCH enmArch, uint32_t cbImage,
1344 uint32_t cSegs, PCRTDBGSEGMENT paSegs, PCRTUUID pUuid, RTDBGCFG hDbgCfg)
1345{
1346 RT_NOREF_PV(cbImage); RT_NOREF_PV(cSegs); RT_NOREF_PV(paSegs);
1347
1348 RTDBGMODMACHOARGS Args;
1349 Args.enmArch = enmArch;
1350 Args.pUuid = pUuid && RTUuidIsNull(pUuid) ? pUuid : NULL;
1351 Args.fOpenImage = false;
1352
1353 /*
1354 * Search for the .dSYM bundle first, since that's generally all we need.
1355 */
1356 int rc = RTDbgCfgOpenDsymBundle(hDbgCfg, pDbgMod->pszImgFile, pUuid,
1357 rtDbgModFromMachOImageOpenDsymMachOCallback, pDbgMod, &Args);
1358 if (RT_FAILURE(rc))
1359 {
1360 /*
1361 * If we cannot get at the .dSYM, try the executable image.
1362 */
1363 Args.fOpenImage = true;
1364 rc = RTDbgCfgOpenMachOImage(hDbgCfg, pDbgMod->pszImgFile, pUuid,
1365 rtDbgModFromMachOImageOpenDsymMachOCallback, pDbgMod, &Args);
1366 }
1367 return rc;
1368}
1369
1370
1371/** @callback_method_impl{FNRTDBGMODDEFERRED} */
1372static DECLCALLBACK(int) rtDbgModFromMachOImageDeferredCallback(PRTDBGMODINT pDbgMod, PRTDBGMODDEFERRED pDeferred)
1373{
1374 return rtDbgModFromMachOImageWorker(pDbgMod, pDeferred->u.MachO.enmArch, pDeferred->cbImage,
1375 pDeferred->u.MachO.cSegs, pDeferred->u.MachO.aSegs,
1376 &pDeferred->u.MachO.Uuid, pDeferred->hDbgCfg);
1377}
1378
1379
1380RTDECL(int) RTDbgModCreateFromMachOImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName,
1381 RTLDRARCH enmArch, uint32_t cbImage, uint32_t cSegs, PCRTDBGSEGMENT paSegs,
1382 PCRTUUID pUuid, RTDBGCFG hDbgCfg, uint32_t fFlags)
1383{
1384 /*
1385 * Input validation and lazy initialization.
1386 */
1387 AssertPtrReturn(phDbgMod, VERR_INVALID_POINTER);
1388 *phDbgMod = NIL_RTDBGMOD;
1389 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1390 AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
1391 if (!pszName)
1392 pszName = RTPathFilenameEx(pszFilename, RTPATH_STR_F_STYLE_HOST);
1393 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
1394 if (cSegs)
1395 {
1396 AssertReturn(cSegs < 1024, VERR_INVALID_PARAMETER);
1397 AssertPtrReturn(paSegs, VERR_INVALID_POINTER);
1398 AssertReturn(!cbImage, VERR_INVALID_PARAMETER);
1399 }
1400 AssertReturn(cbImage || cSegs, VERR_INVALID_PARAMETER);
1401 AssertPtrNullReturn(pUuid, VERR_INVALID_POINTER);
1402 AssertReturn(!(fFlags & ~(RTDBGMOD_F_NOT_DEFERRED)), VERR_INVALID_PARAMETER);
1403
1404 int rc = rtDbgModLazyInit();
1405 if (RT_FAILURE(rc))
1406 return rc;
1407
1408 uint64_t fDbgCfg = 0;
1409 if (hDbgCfg)
1410 {
1411 rc = RTDbgCfgQueryUInt(hDbgCfg, RTDBGCFGPROP_FLAGS, &fDbgCfg);
1412 AssertRCReturn(rc, rc);
1413 }
1414
1415 /*
1416 * Allocate a new module instance.
1417 */
1418 PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgMod));
1419 if (!pDbgMod)
1420 return VERR_NO_MEMORY;
1421 pDbgMod->u32Magic = RTDBGMOD_MAGIC;
1422 pDbgMod->cRefs = 1;
1423 rc = RTCritSectInit(&pDbgMod->CritSect);
1424 if (RT_SUCCESS(rc))
1425 {
1426 pDbgMod->pszName = RTStrCacheEnterLower(g_hDbgModStrCache, pszName);
1427 if (pDbgMod->pszName)
1428 {
1429 pDbgMod->pszImgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
1430 if (pDbgMod->pszImgFile)
1431 {
1432 RTStrCacheRetain(pDbgMod->pszImgFile);
1433 pDbgMod->pszImgFileSpecified = pDbgMod->pszImgFile;
1434
1435 /*
1436 * Load it immediately?
1437 */
1438 if ( !(fDbgCfg & RTDBGCFG_FLAGS_DEFERRED)
1439 || cSegs /* for the time being. */
1440 || (!cbImage && !cSegs)
1441 || (fFlags & RTDBGMOD_F_NOT_DEFERRED) )
1442 rc = rtDbgModFromMachOImageWorker(pDbgMod, enmArch, cbImage, cSegs, paSegs, pUuid, hDbgCfg);
1443 else
1444 {
1445 /*
1446 * Procrastinate. Need image size atm.
1447 */
1448 PRTDBGMODDEFERRED pDeferred;
1449 rc = rtDbgModDeferredCreate(pDbgMod, rtDbgModFromMachOImageDeferredCallback, cbImage, hDbgCfg,
1450 RT_UOFFSETOF_DYN(RTDBGMODDEFERRED, u.MachO.aSegs[cSegs]),
1451 &pDeferred);
1452 if (RT_SUCCESS(rc))
1453 {
1454 pDeferred->u.MachO.Uuid = *pUuid;
1455 pDeferred->u.MachO.enmArch = enmArch;
1456 pDeferred->u.MachO.cSegs = cSegs;
1457 if (cSegs)
1458 memcpy(&pDeferred->u.MachO.aSegs, paSegs, cSegs * sizeof(paSegs[0]));
1459 }
1460 }
1461 if (RT_SUCCESS(rc))
1462 {
1463 *phDbgMod = pDbgMod;
1464 return VINF_SUCCESS;
1465 }
1466
1467 /* Failed, bail out. */
1468 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
1469 }
1470 else
1471 rc = VERR_NO_STR_MEMORY;
1472 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFileSpecified);
1473 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
1474 }
1475 else
1476 rc = VERR_NO_STR_MEMORY;
1477 RTCritSectDelete(&pDbgMod->CritSect);
1478 }
1479
1480 RTMemFree(pDbgMod);
1481 return rc;
1482}
1483
1484
1485
1486RT_EXPORT_SYMBOL(RTDbgModCreateFromMachOImage);
1487
1488
1489
1490/**
1491 * Destroys an module after the reference count has reached zero.
1492 *
1493 * @param pDbgMod The module instance.
1494 */
1495static void rtDbgModDestroy(PRTDBGMODINT pDbgMod)
1496{
1497 /*
1498 * Close the debug info interpreter first, then the image interpret.
1499 */
1500 RTCritSectEnter(&pDbgMod->CritSect); /* paranoia */
1501
1502 if (pDbgMod->pDbgVt)
1503 {
1504 pDbgMod->pDbgVt->pfnClose(pDbgMod);
1505 pDbgMod->pDbgVt = NULL;
1506 pDbgMod->pvDbgPriv = NULL;
1507 }
1508
1509 if (pDbgMod->pImgVt)
1510 {
1511 pDbgMod->pImgVt->pfnClose(pDbgMod);
1512 pDbgMod->pImgVt = NULL;
1513 pDbgMod->pvImgPriv = NULL;
1514 }
1515
1516 /*
1517 * Free the resources.
1518 */
1519 ASMAtomicWriteU32(&pDbgMod->u32Magic, ~RTDBGMOD_MAGIC);
1520 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
1521 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
1522 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFileSpecified);
1523 RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszDbgFile);
1524 RTCritSectLeave(&pDbgMod->CritSect); /* paranoia */
1525 RTCritSectDelete(&pDbgMod->CritSect);
1526 RTMemFree(pDbgMod);
1527}
1528
1529
1530RTDECL(uint32_t) RTDbgModRetain(RTDBGMOD hDbgMod)
1531{
1532 PRTDBGMODINT pDbgMod = hDbgMod;
1533 RTDBGMOD_VALID_RETURN_RC(pDbgMod, UINT32_MAX);
1534 return ASMAtomicIncU32(&pDbgMod->cRefs);
1535}
1536RT_EXPORT_SYMBOL(RTDbgModRetain);
1537
1538
1539RTDECL(uint32_t) RTDbgModRelease(RTDBGMOD hDbgMod)
1540{
1541 if (hDbgMod == NIL_RTDBGMOD)
1542 return 0;
1543 PRTDBGMODINT pDbgMod = hDbgMod;
1544 RTDBGMOD_VALID_RETURN_RC(pDbgMod, UINT32_MAX);
1545
1546 uint32_t cRefs = ASMAtomicDecU32(&pDbgMod->cRefs);
1547 if (!cRefs)
1548 rtDbgModDestroy(pDbgMod);
1549 return cRefs;
1550}
1551RT_EXPORT_SYMBOL(RTDbgModRelease);
1552
1553
1554RTDECL(const char *) RTDbgModName(RTDBGMOD hDbgMod)
1555{
1556 PRTDBGMODINT pDbgMod = hDbgMod;
1557 RTDBGMOD_VALID_RETURN_RC(pDbgMod, NULL);
1558 return pDbgMod->pszName;
1559}
1560RT_EXPORT_SYMBOL(RTDbgModName);
1561
1562
1563RTDECL(const char *) RTDbgModDebugFile(RTDBGMOD hDbgMod)
1564{
1565 PRTDBGMODINT pDbgMod = hDbgMod;
1566 RTDBGMOD_VALID_RETURN_RC(pDbgMod, NULL);
1567 if (pDbgMod->fDeferred || pDbgMod->fExports)
1568 return NULL;
1569 return pDbgMod->pszDbgFile;
1570}
1571RT_EXPORT_SYMBOL(RTDbgModDebugFile);
1572
1573
1574RTDECL(const char *) RTDbgModImageFile(RTDBGMOD hDbgMod)
1575{
1576 PRTDBGMODINT pDbgMod = hDbgMod;
1577 RTDBGMOD_VALID_RETURN_RC(pDbgMod, NULL);
1578 return pDbgMod->pszImgFileSpecified;
1579}
1580RT_EXPORT_SYMBOL(RTDbgModImageFile);
1581
1582
1583RTDECL(const char *) RTDbgModImageFileUsed(RTDBGMOD hDbgMod)
1584{
1585 PRTDBGMODINT pDbgMod = hDbgMod;
1586 RTDBGMOD_VALID_RETURN_RC(pDbgMod, NULL);
1587 return pDbgMod->pszImgFile == pDbgMod->pszImgFileSpecified ? NULL : pDbgMod->pszImgFile;
1588}
1589RT_EXPORT_SYMBOL(RTDbgModImageFileUsed);
1590
1591
1592RTDECL(bool) RTDbgModIsDeferred(RTDBGMOD hDbgMod)
1593{
1594 PRTDBGMODINT pDbgMod = hDbgMod;
1595 RTDBGMOD_VALID_RETURN_RC(pDbgMod, false);
1596 return pDbgMod->fDeferred;
1597}
1598
1599
1600RTDECL(bool) RTDbgModIsExports(RTDBGMOD hDbgMod)
1601{
1602 PRTDBGMODINT pDbgMod = hDbgMod;
1603 RTDBGMOD_VALID_RETURN_RC(pDbgMod, false);
1604 return pDbgMod->fExports;
1605}
1606
1607
1608RTDECL(int) RTDbgModRemoveAll(RTDBGMOD hDbgMod, bool fLeaveSegments)
1609{
1610 PRTDBGMODINT pDbgMod = hDbgMod;
1611 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1612
1613 RTDBGMOD_LOCK(pDbgMod);
1614
1615 /* Only possible on container modules. */
1616 int rc = VINF_SUCCESS;
1617 if (pDbgMod->pDbgVt != &g_rtDbgModVtDbgContainer)
1618 {
1619 if (fLeaveSegments)
1620 {
1621 rc = rtDbgModContainer_LineRemoveAll(pDbgMod);
1622 if (RT_SUCCESS(rc))
1623 rc = rtDbgModContainer_SymbolRemoveAll(pDbgMod);
1624 }
1625 else
1626 rc = rtDbgModContainer_RemoveAll(pDbgMod);
1627 }
1628 else
1629 rc = VERR_ACCESS_DENIED;
1630
1631 RTDBGMOD_UNLOCK(pDbgMod);
1632 return rc;
1633}
1634
1635
1636RTDECL(RTDBGSEGIDX) RTDbgModRvaToSegOff(RTDBGMOD hDbgMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
1637{
1638 PRTDBGMODINT pDbgMod = hDbgMod;
1639 RTDBGMOD_VALID_RETURN_RC(pDbgMod, NIL_RTDBGSEGIDX);
1640 RTDBGMOD_LOCK(pDbgMod);
1641
1642 RTDBGSEGIDX iSeg = pDbgMod->pDbgVt->pfnRvaToSegOff(pDbgMod, uRva, poffSeg);
1643
1644 RTDBGMOD_UNLOCK(pDbgMod);
1645 return iSeg;
1646}
1647RT_EXPORT_SYMBOL(RTDbgModRvaToSegOff);
1648
1649
1650RTDECL(uint64_t) RTDbgModGetTag(RTDBGMOD hDbgMod)
1651{
1652 PRTDBGMODINT pDbgMod = hDbgMod;
1653 RTDBGMOD_VALID_RETURN_RC(pDbgMod, 0);
1654 return pDbgMod->uTag;
1655}
1656RT_EXPORT_SYMBOL(RTDbgModGetTag);
1657
1658
1659RTDECL(int) RTDbgModSetTag(RTDBGMOD hDbgMod, uint64_t uTag)
1660{
1661 PRTDBGMODINT pDbgMod = hDbgMod;
1662 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1663 RTDBGMOD_LOCK(pDbgMod);
1664
1665 pDbgMod->uTag = uTag;
1666
1667 RTDBGMOD_UNLOCK(pDbgMod);
1668 return VINF_SUCCESS;
1669}
1670RT_EXPORT_SYMBOL(RTDbgModSetTag);
1671
1672
1673RTDECL(RTUINTPTR) RTDbgModImageSize(RTDBGMOD hDbgMod)
1674{
1675 PRTDBGMODINT pDbgMod = hDbgMod;
1676 RTDBGMOD_VALID_RETURN_RC(pDbgMod, RTUINTPTR_MAX);
1677 RTDBGMOD_LOCK(pDbgMod);
1678
1679 RTUINTPTR cbImage = pDbgMod->pDbgVt->pfnImageSize(pDbgMod);
1680
1681 RTDBGMOD_UNLOCK(pDbgMod);
1682 return cbImage;
1683}
1684RT_EXPORT_SYMBOL(RTDbgModImageSize);
1685
1686
1687RTDECL(RTLDRFMT) RTDbgModImageGetFormat(RTDBGMOD hDbgMod)
1688{
1689 PRTDBGMODINT pDbgMod = hDbgMod;
1690 RTDBGMOD_VALID_RETURN_RC(pDbgMod, RTLDRFMT_INVALID);
1691 RTDBGMOD_LOCK(pDbgMod);
1692
1693 RTLDRFMT enmFmt;
1694 if ( pDbgMod->pImgVt
1695 && pDbgMod->pImgVt->pfnGetFormat)
1696 enmFmt = pDbgMod->pImgVt->pfnGetFormat(pDbgMod);
1697 else
1698 enmFmt = RTLDRFMT_INVALID;
1699
1700 RTDBGMOD_UNLOCK(pDbgMod);
1701 return enmFmt;
1702}
1703RT_EXPORT_SYMBOL(RTDbgModImageGetFormat);
1704
1705
1706RTDECL(RTLDRARCH) RTDbgModImageGetArch(RTDBGMOD hDbgMod)
1707{
1708 PRTDBGMODINT pDbgMod = hDbgMod;
1709 RTDBGMOD_VALID_RETURN_RC(pDbgMod, RTLDRARCH_INVALID);
1710 RTDBGMOD_LOCK(pDbgMod);
1711
1712 RTLDRARCH enmArch;
1713 if ( pDbgMod->pImgVt
1714 && pDbgMod->pImgVt->pfnGetArch)
1715 enmArch = pDbgMod->pImgVt->pfnGetArch(pDbgMod);
1716 else
1717 enmArch = RTLDRARCH_WHATEVER;
1718
1719 RTDBGMOD_UNLOCK(pDbgMod);
1720 return enmArch;
1721}
1722RT_EXPORT_SYMBOL(RTDbgModImageGetArch);
1723
1724
1725RTDECL(int) RTDbgModImageQueryProp(RTDBGMOD hDbgMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf, size_t *pcbRet)
1726{
1727 PRTDBGMODINT pDbgMod = hDbgMod;
1728 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1729 AssertPtrNullReturn(pcbRet, VERR_INVALID_POINTER);
1730 RTDBGMOD_LOCK(pDbgMod);
1731
1732 int rc;
1733 if ( pDbgMod->pImgVt
1734 && pDbgMod->pImgVt->pfnQueryProp)
1735 rc = pDbgMod->pImgVt->pfnQueryProp(pDbgMod, enmProp, pvBuf, cbBuf, pcbRet);
1736 else
1737 rc = VERR_NOT_FOUND;
1738
1739 RTDBGMOD_UNLOCK(pDbgMod);
1740 return rc;
1741}
1742RT_EXPORT_SYMBOL(RTDbgModImageQueryProp);
1743
1744
1745RTDECL(int) RTDbgModSegmentAdd(RTDBGMOD hDbgMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName,
1746 uint32_t fFlags, PRTDBGSEGIDX piSeg)
1747{
1748 /*
1749 * Validate input.
1750 */
1751 PRTDBGMODINT pDbgMod = hDbgMod;
1752 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1753 AssertMsgReturn(uRva + cb >= uRva, ("uRva=%RTptr cb=%RTptr\n", uRva, cb), VERR_DBG_ADDRESS_WRAP);
1754 Assert(*pszName);
1755 size_t cchName = strlen(pszName);
1756 AssertReturn(cchName > 0, VERR_DBG_SEGMENT_NAME_OUT_OF_RANGE);
1757 AssertReturn(cchName < RTDBG_SEGMENT_NAME_LENGTH, VERR_DBG_SEGMENT_NAME_OUT_OF_RANGE);
1758 AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
1759 AssertPtrNull(piSeg);
1760 AssertMsgReturn(!piSeg || *piSeg == NIL_RTDBGSEGIDX || *piSeg <= RTDBGSEGIDX_LAST, ("%#x\n", *piSeg), VERR_DBG_SPECIAL_SEGMENT);
1761
1762 /*
1763 * Do the deed.
1764 */
1765 RTDBGMOD_LOCK(pDbgMod);
1766 int rc = pDbgMod->pDbgVt->pfnSegmentAdd(pDbgMod, uRva, cb, pszName, cchName, fFlags, piSeg);
1767 RTDBGMOD_UNLOCK(pDbgMod);
1768
1769 return rc;
1770
1771}
1772RT_EXPORT_SYMBOL(RTDbgModSegmentAdd);
1773
1774
1775RTDECL(RTDBGSEGIDX) RTDbgModSegmentCount(RTDBGMOD hDbgMod)
1776{
1777 PRTDBGMODINT pDbgMod = hDbgMod;
1778 RTDBGMOD_VALID_RETURN_RC(pDbgMod, NIL_RTDBGSEGIDX);
1779 RTDBGMOD_LOCK(pDbgMod);
1780
1781 RTDBGSEGIDX cSegs = pDbgMod->pDbgVt->pfnSegmentCount(pDbgMod);
1782
1783 RTDBGMOD_UNLOCK(pDbgMod);
1784 return cSegs;
1785}
1786RT_EXPORT_SYMBOL(RTDbgModSegmentCount);
1787
1788
1789RTDECL(int) RTDbgModSegmentByIndex(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
1790{
1791 AssertMsgReturn(iSeg <= RTDBGSEGIDX_LAST, ("%#x\n", iSeg), VERR_DBG_SPECIAL_SEGMENT);
1792 PRTDBGMODINT pDbgMod = hDbgMod;
1793 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1794 RTDBGMOD_LOCK(pDbgMod);
1795
1796 int rc = pDbgMod->pDbgVt->pfnSegmentByIndex(pDbgMod, iSeg, pSegInfo);
1797
1798 RTDBGMOD_UNLOCK(pDbgMod);
1799 return rc;
1800}
1801RT_EXPORT_SYMBOL(RTDbgModSegmentByIndex);
1802
1803
1804RTDECL(RTUINTPTR) RTDbgModSegmentSize(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg)
1805{
1806 if (iSeg == RTDBGSEGIDX_RVA)
1807 return RTDbgModImageSize(hDbgMod);
1808 RTDBGSEGMENT SegInfo;
1809 int rc = RTDbgModSegmentByIndex(hDbgMod, iSeg, &SegInfo);
1810 return RT_SUCCESS(rc) ? SegInfo.cb : RTUINTPTR_MAX;
1811}
1812RT_EXPORT_SYMBOL(RTDbgModSegmentSize);
1813
1814
1815RTDECL(RTUINTPTR) RTDbgModSegmentRva(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg)
1816{
1817 RTDBGSEGMENT SegInfo;
1818 int rc = RTDbgModSegmentByIndex(hDbgMod, iSeg, &SegInfo);
1819 return RT_SUCCESS(rc) ? SegInfo.uRva : RTUINTPTR_MAX;
1820}
1821RT_EXPORT_SYMBOL(RTDbgModSegmentRva);
1822
1823
1824RTDECL(int) RTDbgModSymbolAdd(RTDBGMOD hDbgMod, const char *pszSymbol, RTDBGSEGIDX iSeg, RTUINTPTR off,
1825 RTUINTPTR cb, uint32_t fFlags, uint32_t *piOrdinal)
1826{
1827 /*
1828 * Validate input.
1829 */
1830 PRTDBGMODINT pDbgMod = hDbgMod;
1831 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1832 AssertPtrReturn(pszSymbol, VERR_INVALID_POINTER);
1833 size_t cchSymbol = strlen(pszSymbol);
1834 AssertReturn(cchSymbol, VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE);
1835 AssertReturn(cchSymbol < RTDBG_SYMBOL_NAME_LENGTH, VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE);
1836 AssertMsgReturn( iSeg <= RTDBGSEGIDX_LAST
1837 || ( iSeg >= RTDBGSEGIDX_SPECIAL_FIRST
1838 && iSeg <= RTDBGSEGIDX_SPECIAL_LAST),
1839 ("%#x\n", iSeg),
1840 VERR_DBG_INVALID_SEGMENT_INDEX);
1841 AssertMsgReturn(off + cb >= off, ("off=%RTptr cb=%RTptr\n", off, cb), VERR_DBG_ADDRESS_WRAP);
1842 AssertReturn(!fFlags, VERR_INVALID_PARAMETER); /* currently reserved. */
1843
1844 RTDBGMOD_LOCK(pDbgMod);
1845
1846 /*
1847 * Convert RVAs.
1848 */
1849 if (iSeg == RTDBGSEGIDX_RVA)
1850 {
1851 iSeg = pDbgMod->pDbgVt->pfnRvaToSegOff(pDbgMod, off, &off);
1852 if (iSeg == NIL_RTDBGSEGIDX)
1853 {
1854 RTDBGMOD_UNLOCK(pDbgMod);
1855 return VERR_DBG_INVALID_RVA;
1856 }
1857 }
1858
1859 /*
1860 * Get down to business.
1861 */
1862 int rc = pDbgMod->pDbgVt->pfnSymbolAdd(pDbgMod, pszSymbol, cchSymbol, iSeg, off, cb, fFlags, piOrdinal);
1863
1864 RTDBGMOD_UNLOCK(pDbgMod);
1865 return rc;
1866}
1867RT_EXPORT_SYMBOL(RTDbgModSymbolAdd);
1868
1869
1870RTDECL(uint32_t) RTDbgModSymbolCount(RTDBGMOD hDbgMod)
1871{
1872 PRTDBGMODINT pDbgMod = hDbgMod;
1873 RTDBGMOD_VALID_RETURN_RC(pDbgMod, UINT32_MAX);
1874 RTDBGMOD_LOCK(pDbgMod);
1875
1876 uint32_t cSymbols = pDbgMod->pDbgVt->pfnSymbolCount(pDbgMod);
1877
1878 RTDBGMOD_UNLOCK(pDbgMod);
1879 return cSymbols;
1880}
1881RT_EXPORT_SYMBOL(RTDbgModSymbolCount);
1882
1883
1884RTDECL(int) RTDbgModSymbolByOrdinal(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
1885{
1886 PRTDBGMODINT pDbgMod = hDbgMod;
1887 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1888 RTDBGMOD_LOCK(pDbgMod);
1889
1890 int rc = pDbgMod->pDbgVt->pfnSymbolByOrdinal(pDbgMod, iOrdinal, pSymInfo);
1891
1892 RTDBGMOD_UNLOCK(pDbgMod);
1893 return rc;
1894}
1895RT_EXPORT_SYMBOL(RTDbgModSymbolByOrdinal);
1896
1897
1898RTDECL(int) RTDbgModSymbolByOrdinalA(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGSYMBOL *ppSymInfo)
1899{
1900 AssertPtr(ppSymInfo);
1901 *ppSymInfo = NULL;
1902
1903 PRTDBGSYMBOL pSymInfo = RTDbgSymbolAlloc();
1904 if (!pSymInfo)
1905 return VERR_NO_MEMORY;
1906
1907 int rc = RTDbgModSymbolByOrdinal(hDbgMod, iOrdinal, pSymInfo);
1908
1909 if (RT_SUCCESS(rc))
1910 *ppSymInfo = pSymInfo;
1911 else
1912 RTDbgSymbolFree(pSymInfo);
1913 return rc;
1914}
1915RT_EXPORT_SYMBOL(RTDbgModSymbolByOrdinalA);
1916
1917
1918/**
1919 * Return a segment number/name as symbol if we couldn't find any
1920 * valid symbols within the segment.
1921 */
1922DECL_NO_INLINE(static, int)
1923rtDbgModSymbolByAddrTrySegments(PRTDBGMODINT pDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
1924 PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
1925{
1926 Assert(iSeg <= RTDBGSEGIDX_LAST);
1927 RTDBGSEGMENT SegInfo;
1928 int rc = pDbgMod->pDbgVt->pfnSegmentByIndex(pDbgMod, iSeg, &SegInfo);
1929 if (RT_SUCCESS(rc))
1930 {
1931 pSymInfo->Value = 0;
1932 pSymInfo->cb = SegInfo.cb;
1933 pSymInfo->offSeg = 0;
1934 pSymInfo->iSeg = iSeg;
1935 pSymInfo->fFlags = 0;
1936 if (SegInfo.szName[0])
1937 RTStrPrintf(pSymInfo->szName, sizeof(pSymInfo->szName), "start_seg%u_%s", SegInfo.iSeg, SegInfo.szName);
1938 else
1939 RTStrPrintf(pSymInfo->szName, sizeof(pSymInfo->szName), "start_seg%u", SegInfo.iSeg);
1940 if (poffDisp)
1941 *poffDisp = off;
1942 return VINF_SUCCESS;
1943 }
1944 return VERR_SYMBOL_NOT_FOUND;
1945}
1946
1947
1948RTDECL(int) RTDbgModSymbolByAddr(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
1949 PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
1950{
1951 /*
1952 * Validate input.
1953 */
1954 PRTDBGMODINT pDbgMod = hDbgMod;
1955 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
1956 AssertPtrNull(poffDisp);
1957 AssertPtr(pSymInfo);
1958 AssertReturn(!(fFlags & ~RTDBGSYMADDR_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
1959
1960 RTDBGMOD_LOCK(pDbgMod);
1961
1962 /*
1963 * Convert RVAs.
1964 */
1965 if (iSeg == RTDBGSEGIDX_RVA)
1966 {
1967 iSeg = pDbgMod->pDbgVt->pfnRvaToSegOff(pDbgMod, off, &off);
1968 if (iSeg == NIL_RTDBGSEGIDX)
1969 {
1970 RTDBGMOD_UNLOCK(pDbgMod);
1971 return VERR_DBG_INVALID_RVA;
1972 }
1973 }
1974
1975 /*
1976 * Get down to business.
1977 */
1978 int rc = pDbgMod->pDbgVt->pfnSymbolByAddr(pDbgMod, iSeg, off, fFlags, poffDisp, pSymInfo);
1979
1980 /* If we failed to locate a symbol, try use the specified segment as a reference. */
1981 if ( rc == VERR_SYMBOL_NOT_FOUND
1982 && iSeg <= RTDBGSEGIDX_LAST
1983 && !(fFlags & RTDBGSYMADDR_FLAGS_GREATER_OR_EQUAL))
1984 rc = rtDbgModSymbolByAddrTrySegments(pDbgMod, iSeg, off, poffDisp, pSymInfo);
1985
1986 RTDBGMOD_UNLOCK(pDbgMod);
1987 return rc;
1988}
1989RT_EXPORT_SYMBOL(RTDbgModSymbolByAddr);
1990
1991
1992RTDECL(int) RTDbgModSymbolByAddrA(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
1993 PRTINTPTR poffDisp, PRTDBGSYMBOL *ppSymInfo)
1994{
1995 AssertPtr(ppSymInfo);
1996 *ppSymInfo = NULL;
1997
1998 PRTDBGSYMBOL pSymInfo = RTDbgSymbolAlloc();
1999 if (!pSymInfo)
2000 return VERR_NO_MEMORY;
2001
2002 int rc = RTDbgModSymbolByAddr(hDbgMod, iSeg, off, fFlags, poffDisp, pSymInfo);
2003
2004 if (RT_SUCCESS(rc))
2005 *ppSymInfo = pSymInfo;
2006 else
2007 RTDbgSymbolFree(pSymInfo);
2008 return rc;
2009}
2010RT_EXPORT_SYMBOL(RTDbgModSymbolByAddrA);
2011
2012
2013RTDECL(int) RTDbgModSymbolByName(RTDBGMOD hDbgMod, const char *pszSymbol, PRTDBGSYMBOL pSymInfo)
2014{
2015 /*
2016 * Validate input.
2017 */
2018 PRTDBGMODINT pDbgMod = hDbgMod;
2019 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
2020 AssertPtr(pszSymbol);
2021 size_t cchSymbol = strlen(pszSymbol);
2022 AssertReturn(cchSymbol, VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE);
2023 AssertReturn(cchSymbol < RTDBG_SYMBOL_NAME_LENGTH, VERR_DBG_SYMBOL_NAME_OUT_OF_RANGE);
2024 AssertPtr(pSymInfo);
2025
2026 /*
2027 * Make the query.
2028 */
2029 RTDBGMOD_LOCK(pDbgMod);
2030 int rc = pDbgMod->pDbgVt->pfnSymbolByName(pDbgMod, pszSymbol, cchSymbol, pSymInfo);
2031 RTDBGMOD_UNLOCK(pDbgMod);
2032
2033 return rc;
2034}
2035RT_EXPORT_SYMBOL(RTDbgModSymbolByName);
2036
2037
2038RTDECL(int) RTDbgModSymbolByNameA(RTDBGMOD hDbgMod, const char *pszSymbol, PRTDBGSYMBOL *ppSymInfo)
2039{
2040 AssertPtr(ppSymInfo);
2041 *ppSymInfo = NULL;
2042
2043 PRTDBGSYMBOL pSymInfo = RTDbgSymbolAlloc();
2044 if (!pSymInfo)
2045 return VERR_NO_MEMORY;
2046
2047 int rc = RTDbgModSymbolByName(hDbgMod, pszSymbol, pSymInfo);
2048
2049 if (RT_SUCCESS(rc))
2050 *ppSymInfo = pSymInfo;
2051 else
2052 RTDbgSymbolFree(pSymInfo);
2053 return rc;
2054}
2055RT_EXPORT_SYMBOL(RTDbgModSymbolByNameA);
2056
2057
2058RTDECL(int) RTDbgModLineAdd(RTDBGMOD hDbgMod, const char *pszFile, uint32_t uLineNo,
2059 RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t *piOrdinal)
2060{
2061 /*
2062 * Validate input.
2063 */
2064 PRTDBGMODINT pDbgMod = hDbgMod;
2065 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
2066 AssertPtr(pszFile);
2067 size_t cchFile = strlen(pszFile);
2068 AssertReturn(cchFile, VERR_DBG_FILE_NAME_OUT_OF_RANGE);
2069 AssertReturn(cchFile < RTDBG_FILE_NAME_LENGTH, VERR_DBG_FILE_NAME_OUT_OF_RANGE);
2070 AssertMsgReturn( iSeg <= RTDBGSEGIDX_LAST
2071 || iSeg == RTDBGSEGIDX_RVA,
2072 ("%#x\n", iSeg),
2073 VERR_DBG_INVALID_SEGMENT_INDEX);
2074 AssertReturn(uLineNo > 0 && uLineNo < UINT32_MAX, VERR_INVALID_PARAMETER);
2075
2076 RTDBGMOD_LOCK(pDbgMod);
2077
2078 /*
2079 * Convert RVAs.
2080 */
2081 if (iSeg == RTDBGSEGIDX_RVA)
2082 {
2083 iSeg = pDbgMod->pDbgVt->pfnRvaToSegOff(pDbgMod, off, &off);
2084 if (iSeg == NIL_RTDBGSEGIDX)
2085 {
2086 RTDBGMOD_UNLOCK(pDbgMod);
2087 return VERR_DBG_INVALID_RVA;
2088 }
2089 }
2090
2091 /*
2092 * Get down to business.
2093 */
2094 int rc = pDbgMod->pDbgVt->pfnLineAdd(pDbgMod, pszFile, cchFile, uLineNo, iSeg, off, piOrdinal);
2095
2096 RTDBGMOD_UNLOCK(pDbgMod);
2097 return rc;
2098}
2099RT_EXPORT_SYMBOL(RTDbgModLineAdd);
2100
2101
2102RTDECL(uint32_t) RTDbgModLineCount(RTDBGMOD hDbgMod)
2103{
2104 PRTDBGMODINT pDbgMod = hDbgMod;
2105 RTDBGMOD_VALID_RETURN_RC(pDbgMod, UINT32_MAX);
2106 RTDBGMOD_LOCK(pDbgMod);
2107
2108 uint32_t cLineNumbers = pDbgMod->pDbgVt->pfnLineCount(pDbgMod);
2109
2110 RTDBGMOD_UNLOCK(pDbgMod);
2111 return cLineNumbers;
2112}
2113RT_EXPORT_SYMBOL(RTDbgModLineCount);
2114
2115
2116RTDECL(int) RTDbgModLineByOrdinal(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
2117{
2118 PRTDBGMODINT pDbgMod = hDbgMod;
2119 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
2120 RTDBGMOD_LOCK(pDbgMod);
2121
2122 int rc = pDbgMod->pDbgVt->pfnLineByOrdinal(pDbgMod, iOrdinal, pLineInfo);
2123
2124 RTDBGMOD_UNLOCK(pDbgMod);
2125 return rc;
2126}
2127RT_EXPORT_SYMBOL(RTDbgModLineByOrdinal);
2128
2129
2130RTDECL(int) RTDbgModLineByOrdinalA(RTDBGMOD hDbgMod, uint32_t iOrdinal, PRTDBGLINE *ppLineInfo)
2131{
2132 AssertPtr(ppLineInfo);
2133 *ppLineInfo = NULL;
2134
2135 PRTDBGLINE pLineInfo = RTDbgLineAlloc();
2136 if (!pLineInfo)
2137 return VERR_NO_MEMORY;
2138
2139 int rc = RTDbgModLineByOrdinal(hDbgMod, iOrdinal, pLineInfo);
2140
2141 if (RT_SUCCESS(rc))
2142 *ppLineInfo = pLineInfo;
2143 else
2144 RTDbgLineFree(pLineInfo);
2145 return rc;
2146}
2147RT_EXPORT_SYMBOL(RTDbgModLineByOrdinalA);
2148
2149
2150RTDECL(int) RTDbgModLineByAddr(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
2151{
2152 /*
2153 * Validate input.
2154 */
2155 PRTDBGMODINT pDbgMod = hDbgMod;
2156 RTDBGMOD_VALID_RETURN_RC(pDbgMod, VERR_INVALID_HANDLE);
2157 AssertPtrNull(poffDisp);
2158 AssertPtr(pLineInfo);
2159
2160 RTDBGMOD_LOCK(pDbgMod);
2161
2162 /*
2163 * Convert RVAs.
2164 */
2165 if (iSeg == RTDBGSEGIDX_RVA)
2166 {
2167 iSeg = pDbgMod->pDbgVt->pfnRvaToSegOff(pDbgMod, off, &off);
2168 if (iSeg == NIL_RTDBGSEGIDX)
2169 {
2170 RTDBGMOD_UNLOCK(pDbgMod);
2171 return VERR_DBG_INVALID_RVA;
2172 }
2173 }
2174
2175 int rc = pDbgMod->pDbgVt->pfnLineByAddr(pDbgMod, iSeg, off, poffDisp, pLineInfo);
2176
2177 RTDBGMOD_UNLOCK(pDbgMod);
2178 return rc;
2179}
2180RT_EXPORT_SYMBOL(RTDbgModLineByAddr);
2181
2182
2183RTDECL(int) RTDbgModLineByAddrA(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTINTPTR poffDisp, PRTDBGLINE *ppLineInfo)
2184{
2185 AssertPtr(ppLineInfo);
2186 *ppLineInfo = NULL;
2187
2188 PRTDBGLINE pLineInfo = RTDbgLineAlloc();
2189 if (!pLineInfo)
2190 return VERR_NO_MEMORY;
2191
2192 int rc = RTDbgModLineByAddr(hDbgMod, iSeg, off, poffDisp, pLineInfo);
2193
2194 if (RT_SUCCESS(rc))
2195 *ppLineInfo = pLineInfo;
2196 else
2197 RTDbgLineFree(pLineInfo);
2198 return rc;
2199}
2200RT_EXPORT_SYMBOL(RTDbgModLineByAddrA);
2201
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