From eaf76a222e709f81e9d7c71b6c47ee172604af05 Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Tue, 24 Mar 2020 00:43:34 +0300 Subject: add Process class It's intended to be used for the future dump writing functionality, to generate a meaningful file name, etc. Also, add Boost.Nowide, which provides handy UTF-8 conversion functions. I'm not sure about this, but things indicate that it's about to be included in Boost. --- .gitmodules | 3 ++ 3rdparty/boost/nowide | 1 + CMakeLists.txt | 7 +-- include/pdb/all.hpp | 1 + include/pdb/process.hpp | 32 +++++++++++++ src/process.cpp | 120 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 161 insertions(+), 3 deletions(-) create mode 160000 3rdparty/boost/nowide create mode 100644 include/pdb/process.hpp create mode 100644 src/process.cpp diff --git a/.gitmodules b/.gitmodules index 26c71b0..495304d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "3rdparty/microsoft/SafeInt"] path = 3rdparty/microsoft/SafeInt url = https://github.com/dcleblanc/SafeInt.git +[submodule "3rdparty/boost/nowide"] + path = 3rdparty/boost/nowide + url = https://github.com/boostorg/nowide.git diff --git a/3rdparty/boost/nowide b/3rdparty/boost/nowide new file mode 160000 index 0000000..7cf83cf --- /dev/null +++ b/3rdparty/boost/nowide @@ -0,0 +1 @@ +Subproject commit 7cf83cf3fcaaf0ee496300d8814fa03f627365e0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 8af82e9..5ad6d0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,9 +2,10 @@ cmake_minimum_required(VERSION 3.5) # for Boost::* imported targets project(pdb_repo CXX) -include(cmake/cmake/common.cmake) - find_package(Boost REQUIRED) +add_subdirectory(3rdparty/boost/nowide) + +include(cmake/cmake/common.cmake) file(GLOB_RECURSE pdb_repo_include "include/*.hpp") file(GLOB_RECURSE pdb_repo_src "src/*.cpp") @@ -12,7 +13,7 @@ add_library(pdb_repo ${pdb_repo_include} ${pdb_repo_src}) target_compile_definitions(pdb_repo PUBLIC _NO_CVCONST_H) target_include_directories(pdb_repo PUBLIC include/) target_include_directories(pdb_repo SYSTEM PUBLIC 3rdparty/microsoft/SafeInt) -target_link_libraries(pdb_repo PUBLIC Boost::boost) +target_link_libraries(pdb_repo PUBLIC Boost::boost PRIVATE Boost::nowide) target_link_libraries(pdb_repo PRIVATE dbghelp) if(MINGW) diff --git a/include/pdb/all.hpp b/include/pdb/all.hpp index 36a68d3..0794362 100644 --- a/include/pdb/all.hpp +++ b/include/pdb/all.hpp @@ -11,6 +11,7 @@ #include "error.hpp" #include "handle.hpp" #include "module.hpp" +#include "process.hpp" #include "repo.hpp" #include "symbol.hpp" #include "utils/file.hpp" diff --git a/include/pdb/process.hpp b/include/pdb/process.hpp new file mode 100644 index 0000000..3ddb6b4 --- /dev/null +++ b/include/pdb/process.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include "handle.hpp" + +#include + +#include + +namespace pdb { + +class Process { +public: + using ID = DWORD; + + static Process current(); + static Process open(ID); + + ID get_id() const { return id; } + + const Handle& get_handle() const { return handle; } + + std::string get_executable_path() const; + +private: + explicit Process(Handle&&); + Process(ID, Handle&&); + + ID id; + Handle handle; +}; + +} // namespace pdb diff --git a/src/process.cpp b/src/process.cpp new file mode 100644 index 0000000..c2a32f4 --- /dev/null +++ b/src/process.cpp @@ -0,0 +1,120 @@ +#include "pdb/all.hpp" + +#include + +#include + +#include + +#include +#include +#include +#include + +namespace pdb { +namespace { + +// Permissions required for MiniDumpWriteDump. +constexpr DWORD permissions = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; + +Handle open_process(DWORD id) { + Handle process{OpenProcess(permissions, FALSE, id)}; + if (!process) { + throw error::windows(GetLastError()); + } + return process; +} + +class PathBuffer { +public: + PathBuffer() : size{min_size} { data.resize(size); } + + DWORD get_size() const { return size; } + + wchar_t* get_data() { return data.data(); } + + void grow() { + if (size < min_size) { + size = min_size; + } else { + if (!SafeMultiply(size, 2, size)) { + throw std::range_error{"couldn't allocate buffer sufficient for a file path"}; + } + } + data.resize(size); + } + +private: + static constexpr DWORD min_size = 256; + + DWORD size; + std::vector data; +}; + +std::string get_current_executable_path(PathBuffer& buffer) { + SetLastError(ERROR_SUCCESS); + + const auto ec = ::GetModuleFileNameW(NULL, buffer.get_data(), buffer.get_size()); + + if (ec == 0) { + throw error::windows(GetLastError()); + } + + if (ec == buffer.get_size() && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + buffer.grow(); + return get_current_executable_path(buffer); + } + + return boost::nowide::narrow(buffer.get_data()); +} + +std::string get_current_executable_path() { + PathBuffer buffer; + return get_current_executable_path(buffer); +} + +std::string get_executable_path(const Handle& process, PathBuffer& buffer) { + auto size = buffer.get_size(); + + const auto ec = ::QueryFullProcessImageNameW(process.get(), 0, buffer.get_data(), &size); + + if (ec != 0) { + return boost::nowide::narrow(buffer.get_data()); + } + + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + buffer.grow(); + return get_executable_path(process, buffer); + } + + throw error::windows(GetLastError()); +} + +std::string get_executable_path(const Handle& process) { + PathBuffer buffer; + return get_executable_path(process, buffer); +} + +} // namespace + +Process Process::current() { + return Process{::GetCurrentProcessId(), Handle{::GetCurrentProcess()}}; +} + +Process Process::open(DWORD id) { + return Process{id, open_process(id)}; +} + +Process::Process(Handle&& handle) : Process{::GetProcessId(handle.get()), std::move(handle)} {} + +Process::Process(ID id, Handle&& handle) : id{id}, handle{std::move(handle)} {} + +std::string Process::get_executable_path() const { + if (handle.get() == ::GetCurrentProcess()) { + return pdb::get_current_executable_path(); + } else { + return pdb::get_executable_path(handle); + } +} + +} // namespace pdb -- cgit v1.2.3