diff --git a/pykd/dbgext.cpp b/pykd/dbgext.cpp index a9ab56b..0333b06 100644 --- a/pykd/dbgext.cpp +++ b/pykd/dbgext.cpp @@ -174,7 +174,10 @@ BOOST_PYTHON_MODULE( pykd ) .def("__getitem__", &pyDia::Symbol::getChildByIndex); python::class_ >("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: DEF_PY_CONST_ULONG(IMAGE_FILE_MACHINE_I386); diff --git a/pykd/diaprint.cpp b/pykd/diaprint.cpp new file mode 100644 index 0000000..a815810 --- /dev/null +++ b/pykd/diaprint.cpp @@ -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 << ""; + 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(); +} + +//////////////////////////////////////////////////////////////////////////////// + +} diff --git a/pykd/diawrapper.cpp b/pykd/diawrapper.cpp index dfe084a..0d54ef9 100644 --- a/pykd/diawrapper.cpp +++ b/pykd/diawrapper.cpp @@ -65,8 +65,6 @@ std::list< Symbol > Symbol::findChildrenImpl( DWORD nameCmpFlags ) { - throwIfNull(__FUNCTION__); - DiaEnumSymbolsPtr symbols; HRESULT hres = m_symbol->findChildren( @@ -147,9 +145,6 @@ LONG Symbol::getOffset() //////////////////////////////////////////////////////////////////////////////// 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); if (S_OK != hres) throw Exception("Call IDiaSymbol::get_value", hres); @@ -203,8 +198,6 @@ python::object Symbol::getValue() bool Symbol::isBasicType() { - throwIfNull(__FUNCTION__); - DWORD baseType = btNoType; return SUCCEEDED( m_symbol->get_baseType(&baseType) ) && @@ -250,8 +243,6 @@ ULONG Symbol::getRegisterId() Symbol Symbol::getChildByName(const std::string &_name) { - throwIfNull(__FUNCTION__); - DiaEnumSymbolsPtr symbols; HRESULT hres = m_symbol->findChildren( @@ -285,8 +276,6 @@ Symbol Symbol::getChildByName(const std::string &_name) ULONG Symbol::getChildCount() { - throwIfNull(__FUNCTION__); - DiaEnumSymbolsPtr symbols; HRESULT hres = m_symbol->findChildren( @@ -309,8 +298,6 @@ ULONG Symbol::getChildCount() Symbol Symbol::getChildByIndex(ULONG _index) { - throwIfNull(__FUNCTION__); - DiaEnumSymbolsPtr symbols; HRESULT hres = 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 << ""; - 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( __inout DiaDataSourcePtr &_scope, __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(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 ); +} + +//////////////////////////////////////////////////////////////////////////////// + } diff --git a/pykd/diawrapper.h b/pykd/diawrapper.h index 54448e3..1bfe2ac 100644 --- a/pykd/diawrapper.h +++ b/pykd/diawrapper.h @@ -56,7 +56,10 @@ private: //////////////////////////////////////////////////////////////////////////////// class Symbol { public: - Symbol() {} + Symbol() + { + throw Exception("DiaSymbol must be created over factory from DiaScope::..."); + } std::list< Symbol > findChildrenImpl( ULONG symTag, @@ -138,7 +141,42 @@ public: 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 TRet callSymbolT( @@ -147,8 +185,6 @@ protected: const char *methodName ) { - throwIfNull(funcName); - TRet retValue; HRESULT hres = (m_symbol->*method)(&retValue); if (S_OK != hres) @@ -157,12 +193,6 @@ protected: 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) : m_machineType(machineType) { @@ -186,13 +216,30 @@ class GlobalScope : public Symbol { public: GlobalScope() {} - // create GlobalScope instance + // GlobalScope factory static GlobalScope openPdb(const std::string &filePath); ULONG getMachineType() const { 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: GlobalScope( diff --git a/pykd/pykd_2008.vcproj b/pykd/pykd_2008.vcproj index 5a4b04a..c936340 100644 --- a/pykd/pykd_2008.vcproj +++ b/pykd/pykd_2008.vcproj @@ -369,6 +369,10 @@ RelativePath=".\diadata.cpp" > + + diff --git a/test/scripts/diatest.py b/test/scripts/diatest.py index 74be14d..97ea559 100644 --- a/test/scripts/diatest.py +++ b/test/scripts/diatest.py @@ -104,3 +104,16 @@ class DiaTest( unittest.TestCase ): gScope = pykd.diaOpenPdb( str(target.module.pdb()) ) self.assertTrue( (gScope.machineType() == pykd.IMAGE_FILE_MACHINE_I386) or (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) +