From c67055bad3cdfc93e2ac57d87f36c6e0993af690 Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Wed, 17 May 2017 06:00:20 +0300 Subject: initial commit --- src/dbghelp.cpp | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 src/dbghelp.cpp (limited to 'src/dbghelp.cpp') diff --git a/src/dbghelp.cpp b/src/dbghelp.cpp new file mode 100644 index 0000000..c319fee --- /dev/null +++ b/src/dbghelp.cpp @@ -0,0 +1,166 @@ +// Copyright (c) 2017 Egor Tensin +// This file is part of the "PDB repository" project. +// For details, see https://github.com/egor-tensin/pdb-repo. +// Distributed under the MIT License. + +#include "pdb/all.hpp" + +#include +#include + +#include +#include + +#include +#include +#include + +namespace pdb +{ + namespace + { + void enable_debug_output() + { + SymSetOptions(SymGetOptions() | SYMOPT_DEBUG | SYMOPT_UNDNAME); + } + + void initialize(HANDLE id) + { + enable_debug_output(); + const auto ret = SymInitialize(id, NULL, FALSE); + if (!ret) + throw error::windows(GetLastError()); + } + + void clean_up(HANDLE id) + { + const auto ret = SymCleanup(id); + if (!ret) + throw error::windows(GetLastError()); + } + + Address gen_next_offline_base(std::size_t pdb_size) + { + static Address id = 0x10000000; + const auto next = id; + id += pdb_size; + return next; + } + + BOOL CALLBACK enum_symbols_callback( + SYMBOL_INFO *info, + ULONG, + VOID *raw_callback_ptr) + { + const auto callback_ptr = reinterpret_cast(raw_callback_ptr); + const auto& callback = *callback_ptr; + callback(SymbolInfo{*info}); + return TRUE; + } + } + + DbgHelp::DbgHelp() + { + initialize(id); + } + + ModuleInfo DbgHelp::load_pdb(const std::string& path) const + { + const auto size = file::get_size(path); + + if (size > std::numeric_limits::max()) + throw std::range_error{"PDB file size is too large"}; + + const auto offline_base = SymLoadModule64( + id, + NULL, + path.c_str(), + NULL, + gen_next_offline_base(size), + static_cast(size)); + + if (!offline_base) + throw error::windows(GetLastError()); + + return get_module_info(offline_base); + } + + ModuleInfo DbgHelp::get_module_info(Address offline_base) const + { + ModuleInfo info; + + const auto ret = SymGetModuleInfo64( + id, + offline_base, + &static_cast(info)); + + if (!ret) + throw error::windows(GetLastError()); + + return info; + } + + void DbgHelp::enum_symbols(const ModuleInfo& module, const OnSymbol& callback) const + { + const auto ret = SymEnumSymbols( + id, + module.get_offline_base(), + NULL, + &enum_symbols_callback, + const_cast(&callback)); + + if (!ret) + throw error::windows(GetLastError()); + } + + SymbolInfo DbgHelp::resolve_symbol(Address online) const + { + DWORD64 displacement = 0; + SymbolInfo symbol; + + const auto ret = SymFromAddr( + id, + online, + &displacement, + &static_cast(symbol)); + + if (!ret) + throw error::windows(GetLastError()); + + return symbol; + } + + SymbolInfo DbgHelp::resolve_symbol(const std::string& name) const + { + SymbolInfo symbol; + + const auto ret = SymFromName( + id, + name.c_str(), + &static_cast(symbol)); + + if (!ret) + throw error::windows(GetLastError()); + + return symbol; + } + + void DbgHelp::close() + { + if (!closed) + { + clean_up(id); + closed = true; + } + } + + DbgHelp::~DbgHelp() + { + try + { + close(); + } + catch (...) + { } + } +} -- cgit v1.2.3