VirtualBox

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

Last change on this file since 100931 was 100931, checked in by vboxsync, 16 months ago

IPRT/dbg: Early PDB support.

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