aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorEgor Tensin <Egor.Tensin@gmail.com>2020-03-24 00:43:34 +0300
committerEgor Tensin <Egor.Tensin@gmail.com>2020-03-24 00:48:16 +0300
commiteaf76a222e709f81e9d7c71b6c47ee172604af05 (patch)
treebf2fd37b9f5e4c6805d05be219d41d75156245cc
parentTravis: incremental Docker builds (diff)
downloadwinapi-debug-eaf76a222e709f81e9d7c71b6c47ee172604af05.tar.gz
winapi-debug-eaf76a222e709f81e9d7c71b6c47ee172604af05.zip
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.
Diffstat (limited to '')
-rw-r--r--.gitmodules3
m---------3rdparty/boost/nowide0
-rw-r--r--CMakeLists.txt7
-rw-r--r--include/pdb/all.hpp1
-rw-r--r--include/pdb/process.hpp32
-rw-r--r--src/process.cpp120
6 files changed, 160 insertions, 3 deletions
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
+Subproject 7cf83cf3fcaaf0ee496300d8814fa03f627365e
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 <windows.h>
+
+#include <string>
+
+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 <boost/nowide/convert.hpp>
+
+#include <SafeInt.hpp>
+
+#include <windows.h>
+
+#include <stdexcept>
+#include <string>
+#include <utility>
+#include <vector>
+
+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<wchar_t> 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