dbgmod.cpp revision e9525bea57dc13d82fd3392913aebb33d2cb79e3
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * IPRT - Debug Module Interpreter.
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync * Copyright (C) 2009-2012 Oracle Corporation
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * available from http://www.virtualbox.org. This file is free software;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * you can redistribute it and/or modify it under the terms of the GNU
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * General Public License (GPL) as published by the Free Software
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * The contents of this file may alternatively be used under the terms
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * of the Common Development and Distribution License Version 1.0
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * VirtualBox OSE distribution, in which case the provisions of the
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * CDDL are applicable instead of those of the GPL.
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * You may elect to license modified versions of this file under the
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * terms and conditions of either the GPL or the CDDL or both.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync/*******************************************************************************
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync* Header Files *
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync*******************************************************************************/
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync/*******************************************************************************
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync* Structures and Typedefs *
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync*******************************************************************************/
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync/** Debug info interpreter registration record. */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /** Pointer to the next record. */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /** Pointer to the virtual function table for the interpreter. */
044af0d1e6474076366759db86f101778c5f20ccvboxsync /** Usage counter. */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync/** Image interpreter registration record. */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /** Pointer to the next record. */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /** Pointer to the virtual function table for the interpreter. */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /** Usage counter. */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync/*******************************************************************************
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync* Defined Constants And Macros *
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync*******************************************************************************/
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync/** Validates a debug module handle and returns rc if not valid. */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync AssertReturn((pDbgMod)->u32Magic == RTDBGMOD_MAGIC, (rc)); \
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync } while (0)
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync/** Locks the debug module. */
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync int rcLock = RTCritSectEnter(&(pDbgMod)->CritSect); \
5b0a093ca572a855886faa6747ad46df859dd041vboxsync } while (0)
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync/** Unlocks the debug module. */
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync int rcLock = RTCritSectLeave(&(pDbgMod)->CritSect); \
d3dea25ec07f6546715fe3af943ea863294b392evboxsync } while (0)
d3dea25ec07f6546715fe3af943ea863294b392evboxsync/*******************************************************************************
d3dea25ec07f6546715fe3af943ea863294b392evboxsync* Global Variables *
d3dea25ec07f6546715fe3af943ea863294b392evboxsync*******************************************************************************/
d3dea25ec07f6546715fe3af943ea863294b392evboxsync/** Init once object for lazy registration of the built-in image and debug
d3dea25ec07f6546715fe3af943ea863294b392evboxsync * info interpreters. */
d3dea25ec07f6546715fe3af943ea863294b392evboxsync/** Read/Write semaphore protecting the list of registered interpreters. */
d3dea25ec07f6546715fe3af943ea863294b392evboxsync/** List of registered image interpreters. */
d3dea25ec07f6546715fe3af943ea863294b392evboxsync/** List of registered debug infor interpreters. */
d3dea25ec07f6546715fe3af943ea863294b392evboxsync/** String cache for the debug info interpreters.
d3dea25ec07f6546715fe3af943ea863294b392evboxsync * RTSTRCACHE is thread safe. */
d3dea25ec07f6546715fe3af943ea863294b392evboxsyncDECLHIDDEN(RTSTRCACHE) g_hDbgModStrCache = NIL_RTSTRCACHE;
d3dea25ec07f6546715fe3af943ea863294b392evboxsync * Cleanup debug info interpreter globals.
d3dea25ec07f6546715fe3af943ea863294b392evboxsync * @param enmReason The cause of the termination.
4bf996d915405be92dc4394b2db1395e00e14d58vboxsync * @param iStatus The meaning of this depends on enmReason.
4bf996d915405be92dc4394b2db1395e00e14d58vboxsync * @param pvUser User argument, unused.
4bf996d915405be92dc4394b2db1395e00e14d58vboxsyncstatic DECLCALLBACK(void) rtDbgModTermCallback(RTTERMREASON enmReason, int32_t iStatus, void *pvUser)
5b0a093ca572a855886faa6747ad46df859dd041vboxsync AssertMsg(pDbg->cUsers == 0, ("%#x %s\n", pDbg->cUsers, pDbg->pVt->pszName));
5b0a093ca572a855886faa6747ad46df859dd041vboxsync AssertMsg(pImg->cUsers == 0, ("%#x %s\n", pImg->cUsers, pImg->pVt->pszName));
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync * Internal worker for register a debug interpreter.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Called while owning the write lock or when locking isn't required.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @returns IPRT status code.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @retval VERR_NO_MEMORY
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @retval VERR_ALREADY_EXISTS
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @param pVt The virtual function table of the debug
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * module interpreter.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsyncstatic int rtDbgModDebugInterpreterRegister(PCRTDBGMODVTDBG pVt)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Search or duplicate registration.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync for (PRTDBGMODREGDBG pCur = g_pDbgHead; pCur; pCur = pCur->pNext)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Create a new record and add it to the end of the list.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync PRTDBGMODREGDBG pReg = (PRTDBGMODREGDBG)RTMemAlloc(sizeof(*pReg));
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Internal worker for register a image interpreter.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Called while owning the write lock or when locking isn't required.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @returns IPRT status code.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @retval VERR_NO_MEMORY
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @retval VERR_ALREADY_EXISTS
044af0d1e6474076366759db86f101778c5f20ccvboxsync * @param pVt The virtual function table of the image
044af0d1e6474076366759db86f101778c5f20ccvboxsync * interpreter.
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsyncstatic int rtDbgModImageInterpreterRegister(PCRTDBGMODVTIMG pVt)
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync * Search or duplicate registration.
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync for (PRTDBGMODREGIMG pCur = g_pImgHead; pCur; pCur = pCur->pNext)
2bb12e589d2c280ad042e4e70635ae7224c7eceevboxsync * Create a new record and add it to the end of the list.
2bb12e589d2c280ad042e4e70635ae7224c7eceevboxsync PRTDBGMODREGIMG pReg = (PRTDBGMODREGIMG)RTMemAlloc(sizeof(*pReg));
044af0d1e6474076366759db86f101778c5f20ccvboxsync * Do-once callback that initializes the read/write semaphore and registers
044af0d1e6474076366759db86f101778c5f20ccvboxsync * the built-in interpreters.
044af0d1e6474076366759db86f101778c5f20ccvboxsync * @returns IPRT status code.
044af0d1e6474076366759db86f101778c5f20ccvboxsync * @param pvUser NULL.
044af0d1e6474076366759db86f101778c5f20ccvboxsyncstatic DECLCALLBACK(int) rtDbgModInitOnce(void *pvUser)
044af0d1e6474076366759db86f101778c5f20ccvboxsync * Create the semaphore and string cache.
044af0d1e6474076366759db86f101778c5f20ccvboxsync rc = RTStrCacheCreate(&g_hDbgModStrCache, "RTDBGMOD");
044af0d1e6474076366759db86f101778c5f20ccvboxsync * Register the interpreters.
044af0d1e6474076366759db86f101778c5f20ccvboxsync rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgNm);
044af0d1e6474076366759db86f101778c5f20ccvboxsync rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgDwarf);
044af0d1e6474076366759db86f101778c5f20ccvboxsync rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgDbgHelp);
044af0d1e6474076366759db86f101778c5f20ccvboxsync rc = rtDbgModImageInterpreterRegister(&g_rtDbgModVtImgLdr);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync * Finally, register the IPRT cleanup callback.
044af0d1e6474076366759db86f101778c5f20ccvboxsync rc = RTTermRegisterCallback(rtDbgModTermCallback, NULL);
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync /* bail out: use the termination callback. */
88acfa6629a7976c0583c1712d2b5b22a87a5121vboxsync rtDbgModTermCallback(RTTERMREASON_UNLOAD, 0, NULL);
044af0d1e6474076366759db86f101778c5f20ccvboxsync * Performs lazy init of our global variables.
044af0d1e6474076366759db86f101778c5f20ccvboxsync * @returns IPRT status code.
044af0d1e6474076366759db86f101778c5f20ccvboxsync return RTOnce(&g_rtDbgModOnce, rtDbgModInitOnce, NULL);
044af0d1e6474076366759db86f101778c5f20ccvboxsyncRTDECL(int) RTDbgModCreate(PRTDBGMOD phDbgMod, const char *pszName, RTUINTPTR cbSeg, uint32_t fFlags)
044af0d1e6474076366759db86f101778c5f20ccvboxsync * Input validation and lazy initialization.
a1df400bbe9d64aad400442e56eb637019300a5evboxsync * Allocate a new module instance.
044af0d1e6474076366759db86f101778c5f20ccvboxsync PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgMod));
044af0d1e6474076366759db86f101778c5f20ccvboxsync pDbgMod->pszImgFileSpecified = RTStrCacheEnter(g_hDbgModStrCache, pszName);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pDbgMod->pszName = RTStrCacheEnterLower(g_hDbgModStrCache, RTPathFilename(pszName));
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsyncRTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, RTDBGCFG hDbgCfg)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Input validation and lazy initialization.
a1df400bbe9d64aad400442e56eb637019300a5evboxsync AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
044af0d1e6474076366759db86f101778c5f20ccvboxsync AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync * Allocate a new module instance.
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgMod));
044af0d1e6474076366759db86f101778c5f20ccvboxsync pDbgMod->pszName = RTStrCacheEnterLower(g_hDbgModStrCache, pszName);
044af0d1e6474076366759db86f101778c5f20ccvboxsync pDbgMod->pszImgFile = RTStrCacheEnter(g_hDbgModStrCache, pszFilename);
044af0d1e6474076366759db86f101778c5f20ccvboxsync pDbgMod->pszImgFileSpecified = pDbgMod->pszImgFile;
044af0d1e6474076366759db86f101778c5f20ccvboxsync * Find an image reader which groks the file.
044af0d1e6474076366759db86f101778c5f20ccvboxsync rc = RTSemRWRequestRead(g_hDbgModRWSem, RT_INDEFINITE_WAIT);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Find a debug info interpreter.
044af0d1e6474076366759db86f101778c5f20ccvboxsync for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * That's it!
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Image detected, but found no debug info we were
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * able to understand.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /** @todo Fall back on exported symbols! */
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync * Could it be a file containing raw debug info?
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync for (PRTDBGMODREGDBG pDbg = g_pDbgHead; pDbg; pDbg = pDbg->pNext)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * That's it!
c58c758d3642ac45d3f12356c406c631fcd8f538vboxsync /* bail out */
7af218a7441de38fc9e814919db04bae3e917664vboxsync RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFileSpecified);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
return rc;
return rc;
if (!pszName)
if (!pDbgMod)
return VERR_NO_MEMORY;
return rc;
return rc;
return VINF_SUCCESS;
return VERR_DBG_NO_MATCHING_INTERPRETER;
static DECLCALLBACK(int) rtDbgModExtDbgInfoOpenCallback(RTDBGCFG hDbgCfg, const char *pszFilename, void *pvUser1, void *pvUser2)
return VINF_CALLBACK_RETURN;
return rc;
typedef struct RTDBGMODOPENDIETI
static DECLCALLBACK(int)
rtDbgModOpenDebugInfoExternalToImageCallback(RTLDRMOD hLdrMod, PCRTLDRDBGINFO pDbgInfo, void *pvUser)
if (!pszExtFile)
if (psz)
if (!pszExtFile)
return VINF_SUCCESS;
int rc;
Log(("rtDbgModOpenDebugInfoExternalToImageCallback: Don't know how to handle enmType=%d and pszFileExt=%s\n",
return VERR_DBG_TODO;
return VINF_CALLBACK_RETURN;
return rc;
int rc = pDbgMod->pImgVt->pfnEnumDbgInfo(pDbgMod, rtDbgModOpenDebugInfoExternalToImageCallback, &Args);
return VINF_SUCCESS;
return VERR_NOT_FOUND;
static DECLCALLBACK(int) rtDbgModFromPeImageOpenCallback(RTDBGCFG hDbgCfg, const char *pszFilename, void *pvUser1, void *pvUser2)
if (!pszNewImgFile)
return VERR_NO_STR_MEMORY;
uint32_t uTimestamp = pDeferred->u.PeImage.uTimestamp; /** @todo add method for getting the timestamp. */
return VINF_CALLBACK_RETURN;
return rc;
static DECLCALLBACK(int) rtDbgModFromPeImageDeferredCallback(PRTDBGMODINT pDbgMod, PRTDBGMODDEFERRED pDeferred)
int rc;
return rc;
RTDECL(int) RTDbgModCreateFromPeImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName, RTLDRMOD hLdrMod,
if (!pszName)
return rc;
if (hDbgCfg)
if (!pDbgMod)
return VERR_NO_MEMORY;
if (!cbImage)
rc = rtDbgModDeferredCreate(pDbgMod, rtDbgModFromPeImageDeferredCallback, cbImage, hDbgCfg, &pDeferred);
return VINF_SUCCESS;
return rc;
if (!cRefs)
return cRefs;
return NULL;
return iSeg;
return cbImage;
return VINF_SUCCESS;
AssertMsgReturn(!piSeg || *piSeg == NIL_RTDBGSEGIDX || *piSeg <= RTDBGSEGIDX_LAST, ("%#x\n", *piSeg), VERR_DBG_SPECIAL_SEGMENT);
return rc;
return cSegs;
return rc;
RTDECL(int) RTDbgModSymbolAdd(RTDBGMOD hDbgMod, const char *pszSymbol, RTDBGSEGIDX iSeg, RTUINTPTR off,
return VERR_DBG_INVALID_RVA;
int rc = pDbgMod->pDbgVt->pfnSymbolAdd(pDbgMod, pszSymbol, cchSymbol, iSeg, off, cb, fFlags, piOrdinal);
return rc;
return cSymbols;
return rc;
if (!pSymInfo)
return VERR_NO_MEMORY;
return rc;
RTDECL(int) RTDbgModSymbolByAddr(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
return VERR_DBG_INVALID_RVA;
return rc;
RTDECL(int) RTDbgModSymbolByAddrA(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
if (!pSymInfo)
return VERR_NO_MEMORY;
return rc;
return rc;
if (!pSymInfo)
return VERR_NO_MEMORY;
return rc;
return VERR_DBG_INVALID_RVA;
return rc;
return cLineNumbers;
return rc;
if (!pLineInfo)
return VERR_NO_MEMORY;
return rc;
RTDECL(int) RTDbgModLineByAddr(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
return VERR_DBG_INVALID_RVA;
return rc;
RTDECL(int) RTDbgModLineByAddrA(RTDBGMOD hDbgMod, RTDBGSEGIDX iSeg, RTUINTPTR off, PRTINTPTR poffDisp, PRTDBGLINE *ppLineInfo)
if (!pLineInfo)
return VERR_NO_MEMORY;
return rc;