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 | 51 | // [TODO] For debug builds, it might be useful to wrap the controller in a proxy that records |
| 52 | 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 | 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 | 91 | opcode_t vm_tool_dispatch_t::on_breakpoint(vm_registers_t &r) |
| 92 | 92 | { |
| 93 | 93 | opcode_t original_op; |
| 94 | − std::size_t cookie_id; | |
| 95 | − std::tie(original_op, cookie_id) = get_original_opcode(r); | |
| 94 | + cookie_t cookie_id; | |
| 95 | + std::tie(original_op, cookie_id) = get_original_opcode_and_cookie(r); | |
| 96 | 96 | |
| 97 | 97 | vm_event_context_t cxt{}; |
| 98 | 98 | cxt.value1.registers = &r; |
| 99 | − cxt.value2.i = cookie_id; | |
| 99 | + cxt.value2.cookie = cookie_id; | |
| 100 | 100 | |
| 101 | 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 | 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 | 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 | 131 | cxt.value1.module = &m; |
| 132 | 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 | 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 | 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 | 171 | if (!cb) |
| 156 | 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 | 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 | 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 | 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 | 211 | if (module == nullptr || util::has_flag(module->header.runtime_flag, runtime_flags_t::builtin)) |
| 196 | 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 | 225 | const auto cookie_id = _breakpoints.cookie_counter++; |
| 210 | 226 | |
| 211 | 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 | 230 | // Record the original opcode |
| 215 | 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 | 246 | std::lock_guard<std::mutex> lock{ _breakpoints.lock }; |
| 231 | 247 | |
| 232 | − // Resolve the cookie to the module/pc pair | |
| 233 | − auto iter_cookie = _breakpoints.cookie_to_modulepc.find(cookie_id); | |
| 234 | − if (iter_cookie == _breakpoints.cookie_to_modulepc.cend()) | |
| 235 | − return; | |
| 248 | + auto iter_cookie = _breakpoints.cookie_to_details.find(cookie_id); | |
| 249 | + if (iter_cookie == _breakpoints.cookie_to_details.cend()) | |
| 250 | + throw vm_system_exception{ "Unknown breakpoint cookie" }; | |
| 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; | |
| 238 | − const auto target_pc = mod_pc_pair.second; | |
| 263 | + auto details = iter_cookie->second; | |
| 264 | + const auto target_pc = details.pc; | |
| 239 | 265 | |
| 240 | 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 | 268 | assert(iter_orig != _breakpoints.original_opcodes.cend()); |
| 243 | 269 | |
| 244 | 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 | 274 | auto original_opcode = iter_pc->second.first; |
| 249 | 275 | |
| 250 | 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 | 278 | assert(code_section[target_pc].op.opcode == opcode_t::brkpt); |
| 253 | 279 | code_section[target_pc].op.opcode = original_opcode; |
| 254 | 280 | |
| 255 | 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 | 284 | // Clean-up the PC mapping to opcode |
| 259 | 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 | 289 | _breakpoints.original_opcodes.erase(iter_orig); |
| 264 | 290 | |
| 265 | 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 | 297 | const auto module = r.module_ref->module.get(); |
| 272 | 298 | const auto current_pc = r.pc - 1; |