dbgmodcontainer.cpp revision 50370d07616e900f524ff4011cd74a66d64ea212
/* $Id$ */
/** @file
* IPRT - Debug Info Container.
*/
/*
* Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define RTDBGMODCNT_WITH_MEM_CACHE
#ifdef RTDBGMODCNT_WITH_MEM_CACHE
# include <iprt/memcache.h>
#endif
#include <iprt/strcache.h>
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Symbol entry.
*/
typedef struct RTDBGMODCTNSYMBOL
{
/** The address core. */
/** The name space core. */
/** The ordinal number core. */
/** The segment index. */
/** The symbol flags. */
/** The symbol size.
* This may be zero while the range in AddrCore indicates 0. */
/** Pointer to a symbol entry in the debug info container. */
typedef RTDBGMODCTNSYMBOL *PRTDBGMODCTNSYMBOL;
/** Pointer to a const symbol entry in the debug info container. */
typedef RTDBGMODCTNSYMBOL const *PCRTDBGMODCTNSYMBOL;
/**
* Line number entry.
*/
typedef struct RTDBGMODCTNLINE
{
/** The address core.
* The Key is the address of the line number. */
/** The ordinal number core. */
/** Pointer to the file name (in string cache). */
const char *pszFile;
/** The line number. */
/** The segment index. */
/** Pointer to a line number entry. */
typedef RTDBGMODCTNLINE *PRTDBGMODCTNLINE;
/** Pointer to const a line number entry. */
typedef RTDBGMODCTNLINE const *PCRTDBGMODCTNLINE;
/**
* Segment entry.
*/
typedef struct RTDBGMODCTNSEGMENT
{
/** The symbol address space tree. */
/** The line number address space tree. */
/** The segment offset. */
/** The segment size. */
/** The segment flags. */
/** The segment name. */
const char *pszName;
/** Pointer to a segment entry in the debug info container. */
typedef RTDBGMODCTNSEGMENT *PRTDBGMODCTNSEGMENT;
/** Pointer to a const segment entry in the debug info container. */
typedef RTDBGMODCTNSEGMENT const *PCRTDBGMODCTNSEGMENT;
/**
* Instance data.
*/
typedef struct RTDBGMODCTN
{
/** The name space. */
/** Tree containing any absolute addresses. */
/** Tree organizing the symbols by ordinal number. */
/** Tree organizing the line numbers by ordinal number. */
/** Segment table. */
/** The number of segments in the segment table. */
/** The image size. 0 means unlimited. */
/** The next symbol ordinal. */
/** The next line number ordinal. */
#ifdef RTDBGMODCNT_WITH_MEM_CACHE
/** Line number allocator.
* Using a cache is a bit overkill since we normally won't free them, but
* it's a construct that exists and does the job relatively efficiently. */
#endif
} RTDBGMODCTN;
/** Pointer to instance data for the debug info container. */
typedef RTDBGMODCTN *PRTDBGMODCTN;
/**
* Fills in a RTDBGSYMBOL structure.
*
* @returns VINF_SUCCESS.
* @param pMySym Our internal symbol representation.
* @param pExtSym The external symbol representation.
*/
{
return VINF_SUCCESS;
}
/** @copydoc RTDBGMODVTDBG::pfnLineByAddr */
static DECLCALLBACK(int) rtDbgModContainer_LineByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
{
/*
* Validate the input address.
*/
/*
* Lookup the nearest line number with an address less or equal to the specified address.
*/
PAVLUINTPTRNODECORE pAvlCore = RTAvlUIntPtrGetBestFit(&pThis->paSegs[iSeg].LineAddrTree, off, false /*fAbove*/);
if (!pAvlCore)
return pThis->iNextLineOrdinal
if (poffDisp)
return VINF_SUCCESS;
}
/** @copydoc RTDBGMODVTDBG::pfnLineByOrdinal */
static DECLCALLBACK(int) rtDbgModContainer_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
{
/*
* Look it up.
*/
return pThis->iNextLineOrdinal
return VINF_SUCCESS;
}
/** @copydoc RTDBGMODVTDBG::pfnLineCount */
{
/* Note! The ordinal numbers are 0-based. */
return pThis->iNextLineOrdinal;
}
/** @copydoc RTDBGMODVTDBG::pfnLineAdd */
static DECLCALLBACK(int) rtDbgModContainer_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo,
{
/*
* Validate the input address.
*/
AssertMsgReturn(off < pThis->paSegs[iSeg].cb, ("off=%RTptr cbSeg=%RTptr\n", off, pThis->paSegs[iSeg].cb),
/*
* Create a new entry.
*/
#ifdef RTDBGMODCNT_WITH_MEM_CACHE
#else
#endif
if (!pLine)
return VERR_NO_MEMORY;
int rc;
{
{
{
if (piOrdinal)
return VINF_SUCCESS;
}
}
/* bail out */
}
else
rc = VERR_NO_MEMORY;
#ifdef RTDBGMODCNT_WITH_MEM_CACHE
#else
#endif
return rc;
}
/** @copydoc RTDBGMODVTDBG::pfnSymbolByAddr */
static DECLCALLBACK(int) rtDbgModContainer_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
{
/*
* Validate the input address.
*/
/*
* Lookup the nearest symbol with an address less or equal to the specified address.
*/
? &pThis->AbsAddrTree
off,
if (!pAvlCore)
return VERR_SYMBOL_NOT_FOUND;
if (poffDisp)
}
/** @copydoc RTDBGMODVTDBG::pfnSymbolByName */
static DECLCALLBACK(int) rtDbgModContainer_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol, PRTDBGSYMBOL pSymInfo)
{
/*
* Look it up in the name space.
*/
if (!pStrCore)
return VERR_SYMBOL_NOT_FOUND;
}
/** @copydoc RTDBGMODVTDBG::pfnSymbolByOrdinal */
static DECLCALLBACK(int) rtDbgModContainer_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
{
/*
* Look it up in the ordinal tree.
*/
return pThis->iNextSymbolOrdinal
}
/** @copydoc RTDBGMODVTDBG::pfnSymbolCount */
{
/* Note! The ordinal numbers are 0-based. */
return pThis->iNextSymbolOrdinal;
}
/** @copydoc RTDBGMODVTDBG::pfnSymbolAdd */
static DECLCALLBACK(int) rtDbgModContainer_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
{
/*
* Address validation. The other arguments have already been validated.
*/
/* Be a little relaxed wrt to the symbol size. */
int rc = VINF_SUCCESS;
{
}
/*
* Create a new entry.
*/
if (!pSymbol)
return VERR_NO_MEMORY;
{
{
? &pThis->AbsAddrTree
{
{
if (piOrdinal)
return rc;
}
/* bail out */
}
else
}
else
}
else
rc = VERR_NO_MEMORY;
return rc;
}
/** @copydoc RTDBGMODVTDBG::pfnSegmentByIndex */
static DECLCALLBACK(int) rtDbgModContainer_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
{
return VERR_DBG_INVALID_SEGMENT_INDEX;
return VINF_SUCCESS;
}
/** @copydoc RTDBGMODVTDBG::pfnSegmentCount */
{
}
/** @copydoc RTDBGMODVTDBG::pfnSegmentAdd */
static DECLCALLBACK(int) rtDbgModContainer_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName, size_t cchName,
{
/*
* Input validation (the bits the caller cannot do).
*/
/* Overlapping segments are not yet supported. Will use flags to deal with it if it becomes necessary. */
while (iSeg-- > 0)
{
if ( uRva <= uCurRvaLast
|| ( cb == 0
&& uRva != uCurRvaLast)
)
)
AssertMsgFailedReturn(("uRva=%RTptr uRvaLast=%RTptr (cb=%RTptr) \"%s\";\n"
"uRva=%RTptr uRvaLast=%RTptr (cb=%RTptr) \"%s\" iSeg=%#x\n",
if (uRvaLastMax < uCurRvaLast)
}
/* Strict ordered segment addition at the moment. */
/*
* Add an entry to the segment table, extending it if necessary.
*/
if (!(iSeg % 8))
{
if (!pvSegs)
return VERR_NO_MEMORY;
}
{
if (piSeg)
return VINF_SUCCESS;
}
return VERR_NO_MEMORY;
}
/** @copydoc RTDBGMODVTDBG::pfnImageSize */
{
}
/** @copydoc RTDBGMODVTDBG::pfnRvaToSegOff */
static DECLCALLBACK(RTDBGSEGIDX) rtDbgModContainer_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
{
if (cSegs <= 7)
{
/*
* Linear search.
*/
{
{
if (poffSeg)
return iSeg;
}
}
}
else
{
/*
* Binary search.
*/
for (;;)
{
{
#if 0 /* Enable if we change the above test. */
while ( iSeg > 0
iSeg--;
#endif
if (poffSeg)
return iSeg;
}
/* advance */
{
/* between iFirst and iSeg. */
break;
}
else
{
/* between iSeg and iLast. paSeg[iSeg].cb == 0 ends up here too. */
break;
}
}
}
/* Invalid. */
return NIL_RTDBGSEGIDX;
}
/** Destroy a line number node. */
{
#ifdef RTDBGMODCNT_WITH_MEM_CACHE
#else
#endif
return 0;
}
/** Destroy a symbol node. */
static DECLCALLBACK(int) rtDbgModContainer_DestroyTreeNode(PAVLRUINTPTRNODECORE pNode, void *pvUser)
{
return 0;
}
/** @copydoc RTDBGMODVTDBG::pfnClose */
{
/*
* Destroy the symbols and instance data.
*/
{
}
#ifdef RTDBGMODCNT_WITH_MEM_CACHE
#else
#endif
return VINF_SUCCESS;
}
/** @copydoc RTDBGMODVTDBG::pfnTryOpen */
{
return VERR_INTERNAL_ERROR_5;
}
/** Virtual function table for the debug info container. */
{
/*.u32Magic = */ RTDBGMODVTDBG_MAGIC,
/*.fSupports = */ 0, /* (Don't call my TryOpen, please.) */
/*.pszName = */ "container",
/*.pfnTryOpen = */ rtDbgModContainer_TryOpen,
/*.pfnClose = */ rtDbgModContainer_Close,
/*.pfnRvaToSegOff = */ rtDbgModContainer_RvaToSegOff,
/*.pfnImageSize = */ rtDbgModContainer_ImageSize,
/*.pfnSegmentAdd = */ rtDbgModContainer_SegmentAdd,
/*.pfnSegmentCount = */ rtDbgModContainer_SegmentCount,
/*.pfnSegmentByIndex = */ rtDbgModContainer_SegmentByIndex,
/*.pfnSymbolAdd = */ rtDbgModContainer_SymbolAdd,
/*.pfnSymbolCount = */ rtDbgModContainer_SymbolCount,
/*.pfnSymbolByOrdinal = */ rtDbgModContainer_SymbolByOrdinal,
/*.pfnSymbolByName = */ rtDbgModContainer_SymbolByName,
/*.pfnSymbolByAddr = */ rtDbgModContainer_SymbolByAddr,
/*.pfnLineAdd = */ rtDbgModContainer_LineAdd,
/*.pfnLineCount = */ rtDbgModContainer_LineCount,
/*.pfnLineByOrdinal = */ rtDbgModContainer_LineByOrdinal,
/*.pfnLineByAddr = */ rtDbgModContainer_LineByAddr,
/*.u32EndMagic = */ RTDBGMODVTDBG_MAGIC
};
/**
* Special container operation for removing all symbols.
*
* @returns IPRT status code.
* @param pMod The module instance.
*/
{
{
}
pThis->iNextSymbolOrdinal = 0;
return VINF_SUCCESS;
}
/**
* Special container operation for removing all line numbers.
*
* @returns IPRT status code.
* @param pMod The module instance.
*/
{
pThis->iNextLineOrdinal = 0;
return VINF_SUCCESS;
}
/**
* Special container operation for removing everything.
*
* @returns IPRT status code.
* @param pMod The module instance.
*/
{
{
}
return VINF_SUCCESS;
}
/**
* Creates a generic debug info container and associates it with the module.
*
* @returns IPRT status code.
* @param pMod The module instance.
* @param cbSeg The size of the initial segment. 0 if segments are to be
* created manually later on.
*/
{
if (!pThis)
return VERR_NO_MEMORY;
pThis->iNextSymbolOrdinal = 0;
pThis->iNextLineOrdinal = 0;
#ifdef RTDBGMODCNT_WITH_MEM_CACHE
int rc = RTMemCacheCreate(&pThis->hLineNumAllocator, sizeof(RTDBGMODCTNLINE), sizeof(void *), UINT32_MAX,
#else
int rc = VINF_SUCCESS;
#endif
if (RT_SUCCESS(rc))
{
/*
* Add the initial segment.
*/
if (cbSeg)
if (RT_SUCCESS(rc))
return rc;
#ifdef RTDBGMODCNT_WITH_MEM_CACHE
#endif
}
return rc;
}