History

Basic debugger implementation - No way to enable it without altering exec main.cpp.

arr committed 10 years ago

Commit f2c6ef31 parent 7c21b7718 files · +776 −72Browse files

Showing the changes to src/vm/tool_dispatch.cpp (1 of 18 files). Show all

Unified · Split

src/vm/tool_dispatch.cpp+90−13
@@ -5,10 +5,10 @@ · 4 unmodified lines
5//5//
6 6
7#include <cassert>7#include <cassert>
8#include <vector>
8#include <debug.h>9#include <debug.h>
9#include <vm_tools.h>10#include <vm_tools.h>
10#include <exceptions.h>11#include <exceptions.h>
11#include <unordered_set>
12#include <utils.h>12#include <utils.h>
13#include "tool_dispatch.h"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 return _tools.size();88 return _tools.size();
89}89}
90 90
91opcode_t vm_tool_dispatch_t::on_breakpoint(vm_registers_t &r, vm_t &vm)91opcode_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
106void 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
116void 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
126void 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
137void 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
145void 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
96std::size_t vm_tool_dispatch_t::subscribe_event(vm_event_t evt, vm_event_callback_t cb)153std::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 debug::log_msg(debug::component_trace_t::tool, debug::log_level_t::debug, "unsubscribe: event: %d %d", evt, cookie_id);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
136std::size_t vm_tool_dispatch_t::set_breakpoint(std::shared_ptr<const vm_module_t> module, vm_pc_t pc)193std::size_t vm_tool_dispatch_t::set_breakpoint(std::shared_ptr<vm_module_t> module, vm_pc_t pc)
137{194{
138 if (module == nullptr || util::has_flag(module->header.runtime_flag, runtime_flags_t::builtin))195 if (module == nullptr || util::has_flag(module->header.runtime_flag, runtime_flags_t::builtin))
139 throw vm_system_exception{ "Unable to set breakpoint in supplied module" };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.198 auto &code_section = module->code_section;
142 // Remove the const value since the code section needs to be updated.199 if (pc >= static_cast<vm_pc_t>(code_section.size()))
143 auto &code_section = const_cast<code_section_t &>(module->code_section);
144 if (pc >= code_section.size())
145 throw vm_system_exception{ "Invalid PC for module" };200 throw vm_system_exception{ "Invalid PC for module" };
146 201
147 const auto real_opcode = code_section[pc].op.opcode;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 // Record the original opcode214 // Record the original opcode
160 auto &pc_map = _breakpoints.original_opcodes[reinterpret_cast<std::uintptr_t>(module.get())];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 // Replace the current opcode with breakpoint218 // Replace the current opcode with breakpoint
164 code_section[pc].op.opcode = opcode_t::brkpt;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 auto iter_pc = pc_map.find(target_pc);245 auto iter_pc = pc_map.find(target_pc);
191 assert(iter_pc != pc_map.cend());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 // Replace the breakpoint opcode with the original250 // Replace the breakpoint opcode with the original
196 auto &code_section = const_cast<code_section_t &>(mod_pc_pair.first->code_section);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 _breakpoints.cookie_to_modulepc.erase(iter_cookie);266 _breakpoints.cookie_to_modulepc.erase(iter_cookie);
212}267}
213 268
214opcode_t vm_tool_dispatch_t::get_original_opcode(const vm_module_t *module, vm_pc_t pc)269std::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 if (module == nullptr || util::has_flag(module->header.runtime_flag, runtime_flags_t::builtin))274 if (module == nullptr || util::has_flag(module->header.runtime_flag, runtime_flags_t::builtin))
217 throw vm_system_exception{ "Unable to determine original opcode in supplied module" };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 if (iter_orig != _breakpoints.original_opcodes.cend())280 if (iter_orig != _breakpoints.original_opcodes.cend())
223 {281 {
224 auto &pc_map = iter_orig->second;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 if (iter_pc != pc_map.cend())284 if (iter_pc != pc_map.cend())
227 return iter_pc->second;285 return iter_pc->second;
228 }286 }
229 287
230 assert(false && "Why are we missing this information?");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
292void 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}