Unified · Split
| @@ -322,8 +322,15 @@ namespace · 321 unmodified lines | |||
| 322 | { | 322 | { |
| 323 | auto msg = std::stringstream{}; | 323 | auto msg = std::stringstream{}; |
| 324 | msg << "Modules:\n"; | 324 | msg << "Modules:\n"; |
| 325 | for (auto m : cxt.vm.get_loaded_modules()) | 325 | |
| 326 | msg << " " << m->module_name->str() << "\n"; | 326 | cxt.vm.enum_loaded_modules([&msg](const loaded_vm_module_t &m) |
| 327 | { | ||
| 328 | auto module_instance = m.module.lock(); | ||
| 329 | if (module_instance == nullptr) | ||
| 330 | return; | ||
| 331 | |||
| 332 | msg << std::setw(24) << module_instance->module_name->str() << std::setw(0) << " " << m.origin->str() << "\n"; | ||
| 333 | }); | ||
| 327 | 334 | ||
| 328 | debug_print_info(msg.str()); | 335 | debug_print_info(msg.str()); |
| 329 | } | 336 | } |
| @@ -625,7 +632,7 @@ namespace · 295 unmodified lines | |||
| 625 | { "r", "Print registers", nullptr, nullptr, cmd_print_registers }, | 632 | { "r", "Print registers", nullptr, nullptr, cmd_print_registers }, |
| 626 | { "t", "Print all threads", nullptr, nullptr, cmd_print_threads }, | 633 | { "t", "Print all threads", nullptr, nullptr, cmd_print_threads }, |
| 627 | { "m", "Print all loaded modules", nullptr, nullptr, cmd_print_modules }, | 634 | { "m", "Print all loaded modules", nullptr, nullptr, cmd_print_modules }, |
| 628 | { "sw", "Stack walk/back trace", "bt ([0-9]+|\\*)?", "bt, bt 34, bt *", cmd_stacktrace }, | 635 | { "bt", "Stack walk/back trace for the current or supplied thread", "bt ([0-9]+|\\*)?", "bt, bt 34, bt *", cmd_stacktrace }, |
| 629 | { "st", "Switch to thread", "st [0-9]+", "st 42", cmd_switchthread }, | 636 | { "st", "Switch to thread", "st [0-9]+", "st 42", cmd_switchthread }, |
| 630 | { "d", "Disassemble the next/previous N instructions", "d (-?[0-9]+)?", "d, d -4, d 5", cmd_disassemble }, | 637 | { "d", "Disassemble the next/previous N instructions", "d (-?[0-9]+)?", "d, d -4, d 5", cmd_disassemble }, |
| 631 | { "x", "Examine memory", "x [mp|fp] [0-9]+ ([0-9]+)?", "x mp 3, x fp 20 6", cmd_examine }, | 638 | { "x", "Examine memory", "x [mp|fp] [0-9]+ ([0-9]+)?", "x mp 3, x fp 20 6", cmd_examine }, |
| @@ -35,6 +35,19 @@ namespace disvm · 34 unmodified lines | |||
| 35 | const char * const label; // Optional | 35 | const char * const label; // Optional |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | // Loaded module reference | ||
| 39 | class loaded_vm_module_t final | ||
| 40 | { | ||
| 41 | public: | ||
| 42 | // Origin of module | ||
| 43 | std::unique_ptr<runtime::vm_string_t> origin; | ||
| 44 | |||
| 45 | // Weak reference to a loaded module | ||
| 46 | std::weak_ptr<runtime::vm_module_t> module; | ||
| 47 | }; | ||
| 48 | |||
| 49 | using loaded_vm_module_callback_t = std::function<void(const loaded_vm_module_t&)>; | ||
| 50 | |||
| 38 | // Virtual machine | 51 | // Virtual machine |
| 39 | class vm_t final | 52 | class vm_t final |
| 40 | { | 53 | { |
| @@ -71,9 +84,11 @@ namespace disvm · 30 unmodified lines | |||
| 71 | // Load the module at the supplied path into the virtual machine | 84 | // Load the module at the supplied path into the virtual machine |
| 72 | std::shared_ptr<runtime::vm_module_t> load_module(const char *path); | 85 | std::shared_ptr<runtime::vm_module_t> load_module(const char *path); |
| 73 | 86 | ||
| 74 | // Get a collection of all currently loaded modules. | 87 | // Enumerate all loaded modules - this can include references to modules that |
| 75 | // Note this will only include modules that have been loaded by a call to vm_t::load_module. | 88 | // have been unloaded due to no longer being used. If the module instance is null, the |
| 76 | std::vector<std::shared_ptr<runtime::vm_module_t>> get_loaded_modules() const; | 89 | // module is no longer loaded. |
| 90 | // Note this will only enumerate modules that have been loaded by a call to vm_t::load_module. | ||
| 91 | void enum_loaded_modules(loaded_vm_module_callback_t callback) const; | ||
| 77 | 92 | ||
| 78 | // Access the scheduler control for this VM. | 93 | // Access the scheduler control for this VM. |
| 79 | runtime::vm_scheduler_control_t &get_scheduler_control() const; | 94 | runtime::vm_scheduler_control_t &get_scheduler_control() const; |
| @@ -94,25 +109,7 @@ namespace disvm · 14 unmodified lines | |||
| 94 | private: | 109 | private: |
| 95 | const runtime::vm_thread_t &schedule_thread(std::unique_ptr<runtime::vm_thread_t> thread); | 110 | const runtime::vm_thread_t &schedule_thread(std::unique_ptr<runtime::vm_thread_t> thread); |
| 96 | 111 | ||
| 97 | // Loaded module reference | 112 | using loaded_modules_t = std::forward_list<loaded_vm_module_t>; |
| 98 | class loaded_module_t final | ||
| 99 | { | ||
| 100 | public: | ||
| 101 | loaded_module_t(std::unique_ptr<runtime::vm_string_t> origin, std::shared_ptr<runtime::vm_module_t> module); | ||
| 102 | loaded_module_t(const loaded_module_t &) = delete; | ||
| 103 | loaded_module_t &operator=(const loaded_module_t &) = delete; | ||
| 104 | |||
| 105 | loaded_module_t(loaded_module_t &&); | ||
| 106 | ~loaded_module_t(); | ||
| 107 | |||
| 108 | // Origin of module | ||
| 109 | std::unique_ptr<runtime::vm_string_t> origin; | ||
| 110 | |||
| 111 | // Weak reference to a loaded module | ||
| 112 | std::weak_ptr<runtime::vm_module_t> module; | ||
| 113 | }; | ||
| 114 | |||
| 115 | using loaded_modules_t = std::forward_list<loaded_module_t>; | ||
| 116 | mutable std::mutex _modules_lock; | 113 | mutable std::mutex _modules_lock; |
| 117 | loaded_modules_t _modules; | 114 | loaded_modules_t _modules; |
| 118 | 115 | ||
| @@ -20,25 +20,6 @@ · 19 unmodified lines | |||
| 20 | using namespace disvm; | 20 | using namespace disvm; |
| 21 | using namespace disvm::runtime; | 21 | using namespace disvm::runtime; |
| 22 | 22 | ||
| 23 | vm_t::loaded_module_t::loaded_module_t(std::unique_ptr<runtime::vm_string_t> origin, std::shared_ptr<runtime::vm_module_t> module) | ||
| 24 | : origin{ std::move(origin) } | ||
| 25 | , module{ module } | ||
| 26 | { | ||
| 27 | assert(this->origin != nullptr); | ||
| 28 | } | ||
| 29 | |||
| 30 | vm_t::loaded_module_t::loaded_module_t(loaded_module_t &&other) | ||
| 31 | : origin{ std::move(other.origin) } | ||
| 32 | , module{ std::move(other.module) } | ||
| 33 | { | ||
| 34 | } | ||
| 35 | |||
| 36 | vm_t::loaded_module_t::~loaded_module_t() | ||
| 37 | { | ||
| 38 | if (origin != nullptr) | ||
| 39 | origin->release(); | ||
| 40 | } | ||
| 41 | |||
| 42 | vm_t::vm_t( | 23 | vm_t::vm_t( |
| 43 | create_vm_interface_callback_t<runtime::vm_scheduler_t> create_scheduler, | 24 | create_vm_interface_callback_t<runtime::vm_scheduler_t> create_scheduler, |
| 44 | create_vm_interface_callback_t<runtime::vm_garbage_collector_t> create_gc) | 25 | create_vm_interface_callback_t<runtime::vm_garbage_collector_t> create_gc) |
| @@ -80,6 +61,13 @@ vm_t::~vm_t() · 35 unmodified lines | |||
| 80 | // Release the scheduler first since it could be using the gc instance. | 61 | // Release the scheduler first since it could be using the gc instance. |
| 81 | _scheduler.reset(); | 62 | _scheduler.reset(); |
| 82 | _gc.reset(); | 63 | _gc.reset(); |
| 64 | |||
| 65 | std::lock_guard<std::mutex> lock{ _modules_lock }; | ||
| 66 | for (auto &m : _modules) | ||
| 67 | { | ||
| 68 | if (m.origin != nullptr) | ||
| 69 | m.origin->release(); | ||
| 70 | } | ||
| 83 | } | 71 | } |
| 84 | 72 | ||
| 85 | vm_version_t vm_t::get_version() const | 73 | vm_version_t vm_t::get_version() const |
| @@ -139,7 +127,7 @@ std::shared_ptr<runtime::vm_module_t> vm_t::load_module(const char *path) · 53 unmodified lines | |||
| 139 | throw vm_user_exception{ "Invalid module path" }; | 127 | throw vm_user_exception{ "Invalid module path" }; |
| 140 | 128 | ||
| 141 | std::lock_guard<std::mutex> lock{ _modules_lock }; | 129 | std::lock_guard<std::mutex> lock{ _modules_lock }; |
| 142 | 130 | ||
| 143 | // Check if the module is already loaded. | 131 | // Check if the module is already loaded. |
| 144 | auto iter = std::begin(_modules); | 132 | auto iter = std::begin(_modules); |
| 145 | while (iter != std::end(_modules)) | 133 | while (iter != std::end(_modules)) |
| @@ -182,26 +170,21 @@ std::shared_ptr<runtime::vm_module_t> vm_t::load_module(const char *path) · 36 unmodified lines | |||
| 182 | _tool_dispatch->on_module_load(new_module, *path_local); | 170 | _tool_dispatch->on_module_load(new_module, *path_local); |
| 183 | } | 171 | } |
| 184 | 172 | ||
| 185 | _modules.push_front(std::move(loaded_module_t{ std::move(path_local), new_module })); | 173 | _modules.push_front(std::move(loaded_vm_module_t{ std::move(path_local), new_module })); |
| 186 | 174 | ||
| 187 | debug::log_msg(debug::component_trace_t::module, debug::log_level_t::debug, "load: vm module: >>%s<<\n", path); | 175 | debug::log_msg(debug::component_trace_t::module, debug::log_level_t::debug, "load: vm module: >>%s<<\n", path); |
| 188 | 176 | ||
| 189 | return new_module; | 177 | return new_module; |
| 190 | } | 178 | } |
| 191 | 179 | ||
| 192 | std::vector<std::shared_ptr<runtime::vm_module_t>> vm_t::get_loaded_modules() const | 180 | void vm_t::enum_loaded_modules(loaded_vm_module_callback_t callback) const |
| 193 | { | 181 | { |
| 194 | auto result = std::vector<std::shared_ptr<runtime::vm_module_t>>{}; | 182 | if (callback == nullptr) |
| 183 | throw vm_system_exception{ "Callback should not be null" }; | ||
| 195 | 184 | ||
| 196 | std::lock_guard<std::mutex> lock{ _modules_lock }; | 185 | std::lock_guard<std::mutex> lock{ _modules_lock }; |
| 197 | for (auto &m : _modules) | 186 | for (auto &m : _modules) |
| 198 | { | 187 | callback(m); |
| 199 | auto loaded_module_maybe = m.module.lock(); | ||
| 200 | if (loaded_module_maybe != nullptr) | ||
| 201 | result.push_back(loaded_module_maybe); | ||
| 202 | } | ||
| 203 | |||
| 204 | return result; | ||
| 205 | } | 188 | } |
| 206 | 189 | ||
| 207 | runtime::vm_scheduler_control_t &vm_t::get_scheduler_control() const | 190 | runtime::vm_scheduler_control_t &vm_t::get_scheduler_control() const |
| @@ -422,7 +422,9 @@ std::shared_ptr<const type_descriptor_t> type_descriptor_t::create( · 421 unmodified lines | |||
| 422 | free_memory(const_cast<byte_t *>(td->pointer_map)); | 422 | free_memory(const_cast<byte_t *>(td->pointer_map)); |
| 423 | debug::assign_debug_pointer(const_cast<byte_t **>(&td->pointer_map)); | 423 | debug::assign_debug_pointer(const_cast<byte_t **>(&td->pointer_map)); |
| 424 | 424 | ||
| 425 | debug::log_msg(debug::component_trace_t::memory, debug::log_level_t::debug, "destroy: type descriptor\n"); | 425 | if (debug::is_component_tracing_enabled<debug::component_trace_t::memory>()) |
| 426 | debug::log_msg(debug::component_trace_t::memory, debug::log_level_t::debug, "destroy: type descriptor\n"); | ||
| 427 | |||
| 426 | free_memory(td); | 428 | free_memory(td); |
| 427 | } | 429 | } |
| 428 | } deleter; | 430 | } deleter; |
| @@ -451,5 +453,6 @@ type_descriptor_t::type_descriptor_t( · 22 unmodified lines | |||
| 451 | , pointer_map{ pointer_map } | 453 | , pointer_map{ pointer_map } |
| 452 | , finalizer{ finalizer } | 454 | , finalizer{ finalizer } |
| 453 | { | 455 | { |
| 454 | debug::log_msg(debug::component_trace_t::memory, debug::log_level_t::debug, "init: type descriptor\n"); | 456 | if (debug::is_component_tracing_enabled<debug::component_trace_t::memory>()) |
| 457 | debug::log_msg(debug::component_trace_t::memory, debug::log_level_t::debug, "init: type descriptor\n"); | ||
| 455 | } | 458 | } |