Unified · Split
| @@ -73,6 +73,9 @@ namespace · 72 unmodified lines | ||
| 73 | 73 | e.header.entry_type = 0; |
| 74 | 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 | 79 | // Inherit the stack extent from the command module and add the entry frame size. |
| 77 | 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 | 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 | 659 | // VM stack |
| 665 | 660 | class vm_stack_t final |
| 666 | 661 | { |
| @@ -680,10 +675,6 @@ namespace disvm · 13 unmodified lines | ||
| 680 | 675 | // Return the current top frame. |
| 681 | 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 | 678 | private: |
| 688 | 679 | std::unique_ptr<vm_alloc_t> _mem; |
| 689 | 680 | }; |
| @@ -741,6 +732,14 @@ namespace disvm · 51 unmodified lines | ||
| 741 | 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 | 743 | // VM thread |
| 745 | 744 | class vm_thread_t final : public vm_alloc_t |
| 746 | 745 | { |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | // |
| 6 | 6 | |
| 7 | 7 | #include <debug.h> |
| 8 | +#include <sstream> | |
| 8 | 9 | #include <exceptions.h> |
| 9 | 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 | 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 | 67 | instance._terminating = true; |
| 51 | 68 | instance._worker_event.notify_all(); |
| 52 | 69 | } |
| @@ -89,7 +106,7 @@ default_scheduler_t::~default_scheduler_t() · 36 unmodified lines | ||
| 89 | 106 | bool default_scheduler_t::is_idle() const |
| 90 | 107 | { |
| 91 | 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 | 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 | 295 | auto layout = dynamic_cast<vm_stack_layout *>(_mem.get()); |
| 296 | 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 | 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 | 177 | std::shared_ptr<const type_descriptor_t> vm_thread_t::type_desc() |
| 157 | 178 | { |
| 158 | 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 | 273 | catch (const unhandled_user_exception &uue) |
| 253 | 274 | { |
| 254 | 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 | 277 | _registers.current_thread_state = vm_thread_state_t::broken; |
| 257 | 278 | } |
| 258 | 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 | 282 | _registers.current_thread_state = vm_thread_state_t::broken; |
| 262 | 283 | } |
| 263 | 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 | 287 | _registers.current_thread_state = vm_thread_state_t::broken; |
| 267 | 288 | } |
| 268 | 289 | |