Showing the changes to src/vm/tool_dispatch.cpp (1 of 11 files). Show all
Unified · Split
| @@ -7,6 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | #include <cassert> |
| 8 | 8 | #include <vector> |
| 9 | 9 | #include <debug.h> |
| 10 | +#include <disvm.h> | |
| 10 | 11 | #include <vm_tools.h> |
| 11 | 12 | #include <exceptions.h> |
| 12 | 13 | #include <utils.h> |
| @@ -21,7 +22,9 @@ vm_tool_t::~vm_tool_t() · 8 unmodified lines | ||
| 21 | 22 | } |
| 22 | 23 | |
| 23 | 24 | vm_tool_dispatch_t::vm_tool_dispatch_t(vm_t &vm) |
| 24 | − : _vm{ vm } | |
| 25 | + : _threads_suspended{ false } | |
| 26 | + , _threads_suspended_count{ 0 } | |
| 27 | + , _vm { vm } | |
| 25 | 28 | { |
| 26 | 29 | _events.cookie_counter = 1; |
| 27 | 30 | _breakpoints.cookie_counter = 1; |
| @@ -161,6 +164,25 @@ void vm_tool_dispatch_t::on_thread_end(vm_thread_t &t) · 133 unmodified lines | ||
| 161 | 164 | _events.fire_event_callbacks(vm_event_t::thread_end, cxt); |
| 162 | 165 | } |
| 163 | 166 | |
| 167 | +void vm_tool_dispatch_t::on_thread_broken(vm_thread_t &) | |
| 168 | +{ | |
| 169 | +} | |
| 170 | + | |
| 171 | +void vm_tool_dispatch_t::block_if_thread_suspended(uint32_t thread_id) | |
| 172 | +{ | |
| 173 | + if (!_threads_suspended) | |
| 174 | + return; | |
| 175 | + | |
| 176 | + std::unique_lock<std::mutex> resume_lock{ _threads_resume_lock }; | |
| 177 | + | |
| 178 | + _threads_suspended_count++; | |
| 179 | + | |
| 180 | + while (_threads_suspended) | |
| 181 | + _threads_resume.wait(resume_lock); | |
| 182 | + | |
| 183 | + _threads_suspended_count--; | |
| 184 | +} | |
| 185 | + | |
| 164 | 186 | vm_t& vm_tool_dispatch_t::get_vm_instance() const |
| 165 | 187 | { |
| 166 | 188 | return _vm; |
| @@ -171,7 +193,7 @@ cookie_t vm_tool_dispatch_t::subscribe_event(vm_event_t evt, vm_event_callback_t · 4 unmodified lines | ||
| 171 | 193 | if (!cb) |
| 172 | 194 | throw vm_system_exception{ "Invalid callback for event" }; |
| 173 | 195 | |
| 174 | − std::lock_guard<std::mutex> lock{ _events.lock }; | |
| 196 | + std::lock_guard<std::mutex> lock{ _events.event_lock }; | |
| 175 | 197 | |
| 176 | 198 | const auto cookie_id = _events.cookie_counter++; |
| 177 | 199 | |
| @@ -190,7 +212,7 @@ cookie_t vm_tool_dispatch_t::subscribe_event(vm_event_t evt, vm_event_callback_t · 12 unmodified lines | ||
| 190 | 212 | |
| 191 | 213 | void vm_tool_dispatch_t::unsubscribe_event(cookie_t cookie_id) |
| 192 | 214 | { |
| 193 | − std::lock_guard<std::mutex> lock{ _events.lock }; | |
| 215 | + std::lock_guard<std::mutex> lock{ _events.event_lock }; | |
| 194 | 216 | |
| 195 | 217 | auto iter = _events.cookie_to_event.find(cookie_id); |
| 196 | 218 | if (iter == _events.cookie_to_event.cend()) |
| @@ -292,6 +314,46 @@ void vm_tool_dispatch_t::clear_breakpoint(cookie_t cookie_id) · 95 unmodified lines | ||
| 292 | 314 | _breakpoints.cookie_to_details.erase(iter_cookie); |
| 293 | 315 | } |
| 294 | 316 | |
| 317 | +void vm_tool_dispatch_t::suspend_all_threads() | |
| 318 | +{ | |
| 319 | + std::lock(_threads_suspend_lock, _threads_resume_lock); | |
| 320 | + std::lock_guard<std::mutex> suspend_lock{ _threads_suspend_lock, std::adopt_lock }; | |
| 321 | + std::lock_guard<std::mutex> resume_lock{ _threads_resume_lock, std::adopt_lock }; | |
| 322 | + | |
| 323 | + _threads_suspended = true; | |
| 324 | + | |
| 325 | + const auto &sched = _vm.get_scheduler_control(); | |
| 326 | + | |
| 327 | + auto current = _threads_suspended_count.load(); | |
| 328 | + auto max = static_cast<uint32_t>(sched.get_runnable_threads().size()); | |
| 329 | + | |
| 330 | + // Sleep and check until we determine all threads have been suspended | |
| 331 | + // Minus 1 to exclude the current thread. | |
| 332 | + while (max != 0 && current < (max - 1)) | |
| 333 | + { | |
| 334 | + std::this_thread::sleep_for(std::chrono::milliseconds{ 20 }); | |
| 335 | + current = _threads_suspended_count.load(); | |
| 336 | + max = static_cast<uint32_t>(sched.get_runnable_threads().size()); | |
| 337 | + } | |
| 338 | + | |
| 339 | + // If the current count is ever equal to the max, then a non vm thread is | |
| 340 | + // inside the tool dispatcher which may be okay, but it indicates a type of | |
| 341 | + // non-invasive debugging that was not originally incorporated into this | |
| 342 | + // dispatcher design. | |
| 343 | + assert(max == 0 || current < max); | |
| 344 | +} | |
| 345 | + | |
| 346 | +void vm_tool_dispatch_t::resume_all_threads() | |
| 347 | +{ | |
| 348 | + std::lock(_threads_suspend_lock, _threads_resume_lock); | |
| 349 | + std::lock_guard<std::mutex> suspend_lock{ _threads_suspend_lock, std::adopt_lock }; | |
| 350 | + | |
| 351 | + _threads_suspended = false; | |
| 352 | + | |
| 353 | + _threads_resume_lock.unlock(); | |
| 354 | + _threads_resume.notify_all(); | |
| 355 | +} | |
| 356 | + | |
| 295 | 357 | std::tuple<opcode_t, cookie_t> vm_tool_dispatch_t::get_original_opcode_and_cookie(const vm_registers_t &r) |
| 296 | 358 | { |
| 297 | 359 | const auto module = r.module_ref->module.get(); |
| @@ -320,7 +382,7 @@ void vm_tool_dispatch_t::events_t::fire_event_callbacks(vm_event_t event_type, v · 22 unmodified lines | ||
| 320 | 382 | auto event_callbacks = std::vector<vm_event_callback_t>{}; |
| 321 | 383 | |
| 322 | 384 | { |
| 323 | − std::lock_guard<std::mutex> lock_local{ lock }; | |
| 385 | + std::lock_guard<std::mutex> lock_local{ event_lock }; | |
| 324 | 386 | |
| 325 | 387 | auto &event_callbacks_tmp = callbacks[event_type]; |
| 326 | 388 | for (auto &c : event_callbacks_tmp) |