dbgmod.cpp revision 6805ae4b939ad0646ed7d4a52696b828e6554bf5
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * IPRT - Debug Module Interpreter.
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * Copyright (C) 2009-2012 Oracle Corporation
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * available from http://www.virtualbox.org. This file is free software;
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * you can redistribute it and/or modify it under the terms of the GNU
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * General Public License (GPL) as published by the Free Software
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * The contents of this file may alternatively be used under the terms
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * of the Common Development and Distribution License Version 1.0
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * VirtualBox OSE distribution, in which case the provisions of the
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * CDDL are applicable instead of those of the GPL.
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * You may elect to license modified versions of this file under the
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * terms and conditions of either the GPL or the CDDL or both.
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync/*******************************************************************************
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync* Header Files *
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync*******************************************************************************/
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/*******************************************************************************
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync* Structures and Typedefs *
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync*******************************************************************************/
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/** Debug info interpreter registration record. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /** Pointer to the next record. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /** Pointer to the virtual function table for the interpreter. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /** Usage counter. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/** Image interpreter registration record. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /** Pointer to the next record. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /** Pointer to the virtual function table for the interpreter. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /** Usage counter. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/*******************************************************************************
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync* Defined Constants And Macros *
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync*******************************************************************************/
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/** Validates a debug module handle and returns rc if not valid. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertReturn((pDbgMod)->u32Magic == RTDBGMOD_MAGIC, (rc)); \
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync } while (0)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/** Locks the debug module. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync int rcLock = RTCritSectEnter(&(pDbgMod)->CritSect); \
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync } while (0)
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync/** Unlocks the debug module. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync int rcLock = RTCritSectLeave(&(pDbgMod)->CritSect); \
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync } while (0)
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync/*******************************************************************************
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync* Global Variables *
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync*******************************************************************************/
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync/** Init once object for lazy registration of the built-in image and debug
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * info interpreters. */
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync/** Read/Write semaphore protecting the list of registered interpreters. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/** List of registered image interpreters. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/** List of registered debug infor interpreters. */
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync/** String cache for the debug info interpreters.
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync * RTSTRCACHE is thread safe. */
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsyncDECLHIDDEN(RTSTRCACHE) g_hDbgModStrCache = NIL_RTSTRCACHE;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Cleanup debug info interpreter globals.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param enmReason The cause of the termination.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param iStatus The meaning of this depends on enmReason.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param pvUser User argument, unused.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncstatic DECLCALLBACK(void) rtDbgModTermCallback(RTTERMREASON enmReason, int32_t iStatus, void *pvUser)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsg(pDbg->cUsers == 0, ("%#x %s\n", pDbg->cUsers, pDbg->pVt->pszName));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsg(pImg->cUsers == 0, ("%#x %s\n", pImg->cUsers, pImg->pVt->pszName));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Internal worker for register a debug interpreter.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Called while owning the write lock or when locking isn't required.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @returns IPRT status code.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @retval VERR_NO_MEMORY
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @retval VERR_ALREADY_EXISTS
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param pVt The virtual function table of the debug
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * module interpreter.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncstatic int rtDbgModDebugInterpreterRegister(PCRTDBGMODVTDBG pVt)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Search or duplicate registration.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync for (PRTDBGMODREGDBG pCur = g_pDbgHead; pCur; pCur = pCur->pNext)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Create a new record and add it to the end of the list.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync PRTDBGMODREGDBG pReg = (PRTDBGMODREGDBG)RTMemAlloc(sizeof(*pReg));
835ac9173220411ef9fe578c3d4c03e5edfa20bevboxsync * Internal worker for register a image interpreter.
835ac9173220411ef9fe578c3d4c03e5edfa20bevboxsync * Called while owning the write lock or when locking isn't required.
835ac9173220411ef9fe578c3d4c03e5edfa20bevboxsync * @returns IPRT status code.
835ac9173220411ef9fe578c3d4c03e5edfa20bevboxsync * @retval VERR_NO_MEMORY
835ac9173220411ef9fe578c3d4c03e5edfa20bevboxsync * @retval VERR_ALREADY_EXISTS
835ac9173220411ef9fe578c3d4c03e5edfa20bevboxsync * @param pVt The virtual function table of the image
835ac9173220411ef9fe578c3d4c03e5edfa20bevboxsync * interpreter.
835ac9173220411ef9fe578c3d4c03e5edfa20bevboxsyncstatic int rtDbgModImageInterpreterRegister(PCRTDBGMODVTIMG pVt)
835ac9173220411ef9fe578c3d4c03e5edfa20bevboxsync * Search or duplicate registration.
835ac9173220411ef9fe578c3d4c03e5edfa20bevboxsync for (PRTDBGMODREGIMG pCur = g_pImgHead; pCur; pCur = pCur->pNext)
835ac9173220411ef9fe578c3d4c03e5edfa20bevboxsync * Create a new record and add it to the end of the list.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync PRTDBGMODREGIMG pReg = (PRTDBGMODREGIMG)RTMemAlloc(sizeof(*pReg));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Do-once callback that initializes the read/write semaphore and registers
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * the built-in interpreters.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @returns IPRT status code.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param pvUser NULL.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncstatic DECLCALLBACK(int) rtDbgModInitOnce(void *pvUser)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Create the semaphore and string cache.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = RTStrCacheCreate(&g_hDbgModStrCache, "RTDBGMOD");
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Register the interpreters.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgNm);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgDwarf);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgCodeView);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtDbgModDebugInterpreterRegister(&g_rtDbgModVtDbgDbgHelp);
84c4a51d2a3c1a5c3f7d6902a8ac8c2eb267f4e0vboxsync rc = rtDbgModImageInterpreterRegister(&g_rtDbgModVtImgLdr);
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * Finally, register the IPRT cleanup callback.
382dd16193dd5770e53a99d3e3f3bc4e96f1ddd8vboxsync rc = RTTermRegisterCallback(rtDbgModTermCallback, NULL);
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync /* bail out: use the termination callback. */
ac1200e63b58a0451085add197084e5a4a1bb4cavboxsync rtDbgModTermCallback(RTTERMREASON_UNLOAD, 0, NULL);
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * Performs lazy init of our global variables.
d960e43fb3727c884b5f7eca3c920c9549839881vboxsync * @returns IPRT status code.
84c4a51d2a3c1a5c3f7d6902a8ac8c2eb267f4e0vboxsync return RTOnce(&g_rtDbgModOnce, rtDbgModInitOnce, NULL);
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsyncRTDECL(int) RTDbgModCreate(PRTDBGMOD phDbgMod, const char *pszName, RTUINTPTR cbSeg, uint32_t fFlags)
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * Input validation and lazy initialization.
510dd1bd989d25f95680fc2a3b51bf11854bc6a4vboxsync * Allocate a new module instance.
44918d7b9fb45f0d3e2ba56bf6d2cede9a2ae566vboxsync PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*pDbgMod));
d960e43fb3727c884b5f7eca3c920c9549839881vboxsync pDbgMod->pszImgFileSpecified = RTStrCacheEnter(g_hDbgModStrCache, pszName);
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync pDbgMod->pszName = RTStrCacheEnterLower(g_hDbgModStrCache, RTPathFilenameEx(pszName, RTPATH_STR_F_STYLE_DOS));
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszImgFile);
382dd16193dd5770e53a99d3e3f3bc4e96f1ddd8vboxsync RTStrCacheRelease(g_hDbgModStrCache, pDbgMod->pszName);
382dd16193dd5770e53a99d3e3f3bc4e96f1ddd8vboxsyncRTDECL(int) RTDbgModCreateFromMap(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName,
382dd16193dd5770e53a99d3e3f3bc4e96f1ddd8vboxsync * Input validation and lazy initialization.
42f4857b15e5d875e39345f1d1b804c2c1313e91vboxsync AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
42f4857b15e5d875e39345f1d1b804c2c1313e91vboxsync AssertReturn(*pszFilename, VERR_INVALID_PARAMETER);
42f4857b15e5d875e39345f1d1b804c2c1313e91vboxsync AssertPtrNullReturn(pszName, VERR_INVALID_POINTER);
42f4857b15e5d875e39345f1d1b804c2c1313e91vboxsync AssertReturn(uSubtrahend == 0, VERR_NOT_IMPLEMENTED); /** @todo implement uSubtrahend. */
42f4857b15e5d875e39345f1d1b804c2c1313e91vboxsync pszName = RTPathFilenameEx(pszFilename, RTPATH_STR_F_STYLE_DOS);
c40afa339b10a23d6fffcbeb7d4572bb494685f0vboxsync * Allocate a new module instance.
44918d7b9fb45f0d3e2ba56bf6d2cede9a2ae566vboxsync PRTDBGMODINT pDbgMod = (PRTDBGMODINT)RTMemAllocZ(sizeof(*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) rtDbgModExtDbgInfoOpenCallback2(RTDBGCFG hDbgCfg, const char *pszFilename, void *pvUser1, void *pvUser2)
return VINF_CALLBACK_RETURN;
return rc;
int rc;
switch (enmFmt)
case RTLDRFMT_MACHO:
return VINF_SUCCESS;
case RTLDRFMT_ELF:
case RTLDRFMT_PE:
case RTLDRFMT_LX:
if (pszzExts)
return VERR_NOT_FOUND;
RTDECL(int) RTDbgModCreateFromImage(PRTDBGMOD phDbgMod, const char *pszFilename, const char *pszName,
return rc;
if (!pszName)
if (!pDbgMod)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
if (!pImg)
return rc;
return rc;
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;
if (fLeaveSegments)
return rc;
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;