pykd/pykd/diawrapper.cpp
SND\EreTIk_cp 394dfb7816 [+] pyDia: new tests, __getitem__
[~] pyDia: bugfix

git-svn-id: https://pykd.svn.codeplex.com/svn@69946 9b283d60-5439-405e-af05-b73fd8c4d996
2017-11-08 17:06:26 +04:00

554 lines
15 KiB
C++

#include "stdafx.h"
#include "diawrapper.h"
#include "utils.h"
namespace pyDia {
////////////////////////////////////////////////////////////////////////////////
PyObject *Exception::diaExceptTypeObject = NULL;
const std::string Exception::descPrefix("pyDia: ");
////////////////////////////////////////////////////////////////////////////////
#define _DEF_SYM_TAG_VAL(x) Symbol::ValueNameEntry(SymTag##x, #x)
const Symbol::ValueNameEntry Symbol::symTagName[SymTagMax] = {
_DEF_SYM_TAG_VAL(Null),
_DEF_SYM_TAG_VAL(Exe),
_DEF_SYM_TAG_VAL(Compiland),
_DEF_SYM_TAG_VAL(CompilandDetails),
_DEF_SYM_TAG_VAL(CompilandEnv),
_DEF_SYM_TAG_VAL(Function),
_DEF_SYM_TAG_VAL(Block),
_DEF_SYM_TAG_VAL(Data),
_DEF_SYM_TAG_VAL(Annotation),
_DEF_SYM_TAG_VAL(Label),
_DEF_SYM_TAG_VAL(PublicSymbol),
_DEF_SYM_TAG_VAL(UDT),
_DEF_SYM_TAG_VAL(Enum),
_DEF_SYM_TAG_VAL(FunctionType),
_DEF_SYM_TAG_VAL(PointerType),
_DEF_SYM_TAG_VAL(ArrayType),
_DEF_SYM_TAG_VAL(BaseType),
_DEF_SYM_TAG_VAL(Typedef),
_DEF_SYM_TAG_VAL(BaseClass),
_DEF_SYM_TAG_VAL(Friend),
_DEF_SYM_TAG_VAL(FunctionArgType),
_DEF_SYM_TAG_VAL(FuncDebugStart),
_DEF_SYM_TAG_VAL(FuncDebugEnd),
_DEF_SYM_TAG_VAL(UsingNamespace),
_DEF_SYM_TAG_VAL(VTableShape),
_DEF_SYM_TAG_VAL(VTable),
_DEF_SYM_TAG_VAL(Custom),
_DEF_SYM_TAG_VAL(Thunk),
_DEF_SYM_TAG_VAL(CustomType),
_DEF_SYM_TAG_VAL(ManagedType),
_DEF_SYM_TAG_VAL(Dimension)
};
#undef _DEF_SYM_TAG_VAL
#define _DEF_LOC_TYPE(x) Symbol::ValueNameEntry(LocIs##x, #x)
const Symbol::ValueNameEntry Symbol::locTypeName[LocTypeMax] = {
_DEF_LOC_TYPE(Null),
_DEF_LOC_TYPE(Static),
_DEF_LOC_TYPE(TLS),
_DEF_LOC_TYPE(RegRel),
_DEF_LOC_TYPE(ThisRel),
_DEF_LOC_TYPE(Enregistered),
_DEF_LOC_TYPE(BitField),
_DEF_LOC_TYPE(Slot),
_DEF_LOC_TYPE(IlRel),
Symbol::ValueNameEntry(LocInMetaData, "InMetaData"),
_DEF_LOC_TYPE(Constant)
};
#undef _DEF_LOC_TYPE
#define _DEF_BASIC_TYPE(x) Symbol::ValueNameEntry(bt##x, #x)
const Symbol::ValueNameEntry Symbol::basicTypeName[] = {
_DEF_BASIC_TYPE(NoType),
_DEF_BASIC_TYPE(Void),
_DEF_BASIC_TYPE(Char),
_DEF_BASIC_TYPE(WChar),
_DEF_BASIC_TYPE(Int),
_DEF_BASIC_TYPE(UInt),
_DEF_BASIC_TYPE(Float),
_DEF_BASIC_TYPE(BCD),
_DEF_BASIC_TYPE(Bool),
_DEF_BASIC_TYPE(Long),
_DEF_BASIC_TYPE(ULong),
_DEF_BASIC_TYPE(Currency),
_DEF_BASIC_TYPE(Date),
_DEF_BASIC_TYPE(Variant),
_DEF_BASIC_TYPE(Complex),
_DEF_BASIC_TYPE(Bit),
_DEF_BASIC_TYPE(BSTR),
_DEF_BASIC_TYPE(Hresult)
};
#undef _DEF_BASIC_TYPE
const size_t Symbol::cntBasicTypeName = _countof(Symbol::basicTypeName);
////////////////////////////////////////////////////////////////////////////////
#define callSymbol(method) \
callSymbolT( &IDiaSymbol::##method, __FUNCTION__, #method)
////////////////////////////////////////////////////////////////////////////////
std::string Exception::makeFullDesc(const std::string &desc, HRESULT hres)
{
std::stringstream sstream;
sstream << descPrefix << desc << " failed" << std::endl;
sstream << "Return value is 0x" << std::hex << hres;
PCHAR errMessage = NULL;
FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
hres,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(PCHAR)&errMessage,
0,
NULL);
if (errMessage)
{
sstream << ": " << std::endl;
sstream << errMessage;
LocalFree(errMessage);
}
else
{
sstream << std::endl;
}
return sstream.str();
}
////////////////////////////////////////////////////////////////////////////////
void Exception::exceptionTranslate( const Exception &e )
{
boost::python::object pyExcept(e);
PyErr_SetObject( diaExceptTypeObject, pyExcept.ptr() );
}
////////////////////////////////////////////////////////////////////////////////
std::list< Symbol > Symbol::findChildrenImpl(
ULONG symTag,
const std::string &name,
DWORD nameCmpFlags
)
{
throwIfNull(__FUNCTION__);
DiaEnumSymbolsPtr symbols;
HRESULT hres =
m_symbol->findChildren(
static_cast<enum SymTagEnum>(symTag),
toWStr(name),
nameCmpFlags,
&symbols);
if (S_OK != hres)
throw Exception("Call IDiaSymbol::findChildren", hres);
std::list< Symbol > childList;
DiaSymbolPtr child;
ULONG celt;
while ( SUCCEEDED(symbols->Next(1, &child, &celt)) && (celt == 1) )
childList.push_back( Symbol(child) );
return childList;
}
////////////////////////////////////////////////////////////////////////////////
ULONGLONG Symbol::getSize()
{
return callSymbol(get_length);
}
////////////////////////////////////////////////////////////////////////////////
std::string Symbol::getName()
{
autoBstr retValue( callSymbol(get_name) );
return retValue.asStr();
}
////////////////////////////////////////////////////////////////////////////////
Symbol Symbol::getType()
{
return Symbol( callSymbol(get_type) );
}
////////////////////////////////////////////////////////////////////////////////
Symbol Symbol::getIndexType()
{
return Symbol( callSymbol(get_arrayIndexType) );
}
////////////////////////////////////////////////////////////////////////////////
ULONG Symbol::getSymTag()
{
return callSymbol(get_symTag);
}
////////////////////////////////////////////////////////////////////////////////
ULONG Symbol::getRva()
{
return callSymbol(get_relativeVirtualAddress);
}
////////////////////////////////////////////////////////////////////////////////
ULONG Symbol::getLocType()
{
return callSymbol(get_locationType);
}
////////////////////////////////////////////////////////////////////////////////
void Symbol::getValueImpl(VARIANT &vtValue)
{
throwIfNull(__FUNCTION__);
HRESULT hres = m_symbol->get_value(&vtValue);
if (S_OK != hres)
throw Exception("Call IDiaSymbol::get_value", hres);
}
////////////////////////////////////////////////////////////////////////////////
python::object Symbol::getValue()
{
VARIANT vtValue = { VT_EMPTY };
getValueImpl(vtValue);
switch (vtValue.vt)
{
case VT_I1:
case VT_UI1:
return python::object( static_cast<ULONG>(vtValue.bVal) );
case VT_BOOL:
return python::object( static_cast<bool>(!!vtValue.iVal) );
case VT_I2:
case VT_UI2:
return python::object( static_cast<ULONG>(vtValue.iVal) );
case VT_I4:
case VT_UI4:
case VT_INT:
case VT_UINT:
case VT_ERROR:
case VT_HRESULT:
return python::object( vtValue.lVal );
case VT_I8:
case VT_UI8:
return python::object( float(vtValue.llVal) );
case VT_R4:
return python::object( double(vtValue.fltVal) );
case VT_R8:
return python::object( vtValue.dblVal );
case VT_BSTR:
return python::object( autoBstr::asStr(vtValue.bstrVal).c_str() );
}
throw Exception("Unknown value type");
}
////////////////////////////////////////////////////////////////////////////////
bool Symbol::isBasicType()
{
throwIfNull(__FUNCTION__);
DWORD baseType = btNoType;
return
SUCCEEDED( m_symbol->get_baseType(&baseType) ) &&
(btNoType != baseType);
}
////////////////////////////////////////////////////////////////////////////////
ULONG Symbol::getBaseType()
{
return callSymbol(get_baseType);
}
////////////////////////////////////////////////////////////////////////////////
ULONG Symbol::getBitPosition()
{
return callSymbol(get_bitPosition);
}
////////////////////////////////////////////////////////////////////////////////
Symbol Symbol::getChildByName(const std::string &_name)
{
throwIfNull(__FUNCTION__);
DiaEnumSymbolsPtr symbols;
HRESULT hres =
m_symbol->findChildren(
SymTagNull,
toWStr(_name),
nsCaseSensitive,
&symbols);
if (S_OK != hres)
throw Exception("Call IDiaSymbol::findChildren", hres);
LONG count;
hres = symbols->get_Count(&count);
if (S_OK != hres)
throw Exception("Call IDiaEnumSymbols::get_Count", hres);
if (!count)
throw Exception(_name + " not found");
if (count != 1)
throw Exception(_name + " is not unique");
DiaSymbolPtr child;
hres = symbols->Item(0, &child);
if (S_OK != hres)
throw Exception("Call IDiaEnumSymbols::Item", hres);
return Symbol(child);
}
////////////////////////////////////////////////////////////////////////////////
ULONG Symbol::getChildCount()
{
throwIfNull(__FUNCTION__);
DiaEnumSymbolsPtr symbols;
HRESULT hres =
m_symbol->findChildren(
SymTagNull,
NULL,
nsCaseSensitive,
&symbols);
if (S_OK != hres)
throw Exception("Call IDiaSymbol::findChildren", hres);
LONG count;
hres = symbols->get_Count(&count);
if (S_OK != hres)
throw Exception("Call IDiaEnumSymbols::get_Count", hres);
return count;
}
////////////////////////////////////////////////////////////////////////////////
Symbol Symbol::getChildByIndex(ULONG _index)
{
throwIfNull(__FUNCTION__);
DiaEnumSymbolsPtr symbols;
HRESULT hres =
m_symbol->findChildren(
SymTagNull,
NULL,
nsCaseSensitive,
&symbols);
if (S_OK != hres)
throw Exception("Call IDiaSymbol::findChildren", hres);
LONG count;
hres = symbols->get_Count(&count);
if (S_OK != hres)
throw Exception("Call IDiaEnumSymbols::get_Count", hres);
if (LONG(_index) >= count)
throw Exception("Attempt to access non-existing element by index");
DiaSymbolPtr child;
hres = symbols->Item(_index, &child);
if (S_OK != hres)
throw Exception("Call IDiaEnumSymbols::Item", hres);
return Symbol(child);
}
////////////////////////////////////////////////////////////////////////////////
std::string Symbol::print()
{
std::stringstream sstream;
if (m_symbol)
{
DWORD dwValue;
autoBstr bstrValue;
VARIANT vtValue = { VT_EMPTY };
bool bValue;
sstream << "symTag: ";
HRESULT hres = m_symbol->get_symTag(&dwValue);
if ((S_OK == hres) && dwValue < _countof(symTagName))
sstream << symTagName[dwValue].second;
else
sstream << "<unknown>";
sstream << ", ";
hres = m_symbol->get_name(&bstrValue);
if (S_OK == hres)
sstream << "\"" << bstrValue.asStr().c_str() << "\"";
else
sstream << "<no-name>";
bstrValue.free();
hres = m_symbol->get_locationType(&dwValue);
if ((S_OK == hres) && dwValue < _countof(locTypeName))
{
sstream << std::endl;
sstream << "Location: " << locTypeName[dwValue].second;
if (dwValue == LocIsStatic)
{
hres = m_symbol->get_relativeVirtualAddress(&dwValue);
if (S_OK == hres)
sstream << ", RVA: 0x" << std::hex << dwValue;
}
}
bValue = false;
try
{
getValueImpl(vtValue);
bValue = true;
}
catch (const Exception &except)
{
DBG_UNREFERENCED_PARAMETER(except);
}
if (bValue)
{
switch (vtValue.vt)
{
case VT_I1:
case VT_UI1:
sstream << std::endl << "Value is ";
sstream << std::hex << "0x" << vtValue.bVal;
break;
case VT_BOOL:
sstream << std::endl << "Value is ";
sstream << vtValue.iVal ? "True" : "False";
break;
case VT_I2:
case VT_UI2:
sstream << std::endl << "Value is ";
sstream << std::hex << "0x" << vtValue.iVal;
break;
case VT_I4:
case VT_UI4:
case VT_INT:
case VT_UINT:
case VT_ERROR:
case VT_HRESULT:
sstream << std::endl << "Value is ";
sstream << std::hex << "0x" << vtValue.lVal;
break;
case VT_I8:
case VT_UI8:
sstream << std::endl << "Value is ";
sstream << std::hex << "0x" << vtValue.llVal;
break;
case VT_R4:
sstream << std::endl << "Value is ";
sstream << vtValue.fltVal;
break;
case VT_R8:
sstream << std::endl << "Value is ";
sstream << vtValue.dblVal;
break;
case VT_BSTR:
sstream << std::endl << "Value is ";
sstream << "\"" << autoBstr::asStr(vtValue.bstrVal).c_str() << "\"";
break;
}
}
hres = m_symbol->get_baseType(&dwValue);
if (SUCCEEDED(hres) && btNoType != dwValue)
{
for (ULONG i = 0; i < cntBasicTypeName; ++i)
{
if (basicTypeName[i].first == dwValue)
{
sstream << std::endl;
sstream << "Basic type is " << basicTypeName[i].second;
break;
}
}
}
}
return sstream.str();
}
////////////////////////////////////////////////////////////////////////////////
GlobalScope::GlobalScope(
__inout DiaDataSourcePtr &_scope,
__inout DiaSessionPtr &_session,
__inout DiaSymbolPtr &_globalScope
) : Symbol(_globalScope)
, m_source( _scope.Detach() )
, m_session( _session.Detach() )
{
}
////////////////////////////////////////////////////////////////////////////////
GlobalScope GlobalScope::openPdb(const std::string &filePath)
{
DiaDataSourcePtr _scope;
HRESULT hres =
_scope.CoCreateInstance(__uuidof(DiaSource), NULL, CLSCTX_INPROC_SERVER);
if ( S_OK != hres )
throw Exception("Call ::CoCreateInstance", hres);
hres = _scope->loadDataFromPdb( toWStr(filePath) );
if ( S_OK != hres )
throw Exception("Call IDiaDataSource::loadDataFromPdb", hres);
DiaSessionPtr _session;
hres = _scope->openSession(&_session);
if ( S_OK != hres )
throw Exception("Call IDiaDataSource::openSession", hres);
DiaSymbolPtr _globalScope;
hres = _session->get_globalScope(&_globalScope);
if ( S_OK != hres )
throw Exception("Call IDiaSymbol::get_globalScope", hres);
return GlobalScope(_scope, _session, _globalScope);
}
////////////////////////////////////////////////////////////////////////////////
}