VirtualBox

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

Last change on this file since 58591 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

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