dbgmoddwarf.cpp revision c7814cf6e1240a519cbec0441e033d0e2470ed00
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * IPRT - Debug Info Reader For DWARF.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * Copyright (C) 2011-2012 Oracle Corporation
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * This file is part of VirtualBox Open Source Edition (OSE), as
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * available from http://www.virtualbox.org. This file is free software;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * you can redistribute it and/or modify it under the terms of the GNU
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * General Public License (GPL) as published by the Free Software
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * Foundation, in version 2 as it comes in the "COPYING" file of the
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * The contents of this file may alternatively be used under the terms
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * of the Common Development and Distribution License Version 1.0
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * VirtualBox OSE distribution, in which case the provisions of the
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * CDDL are applicable instead of those of the GPL.
cd3e933325e68e23516a196a8fea7f49b1e497c3Ali Bahrami * You may elect to license modified versions of this file under the
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * terms and conditions of either the GPL or the CDDL or both.
cd3e933325e68e23516a196a8fea7f49b1e497c3Ali Bahrami/*******************************************************************************
cd3e933325e68e23516a196a8fea7f49b1e497c3Ali Bahrami* Header Files *
cd3e933325e68e23516a196a8fea7f49b1e497c3Ali Bahrami*******************************************************************************/
cd3e933325e68e23516a196a8fea7f49b1e497c3Ali Bahrami/*******************************************************************************
cd3e933325e68e23516a196a8fea7f49b1e497c3Ali Bahrami* Defined Constants And Macros *
cd3e933325e68e23516a196a8fea7f49b1e497c3Ali Bahrami*******************************************************************************/
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock/** @name Standard DWARF Line Number Opcodes
typedef enum krtDbgModDwarfSect
typedef struct RTDWARFABBREV
bool fFilled;
bool fChildren;
typedef struct RTDBGMODDWARF
void const *pv;
bool fPresent;
typedef struct RTDWARFCURSOR
bool f64bitDwarf;
bool fNativEndian;
int rc;
typedef struct RTDWARFLINESTATE
bool fIsStatement;
bool fBasicBlock;
bool fEndSequence;
bool fPrologueEnd;
bool fEpilogueBegin;
} Regs;
} Hdr;
const char **papszIncPaths;
char **papszFileNames;
typedef DECLCALLBACK(int) FNRTDWARFATTRDECODER(PRTDWARFDIE pDie, uint8_t *pbMember, PCRTDWARFATTRDESC pDesc,
typedef struct RTDWARFATTRDESC
a_uAttr, \
typedef struct RTDWARFDIEDESC
typedef struct RTDWARFDIE
} RTDWARFDIE;
typedef struct RTDWARFADDR
} RTDWARFADDR;
typedef struct RTDWARFADDRRANGE
typedef enum krtDwarfRef
} krtDwarfRef;
typedef struct RTDWARFREF
} RTDWARFREF;
typedef struct RTDWARFDIECOMPILEUNIT
const char *pszName;
bool fUseUtf8;
bool fMainFunction;
const char *pszCurDir;
const char *pszProducer;
ATTR_ENTRY(DW_AT_language, RTDWARFDIECOMPILEUNIT, uLanguage, ATTR_INIT_ZERO, rtDwarfDecode_UnsignedInt),
ATTR_ENTRY(DW_AT_macro_info, RTDWARFDIECOMPILEUNIT, MacroInfoRef, ATTR_INIT_ZERO, rtDwarfDecode_SectOff),
ATTR_ENTRY(DW_AT_stmt_list, RTDWARFDIECOMPILEUNIT, StmtListRef, ATTR_INIT_ZERO, rtDwarfDecode_SectOff),
ATTR_ENTRY(DW_AT_producer, RTDWARFDIECOMPILEUNIT, pszProducer, ATTR_INIT_ZERO, rtDwarfDecode_String),
ATTR_ENTRY(DW_AT_identifier_case, RTDWARFDIECOMPILEUNIT, uIdentifierCase,ATTR_INIT_ZERO, rtDwarfDecode_UnsignedInt),
ATTR_ENTRY(DW_AT_base_types, RTDWARFDIECOMPILEUNIT, BaseTypesRef, ATTR_INIT_ZERO, rtDwarfDecode_Reference),
ATTR_ENTRY(DW_AT_main_subprogram, RTDWARFDIECOMPILEUNIT, fMainFunction, ATTR_INIT_ZERO, rtDwarfDecode_Bool)
static const RTDWARFDIEDESC g_CompileUnitDesc = DIE_DESC_INIT(RTDWARFDIECOMPILEUNIT, g_aCompileUnitAttrs);
typedef struct RTDWARFDIESUBPROGRAM
const char *pszName;
const char *pszLinkageName;
ATTR_ENTRY(DW_AT_linkage_name, RTDWARFDIESUBPROGRAM, pszLinkageName, ATTR_INIT_ZERO, rtDwarfDecode_String),
static const RTDWARFDIEDESC g_SubProgramDesc = DIE_DESC_INIT(RTDWARFDIESUBPROGRAM, g_aSubProgramAttrs);
static const struct RTDWARFTAGDESC
const char *pszName;
} g_aTagDescs[] =
static DECLCALLBACK(int) rtDbgModHlpAddSegmentCallback(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
return pMod->pDbgVt->pfnSegmentAdd(pMod, pSeg->RVA, cb, pSeg->pchName, pSeg->cchName, 0 /*fFlags*/, NULL);
return pMod->pDbgVt->pfnSegmentAdd(pMod, pSeg->LinkAddress, cb, pSeg->pchName, pSeg->cchName, 0 /*fFlags*/, NULL);
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VERR_OUT_OF_RANGE;
return pThis->pMod->pImgVt->pfnMapPart(pThis->pMod, pThis->aSections[enmSect].offFile, pThis->aSections[enmSect].cb,
#ifdef SOME_UNUSED_FUNCTION
return VINF_SUCCESS;
int rc = pThis->pMod->pImgVt->pfnUnmapPart(pThis->pMod, pThis->aSections[enmSect].cb, &pThis->aSections[enmSect].pv);
return rc;
return VINF_SUCCESS;
return uErrValue;
return u8;
return uErrValue;
return u16;
return uErrValue;
return u32;
return uErrValue;
return u64;
return uErrValue;
off++;
return u64Ret;
return sErrValue;
return (int8_t)b;
off++;
return uErrValue;
return sErrValue;
return VINF_SUCCESS;
return pszErrValue;
return pszRet;
static uint64_t rtDwarfCursor_GetVarSizedU(PRTDWARFCURSOR pCursor, size_t cbValue, uint64_t uErrValue)
switch (cbValue)
return uErrValue;
return uErrValue;
return u64Ret;
return uErrValue;
return cbUnit;
return offRet;
Log(("rtDwarfCursor_CalcPos: bad position %#zx, cbUnitLeft=%#zu\n", offRelative, pCursor->cbUnitLeft));
return NULL;
AssertFailed();
static int rtDwarfCursor_Init(PRTDWARFCURSOR pCursor, PRTDBGMODDWARF pThis, krtDbgModDwarfSect enmSect)
return rc;
return VINF_SUCCESS;
Log(("rtDwarfCursor_InitWithOffset: offSect=%#x cb=%#x enmSect=%d\n", offSect, pThis->aSections[enmSect].cb, enmSect));
return VERR_DWARF_BAD_POS;
return rc;
return rcOther;
static int rtDwarfLine_DefineFileName(PRTDWARFLINESTATE pLnState, const char *pszFilename, uint64_t idxInc)
void *pv = RTMemRealloc(pLnState->papszFileNames, sizeof(pLnState->papszFileNames[0]) * (iFileName + 2));
if (!pv)
return VERR_NO_MEMORY;
return VERR_NO_STR_MEMORY;
return rc;
int rc = rtDbgModDwarfLinkAddressToSegOffset(pLnState->pDwarfMod, pLnState->Regs.uAddress, &iSeg, &offSeg);
Log2(("rtDwarfLine_AddLine: %x:%08llx (%#llx) %s(%d) [offOpCode=%08x]\n", iSeg, offSeg, pLnState->Regs.uAddress, pszFile, pLnState->Regs.uLine, offOpCode));
return rc;
#ifdef LOG_ENABLED
Log2(("%08x: DW Special Opcode %#04x: uLine + %d => %u; uAddress + %#llx => %#llx; idxOp + %#llx => %#llx\n",
switch (bOpCode)
case DW_LNS_copy:
case DW_LNS_advance_pc:
case DW_LNS_advance_line:
Log2(("%08x: DW_LNS_advance_line: uLine + %d => %u\n", offOpCode, cLineDelta, pLnState->Regs.uLine));
case DW_LNS_set_file:
case DW_LNS_set_column:
case DW_LNS_negate_stmt:
case DW_LNS_set_basic_block:
case DW_LNS_const_add_pc:
case DW_LNS_fixed_advance_pc:
case DW_LNS_set_prologue_end:
case DW_LNS_set_isa:
Log(("rtDwarfLine_RunProgram: Unknown standard opcode %#x, %#x operands, at %08x.\n", bOpCode, cOpsToSkip, offOpCode));
while (cOpsToSkip-- > 0)
case DW_LNS_extended:
return VERR_DWARF_BAD_LNE;
switch (bOpCode)
case DW_LNE_end_sequence:
case DW_LNE_set_address:
case DW_LNE_define_file:
case DW_LNE_set_descriminator:
Log(("rtDwarfLine_RunProgram: Unknown extended opcode %#x, length %#x at %08x\n", bOpCode, cbInstr, offOpCode));
return rc;
return rc;
return rc;
if (!*psz)
return rc;
void *pv = RTMemRealloc(pLnState->papszIncPaths, sizeof(pLnState->papszIncPaths[0]) * (pLnState->cIncPaths + 2));
if (!pv)
return VERR_NO_MEMORY;
if (!*psz)
LnState.Hdr.u8DefIsStmt, LnState.Hdr.s8LineBase, LnState.Hdr.u8LineRange, LnState.Hdr.u8OpcodeBase));
return rc;
return VINF_SUCCESS;
return rc;
if (!uCode)
return NULL;
bool fFillCache = true;
fFillCache = false;
if (!pv)
fFillCache = false;
int rc = rtDwarfCursor_InitWithOffset(&Cursor, pThis, krtDbgModDwarfSect_abbrev, pThis->offCachedAbbrev);
return NULL;
if (fFillCache)
} while (uAttr != 0);
} while (uAttr != 0);
return pRet;
NULL);
static const char *rtDwarfDecode_GetStrp(PRTDBGMODDWARF pThis, PRTDWARFCURSOR pCursor, const char *pszErrValue)
return pszErrValue;
return pszErrValue;
return pszErrValue;
static DECLCALLBACK(int) rtDwarfDecode_Address(PRTDWARFDIE pDie, uint8_t *pbMember, PCRTDWARFATTRDESC pDesc,
switch (uForm)
return VINF_SUCCESS;
static DECLCALLBACK(int) rtDwarfDecode_Bool(PRTDWARFDIE pDie, uint8_t *pbMember, PCRTDWARFATTRDESC pDesc,
switch (uForm)
case DW_FORM_flag:
case DW_FORM_flag_present:
*pfMember = true;
return VINF_SUCCESS;
static DECLCALLBACK(int) rtDwarfDecode_LowHighPc(PRTDWARFDIE pDie, uint8_t *pbMember, PCRTDWARFATTRDESC pDesc,
switch (uForm)
return VINF_SUCCESS;
static DECLCALLBACK(int) rtDwarfDecode_Ranges(PRTDWARFDIE pDie, uint8_t *pbMember, PCRTDWARFATTRDESC pDesc,
switch (uForm)
return VINF_SUCCESS;
static DECLCALLBACK(int) rtDwarfDecode_Reference(PRTDWARFDIE pDie, uint8_t *pbMember, PCRTDWARFATTRDESC pDesc,
switch (uForm)
case DW_FORM_ref_addr:
case DW_FORM_ref_sig8:
return VINF_SUCCESS;
static DECLCALLBACK(int) rtDwarfDecode_SectOff(PRTDWARFDIE pDie, uint8_t *pbMember, PCRTDWARFATTRDESC pDesc,
switch (uForm)
return VINF_SUCCESS;
static DECLCALLBACK(int) rtDwarfDecode_String(PRTDWARFDIE pDie, uint8_t *pbMember, PCRTDWARFATTRDESC pDesc,
switch (uForm)
case DW_FORM_string:
case DW_FORM_strp:
static DECLCALLBACK(int) rtDwarfDecode_UnsignedInt(PRTDWARFDIE pDie, uint8_t *pbMember, PCRTDWARFATTRDESC pDesc,
switch (uForm)
return VERR_OUT_OF_RANGE;
return VERR_OUT_OF_RANGE;
return VERR_OUT_OF_RANGE;
return VERR_OUT_OF_RANGE;
return VINF_SUCCESS;
case DW_TAG_subprogram:
Log5(("subprogram %s (%s) <implement ranges>\n", pSubProgram->pszName, pSubProgram->pszLinkageName));
return rc;
case ATTR_INIT_ZERO:
case ATTR_INIT_FFFS:
AssertFailed();
AssertFailed();
if (pDie)
if (pParent)
return pDie;
switch (uForm)
case DW_FORM_addr:
case DW_FORM_block:
case DW_FORM_exprloc:
case DW_FORM_block1:
case DW_FORM_block2:
case DW_FORM_block4:
case DW_FORM_data1:
case DW_FORM_ref1:
case DW_FORM_flag:
case DW_FORM_data2:
case DW_FORM_ref2:
case DW_FORM_data4:
case DW_FORM_ref4:
case DW_FORM_data8:
case DW_FORM_ref8:
case DW_FORM_ref_sig8:
case DW_FORM_udata:
case DW_FORM_sdata:
case DW_FORM_ref_udata:
case DW_FORM_string:
case DW_FORM_indirect:
case DW_FORM_strp:
case DW_FORM_ref_addr:
case DW_FORM_sec_offset:
case DW_FORM_flag_present:
return VERR_DWARF_UNKNOWN_FORM;
#ifdef SOME_UNUSED_FUNCTION
return rc;
int rc = rtDwarfCursor_InitWithOffset(&AbbrevCursor, pThis, krtDbgModDwarfSect_abbrev, pAbbrev->offSpec);
return rc;
if (uAttr == 0)
if (pAttr)
return rc;
return VERR_DWARF_BAD_INFO;
if (!uAbbrCode)
return VERR_DWARF_BAD_INFO;
if (!pAbbrev)
return VERR_DWARF_ABBREV_NOT_FOUND;
return VERR_DWARF_BAD_INFO;
pUnit = (PRTDWARFDIECOMPILEUNIT)rtDwarfInfo_NewDie(pThis, &g_CompileUnitDesc, pAbbrev, NULL /*pParent*/);
if (!pUnit)
return VERR_NO_MEMORY;
return rc;
if (!uAbbrCode)
if (!pParentDie)
return VERR_DWARF_BAD_INFO;
cDepth--;
if (!pAbbrev)
return VERR_DWARF_ABBREV_NOT_FOUND;
const char *pszName;
if (!pNewDie)
return VERR_NO_MEMORY;
cDepth++;
return rc;
return rc;
static DECLCALLBACK(int) rtDbgModDwarf_LineByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off,
static DECLCALLBACK(int) rtDbgModDwarf_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
static DECLCALLBACK(int) rtDbgModDwarf_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo,
static DECLCALLBACK(int) rtDbgModDwarf_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
static DECLCALLBACK(int) rtDbgModDwarf_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
static DECLCALLBACK(int) rtDbgModDwarf_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
static DECLCALLBACK(int) rtDbgModDwarf_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
static DECLCALLBACK(int) rtDbgModDwarf_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
static DECLCALLBACK(int) rtDbgModDwarf_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName, size_t cchName,
static DECLCALLBACK(RTDBGSEGIDX) rtDbgModDwarf_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
pThis->pMod->pImgVt->pfnUnmapPart(pThis->pMod, pThis->aSections[iSect].cb, &pThis->aSections[iSect].pv);
return VINF_SUCCESS;
static DECLCALLBACK(int) rtDbgModDwarfEnumCallback(RTLDRMOD hLdrMod, uint32_t iDbgInfo, RTLDRDBGINFOTYPE enmType,
|| !pszPartNm
|| pszExtFile)
return VINF_SUCCESS;
#define ELSE_IF_STRCMP_SET(a_Name) else if (!strcmp(pszPartNm, #a_Name)) enmSect = krtDbgModDwarfSect_ ## a_Name
return VINF_SUCCESS;
AssertMsgReturn(!pThis->aSections[enmSect].fPresent, ("duplicate %s\n", pszPartNm), VINF_SUCCESS /*ignore*/);
return VINF_SUCCESS;
return VERR_DBG_NO_MATCHING_INTERPRETER;
if (!pThis)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
return rc;