aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/include/winapi
diff options
context:
space:
mode:
Diffstat (limited to 'include/winapi')
-rw-r--r--include/winapi/debug.hpp13
-rw-r--r--include/winapi/debug/address.hpp34
-rw-r--r--include/winapi/debug/call_stack.hpp53
-rw-r--r--include/winapi/debug/dbghelp.hpp72
-rw-r--r--include/winapi/debug/module.hpp54
-rw-r--r--include/winapi/debug/repo.hpp58
-rw-r--r--include/winapi/debug/symbol.hpp97
7 files changed, 381 insertions, 0 deletions
diff --git a/include/winapi/debug.hpp b/include/winapi/debug.hpp
new file mode 100644
index 0000000..dc42557
--- /dev/null
+++ b/include/winapi/debug.hpp
@@ -0,0 +1,13 @@
+// Copyright (c) 2017 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "winapi-debug" project.
+// For details, see https://github.com/egor-tensin/winapi-debug.
+// Distributed under the MIT License.
+
+#pragma once
+
+#include "debug/address.hpp"
+#include "debug/call_stack.hpp"
+#include "debug/dbghelp.hpp"
+#include "debug/module.hpp"
+#include "debug/repo.hpp"
+#include "debug/symbol.hpp"
diff --git a/include/winapi/debug/address.hpp b/include/winapi/debug/address.hpp
new file mode 100644
index 0000000..3d7acd6
--- /dev/null
+++ b/include/winapi/debug/address.hpp
@@ -0,0 +1,34 @@
+// Copyright (c) 2017 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "winapi-debug" project.
+// For details, see https://github.com/egor-tensin/winapi-debug.
+// Distributed under the MIT License.
+
+#pragma once
+
+#include <windows.h>
+
+#include <sstream>
+#include <string>
+
+namespace pdb {
+
+typedef DWORD64 Address;
+
+inline std::string format_address(Address address) {
+ std::ostringstream oss;
+ oss << std::hex << std::showbase << address;
+ return oss.str();
+}
+
+inline std::string format_address(void* address) {
+ return format_address(reinterpret_cast<Address>(address));
+}
+
+inline bool parse_address(Address& dest, const std::string& src) {
+ std::istringstream iss{src};
+ iss >> std::hex;
+ char c;
+ return iss >> dest && !iss.get(c);
+}
+
+} // namespace pdb
diff --git a/include/winapi/debug/call_stack.hpp b/include/winapi/debug/call_stack.hpp
new file mode 100644
index 0000000..30f642c
--- /dev/null
+++ b/include/winapi/debug/call_stack.hpp
@@ -0,0 +1,53 @@
+// Copyright (c) 2020 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "winapi-debug" project.
+// For details, see https://github.com/egor-tensin/winapi-debug.
+// Distributed under the MIT License.
+
+#pragma once
+
+#include "address.hpp"
+#include "dbghelp.hpp"
+
+#include <windows.h>
+
+#include <array>
+#include <cstddef>
+#include <functional>
+#include <ostream>
+#include <string>
+
+namespace pdb {
+
+class CallStack {
+public:
+ static constexpr std::size_t frames_to_skip = 0;
+ static constexpr std::size_t frames_to_capture = 62;
+
+ // Imposed by CaptureStackBackTrace:
+ static constexpr std::size_t max_length = 62;
+
+ static_assert(frames_to_skip + frames_to_capture <= max_length,
+ "Call stack length is too large");
+
+ static CallStack capture();
+
+ using AddressCallback = std::function<bool(Address)>;
+ bool for_each_address(const AddressCallback& callback) const;
+
+ static std::string pretty_print_address(const DbgHelp& dbghelp, Address addr);
+
+ void dump(std::ostream& os, const DbgHelp&) const;
+
+ const std::array<Address, max_length> frames;
+ const std::size_t length;
+
+ const Address* begin() const { return frames.data(); }
+ const Address* cbegin() const { return begin(); }
+ const Address* end() const { return begin() + length; }
+ const Address* cend() const { return end(); }
+
+private:
+ CallStack() = default;
+};
+
+} // namespace pdb
diff --git a/include/winapi/debug/dbghelp.hpp b/include/winapi/debug/dbghelp.hpp
new file mode 100644
index 0000000..6965823
--- /dev/null
+++ b/include/winapi/debug/dbghelp.hpp
@@ -0,0 +1,72 @@
+// Copyright (c) 2017 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "winapi-debug" project.
+// For details, see https://github.com/egor-tensin/winapi-debug.
+// Distributed under the MIT License.
+
+#pragma once
+
+#include "address.hpp"
+#include "module.hpp"
+#include "symbol.hpp"
+
+#include <windows.h>
+
+#include <functional>
+#include <string>
+
+namespace pdb {
+
+class DbgHelp {
+public:
+ static DbgHelp current_process() { return DbgHelp{true}; }
+ static DbgHelp post_mortem() { return DbgHelp{false}; }
+
+ void swap(DbgHelp& other) noexcept;
+
+ DbgHelp(DbgHelp&& other) noexcept;
+ DbgHelp& operator=(DbgHelp) noexcept;
+ ~DbgHelp();
+
+ ModuleInfo load_pdb(const std::string& path) const;
+
+ typedef std::function<void(const ModuleInfo&)> OnModule;
+ void enum_modules(const OnModule&) const;
+
+ ModuleInfo resolve_module(Address) const;
+
+ typedef std::function<void(const SymbolInfo&)> OnSymbol;
+ static constexpr auto all_symbols = "*!*";
+ void enum_symbols(const ModuleInfo&, const std::string& mask, const OnSymbol&) const;
+ void enum_symbols(const ModuleInfo&, const OnSymbol&) const;
+ void enum_symbols(const std::string& mask, const OnSymbol&) const;
+ void enum_symbols(const OnSymbol&) const;
+
+ SymbolInfo resolve_symbol(Address) const;
+ SymbolInfo resolve_symbol(const std::string&) const;
+
+ LineInfo resolve_line(Address) const;
+
+private:
+ explicit DbgHelp(bool invade_current_process);
+
+ void close();
+
+ HANDLE id = NULL;
+
+ DbgHelp(const DbgHelp&) = delete;
+};
+
+inline void swap(DbgHelp& a, DbgHelp& b) noexcept {
+ a.swap(b);
+}
+
+} // namespace pdb
+
+namespace std {
+
+template <>
+inline void swap(pdb::DbgHelp& a, pdb::DbgHelp& b) noexcept {
+ a.swap(b);
+}
+
+} // namespace std
diff --git a/include/winapi/debug/module.hpp b/include/winapi/debug/module.hpp
new file mode 100644
index 0000000..5cfa69d
--- /dev/null
+++ b/include/winapi/debug/module.hpp
@@ -0,0 +1,54 @@
+// Copyright (c) 2017 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "winapi-debug" project.
+// For details, see https://github.com/egor-tensin/winapi-debug.
+// Distributed under the MIT License.
+
+#pragma once
+
+#include "address.hpp"
+
+#include <dbghelp.h>
+#include <windows.h>
+
+#include <string>
+
+namespace pdb {
+
+class ModuleInfo {
+public:
+ typedef IMAGEHLP_MODULEW64 Impl;
+
+ ModuleInfo();
+ explicit ModuleInfo(const Impl& impl);
+
+ explicit operator Impl&() { return impl; }
+ explicit operator const Impl&() const { return impl; }
+
+ Address get_offline_base() const { return impl.BaseOfImage; }
+
+ std::string get_name() const;
+
+private:
+ static Impl create_impl();
+
+ Impl impl;
+};
+
+class Module : public ModuleInfo {
+public:
+ Module(Address online_base, const ModuleInfo& info)
+ : ModuleInfo{info}, online_base{online_base} {}
+
+ Address get_online_base() const { return online_base; }
+
+ Address translate_offline_address(Address offline) const;
+ Address translate_online_address(Address online) const;
+
+private:
+ std::string invalid_offline_address(Address offline) const;
+ std::string invalid_online_address(Address online) const;
+
+ const Address online_base;
+};
+
+} // namespace pdb
diff --git a/include/winapi/debug/repo.hpp b/include/winapi/debug/repo.hpp
new file mode 100644
index 0000000..3b194ff
--- /dev/null
+++ b/include/winapi/debug/repo.hpp
@@ -0,0 +1,58 @@
+// Copyright (c) 2017 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "winapi-debug" project.
+// For details, see https://github.com/egor-tensin/winapi-debug.
+// Distributed under the MIT License.
+
+#pragma once
+
+#include "address.hpp"
+#include "dbghelp.hpp"
+#include "module.hpp"
+#include "symbol.hpp"
+
+#include <winapi/file.hpp>
+
+#include <functional>
+#include <map>
+#include <string>
+#include <unordered_set>
+
+namespace pdb {
+
+class Repo {
+public:
+ Repo() = default;
+
+ Address add_pdb(Address online_base, const std::string& path);
+
+ typedef std::function<void(const Symbol&)> OnSymbol;
+ void enum_symbols(const OnSymbol&) const;
+ void enum_symbols(Address offline_base, const OnSymbol&) const;
+ void enum_symbols(const Module&, const OnSymbol&) const;
+
+ Symbol resolve_symbol(Address) const;
+ Symbol resolve_symbol(const std::string&) const;
+
+ LineInfo resolve_line(Address) const;
+
+ const Module& module_with_online_base(Address) const;
+ const Module& module_with_offline_base(Address) const;
+
+private:
+ Symbol symbol_from_buffer(const SymbolInfo&) const;
+ static Symbol symbol_from_buffer(const Module&, const SymbolInfo&);
+
+ const Module& module_from_online_address(Address) const;
+ const Module& module_from_offline_address(Address) const;
+
+ Address address_offline_to_online(Address) const;
+ Address address_online_to_offline(Address) const;
+
+ const DbgHelp dbghelp{DbgHelp::post_mortem()};
+
+ std::unordered_set<winapi::File::ID> file_ids;
+ std::map<Address, Module> online_bases;
+ std::map<Address, const Module&> offline_bases;
+};
+
+} // namespace pdb
diff --git a/include/winapi/debug/symbol.hpp b/include/winapi/debug/symbol.hpp
new file mode 100644
index 0000000..47e4fb1
--- /dev/null
+++ b/include/winapi/debug/symbol.hpp
@@ -0,0 +1,97 @@
+// Copyright (c) 2017 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "winapi-debug" project.
+// For details, see https://github.com/egor-tensin/winapi-debug.
+// Distributed under the MIT License.
+
+#pragma once
+
+#include "address.hpp"
+#include "module.hpp"
+
+#include <dbghelp.h>
+#include <windows.h>
+
+#include <array>
+#include <climits>
+#include <cstddef>
+#include <string>
+#include <type_traits>
+
+namespace pdb {
+namespace symbol {
+
+// MinGW-w64 (as of version 7.0) doesn't have SymTagEnum
+typedef ULONG Tag;
+
+constexpr Tag SYM_TAG_FUNCTION = 5;
+
+#ifdef _MSC_VER
+static_assert(static_cast<Tag>(SymTagFunction) == SYM_TAG_FUNCTION,
+ "unexpected SymTagFunction value");
+#endif
+
+} // namespace symbol
+
+class SymbolInfo {
+public:
+ typedef SYMBOL_INFOW Impl;
+
+ SymbolInfo();
+ explicit SymbolInfo(const Impl& impl);
+
+ explicit operator Impl&() { return get_impl(); }
+ explicit operator const Impl&() const { return get_impl(); }
+
+ Address get_displacement() const { return displacement; }
+ void set_displacement(Address new_value) { displacement = new_value; }
+
+ std::string get_name() const;
+
+ Address get_offline_base() const { return get_impl().ModBase; }
+ Address get_offline_address() const { return get_impl().Address; }
+
+ symbol::Tag get_tag() const { return get_impl().Tag; }
+
+ enum class Type : symbol::Tag {
+ Function = symbol::SYM_TAG_FUNCTION,
+ RESERVED = ULONG_MAX,
+ };
+
+ Type get_type() const { return static_cast<Type>(get_tag()); }
+
+ bool is_function() const { return get_type() == Type::Function; }
+
+private:
+ static constexpr std::size_t char_size = sizeof(std::remove_extent<decltype(Impl::Name)>::type);
+ static_assert(char_size == sizeof(wchar_t), "Aren't we using the wide WinAPI?");
+ static constexpr std::size_t max_buffer_size = sizeof(Impl) + (MAX_SYM_NAME - 1) * char_size;
+
+ std::array<unsigned char, max_buffer_size> buffer;
+ Address displacement = 0;
+
+ const Impl& get_impl() const { return *reinterpret_cast<const Impl*>(buffer.data()); }
+ Impl& get_impl() { return *reinterpret_cast<Impl*>(buffer.data()); }
+};
+
+class Symbol : public SymbolInfo {
+public:
+ Symbol(Address online_address, const SymbolInfo& info)
+ : SymbolInfo{info}, online_address{online_address} {}
+
+ Address get_online_address() const { return online_address; }
+
+private:
+ const Address online_address;
+};
+
+class LineInfo {
+public:
+ typedef IMAGEHLP_LINEW64 Impl;
+
+ explicit LineInfo(const Impl& impl);
+
+ const std::string file_path;
+ const unsigned long line_number;
+};
+
+} // namespace pdb