Showing the changes to src/vm/tool_dispatch.cpp (1 of 14 files). Show all
Unified · Split
| @@ -50,7 +50,7 @@ std::size_t vm_tool_dispatch_t::load_tool(std::shared_ptr<runtime::vm_tool_t> to · 49 unmodified lines | |||
| 50 | { | 50 | { |
| 51 | // [TODO] For debug builds, it might be useful to wrap the controller in a proxy that records | 51 | // [TODO] For debug builds, it might be useful to wrap the controller in a proxy that records |
| 52 | // the subscribed callbacks and asserts they are all properly unsubscribed during agent unload. | 52 | // the subscribed callbacks and asserts they are all properly unsubscribed during agent unload. |
| 53 | tool->on_load(_vm, *this, current_id); | 53 | tool->on_load(*this, current_id); |
| 54 | } | 54 | } |
| 55 | catch (...) | 55 | catch (...) |
| 56 | { | 56 | { |
| @@ -91,12 +91,12 @@ std::size_t vm_tool_dispatch_t::unload_tool(std::size_t tool_id) · 34 unmodified lines | |||
| 91 | opcode_t vm_tool_dispatch_t::on_breakpoint(vm_registers_t &r) | 91 | opcode_t vm_tool_dispatch_t::on_breakpoint(vm_registers_t &r) |
| 92 | { | 92 | { |
| 93 | opcode_t original_op; | 93 | opcode_t original_op; |
| 94 | std::size_t cookie_id; | 94 | cookie_t cookie_id; |
| 95 | std::tie(original_op, cookie_id) = get_original_opcode(r); | 95 | std::tie(original_op, cookie_id) = get_original_opcode_and_cookie(r); |
| 96 | 96 | ||
| 97 | vm_event_context_t cxt{}; | 97 | vm_event_context_t cxt{}; |
| 98 | cxt.value1.registers = &r; | 98 | cxt.value1.registers = &r; |
| 99 | cxt.value2.i = cookie_id; | 99 | cxt.value2.cookie = cookie_id; |
| 100 | 100 | ||
| 101 | _events.fire_event_callbacks(vm_event_t::breakpoint, cxt); | 101 | _events.fire_event_callbacks(vm_event_t::breakpoint, cxt); |
| 102 | 102 | ||
| @@ -123,7 +123,7 @@ void vm_tool_dispatch_t::on_exception_unhandled(vm_registers_t &r, const vm_stri · 20 unmodified lines | |||
| 123 | _events.fire_event_callbacks(vm_event_t::exception_unhandled, cxt); | 123 | _events.fire_event_callbacks(vm_event_t::exception_unhandled, cxt); |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | void vm_tool_dispatch_t::on_module_load(std::shared_ptr<vm_module_t> &m, const vm_string_t &path) | 126 | void vm_tool_dispatch_t::on_module_vm_load(std::shared_ptr<vm_module_t> &m, const vm_string_t &path) |
| 127 | { | 127 | { |
| 128 | assert(m != nullptr); | 128 | assert(m != nullptr); |
| 129 | 129 | ||
| @@ -131,7 +131,18 @@ void vm_tool_dispatch_t::on_module_load(std::shared_ptr<vm_module_t> &m, const v · 1 unmodified line | |||
| 131 | cxt.value1.module = &m; | 131 | cxt.value1.module = &m; |
| 132 | cxt.value2.str = &path; | 132 | cxt.value2.str = &path; |
| 133 | 133 | ||
| 134 | _events.fire_event_callbacks(vm_event_t::module_load, cxt); | 134 | _events.fire_event_callbacks(vm_event_t::module_vm_load, cxt); |
| 135 | } | ||
| 136 | |||
| 137 | void vm_tool_dispatch_t::on_module_thread_load(vm_registers_t &r, std::shared_ptr<vm_module_t> &m) | ||
| 138 | { | ||
| 139 | assert(m != nullptr); | ||
| 140 | |||
| 141 | vm_event_context_t cxt{}; | ||
| 142 | cxt.value1.registers = &r; | ||
| 143 | cxt.value2.module = &m; | ||
| 144 | |||
| 145 | _events.fire_event_callbacks(vm_event_t::module_thread_load, cxt); | ||
| 135 | } | 146 | } |
| 136 | 147 | ||
| 137 | void vm_tool_dispatch_t::on_thread_begin(vm_thread_t &t) | 148 | void vm_tool_dispatch_t::on_thread_begin(vm_thread_t &t) |
| @@ -150,7 +161,12 @@ void vm_tool_dispatch_t::on_thread_end(vm_thread_t &t) · 12 unmodified lines | |||
| 150 | _events.fire_event_callbacks(vm_event_t::thread_end, cxt); | 161 | _events.fire_event_callbacks(vm_event_t::thread_end, cxt); |
| 151 | } | 162 | } |
| 152 | 163 | ||
| 153 | std::size_t vm_tool_dispatch_t::subscribe_event(vm_event_t evt, vm_event_callback_t cb) | 164 | vm_t& vm_tool_dispatch_t::get_vm_instance() const |
| 165 | { | ||
| 166 | return _vm; | ||
| 167 | } | ||
| 168 | |||
| 169 | cookie_t vm_tool_dispatch_t::subscribe_event(vm_event_t evt, vm_event_callback_t cb) | ||
| 154 | { | 170 | { |
| 155 | if (!cb) | 171 | if (!cb) |
| 156 | throw vm_system_exception{ "Invalid callback for event" }; | 172 | throw vm_system_exception{ "Invalid callback for event" }; |
| @@ -172,7 +188,7 @@ std::size_t vm_tool_dispatch_t::subscribe_event(vm_event_t evt, vm_event_callbac · 15 unmodified lines | |||
| 172 | return cookie_id; | 188 | return cookie_id; |
| 173 | } | 189 | } |
| 174 | 190 | ||
| 175 | void vm_tool_dispatch_t::unsubscribe_event(std::size_t cookie_id) | 191 | void vm_tool_dispatch_t::unsubscribe_event(cookie_t cookie_id) |
| 176 | { | 192 | { |
| 177 | std::lock_guard<std::mutex> lock{ _events.lock }; | 193 | std::lock_guard<std::mutex> lock{ _events.lock }; |
| 178 | 194 | ||
| @@ -190,7 +206,7 @@ void vm_tool_dispatch_t::unsubscribe_event(std::size_t cookie_id) · 11 unmodified lines | |||
| 190 | debug::log_msg(debug::component_trace_t::tool, debug::log_level_t::debug, "unsubscribe: event: %d %d", evt, cookie_id); | 206 | debug::log_msg(debug::component_trace_t::tool, debug::log_level_t::debug, "unsubscribe: event: %d %d", evt, cookie_id); |
| 191 | } | 207 | } |
| 192 | 208 | ||
| 193 | std::size_t vm_tool_dispatch_t::set_breakpoint(std::shared_ptr<vm_module_t> module, vm_pc_t pc) | 209 | cookie_t vm_tool_dispatch_t::set_breakpoint(std::shared_ptr<vm_module_t> module, vm_pc_t pc) |
| 194 | { | 210 | { |
| 195 | if (module == nullptr || util::has_flag(module->header.runtime_flag, runtime_flags_t::builtin)) | 211 | if (module == nullptr || util::has_flag(module->header.runtime_flag, runtime_flags_t::builtin)) |
| 196 | throw vm_system_exception{ "Unable to set breakpoint in supplied module" }; | 212 | throw vm_system_exception{ "Unable to set breakpoint in supplied module" }; |
| @@ -209,7 +225,7 @@ std::size_t vm_tool_dispatch_t::set_breakpoint(std::shared_ptr<vm_module_t> modu · 12 unmodified lines | |||
| 209 | const auto cookie_id = _breakpoints.cookie_counter++; | 225 | const auto cookie_id = _breakpoints.cookie_counter++; |
| 210 | 226 | ||
| 211 | // Map the cookie to the module/pc pair. | 227 | // Map the cookie to the module/pc pair. |
| 212 | _breakpoints.cookie_to_modulepc[cookie_id] = std::make_pair(module, pc); | 228 | _breakpoints.cookie_to_details[cookie_id] = { module, pc }; |
| 213 | 229 | ||
| 214 | // Record the original opcode | 230 | // Record the original opcode |
| 215 | auto &pc_map = _breakpoints.original_opcodes[reinterpret_cast<std::uintptr_t>(module.get())]; | 231 | auto &pc_map = _breakpoints.original_opcodes[reinterpret_cast<std::uintptr_t>(module.get())]; |
| @@ -225,20 +241,30 @@ std::size_t vm_tool_dispatch_t::set_breakpoint(std::shared_ptr<vm_module_t> modu · 9 unmodified lines | |||
| 225 | } | 241 | } |
| 226 | } | 242 | } |
| 227 | 243 | ||
| 228 | void vm_tool_dispatch_t::clear_breakpoint(std::size_t cookie_id) | 244 | breakpoint_details_t vm_tool_dispatch_t::get_breakpoint_details(cookie_t cookie_id) const |
| 229 | { | 245 | { |
| 230 | std::lock_guard<std::mutex> lock{ _breakpoints.lock }; | 246 | std::lock_guard<std::mutex> lock{ _breakpoints.lock }; |
| 231 | 247 | ||
| 232 | // Resolve the cookie to the module/pc pair | 248 | auto iter_cookie = _breakpoints.cookie_to_details.find(cookie_id); |
| 233 | auto iter_cookie = _breakpoints.cookie_to_modulepc.find(cookie_id); | 249 | if (iter_cookie == _breakpoints.cookie_to_details.cend()) |
| 234 | if (iter_cookie == _breakpoints.cookie_to_modulepc.cend()) | 250 | throw vm_system_exception{ "Unknown breakpoint cookie" }; |
| 235 | return; | 251 | |
| 252 | return iter_cookie->second; | ||
| 253 | } | ||
| 254 | |||
| 255 | void vm_tool_dispatch_t::clear_breakpoint(cookie_t cookie_id) | ||
| 256 | { | ||
| 257 | std::lock_guard<std::mutex> lock{ _breakpoints.lock }; | ||
| 258 | |||
| 259 | auto iter_cookie = _breakpoints.cookie_to_details.find(cookie_id); | ||
| 260 | if (iter_cookie == _breakpoints.cookie_to_details.cend()) | ||
| 261 | throw vm_system_exception{ "Unknown breakpoint cookie" }; | ||
| 236 | 262 | ||
| 237 | auto mod_pc_pair = iter_cookie->second; | 263 | auto details = iter_cookie->second; |
| 238 | const auto target_pc = mod_pc_pair.second; | 264 | const auto target_pc = details.pc; |
| 239 | 265 | ||
| 240 | // Determine the original opcode | 266 | // Determine the original opcode |
| 241 | auto iter_orig = _breakpoints.original_opcodes.find(reinterpret_cast<std::uintptr_t>(mod_pc_pair.first.get())); | 267 | auto iter_orig = _breakpoints.original_opcodes.find(reinterpret_cast<std::uintptr_t>(details.module.get())); |
| 242 | assert(iter_orig != _breakpoints.original_opcodes.cend()); | 268 | assert(iter_orig != _breakpoints.original_opcodes.cend()); |
| 243 | 269 | ||
| 244 | auto &pc_map = iter_orig->second; | 270 | auto &pc_map = iter_orig->second; |
| @@ -248,12 +274,12 @@ void vm_tool_dispatch_t::clear_breakpoint(std::size_t cookie_id) · 3 unmodified lines | |||
| 248 | auto original_opcode = iter_pc->second.first; | 274 | auto original_opcode = iter_pc->second.first; |
| 249 | 275 | ||
| 250 | // Replace the breakpoint opcode with the original | 276 | // Replace the breakpoint opcode with the original |
| 251 | auto &code_section = const_cast<code_section_t &>(mod_pc_pair.first->code_section); | 277 | auto &code_section = const_cast<code_section_t &>(details.module->code_section); |
| 252 | assert(code_section[target_pc].op.opcode == opcode_t::brkpt); | 278 | assert(code_section[target_pc].op.opcode == opcode_t::brkpt); |
| 253 | code_section[target_pc].op.opcode = original_opcode; | 279 | code_section[target_pc].op.opcode = original_opcode; |
| 254 | 280 | ||
| 255 | if (debug::is_component_tracing_enabled<debug::component_trace_t::tool>()) | 281 | if (debug::is_component_tracing_enabled<debug::component_trace_t::tool>()) |
| 256 | debug::log_msg(debug::component_trace_t::tool, debug::log_level_t::debug, "breakpoint: unset: %d %d >>%s<<", cookie_id, target_pc, mod_pc_pair.first->module_name->str()); | 282 | debug::log_msg(debug::component_trace_t::tool, debug::log_level_t::debug, "breakpoint: unset: %d %d >>%s<<", cookie_id, target_pc, details.module->module_name->str()); |
| 257 | 283 | ||
| 258 | // Clean-up the PC mapping to opcode | 284 | // Clean-up the PC mapping to opcode |
| 259 | pc_map.erase(iter_pc); | 285 | pc_map.erase(iter_pc); |
| @@ -263,10 +289,10 @@ void vm_tool_dispatch_t::clear_breakpoint(std::size_t cookie_id) · 3 unmodified lines | |||
| 263 | _breakpoints.original_opcodes.erase(iter_orig); | 289 | _breakpoints.original_opcodes.erase(iter_orig); |
| 264 | 290 | ||
| 265 | // Remove the cookie map | 291 | // Remove the cookie map |
| 266 | _breakpoints.cookie_to_modulepc.erase(iter_cookie); | 292 | _breakpoints.cookie_to_details.erase(iter_cookie); |
| 267 | } | 293 | } |
| 268 | 294 | ||
| 269 | std::tuple<opcode_t, std::size_t> vm_tool_dispatch_t::get_original_opcode(const vm_registers_t &r) | 295 | std::tuple<opcode_t, cookie_t> vm_tool_dispatch_t::get_original_opcode_and_cookie(const vm_registers_t &r) |
| 270 | { | 296 | { |
| 271 | const auto module = r.module_ref->module.get(); | 297 | const auto module = r.module_ref->module.get(); |
| 272 | const auto current_pc = r.pc - 1; | 298 | const auto current_pc = r.pc - 1; |