summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorAli Mohammad Pur <ali.mpfard@gmail.com>2021-06-01 20:08:24 +0430
committerAli Mohammad Pur <Ali.mpfard@gmail.com>2021-06-02 16:09:16 +0430
commitb250a6ae7e02e4fca5b668f0fd2da9fe1940bb6f (patch)
treebf48da00890add9e7bf6fbe5699b3d1d3dc55180 /Userland
parent56bf80251c14847e8a1fa7f07378941aa9c60d37 (diff)
downloadserenity-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.h2
-rw-r--r--Userland/Utilities/wasm.cpp82
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");