Unified · Split
| @@ -304,7 +304,7 @@ namespace · 303 unmodified lines | |||
| 304 | 304 | ||
| 305 | void cmd_term(const std::vector<std::string> &, dbg_cmd_cxt_t &) | 305 | void cmd_term(const std::vector<std::string> &, dbg_cmd_cxt_t &) |
| 306 | { | 306 | { |
| 307 | throw vm_user_exception{ "Debugger signaled VM termination" }; | 307 | throw vm_term_request{}; |
| 308 | } | 308 | } |
| 309 | 309 | ||
| 310 | void cmd_print_registers(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt) | 310 | void cmd_print_registers(const std::vector<std::string> &, dbg_cmd_cxt_t &cxt) |
| @@ -128,6 +128,18 @@ namespace disvm · 127 unmodified lines | |||
| 128 | const char *module_name; | 128 | const char *module_name; |
| 129 | const vm_pc_t program_counter; | 129 | const vm_pc_t program_counter; |
| 130 | }; | 130 | }; |
| 131 | |||
| 132 | class vm_term_request final : public vm_user_exception | ||
| 133 | { | ||
| 134 | public: | ||
| 135 | explicit vm_term_request() | ||
| 136 | : vm_user_exception("VM termination requested") | ||
| 137 | { } | ||
| 138 | |||
| 139 | explicit vm_term_request(const char *msg) | ||
| 140 | : vm_user_exception(msg) | ||
| 141 | { } | ||
| 142 | }; | ||
| 131 | } | 143 | } |
| 132 | } | 144 | } |
| 133 | 145 | ||
| @@ -717,7 +717,7 @@ namespace disvm · 716 unmodified lines | |||
| 717 | exiting, // exit instruction | 717 | exiting, // exit instruction |
| 718 | empty_stack, | 718 | empty_stack, |
| 719 | 719 | ||
| 720 | broken, // thread crashed | 720 | broken, // thread crashed - the scheduler is free to terminate the entire VM if any thread enters this state. |
| 721 | }; | 721 | }; |
| 722 | 722 | ||
| 723 | // Forward declaration | 723 | // Forward declaration |
| @@ -787,6 +787,10 @@ namespace disvm · 63 unmodified lines | |||
| 787 | 787 | ||
| 788 | vm_thread_state_t get_state() const; | 788 | vm_thread_state_t get_state() const; |
| 789 | 789 | ||
| 790 | // This function will only return a non-null | ||
| 791 | // value if this thread is in the broken state. | ||
| 792 | const char *get_error_message() const; | ||
| 793 | |||
| 790 | uint32_t get_thread_id() const; | 794 | uint32_t get_thread_id() const; |
| 791 | 795 | ||
| 792 | uint32_t get_parent_thread_id() const; | 796 | uint32_t get_parent_thread_id() const; |
| @@ -794,9 +798,10 @@ namespace disvm · 1 unmodified line | |||
| 794 | const vm_registers_t& get_registers() const; | 798 | const vm_registers_t& get_registers() const; |
| 795 | 799 | ||
| 796 | private: | 800 | private: |
| 801 | vm_registers_t _registers; | ||
| 797 | const uint32_t _thread_id; | 802 | const uint32_t _thread_id; |
| 798 | const uint32_t _parent_thread_id; | 803 | const uint32_t _parent_thread_id; |
| 799 | vm_registers_t _registers; | 804 | char *_error_message; |
| 800 | }; | 805 | }; |
| 801 | 806 | ||
| 802 | // | 807 | // |
| @@ -49,6 +49,7 @@ namespace disvm · 48 unmodified lines | |||
| 49 | 49 | ||
| 50 | thread_begin, // value1: const vm_thread_t | 50 | thread_begin, // value1: const vm_thread_t |
| 51 | thread_end, // value1: const vm_thread_t | 51 | thread_end, // value1: const vm_thread_t |
| 52 | thread_broken, // value1: const vm_thread_t | ||
| 52 | 53 | ||
| 53 | exception_raised, // value1: vm_registers_t | 54 | exception_raised, // value1: vm_registers_t |
| 54 | // value2: const vm_string_t - exception ID | 55 | // value2: const vm_string_t - exception ID |
| @@ -216,8 +216,6 @@ namespace · 215 unmodified lines | |||
| 216 | if (!success) | 216 | if (!success) |
| 217 | throw module_reader_exception{ "Failed to read magic number" }; | 217 | throw module_reader_exception{ "Failed to read magic number" }; |
| 218 | 218 | ||
| 219 | assert(header.magic_number == magic_number_constants::xmagic || header.magic_number == magic_number_constants::smagic); | ||
| 220 | |||
| 221 | // If the object file is signed, read in the signature. | 219 | // If the object file is signed, read in the signature. |
| 222 | if (header.magic_number == magic_number_constants::smagic) | 220 | if (header.magic_number == magic_number_constants::smagic) |
| 223 | { | 221 | { |
| @@ -228,10 +226,14 @@ namespace · 4 unmodified lines | |||
| 228 | const auto bytesRead = reader.get_next_bytes(header.Signature.length, header.Signature.signature.get()); | 226 | const auto bytesRead = reader.get_next_bytes(header.Signature.length, header.Signature.signature.get()); |
| 229 | if (bytesRead != header.Signature.length) throw module_reader_exception{ "Failed to read full signature" }; | 227 | if (bytesRead != header.Signature.length) throw module_reader_exception{ "Failed to read full signature" }; |
| 230 | } | 228 | } |
| 231 | else | 229 | else if (header.magic_number == magic_number_constants::xmagic) |
| 232 | { | 230 | { |
| 233 | header.Signature.length = word_t{ 0 }; | 231 | header.Signature.length = word_t{ 0 }; |
| 234 | } | 232 | } |
| 233 | else | ||
| 234 | { | ||
| 235 | throw module_reader_exception{ "Invalid magic number in module" }; | ||
| 236 | } | ||
| 235 | 237 | ||
| 236 | auto runtime_flags = operand_t{}; | 238 | auto runtime_flags = operand_t{}; |
| 237 | std::tie(success, runtime_flags) = read_next_operand(reader); | 239 | std::tie(success, runtime_flags) = read_next_operand(reader); |
| @@ -46,6 +46,13 @@ void default_scheduler_t::worker_main(default_scheduler_t &instance) · 45 unmodified lines | |||
| 46 | current_thread->vm_thread->execute(instance._vm, instance._vm_thread_quanta); | 46 | current_thread->vm_thread->execute(instance._vm, instance._vm_thread_quanta); |
| 47 | } | 47 | } |
| 48 | } | 48 | } |
| 49 | catch (const vm_term_request &te) | ||
| 50 | { | ||
| 51 | std::cerr << te.what() << std::endl; | ||
| 52 | |||
| 53 | instance._terminating = true; | ||
| 54 | instance._worker_event.notify_all(); | ||
| 55 | } | ||
| 49 | catch (const vm_system_exception &se) | 56 | catch (const vm_system_exception &se) |
| 50 | { | 57 | { |
| 51 | std::stringstream err_msg; | 58 | std::stringstream err_msg; |
| @@ -428,12 +435,12 @@ bool default_scheduler_t::enqueue_thread_unsafe(std::shared_ptr<thread_instance_ · 376 unmodified lines | |||
| 428 | 435 | ||
| 429 | case vm_thread_state_t::broken: | 436 | case vm_thread_state_t::broken: |
| 430 | { | 437 | { |
| 431 | _non_runnable_vm_thread_ids.push_front(thread_id); | ||
| 432 | |||
| 433 | if (debug::is_component_tracing_enabled<debug::component_trace_t::scheduler>()) | 438 | if (debug::is_component_tracing_enabled<debug::component_trace_t::scheduler>()) |
| 434 | debug::log_msg(debug::component_trace_t::scheduler, debug::log_level_t::debug, "scheduler: broken: %d\n", thread_id); | 439 | debug::log_msg(debug::component_trace_t::scheduler, debug::log_level_t::debug, "scheduler: broken: %d\n", thread_id); |
| 435 | 440 | ||
| 436 | break; | 441 | auto err_msg = thread_instance->vm_thread->get_error_message(); |
| 442 | assert(err_msg != nullptr); | ||
| 443 | throw vm_term_request{ err_msg }; | ||
| 437 | } | 444 | } |
| 438 | 445 | ||
| 439 | case vm_thread_state_t::release: | 446 | case vm_thread_state_t::release: |
| @@ -13,7 +13,6 @@ · 12 unmodified lines | |||
| 13 | #include <condition_variable> | 13 | #include <condition_variable> |
| 14 | #include <vector> | 14 | #include <vector> |
| 15 | #include <deque> | 15 | #include <deque> |
| 16 | #include <forward_list> | ||
| 17 | #include <unordered_set> | 16 | #include <unordered_set> |
| 18 | #include <unordered_map> | 17 | #include <unordered_map> |
| 19 | #include <atomic> | 18 | #include <atomic> |
| @@ -96,7 +95,6 @@ namespace disvm · 76 unmodified lines | |||
| 96 | std::size_t _gc_counter; | 95 | std::size_t _gc_counter; |
| 97 | 96 | ||
| 98 | std::unordered_set<uint32_t> _blocked_vm_thread_ids; | 97 | std::unordered_set<uint32_t> _blocked_vm_thread_ids; |
| 99 | std::forward_list<uint32_t> _non_runnable_vm_thread_ids; | ||
| 100 | 98 | ||
| 101 | using all_thread_map_t = std::unordered_map<uint32_t, std::shared_ptr<thread_instance_t>>; | 99 | using all_thread_map_t = std::unordered_map<uint32_t, std::shared_ptr<thread_instance_t>>; |
| 102 | all_thread_map_t _all_vm_threads; | 100 | all_thread_map_t _all_vm_threads; |
| @@ -111,6 +111,7 @@ vm_thread_t::vm_thread_t( · 110 unmodified lines | |||
| 111 | vm_module_ref_t &entry, | 111 | vm_module_ref_t &entry, |
| 112 | uint32_t parent_thread_id) | 112 | uint32_t parent_thread_id) |
| 113 | : vm_alloc_t(vm_thread_t::type_desc()) | 113 | : vm_alloc_t(vm_thread_t::type_desc()) |
| 114 | , _error_message{ nullptr } | ||
| 114 | , _parent_thread_id{ parent_thread_id } | 115 | , _parent_thread_id{ parent_thread_id } |
| 115 | , _registers{ *this, entry } | 116 | , _registers{ *this, entry } |
| 116 | , _thread_id{ get_unique_thread_id() } | 117 | , _thread_id{ get_unique_thread_id() } |
| @@ -135,6 +136,7 @@ vm_thread_t::vm_thread_t( · 18 unmodified lines | |||
| 135 | const vm_frame_t &initial_frame, | 136 | const vm_frame_t &initial_frame, |
| 136 | vm_pc_t start_pc) | 137 | vm_pc_t start_pc) |
| 137 | : vm_alloc_t(vm_thread_t::type_desc()) | 138 | : vm_alloc_t(vm_thread_t::type_desc()) |
| 139 | , _error_message{ nullptr } | ||
| 138 | , _parent_thread_id{ parent_thread_id } | 140 | , _parent_thread_id{ parent_thread_id } |
| 139 | , _registers{ *this, entry } | 141 | , _registers{ *this, entry } |
| 140 | , _thread_id{ get_unique_thread_id() } | 142 | , _thread_id{ get_unique_thread_id() } |
| @@ -162,6 +164,9 @@ vm_thread_t::~vm_thread_t() · 21 unmodified lines | |||
| 162 | { | 164 | { |
| 163 | if (debug::is_component_tracing_enabled<debug::component_trace_t::thread>()) | 165 | if (debug::is_component_tracing_enabled<debug::component_trace_t::thread>()) |
| 164 | debug::log_msg(debug::component_trace_t::thread, debug::log_level_t::debug, "destroy: vm thread: %d %d\n", _thread_id, _parent_thread_id); | 166 | debug::log_msg(debug::component_trace_t::thread, debug::log_level_t::debug, "destroy: vm thread: %d %d\n", _thread_id, _parent_thread_id); |
| 167 | |||
| 168 | free_memory(_error_message); | ||
| 169 | debug::assign_debug_pointer(&_error_message); | ||
| 165 | } | 170 | } |
| 166 | 171 | ||
| 167 | namespace | 172 | namespace |
| @@ -214,6 +219,7 @@ namespace · 46 unmodified lines | |||
| 214 | 219 | ||
| 215 | vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta) | 220 | vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta) |
| 216 | { | 221 | { |
| 222 | const auto max_error_message = std::size_t{ 1024 }; | ||
| 217 | _registers.current_thread_state = vm_thread_state_t::running; | 223 | _registers.current_thread_state = vm_thread_state_t::running; |
| 218 | _registers.current_thread_quanta = quanta; | 224 | _registers.current_thread_quanta = quanta; |
| 219 | assert(_registers.pc != runtime_constants::invalid_program_counter); | 225 | assert(_registers.pc != runtime_constants::invalid_program_counter); |
| @@ -226,27 +232,27 @@ vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta) · 6 unmodified lines | |||
| 226 | else | 232 | else |
| 227 | execute_impl<execute_with_tool_t>(_registers, vm); | 233 | execute_impl<execute_with_tool_t>(_registers, vm); |
| 228 | } | 234 | } |
| 235 | catch (const vm_term_request &) | ||
| 236 | { | ||
| 237 | throw; | ||
| 238 | } | ||
| 229 | catch (const unhandled_user_exception &uue) | 239 | catch (const unhandled_user_exception &uue) |
| 230 | { | 240 | { |
| 231 | // [TODO] Store the exception | 241 | _error_message = calloc_memory<char>(max_error_message); |
| 232 | std::fprintf(stderr, "%s - '%s' in %s at instruction %d\n", uue.what(), uue.exception_id, uue.module_name, uue.program_counter); | 242 | std::snprintf(_error_message, max_error_message, "%s - '%s' in %s at instruction %d", uue.what(), uue.exception_id, uue.module_name, uue.program_counter); |
| 233 | _registers.current_thread_state = vm_thread_state_t::broken; | 243 | _registers.current_thread_state = vm_thread_state_t::broken; |
| 234 | if (tool_dispatch != nullptr) | ||
| 235 | tool_dispatch->on_thread_broken(*this); | ||
| 236 | } | 244 | } |
| 237 | catch (const index_out_of_range_memory &ioor) | 245 | catch (const index_out_of_range_memory &ioor) |
| 238 | { | 246 | { |
| 239 | std::fprintf(stderr, "%s - %d [%d,%d]\n", ioor.what(), ioor.invalid_value, ioor.valid_min, ioor.valid_max); | 247 | _error_message = calloc_memory<char>(max_error_message); |
| 248 | std::snprintf(_error_message, max_error_message, "%s - %d [%d,%d]", ioor.what(), ioor.invalid_value, ioor.valid_min, ioor.valid_max); | ||
| 240 | _registers.current_thread_state = vm_thread_state_t::broken; | 249 | _registers.current_thread_state = vm_thread_state_t::broken; |
| 241 | if (tool_dispatch != nullptr) | ||
| 242 | tool_dispatch->on_thread_broken(*this); | ||
| 243 | } | 250 | } |
| 244 | catch (const vm_user_exception &ue) | 251 | catch (const vm_user_exception &ue) |
| 245 | { | 252 | { |
| 246 | std::fprintf(stderr, "%s\n", ue.what()); | 253 | _error_message = calloc_memory<char>(max_error_message); |
| 254 | std::snprintf(_error_message, max_error_message, "%s", ue.what()); | ||
| 247 | _registers.current_thread_state = vm_thread_state_t::broken; | 255 | _registers.current_thread_state = vm_thread_state_t::broken; |
| 248 | if (tool_dispatch != nullptr) | ||
| 249 | tool_dispatch->on_thread_broken(*this); | ||
| 250 | } | 256 | } |
| 251 | 257 | ||
| 252 | // Log the execution result | 258 | // Log the execution result |
| @@ -262,16 +268,22 @@ vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta) · 9 unmodified lines | |||
| 262 | _registers.current_thread_state); | 268 | _registers.current_thread_state); |
| 263 | } | 269 | } |
| 264 | 270 | ||
| 265 | // If the thread is still in the running state transition it back to its entry state. | 271 | switch (_registers.current_thread_state) |
| 266 | if (_registers.current_thread_state == vm_thread_state_t::running) | ||
| 267 | { | 272 | { |
| 273 | case vm_thread_state_t::running: | ||
| 268 | _registers.current_thread_state = (tool_dispatch == nullptr) ? vm_thread_state_t::ready : vm_thread_state_t::debug; | 274 | _registers.current_thread_state = (tool_dispatch == nullptr) ? vm_thread_state_t::ready : vm_thread_state_t::debug; |
| 269 | } | 275 | break; |
| 270 | else if (vm_thread_state_t::exiting == _registers.current_thread_state | 276 | |
| 271 | || vm_thread_state_t::empty_stack == _registers.current_thread_state) | 277 | case vm_thread_state_t::empty_stack: |
| 272 | { | 278 | case vm_thread_state_t::exiting: |
| 273 | if (tool_dispatch != nullptr) | 279 | if (tool_dispatch != nullptr) |
| 274 | tool_dispatch->on_thread_end(*this); | 280 | tool_dispatch->on_thread_end(*this); |
| 281 | break; | ||
| 282 | |||
| 283 | case vm_thread_state_t::broken: | ||
| 284 | if (tool_dispatch != nullptr) | ||
| 285 | tool_dispatch->on_thread_broken(*this); | ||
| 286 | break; | ||
| 275 | } | 287 | } |
| 276 | 288 | ||
| 277 | return _registers.current_thread_state; | 289 | return _registers.current_thread_state; |
| @@ -288,6 +300,11 @@ vm_thread_state_t vm_thread_t::get_state() const · 10 unmodified lines | |||
| 288 | return _registers.current_thread_state; | 300 | return _registers.current_thread_state; |
| 289 | } | 301 | } |
| 290 | 302 | ||
| 303 | const char *vm_thread_t::get_error_message() const | ||
| 304 | { | ||
| 305 | return _error_message; | ||
| 306 | } | ||
| 307 | |||
| 291 | uint32_t vm_thread_t::get_thread_id() const | 308 | uint32_t vm_thread_t::get_thread_id() const |
| 292 | { | 309 | { |
| 293 | return _thread_id; | 310 | return _thread_id; |
| @@ -164,8 +164,12 @@ void vm_tool_dispatch_t::on_thread_end(vm_thread_t &t) · 163 unmodified lines | |||
| 164 | _events.fire_event_callbacks(vm_event_t::thread_end, cxt); | 164 | _events.fire_event_callbacks(vm_event_t::thread_end, cxt); |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | void vm_tool_dispatch_t::on_thread_broken(vm_thread_t &) | 167 | void vm_tool_dispatch_t::on_thread_broken(vm_thread_t &t) |
| 168 | { | 168 | { |
| 169 | vm_event_context_t cxt{}; | ||
| 170 | cxt.value1.thread = &t; | ||
| 171 | |||
| 172 | _events.fire_event_callbacks(vm_event_t::thread_broken, cxt); | ||
| 169 | } | 173 | } |
| 170 | 174 | ||
| 171 | void vm_tool_dispatch_t::block_if_thread_suspended(uint32_t thread_id) | 175 | void vm_tool_dispatch_t::block_if_thread_suspended(uint32_t thread_id) |