Showing the changes to src/vm/tool_dispatch.cpp (1 of 18 files). Show all
Unified · Split
| @@ -5,10 +5,10 @@ · 4 unmodified lines | ||
| 5 | 5 | // |
| 6 | 6 | |
| 7 | 7 | #include <cassert> |
| 8 | +#include <vector> | |
| 8 | 9 | #include <debug.h> |
| 9 | 10 | #include <vm_tools.h> |
| 10 | 11 | #include <exceptions.h> |
| 11 | −#include <unordered_set> | |
| 12 | 12 | #include <utils.h> |
| 13 | 13 | #include "tool_dispatch.h" |
| 14 | 14 | |
| @@ -88,9 +88,66 @@ std::size_t vm_tool_dispatch_t::unload_tool(std::size_t tool_id) · 73 unmodified lines | ||
| 88 | 88 | return _tools.size(); |
| 89 | 89 | } |
| 90 | 90 | |
| 91 | −opcode_t vm_tool_dispatch_t::on_breakpoint(vm_registers_t &r, vm_t &vm) | |
| 91 | +opcode_t vm_tool_dispatch_t::on_breakpoint(vm_registers_t &r) | |
| 92 | 92 | { |
| 93 | − return get_original_opcode(r.module_ref->module.get(), r.pc - 1); | |
| 93 | + opcode_t original_op; | |
| 94 | + std::size_t cookie_id; | |
| 95 | + std::tie(original_op, cookie_id) = get_original_opcode(r); | |
| 96 | + | |
| 97 | + vm_event_context_t cxt{}; | |
| 98 | + cxt.value1.registers = &r; | |
| 99 | + cxt.value2.i = cookie_id; | |
| 100 | + | |
| 101 | + _events.fire_event_callbacks(vm_event_t::breakpoint, cxt); | |
| 102 | + | |
| 103 | + return original_op; | |
| 104 | +} | |
| 105 | + | |
| 106 | +void vm_tool_dispatch_t::on_exception_raised(vm_registers_t &r, const vm_string_t &id, vm_alloc_t &e) | |
| 107 | +{ | |
| 108 | + vm_event_context_t cxt{}; | |
| 109 | + cxt.value1.registers = &r; | |
| 110 | + cxt.value2.str = &id; | |
| 111 | + cxt.value3.alloc = &e; | |
| 112 | + | |
| 113 | + _events.fire_event_callbacks(vm_event_t::exception_raised, cxt); | |
| 114 | +} | |
| 115 | + | |
| 116 | +void vm_tool_dispatch_t::on_exception_unhandled(vm_registers_t &r, const vm_string_t &id, vm_alloc_t &e) | |
| 117 | +{ | |
| 118 | + vm_event_context_t cxt{}; | |
| 119 | + cxt.value1.registers = &r; | |
| 120 | + cxt.value2.str = &id; | |
| 121 | + cxt.value3.alloc = &e; | |
| 122 | + | |
| 123 | + _events.fire_event_callbacks(vm_event_t::exception_unhandled, cxt); | |
| 124 | +} | |
| 125 | + | |
| 126 | +void vm_tool_dispatch_t::on_module_load(std::shared_ptr<vm_module_t> &m, const vm_string_t &path) | |
| 127 | +{ | |
| 128 | + assert(m != nullptr); | |
| 129 | + | |
| 130 | + vm_event_context_t cxt{}; | |
| 131 | + cxt.value1.module = &m; | |
| 132 | + cxt.value2.str = &path; | |
| 133 | + | |
| 134 | + _events.fire_event_callbacks(vm_event_t::module_load, cxt); | |
| 135 | +} | |
| 136 | + | |
| 137 | +void vm_tool_dispatch_t::on_thread_begin(vm_thread_t &t) | |
| 138 | +{ | |
| 139 | + vm_event_context_t cxt{}; | |
| 140 | + cxt.value1.thread = &t; | |
| 141 | + | |
| 142 | + _events.fire_event_callbacks(vm_event_t::thread_begin, cxt); | |
| 143 | +} | |
| 144 | + | |
| 145 | +void vm_tool_dispatch_t::on_thread_end(vm_thread_t &t) | |
| 146 | +{ | |
| 147 | + vm_event_context_t cxt{}; | |
| 148 | + cxt.value1.thread = &t; | |
| 149 | + | |
| 150 | + _events.fire_event_callbacks(vm_event_t::thread_end, cxt); | |
| 94 | 151 | } |
| 95 | 152 | |
| 96 | 153 | std::size_t vm_tool_dispatch_t::subscribe_event(vm_event_t evt, vm_event_callback_t cb) |
| @@ -133,15 +190,13 @@ void vm_tool_dispatch_t::unsubscribe_event(std::size_t cookie_id) · 36 unmodified lines | ||
| 133 | 190 | debug::log_msg(debug::component_trace_t::tool, debug::log_level_t::debug, "unsubscribe: event: %d %d", evt, cookie_id); |
| 134 | 191 | } |
| 135 | 192 | |
| 136 | −std::size_t vm_tool_dispatch_t::set_breakpoint(std::shared_ptr<const vm_module_t> module, vm_pc_t pc) | |
| 193 | +std::size_t vm_tool_dispatch_t::set_breakpoint(std::shared_ptr<vm_module_t> module, vm_pc_t pc) | |
| 137 | 194 | { |
| 138 | 195 | if (module == nullptr || util::has_flag(module->header.runtime_flag, runtime_flags_t::builtin)) |
| 139 | 196 | throw vm_system_exception{ "Unable to set breakpoint in supplied module" }; |
| 140 | 197 | |
| 141 | − // [TODO] This should be re-considered. Removing 'const' is less than ideal. | |
| 142 | − // Remove the const value since the code section needs to be updated. | |
| 143 | − auto &code_section = const_cast<code_section_t &>(module->code_section); | |
| 144 | − if (pc >= code_section.size()) | |
| 198 | + auto &code_section = module->code_section; | |
| 199 | + if (pc >= static_cast<vm_pc_t>(code_section.size())) | |
| 145 | 200 | throw vm_system_exception{ "Invalid PC for module" }; |
| 146 | 201 | |
| 147 | 202 | const auto real_opcode = code_section[pc].op.opcode; |
| @@ -158,7 +213,7 @@ std::size_t vm_tool_dispatch_t::set_breakpoint(std::shared_ptr<const vm_module_t · 10 unmodified lines | ||
| 158 | 213 | |
| 159 | 214 | // Record the original opcode |
| 160 | 215 | auto &pc_map = _breakpoints.original_opcodes[reinterpret_cast<std::uintptr_t>(module.get())]; |
| 161 | − pc_map[pc] = real_opcode; | |
| 216 | + pc_map[pc] = std::make_pair(real_opcode, cookie_id); | |
| 162 | 217 | |
| 163 | 218 | // Replace the current opcode with breakpoint |
| 164 | 219 | code_section[pc].op.opcode = opcode_t::brkpt; |
| @@ -190,7 +245,7 @@ void vm_tool_dispatch_t::clear_breakpoint(std::size_t cookie_id) · 25 unmodified lines | ||
| 190 | 245 | auto iter_pc = pc_map.find(target_pc); |
| 191 | 246 | assert(iter_pc != pc_map.cend()); |
| 192 | 247 | |
| 193 | − auto original_opcode = iter_pc->second; | |
| 248 | + auto original_opcode = iter_pc->second.first; | |
| 194 | 249 | |
| 195 | 250 | // Replace the breakpoint opcode with the original |
| 196 | 251 | auto &code_section = const_cast<code_section_t &>(mod_pc_pair.first->code_section); |
| @@ -211,8 +266,11 @@ void vm_tool_dispatch_t::clear_breakpoint(std::size_t cookie_id) · 14 unmodified lines | ||
| 211 | 266 | _breakpoints.cookie_to_modulepc.erase(iter_cookie); |
| 212 | 267 | } |
| 213 | 268 | |
| 214 | −opcode_t vm_tool_dispatch_t::get_original_opcode(const vm_module_t *module, vm_pc_t pc) | |
| 269 | +std::tuple<opcode_t, std::size_t> vm_tool_dispatch_t::get_original_opcode(const vm_registers_t &r) | |
| 215 | 270 | { |
| 271 | + const auto module = r.module_ref->module.get(); | |
| 272 | + const auto current_pc = r.pc - 1; | |
| 273 | + | |
| 216 | 274 | if (module == nullptr || util::has_flag(module->header.runtime_flag, runtime_flags_t::builtin)) |
| 217 | 275 | throw vm_system_exception{ "Unable to determine original opcode in supplied module" }; |
| 218 | 276 | |
| @@ -222,11 +280,30 @@ opcode_t vm_tool_dispatch_t::get_original_opcode(const vm_module_t *module, vm_p · 3 unmodified lines | ||
| 222 | 280 | if (iter_orig != _breakpoints.original_opcodes.cend()) |
| 223 | 281 | { |
| 224 | 282 | auto &pc_map = iter_orig->second; |
| 225 | − auto iter_pc = pc_map.find(pc); | |
| 283 | + auto iter_pc = pc_map.find(current_pc); | |
| 226 | 284 | if (iter_pc != pc_map.cend()) |
| 227 | 285 | return iter_pc->second; |
| 228 | 286 | } |
| 229 | 287 | |
| 230 | 288 | assert(false && "Why are we missing this information?"); |
| 231 | − return opcode_t::runt; // Return NOP instruction? | |
| 289 | + return std::make_tuple(opcode_t::runt, 0); // Return NOP instruction? | |
| 290 | +} | |
| 291 | + | |
| 292 | +void vm_tool_dispatch_t::events_t::fire_event_callbacks(vm_event_t event_type, vm_event_context_t &cxt) | |
| 293 | +{ | |
| 294 | + auto event_callbacks = std::vector<vm_event_callback_t>{}; | |
| 295 | + | |
| 296 | + { | |
| 297 | + std::lock_guard<std::mutex> lock_local{ lock }; | |
| 298 | + | |
| 299 | + auto &event_callbacks_tmp = callbacks[event_type]; | |
| 300 | + for (auto &c : event_callbacks_tmp) | |
| 301 | + { | |
| 302 | + assert(static_cast<bool>(c.second) && "Why is callback empty?"); | |
| 303 | + event_callbacks.push_back(c.second); | |
| 304 | + } | |
| 305 | + } | |
| 306 | + | |
| 307 | + for (auto &c : event_callbacks) | |
| 308 | + c(event_type, cxt); | |
| 232 | 309 | } |