VirtualBox

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

Last change on this file since 84204 was 83085, checked in by vboxsync, 5 years ago

IPRT,VMM,DBGPlugInDarwin: Implemented in-memory guest kernel and kext image loading for OS X / Mach-O. Requires LINKEDIT to not be jettisoned to work.

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