dbgmodnm.cpp revision 2d8870843ff566fee9bd3a6a5942414254106479
/* $Id$ */
/** @file
* IPRT - Debug Map Reader For NM Like Mapfiles.
*/
/*
* Copyright (C) 2009 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 *
*******************************************************************************/
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Instance data.
*/
typedef struct RTDBGMODNM
{
/** The debug container containing doing the real work. */
} RTDBGMODNM;
/** Pointer to instance data NM map reader. */
typedef RTDBGMODNM *PRTDBGMODNM;
/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByAddr} */
{
}
/** @interface_method_impl{RTDBGMODVTDBG,pfnLineByOrdinal} */
static DECLCALLBACK(int) rtDbgModNm_LineByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGLINE pLineInfo)
{
}
/** @interface_method_impl{RTDBGMODVTDBG,pfnLineCount} */
{
}
/** @interface_method_impl{RTDBGMODVTDBG,pfnLineAdd} */
static DECLCALLBACK(int) rtDbgModNm_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo,
{
}
/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByAddr} */
static DECLCALLBACK(int) rtDbgModNm_SymbolByAddr(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, RTUINTPTR off, uint32_t fFlags,
{
}
/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByName} */
static DECLCALLBACK(int) rtDbgModNm_SymbolByName(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
{
}
/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolByOrdinal} */
static DECLCALLBACK(int) rtDbgModNm_SymbolByOrdinal(PRTDBGMODINT pMod, uint32_t iOrdinal, PRTDBGSYMBOL pSymInfo)
{
}
/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolCount} */
{
}
/** @interface_method_impl{RTDBGMODVTDBG,pfnSymbolAdd} */
static DECLCALLBACK(int) rtDbgModNm_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol,
{
}
/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentByIndex} */
static DECLCALLBACK(int) rtDbgModNm_SegmentByIndex(PRTDBGMODINT pMod, RTDBGSEGIDX iSeg, PRTDBGSEGMENT pSegInfo)
{
}
/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentCount} */
{
}
/** @interface_method_impl{RTDBGMODVTDBG,pfnSegmentAdd} */
static DECLCALLBACK(int) rtDbgModNm_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName,
{
}
/** @interface_method_impl{RTDBGMODVTDBG,pfnImageSize} */
{
}
/** @interface_method_impl{RTDBGMODVTDBG,pfnRvaToSegOff} */
static DECLCALLBACK(RTDBGSEGIDX) rtDbgModNm_RvaToSegOff(PRTDBGMODINT pMod, RTUINTPTR uRva, PRTUINTPTR poffSeg)
{
}
/** @interface_method_impl{RTDBGMODVTDBG,pfnClose} */
{
return VINF_SUCCESS;
}
/**
* Scans a NM-like map file.
*
* This implements both passes to avoid code duplication.
*
* @returns IPRT status code.
* @param pThis The instance data.
* @param pStrm The stream.
* @param fAddSymbols false in the first pass, true in the second.
*/
{
/*
* Try parse the stream.
*/
unsigned cchAddr = 0;
int fWithType = -1;
char szLine[512];
int rc;
{
char chType;
if (RT_C_IS_XDIGIT(szLine[0]))
{
/*
* This is really what C was made for, string parsing.
*/
/* The the symbol value (address). */
char *psz;
if (rc != VWRN_TRAILING_CHARS)
return VERR_DBG_NOT_NM_MAP_FILE;
/* Check the address width. */
if (cchAddr == 0)
return VERR_DBG_NOT_NM_MAP_FILE;
/* Get the type and check for single space before symbol. */
char *pszName;
if (fWithType < 0)
fWithType = RT_C_IS_BLANK(szLine[cchAddr + 2]) ? 1 : 0; /* have type? Linux 2.4 /proc/ksyms doesn't. */
if (fWithType)
{
if ( RT_C_IS_BLANK(chType)
return VERR_DBG_NOT_NM_MAP_FILE;
}
else
{
chType = 'T';
}
/* Find the end of the symbol name. */
char *pszNameEnd = pszName;
char ch;
pszNameEnd++;
char *pszModName = pszNameEnd;
char *pszModNameEnd = pszModName;
if (*pszModName)
{
*pszModName++ = '\0';
if (*pszModName != '\0')
{
if (*pszModName != '[')
return VERR_DBG_NOT_LINUX_KALLSYMS;
pszModNameEnd = ++pszModName;
if (ch != ']')
return VERR_DBG_NOT_LINUX_KALLSYMS;
return VERR_DBG_NOT_LINUX_KALLSYMS;
*pszModNameEnd = '\0';
if (*pszEnd)
if (*pszEnd)
return VERR_DBG_NOT_LINUX_KALLSYMS;
}
}
/*
* Did the module change? Then update the symbol prefix.
*/
{
if (cchMod == 0)
offSym = 0;
else
{
}
}
/*
* Validate the type and add the symbol if it's a type we care for.
*/
RTDBGSEGIDX iSegSym = 0;
switch (chType)
{
/* absolute */
case 'a':
/// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
break;
case 'A':
/// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
break;
case 'b':
/// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
break;
case 'B':
/// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
break;
case 'c':
/// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL | RTDBG_SYM_FLAGS_COMMON;
break;
case 'C':
/// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC | RTDBG_SYM_FLAGS_COMMON;
break;
case 'd':
/// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
break;
case 'D':
/// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
break;
case 'g':
/// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
break;
case 'G':
/// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
break;
case 'i':
/// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
break;
case 'I':
/// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
break;
case 'r':
/// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL | RTDBG_SYM_FLAGS_CONST;
break;
case 'R':
/// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC | RTDBG_SYM_FLAGS_CONST;
break;
case 's':
/// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL;
break;
case 'S':
/// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC;
break;
case 't':
/// @todo fFlags |= RTDBG_SYM_FLAGS_LOCAL | RTDBG_SYM_FLAGS_TEXT;
break;
case 'T':
/// @todo fFlags |= RTDBG_SYM_FLAGS_PUBLIC | RTDBG_SYM_FLAGS_TEXT;
break;
case 'w':
/// @todo fFlags |= RTDBG_SYM_FLAGS_WEAK | RTDBG_SYM_FLAGS_LOCAL; //???
break;
case 'W':
/// @todo fFlags |= RTDBG_SYM_FLAGS_WEAK | RTDBG_SYM_FLAGS_PUBLIC;
break;
case 'N': /* debug */
case 'n':
case '-': /* stabs */
case 'U':
case 'v': /* weakext */
case 'V':
break;
default:
return VERR_DBG_NOT_NM_MAP_FILE;
}
if (iSegSym != NIL_RTDBGSEGIDX)
{
if (fAddSymbols)
{
if (iSegSym == 0)
else
if ( RT_FAILURE(rc)
&& rc != VERR_DBG_DUPLICATE_SYMBOL
return rc;
}
/* Track segment span. */
if (iSegSym == 0)
{
}
}
}
else
{
/*
* This is either a blank line or a symbol without an address.
*/
if (szLine[0])
{
if (cchAddr == 0)
return VERR_DBG_NOT_NM_MAP_FILE;
if ( chType != 'U'
&& chType != 'w')
return VERR_DBG_NOT_NM_MAP_FILE;
return VERR_DBG_NOT_NM_MAP_FILE;
return VERR_DBG_NOT_NM_MAP_FILE;
}
/* else: blank - ignored */
}
}
/*
* The final segment.
*/
{
if (fAddSymbols)
rc = VINF_SUCCESS;
else
{
if ( u64Low != UINT64_MAX
|| u64High != 0)
else /* No sensible symbols... throw an error instead? */
}
}
return rc;
}
/** @interface_method_impl{RTDBGMODVTDBG,pfnTryOpen} */
{
/*
* Fend off images.
*/
if ( !pMod->pszDbgFile
return VERR_DBG_NO_MATCHING_INTERPRETER;
/*
* Try open the file and create an instance.
*/
if (RT_SUCCESS(rc))
{
if (pThis)
{
if (RT_SUCCESS(rc))
{
/*
* Scan the file twice, first to figure the segment
* sizes, then to add the symbol.
*/
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
return rc;
}
}
}
else
rc = VERR_NO_MEMORY;
}
return rc;
}
/** Virtual function table for the NM-like map file reader. */
{
/*.u32Magic = */ RTDBGMODVTDBG_MAGIC,
/*.fSupports = */ RT_DBGTYPE_MAP,
/*.pszName = */ "nm",
/*.pfnTryOpen = */ rtDbgModNm_TryOpen,
/*.pfnClose = */ rtDbgModNm_Close,
/*.pfnRvaToSegOff = */ rtDbgModNm_RvaToSegOff,
/*.pfnImageSize = */ rtDbgModNm_ImageSize,
/*.pfnSegmentAdd = */ rtDbgModNm_SegmentAdd,
/*.pfnSegmentCount = */ rtDbgModNm_SegmentCount,
/*.pfnSegmentByIndex = */ rtDbgModNm_SegmentByIndex,
/*.pfnSymbolAdd = */ rtDbgModNm_SymbolAdd,
/*.pfnSymbolCount = */ rtDbgModNm_SymbolCount,
/*.pfnSymbolByOrdinal = */ rtDbgModNm_SymbolByOrdinal,
/*.pfnSymbolByName = */ rtDbgModNm_SymbolByName,
/*.pfnSymbolByAddr = */ rtDbgModNm_SymbolByAddr,
/*.pfnLineAdd = */ rtDbgModNm_LineAdd,
/*.pfnLineCount = */ rtDbgModNm_LineCount,
/*.pfnLineByOrdinal = */ rtDbgModNm_LineByOrdinal,
/*.pfnLineByAddr = */ rtDbgModNm_LineByAddr,
/*.u32EndMagic = */ RTDBGMODVTDBG_MAGIC
};