dbgmodcontainer.cpp revision aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32
/* $Id$ */
/** @file
* IPRT - Debug Info Container.
*/
/*
* Copyright (C) 2009 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* 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.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <iprt/dbg.h>
#include "internal/iprt.h"
#include <iprt/avl.h>
#include <iprt/err.h>
#include <iprt/mem.h>
#include <iprt/string.h>
#include <iprt/strcache.h>
#include "internal/dbgmod.h"
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Symbol entry.
*/
typedef struct RTDBGMODCTNSYMBOL
{
/** The address core. */
AVLRUINTPTRNODECORE AddrCore;
/** The name space core. */
RTSTRSPACECORE NameCore;
/** The ordinal number core. */
AVLU32NODECORE OrdinalCore;
/** The segment index. */
RTDBGSEGIDX iSeg;
/** The symbol flags. */
uint32_t fFlags;
/** The symbol size.
* This may be zero while the range in AddrCore indicates 0. */
RTUINTPTR cb;
} RTDBGMODCTNSYMBOL;
/** 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. */
AVLUINTPTRNODECORE AddrCore;
/** The ordinal number core. */
AVLU32NODECORE OrdinalCore;
/** Pointer to the file name (in string cache). */
const char *pszFile;
/** The line number. */
uint32_t uLineNo;
/** The segment index. */
RTDBGSEGIDX iSeg;
} RTDBGMODCTNLINE;
/** 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. */
AVLRUINTPTRTREE SymAddrTree;
/** The line number address space tree. */
AVLUINTPTRTREE LineAddrTree;
/** The segment offset. */
RTUINTPTR off;
/** The segment size. */
RTUINTPTR cb;
/** The segment flags. */
uint32_t fFlags;
/** The segment name. */
const char *pszName;
} RTDBGMODCTNSEGMENT;
/** 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. */
RTSTRSPACE Names;
/** Tree containing any absolute addresses. */
AVLRUINTPTRTREE AbsAddrTree;
/** Tree organizing the symbols by ordinal number. */
AVLU32TREE SymbolOrdinalTree;
/** Tree organizing the line numbers by ordinal number. */
AVLU32TREE LineOrdinalTree;
/** Segment table. */
PRTDBGMODCTNSEGMENT paSegs;
/** The number of segments in the segment table. */
RTDBGSEGIDX cSegs;
/** The image size. 0 means unlimited. */
RTUINTPTR cb;
/** The next symbol ordinal. */
uint32_t iNextSymbolOrdinal;
/** The next line number ordinal. */
uint32_t iNextLineOrdinal;
} 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.
*/
DECLINLINE(int) rtDbgModContainerReturnSymbol(PCRTDBGMODCTNSYMBOL pMySym, PRTDBGSYMBOL pExtSym)
{
pExtSym->Value = pMySym->AddrCore.Key;
pExtSym->offSeg = pMySym->AddrCore.Key;
pExtSym->iSeg = pMySym->iSeg;
pExtSym->fFlags = pMySym->fFlags;
pExtSym->cb = pMySym->cb;
pExtSym->iOrdinal = pMySym->OrdinalCore.Key;
Assert(pMySym->NameCore.cchString < sizeof(pExtSym->szName));
memcpy(pExtSym->szName, pMySym->NameCore.pszString, pMySym->NameCore.cchString + 1);
return VINF_SUCCESS;
}
/** @copydoc RTDBGMODVTDBG::pfnLineByAddr */
static DECLCALLBACK(int) rtDbgModContainer_LineByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
PRTINTPTR poffDisp, PRTDBGLINE pLineInfo)
{
PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
/*
* Validate the input address.
*/
AssertMsgReturn(iSeg < pThis->cSegs,
("iSeg=%#x cSegs=%#x\n", pThis->cSegs),
VERR_DBG_INVALID_SEGMENT_INDEX);
AssertMsgReturn(off < pThis->paSegs[iSeg].cb,
("off=%RTptr cbSeg=%RTptr\n", off, pThis->paSegs[iSeg].cb),
VERR_DBG_INVALID_SEGMENT_OFFSET);
/*
* 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
? VERR_DBG_LINE_NOT_FOUND
: VERR_DBG_NO_LINE_NUMBERS;
PCRTDBGMODCTNLINE pMyLine = RT_FROM_MEMBER(pAvlCore, RTDBGMODCTNLINE const, AddrCore);
pLineInfo->Address = pMyLine->AddrCore.Key;
pLineInfo->offSeg = pMyLine->AddrCore.Key;
pLineInfo->iSeg = iSeg;
pLineInfo->uLineNo = pMyLine->uLineNo;
pLineInfo->iOrdinal = pMyLine->OrdinalCore.Key;
strcpy(pLineInfo->szFilename, pMyLine->pszFile);
if (poffDisp)
*poffDisp = off - pMyLine->AddrCore.Key;
return VINF_SUCCESS;
}
/** @copydoc RTDBGMODVTDBG::pfnLineByOrdinal */
static DECLCALLBACK(int) rtDbgModContainer_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
{
PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
/*
* Look it up.
*/
if (iOrdinal >= pThis->iNextLineOrdinal)
return pThis->iNextLineOrdinal
? VERR_DBG_LINE_NOT_FOUND
: VERR_DBG_NO_LINE_NUMBERS;
PAVLU32NODECORE pAvlCore = RTAvlU32Get(&pThis->LineOrdinalTree, iOrdinal);
AssertReturn(pAvlCore, VERR_DBG_LINE_NOT_FOUND);
PCRTDBGMODCTNLINE pMyLine = RT_FROM_MEMBER(pAvlCore, RTDBGMODCTNLINE const, OrdinalCore);
pLineInfo->Address = pMyLine->AddrCore.Key;
pLineInfo->offSeg = pMyLine->AddrCore.Key;
pLineInfo->iSeg = pMyLine->iSeg;
pLineInfo->uLineNo = pMyLine->uLineNo;
pLineInfo->iOrdinal = pMyLine->OrdinalCore.Key;
strcpy(pLineInfo->szFilename, pMyLine->pszFile);
return VINF_SUCCESS;
}
/** @copydoc RTDBGMODVTDBG::pfnLineCount */
static DECLCALLBACK(uint32_t) rtDbgModContainer_LineCount(PRTDBGMODINT pMod)
{
PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
/* 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,
uint32_t iSeg, RTUINTPTR off, uint32_t *piOrdinal)
{
PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
/*
* Validate the input address.
*/
AssertMsgReturn(iSeg < pThis->cSegs, ("iSeg=%#x cSegs=%#x\n", pThis->cSegs),
VERR_DBG_INVALID_SEGMENT_INDEX);
AssertMsgReturn(off < pThis->paSegs[iSeg].cb, ("off=%RTptr cbSeg=%RTptr\n", off, pThis->paSegs[iSeg].cb),
VERR_DBG_INVALID_SEGMENT_OFFSET);
/*
* Create a new entry.
*/
PRTDBGMODCTNLINE pLine = (PRTDBGMODCTNLINE)RTMemAllocZ(sizeof(*pLine));
if (!pLine)
return VERR_NO_MEMORY;
pLine->AddrCore.Key = off;
pLine->OrdinalCore.Key = pThis->iNextLineOrdinal;
pLine->uLineNo = uLineNo;
pLine->iSeg = iSeg;
pLine->pszFile = RTStrCacheEnterN(g_hDbgModStrCache, pszFile, cchFile);
int rc;
if (pLine->pszFile)
{
if (RTAvlUIntPtrInsert(&pThis->paSegs[iSeg].LineAddrTree, &pLine->AddrCore))
{
if (RTAvlU32Insert(&pThis->LineOrdinalTree, &pLine->OrdinalCore))
{
if (piOrdinal)
*piOrdinal = pThis->iNextLineOrdinal;
pThis->iNextLineOrdinal++;
return VINF_SUCCESS;
}
rc = VERR_INTERNAL_ERROR_5;
RTAvlUIntPtrRemove(&pThis->paSegs[iSeg].LineAddrTree, pLine->AddrCore.Key);
}
/* bail out */
rc = VERR_DBG_ADDRESS_CONFLICT;
RTStrCacheRelease(g_hDbgModStrCache, pLine->pszFile);
}
else
rc = VERR_NO_MEMORY;
RTMemFree(pLine);
return rc;
}
/** @copydoc RTDBGMODVTDBG::pfnSymbolByAddr */
static DECLCALLBACK(int) rtDbgModContainer_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
PRTINTPTR poffDisp, PRTDBGSYMBOL pSymInfo)
{
PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
/*
* Validate the input address.
*/
AssertMsgReturn( iSeg == RTDBGSEGIDX_ABS
|| iSeg < pThis->cSegs,
("iSeg=%#x cSegs=%#x\n", pThis->cSegs),
VERR_DBG_INVALID_SEGMENT_INDEX);
AssertMsgReturn( iSeg >= RTDBGSEGIDX_SPECIAL_FIRST
|| off <= pThis->paSegs[iSeg].cb,
("off=%RTptr cbSeg=%RTptr\n", off, pThis->paSegs[iSeg].cb),
VERR_DBG_INVALID_SEGMENT_OFFSET);
/*
* Lookup the nearest symbol with an address less or equal to the specified address.
*/
PAVLRUINTPTRNODECORE pAvlCore = RTAvlrUIntPtrGetBestFit( iSeg == RTDBGSEGIDX_ABS
? &pThis->AbsAddrTree
: &pThis->paSegs[iSeg].SymAddrTree,
off,
false /*fAbove*/);
if (!pAvlCore)
return VERR_SYMBOL_NOT_FOUND;
PCRTDBGMODCTNSYMBOL pMySym = RT_FROM_MEMBER(pAvlCore, RTDBGMODCTNSYMBOL const, AddrCore);
if (poffDisp)
*poffDisp = off - pMySym->AddrCore.Key;
return rtDbgModContainerReturnSymbol(pMySym, pSymInfo);
}
/** @copydoc RTDBGMODVTDBG::pfnSymbolByName */
static DECLCALLBACK(int) rtDbgModContainer_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol, PRTDBGSYMBOL pSymInfo)
{
PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
NOREF(cchSymbol);
/*
* Look it up in the name space.
*/
PRTSTRSPACECORE pStrCore = RTStrSpaceGet(&pThis->Names, pszSymbol);
if (!pStrCore)
return VERR_SYMBOL_NOT_FOUND;
PCRTDBGMODCTNSYMBOL pMySym = RT_FROM_MEMBER(pStrCore, RTDBGMODCTNSYMBOL const, NameCore);
return rtDbgModContainerReturnSymbol(pMySym, pSymInfo);
}
/** @copydoc RTDBGMODVTDBG::pfnSymbolByOrdinal */
static DECLCALLBACK(int) rtDbgModContainer_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
{
PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
/*
* Look it up in the ordinal tree.
*/
if (iOrdinal >= pThis->iNextSymbolOrdinal)
return pThis->iNextSymbolOrdinal
? VERR_DBG_NO_SYMBOLS
: VERR_SYMBOL_NOT_FOUND;
PAVLU32NODECORE pAvlCore = RTAvlU32Get(&pThis->SymbolOrdinalTree, iOrdinal);
AssertReturn(pAvlCore, VERR_SYMBOL_NOT_FOUND);
PCRTDBGMODCTNSYMBOL pMySym = RT_FROM_MEMBER(pAvlCore, RTDBGMODCTNSYMBOL const, OrdinalCore);
return rtDbgModContainerReturnSymbol(pMySym, pSymInfo);
}
/** @copydoc RTDBGMODVTDBG::pfnSymbolCount */
static DECLCALLBACK(uint32_t) rtDbgModContainer_SymbolCount(PRTDBGMODINT pMod)
{
PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
/* 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,
RTDBGSEGIDX iSeg, RTUINTPTR off, RTUINTPTR cb, uint32_t fFlags,
uint32_t *piOrdinal)
{
PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
/*
* Address validation. The other arguments have already been validated.
*/
AssertMsgReturn( iSeg == RTDBGSEGIDX_ABS
|| iSeg < pThis->cSegs,
("iSeg=%#x cSegs=%#x\n", pThis->cSegs),
VERR_DBG_INVALID_SEGMENT_INDEX);
AssertMsgReturn( iSeg >= RTDBGSEGIDX_SPECIAL_FIRST
|| off + cb <= pThis->paSegs[iSeg].cb,
("off=%RTptr cb=%RTptr cbSeg=%RTptr\n", off, cb, pThis->paSegs[iSeg].cb),
VERR_DBG_INVALID_SEGMENT_OFFSET);
/*
* Create a new entry.
*/
PRTDBGMODCTNSYMBOL pSymbol = (PRTDBGMODCTNSYMBOL)RTMemAllocZ(sizeof(*pSymbol));
if (!pSymbol)
return VERR_NO_MEMORY;
pSymbol->AddrCore.Key = off;
pSymbol->AddrCore.KeyLast = off + (cb ? cb - 1 : 0);
pSymbol->OrdinalCore.Key = pThis->iNextSymbolOrdinal;
pSymbol->iSeg = iSeg;
pSymbol->cb = cb;
pSymbol->fFlags = fFlags;
pSymbol->NameCore.pszString = RTStrCacheEnter(g_hDbgModStrCache, pszSymbol);
int rc;
if (pSymbol->NameCore.pszString)
{
if (RTStrSpaceInsert(&pThis->Names, &pSymbol->NameCore))
{
PAVLRUINTPTRTREE pAddrTree = iSeg == RTDBGSEGIDX_ABS
? &pThis->AbsAddrTree
: &pThis->paSegs[iSeg].SymAddrTree;
if (RTAvlrUIntPtrInsert(pAddrTree, &pSymbol->AddrCore))
{
if (RTAvlU32Insert(&pThis->LineOrdinalTree, &pSymbol->OrdinalCore))
{
if (piOrdinal)
*piOrdinal = pThis->iNextSymbolOrdinal;
pThis->iNextSymbolOrdinal++;
return VINF_SUCCESS;
}
/* bail out */
rc = VERR_INTERNAL_ERROR_5;
RTAvlrUIntPtrRemove(pAddrTree, pSymbol->AddrCore.Key);
}
else
rc = VERR_DBG_ADDRESS_CONFLICT;
RTStrSpaceRemove(&pThis->Names, pSymbol->NameCore.pszString);
}
else
rc = VERR_DBG_DUPLICATE_SYMBOL;
RTStrCacheRelease(g_hDbgModStrCache, pSymbol->NameCore.pszString);
}
else
rc = VERR_NO_MEMORY;
RTMemFree(pSymbol);
return rc;
}
/** @copydoc RTDBGMODVTDBG::pfnSegmentByIndex */
static DECLCALLBACK(int) rtDbgModContainer_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
{
PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
if (iSeg >= pThis->cSegs)
return VERR_DBG_INVALID_SEGMENT_INDEX;
pSegInfo->Address = RTUINTPTR_MAX;
pSegInfo->uRva = pThis->paSegs[iSeg].off;
pSegInfo->cb = pThis->paSegs[iSeg].cb;
pSegInfo->fFlags = pThis->paSegs[iSeg].fFlags;
pSegInfo->iSeg = iSeg;
strcpy(pSegInfo->szName, pThis->paSegs[iSeg].pszName);
return VINF_SUCCESS;
}
/** @copydoc RTDBGMODVTDBG::pfnSegmentCount */
static DECLCALLBACK(RTDBGSEGIDX) rtDbgModContainer_SegmentCount(PRTDBGMODINT pMod)
{
PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
return pThis->cSegs;
}
/** @copydoc RTDBGMODVTDBG::pfnSegmentAdd */
static DECLCALLBACK(int) rtDbgModContainer_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName, size_t cchName,
uint32_t fFlags, PRTDBGSEGIDX piSeg)
{
PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
/*
* 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. */
RTUINTPTR uRvaLast = uRva + RT_MAX(cb, 1) - 1;
RTUINTPTR uRvaLastMax = uRvaLast;
RTDBGSEGIDX iSeg = pThis->cSegs;
while (iSeg-- > 0)
{
RTUINTPTR uCurRva = pThis->paSegs[iSeg].off;
RTUINTPTR uCurRvaLast = uCurRva + RT_MAX(pThis->paSegs[iSeg].cb, 1) - 1;
if ( uRva <= uCurRvaLast
&& uRvaLast >= uCurRva)
AssertMsgFailedReturn(("uRva=%RTptr uRvaLast=%RTptr (cb=%RTptr) \"%s\";\n"
"uRva=%RTptr uRvaLast=%RTptr (cb=%RTptr) \"%s\" iSeg=%#x\n",
uRva, uRvaLast, cb, pszName,
uCurRva, uCurRvaLast, pThis->paSegs[iSeg].cb, pThis->paSegs[iSeg].pszName, iSeg),
VERR_DBG_SEGMENT_INDEX_CONFLICT);
if (uRvaLastMax < uCurRvaLast)
uRvaLastMax = uCurRvaLast;
}
/* Strict ordered segment addition at the moment. */
iSeg = pThis->cSegs;
AssertMsgReturn(!piSeg || *piSeg == NIL_RTDBGSEGIDX || *piSeg == iSeg,
("iSeg=%#x *piSeg=%#x\n", iSeg, *piSeg),
VERR_DBG_INVALID_SEGMENT_INDEX);
/*
* Add an entry to the segment table, extending it if necessary.
*/
if (!(iSeg % 8))
{
void *pvSegs = RTMemRealloc(pThis->paSegs, sizeof(RTDBGMODCTNSEGMENT) * (iSeg + 8));
if (!pvSegs)
return VERR_NO_MEMORY;
pThis->paSegs = (PRTDBGMODCTNSEGMENT)pvSegs;
}
pThis->paSegs[iSeg].SymAddrTree = NULL;
pThis->paSegs[iSeg].LineAddrTree = NULL;
pThis->paSegs[iSeg].off = uRva;
pThis->paSegs[iSeg].cb = cb;
pThis->paSegs[iSeg].fFlags = fFlags;
pThis->paSegs[iSeg].pszName = RTStrCacheEnterN(g_hDbgModStrCache, pszName, cchName);
if (pThis->paSegs[iSeg].pszName)
{
if (piSeg)
*piSeg = iSeg;
pThis->cSegs++;
pThis->cb = uRvaLastMax + 1;
if (!pThis->cb)
pThis->cb = RTUINTPTR_MAX;
return VINF_SUCCESS;
}
return VERR_NO_MEMORY;
}
/** @copydoc RTDBGMODVTDBG::pfnRvaToSegOff */
static DECLCALLBACK(RTUINTPTR) rtDbgModContainer_ImageSize(PRTDBGMODINT pMod)
{
PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
return pThis->cb;
}
/** @copydoc RTDBGMODVTDBG::pfnRvaToSegOff */
static DECLCALLBACK(RTDBGSEGIDX) rtDbgModContainer_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
{
PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
PCRTDBGMODCTNSEGMENT paSeg = pThis->paSegs;
uint32_t const cSegs = pThis->cSegs;
if (cSegs <= 7)
{
/*
* Linear search.
*/
for (uint32_t iSeg = 0; iSeg < cSegs; iSeg++)
{
RTUINTPTR offSeg = uRva - paSeg[iSeg].off;
if (offSeg < paSeg[iSeg].cb)
{
if (poffSeg)
*poffSeg = offSeg;
return iSeg;
}
}
}
else
{
/*
* Binary search.
*/
uint32_t iFirst = 0;
uint32_t iLast = cSegs - 1;
for (;;)
{
uint32_t iSeg = iFirst + (iFirst - iLast) / 2;
RTUINTPTR offSeg = uRva - paSeg[iSeg].off;
if (offSeg < paSeg[iSeg].cb)
{
if (poffSeg)
*poffSeg = offSeg;
return iSeg;
}
/* advance */
if (uRva < paSeg[iSeg].off)
{
/* between iFirst and iSeg. */
if (iSeg == iFirst)
break;
iLast = iSeg - 1;
}
else
{
/* between iSeg and iLast. */
if (iSeg == iLast)
break;
iFirst = iSeg + 1;
}
}
}
/* Invalid. */
return NIL_RTDBGSEGIDX;
}
/** Destroy a symbol node. */
static DECLCALLBACK(int) rtDbgModContainer_DestroyTreeNode(PAVLRUINTPTRNODECORE pNode, void *pvUser)
{
PRTDBGMODCTNSYMBOL pSym = RT_FROM_MEMBER(pNode, RTDBGMODCTNSYMBOL, AddrCore);
RTStrCacheRelease(g_hDbgModStrCache, pSym->NameCore.pszString);
pSym->NameCore.pszString = NULL;
RTMemFree(pSym);
return 0;
}
/** @copydoc RTDBGMODVTDBG::pfnClose */
static DECLCALLBACK(int) rtDbgModContainer_Close(PRTDBGMODINT pMod)
{
PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv;
/*
* Destroy the symbols and instance data.
*/
for (uint32_t iSeg = 0; iSeg < pThis->cSegs; iSeg++)
{
RTAvlrUIntPtrDestroy(&pThis->paSegs[iSeg].SymAddrTree, rtDbgModContainer_DestroyTreeNode, NULL);
RTStrCacheRelease(g_hDbgModStrCache, pThis->paSegs[iSeg].pszName);
pThis->paSegs[iSeg].pszName = NULL;
}
RTAvlrUIntPtrDestroy(&pThis->AbsAddrTree, rtDbgModContainer_DestroyTreeNode, NULL);
pThis->Names = NULL;
RTMemFree(pThis->paSegs);
pThis->paSegs = NULL;
RTMemFree(pThis);
return VINF_SUCCESS;
}
/** @copydoc RTDBGMODVTDBG::pfnTryOpen */
static DECLCALLBACK(int) rtDbgModContainer_TryOpen(PRTDBGMODINT pMod)
{
return VERR_INTERNAL_ERROR_5;
}
/** Virtual function table for the debug info container. */
static RTDBGMODVTDBG const g_rtDbgModVtDbgContainer =
{
/*.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
};
/**
* 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.
*/
int rtDbgModContainerCreate(PRTDBGMODINT pMod, RTUINTPTR cbSeg)
{
PRTDBGMODCTN pThis = (PRTDBGMODCTN)RTMemAlloc(sizeof(*pThis));
if (!pThis)
return VERR_NO_MEMORY;
pThis->Names = NULL;
pThis->AbsAddrTree = NULL;
pThis->SymbolOrdinalTree = NULL;
pThis->LineOrdinalTree = NULL;
pThis->paSegs = NULL;
pThis->cSegs = 0;
pThis->cb = 0;
pThis->iNextSymbolOrdinal = 0;
pThis->iNextLineOrdinal = 0;
pMod->pDbgVt = &g_rtDbgModVtDbgContainer;
pMod->pvDbgPriv = pThis;
/*
* Add the initial segment.
*/
if (cbSeg)
{
int rc = rtDbgModContainer_SegmentAdd(pMod, 0, cbSeg, "default", sizeof("default") - 1, 0, NULL);
if (RT_FAILURE(rc))
{
RTMemFree(pThis);
pMod->pDbgVt = NULL;
pMod->pvDbgPriv = NULL;
return rc;
}
}
return VINF_SUCCESS;
}