diff options
author | Egor Tensin <Egor.Tensin@gmail.com> | 2017-05-20 02:47:57 +0300 |
---|---|---|
committer | Egor Tensin <Egor.Tensin@gmail.com> | 2017-05-20 02:47:57 +0300 |
commit | f4f39e74fae3c8b8d8fdb2f560e8a50777b6de1d (patch) | |
tree | a15a2c289e6d0f5fa8ccb2d71b1c4af24f0bd4b9 | |
parent | don't load multiple PDBs with the same base (diff) | |
download | winapi-debug-f4f39e74fae3c8b8d8fdb2f560e8a50777b6de1d.tar.gz winapi-debug-f4f39e74fae3c8b8d8fdb2f560e8a50777b6de1d.zip |
don't load the same PDB twice
-rw-r--r-- | include/pdb/repo.hpp | 4 | ||||
-rw-r--r-- | include/pdb/utils/file.hpp | 30 | ||||
-rw-r--r-- | src/repo.cpp | 21 | ||||
-rw-r--r-- | src/utils/file.cpp | 26 |
4 files changed, 77 insertions, 4 deletions
diff --git a/include/pdb/repo.hpp b/include/pdb/repo.hpp index 239bd7e..aa5c3c3 100644 --- a/include/pdb/repo.hpp +++ b/include/pdb/repo.hpp @@ -9,10 +9,12 @@ #include "dbghelp.hpp" #include "module.hpp" #include "symbol.hpp" +#include "utils/file.hpp" #include <functional> #include <map> #include <string> +#include <unordered_set> namespace pdb { @@ -45,5 +47,7 @@ namespace pdb std::map<Address, Module> online_modules; std::map<Address, const Module&> offline_modules; + + std::unordered_set<file::ID> module_ids; }; } diff --git a/include/pdb/utils/file.hpp b/include/pdb/utils/file.hpp index 5b83f2b..50975aa 100644 --- a/include/pdb/utils/file.hpp +++ b/include/pdb/utils/file.hpp @@ -5,14 +5,44 @@ #pragma once +#include <Windows.h> + #include <cstddef> +#include <cstring> +#include <functional> #include <string> +#include <type_traits> namespace pdb { namespace file { std::size_t get_size(const std::string&); + + struct ID + { + const FILE_ID_INFO raw; + + bool operator==(const ID& other) const + { + static_assert(std::is_pod<FILE_ID_INFO>::value, "Can't memcmp if file IDs aren't PODs"); + return 0 == std::memcmp(&raw, &other.raw, sizeof(FILE_ID_INFO)); + } + }; + + ID query_id(const std::string&); } } + +namespace std +{ + template <> + struct hash<pdb::file::ID> + { + std::size_t operator()(const pdb::file::ID& id) const + { + return _Bitwise_hash<FILE_ID_INFO>{}(id.raw); + } + }; +} diff --git a/src/repo.cpp b/src/repo.cpp index 9a06481..02ca1db 100644 --- a/src/repo.cpp +++ b/src/repo.cpp @@ -6,6 +6,7 @@ #include "pdb/all.hpp" #include <map> +#include <sstream> #include <stdexcept> #include <string> #include <utility> @@ -41,11 +42,18 @@ namespace pdb return it->second; } - std::string pdb_already_loaded(Address online_base) + std::string pdb_already_loaded(Address online_base, const std::string& path) { std::ostringstream oss; - oss << "module with online base address " << format_address - << " has already been loaded"; + 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(); } } @@ -53,13 +61,18 @@ namespace pdb Address Repo::add_pdb(Address online_base, const std::string& path) { if (online_modules.find(online_base) != online_modules.cend()) - throw std::runtime_error{pdb_already_loaded(online_base)}; + throw std::runtime_error{pdb_already_loaded(online_base, path)}; + + auto file_id = file::query_id(path); + if (module_ids.find(file_id) != module_ids.cend()) + throw std::runtime_error{pdb_already_loaded(path)}; Module module{online_base, dbghelp.load_pdb(path)}; const auto offline_base = module.get_offline_base(); const auto it = online_modules.emplace(online_base, std::move(module)); offline_modules.emplace(offline_base, it.first->second); + module_ids.emplace(std::move(file_id)); return offline_base; } diff --git a/src/utils/file.cpp b/src/utils/file.cpp index f013d90..dba8a38 100644 --- a/src/utils/file.cpp +++ b/src/utils/file.cpp @@ -44,5 +44,31 @@ namespace pdb 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()); + + ID id; + + if (!GetFileInformationByHandleEx( + handle.get(), + FileIdInfo, + &id, + sizeof(id))) + throw error::windows(GetLastError()); + + return id; + } } } |