7
#pragma comment(lib, "dbghelp.lib")
9
#include <boost/regex.hpp>
11
#include "kdlib/symengine.h"
12
#include "dia/diawrapper.h"
21
const DiaRegToRegRelativeBase g_DiaRegToRegRelativeAmd64 {
22
{ CV_AMD64_RIP, rriInstructionPointer },
23
{ CV_AMD64_RBP, rriStackFrame },
24
{ CV_ALLREG_VFRAME, rriStackFrame },
25
{ CV_AMD64_RSP, rriStackPointer },
28
const DiaRegToRegRelativeBase g_DiaRegToRegRelativeI386 {
29
{ CV_REG_EIP, rriInstructionPointer },
30
{ CV_REG_EBP, rriStackFrame },
31
{ CV_ALLREG_VFRAME, rriStackFrame },
32
{ CV_REG_ESP, rriStackPointer },
35
const DiaRegToRegRelativeBase g_DiaRegToRegRelativeArm64 {
36
{ CV_ARM64_PC, rriInstructionPointer },
37
{ CV_ARM64_FP, rriStackFrame },
38
{ CV_ARM64_SP, rriStackPointer },
41
const DiaRegToRegRelativeBase g_DiaRegToRegRelativeArm {
42
{ CV_ARM_PC, rriInstructionPointer },
43
{ CV_ARM_R11, rriStackFrame },
44
{ CV_ARM_SP, rriStackPointer },
51
const std::wstring DiaException::descPrefix(L"pyDia: ");
53
std::wstring DiaException::makeFullDesc(const std::wstring &desc, HRESULT hres, IDiaSymbol *symbol )
55
std::wstringstream sstream;
56
sstream << descPrefix << desc << L" failed" << std::endl;
60
HRESULT locRes = symbol->get_undecoratedName(&bstrName);
61
if (S_OK == locRes && bstrName)
63
sstream << L"Symbol name: \"" << _bstr_t(bstrName, false) << L"\"";
67
locRes = symbol->get_name(&bstrName);
68
if (S_OK == locRes && bstrName)
70
sstream << L"Symbol name: " << _bstr_t(bstrName, false);
74
sstream << L"Symbol: ";
79
locRes = symbol->get_relativeVirtualAddress(&dwValue);
82
sstream << L", RVA= 0x" << std::hex << dwValue;
85
locRes = symbol->get_symTag(&dwValue);
88
sstream << L", tag= " << std::dec << dwValue;
91
locRes = symbol->get_locationType(&dwValue);
94
sstream << L", location: " << std::dec << dwValue;
99
sstream << L"Return value is 0x" << std::hex << hres;
103
#define _CASE_DIA_ERROR(x) case E_PDB_##x: sstream << L": E_PDB_" L#x << std::endl; break
105
_CASE_DIA_ERROR(USAGE);
106
_CASE_DIA_ERROR(OUT_OF_MEMORY);
107
_CASE_DIA_ERROR(FILE_SYSTEM);
108
_CASE_DIA_ERROR(NOT_FOUND);
109
_CASE_DIA_ERROR(INVALID_SIG);
110
_CASE_DIA_ERROR(INVALID_AGE);
111
_CASE_DIA_ERROR(PRECOMP_REQUIRED);
112
_CASE_DIA_ERROR(OUT_OF_TI);
113
_CASE_DIA_ERROR(NOT_IMPLEMENTED);
114
_CASE_DIA_ERROR(V1_PDB);
115
_CASE_DIA_ERROR(FORMAT);
116
_CASE_DIA_ERROR(LIMIT);
117
_CASE_DIA_ERROR(CORRUPT);
118
_CASE_DIA_ERROR(TI16);
119
_CASE_DIA_ERROR(ACCESS_DENIED);
120
_CASE_DIA_ERROR(ILLEGAL_TYPE_EDIT);
121
_CASE_DIA_ERROR(INVALID_EXECUTABLE);
122
_CASE_DIA_ERROR(DBG_NOT_FOUND);
123
_CASE_DIA_ERROR(NO_DEBUG_INFO);
124
_CASE_DIA_ERROR(INVALID_EXE_TIMESTAMP);
125
_CASE_DIA_ERROR(RESERVED);
126
_CASE_DIA_ERROR(DEBUG_INFO_NOT_IN_PDB);
127
_CASE_DIA_ERROR(SYMSRV_BAD_CACHE_PATH);
128
_CASE_DIA_ERROR(SYMSRV_CACHE_FULL);
130
#undef _CASE_DIA_ERROR
133
PWCHAR errMessage = NULL;
135
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
138
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
144
sstream << L": " << std::endl;
145
sstream << errMessage;
146
LocalFree(errMessage);
150
sstream << std::endl;
155
return sstream.str();
160
#define callSymbol(method) \
161
callSymbolT( &IDiaSymbol::##method, L#method)
165
std::wstring getBasicTypeName( ULONG basicType )
167
for ( size_t i = 0; i < DiaSymbol::cntBasicTypeName; ++i )
169
if ( basicType == DiaSymbol::basicTypeName[i].first )
170
return std::wstring( DiaSymbol::basicTypeName[i].second );
173
std::wstringstream sstr;
175
sstr << L"faild to find basic type with index %d" << basicType;
177
throw DiaException( sstr.str() );
182
DiaSymbol::DiaSymbol(const DiaSymbolPtr &_symbol, const std::wstring &_scope, MachineTypes machineType)
183
: m_symbol(_symbol), m_scope(_scope), m_machineType(machineType)
189
SymbolPtr DiaSymbol::fromGlobalScope( IDiaSymbol *_symbol, const std::wstring& _scope )
191
MachineTypes machineType;
192
HRESULT hres = _symbol->get_machineType( (DWORD*)&machineType);
194
throw DiaException( L"IDiaSymbol::get_machineType", hres);
196
machineType = machine_I386;
198
return SymbolPtr(new DiaSymbol(DiaSymbolPtr(_symbol), _scope, machineType));
203
SymbolPtrList DiaSymbol::findChildren(
205
const std::wstring &name,
209
DiaEnumSymbolsPtr symbols;
212
const std::wstring decoratedMask = name.empty() ?
213
std::wstring() : std::wstring(L"*") + name.c_str() + L"*";
216
m_symbol->findChildren(
217
static_cast<enum ::SymTagEnum>(symTag),
218
decoratedMask.empty() ? NULL : decoratedMask.c_str(),
219
(caseSensitive ? nsCaseSensitive : nsCaseInsensitive) | nsfUndecoratedName | nsfRegularExpression,
223
throw DiaException(L"Call IDiaSymbol::findChildren", hres);
225
SymbolPtrList childList;
229
while ( SUCCEEDED(symbols->Next(1, &child, &celt)) && (celt == 1) )
231
SymbolPtr symbol( new DiaSymbol(child, m_scope, m_machineType) );
235
::SymMatchStringW(symbol->getName().c_str(), name.c_str(), caseSensitive) )
237
childList.push_back( symbol );
246
SymbolPtrList DiaSymbol::findChildrenByRVA(unsigned long symTag, unsigned long rva)
248
DiaEnumSymbolsPtr symbols;
251
hres = m_symbol->findChildrenExByRVA(
252
static_cast<enum ::SymTagEnum>(symTag),
254
nsCaseSensitive | nsfUndecoratedName,
259
throw DiaException(L"Call IDiaSymbol::findChildrenExByRVA", hres);
261
SymbolPtrList childList;
264
while (SUCCEEDED(symbols->Next(1, &child, &celt)) && (celt == 1))
266
SymbolPtr symbol(new DiaSymbol(child, m_scope, m_machineType));
269
childList.push_back(symbol);
277
ULONG DiaSymbol::getBaseType()
279
return callSymbol(get_baseType);
284
ULONG DiaSymbol::getBitPosition()
286
return callSymbol(get_bitPosition);
291
size_t DiaSymbol::getChildCount(ULONG symTag)
293
DiaEnumSymbolsPtr symbols;
295
m_symbol->findChildren(
296
static_cast<enum ::SymTagEnum>(symTag),
298
nsfCaseSensitive | nsfUndecoratedName,
301
throw DiaException(L"Call IDiaSymbol::findChildren", hres);
304
hres = symbols->get_Count(&count);
306
throw DiaException(L"Call IDiaEnumSymbols::get_Count", hres);
313
SymbolPtr DiaSymbol::getChildByIndex(ULONG symTag, ULONG _index )
315
DiaEnumSymbolsPtr symbols;
317
m_symbol->findChildren(
318
static_cast<enum ::SymTagEnum>(symTag),
320
nsfCaseSensitive | nsfUndecoratedName,
323
throw DiaException(L"Call IDiaSymbol::findChildren", hres);
336
hres = symbols->Item(_index, &child);
338
throw DiaException(L"Call IDiaEnumSymbols::Item", hres);
340
return SymbolPtr( new DiaSymbol(child, m_scope, m_machineType) );
346
SymbolPtr DiaSymbol::getChildByName(const std::wstring &name )
349
DiaEnumSymbolsPtr symbols;
351
m_symbol->findChildren(
353
_bstr_t(name.c_str()),
357
throw DiaException(L"Call IDiaSymbol::findChildren", hres);
360
hres = symbols->get_Count(&count);
362
throw DiaException(L"Call IDiaEnumSymbols::get_Count", hres);
367
hres = symbols->Item(0, &child);
369
throw DiaException(L"Call IDiaEnumSymbols::Item", hres);
371
return SymbolPtr( new DiaSymbol(child, m_scope, m_machineType) );
376
m_symbol->findChildren(
378
_bstr_t((std::wstring(L"*") + name + L"*").c_str()),
379
nsfCaseSensitive | nsfRegularExpression | nsfUndecoratedName,
382
throw DiaException(L"Call IDiaSymbol::findChildren", hres);
384
hres = symbols->get_Count(&count);
386
throw DiaException(L"Call IDiaEnumSymbols::get_Count", hres);
392
while ( SUCCEEDED(symbols->Next(1, &child, &celt)) && (celt == 1) )
394
SymbolPtr symbol ( new DiaSymbol(child, m_scope, m_machineType) );
395
if (symbol->getName() == name)
402
throw DiaException(std::wstring(L"symbol \"") + name + L"\" is not found");
407
size_t DiaSymbol::getCount()
409
return callSymbol(get_count);
414
ULONG DiaSymbol::getDataKind()
416
return callSymbol(get_dataKind);
421
ULONG DiaSymbol::getRegisterId()
423
return callSymbol(get_registerId);
428
unsigned long DiaSymbol::getRegRelativeId()
430
switch (m_machineType)
432
case IMAGE_FILE_MACHINE_AMD64:
433
return getRegRelativeIdImpl(g_DiaRegToRegRelativeAmd64);
434
case IMAGE_FILE_MACHINE_I386:
435
return getRegRelativeIdImpl(g_DiaRegToRegRelativeI386);
436
case IMAGE_FILE_MACHINE_ARM64:
437
return getRegRelativeIdImpl(g_DiaRegToRegRelativeArm64);
438
case IMAGE_FILE_MACHINE_ARMNT:
439
return getRegRelativeIdImpl(g_DiaRegToRegRelativeArm);
441
throw DiaException(L"Unsupported machine type");
446
SymbolPtr DiaSymbol::getObjectPointerType()
448
DiaSymbolPtr diaSymbol(callSymbol(get_objectPointerType));
449
return SymbolPtr( new DiaSymbol( diaSymbol, m_scope, m_machineType ) );
454
ULONG DiaSymbol::getCallingConvention()
456
return callSymbol(get_callingConvention);
461
SymbolPtr DiaSymbol::getClassParent()
463
DiaSymbolPtr diaSymbol(callSymbol(get_classParent));
464
return SymbolPtr( new DiaSymbol( diaSymbol, m_scope, m_machineType ) );
470
ULONG DiaSymbol::getRegRelativeIdImpl(const DiaRegToRegRelativeBase &DiaRegToRegRelative)
472
const DWORD registerId = callSymbol(get_registerId);
473
DiaRegToRegRelativeBase::const_iterator it = DiaRegToRegRelative.find(registerId);
474
if (it == DiaRegToRegRelative.end())
475
throw DiaException(L"Cannot convert DIA register ID to relative register ID");
481
bool DiaSymbol::isUndecorated(const std::wstring &undecName)
483
if (m_machineType != machine_I386)
486
BSTR bstrName = NULL;
487
HRESULT hres = m_symbol->get_name(&bstrName);
491
return !( undecName == std::wstring( _bstr_t(bstrName, false) ) );
496
SymbolPtr DiaSymbol::getIndexType()
498
DiaSymbolPtr diaSymbol(callSymbol(get_arrayIndexType));
499
return SymbolPtr( new DiaSymbol(diaSymbol, m_scope, m_machineType) );
504
ULONG DiaSymbol::getLocType()
506
return callSymbol(get_locationType);
511
static const boost::wregex stdcallMatch(L"^_(\\w+)(@\\d+)?$");
512
static const boost::wregex fastcallMatch(L"^@(\\w+)(@\\d+)?$");
514
std::wstring DiaSymbol::getName()
517
BSTR bstrName = NULL;
520
hres = m_symbol->get_symTag( &symTag );
522
if ( FAILED( hres ) )
523
throw DiaException(L"Call IDiaSymbol::get_symTag", hres);
525
if (symTag == SymTagData || symTag == SymTagFunction)
527
hres = m_symbol->get_name(&bstrName);
529
return std::wstring( _bstr_t(bstrName, false) );
532
if( symTag == SymTagData || symTag == SymTagFunction || symTag == SymTagPublicSymbol )
534
hres = m_symbol->get_undecoratedNameEx( UNDNAME_NAME_ONLY, &bstrName);
535
if ( FAILED( hres ) )
536
throw DiaException(L"Call IDiaSymbol::get_undecoratedNameEx", hres);
540
std::wstring retStr = _bstr_t(bstrName, false);
542
if ( (symTag == SymTagPublicSymbol) && !isUndecorated(retStr) )
544
boost::wsmatch matchResult;
546
if ( boost::regex_match( retStr, matchResult, stdcallMatch ) )
547
return std::wstring( matchResult[1].first, matchResult[1].second );
549
if ( boost::regex_match( retStr, matchResult, fastcallMatch ) )
550
return std::wstring( matchResult[1].first, matchResult[1].second );
557
bstrName = callSymbol(get_name);
559
return std::wstring( _bstr_t(bstrName, false) );
562
std::wstring DiaSymbol::getScopeName()
569
LONG DiaSymbol::getOffset()
571
return callSymbol(get_offset);
576
ULONG DiaSymbol::getRva()
578
return callSymbol(get_relativeVirtualAddress);
583
size_t DiaSymbol::getSize()
585
return static_cast<size_t>( callSymbol(get_length) );
590
SymTags DiaSymbol::getSymTag()
592
return static_cast<SymTags>( callSymbol(get_symTag) );
597
SymbolPtr DiaSymbol::getType()
599
DiaSymbolPtr diaSymbol(callSymbol(get_type));
600
return SymbolPtr( new DiaSymbol( diaSymbol, m_scope, m_machineType ) );
605
ULONG DiaSymbol::getUdtKind()
607
return callSymbol(get_udtKind);
612
ULONGLONG DiaSymbol::getVa()
614
return callSymbol(get_virtualAddress);
619
void DiaSymbol::getValue( NumVariant &btv )
622
HRESULT hres = m_symbol->get_value(&vtValue);
624
throw DiaException( L"Call IDiaSymbol::get_value", hres);
629
btv = NumVariant(vtValue.cVal);
633
btv = NumVariant(vtValue.bVal);
637
btv = NumVariant(vtValue.boolVal);
641
btv = NumVariant(vtValue.iVal);
645
btv = NumVariant(vtValue.uiVal);
650
btv = NumVariant(vtValue.lVal);
657
btv = NumVariant(vtValue.ulVal);
661
btv = NumVariant(vtValue.llVal);
665
btv = NumVariant(vtValue.llVal);
669
btv = NumVariant(vtValue.fltVal);
673
btv = NumVariant(vtValue.dblVal);
677
throw DbgException( "Unsupported const value" );
683
int DiaSymbol::getVirtualBasePointerOffset()
685
return callSymbol(get_virtualBasePointerOffset);
690
ULONG DiaSymbol::getVirtualBaseDispIndex()
692
return callSymbol(get_virtualBaseDispIndex);
697
ULONG DiaSymbol::getVirtualBaseDispSize()
699
DiaSymbolPtr diaSymbol(callSymbol(get_virtualBaseTableType));
700
SymbolPtr baseTableType = SymbolPtr( new DiaSymbol( diaSymbol, m_scope, m_machineType ) );
702
return (ULONG)baseTableType->getType()->getSize();
707
bool DiaSymbol::isBasicType()
709
DWORD baseType = btNoType;
711
SUCCEEDED( m_symbol->get_baseType(&baseType) ) &&
712
(btNoType != baseType);
717
bool DiaSymbol::isConstant()
720
BOOL retBool = FALSE;
722
hres = m_symbol->get_constType( &retBool );
723
if ( FAILED( hres ) )
724
throw DiaException(L"Call IDiaSymbol::get_constType", hres, m_symbol);
731
bool DiaSymbol::isIndirectVirtualBaseClass()
733
return !!callSymbol(get_indirectVirtualBaseClass);
738
bool DiaSymbol::isVirtualBaseClass()
740
return !!callSymbol(get_virtualBaseClass);
745
bool DiaSymbol::isVirtual()
747
return !!callSymbol(get_virtual);
752
SymbolPtr DiaSymbol::getVirtualTableShape()
754
DiaSymbolPtr diaSymbol(callSymbol(get_virtualTableShape));
755
return SymbolPtr( new DiaSymbol( diaSymbol, m_scope, m_machineType ) );
760
unsigned long DiaSymbol::getVirtualBaseOffset()
762
return callSymbol(get_virtualBaseOffset);
767
SymbolPtrList DiaSymbol::findInlineFramesByVA(MEMOFFSET_64 va)
769
CComPtr<IDiaEnumSymbols> symEnum;
770
HRESULT hres = m_symbol->findInlineFramesByVA(va, &symEnum);
772
return SymbolPtrList();
775
hres = symEnum->get_Count(&count);
777
throw DiaException(L"Call IDiaSymbol::findInlineFramesByVA", hres);
779
SymbolPtrList symList;
781
for (auto i = 0; i < count; ++i)
783
CComPtr<IDiaSymbol> sym;
784
hres = symEnum->Item(i, &sym);
786
throw DiaException(L"Call IDiaEnumSymbols::Item", hres);
788
SymbolPtr symbol(new DiaSymbol(sym, m_scope, m_machineType));
790
symList.push_back(symbol);
798
void DiaSymbol::getInlineSourceLine(MEMOFFSET_64 offset, std::wstring &fileName, unsigned long &lineNo)
800
CComPtr<IDiaEnumLineNumbers> enumLineNumbers;
802
HRESULT hres = m_symbol->findInlineeLinesByVA(offset, 1, &enumLineNumbers);
804
throw DiaException(L"Call IDiaSymbol::findInlineeLinesByVA", hres);
806
DiaLineNumberPtr sourceLine;
807
hres = enumLineNumbers->Item(0, &sourceLine);
809
throw DiaException(L"failed to find source line");
811
DiaSourceFilePtr sourceFile;
812
hres = sourceLine->get_sourceFile(&sourceFile);
814
throw DiaException(L"failed to find source line");
816
autoBstr fileNameBstr;
817
hres = sourceFile->get_fileName(&fileNameBstr);
819
throw DiaException(L"failed to find source line");
820
fileName = _bstr_t(fileNameBstr, false);
822
hres = sourceLine->get_lineNumber(&lineNo);
824
throw DiaException(L"failed to find source line");
829
SymbolPtr DiaSymbol::getLexicalParent()
831
DiaSymbolPtr diaSymbol(callSymbol(get_lexicalParent));
832
return SymbolPtr(new DiaSymbol(diaSymbol, m_scope, m_machineType));
837
std::wstring DiaSession::getScopeName( IDiaSession* session, IDiaSymbol *globalScope )
839
std::wstring scopeName;
844
HRESULT hres = session->get_loadAddress(&loadBase);
848
scopeName = getModuleName(loadBase);
850
catch (DbgException e)
853
BSTR bstrName = NULL;
854
hres = globalScope->get_name(&bstrName);
856
scopeName = std::wstring(_bstr_t(bstrName, false));
863
SymbolPtr DiaSession::findByRva( ULONG rva, ULONG symTag, LONG* pdisplacement )
869
m_session->findSymbolByRVAEx(
871
static_cast<enum ::SymTagEnum>(symTag),
876
throw DiaException(L"Call IDiaSession::findSymbolByRVAEx", hres);
878
throw DiaException(L"Call IDiaSession::findSymbolByRVAEx", E_UNEXPECTED);
879
if ( !pdisplacement && displacement)
880
throw DiaException(L"Call IDiaSession::findSymbolByRVAEx failed to find symbol" );
883
*pdisplacement = displacement;
885
return SymbolPtr( new DiaSymbol(child, m_globalSymbol->getScopeName(), m_globalSymbol->getMachineType() ) );
890
void DiaSession::getSourceLine( ULONG64 offset, std::wstring &fileName, ULONG &lineNo, LONG &displacement )
892
DiaEnumLineNumbersPtr lines;
894
HRESULT hres = m_session->findLinesByVA( offset, 1, &lines );
896
throw DiaException(L"failed to find source line");
898
DiaLineNumberPtr sourceLine;
899
hres = lines->Item( 0, &sourceLine );
901
throw DiaException(L"failed to find source line");
903
DiaSourceFilePtr sourceFile;
904
hres = sourceLine->get_sourceFile( &sourceFile );
906
throw DiaException(L"failed to find source line");
908
autoBstr fileNameBstr;
909
hres = sourceFile->get_fileName ( &fileNameBstr );
911
throw DiaException(L"failed to find source line");
912
fileName = _bstr_t(fileNameBstr, false);
914
hres = sourceLine->get_lineNumber( &lineNo);
916
throw DiaException(L"failed to find source line");
919
hres = sourceLine->get_virtualAddress ( &va );
921
throw DiaException(L"failed to find source line");
923
displacement = (LONG)( (LONGLONG)offset - (LONGLONG)va );