From 669bf73fb6abdba7e22327a1cae063eddab1da1c Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 19 Oct 2024 10:59:50 +0200 Subject: [PATCH] Basic working thread support --- src/windows-emulator/handles.hpp | 51 ++++++++++++++++++++--- src/windows-emulator/process_context.hpp | 34 +++++++++++---- src/windows-emulator/syscalls.cpp | 13 ++++-- src/windows-emulator/windows_emulator.cpp | 35 +++++++++++++++- 4 files changed, 114 insertions(+), 19 deletions(-) diff --git a/src/windows-emulator/handles.hpp b/src/windows-emulator/handles.hpp index 05f26a82..b0f7dd22 100644 --- a/src/windows-emulator/handles.hpp +++ b/src/windows-emulator/handles.hpp @@ -138,9 +138,8 @@ public: return this->store_.size(); } - bool erase(const handle_value h) + bool erase(const typename value_map::iterator& entry) { - const auto entry = this->get_iterator(h); if (entry == this->store_.end()) { return false; @@ -158,6 +157,12 @@ public: return true; } + bool erase(const handle_value h) + { + const auto entry = this->get_iterator(h); + return this->erase(entry); + } + bool erase(const handle h) { return this->erase(h.value); @@ -171,6 +176,12 @@ public: return this->erase(hh); } + bool erase(const T& value) + { + const auto entry = this->find(value); + return this->erase(entry); + } + void serialize(utils::buffer_serializer& buffer) const { buffer.write_map(this->store_); @@ -181,22 +192,50 @@ public: buffer.read_map(this->store_); } - value_map::iterator begin() + typename value_map::iterator find(const T& value) + { + auto i = this->store_.begin(); + for (; i != this->store_.end(); ++i) + { + if (&i->second == &value) + { + break; + } + } + + return i; + } + + typename value_map::const_iterator find(const T& value) const + { + auto i = this->store_.begin(); + for (; i != this->store_.end(); ++i) + { + if (&i->second == &value) + { + break; + } + } + + return i; + } + + typename value_map::iterator begin() { return this->store_.begin(); } - value_map::const_iterator begin() const + typename value_map::const_iterator begin() const { return this->store_.begin(); } - value_map::iterator end() + typename value_map::iterator end() { return this->store_.end(); } - value_map::const_iterator end() const + typename value_map::const_iterator end() const { return this->store_.end(); } diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 98c70ce6..0bd0e6e9 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -21,12 +21,31 @@ #define GDT_LIMIT 0x1000 #define GDT_ENTRY_SIZE 0x8 -struct event +struct ref_counted_object +{ + uint32_t ref_count{1}; + + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(this->ref_count); + } + + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->ref_count); + } + + static bool deleter(ref_counted_object& e) + { + return --e.ref_count == 0; + } +}; + +struct event : ref_counted_object { bool signaled{}; EVENT_TYPE type{}; std::wstring name{}; - uint32_t ref_count{0}; bool is_signaled() { @@ -45,7 +64,8 @@ struct event buffer.write(this->signaled); buffer.write(this->type); buffer.write(this->name); - buffer.write(this->ref_count); + + ref_counted_object::serialize(buffer); } void deserialize(utils::buffer_deserializer& buffer) @@ -53,12 +73,8 @@ struct event buffer.read(this->signaled); buffer.read(this->type); buffer.read(this->name); - buffer.read(this->ref_count); - } - static bool deleter(event& e) - { - return --e.ref_count == 0; + ref_counted_object::deserialize(buffer); } }; @@ -157,7 +173,7 @@ private: bool was_moved_{false}; }; -class emulator_thread +class emulator_thread : ref_counted_object { public: emulator_thread() = default; diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index e08aa44b..6b910e14 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -273,6 +273,11 @@ namespace return STATUS_SUCCESS; } + if (value.type == handle_types::thread && c.proc.threads.erase(handle)) + { + return STATUS_SUCCESS; + } + if (value.type == handle_types::event && c.proc.events.erase(handle)) { return STATUS_SUCCESS; @@ -319,7 +324,6 @@ namespace event e{}; e.type = event_type; e.signaled = initial_state != FALSE; - e.ref_count = 1; e.name = std::move(name); const auto handle = c.proc.events.store(std::move(e)); @@ -2032,10 +2036,13 @@ namespace return STATUS_WAIT_0; } - NTSTATUS handle_NtTerminateThread(const syscall_context& c, const uint64_t thread_handle, + NTSTATUS handle_NtTerminateThread(const syscall_context& c, uint64_t thread_handle, const NTSTATUS exit_status) { - auto* thread = c.proc.threads.get(thread_handle); + auto* thread = !thread_handle + ? c.proc.active_thread + : c.proc.threads.get(thread_handle); + if (!thread) { return STATUS_INVALID_HANDLE; diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index e42aa53c..0b9ddd68 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -430,6 +430,33 @@ namespace thread.setup_if_necessary(emu, context); } + void cleanup_threads(process_context& context) + { + while (true) + { + bool has_changed = false; + for (auto i = context.threads.begin(); i != context.threads.end(); ++i) + { + if (i->second.exit_status.has_value()) + { + if (&i->second == context.active_thread) + { + context.active_thread = nullptr; + } + + context.threads.erase(i); + has_changed = true; + break; + } + } + + if (!has_changed) + { + break; + } + } + } + void switch_to_thread(x64_emulator& emu, process_context& context, const handle thread_handle) { auto* thread = context.threads.get(thread_handle); @@ -443,13 +470,19 @@ namespace void switch_to_next_thread(x64_emulator& emu, process_context& context) { - bool next_thread = false; + //cleanup_threads(context); + bool next_thread = false; for (auto& thread : context.threads) { if (next_thread) { + if (thread.second.exit_status.has_value()) + { + continue; + } + switch_to_thread(emu, context, thread.second); return; }