5#include <Logger/Logger.h>
8#include "../Private/Helpers.h"
9#include "../Private/Offsets.h"
44 void PdbReader::
Read(
const std::wstring& path, std::unordered_map<std::string, intptr_t>* offsets_dump,
45 std::unordered_map<std::string, BitField>* bitfields_dump,
const std::unordered_set<std::string> filter_set)
47 offsets_dump_ = offsets_dump;
48 bitfields_dump_ = bitfields_dump;
49 filter_set_ = filter_set;
51 offsets_dump_->reserve(550000);
52 bitfields_dump_->reserve(11000);
54 std::ifstream f{path};
56 throw std::runtime_error(
"Failed to open pdb file");
58 IDiaDataSource* data_source;
59 IDiaSession* dia_session;
64 LoadDataFromPdb(path, &data_source, &dia_session, &symbol);
66 catch (
const std::runtime_error&)
68 Log::GetLog()->error(
"Failed to load data from pdb file ");
72 Log::GetLog()->info(
"Dumping structures..");
75 Log::GetLog()->info(
"Dumping functions..");
76 DumpFunctions(symbol);
78 Log::GetLog()->info(
"Dumping globals..");
79 DumpGlobalVariables(symbol);
81 Cleanup(symbol, dia_session, data_source);
83 Log::GetLog()->info(
"Successfully read information from PDB\n");
86 void PdbReader::LoadDataFromPdb(
const std::wstring& path, IDiaDataSource** dia_source, IDiaSession** session,
89 const std::string current_dir = Tools::GetCurrentDir();
91 const std::string lib_path = current_dir +
"\\msdia140.dll";
92 const HMODULE h_module = LoadLibraryA(lib_path.c_str());
93 if (h_module ==
nullptr)
95 throw std::runtime_error(
"Failed to load msdia140.dll. Error code - " + std::to_string(GetLastError()));
98 const auto dll_get_class_object =
reinterpret_cast<HRESULT(
WINAPI*)(REFCLSID, REFIID, LPVOID)>(GetProcAddress(
99 h_module,
"DllGetClassObject"));
100 if (dll_get_class_object ==
nullptr)
102 throw std::runtime_error(
"Can't find DllGetClassObject. Error code - " + std::to_string(GetLastError()));
105 IClassFactory* class_factory;
106 HRESULT hr = dll_get_class_object(
__uuidof(DiaSource), IID_IClassFactory, &class_factory);
109 throw std::runtime_error(
"DllGetClassObject has failed. Error code - " + std::to_string(GetLastError()));
112 hr = class_factory->CreateInstance(
nullptr,
__uuidof(IDiaDataSource),
reinterpret_cast<
void**>(dia_source));
115 class_factory->Release();
116 throw std::runtime_error(
"CreateInstance has failed. Error code - " + std::to_string(GetLastError()));
119 hr = (*dia_source)->loadDataFromPdb(path.c_str());
122 class_factory->Release();
123 throw std::runtime_error(
"loadDataFromPdb has failed. HRESULT - " + std::to_string(hr));
128 hr = (*dia_source)->openSession(session);
131 class_factory->Release();
132 throw std::runtime_error(
"openSession has failed. HRESULT - " + std::to_string(hr));
137 hr = (*session)->get_globalScope(symbol);
140 class_factory->Release();
141 throw std::runtime_error(
"get_globalScope has failed. HRESULT - " + std::to_string(hr));
144 class_factory->Release();
149 IDiaSymbol* symbol =
nullptr;
151 CComPtr<IDiaEnumSymbols> enum_symbols;
152 if (FAILED(g_symbol->findChildren(SymTagUDT,
nullptr, nsNone, &enum_symbols)))
153 throw std::runtime_error(
"Failed to find symbols");
156 while (SUCCEEDED(enum_symbols->Next(1, &symbol, &celt)) && celt == 1)
158 CComPtr<IDiaSymbol> sym(symbol);
160 const uint32_t sym_id = GetSymbolId(symbol);
161 if (visited_.find(sym_id) != visited_.end())
164 visited_.insert(sym_id);
166 std::string str_name = GetSymbolNameString(sym);
168 if (FilterSymbols(str_name))
171 DumpType(sym, str_name, 0);
179 CComPtr<IDiaEnumSymbols> enum_symbols;
180 if (FAILED(g_symbol->findChildren(SymTagFunction,
nullptr, nsNone, &enum_symbols)))
181 throw std::runtime_error(
"Failed to find symbols");
184 std::stringstream ss;
185 while (SUCCEEDED(enum_symbols->Next(1, &symbol, &celt)) && celt == 1)
187 CComPtr<IDiaSymbol> sym(symbol);
190 if (sym->get_symTag(&sym_tag_type) != S_OK)
193 std::string str_name = GetSymbolNameString(sym);
195 if (FilterSymbols(str_name))
198 const uint32_t sym_id = GetSymbolId(sym);
200 if (visited_.find(sym_id) != visited_.end())
203 visited_.insert(sym_id);
205 if (str_name.empty())
209 if (sym->get_addressOffset(&offset) != S_OK)
213 ss.str(std::string());
216 if (str_name.find(
':') != std::string::npos)
218 ss << ReplaceString(str_name,
"::",
".") <<
"(" << GetFunctionSymbolParams(sym) <<
")";
219 (*offsets_dump_)[ss.str()] = offset;
225 ss <<
"Global." << str_name <<
"(" << GetFunctionSymbolParams(sym) <<
")";
226 (*offsets_dump_)[ss.str()] = offset;
236 CComPtr<IDiaEnumSymbols> enum_symbols;
237 if (FAILED(g_symbol->findChildren(SymTagData,
nullptr, nsNone, &enum_symbols)))
238 throw std::runtime_error(
"Failed to find symbols");
241 while (SUCCEEDED(enum_symbols->Next(1, &symbol, &celt)) && celt == 1)
243 CComPtr<IDiaSymbol> sym(symbol);
245 const uint32_t sym_id = GetSymbolId(symbol);
246 if (visited_.find(sym_id) != visited_.end())
249 visited_.insert(sym_id);
251 std::string str_name = GetSymbolNameString(sym);
252 if (FilterSymbols(str_name))
256 if (sym->get_symTag(&sym_tag) != S_OK)
260 if (sym->get_addressOffset(&offset) != S_OK)
263 (*offsets_dump_)[
"Global." + str_name] = offset;
269 CComPtr<IDiaEnumSymbols> enum_children;
270 IDiaSymbol* symbol_child;
277 if (symbol->get_symTag(&sym_tag) != S_OK)
283 DumpData(symbol, structure);
287 if (SUCCEEDED(symbol->findChildren(SymTagNull,
nullptr, nsNone, &enum_children)))
289 while (SUCCEEDED(enum_children->Next(1, &symbol_child, &celt)) && celt == 1)
291 CComPtr<IDiaSymbol> sym_child(symbol_child);
293 DumpType(sym_child, structure, indent + 2);
305 if (symbol->get_locationType(&loc_type) != S_OK)
308 if (loc_type != LocIsThisRel && loc_type != LocIsBitField)
311 CComPtr<IDiaSymbol> type;
312 if (symbol->get_type(&type) != S_OK)
319 if (symbol->get_offset(&offset) != S_OK)
322 std::string str_name = GetSymbolNameString(symbol);
323 if (str_name.empty())
326 if (loc_type == LocIsBitField)
329 if (symbol->get_bitPosition(&bit_position) != S_OK)
333 if (symbol->get_length(&num_bits) != S_OK)
337 if (type->get_length(&length) != S_OK)
340 const BitField bit_field{
static_cast<DWORD64>(offset), bit_position, num_bits, length};
342 (*bitfields_dump_)[structure +
"." + str_name] = bit_field;
344 else if (loc_type == LocIsThisRel)
346 (*offsets_dump_)[structure +
"." + str_name] = offset;
355 for (
const auto& filter : filter_set_)
357 if (input.starts_with(filter))
361 if (input.find(
'`') != std::string::npos)
373 HRESULT hr = symbol->get_name(&str);
379 name = Tools::Utf8Encode(str);
390 symbol->get_symIndexId(&id);
395 void PdbReader::Cleanup(IDiaSymbol* symbol, IDiaSession* session, IDiaDataSource* source)
397 if (symbol !=
nullptr)
399 if (session !=
nullptr)
401 if (source !=
nullptr)
409 std::string parameterTypes;
410 BSTR undecorated =
nullptr;
411 if (SUCCEEDED(pFunction->get_undecoratedNameEx(0x20000, &undecorated))
412 && undecorated !=
nullptr)
414 parameterTypes = Tools::Utf8Encode(undecorated);
415 const size_t start = parameterTypes.find(
'(');
416 const size_t end = parameterTypes.find(
')');
417 if (start != std::string::npos && end != std::string::npos)
419 parameterTypes = parameterTypes.substr(start + 1, end - start - 1);
420 parameterTypes = ReplaceString(parameterTypes,
"struct ",
"");
421 parameterTypes = ReplaceString(parameterTypes,
"class ",
"");
422 parameterTypes = ReplaceString(parameterTypes,
"enum ",
"");
424 parameterTypes = ReplaceString(parameterTypes,
"const ",
"");
425 parameterTypes = ReplaceString(parameterTypes,
" ",
"");
426 parameterTypes = ReplaceString(parameterTypes,
"__ptr64",
"");
427 if (parameterTypes ==
"void")
428 parameterTypes.clear();
432 return parameterTypes;
void DumpType(IDiaSymbol *, const std::string &, int) const
void Read(const std::wstring &path, std::unordered_map< std::string, intptr_t > *offsets_dump, std::unordered_map< std::string, BitField > *bitfields_dump, const std::unordered_set< std::string > filter_set)
bool FilterSymbols(const std::string input)
void DumpFunctions(IDiaSymbol *)
void DumpData(IDiaSymbol *, const std::string &) const
void DumpGlobalVariables(IDiaSymbol *)
void DumpStructs(IDiaSymbol *)