VirtualBox

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

Last change on this file since 99570 was 99570, checked in by vboxsync, 19 months ago

Runtime/dbg/dbgmod.cpp: Improve error message to identify the name and
length of the segment which has exceeded RTDBG_SEGMENT_NAME_LENGTH.

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