aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/dbghelp.cpp
diff options
context:
space:
mode:
authorEgor Tensin <Egor.Tensin@gmail.com>2017-05-17 06:00:20 +0300
committerEgor Tensin <Egor.Tensin@gmail.com>2017-05-17 06:00:20 +0300
commitc67055bad3cdfc93e2ac57d87f36c6e0993af690 (patch)
treeda8759c66f1af00415784e5824e6bfc2195aee92 /src/dbghelp.cpp
downloadwinapi-debug-c67055bad3cdfc93e2ac57d87f36c6e0993af690.tar.gz
winapi-debug-c67055bad3cdfc93e2ac57d87f36c6e0993af690.zip
initial commit
Diffstat (limited to 'src/dbghelp.cpp')
-rw-r--r--src/dbghelp.cpp166
1 files changed, 166 insertions, 0 deletions
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 <Egor.Tensin@gmail.com>
+// 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 <Windows.h>
+#include <DbgHelp.h>
+
+#include <cstddef>
+#include <cstring>
+
+#include <limits>
+#include <stdexcept>
+#include <string>
+
+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<DbgHelp::OnSymbol*>(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<DWORD>::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<DWORD>(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<ModuleInfo::Raw&>(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<OnSymbol*>(&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_INFO&>(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_INFO&>(symbol));
+
+ if (!ret)
+ throw error::windows(GetLastError());
+
+ return symbol;
+ }
+
+ void DbgHelp::close()
+ {
+ if (!closed)
+ {
+ clean_up(id);
+ closed = true;
+ }
+ }
+
+ DbgHelp::~DbgHelp()
+ {
+ try
+ {
+ close();
+ }
+ catch (...)
+ { }
+ }
+}