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
1313 #include <utils.h>
1414 #include <vm_memory.h>
1515 #include <vm_asm.h>
16+#include <exceptions.h>
1617 #include "exec.h"
1718
1819 using namespace disvm;
@@ -289,6 +290,11 @@ namespace · 270 unmodified lines
289290 cxt.exit_break = true;
290291 }
291292
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+
292298 void cmd_print_registers(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt)
293299 {
294300 auto s = registers_to_string(*cxt.current_register);
@@ -740,6 +746,7 @@ namespace · 445 unmodified lines
740746 const dbg_cmd_t cmds[] =
741747 {
742748 { "c", "Continue", nullptr, nullptr, cmd_continue },
749+ { "term", "Terminate the VM instance", nullptr, nullptr, cmd_term },
743750
744751 { "r", "Print registers", nullptr, nullptr, cmd_print_registers },
745752 { "t", "Print all threads", nullptr, nullptr, cmd_print_threads },
@@ -862,8 +869,18 @@ namespace · 116 unmodified lines
862869 }
863870 }
864871
865−debugger::debugger()
866− : _tool_id{ 0 }
872+std::ostream& operator<<(std::ostream &ss, const debugger_options o)
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+
881+debugger::debugger(const debugger_options &opt)
882+ : _options{ opt }
883+ , _tool_id{ 0 }
867884 , controller{ nullptr }
868885 { }
869886
@@ -896,7 +913,7 @@ void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id) · 26 unmodified lines
896913 debug_print_info(ss.str());
897914 }));
898915
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)
900917 {
901918 auto ss = std::stringstream{};
902919 ss << "Exception '"
@@ -904,6 +921,9 @@ void debugger::on_load(vm_tool_controller_t &controller_, std::size_t tool_id) · 1 unmodified line
904921 << "' thrown.";
905922
906923 debug_print_info(ss.str());
924+
925+ if (_options.break_on_exception)
926+ prompt(*this, *cxt.value1.registers);
907927 }));
908928
909929 _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
928948 if (util::has_flag(m->header.runtime_flag, runtime_flags_t::builtin))
929949 ss << " (built-in)";
930950
931−
932951 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);
933965 }));
934966
935967 _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
1212 #include <disvm.h>
1313 #include <vm_tools.h>
1414
15+struct debugger_options
16+{
17+ bool break_on_enter;
18+ bool break_on_module_load;
19+ bool break_on_exception;
20+};
21+
22+std::ostream& operator<<(std::ostream &ss, const debugger_options o);
23+
1524 class debugger final : public disvm::runtime::vm_tool_t
1625 {
1726 public:
18− debugger();
27+ debugger(const debugger_options &);
1928
2029 public: // 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;
2231
2332 void on_unload() override;
2433
@@ -27,6 +36,7 @@ public: · 2 unmodified lines
2736 std::vector<disvm::runtime::cookie_t> breakpoint_cookies;
2837
2938 private:
39+ debugger_options _options;
3040 std::size_t _tool_id;
3141 std::vector<disvm::runtime::cookie_t> _event_cookies;
3242 };
src/exec/main.cpp+140−15
@@ -30,10 +30,14 @@ namespace · 29 unmodified lines
3030
3131 std::shared_ptr<const vm_module_t> command_module;
3232
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)
3434 {
35+ if (vm_args.size() == 0)
36+ throw vm_user_exception{ "Entry module not supplied" };
37+
3538 // 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) };
3741
3842 // Pre-load the command module in the VM.
3943 command_module = vm.load_module(command_module_path->str());
@@ -41,9 +45,9 @@ namespace · 1 unmodified line
4145 // Convert arguments to a list
4246 vm_list_t *args = nullptr;
4347 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)
4549 {
46− auto tmp = argv[i];
50+ auto tmp = vm_args[i];
4751 auto arg = new vm_string_t{ std::strlen(tmp), reinterpret_cast<uint8_t *>(tmp) };
4852 if (args == nullptr)
4953 {
@@ -165,39 +169,160 @@ namespace · 115 unmodified lines
165169 }
166170 }
167171
172+struct 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+
182+struct 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+
192+void 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+
205+void 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+
217+void 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+
168264 int main(int argc, char* argv[])
169265 {
170− // [TODO] Handle command line arguments
171− assert(argc > 1);
266+ exec_options options = {};
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+ }
172297
173298 vm_t vm;
174299
175− //vm.load_tool(std::make_shared<debugger>());
300+ if (options.enabled_debugger)
301+ vm.load_tool(std::make_shared<debugger>(options.debugger));
176302
177303 try
178304 {
179− // Ignore the process name
180− auto entry = create_entry_module(vm, argc - 1, argv + 1);
305+ auto entry = create_entry_module(vm, options.vm_args);
181306
182307 vm.exec(std::move(entry));
183308
184309 vm.spin_sleep_till_idle(std::chrono::milliseconds(100));
185310 }
186− catch (vm_user_exception &ue)
311+ catch (const vm_user_exception &ue)
187312 {
188− std::cout << ue.what() << std::endl;
313+ std::cerr << ue.what() << std::endl;
189314
190315 return EXIT_FAILURE;
191316 }
192− catch (vm_system_exception &se)
317+ catch (const vm_system_exception &se)
193318 {
194− std::cout
195− << "Internal exception:\n\t"
319+ std::cerr
320+ << "Internal exception:\n "
196321 << se.what()
197322 << std::endl;
198323
199324 return EXIT_FAILURE;
200325 }
201326
202− return 0;
327+ return EXIT_SUCCESS;
203328 }
src/vm/garbage_collector.cpp+1−1
@@ -158,7 +158,7 @@ namespace · 157 unmodified lines
158158 add_pointer_to_queue = std::function<void(pointer_t p, std::size_t)>{ [&allocs](pointer_t p, std::size_t) -> void
159159 {
160160 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);
162162 allocs.push(a);
163163 } };
164164 }
src/vm/scheduler.cpp+1−1
@@ -58,7 +58,7 @@ void default_scheduler_t::worker_main(default_scheduler_t &instance) · 57 unmodified lines
5858 if (module_ref.module->module_name != nullptr)
5959 module_name = module_ref.module->module_name->str();
6060
61− err_msg << "\t" << module_name << "@" << pc << "\n";
61+ err_msg << " " << module_name << "@" << pc << "\n";
6262 return true;
6363 });
6464 }