VirtualBox

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

Last change on this file was 103438, checked in by vboxsync, 3 months ago

IPRT/dbgmod: Simplified and restored old alloca errora handling behavior in rtDbgModOpenDebugInfoExternalToImageCallback. bugref:3409

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

© 2023 Oracle
ContactPrivacy policyTerms of Use