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 | #include <cassert> | 7 | #include <cassert> |
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | #include <debug.h> | 9 | #include <debug.h> |
| 10 | #include <disvm.h> | ||
| 10 | #include <vm_tools.h> | 11 | #include <vm_tools.h> |
| 11 | #include <exceptions.h> | 12 | #include <exceptions.h> |
| 12 | #include <utils.h> | 13 | #include <utils.h> |
| @@ -21,7 +22,9 @@ vm_tool_t::~vm_tool_t() · 8 unmodified lines | |||
| 21 | } | 22 | } |
| 22 | 23 | ||
| 23 | vm_tool_dispatch_t::vm_tool_dispatch_t(vm_t &vm) | 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 | _events.cookie_counter = 1; | 29 | _events.cookie_counter = 1; |
| 27 | _breakpoints.cookie_counter = 1; | 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 | _events.fire_event_callbacks(vm_event_t::thread_end, cxt); | 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 | vm_t& vm_tool_dispatch_t::get_vm_instance() const | 186 | vm_t& vm_tool_dispatch_t::get_vm_instance() const |
| 165 | { | 187 | { |
| 166 | return _vm; | 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 | if (!cb) | 193 | if (!cb) |
| 172 | throw vm_system_exception{ "Invalid callback for event" }; | 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 | const auto cookie_id = _events.cookie_counter++; | 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 | void vm_tool_dispatch_t::unsubscribe_event(cookie_t cookie_id) | 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 | auto iter = _events.cookie_to_event.find(cookie_id); | 217 | auto iter = _events.cookie_to_event.find(cookie_id); |
| 196 | if (iter == _events.cookie_to_event.cend()) | 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 | _breakpoints.cookie_to_details.erase(iter_cookie); | 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 | std::tuple<opcode_t, cookie_t> vm_tool_dispatch_t::get_original_opcode_and_cookie(const vm_registers_t &r) | 357 | std::tuple<opcode_t, cookie_t> vm_tool_dispatch_t::get_original_opcode_and_cookie(const vm_registers_t &r) |
| 296 | { | 358 | { |
| 297 | const auto module = r.module_ref->module.get(); | 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 | auto event_callbacks = std::vector<vm_event_callback_t>{}; | 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 | auto &event_callbacks_tmp = callbacks[event_type]; | 387 | auto &event_callbacks_tmp = callbacks[event_type]; |
| 326 | for (auto &c : event_callbacks_tmp) | 388 | for (auto &c : event_callbacks_tmp) |