History

Change assert to exception if a dis module contains an invalid magic number. Broken threads now terminate the VM using the default scheduler. Tools can not get a callback for broken threads.

arr committed 10 years ago

Commit 096b0c71 parent 9c1abd69 files · +74 −28Browse files

Unified · Split

9 files
  1. src/exec/debugger.cpp +1 −1
  2. src/include/exceptions.h +12 −0
  3. src/include/runtime.h +7 −2
  4. src/include/vm_tools.h +1 −0
  5. src/vm/module_reader.cpp +5 −3
  6. src/vm/scheduler.cpp +10 −3
  7. src/vm/scheduler.h +0 −2
  8. src/vm/thread.cpp +33 −16
  9. src/vm/tool_dispatch.cpp +5 −1
src/exec/debugger.cpp+1−1
@@ -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)
src/include/exceptions.h+12−0
@@ -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
src/include/runtime.h+7−2
@@ -717,7 +717,7 @@ namespace disvm · 716 unmodified lines
717 exiting, // exit instruction717 exiting, // exit instruction
718 empty_stack,718 empty_stack,
719 719
720 broken, // thread crashed720 broken, // thread crashed - the scheduler is free to terminate the entire VM if any thread enters this state.
721 };721 };
722 722
723 // Forward declaration723 // 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 //
src/include/vm_tools.h+1−0
@@ -49,6 +49,7 @@ namespace disvm · 48 unmodified lines
49 49
50 thread_begin, // value1: const vm_thread_t50 thread_begin, // value1: const vm_thread_t
51 thread_end, // value1: const vm_thread_t51 thread_end, // value1: const vm_thread_t
52 thread_broken, // value1: const vm_thread_t
52 53
53 exception_raised, // value1: vm_registers_t54 exception_raised, // value1: vm_registers_t
54 // value2: const vm_string_t - exception ID55 // value2: const vm_string_t - exception ID
src/vm/module_reader.cpp+5−3
@@ -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 else229 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);
src/vm/scheduler.cpp+10−3
@@ -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:
src/vm/scheduler.h+0−2
@@ -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;
src/vm/thread.cpp+33−16
@@ -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
167namespace172namespace
@@ -214,6 +219,7 @@ namespace · 46 unmodified lines
214 219
215vm_thread_state_t vm_thread_t::execute(vm_t &vm, const uint32_t quanta)220vm_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 else232 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 exception241 _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 result258 // 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_state276
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
303const char *vm_thread_t::get_error_message() const
304{
305 return _error_message;
306}
307
291uint32_t vm_thread_t::get_thread_id() const308uint32_t vm_thread_t::get_thread_id() const
292{309{
293 return _thread_id;310 return _thread_id;
src/vm/tool_dispatch.cpp+5−1
@@ -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
167void vm_tool_dispatch_t::on_thread_broken(vm_thread_t &)167void 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
171void vm_tool_dispatch_t::block_if_thread_suspended(uint32_t thread_id)175void vm_tool_dispatch_t::block_if_thread_suspended(uint32_t thread_id)