[+] pyDia: findByRva for global scope

git-svn-id: https://pykd.svn.codeplex.com/svn@69976 9b283d60-5439-405e-af05-b73fd8c4d996
This commit is contained in:
SND\EreTIk_cp 2011-09-23 09:01:49 +00:00 committed by Mikhail I. Izmestev
parent 2d40f6c38a
commit 910849825e
6 changed files with 401 additions and 299 deletions

View File

@ -174,7 +174,10 @@ BOOST_PYTHON_MODULE( pykd )
.def("__getitem__", &pyDia::Symbol::getChildByIndex); .def("__getitem__", &pyDia::Symbol::getChildByIndex);
python::class_<pyDia::GlobalScope, python::bases<pyDia::Symbol> >("DiaScope", "class wrapper for MS DIA Symbol" ) python::class_<pyDia::GlobalScope, python::bases<pyDia::Symbol> >("DiaScope", "class wrapper for MS DIA Symbol" )
.def("machineType", &pyDia::GlobalScope::getMachineType, "Retrieves the type of the target CPU: IMAGE_FILE_MACHINE_XXX"); .def("machineType", &pyDia::GlobalScope::getMachineType,
"Retrieves the type of the target CPU: IMAGE_FILE_MACHINE_XXX")
.def("findByRva", &pyDia::GlobalScope::findByRva,
"Find symbol by RVA. Return tuple: (DiaSymbol, offset)");
// CPU type: // CPU type:
DEF_PY_CONST_ULONG(IMAGE_FILE_MACHINE_I386); DEF_PY_CONST_ULONG(IMAGE_FILE_MACHINE_I386);

299
pykd/diaprint.cpp Normal file
View File

@ -0,0 +1,299 @@
#include "stdafx.h"
#include "diawrapper.h"
#include "utils.h"
namespace pyDia {
static void printVariant(
__in const VARIANT &vtValue,
__out std::stringstream &sstream
)
{
switch (vtValue.vt)
{
case VT_I1:
case VT_UI1:
sstream << ", Value: ";
sstream << "0x" << std::hex << vtValue.bVal;
break;
case VT_BOOL:
sstream << ", Value: ";
sstream << vtValue.iVal ? "True" : "False";
break;
case VT_I2:
case VT_UI2:
sstream << ", Value: ";
sstream << "0x" << std::hex << vtValue.iVal;
break;
case VT_I4:
case VT_UI4:
case VT_INT:
case VT_UINT:
case VT_ERROR:
case VT_HRESULT:
sstream << ", Value: ";
sstream << "0x" << std::hex << vtValue.lVal;
break;
case VT_I8:
case VT_UI8:
sstream << ", Value: ";
sstream << "0x" << std::hex << vtValue.llVal;
break;
case VT_R4:
sstream << ", Value: ";
sstream << vtValue.fltVal;
break;
case VT_R8:
sstream << ", Value: ";
sstream << vtValue.dblVal;
break;
case VT_BSTR:
sstream << ", Value: ";
sstream << "\"" << autoBstr::asStr(vtValue.bstrVal).c_str() << "\"";
break;
}
}
////////////////////////////////////////////////////////////////////////////////
std::string Symbol::printImpl(
IDiaSymbol *_symbol,
DWORD machineType,
ULONG indent /*= 0*/,
Symbol::checkSymLoop *checkLoopPrev /*= NULL*/,
const char *prefix /*= NULL*/
)
{
assert(_symbol);
std::stringstream sstream;
for (ULONG i =0; i < indent; ++i)
sstream << " ";
if (prefix)
sstream << prefix;
checkSymLoop _loop(checkLoopPrev, _symbol);
if (_loop.check())
{
sstream << "<...see above...>";
return sstream.str();
}
DWORD dwValue;
autoBstr bstrValue;
VARIANT vtValue = { VT_EMPTY };
bool bValue;
LONG lValue;
ULONGLONG ullValue;
HRESULT hres;
DWORD locType = LocIsNull;
hres = _symbol->get_locationType(&locType);
bool bLocation = (S_OK == hres);
if (bLocation)
{
hres = _symbol->get_offset(&lValue);
const bool bNegOffset = lValue < 0;
lValue = bNegOffset ? -1 * lValue : lValue;
switch (locType)
{
case LocIsBitField:
case LocIsThisRel:
assert(S_OK == hres);
sstream << (bNegOffset ? "-" : "+") << "0x" << std::hex << lValue;
if (LocIsBitField == locType)
{
hres = _symbol->get_bitPosition(&dwValue);
if (S_OK == hres)
sstream << ", Bit position: " << dwValue;
}
break;
case LocIsEnregistered:
case LocIsRegRel:
hres = _symbol->get_registerId(&dwValue);
if (S_OK == hres)
{
const char *regName = NULL;
if (IMAGE_FILE_MACHINE_I386 == machineType)
{
for (ULONG i = 0; i < cntI386RegName; ++i)
{
if (dwValue == i386RegName[i].first)
{
regName = i386RegName[i].second;
break;
}
}
}
else if (IMAGE_FILE_MACHINE_AMD64 == machineType)
{
for (ULONG i = 0; i < cntI386RegName; ++i)
{
if (dwValue == i386RegName[i].first)
{
regName = i386RegName[i].second;
break;
}
}
}
if (!regName)
{
sstream << locTypeName[locType].second;
}
else
{
if (LocIsEnregistered == locType)
{
sstream << regName;
}
else
{
sstream << "[" << regName;
sstream << (bNegOffset ? "-" : "+") << "0x" << std::hex << lValue;
sstream << "]";
}
}
}
else
{
sstream << locTypeName[locType].second;
}
break;
default:
if (S_OK == _symbol->get_relativeVirtualAddress(&dwValue))
sstream << "RVA:0x" << std::hex << dwValue;
else if (locType < _countof(locTypeName))
sstream << "Location: " << locTypeName[locType].second;
if (S_OK == hres)
{
sstream << ", Offset: ";
sstream << (bNegOffset ? "-" : "+") << "0x" << std::hex << lValue;
}
break;
}
}
bool bFuncDebugRange = false;
hres = _symbol->get_symTag(&dwValue);
if ((S_OK == hres) && dwValue < _countof(symTagName))
{
if (bLocation)
sstream << ", ";
sstream << symTagName[dwValue].second;
if (SymTagUDT == symTagName[dwValue].first)
{
hres = _symbol->get_udtKind(&dwValue);
if ((S_OK == hres) && (dwValue < cntUdtKindName))
sstream << ": " << udtKindName[dwValue].second;
}
bFuncDebugRange =
(SymTagFuncDebugStart == symTagName[dwValue].first) ||
(SymTagFuncDebugEnd == symTagName[dwValue].first);
}
else
{
sstream << "!invalid symTag!";
}
sstream << ", ";
hres = _symbol->get_name(&bstrValue);
if (S_OK == hres)
sstream << "\"" << bstrValue.asStr().c_str() << "\"";
else
sstream << "<no-name>";
bstrValue.free();
hres = _symbol->get_length(&ullValue);
if (S_OK == hres)
sstream << ", Length: 0x" << std::hex << ullValue;
bValue = false;
try
{
getValueImpl(_symbol, vtValue);
bValue = true;
}
catch (const Exception &except)
{
DBG_UNREFERENCED_PARAMETER(except);
}
if (bValue)
printVariant(vtValue, sstream);
hres = _symbol->get_baseType(&dwValue);
if (SUCCEEDED(hres) && btNoType != dwValue)
{
for (ULONG i = 0; i < cntBasicTypeName; ++i)
{
if (basicTypeName[i].first == dwValue)
{
sstream << ", Basic type: " << basicTypeName[i].second;
break;
}
}
}
DiaSymbolPtr pType;
hres = _symbol->get_type(&pType);
if (S_OK == hres)
{
sstream << std::endl;
sstream << printImpl(pType, machineType, indent+1, &_loop, "Type: ").c_str();
}
if (bFuncDebugRange)
return sstream.str();
DiaEnumSymbolsPtr symbols;
hres =
_symbol->findChildren(
SymTagNull,
NULL,
nsCaseSensitive,
&symbols);
if (S_OK == hres)
{
if (indent <= 2)
{
DiaSymbolPtr child;
ULONG celt;
while ( SUCCEEDED(symbols->Next(1, &child, &celt)) && (celt == 1) )
{
sstream << std::endl;
sstream << printImpl(child, machineType, indent + 1, &_loop).c_str();
child.Release();
}
}
else
{
lValue = 0;
symbols->get_Count(&lValue);
if (lValue)
{
sstream << std::endl;
for (ULONG i =0; i < indent+1; ++i)
sstream << " ";
sstream << "<...>";
}
}
}
return sstream.str();
}
////////////////////////////////////////////////////////////////////////////////
}

View File

@ -65,8 +65,6 @@ std::list< Symbol > Symbol::findChildrenImpl(
DWORD nameCmpFlags DWORD nameCmpFlags
) )
{ {
throwIfNull(__FUNCTION__);
DiaEnumSymbolsPtr symbols; DiaEnumSymbolsPtr symbols;
HRESULT hres = HRESULT hres =
m_symbol->findChildren( m_symbol->findChildren(
@ -147,9 +145,6 @@ LONG Symbol::getOffset()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Symbol::getValueImpl(IDiaSymbol *_symbol, VARIANT &vtValue) void Symbol::getValueImpl(IDiaSymbol *_symbol, VARIANT &vtValue)
{ {
if (!_symbol)
throw Exception(std::string(__FUNCTION__) + " failed, DIA object is not initialized");
HRESULT hres = _symbol->get_value(&vtValue); HRESULT hres = _symbol->get_value(&vtValue);
if (S_OK != hres) if (S_OK != hres)
throw Exception("Call IDiaSymbol::get_value", hres); throw Exception("Call IDiaSymbol::get_value", hres);
@ -203,8 +198,6 @@ python::object Symbol::getValue()
bool Symbol::isBasicType() bool Symbol::isBasicType()
{ {
throwIfNull(__FUNCTION__);
DWORD baseType = btNoType; DWORD baseType = btNoType;
return return
SUCCEEDED( m_symbol->get_baseType(&baseType) ) && SUCCEEDED( m_symbol->get_baseType(&baseType) ) &&
@ -250,8 +243,6 @@ ULONG Symbol::getRegisterId()
Symbol Symbol::getChildByName(const std::string &_name) Symbol Symbol::getChildByName(const std::string &_name)
{ {
throwIfNull(__FUNCTION__);
DiaEnumSymbolsPtr symbols; DiaEnumSymbolsPtr symbols;
HRESULT hres = HRESULT hres =
m_symbol->findChildren( m_symbol->findChildren(
@ -285,8 +276,6 @@ Symbol Symbol::getChildByName(const std::string &_name)
ULONG Symbol::getChildCount() ULONG Symbol::getChildCount()
{ {
throwIfNull(__FUNCTION__);
DiaEnumSymbolsPtr symbols; DiaEnumSymbolsPtr symbols;
HRESULT hres = HRESULT hres =
m_symbol->findChildren( m_symbol->findChildren(
@ -309,8 +298,6 @@ ULONG Symbol::getChildCount()
Symbol Symbol::getChildByIndex(ULONG _index) Symbol Symbol::getChildByIndex(ULONG _index)
{ {
throwIfNull(__FUNCTION__);
DiaEnumSymbolsPtr symbols; DiaEnumSymbolsPtr symbols;
HRESULT hres = HRESULT hres =
m_symbol->findChildren( m_symbol->findChildren(
@ -349,280 +336,6 @@ std::string Symbol::print()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::string Symbol::printImpl(IDiaSymbol *_symbol, DWORD machineType, ULONG indent /*= 0*/)
{
std::stringstream sstream;
for (ULONG i =0; i < indent; ++i)
sstream << " ";
if (_symbol)
{
DWORD dwValue;
autoBstr bstrValue;
VARIANT vtValue = { VT_EMPTY };
bool bValue;
LONG lValue;
ULONGLONG ullValue;
HRESULT hres;
DWORD locType = LocIsNull;
hres = _symbol->get_locationType(&locType);
bool bLocation = (S_OK == hres);
if (bLocation)
{
hres = _symbol->get_offset(&lValue);
const bool bNegOffset = lValue < 0;
lValue = bNegOffset ? -1 * lValue : lValue;
switch (locType)
{
case LocIsBitField:
case LocIsThisRel:
assert(S_OK == hres);
sstream << (bNegOffset ? "-" : "+") << "0x" << std::hex << lValue;
if (LocIsBitField == locType)
{
hres = _symbol->get_bitPosition(&dwValue);
if (S_OK == hres)
sstream << ", Bit position: " << dwValue;
}
break;
case LocIsEnregistered:
case LocIsRegRel:
hres = _symbol->get_registerId(&dwValue);
if (S_OK == hres)
{
const char *regName = NULL;
if (IMAGE_FILE_MACHINE_I386 == machineType)
{
for (ULONG i = 0; i < cntI386RegName; ++i)
{
if (dwValue == i386RegName[i].first)
{
regName = i386RegName[i].second;
break;
}
}
}
else if (IMAGE_FILE_MACHINE_AMD64 == machineType)
{
for (ULONG i = 0; i < cntI386RegName; ++i)
{
if (dwValue == i386RegName[i].first)
{
regName = i386RegName[i].second;
break;
}
}
}
if (!regName)
{
sstream << locTypeName[locType].second;
}
else
{
if (LocIsEnregistered == locType)
{
sstream << regName;
}
else
{
sstream << "[" << regName;
sstream << (bNegOffset ? "-" : "+") << "0x" << std::hex << lValue;
sstream << "]";
}
}
}
else
{
sstream << locTypeName[locType].second;
}
break;
default:
if (S_OK == _symbol->get_relativeVirtualAddress(&dwValue))
sstream << "RVA:0x" << std::hex << dwValue;
else if (locType < _countof(locTypeName))
sstream << "Location: " << locTypeName[locType].second;
if (S_OK == hres)
{
sstream << ", Offset: ";
sstream << (bNegOffset ? "-" : "+") << "0x" << std::hex << lValue;
}
break;
}
}
hres = _symbol->get_symTag(&dwValue);
if ((S_OK == hres) && dwValue < _countof(symTagName))
{
if (bLocation)
sstream << ", ";
sstream << symTagName[dwValue].second;
if (SymTagUDT == symTagName[dwValue].first)
{
hres = _symbol->get_udtKind(&dwValue);
if ((S_OK == hres) && (dwValue < cntUdtKindName))
sstream << ": " << udtKindName[dwValue].second;
}
}
else
{
sstream << "!invalid symTag!";
}
sstream << ", ";
hres = _symbol->get_name(&bstrValue);
if (S_OK == hres)
sstream << "\"" << bstrValue.asStr().c_str() << "\"";
else
sstream << "<no-name>";
bstrValue.free();
hres = _symbol->get_length(&ullValue);
if (S_OK == hres)
sstream << ", Length: 0x" << std::hex << ullValue;
bValue = false;
try
{
getValueImpl(_symbol, vtValue);
bValue = true;
}
catch (const Exception &except)
{
DBG_UNREFERENCED_PARAMETER(except);
}
if (bValue)
{
switch (vtValue.vt)
{
case VT_I1:
case VT_UI1:
sstream << ", Value: ";
sstream << "0x" << std::hex << vtValue.bVal;
break;
case VT_BOOL:
sstream << ", Value: ";
sstream << vtValue.iVal ? "True" : "False";
break;
case VT_I2:
case VT_UI2:
sstream << ", Value: ";
sstream << "0x" << std::hex << vtValue.iVal;
break;
case VT_I4:
case VT_UI4:
case VT_INT:
case VT_UINT:
case VT_ERROR:
case VT_HRESULT:
sstream << ", Value: ";
sstream << "0x" << std::hex << vtValue.lVal;
break;
case VT_I8:
case VT_UI8:
sstream << ", Value: ";
sstream << "0x" << std::hex << vtValue.llVal;
break;
case VT_R4:
sstream << ", Value: ";
sstream << vtValue.fltVal;
break;
case VT_R8:
sstream << ", Value: ";
sstream << vtValue.dblVal;
break;
case VT_BSTR:
sstream << ", Value: ";
sstream << "\"" << autoBstr::asStr(vtValue.bstrVal).c_str() << "\"";
break;
}
}
hres = _symbol->get_baseType(&dwValue);
if (SUCCEEDED(hres) && btNoType != dwValue)
{
for (ULONG i = 0; i < cntBasicTypeName; ++i)
{
if (basicTypeName[i].first == dwValue)
{
sstream << ", Basic type: " << basicTypeName[i].second;
break;
}
}
}
DWORD dwThisSymbol = 0;
hres = _symbol->get_symIndexId(&dwThisSymbol);
assert(S_OK == hres);
if (S_OK == hres)
{
DiaSymbolPtr pType;
hres = _symbol->get_type(&pType);
if (S_OK == hres)
{
DWORD dwTypeSymbol;
hres = pType->get_symIndexId(&dwTypeSymbol);
if ((S_OK == hres) && (dwTypeSymbol != dwThisSymbol))
{
sstream << std::endl;
for (ULONG i =0; i < indent; ++i)
sstream << " ";
sstream << "Type: " << std::endl;
sstream << printImpl(pType, machineType, indent + 1).c_str();
}
}
}
DiaEnumSymbolsPtr symbols;
hres =
_symbol->findChildren(
SymTagNull,
NULL,
nsCaseSensitive,
&symbols);
if (S_OK == hres)
{
if (indent <= 2)
{
DiaSymbolPtr child;
ULONG celt;
while ( SUCCEEDED(symbols->Next(1, &child, &celt)) && (celt == 1) )
{
sstream << std::endl << printImpl(child, machineType, indent + 1).c_str();
child.Release();
}
}
else
{
lValue = 0;
symbols->get_Count(&lValue);
if (lValue)
{
sstream << std::endl;
for (ULONG i =0; i < indent+1; ++i)
sstream << " ";
sstream << "<...>";
}
}
}
}
return sstream.str();
}
////////////////////////////////////////////////////////////////////////////////
GlobalScope::GlobalScope( GlobalScope::GlobalScope(
__inout DiaDataSourcePtr &_scope, __inout DiaDataSourcePtr &_scope,
__inout DiaSessionPtr &_session, __inout DiaSessionPtr &_session,
@ -664,4 +377,27 @@ GlobalScope GlobalScope::openPdb(const std::string &filePath)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Symbol GlobalScope::findByRvaImpl(
__in ULONG rva,
__in ULONG symTag,
__out LONG &displacement
)
{
DiaSymbolPtr child;
HRESULT hres =
m_session->findSymbolByRVAEx(
rva,
static_cast<enum SymTagEnum>(symTag),
&child,
&displacement);
if (S_OK != hres)
throw Exception("Call IDiaSession::findSymbolByRVAEx", hres);
if (!child)
throw Exception("Call IDiaSession::findSymbolByRVAEx", E_UNEXPECTED);
return Symbol( child, m_machineType );
}
////////////////////////////////////////////////////////////////////////////////
} }

View File

@ -56,7 +56,10 @@ private:
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
class Symbol { class Symbol {
public: public:
Symbol() {} Symbol()
{
throw Exception("DiaSymbol must be created over factory from DiaScope::...");
}
std::list< Symbol > findChildrenImpl( std::list< Symbol > findChildrenImpl(
ULONG symTag, ULONG symTag,
@ -138,7 +141,42 @@ public:
protected: protected:
static std::string printImpl(IDiaSymbol *_symbol, DWORD machineType, ULONG indent = 0); // Check symbols loop
class checkSymLoop
{
public:
checkSymLoop(checkSymLoop *prev, IDiaSymbol *_symbol)
: m_prev(prev)
, m_symIndexId(0)
{
_symbol->get_symIndexId(&m_symIndexId);
}
bool check() const
{
const checkSymLoop *prev = m_prev;
while (prev)
{
if (prev->m_symIndexId == m_symIndexId)
return true;
prev = prev->m_prev;
}
return false;
}
private:
const checkSymLoop *m_prev;
DWORD m_symIndexId;
};
static std::string printImpl(
IDiaSymbol *_symbol,
DWORD machineType,
ULONG indent = 0,
checkSymLoop *checkLoopPrev = NULL,
const char *prefix = NULL
);
template <typename TRet> template <typename TRet>
TRet callSymbolT( TRet callSymbolT(
@ -147,8 +185,6 @@ protected:
const char *methodName const char *methodName
) )
{ {
throwIfNull(funcName);
TRet retValue; TRet retValue;
HRESULT hres = (m_symbol->*method)(&retValue); HRESULT hres = (m_symbol->*method)(&retValue);
if (S_OK != hres) if (S_OK != hres)
@ -157,12 +193,6 @@ protected:
return retValue; return retValue;
} }
void throwIfNull(const char *desc)
{
if (!m_symbol)
throw Exception(std::string(desc) + " failed, DIA object is not initialized");
}
Symbol(__inout DiaSymbolPtr &_symbol, DWORD machineType) Symbol(__inout DiaSymbolPtr &_symbol, DWORD machineType)
: m_machineType(machineType) : m_machineType(machineType)
{ {
@ -186,13 +216,30 @@ class GlobalScope : public Symbol {
public: public:
GlobalScope() {} GlobalScope() {}
// create GlobalScope instance // GlobalScope factory
static GlobalScope openPdb(const std::string &filePath); static GlobalScope openPdb(const std::string &filePath);
ULONG getMachineType() const { ULONG getMachineType() const {
return m_machineType; return m_machineType;
} }
// RVA -> Symbol
python::tuple findByRva(
ULONG rva,
ULONG symTag
)
{
LONG displacement;
Symbol child = findByRvaImpl(rva, symTag, displacement);
return python::make_tuple(child, displacement);
}
Symbol findByRvaImpl(
__in ULONG rva,
__in ULONG symTag,
__out LONG &displacement
);
private: private:
GlobalScope( GlobalScope(

View File

@ -369,6 +369,10 @@
RelativePath=".\diadata.cpp" RelativePath=".\diadata.cpp"
> >
</File> </File>
<File
RelativePath=".\diaprint.cpp"
>
</File>
<File <File
RelativePath=".\diawrapper.cpp" RelativePath=".\diawrapper.cpp"
> >

View File

@ -104,3 +104,16 @@ class DiaTest( unittest.TestCase ):
gScope = pykd.diaOpenPdb( str(target.module.pdb()) ) gScope = pykd.diaOpenPdb( str(target.module.pdb()) )
self.assertTrue( (gScope.machineType() == pykd.IMAGE_FILE_MACHINE_I386) or self.assertTrue( (gScope.machineType() == pykd.IMAGE_FILE_MACHINE_I386) or
(gScope.machineType() == pykd.IMAGE_FILE_MACHINE_AMD64) ) (gScope.machineType() == pykd.IMAGE_FILE_MACHINE_AMD64) )
def testFindByRva(self):
gScope = pykd.diaOpenPdb( str(target.module.pdb()) )
func = gScope["FuncWithName0"]
tplSymOffset = gScope.findByRva(func.rva(), pykd.SymTagFunction)
self.assertEqual(tplSymOffset[0].indexId(), func.indexId())
self.assertEqual(tplSymOffset[1], 0)
tplSymOffset = gScope.findByRva(func.rva() + 2, pykd.SymTagFunction)
self.assertEqual(tplSymOffset[0].indexId(), func.indexId())
self.assertEqual(tplSymOffset[1], 2)