Unified · Split
| @@ -73,6 +73,9 @@ namespace · 72 unmodified lines | |||
| 73 | e.header.entry_type = 0; | 73 | e.header.entry_type = 0; |
| 74 | e.header.runtime_flag = (runtime_flags_t::has_import); | 74 | e.header.runtime_flag = (runtime_flags_t::has_import); |
| 75 | 75 | ||
| 76 | std::array<uint8_t, 8> mod_name = { "_entry_" }; | ||
| 77 | e.module_name = std::make_unique<vm_string_t>(mod_name.size() - 1, mod_name.data()); | ||
| 78 | |||
| 76 | // Inherit the stack extent from the command module and add the entry frame size. | 79 | // Inherit the stack extent from the command module and add the entry frame size. |
| 77 | e.header.stack_extent = command_module->header.stack_extent + sizeof(vm_entry_frame_t); | 80 | e.header.stack_extent = command_module->header.stack_extent + sizeof(vm_entry_frame_t); |
| 78 | 81 | ||
| @@ -656,11 +656,6 @@ namespace disvm · 655 unmodified lines | |||
| 656 | pointer_t fixed_point_register_2() const; | 656 | pointer_t fixed_point_register_2() const; |
| 657 | }; | 657 | }; |
| 658 | 658 | ||
| 659 | // Callback for stack walk. | ||
| 660 | // Returning 'false' during the stack walk will terminate the walk. | ||
| 661 | // The second parameter is reserved for internal use by the VM and should not be manipulated. | ||
| 662 | using vm_stack_walk_callback_t = std::function<bool(const vm_frame_t *f, const void *reserved)>; | ||
| 663 | |||
| 664 | // VM stack | 659 | // VM stack |
| 665 | class vm_stack_t final | 660 | class vm_stack_t final |
| 666 | { | 661 | { |
| @@ -680,10 +675,6 @@ namespace disvm · 13 unmodified lines | |||
| 680 | // Return the current top frame. | 675 | // Return the current top frame. |
| 681 | vm_frame_t *peek_frame() const; | 676 | vm_frame_t *peek_frame() const; |
| 682 | 677 | ||
| 683 | // Walk the stack getting a callback for each frame. | ||
| 684 | // This function is __not__ thread safe. | ||
| 685 | void walk_stack(vm_stack_walk_callback_t callback) const; | ||
| 686 | |||
| 687 | private: | 678 | private: |
| 688 | std::unique_ptr<vm_alloc_t> _mem; | 679 | std::unique_ptr<vm_alloc_t> _mem; |
| 689 | }; | 680 | }; |
| @@ -741,6 +732,14 @@ namespace disvm · 51 unmodified lines | |||
| 741 | pointer_t dest; | 732 | pointer_t dest; |
| 742 | }; | 733 | }; |
| 743 | 734 | ||
| 735 | // Callback for stack walk. | ||
| 736 | // Returning 'false' during the stack walk will terminate the walk. | ||
| 737 | using vm_stack_walk_callback_t = std::function<bool(const pointer_t frame, const vm_pc_t pc, const vm_module_ref_t &module_ref)>; | ||
| 738 | |||
| 739 | // Walk the stack getting a callback for each frame. | ||
| 740 | // This function is __not__ thread safe if the vm thread being walked is not stopped. | ||
| 741 | void walk_stack(const vm_registers_t &r, vm_stack_walk_callback_t callback); | ||
| 742 | |||
| 744 | // VM thread | 743 | // VM thread |
| 745 | class vm_thread_t final : public vm_alloc_t | 744 | class vm_thread_t final : public vm_alloc_t |
| 746 | { | 745 | { |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | |||
| 5 | // | 5 | // |
| 6 | 6 | ||
| 7 | #include <debug.h> | 7 | #include <debug.h> |
| 8 | #include <sstream> | ||
| 8 | #include <exceptions.h> | 9 | #include <exceptions.h> |
| 9 | #include "scheduler.h" | 10 | #include "scheduler.h" |
| 10 | 11 | ||
| @@ -45,8 +46,24 @@ void default_scheduler_t::worker_main(default_scheduler_t &instance) · 34 unmodified lines | |||
| 45 | } | 46 | } |
| 46 | catch (const vm_system_exception &se) | 47 | catch (const vm_system_exception &se) |
| 47 | { | 48 | { |
| 48 | std::printf("%s\n", se.what()); | 49 | std::stringstream err_msg; |
| 50 | err_msg << se.what() << "\n"; | ||
| 49 | 51 | ||
| 52 | if (current_thread != nullptr) | ||
| 53 | { | ||
| 54 | const auto &r = current_thread->vm_thread->get_registers(); | ||
| 55 | walk_stack(r, [&err_msg](const pointer_t, const vm_pc_t pc, const vm_module_ref_t &module_ref) | ||
| 56 | { | ||
| 57 | auto module_name = "<No Name>"; | ||
| 58 | if (module_ref.module->module_name != nullptr) | ||
| 59 | module_name = module_ref.module->module_name->str(); | ||
| 60 | |||
| 61 | err_msg << "\t" << module_name << "@" << pc << "\n"; | ||
| 62 | return true; | ||
| 63 | }); | ||
| 64 | } | ||
| 65 | |||
| 66 | std::fprintf(stderr, "%s\n", err_msg.str().c_str()); | ||
| 50 | instance._terminating = true; | 67 | instance._terminating = true; |
| 51 | instance._worker_event.notify_all(); | 68 | instance._worker_event.notify_all(); |
| 52 | } | 69 | } |
| @@ -89,7 +106,7 @@ default_scheduler_t::~default_scheduler_t() · 36 unmodified lines | |||
| 89 | bool default_scheduler_t::is_idle() const | 106 | bool default_scheduler_t::is_idle() const |
| 90 | { | 107 | { |
| 91 | std::lock_guard<std::mutex> lock{ _vm_threads_lock }; | 108 | std::lock_guard<std::mutex> lock{ _vm_threads_lock }; |
| 92 | return _running_vm_thread_count == 0 && _runnable_vm_threads.empty() && _blocked_vm_thread_ids.empty() && !_terminating; | 109 | return (_terminating) || (_running_vm_thread_count == 0 && _runnable_vm_threads.empty() && _blocked_vm_thread_ids.empty()); |
| 93 | } | 110 | } |
| 94 | 111 | ||
| 95 | vm_scheduler_control_t &default_scheduler_t::get_controller() const | 112 | vm_scheduler_control_t &default_scheduler_t::get_controller() const |
| @@ -295,24 +295,3 @@ vm_frame_t *vm_stack_t::peek_frame() const · 294 unmodified lines | |||
| 295 | auto layout = dynamic_cast<vm_stack_layout *>(_mem.get()); | 295 | auto layout = dynamic_cast<vm_stack_layout *>(_mem.get()); |
| 296 | return layout->top_frame; | 296 | return layout->top_frame; |
| 297 | } | 297 | } |
| 298 | |||
| 299 | void vm_stack_t::walk_stack(vm_stack_walk_callback_t callback) const | ||
| 300 | { | ||
| 301 | if (callback == nullptr) | ||
| 302 | return; | ||
| 303 | |||
| 304 | auto layout = dynamic_cast<vm_stack_layout *>(_mem.get()); | ||
| 305 | auto current_page = layout->top_page; | ||
| 306 | auto current_frame = layout->top_frame; | ||
| 307 | |||
| 308 | while (current_page != nullptr && current_frame != nullptr) | ||
| 309 | { | ||
| 310 | if (!callback(current_frame, current_page)) | ||
| 311 | break; | ||
| 312 | |||
| 313 | current_frame = current_frame->prev_frame(); | ||
| 314 | |||
| 315 | if (!current_page->contains_frame(current_frame)) | ||
| 316 | current_page = current_page->prev_page; | ||
| 317 | } | ||
| 318 | } | ||
| @@ -153,6 +153,27 @@ vm_registers_t::~vm_registers_t() · 152 unmodified lines | |||
| 153 | debug::assign_debug_pointer(&module_ref); | 153 | debug::assign_debug_pointer(&module_ref); |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | void disvm::runtime::walk_stack(const vm_registers_t &r, vm_stack_walk_callback_t callback) | ||
| 157 | { | ||
| 158 | assert(callback != nullptr); | ||
| 159 | |||
| 160 | auto current_pc = r.pc; | ||
| 161 | auto current_module = r.module_ref; | ||
| 162 | auto current_frame = r.stack.peek_frame(); | ||
| 163 | while (current_frame != nullptr) | ||
| 164 | { | ||
| 165 | if (!callback(current_frame->base(), current_pc, *current_module)) | ||
| 166 | break; | ||
| 167 | |||
| 168 | current_pc = current_frame->prev_pc(); | ||
| 169 | auto prev_module_maybe = current_frame->prev_module_ref(); | ||
| 170 | if (prev_module_maybe != nullptr) | ||
| 171 | current_module = prev_module_maybe; | ||
| 172 | |||
| 173 | current_frame = current_frame->prev_frame(); | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 156 | std::shared_ptr<const type_descriptor_t> vm_thread_t::type_desc() | 177 | std::shared_ptr<const type_descriptor_t> vm_thread_t::type_desc() |
| 157 | { | 178 | { |
| 158 | return intrinsic_type_desc::type<vm_thread_t>(); | 179 | return intrinsic_type_desc::type<vm_thread_t>(); |
| @@ -252,17 +273,17 @@ vm_thread_state_t vm_thread_t::execute(vm_t &virtual_machine, const uint32_t qua · 93 unmodified lines | |||
| 252 | catch (const unhandled_user_exception &uue) | 273 | catch (const unhandled_user_exception &uue) |
| 253 | { | 274 | { |
| 254 | // [TODO] Store the exception | 275 | // [TODO] Store the exception |
| 255 | std::printf("%s - %s in %s at instruction %d\n", uue.what(), uue.exception_id, uue.module_name, uue.program_counter); | 276 | std::fprintf(stderr, "%s - %s in %s at instruction %d\n", uue.what(), uue.exception_id, uue.module_name, uue.program_counter); |
| 256 | _registers.current_thread_state = vm_thread_state_t::broken; | 277 | _registers.current_thread_state = vm_thread_state_t::broken; |
| 257 | } | 278 | } |
| 258 | catch (const index_out_of_range_memory &ioor) | 279 | catch (const index_out_of_range_memory &ioor) |
| 259 | { | 280 | { |
| 260 | std::printf("%s - %d [%d,%d]\n", ioor.what(), ioor.invalid_value, ioor.valid_min, ioor.valid_max); | 281 | std::fprintf(stderr, "%s - %d [%d,%d]\n", ioor.what(), ioor.invalid_value, ioor.valid_min, ioor.valid_max); |
| 261 | _registers.current_thread_state = vm_thread_state_t::broken; | 282 | _registers.current_thread_state = vm_thread_state_t::broken; |
| 262 | } | 283 | } |
| 263 | catch (const vm_user_exception &ue) | 284 | catch (const vm_user_exception &ue) |
| 264 | { | 285 | { |
| 265 | std::printf("%s\n", ue.what()); | 286 | std::fprintf(stderr, "%s\n", ue.what()); |
| 266 | _registers.current_thread_state = vm_thread_state_t::broken; | 287 | _registers.current_thread_state = vm_thread_state_t::broken; |
| 267 | } | 288 | } |
| 268 | 289 | ||