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
55 //
66
77 #include <cassert>
8+#include <vector>
89 #include <debug.h>
910 #include <vm_tools.h>
1011 #include <exceptions.h>
11−#include <unordered_set>
1212 #include <utils.h>
1313 #include "tool_dispatch.h"
1414
@@ -88,9 +88,66 @@ std::size_t vm_tool_dispatch_t::unload_tool(std::size_t tool_id) · 73 unmodified lines
8888 return _tools.size();
8989 }
9090
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)
9292 {
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);
94151 }
95152
96153 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
133190 debug::log_msg(debug::component_trace_t::tool, debug::log_level_t::debug, "unsubscribe: event: %d %d", evt, cookie_id);
134191 }
135192
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)
137194 {
138195 if (module == nullptr || util::has_flag(module->header.runtime_flag, runtime_flags_t::builtin))
139196 throw vm_system_exception{ "Unable to set breakpoint in supplied module" };
140197
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()))
145200 throw vm_system_exception{ "Invalid PC for module" };
146201
147202 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
158213
159214 // Record the original opcode
160215 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);
162217
163218 // Replace the current opcode with breakpoint
164219 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
190245 auto iter_pc = pc_map.find(target_pc);
191246 assert(iter_pc != pc_map.cend());
192247
193− auto original_opcode = iter_pc->second;
248+ auto original_opcode = iter_pc->second.first;
194249
195250 // Replace the breakpoint opcode with the original
196251 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
211266 _breakpoints.cookie_to_modulepc.erase(iter_cookie);
212267 }
213268
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)
215270 {
271+ const auto module = r.module_ref->module.get();
272+ const auto current_pc = r.pc - 1;
273+
216274 if (module == nullptr || util::has_flag(module->header.runtime_flag, runtime_flags_t::builtin))
217275 throw vm_system_exception{ "Unable to determine original opcode in supplied module" };
218276
@@ -222,11 +280,30 @@ opcode_t vm_tool_dispatch_t::get_original_opcode(const vm_module_t *module, vm_p · 3 unmodified lines
222280 if (iter_orig != _breakpoints.original_opcodes.cend())
223281 {
224282 auto &pc_map = iter_orig->second;
225− auto iter_pc = pc_map.find(pc);
283+ auto iter_pc = pc_map.find(current_pc);
226284 if (iter_pc != pc_map.cend())
227285 return iter_pc->second;
228286 }
229287
230288 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);
232309 }