diff options
-rw-r--r-- | include/pdb/address.hpp | 35 | ||||
-rw-r--r-- | include/pdb/dbghelp.hpp | 44 | ||||
-rw-r--r-- | include/pdb/error.hpp | 53 | ||||
-rw-r--r-- | include/pdb/handle.hpp | 30 | ||||
-rw-r--r-- | include/pdb/module.hpp | 61 | ||||
-rw-r--r-- | include/pdb/repo.hpp | 58 | ||||
-rw-r--r-- | include/pdb/symbol.hpp | 167 | ||||
-rw-r--r-- | include/pdb/utils/file.hpp | 77 | ||||
-rw-r--r-- | src/dbghelp.cpp | 243 | ||||
-rw-r--r-- | src/error.cpp | 75 | ||||
-rw-r--r-- | src/module.cpp | 99 | ||||
-rw-r--r-- | src/repo.cpp | 302 | ||||
-rw-r--r-- | src/utils/file.cpp | 110 | ||||
-rw-r--r-- | utils/addr2name.cpp | 163 | ||||
-rw-r--r-- | utils/command_line.hpp | 44 | ||||
-rw-r--r-- | utils/enum_symbols.cpp | 94 | ||||
-rw-r--r-- | utils/name2addr.cpp | 96 | ||||
-rw-r--r-- | utils/pdb_descr.hpp | 59 |
18 files changed, 789 insertions, 1021 deletions
diff --git a/include/pdb/address.hpp b/include/pdb/address.hpp index 4a62249..ea3b79d 100644 --- a/include/pdb/address.hpp +++ b/include/pdb/address.hpp @@ -10,22 +10,21 @@ #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 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 { + +typedef DWORD64 Address; + +inline std::string format_address(Address address) { + std::ostringstream oss; + oss << std::hex << std::showbase << address; + return oss.str(); } + +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/pdb/dbghelp.hpp b/include/pdb/dbghelp.hpp index 2555de1..4f11e22 100644 --- a/include/pdb/dbghelp.hpp +++ b/include/pdb/dbghelp.hpp @@ -14,33 +14,33 @@ #include <functional> #include <string> -namespace pdb -{ - class DbgHelp - { - public: - DbgHelp(); - ~DbgHelp(); +namespace pdb { - void close(); +class DbgHelp { +public: + DbgHelp(); + ~DbgHelp(); - ModuleInfo load_pdb(const std::string& path) const; + void close(); - typedef std::function<void (const SymbolInfo&)> OnSymbol; - void enum_symbols(const ModuleInfo&, const OnSymbol&) const; + ModuleInfo load_pdb(const std::string& path) const; - SymbolInfo resolve_symbol(Address) const; - SymbolInfo resolve_symbol(const std::string&) const; + typedef std::function<void(const SymbolInfo&)> OnSymbol; + void enum_symbols(const ModuleInfo&, const OnSymbol&) const; - LineInfo resolve_line(Address) const; + SymbolInfo resolve_symbol(Address) const; + SymbolInfo resolve_symbol(const std::string&) const; - private: - ModuleInfo get_module_info(Address offline_base) const; + LineInfo resolve_line(Address) const; - const HANDLE id = GetCurrentProcess(); - bool closed = false; +private: + ModuleInfo get_module_info(Address offline_base) const; - DbgHelp(const DbgHelp&) = delete; - DbgHelp& operator=(const DbgHelp&) = delete; - }; -} + const HANDLE id = GetCurrentProcess(); + bool closed = false; + + DbgHelp(const DbgHelp&) = delete; + DbgHelp& operator=(const DbgHelp&) = delete; +}; + +} // namespace pdb diff --git a/include/pdb/error.hpp b/include/pdb/error.hpp index 6640907..2b9a8be 100644 --- a/include/pdb/error.hpp +++ b/include/pdb/error.hpp @@ -10,33 +10,28 @@ #include <string> #include <system_error> -namespace pdb -{ - namespace error - { - class CategoryWindows : public std::error_category - { - public: - CategoryWindows() = default; - - const char* name() const noexcept { return "Windows"; } - - std::string message(int) const; - }; - - inline const CategoryWindows& category_windows() - { - static const CategoryWindows instance; - return instance; - } - - inline std::system_error windows(DWORD code) - { - static_assert(sizeof(DWORD) == sizeof(int), "Aren't DWORDs the same size as ints?"); - - return std::system_error{ - static_cast<int>(code), - category_windows()}; - } - } +namespace pdb { +namespace error { + +class CategoryWindows : public std::error_category { +public: + CategoryWindows() = default; + + const char* name() const noexcept { return "Windows"; } + + std::string message(int) const; +}; + +inline const CategoryWindows& category_windows() { + static const CategoryWindows instance; + return instance; } + +inline std::system_error windows(DWORD code) { + static_assert(sizeof(DWORD) == sizeof(int), "Aren't DWORDs the same size as ints?"); + + return std::system_error{static_cast<int>(code), category_windows()}; +} + +} // namespace error +} // namespace pdb diff --git a/include/pdb/handle.hpp b/include/pdb/handle.hpp index 52fb805..7c0cc40 100644 --- a/include/pdb/handle.hpp +++ b/include/pdb/handle.hpp @@ -8,22 +8,20 @@ #include <Windows.h> #include <cassert> - #include <memory> -namespace pdb -{ - struct CloseHandle - { - void operator()(HANDLE raw) const - { - if (raw == NULL || raw == INVALID_HANDLE_VALUE) - return; - const auto ret = ::CloseHandle(raw); - assert(ret); - UNREFERENCED_PARAMETER(ret); - } - }; +namespace pdb { + +struct CloseHandle { + void operator()(HANDLE raw) const { + if (raw == NULL || raw == INVALID_HANDLE_VALUE) + return; + const auto ret = ::CloseHandle(raw); + assert(ret); + UNREFERENCED_PARAMETER(ret); + } +}; + +typedef std::unique_ptr<void, CloseHandle> Handle; - typedef std::unique_ptr<void, CloseHandle> Handle; -} +} // namespace pdb diff --git a/include/pdb/module.hpp b/include/pdb/module.hpp index 926db2c..47eeef3 100644 --- a/include/pdb/module.hpp +++ b/include/pdb/module.hpp @@ -14,46 +14,43 @@ #include <string> -namespace pdb -{ - class ModuleInfo - { - public: - typedef IMAGEHLP_MODULE64 Raw; +namespace pdb { - ModuleInfo(); - explicit ModuleInfo(const Raw& raw); +class ModuleInfo { +public: + typedef IMAGEHLP_MODULE64 Raw; - explicit operator Raw&() { return raw; } - explicit operator const Raw&() const { return raw; } + ModuleInfo(); + explicit ModuleInfo(const Raw& raw); - Address get_offline_base() const { return raw.BaseOfImage; } + explicit operator Raw&() { return raw; } + explicit operator const Raw&() const { return raw; } - std::string get_name() const { return raw.ModuleName; } + Address get_offline_base() const { return raw.BaseOfImage; } - private: - static Raw create_raw(); + std::string get_name() const { return raw.ModuleName; } - Raw raw; - }; +private: + static Raw create_raw(); - class Module : public ModuleInfo - { - public: - Module(Address online_base, const ModuleInfo& info) - : ModuleInfo{info} - , online_base{online_base} - { } + Raw raw; +}; - Address get_online_base() const { return online_base; } +class Module : public ModuleInfo { +public: + Module(Address online_base, const ModuleInfo& info) + : ModuleInfo{info}, online_base{online_base} {} - Address translate_offline_address(Address offline) const; - Address translate_online_address(Address online) const; + Address get_online_base() const { return online_base; } - private: - std::string invalid_offline_address(Address offline) const; - std::string invalid_online_address(Address online) const; + Address translate_offline_address(Address offline) const; + Address translate_online_address(Address online) const; - const Address online_base; - }; -} +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/pdb/repo.hpp b/include/pdb/repo.hpp index c8a2964..8bc5596 100644 --- a/include/pdb/repo.hpp +++ b/include/pdb/repo.hpp @@ -16,42 +16,42 @@ #include <string> #include <unordered_set> -namespace pdb -{ - class Repo - { - public: - Repo() = default; +namespace pdb { - Address add_pdb(Address online_base, const std::string& path); +class Repo { +public: + Repo() = default; - 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; + Address add_pdb(Address online_base, const std::string& path); - Symbol resolve_symbol(Address) const; - Symbol resolve_symbol(const std::string&) const; + 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; - LineInfo resolve_line(Address) const; + Symbol resolve_symbol(Address) const; + Symbol resolve_symbol(const std::string&) const; - const Module& module_with_online_base(Address) const; - const Module& module_with_offline_base(Address) const; + LineInfo resolve_line(Address) const; - private: - Symbol symbol_from_buffer(const SymbolInfo&) const; - static Symbol symbol_from_buffer(const Module&, const SymbolInfo&); + const Module& module_with_online_base(Address) const; + const Module& module_with_offline_base(Address) const; - const Module& module_from_online_address(Address) const; - const Module& module_from_offline_address(Address) const; +private: + Symbol symbol_from_buffer(const SymbolInfo&) const; + static Symbol symbol_from_buffer(const Module&, const SymbolInfo&); - Address address_offline_to_online(Address) const; - Address address_online_to_offline(Address) const; + const Module& module_from_online_address(Address) const; + const Module& module_from_offline_address(Address) const; - const DbgHelp dbghelp; + Address address_offline_to_online(Address) const; + Address address_online_to_offline(Address) const; - std::unordered_set<file::ID> file_ids; - std::map<Address, Module> online_bases; - std::map<Address, const Module&> offline_bases; - }; -} + const DbgHelp dbghelp; + + std::unordered_set<file::ID> file_ids; + std::map<Address, Module> online_bases; + std::map<Address, const Module&> offline_bases; +}; + +} // namespace pdb diff --git a/include/pdb/symbol.hpp b/include/pdb/symbol.hpp index ec0f80c..d9f3f0c 100644 --- a/include/pdb/symbol.hpp +++ b/include/pdb/symbol.hpp @@ -8,134 +8,113 @@ #include "address.hpp" #include "module.hpp" -#include <safeint.h> - #include <Windows.h> +#include <safeint.h> #pragma warning(push, 0) #include <DbgHelp.h> #pragma warning(pop) #include <cstddef> #include <cstring> - #include <stdexcept> #include <string> -namespace pdb -{ - class SymbolInfo - { - public: - typedef SYMBOL_INFO Raw; - - SymbolInfo() - : raw{*reinterpret_cast<Raw*>(buffer)} - { - raw.SizeOfStruct = sizeof(Raw); - raw.MaxNameLen = MAX_SYM_NAME; - } +namespace pdb { - explicit SymbolInfo(const Raw& raw) - : SymbolInfo{} - { - if (raw.SizeOfStruct != sizeof(raw)) - throw std::runtime_error{"invalid SYMBOL_INFO.SizeOfStruct"}; - const auto raw_size = calc_size(raw); - if (raw_size > sizeof(buffer)) - throw std::runtime_error{"SYMBOL_INFO is too large"}; - std::memcpy(buffer, &raw, raw_size); - } +class SymbolInfo { +public: + typedef SYMBOL_INFO Raw; - explicit operator Raw&() { return raw; } + SymbolInfo() : raw{*reinterpret_cast<Raw*>(buffer)} { + raw.SizeOfStruct = sizeof(Raw); + raw.MaxNameLen = MAX_SYM_NAME; + } - explicit operator const Raw&() const { return raw; } + explicit SymbolInfo(const Raw& raw) : SymbolInfo{} { + if (raw.SizeOfStruct != sizeof(raw)) + throw std::runtime_error{"invalid SYMBOL_INFO.SizeOfStruct"}; + const auto raw_size = calc_size(raw); + if (raw_size > sizeof(buffer)) + throw std::runtime_error{"SYMBOL_INFO is too large"}; + std::memcpy(buffer, &raw, raw_size); + } - Address get_displacement() const { return displacement; } + explicit operator Raw&() { return raw; } - void set_displacement(Address new_value) - { - displacement = new_value; - } + explicit operator const Raw&() const { return raw; } - std::string get_name() const { return {raw.Name, raw.NameLen}; } + Address get_displacement() const { return displacement; } - Address get_offline_base() const { return raw.ModBase; } + void set_displacement(Address new_value) { displacement = new_value; } - Address get_offline_address() const { return raw.Address; } + std::string get_name() const { return {raw.Name, raw.NameLen}; } - typedef ULONG Tag; + Address get_offline_base() const { return raw.ModBase; } - Tag get_tag() const { return raw.Tag; } + Address get_offline_address() const { return raw.Address; } - enum class Type : Tag - { - Function = SymTagFunction, - RESERVED = SymTagMax, - }; + typedef ULONG Tag; - Type get_type() const { return static_cast<Type>(get_tag()); } + Tag get_tag() const { return raw.Tag; } - bool is_function() const { return get_type() == Type::Function; } + enum class Type : Tag { + Function = SymTagFunction, + RESERVED = SymTagMax, + }; - private: - static constexpr std::size_t max_buffer_size = sizeof(Raw) + MAX_SYM_NAME - 1; + Type get_type() const { return static_cast<Type>(get_tag()); } - static std::size_t calc_size(const Raw& raw) - { - using namespace msl::utilities; - try - { - return SafeInt<std::size_t>{raw.SizeOfStruct} + raw.NameLen - 1; - } - catch (const SafeIntException&) - { - throw std::runtime_error{"invalid SYMBOL_INFO size"}; - } + bool is_function() const { return get_type() == Type::Function; } + +private: + static constexpr std::size_t max_buffer_size = sizeof(Raw) + MAX_SYM_NAME - 1; + + static std::size_t calc_size(const Raw& raw) { + using namespace msl::utilities; + try { + return SafeInt<std::size_t>{raw.SizeOfStruct} + raw.NameLen - 1; + } catch (const SafeIntException&) { + throw std::runtime_error{"invalid SYMBOL_INFO size"}; } + } - unsigned char buffer[max_buffer_size] = {0}; - Address displacement = 0; + unsigned char buffer[max_buffer_size] = {0}; + Address displacement = 0; - protected: - Raw& raw; - }; +protected: + Raw& raw; +}; - class Symbol : public SymbolInfo - { - public: - Symbol(Address online_address, const SymbolInfo& info) - : SymbolInfo{info} - , online_address{online_address} - { } +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; } + Address get_online_address() const { return online_address; } - private: - const Address online_address; - }; +private: + const Address online_address; +}; - class LineInfo - { - public: - typedef IMAGEHLP_LINE64 Raw; +class LineInfo { +public: + typedef IMAGEHLP_LINE64 Raw; - explicit LineInfo(const Raw& raw) - : file_path{raw.FileName} - , line_number{cast_line_number(raw.LineNumber)} - { } + explicit LineInfo(const Raw& raw) + : file_path{raw.FileName}, line_number{cast_line_number(raw.LineNumber)} {} - const std::string file_path; - const unsigned long line_number; + const std::string file_path; + const unsigned long line_number; - private: - static unsigned long cast_line_number(DWORD raw) - { - unsigned long dest = 0; +private: + static unsigned long cast_line_number(DWORD raw) { + unsigned long dest = 0; - if (!msl::utilities::SafeCast(raw, dest)) - throw std::runtime_error{"invalid line number"}; + if (!msl::utilities::SafeCast(raw, dest)) + throw std::runtime_error{"invalid line number"}; - return dest; - } - }; -} + return dest; + } +}; + +} // namespace pdb diff --git a/include/pdb/utils/file.hpp b/include/pdb/utils/file.hpp index bf97115..acb5cfc 100644 --- a/include/pdb/utils/file.hpp +++ b/include/pdb/utils/file.hpp @@ -5,55 +5,50 @@ #pragma once -#include <Windows.h> - #pragma warning(push, 0) #include <boost/functional/hash.hpp> #pragma warning(pop) +#include <Windows.h> + #include <cstddef> #include <cstring> - #include <functional> #include <string> -namespace pdb -{ - namespace file - { - std::size_t get_size(const std::string&); - - inline bool operator==(const FILE_ID_128& a, const FILE_ID_128& b) - { - return 0 == std::memcmp(a.Identifier, b.Identifier, sizeof(a.Identifier)); - } - - struct ID - { - const FILE_ID_INFO raw; - - bool operator==(const ID& other) const - { - return raw.VolumeSerialNumber == other.raw.VolumeSerialNumber - && raw.FileId == other.raw.FileId; - } - }; - - ID query_id(const std::string&); - } -} +namespace pdb { +namespace file { -namespace std -{ - template <> - struct hash<pdb::file::ID> - { - std::size_t operator()(const pdb::file::ID& id) const - { - std::size_t seed = 0; - boost::hash_combine(seed, id.raw.VolumeSerialNumber); - boost::hash_combine(seed, id.raw.FileId.Identifier); - return seed; - } - }; +std::size_t get_size(const std::string&); + +inline bool operator==(const FILE_ID_128& a, const FILE_ID_128& b) { + return 0 == std::memcmp(a.Identifier, b.Identifier, sizeof(a.Identifier)); } + +struct ID { + const FILE_ID_INFO raw; + + bool operator==(const ID& other) const { + return raw.VolumeSerialNumber == other.raw.VolumeSerialNumber && + raw.FileId == other.raw.FileId; + } +}; + +ID query_id(const std::string&); + +} // namespace file +} // namespace pdb + +namespace std { + +template <> +struct hash<pdb::file::ID> { + std::size_t operator()(const pdb::file::ID& id) const { + std::size_t seed = 0; + boost::hash_combine(seed, id.raw.VolumeSerialNumber); + boost::hash_combine(seed, id.raw.FileId.Identifier); + return seed; + } +}; + +} // namespace std diff --git a/src/dbghelp.cpp b/src/dbghelp.cpp index 38cb6f5..40c2ba5 100644 --- a/src/dbghelp.cpp +++ b/src/dbghelp.cpp @@ -5,180 +5,137 @@ #include "pdb/all.hpp" -#include <safeint.h> - #include <Windows.h> +#include <safeint.h> #pragma warning(push, 0) #include <DbgHelp.h> #pragma warning(pop, 0) #include <cstddef> #include <cstring> - #include <stdexcept> #include <string> -namespace pdb -{ - namespace - { - void set_dbghelp_options() - { - SymSetOptions(SymGetOptions() - | SYMOPT_DEBUG - | SYMOPT_LOAD_LINES - | SYMOPT_UNDNAME); - } - - void initialize(HANDLE id) - { - set_dbghelp_options(); - - if (!SymInitialize(id, NULL, FALSE)) - throw error::windows(GetLastError()); - } - - void clean_up(HANDLE id) - { - if (!SymCleanup(id)) - throw error::windows(GetLastError()); - } - - Address next_offline_base = 0x10000000; - - Address gen_next_offline_base(std::size_t pdb_size) - { - const auto base = next_offline_base; - using msl::utilities::SafeAdd; - if (!SafeAdd(next_offline_base, pdb_size, next_offline_base)) - throw std::runtime_error{"no more PDB files can be added, the internal address space is exhausted"}; - return base; - } - - 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; - } - } +namespace pdb { +namespace { - DbgHelp::DbgHelp() - { - initialize(id); - } +void set_dbghelp_options() { + SymSetOptions(SymGetOptions() | SYMOPT_DEBUG | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); +} - DbgHelp::~DbgHelp() - { - try - { - close(); - } - catch (...) - { } - } +void initialize(HANDLE id) { + set_dbghelp_options(); - void DbgHelp::close() - { - if (!closed) - { - clean_up(id); - closed = true; - } - } + if (!SymInitialize(id, NULL, FALSE)) + throw error::windows(GetLastError()); +} - ModuleInfo DbgHelp::load_pdb(const std::string& path) const - { - DWORD size = 0; - if (!msl::utilities::SafeCast(file::get_size(path), size)) - throw std::range_error{"PDB file is too large"}; +void clean_up(HANDLE id) { + if (!SymCleanup(id)) + throw error::windows(GetLastError()); +} - const auto offline_base = SymLoadModule64( - id, - NULL, - path.c_str(), - NULL, - gen_next_offline_base(size), - size); +Address next_offline_base = 0x10000000; - if (!offline_base) - throw error::windows(GetLastError()); +Address gen_next_offline_base(std::size_t pdb_size) { + const auto base = next_offline_base; + using msl::utilities::SafeAdd; + if (!SafeAdd(next_offline_base, pdb_size, next_offline_base)) + throw std::runtime_error{ + "no more PDB files can be added, the internal address space is exhausted"}; + return base; +} - return get_module_info(offline_base); - } +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; +} - ModuleInfo DbgHelp::get_module_info(Address offline_base) const - { - ModuleInfo info; +} // namespace - if (!SymGetModuleInfo64( - id, - offline_base, - &static_cast<ModuleInfo::Raw&>(info))) - throw error::windows(GetLastError()); +DbgHelp::DbgHelp() { + initialize(id); +} - return info; +DbgHelp::~DbgHelp() { + try { + close(); + } catch (...) { } +} - void DbgHelp::enum_symbols(const ModuleInfo& module, const OnSymbol& callback) const - { - if (!SymEnumSymbols( - id, - module.get_offline_base(), - NULL, - &enum_symbols_callback, - const_cast<OnSymbol*>(&callback))) - throw error::windows(GetLastError()); +void DbgHelp::close() { + if (!closed) { + clean_up(id); + closed = true; } +} - SymbolInfo DbgHelp::resolve_symbol(Address offline) const - { - Address displacement = 0; - SymbolInfo symbol; +ModuleInfo DbgHelp::load_pdb(const std::string& path) const { + DWORD size = 0; + if (!msl::utilities::SafeCast(file::get_size(path), size)) + throw std::range_error{"PDB file is too large"}; - if (!SymFromAddr( - id, - offline, - &displacement, - &static_cast<SYMBOL_INFO&>(symbol))) - throw error::windows(GetLastError()); + const auto offline_base = + SymLoadModule64(id, NULL, path.c_str(), NULL, gen_next_offline_base(size), size); - symbol.set_displacement(displacement); - return symbol; - } + if (!offline_base) + throw error::windows(GetLastError()); - SymbolInfo DbgHelp::resolve_symbol(const std::string& name) const - { - SymbolInfo symbol; + return get_module_info(offline_base); +} - if (!SymFromName( - id, - name.c_str(), - &static_cast<SYMBOL_INFO&>(symbol))) - throw error::windows(GetLastError()); +ModuleInfo DbgHelp::get_module_info(Address offline_base) const { + ModuleInfo info; - return symbol; - } + if (!SymGetModuleInfo64(id, offline_base, &static_cast<ModuleInfo::Raw&>(info))) + throw error::windows(GetLastError()); - LineInfo DbgHelp::resolve_line(Address offline) const - { - IMAGEHLP_LINE64 raw; - std::memset(&raw, 0, sizeof(raw)); - raw.SizeOfStruct = sizeof(raw); + return info; +} - DWORD displacement = 0; +void DbgHelp::enum_symbols(const ModuleInfo& module, const OnSymbol& callback) const { + if (!SymEnumSymbols(id, + module.get_offline_base(), + NULL, + &enum_symbols_callback, + const_cast<OnSymbol*>(&callback))) + throw error::windows(GetLastError()); +} - if (!SymGetLineFromAddr64( - id, - offline, - &displacement, - &raw)) - throw error::windows(GetLastError()); +SymbolInfo DbgHelp::resolve_symbol(Address offline) const { + Address displacement = 0; + SymbolInfo symbol; - return LineInfo{raw}; - } + if (!SymFromAddr(id, offline, &displacement, &static_cast<SYMBOL_INFO&>(symbol))) + throw error::windows(GetLastError()); + + symbol.set_displacement(displacement); + return symbol; } + +SymbolInfo DbgHelp::resolve_symbol(const std::string& name) const { + SymbolInfo symbol; + + if (!SymFromName(id, name.c_str(), &static_cast<SYMBOL_INFO&>(symbol))) + throw error::windows(GetLastError()); + + return symbol; +} + +LineInfo DbgHelp::resolve_line(Address offline) const { + IMAGEHLP_LINE64 raw; + std::memset(&raw, 0, sizeof(raw)); + raw.SizeOfStruct = sizeof(raw); + + DWORD displacement = 0; + + if (!SymGetLineFromAddr64(id, offline, &displacement, &raw)) + throw error::windows(GetLastError()); + + return LineInfo{raw}; +} + +} // namespace pdb diff --git a/src/error.cpp b/src/error.cpp index 10b668b..320c5d0 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -9,45 +9,40 @@ #include <string> -namespace pdb -{ - namespace error - { - namespace - { - std::string trim_trailing_newline(const std::string& s) - { - const auto last_pos = s.find_last_not_of("\r\n"); - if (std::string::npos == last_pos) - return {}; - return s.substr(0, last_pos + 1); - } - } - - std::string CategoryWindows::message(int code) const - { - char* buf; - - const auto nbwritten = FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - code, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - reinterpret_cast<char*>(&buf), - 0, - NULL); - - if (0 == nbwritten) - { - LocalFree(buf); - return "Couldn't format the error message"; - } - - std::string msg{buf, nbwritten}; - LocalFree(buf); - return trim_trailing_newline(msg); - } +namespace pdb { +namespace error { +namespace { + +std::string trim_trailing_newline(const std::string& s) { + const auto last_pos = s.find_last_not_of("\r\n"); + if (std::string::npos == last_pos) + return {}; + return s.substr(0, last_pos + 1); +} + +} // namespace + +std::string CategoryWindows::message(int code) const { + char* buf; + + const auto nbwritten = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + code, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast<char*>(&buf), + 0, + NULL); + + if (0 == nbwritten) { + LocalFree(buf); + return "Couldn't format the error message"; } + + std::string msg{buf, nbwritten}; + LocalFree(buf); + return trim_trailing_newline(msg); } + +} // namespace error +} // namespace pdb diff --git a/src/module.cpp b/src/module.cpp index 2c1d26c..0bf9329 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -8,69 +8,58 @@ #include <safeint.h> #include <cstring> - #include <sstream> #include <stdexcept> #include <string> -namespace pdb -{ - ModuleInfo::ModuleInfo() - : ModuleInfo{create_raw()} - { } +namespace pdb { + +ModuleInfo::ModuleInfo() : ModuleInfo{create_raw()} {} - ModuleInfo::ModuleInfo(const Raw& raw) - : raw{raw} - { - if (raw.SizeOfStruct != sizeof(raw)) - throw std::runtime_error{"invalid IMAGEHLP_MODULE64.SizeOfStruct"}; - } +ModuleInfo::ModuleInfo(const Raw& raw) : raw{raw} { + if (raw.SizeOfStruct != sizeof(raw)) + throw std::runtime_error{"invalid IMAGEHLP_MODULE64.SizeOfStruct"}; +} - ModuleInfo::Raw ModuleInfo::create_raw() - { - Raw raw; - std::memset(&raw, 0, sizeof(raw)); - raw.SizeOfStruct = sizeof(raw); - return raw; - } +ModuleInfo::Raw ModuleInfo::create_raw() { + Raw raw; + std::memset(&raw, 0, sizeof(raw)); + raw.SizeOfStruct = sizeof(raw); + return raw; +} - Address Module::translate_offline_address(Address offline) const - { - if (offline < get_offline_base()) - throw std::range_error{invalid_offline_address(offline)}; - const auto offset = offline - get_offline_base(); - auto online = offset; - if (!msl::utilities::SafeAdd(online, get_online_base(), online)) - throw std::range_error{invalid_offline_address(offline)}; - return online; - } +Address Module::translate_offline_address(Address offline) const { + if (offline < get_offline_base()) + throw std::range_error{invalid_offline_address(offline)}; + const auto offset = offline - get_offline_base(); + auto online = offset; + if (!msl::utilities::SafeAdd(online, get_online_base(), online)) + throw std::range_error{invalid_offline_address(offline)}; + return online; +} - Address Module::translate_online_address(Address online) const - { - if (online < get_online_base()) - throw std::range_error{invalid_online_address(online)}; - const auto offset = online - get_online_base(); - auto offline = offset; - if (!msl::utilities::SafeAdd(offline, get_offline_base(), offline)) - throw std::range_error{invalid_online_address(offline)}; - return offline; - } +Address Module::translate_online_address(Address online) const { + if (online < get_online_base()) + throw std::range_error{invalid_online_address(online)}; + const auto offset = online - get_online_base(); + auto offline = offset; + if (!msl::utilities::SafeAdd(offline, get_offline_base(), offline)) + throw std::range_error{invalid_online_address(offline)}; + return offline; +} - std::string Module::invalid_offline_address(Address offline) const - { - std::ostringstream oss; - oss << "offline address " << format_address(offline) - << " doesn't belong to module " << get_name() - << " (base offline address " << format_address(get_offline_base()) << ')'; - return oss.str(); - } +std::string Module::invalid_offline_address(Address offline) const { + std::ostringstream oss; + oss << "offline address " << format_address(offline) << " doesn't belong to module " + << get_name() << " (base offline address " << format_address(get_offline_base()) << ')'; + return oss.str(); +} - std::string Module::invalid_online_address(Address online) const - { - std::ostringstream oss; - oss << "online address " << format_address(online) - << " doesn't belong to module " << get_name() - << " (base online address " << format_address(get_online_base()) << ')'; - return oss.str(); - } +std::string Module::invalid_online_address(Address online) const { + std::ostringstream oss; + oss << "online address " << format_address(online) << " doesn't belong to module " << get_name() + << " (base online address " << format_address(get_online_base()) << ')'; + return oss.str(); } + +} // namespace pdb diff --git a/src/repo.cpp b/src/repo.cpp index 7a19c83..d7f2c74 100644 --- a/src/repo.cpp +++ b/src/repo.cpp @@ -11,194 +11,160 @@ #include <string> #include <utility> -namespace pdb -{ - namespace - { - std::string pdb_already_loaded(Address online_base, const std::string& path) - { - std::ostringstream oss; - oss << "module with online base address " << format_address(online_base) - << " has already been loaded: " << path; - return oss.str(); - } - - std::string pdb_already_loaded(const std::string& path) - { - std::ostringstream oss; - oss << "module has already been loaded: " << path; - return oss.str(); - } - - std::string offline_base_already_used(Address base) - { - std::ostringstream oss; - oss << "module with offline base address " << format_address(base) - << " has already been loaded (shouldn't happen)"; - return oss.str(); - } - - std::string module_not_found(Address base) - { - std::ostringstream oss; - oss << "module with base address " << format_address(base) - << " wasn't found"; - return oss.str(); - } - - std::string guess_module_no_modules(Address pivot) - { - std::ostringstream oss; - oss << "couldn't select a module for address " << format_address(pivot) - << ": no modules have been loaded yet"; - return oss.str(); - } - - std::string guess_module_address_too_low(Address pivot) - { - std::ostringstream oss; - oss << "couldn't select a module for address " << format_address(pivot) - << ": it's too low"; - return oss.str(); - } - - template <typename Value> - const Module& lookup_module( - const std::map<Address, Value>& modules, - Address base) - { - const auto it = modules.find(base); - if (it == modules.cend()) - throw std::runtime_error{module_not_found(base)}; - return it->second; - } - - template <typename Value> - const Module& guess_module( - const std::map<Address, Value>& modules, - Address pivot) - { - if (modules.empty()) - throw std::range_error{guess_module_no_modules(pivot)}; - - auto it = modules.lower_bound(pivot); - - if (it == modules.cend()) - { - --it; - return it->second; - } - - if (it->first > pivot) - { - if (it == modules.cbegin()) - throw std::range_error{guess_module_address_too_low(pivot)}; - --it; - return it->second; - } - - return it->second; - } - } +namespace pdb { +namespace { + +std::string pdb_already_loaded(Address online_base, const std::string& path) { + std::ostringstream oss; + oss << "module with online base address " << format_address(online_base) + << " has already been loaded: " << path; + return oss.str(); +} - Address Repo::add_pdb(Address online_base, const std::string& path) - { - if (online_bases.find(online_base) != online_bases.cend()) - throw std::runtime_error{pdb_already_loaded(online_base, path)}; +std::string pdb_already_loaded(const std::string& path) { + std::ostringstream oss; + oss << "module has already been loaded: " << path; + return oss.str(); +} - auto file_id = file::query_id(path); - if (file_ids.find(file_id) != file_ids.cend()) - throw std::runtime_error{pdb_already_loaded(path)}; +std::string offline_base_already_used(Address base) { + std::ostringstream oss; + oss << "module with offline base address " << format_address(base) + << " has already been loaded (shouldn't happen)"; + return oss.str(); +} - Module module{online_base, dbghelp.load_pdb(path)}; - const auto offline_base = module.get_offline_base(); +std::string module_not_found(Address base) { + std::ostringstream oss; + oss << "module with base address " << format_address(base) << " wasn't found"; + return oss.str(); +} - if (offline_bases.find(offline_base) != offline_bases.cend()) - throw std::runtime_error{offline_base_already_used(offline_base)}; +std::string guess_module_no_modules(Address pivot) { + std::ostringstream oss; + oss << "couldn't select a module for address " << format_address(pivot) + << ": no modules have been loaded yet"; + return oss.str(); +} - file_ids.emplace(std::move(file_id)); - const auto it = online_bases.emplace(online_base, std::move(module)); - offline_bases.emplace(offline_base, it.first->second); +std::string guess_module_address_too_low(Address pivot) { + std::ostringstream oss; + oss << "couldn't select a module for address " << format_address(pivot) << ": it's too low"; + return oss.str(); +} - return offline_base; - } +template <typename Value> +const Module& lookup_module(const std::map<Address, Value>& modules, Address base) { + const auto it = modules.find(base); + if (it == modules.cend()) + throw std::runtime_error{module_not_found(base)}; + return it->second; +} - void Repo::enum_symbols(const OnSymbol& callback) const - { - for (const auto& it : offline_bases) - enum_symbols(it.second, callback); - } +template <typename Value> +const Module& guess_module(const std::map<Address, Value>& modules, Address pivot) { + if (modules.empty()) + throw std::range_error{guess_module_no_modules(pivot)}; - void Repo::enum_symbols(Address offline_base, const OnSymbol& callback) const - { - const auto it = offline_bases.find(offline_base); - if (it == offline_bases.cend()) - throw std::runtime_error{"unknown module"}; - enum_symbols(it->second, callback); - } + auto it = modules.lower_bound(pivot); - void Repo::enum_symbols(const Module& module, const OnSymbol& callback) const - { - dbghelp.enum_symbols(module, [&] (const SymbolInfo& raw) - { - callback(symbol_from_buffer(module, raw)); - }); + if (it == modules.cend()) { + --it; + return it->second; } - Symbol Repo::resolve_symbol(Address online) const - { - return symbol_from_buffer(dbghelp.resolve_symbol(address_online_to_offline(online))); + if (it->first > pivot) { + if (it == modules.cbegin()) + throw std::range_error{guess_module_address_too_low(pivot)}; + --it; + return it->second; } - Symbol Repo::resolve_symbol(const std::string& name) const - { - return symbol_from_buffer(dbghelp.resolve_symbol(name)); - } + return it->second; +} - LineInfo Repo::resolve_line(Address online) const - { - return dbghelp.resolve_line(address_online_to_offline(online)); - } +} // namespace - const Module& Repo::module_with_online_base(Address base) const - { - return lookup_module(online_bases, base); - } +Address Repo::add_pdb(Address online_base, const std::string& path) { + if (online_bases.find(online_base) != online_bases.cend()) + throw std::runtime_error{pdb_already_loaded(online_base, path)}; - const Module& Repo::module_with_offline_base(Address base) const - { - return lookup_module(offline_bases, base); - } + auto file_id = file::query_id(path); + if (file_ids.find(file_id) != file_ids.cend()) + throw std::runtime_error{pdb_already_loaded(path)}; - Symbol Repo::symbol_from_buffer(const SymbolInfo& raw) const - { - return symbol_from_buffer(module_with_offline_base(raw.get_offline_base()), raw); - } + Module module{online_base, dbghelp.load_pdb(path)}; + const auto offline_base = module.get_offline_base(); - Symbol Repo::symbol_from_buffer(const Module& module, const SymbolInfo& raw) - { - return {module.translate_offline_address(raw.get_offline_address()), raw}; - } + if (offline_bases.find(offline_base) != offline_bases.cend()) + throw std::runtime_error{offline_base_already_used(offline_base)}; - Address Repo::address_online_to_offline(Address online) const - { - return module_from_online_address(online) - .translate_online_address(online); - } + file_ids.emplace(std::move(file_id)); + const auto it = online_bases.emplace(online_base, std::move(module)); + offline_bases.emplace(offline_base, it.first->second); - Address Repo::address_offline_to_online(Address offline) const - { - return module_from_offline_address(offline) - .translate_offline_address(offline); - } + return offline_base; +} - const Module& Repo::module_from_online_address(Address online) const - { - return guess_module(online_bases, online); - } +void Repo::enum_symbols(const OnSymbol& callback) const { + for (const auto& it : offline_bases) + enum_symbols(it.second, callback); +} - const Module& Repo::module_from_offline_address(Address offline) const - { - return guess_module(offline_bases, offline); - } +void Repo::enum_symbols(Address offline_base, const OnSymbol& callback) const { + const auto it = offline_bases.find(offline_base); + if (it == offline_bases.cend()) + throw std::runtime_error{"unknown module"}; + enum_symbols(it->second, callback); } + +void Repo::enum_symbols(const Module& module, const OnSymbol& callback) const { + dbghelp.enum_symbols(module, + [&](const SymbolInfo& raw) { callback(symbol_from_buffer(module, raw)); }); +} + +Symbol Repo::resolve_symbol(Address online) const { + return symbol_from_buffer(dbghelp.resolve_symbol(address_online_to_offline(online))); +} + +Symbol Repo::resolve_symbol(const std::string& name) const { + return symbol_from_buffer(dbghelp.resolve_symbol(name)); +} + +LineInfo Repo::resolve_line(Address online) const { + return dbghelp.resolve_line(address_online_to_offline(online)); +} + +const Module& Repo::module_with_online_base(Address base) const { + return lookup_module(online_bases, base); +} + +const Module& Repo::module_with_offline_base(Address base) const { + return lookup_module(offline_bases, base); +} + +Symbol Repo::symbol_from_buffer(const SymbolInfo& raw) const { + return symbol_from_buffer(module_with_offline_base(raw.get_offline_base()), raw); +} + +Symbol Repo::symbol_from_buffer(const Module& module, const SymbolInfo& raw) { + return {module.translate_offline_address(raw.get_offline_address()), raw}; +} + +Address Repo::address_online_to_offline(Address online) const { + return module_from_online_address(online).translate_online_address(online); +} + +Address Repo::address_offline_to_online(Address offline) const { + return module_from_offline_address(offline).translate_offline_address(offline); +} + +const Module& Repo::module_from_online_address(Address online) const { + return guess_module(online_bases, online); +} + +const Module& Repo::module_from_offline_address(Address offline) const { + return guess_module(offline_bases, offline); +} + +} // namespace pdb diff --git a/src/utils/file.cpp b/src/utils/file.cpp index c0bb4bd..c25307a 100644 --- a/src/utils/file.cpp +++ b/src/utils/file.cpp @@ -5,70 +5,60 @@ #include "pdb/all.hpp" -#include <safeint.h> - #include <Windows.h> +#include <safeint.h> #include <cstddef> - #include <stdexcept> #include <string> -namespace pdb -{ - namespace file - { - std::size_t get_size(const std::string& path) - { - const Handle handle{CreateFileA( - path.c_str(), - FILE_READ_ATTRIBUTES, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL)}; - - if (handle.get() == INVALID_HANDLE_VALUE) - throw error::windows(GetLastError()); - - LARGE_INTEGER size; - - if (!GetFileSizeEx(handle.get(), &size)) - throw error::windows(GetLastError()); - - std::size_t result = 0; - - if (!msl::utilities::SafeCast(size.QuadPart, result)) - throw std::runtime_error{"invalid file size"}; - - return result; - } - - ID query_id(const std::string& path) - { - const Handle handle{CreateFileA( - path.c_str(), - FILE_READ_ATTRIBUTES, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL)}; - - if (handle.get() == INVALID_HANDLE_VALUE) - throw error::windows(GetLastError()); - - FILE_ID_INFO id; - - if (!GetFileInformationByHandleEx( - handle.get(), - FileIdInfo, - &id, - sizeof(id))) - throw error::windows(GetLastError()); - - return {id}; - } - } +namespace pdb { +namespace file { + +std::size_t get_size(const std::string& path) { + const Handle handle{CreateFileA(path.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL)}; + + if (handle.get() == INVALID_HANDLE_VALUE) + throw error::windows(GetLastError()); + + LARGE_INTEGER size; + + if (!GetFileSizeEx(handle.get(), &size)) + throw error::windows(GetLastError()); + + std::size_t result = 0; + + if (!msl::utilities::SafeCast(size.QuadPart, result)) + throw std::runtime_error{"invalid file size"}; + + return result; } + +ID query_id(const std::string& path) { + const Handle handle{CreateFileA(path.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL)}; + + if (handle.get() == INVALID_HANDLE_VALUE) + throw error::windows(GetLastError()); + + FILE_ID_INFO id; + + if (!GetFileInformationByHandleEx(handle.get(), FileIdInfo, &id, sizeof(id))) + throw error::windows(GetLastError()); + + return {id}; +} + +} // namespace file +} // namespace pdb diff --git a/utils/addr2name.cpp b/utils/addr2name.cpp index 87206f2..fe749b8 100644 --- a/utils/addr2name.cpp +++ b/utils/addr2name.cpp @@ -4,9 +4,8 @@ // Distributed under the MIT License. #include "command_line.hpp" -#include "pdb_descr.hpp" - #include "pdb/all.hpp" +#include "pdb_descr.hpp" #pragma warning(push, 0) #include <boost/program_options.hpp> @@ -18,113 +17,89 @@ #include <string> #include <vector> -namespace -{ - class Addr2Name : public SettingsParser - { - public: - explicit Addr2Name(const std::string& argv0) - : SettingsParser{argv0} - { - visible.add_options() - ("pdb", - boost::program_options::value<std::vector<PDB>>(&pdbs) - ->value_name("ADDR,PATH"), - "load a PDB file") - ("lines,l", - boost::program_options::bool_switch(&lines), - "try to resolve source files & line numbers"); - hidden.add_options() - ("address", - boost::program_options::value<std::vector<pdb::Address>>(&addresses) - ->value_name("ADDR"), - "add an address to resolve"); - positional.add("address", -1); - } - - const char* get_short_description() const override - { - return "[-h|--help] [--pdb ADDR,PATH]... [--] [ADDR]..."; - } - - std::vector<PDB> pdbs; - std::vector<pdb::Address> addresses; - bool lines = false; - }; - - std::string format_symbol(const pdb::Module& module, const pdb::Symbol& symbol) - { - std::ostringstream oss; - oss << module.get_name() << '!' << symbol.get_name(); - const auto displacement = symbol.get_displacement(); - if (displacement) - oss << '+' << pdb::format_address(displacement); - return oss.str(); +namespace { + +class Addr2Name : public SettingsParser { +public: + explicit Addr2Name(const std::string& argv0) : SettingsParser{argv0} { + namespace po = boost::program_options; + + visible.add_options()( + "pdb", po::value<std::vector<PDB>>(&pdbs)->value_name("ADDR,PATH"), "load a PDB file"); + visible.add_options()( + "lines,l", po::bool_switch(&lines), "try to resolve source files & line numbers"); + hidden.add_options()("address", + po::value<std::vector<pdb::Address>>(&addresses)->value_name("ADDR"), + "add an address to resolve"); + positional.add("address", -1); } - std::string format_line_info(const pdb::LineInfo& line_info) - { - std::ostringstream oss; - oss << '[' << line_info.file_path << " @ " << line_info.line_number << ']'; - return oss.str(); + const char* get_short_description() const override { + return "[-h|--help] [--pdb ADDR,PATH]... [--] [ADDR]..."; } - void dump_error(const std::exception& e) - { - std::cerr << "error: " << e.what() << '\n'; - } + std::vector<PDB> pdbs; + std::vector<pdb::Address> addresses; + bool lines = false; +}; + +std::string format_symbol(const pdb::Module& module, const pdb::Symbol& symbol) { + std::ostringstream oss; + oss << module.get_name() << '!' << symbol.get_name(); + const auto displacement = symbol.get_displacement(); + if (displacement) + oss << '+' << pdb::format_address(displacement); + return oss.str(); +} - void resolve_symbol(const pdb::Repo& repo, pdb::Address address, bool lines = false) - { - try - { - const auto symbol = repo.resolve_symbol(address); - const auto& module = repo.module_with_offline_base(symbol.get_offline_base()); - - std::ostringstream msg; - msg << format_symbol(module, symbol); - - if (lines) - { - try - { - const auto line_info = repo.resolve_line(address); - msg << ' ' << format_line_info(line_info); - } - catch (const std::exception& e) - { - dump_error(e); - } - } +std::string format_line_info(const pdb::LineInfo& line_info) { + std::ostringstream oss; + oss << '[' << line_info.file_path << " @ " << line_info.line_number << ']'; + return oss.str(); +} - std::cout << msg.str() << '\n'; - } - catch (const std::exception& e) - { - dump_error(e); - std::cout << pdb::format_address(address) << '\n'; +void dump_error(const std::exception& e) { + std::cerr << "error: " << e.what() << '\n'; +} + +void resolve_symbol(const pdb::Repo& repo, pdb::Address address, bool lines = false) { + try { + const auto symbol = repo.resolve_symbol(address); + const auto& module = repo.module_with_offline_base(symbol.get_offline_base()); + + std::ostringstream msg; + msg << format_symbol(module, symbol); + + if (lines) { + try { + const auto line_info = repo.resolve_line(address); + msg << ' ' << format_line_info(line_info); + } catch (const std::exception& e) { + dump_error(e); + } } + + std::cout << msg.str() << '\n'; + } catch (const std::exception& e) { + dump_error(e); + std::cout << pdb::format_address(address) << '\n'; } } -int main(int argc, char* argv[]) -{ - try - { +} // namespace + +int main(int argc, char* argv[]) { + try { Addr2Name settings{argv[0]}; - try - { + try { settings.parse(argc, argv); - } - catch (const boost::program_options::error& e) - { + } catch (const boost::program_options::error& e) { settings.usage_error(e); return 1; } - if (settings.exit_with_usage) - { + if (settings.exit_with_usage) { settings.usage(); return 0; } @@ -136,9 +111,7 @@ int main(int argc, char* argv[]) for (const auto& address : settings.addresses) resolve_symbol(repo, address, settings.lines); - } - catch (const std::exception& e) - { + } catch (const std::exception& e) { dump_error(e); return 1; } diff --git a/utils/command_line.hpp b/utils/command_line.hpp index 352c210..c991e4a 100644 --- a/utils/command_line.hpp +++ b/utils/command_line.hpp @@ -15,35 +15,25 @@ #include <ostream> #include <string> -class SettingsParser -{ +class SettingsParser { public: - explicit SettingsParser(const std::string& argv0) - : prog_name{extract_filename(argv0)} - { - visible.add_options() - ("help,h", - "show this message and exit"); + explicit SettingsParser(const std::string& argv0) : prog_name{extract_filename(argv0)} { + visible.add_options()("help,h", "show this message and exit"); } virtual ~SettingsParser() = default; - virtual const char* get_short_description() const - { - return "[--option VALUE]..."; - } + virtual const char* get_short_description() const { return "[--option VALUE]..."; } - virtual void parse(int argc, char* argv[]) - { + virtual void parse(int argc, char* argv[]) { boost::program_options::options_description all; all.add(hidden).add(visible); boost::program_options::variables_map vm; - boost::program_options::store( - boost::program_options::command_line_parser{argc, argv} - .options(all) - .positional(positional) - .run(), - vm); + boost::program_options::store(boost::program_options::command_line_parser{argc, argv} + .options(all) + .positional(positional) + .run(), + vm); if (vm.count("help")) exit_with_usage = true; else @@ -52,13 +42,9 @@ public: bool exit_with_usage = false; - void usage() const - { - std::cout << *this; - } + void usage() const { std::cout << *this; } - void usage_error(const std::exception& e) const - { + void usage_error(const std::exception& e) const { std::cerr << "usage error: " << e.what() << '\n'; std::cerr << *this; } @@ -69,15 +55,13 @@ protected: boost::program_options::positional_options_description positional; private: - static std::string extract_filename(const std::string& path) - { + static std::string extract_filename(const std::string& path) { return boost::filesystem::path{path}.filename().string(); } const std::string prog_name; - friend std::ostream& operator<<(std::ostream& os, const SettingsParser& parser) - { + friend std::ostream& operator<<(std::ostream& os, const SettingsParser& parser) { const auto short_descr = parser.get_short_description(); os << "usage: " << parser.prog_name << ' ' << short_descr << '\n'; os << parser.visible; diff --git a/utils/enum_symbols.cpp b/utils/enum_symbols.cpp index 8fa0960..0759dd6 100644 --- a/utils/enum_symbols.cpp +++ b/utils/enum_symbols.cpp @@ -4,9 +4,8 @@ // Distributed under the MIT License. #include "command_line.hpp" -#include "pdb_descr.hpp" - #include "pdb/all.hpp" +#include "pdb_descr.hpp" #pragma warning(push, 0) #include <boost/program_options.hpp> @@ -17,88 +16,67 @@ #include <string> #include <vector> -namespace -{ - class EnumSymbols : public SettingsParser - { - public: - explicit EnumSymbols(const std::string& argv0) - : SettingsParser{argv0} - { - visible.add_options() - ("pdb", - boost::program_options::value<std::vector<PDB>>(&pdbs) - ->value_name("ADDR,PATH"), - "load a PDB file") - ("functions", - boost::program_options::value<pdb::Symbol::Tag>(&tag) - ->implicit_value(function_tag) - ->zero_tokens(), - "only list functions"); - } +namespace { - const char* get_short_description() const override - { - return "[-h|--help] [--pdb ADDR,PATH]... [--functions]"; - } +class EnumSymbols : public SettingsParser { +public: + explicit EnumSymbols(const std::string& argv0) : SettingsParser{argv0} { + namespace po = boost::program_options; - std::vector<PDB> pdbs; + visible.add_options()( + "pdb", po::value<std::vector<PDB>>(&pdbs)->value_name("ADDR,PATH"), "load a PDB file"); + visible.add_options()( + "functions", + po::value<pdb::Symbol::Tag>(&tag)->implicit_value(function_tag)->zero_tokens(), + "only list functions"); + } - bool type_specified() const - { - return tag != reserved_tag; - } + const char* get_short_description() const override { + return "[-h|--help] [--pdb ADDR,PATH]... [--functions]"; + } - pdb::Symbol::Type get_type() const - { - return static_cast<pdb::Symbol::Type>(tag); - } + std::vector<PDB> pdbs; - private: - static const auto reserved_tag = static_cast<pdb::Symbol::Tag>(pdb::Symbol::Type::RESERVED); - static const auto function_tag = static_cast<pdb::Symbol::Tag>(pdb::Symbol::Type::Function); + bool type_specified() const { return tag != reserved_tag; } - pdb::Symbol::Tag tag = reserved_tag; - }; -} + pdb::Symbol::Type get_type() const { return static_cast<pdb::Symbol::Type>(tag); } + +private: + static const auto reserved_tag = static_cast<pdb::Symbol::Tag>(pdb::Symbol::Type::RESERVED); + static const auto function_tag = static_cast<pdb::Symbol::Tag>(pdb::Symbol::Type::Function); + + pdb::Symbol::Tag tag = reserved_tag; +}; -int main(int argc, char* argv[]) -{ - try - { +} // namespace + +int main(int argc, char* argv[]) { + try { EnumSymbols settings{argv[0]}; - try - { + try { settings.parse(argc, argv); - } - catch (const boost::program_options::error& e) - { + } catch (const boost::program_options::error& e) { settings.usage_error(e); return 1; } - if (settings.exit_with_usage) - { + if (settings.exit_with_usage) { settings.usage(); return 0; } pdb::Repo repo; - for (const auto& pdb : settings.pdbs) - { + for (const auto& pdb : settings.pdbs) { const auto id = repo.add_pdb(pdb.online_base, pdb.path); - repo.enum_symbols(id, [&] (const pdb::Symbol& symbol) - { + repo.enum_symbols(id, [&](const pdb::Symbol& symbol) { if (!settings.type_specified() || settings.get_type() == symbol.get_type()) std::cout << symbol.get_name() << '\n'; }); } - } - catch (const std::exception& e) - { + } catch (const std::exception& e) { std::cerr << "error: " << e.what() << '\n'; return 1; } diff --git a/utils/name2addr.cpp b/utils/name2addr.cpp index 22c637b..f5b3b26 100644 --- a/utils/name2addr.cpp +++ b/utils/name2addr.cpp @@ -4,9 +4,8 @@ // Distributed under the MIT License. #include "command_line.hpp" -#include "pdb_descr.hpp" - #include "pdb/all.hpp" +#include "pdb_descr.hpp" #pragma warning(push, 0) #include <boost/program_options.hpp> @@ -17,74 +16,57 @@ #include <string> #include <vector> -namespace -{ - class Name2Addr : public SettingsParser - { - public: - explicit Name2Addr(const std::string& argv0) - : SettingsParser{argv0} - { - visible.add_options() - ("pdb", - boost::program_options::value<std::vector<PDB>>(&pdbs) - ->value_name("ADDR,PATH"), - "load a PDB file"); - hidden.add_options() - ("name", - boost::program_options::value<std::vector<std::string>>(&names) - ->value_name("NAME"), - "add a name to resolve"); - positional.add("name", -1); - } +namespace { - const char* get_short_description() const override - { - return "[-h|--help] [--pdb ADDR,PATH]... [--] [NAME]..."; - } +class Name2Addr : public SettingsParser { +public: + explicit Name2Addr(const std::string& argv0) : SettingsParser{argv0} { + namespace po = boost::program_options; - std::vector<PDB> pdbs; - std::vector<std::string> names; - }; + visible.add_options()( + "pdb", po::value<std::vector<PDB>>(&pdbs)->value_name("ADDR,PATH"), "load a PDB file"); + hidden.add_options()("name", + po::value<std::vector<std::string>>(&names)->value_name("NAME"), + "add a name to resolve"); + positional.add("name", -1); + } - void dump_error(const std::exception& e) - { - std::cerr << "error: " << e.what() << '\n'; + const char* get_short_description() const override { + return "[-h|--help] [--pdb ADDR,PATH]... [--] [NAME]..."; } - void resolve_symbol(const pdb::Repo& repo, const std::string& name) - { - try - { - const auto address = repo.resolve_symbol(name).get_online_address(); - std::cout << pdb::format_address(address) << '\n'; - } - catch (const std::exception& e) - { - dump_error(e); - std::cout << name << '\n'; - } + std::vector<PDB> pdbs; + std::vector<std::string> names; +}; + +void dump_error(const std::exception& e) { + std::cerr << "error: " << e.what() << '\n'; +} + +void resolve_symbol(const pdb::Repo& repo, const std::string& name) { + try { + const auto address = repo.resolve_symbol(name).get_online_address(); + std::cout << pdb::format_address(address) << '\n'; + } catch (const std::exception& e) { + dump_error(e); + std::cout << name << '\n'; } } -int main(int argc, char* argv[]) -{ - try - { +} // namespace + +int main(int argc, char* argv[]) { + try { Name2Addr settings{argv[0]}; - try - { + try { settings.parse(argc, argv); - } - catch (const boost::program_options::error& e) - { + } catch (const boost::program_options::error& e) { settings.usage_error(e); return 1; } - if (settings.exit_with_usage) - { + if (settings.exit_with_usage) { settings.usage(); return 0; } @@ -96,9 +78,7 @@ int main(int argc, char* argv[]) for (const auto& name : settings.names) resolve_symbol(repo, name); - } - catch (const std::exception& e) - { + } catch (const std::exception& e) { dump_error(e); return 1; } diff --git a/utils/pdb_descr.hpp b/utils/pdb_descr.hpp index cde815a..f2e6f38 100644 --- a/utils/pdb_descr.hpp +++ b/utils/pdb_descr.hpp @@ -15,13 +15,11 @@ #include <string> #include <vector> -struct PDB -{ +struct PDB { pdb::Address online_base; std::string path; - static PDB parse(std::string src) - { + static PDB parse(std::string src) { static constexpr auto sep = ','; const auto sep_pos = src.find(sep); @@ -35,8 +33,7 @@ struct PDB return {online_base, src.substr(sep_pos + 1)}; } - static pdb::Address parse_address(const std::string& src) - { + static pdb::Address parse_address(const std::string& src) { pdb::Address dest; if (!pdb::parse_address(dest, src)) boost::throw_exception(boost::program_options::invalid_option_value{src}); @@ -44,32 +41,28 @@ struct PDB } }; -namespace boost -{ - namespace program_options - { - template <typename charT> - void validate( - boost::any& dest, - const std::vector<std::basic_string<charT>>& src_tokens, - PDB*, - int) - { - validators::check_first_occurrence(dest); - const auto& src_token = validators::get_single_string(src_tokens); - dest = any{PDB::parse(src_token)}; - } +namespace boost { +namespace program_options { - template <typename charT> - void validate( - boost::any& dest, - const std::vector<std::basic_string<charT>>& src_tokens, - pdb::Address*, - int) - { - validators::check_first_occurrence(dest); - const auto& src_token = validators::get_single_string(src_tokens); - dest = any{PDB::parse_address(src_token)}; - } - } +template <typename charT> +void validate(boost::any& dest, + const std::vector<std::basic_string<charT>>& src_tokens, + PDB*, + int) { + validators::check_first_occurrence(dest); + const auto& src_token = validators::get_single_string(src_tokens); + dest = any{PDB::parse(src_token)}; +} + +template <typename charT> +void validate(boost::any& dest, + const std::vector<std::basic_string<charT>>& src_tokens, + pdb::Address*, + int) { + validators::check_first_occurrence(dest); + const auto& src_token = validators::get_single_string(src_tokens); + dest = any{PDB::parse_address(src_token)}; } + +} // namespace program_options +} // namespace boost |