History

Additional debugger command (term) Add command line arguments for enabling debugger from exec

Remove tabs from all logging

arr committed 10 years ago

Commit 660681b1 parent e2f8e255 files · +190 −23Browse files

Unified · Split

5 files
  1. src/exec/debugger.cpp +36 −4
  2. src/exec/exec.h +12 −2
  3. src/exec/main.cpp +140 −15
  4. src/vm/garbage_collector.cpp +1 −1
  5. src/vm/scheduler.cpp +1 −1
src/exec/debugger.cpp+36−4
@@ -13,6 +13,7 @@ · 12 unmodified lines
13#include <utils.h>13#include <utils.h>
14#include <vm_memory.h>14#include <vm_memory.h>
15#include <vm_asm.h>15#include <vm_asm.h>
16#include <exceptions.h>
16#include "exec.h"17#include "exec.h"
17 18
18using namespace disvm;19using namespace disvm;
@@ -289,6 +290,11 @@ namespace · 270 unmodified lines
289 cxt.exit_break = true;290 cxt.exit_break = true;
290 }291 }
291 292
293 void cmd_term(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt)
294 {
295 throw vm_user_exception{ "Debugger signaled VM termination" };
296 }
297
292 void cmd_print_registers(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt)298 void cmd_print_registers(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt)
293 {299 {
294 auto s = registers_to_string(*cxt.current_register);300 auto s = registers_to_string(*cxt.current_register);
@@ -740,6 +746,7 @@ namespace · 445 unmodified lines
740 const dbg_cmd_t cmds[] =746 const dbg_cmd_t cmds[] =
741 {747 {
742 { "c", "Continue", nullptr, nullptr, cmd_continue },748 { "c", "Continue", nullptr, nullptr, cmd_continue },
749 { "term", "Terminate the VM instance", nullptr, nullptr, cmd_term },
743 750
744 { "r", "Print registers", nullptr, nullptr, cmd_print_registers },751 { "r", "Print registers", nullptr, nullptr, cmd_print_registers },
745 { "t", "Print all threads", nullptr, nullptr, cmd_print_threads },752 { "t", "Print all threads", nullptr, nullptr, cmd_print_threads },
@@ -862,8 +869,18 @@ namespace · 116 unmodified lines
862 }869 }
863}870}
864 871
865debugger::debugger()872std::ostream& operator<<(std::ostream &ss, const debugger_options o)
866 : _tool_id{ 0 }873{
874 ss << "Break on enter: " << std::boolalpha << o.break_on_enter << "\n"
875 << "Break on module load: " << std::boolalpha << o.break_on_module_load << "\n"
876 << "Break on exception: " << std::boolalpha << o.break_on_exception << "\n";
877
878 return ss;
879}
880
881debugger::debugger(const debugger_options &opt)
882 : _options{ opt }
883 , _tool_id{ 0 }
867 , controller{ nullptr }884 , controller{ nullptr }
868{ }885{ }
869 886
@@ -896,7 +913,7 @@ void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id) · 26 unmodified lines
896 debug_print_info(ss.str());913 debug_print_info(ss.str());
897 }));914 }));
898 915
899 _event_cookies.push_back(controller->subscribe_event(vm_event_t::exception_raised, [](vm_event_t, vm_event_context_t &cxt)916 _event_cookies.push_back(controller->subscribe_event(vm_event_t::exception_raised, [&](vm_event_t, vm_event_context_t &cxt)
900 {917 {
901 auto ss = std::stringstream{};918 auto ss = std::stringstream{};
902 ss << "Exception '"919 ss << "Exception '"
@@ -904,6 +921,9 @@ void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id) · 1 unmodified line
904 << "' thrown.";921 << "' thrown.";
905 922
906 debug_print_info(ss.str());923 debug_print_info(ss.str());
924
925 if (_options.break_on_exception)
926 prompt(*this, *cxt.value1.registers);
907 }));927 }));
908 928
909 _event_cookies.push_back(controller->subscribe_event(vm_event_t::exception_unhandled, [&](vm_event_t, vm_event_context_t &cxt)929 _event_cookies.push_back(controller->subscribe_event(vm_event_t::exception_unhandled, [&](vm_event_t, vm_event_context_t &cxt)
@@ -928,8 +948,20 @@ void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id) · 18 unmodified lines
928 if (util::has_flag(m->header.runtime_flag, runtime_flags_t::builtin))948 if (util::has_flag(m->header.runtime_flag, runtime_flags_t::builtin))
929 ss << " (built-in)";949 ss << " (built-in)";
930 950
931
932 debug_print_info(ss.str());951 debug_print_info(ss.str());
952
953 // If the break on enter flag was set, it will be true
954 // and the first module load will be the user entry module.
955 if (_options.break_on_enter)
956 {
957 // Reset the break on enter flag and set a breakpoint
958 // on the entry PC for the module - 'break on enter'
959 _options.break_on_enter = false;
960 controller->set_breakpoint(m, m->header.entry_pc);
961 }
962
963 if (_options.break_on_module_load)
964 prompt(*this, *cxt.value1.registers);
933 }));965 }));
934 966
935 _event_cookies.push_back(controller->subscribe_event(vm_event_t::breakpoint, [&](vm_event_t, vm_event_context_t &cxt)967 _event_cookies.push_back(controller->subscribe_event(vm_event_t::breakpoint, [&](vm_event_t, vm_event_context_t &cxt)
src/exec/exec.h+12−2
@@ -12,13 +12,22 @@ · 11 unmodified lines
12#include <disvm.h>12#include <disvm.h>
13#include <vm_tools.h>13#include <vm_tools.h>
14 14
15struct debugger_options
16{
17 bool break_on_enter;
18 bool break_on_module_load;
19 bool break_on_exception;
20};
21
22std::ostream& operator<<(std::ostream &ss, const debugger_options o);
23
15class debugger final : public disvm::runtime::vm_tool_t24class debugger final : public disvm::runtime::vm_tool_t
16{25{
17public:26public:
18 debugger();27 debugger(const debugger_options &);
19 28
20public: // vm_tool_t29public: // vm_tool_t
21 void on_load(disvm::runtime::vm_tool_controller_t &controller, std::size_t tool_id) override;30 void on_load(disvm::runtime::vm_tool_controller_t &, std::size_t tool_id) override;
22 31
23 void on_unload() override;32 void on_unload() override;
24 33
@@ -27,6 +36,7 @@ public: · 2 unmodified lines
27 std::vector<disvm::runtime::cookie_t> breakpoint_cookies;36 std::vector<disvm::runtime::cookie_t> breakpoint_cookies;
28 37
29private:38private:
39 debugger_options _options;
30 std::size_t _tool_id;40 std::size_t _tool_id;
31 std::vector<disvm::runtime::cookie_t> _event_cookies;41 std::vector<disvm::runtime::cookie_t> _event_cookies;
32};42};
src/exec/main.cpp+140−15
@@ -30,10 +30,14 @@ namespace · 29 unmodified lines
30 30
31 std::shared_ptr<const vm_module_t> command_module;31 std::shared_ptr<const vm_module_t> command_module;
32 32
33 std::unique_ptr<vm_module_t> create_entry_module(vm_t &vm, int argc, char* argv[])33 std::unique_ptr<vm_module_t> create_entry_module(vm_t &vm, const std::vector<char *> &vm_args)
34 {34 {
35 if (vm_args.size() == 0)
36 throw vm_user_exception{ "Entry module not supplied" };
37
35 // First argument is the module to load38 // First argument is the module to load
36 auto command_module_path = new vm_string_t{ std::strlen(argv[0]), reinterpret_cast<uint8_t *>(argv[0]) };39 auto entry_module_path = vm_args[0];
40 auto command_module_path = new vm_string_t{ std::strlen(entry_module_path), reinterpret_cast<uint8_t *>(entry_module_path) };
37 41
38 // Pre-load the command module in the VM.42 // Pre-load the command module in the VM.
39 command_module = vm.load_module(command_module_path->str());43 command_module = vm.load_module(command_module_path->str());
@@ -41,9 +45,9 @@ namespace · 1 unmodified line
41 // Convert arguments to a list45 // Convert arguments to a list
42 vm_list_t *args = nullptr;46 vm_list_t *args = nullptr;
43 vm_list_t *last = nullptr;47 vm_list_t *last = nullptr;
44 for (auto i = 1; i < argc; ++i)48 for (auto i = std::size_t{ 1 }; i < vm_args.size(); ++i)
45 {49 {
46 auto tmp = argv[i];50 auto tmp = vm_args[i];
47 auto arg = new vm_string_t{ std::strlen(tmp), reinterpret_cast<uint8_t *>(tmp) };51 auto arg = new vm_string_t{ std::strlen(tmp), reinterpret_cast<uint8_t *>(tmp) };
48 if (args == nullptr)52 if (args == nullptr)
49 {53 {
@@ -165,39 +169,160 @@ namespace · 115 unmodified lines
165 }169 }
166}170}
167 171
172struct arg_exception_t : std::runtime_error
173{
174 arg_exception_t(const char *m, const char *arg)
175 : std::runtime_error{ m }
176 , arg{ arg }
177 { }
178
179 const char * const arg;
180};
181
182struct exec_options
183{
184 std::vector<char *> vm_args;
185
186 bool print_help;
187 bool quiet_start;
188 bool enabled_debugger;
189 debugger_options debugger;
190};
191
192void print_banner(const exec_options &options)
193{
194 std::cout
195 << "DisVM\n"
196 << "----------------\n"
197 << "Debugger enabled: " << std::boolalpha << options.enabled_debugger << "\n";
198
199 if (options.enabled_debugger)
200 std::cout << options.debugger << "\n";
201
202 std::cout << std::endl;
203}
204
205void print_help()
206{
207 std::cout
208 << "Usage: disvm-exec [-d[e|m|x]*] [-q] [-?] <entry module> <args>*\n"
209 << " d - Enable debugger\n"
210 << " e - Break on entry\n"
211 << " m - Break on module load\n"
212 << " x - Break on exception (first chance)\n"
213 << " q - Suppress banner and configuration\n"
214 << " ? - Print help\n";
215}
216
217void process_arg(char* arg, std::function<char *()> next, exec_options &options)
218{
219 assert(arg != nullptr && next != nullptr);
220 if (arg[0] != '-')
221 {
222 for (; arg != nullptr; arg = next())
223 options.vm_args.push_back(arg);
224
225 return;
226 }
227
228 auto arg_len = std::strlen(arg);
229 if (arg_len < 2)
230 throw arg_exception_t{ "Invalid flag format", arg };
231
232 switch (arg[1])
233 {
234 case 'd':
235 options.enabled_debugger = true;
236 for (auto i = std::size_t{ 2 }; i < arg_len; ++i)
237 {
238 switch (arg[i])
239 {
240 case 'e': options.debugger.break_on_enter = true;
241 break;
242 case 'm': options.debugger.break_on_module_load = true;
243 break;
244 case 'x': options.debugger.break_on_exception = true;
245 break;
246 }
247 }
248
249 break;
250
251 case 'q':
252 options.quiet_start = true;
253 break;
254
255 case '?':
256 options.print_help = true;
257 break;
258
259 default:
260 throw arg_exception_t{ "Unknown flag", arg };
261 }
262}
263
168int main(int argc, char* argv[])264int main(int argc, char* argv[])
169{265{
170 // [TODO] Handle command line arguments266 exec_options options = {};
171 assert(argc > 1);267
268 try
269 {
270 // Ignore the process name
271 auto arg_idx = int{ 1 };
272 auto next_arg = [&]()
273 {
274 return arg_idx < argc ? argv[arg_idx++] : nullptr;
275 };
276
277 for (auto curr_arg = next_arg(); curr_arg != nullptr; curr_arg = next_arg())
278 process_arg(curr_arg, next_arg, options);
279 }
280 catch (const arg_exception_t &ae)
281 {
282 std::cerr << ae.what();
283 if (ae.arg != nullptr)
284 std::cerr << ": " << ae.arg << std::endl;
285
286 return EXIT_FAILURE;
287 }
288
289 if (!options.quiet_start)
290 print_banner(options);
291
292 if (options.print_help)
293 {
294 print_help();
295 return EXIT_SUCCESS;
296 }
172 297
173 vm_t vm;298 vm_t vm;
174 299
175 //vm.load_tool(std::make_shared<debugger>());300 if (options.enabled_debugger)
301 vm.load_tool(std::make_shared<debugger>(options.debugger));
176 302
177 try303 try
178 {304 {
179 // Ignore the process name305 auto entry = create_entry_module(vm, options.vm_args);
180 auto entry = create_entry_module(vm, argc - 1, argv + 1);
181 306
182 vm.exec(std::move(entry));307 vm.exec(std::move(entry));
183 308
184 vm.spin_sleep_till_idle(std::chrono::milliseconds(100));309 vm.spin_sleep_till_idle(std::chrono::milliseconds(100));
185 }310 }
186 catch (vm_user_exception &ue)311 catch (const vm_user_exception &ue)
187 {312 {
188 std::cout << ue.what() << std::endl;313 std::cerr << ue.what() << std::endl;
189 314
190 return EXIT_FAILURE;315 return EXIT_FAILURE;
191 }316 }
192 catch (vm_system_exception &se)317 catch (const vm_system_exception &se)
193 {318 {
194 std::cout319 std::cerr
195 << "Internal exception:\n\t"320 << "Internal exception:\n "
196 << se.what()321 << se.what()
197 << std::endl;322 << std::endl;
198 323
199 return EXIT_FAILURE;324 return EXIT_FAILURE;
200 }325 }
201 326
202 return 0;327 return EXIT_SUCCESS;
203}328}
src/vm/garbage_collector.cpp+1−1
@@ -158,7 +158,7 @@ namespace · 157 unmodified lines
158 add_pointer_to_queue = std::function<void(pointer_t p, std::size_t)>{ [&allocs](pointer_t p, std::size_t) -> void158 add_pointer_to_queue = std::function<void(pointer_t p, std::size_t)>{ [&allocs](pointer_t p, std::size_t) -> void
159 {159 {
160 auto a = vm_alloc_t::from_allocation(p);160 auto a = vm_alloc_t::from_allocation(p);
161 debug::log_msg(debug::component_trace_t::garbage_collector, debug::log_level_t::debug, "\tref: %#" PRIxPTR "\n", a);161 debug::log_msg(debug::component_trace_t::garbage_collector, debug::log_level_t::debug, " ref: %#" PRIxPTR "\n", a);
162 allocs.push(a);162 allocs.push(a);
163 } };163 } };
164 }164 }
src/vm/scheduler.cpp+1−1
@@ -58,7 +58,7 @@ void default_scheduler_t::worker_main(default_scheduler_t &instance) · 57 unmodified lines
58 if (module_ref.module->module_name != nullptr)58 if (module_ref.module->module_name != nullptr)
59 module_name = module_ref.module->module_name->str();59 module_name = module_ref.module->module_name->str();
60 60
61 err_msg << "\t" << module_name << "@" << pc << "\n";61 err_msg << " " << module_name << "@" << pc << "\n";
62 return true;62 return true;
63 });63 });
64 }64 }