diff options
author | Ali Mohammad Pur <ali.mpfard@gmail.com> | 2021-06-01 20:08:24 +0430 |
---|---|---|
committer | Ali Mohammad Pur <Ali.mpfard@gmail.com> | 2021-06-02 16:09:16 +0430 |
commit | b250a6ae7e02e4fca5b668f0fd2da9fe1940bb6f (patch) | |
tree | bf48da00890add9e7bf6fbe5699b3d1d3dc55180 /Userland | |
parent | 56bf80251c14847e8a1fa7f07378941aa9c60d37 (diff) | |
download | serenity-b250a6ae7e02e4fca5b668f0fd2da9fe1940bb6f.zip |
wasm: Add a way to create dummy function exports
This should allow running modules with their imports stubbed out
in wasm, to debug them.
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibWasm/Types.h | 2 | ||||
-rw-r--r-- | Userland/Utilities/wasm.cpp | 82 |
2 files changed, 82 insertions, 2 deletions
diff --git a/Userland/Libraries/LibWasm/Types.h b/Userland/Libraries/LibWasm/Types.h index bb0299b38a..e9142ac504 100644 --- a/Userland/Libraries/LibWasm/Types.h +++ b/Userland/Libraries/LibWasm/Types.h @@ -499,7 +499,7 @@ class ImportSection { public: class Import { public: - using ImportDesc = Variant<TypeIndex, TableType, MemoryType, GlobalType>; + using ImportDesc = Variant<TypeIndex, TableType, MemoryType, GlobalType, FunctionType>; Import(String module, String name, ImportDesc description) : m_module(move(module)) , m_name(move(name)) diff --git a/Userland/Utilities/wasm.cpp b/Userland/Utilities/wasm.cpp index 5b1d7f786d..8521c8b5ac 100644 --- a/Userland/Utilities/wasm.cpp +++ b/Userland/Utilities/wasm.cpp @@ -49,11 +49,14 @@ static void sigint_handler(int) g_continue = false; } -static bool post_interpret_hook(Wasm::Configuration&, Wasm::InstructionPointer&, const Wasm::Instruction&, const Wasm::Interpreter& interpreter) +static bool post_interpret_hook(Wasm::Configuration&, Wasm::InstructionPointer& ip, const Wasm::Instruction& instr, const Wasm::Interpreter& interpreter) { if (interpreter.did_trap()) { g_continue = false; const_cast<Wasm::Interpreter&>(interpreter).clear_trap(); + warnln("Trapped when executing ip={}", ip); + g_printer.print(instr); + warnln(""); } return true; } @@ -274,6 +277,7 @@ int main(int argc, char* argv[]) String exported_function_to_execute; Vector<u64> values_to_push; Vector<String> modules_to_link_in; + HashMap<Wasm::Linker::Name, Wasm::HostFunction> exported_host_functions; Core::ArgsParser parser; parser.add_positional_argument(filename, "File name to parse", "file"); @@ -309,6 +313,71 @@ int main(int argc, char* argv[]) return false; }, }); + parser.add_option(Core::ArgsParser::Option { + .requires_argument = true, + .help_string = "Export a noop function that returns default-initialised values (module!name::t,t,t...:t,t,t...)", + .long_name = "export-noop", + .short_name = 0, + .value_name = "module!name:atypes:rtypes", + .accept_value = [&](const char* str) -> bool { + GenericLexer lexer { str }; + auto name = lexer.consume_until("::"); + auto parts = name.split_view('!'); + if (parts.size() != 2) { + warnln("Expected a two-part name module!name, got '{}'", name); + return false; + } + auto module_name = parts[0]; + auto export_name = parts[1]; + + auto arg_types = lexer.consume_until(":").split_view(','); + auto ret_types = lexer.consume_all().split_view(','); + Vector<Wasm::ValueType> argument_types, return_types; + for (auto& name : arg_types) { + if (name == "i32") { + argument_types.empend(Wasm::ValueType::Kind::I32); + } else if (name == "i64") { + argument_types.empend(Wasm::ValueType::Kind::I64); + } else if (name == "f32") { + argument_types.empend(Wasm::ValueType::Kind::F32); + } else if (name == "f64") { + argument_types.empend(Wasm::ValueType::Kind::F64); + } else { + warnln("Unknown type '{}'", name); + return false; + } + } + for (auto& name : ret_types) { + if (name == "i32") { + return_types.empend(Wasm::ValueType::Kind::I32); + } else if (name == "i64") { + return_types.empend(Wasm::ValueType::Kind::I64); + } else if (name == "f32") { + return_types.empend(Wasm::ValueType::Kind::F32); + } else if (name == "f64") { + return_types.empend(Wasm::ValueType::Kind::F64); + } else { + warnln("Unknown type '{}'", name); + return false; + } + } + + Wasm::FunctionType function_type { argument_types, return_types }; + exported_host_functions.set( + Wasm::Linker::Name { module_name, export_name, function_type }, + Wasm::HostFunction { + [&](auto&, auto&) -> Wasm::Result { + Vector<Wasm::Value> values; + values.ensure_capacity(return_types.size()); + for (auto& type : return_types) + values.empend(type, 0ull); + return Wasm::Result { move(values) }; + }, + function_type }); + + return true; + }, + }); parser.parse(argc, argv); if (debug && exported_function_to_execute.is_empty()) { @@ -365,9 +434,20 @@ int main(int argc, char* argv[]) linked_instances.append(instantiation_result.release_value()); } + HashMap<Wasm::Linker::Name, Wasm::ExternValue> exports; + for (auto& entry : exported_host_functions) { + auto address = machine.store().allocate(move(entry.value)); + if (!address.has_value()) { + warnln("Could not export {}/{}", entry.key.module, entry.key.name); + return 1; + } + exports.set(entry.key, *address); + } + Wasm::Linker linker { parse_result.value() }; for (auto& instance : linked_instances) linker.link(instance); + linker.link(exports); auto link_result = linker.finish(); if (link_result.is_error()) { warnln("Linking main module failed"); |