Skip to content

Commit

Permalink
Implement directory mapping and WASI file functions
Browse files Browse the repository at this point in the history
Refactor the importing of WASI functions to be clearer.
Implement path_open, fd_seek, fd_read, environ_sizes_get, environ_get for file acces.
Implement the mapping of real directories to virtual ones so that WASI can use different directories.
Add flag '--mapdirs' 'real' 'virtual' for mapping directories.
Add flag '--env' for sharing host envrionment variables.
Add flag '--help' for printing available walrus options.
Also improve random_get test to not have a result.

Signed-off-by: Adam Laszlo Kulcsar <kuladam@inf.u-szeged.hu>
  • Loading branch information
kulcsaradam committed Feb 13, 2024
1 parent 4667254 commit 9c89d72
Show file tree
Hide file tree
Showing 14 changed files with 499 additions and 21 deletions.
29 changes: 29 additions & 0 deletions src/runtime/SpecTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class SpecTestFunctionTypes {
I32_RI32,
I32I32_RI32,
I32I32I32I32_RI32,
I32I64I32I32_RI32,
I32I32I32I32I32I64I64I32I32_RI32,
RI32,
I64R,
F32R,
Expand Down Expand Up @@ -88,6 +90,33 @@ class SpecTestFunctionTypes {
result->push_back(Value::Type::I32);
m_vector[index++] = new FunctionType(param, result);
}
{
// I32I64I32I32_RI32
param = new ValueTypeVector();
result = new ValueTypeVector();
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I64);
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
result->push_back(Value::Type::I32);
m_vector[index++] = new FunctionType(param, result);
}
{
// I32I32I32I32I32I64I64I32I32_RI32
param = new ValueTypeVector();
result = new ValueTypeVector();
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I64);
param->push_back(Value::Type::I64);
param->push_back(Value::Type::I32);
param->push_back(Value::Type::I32);
result->push_back(Value::Type::I32);
m_vector[index++] = new FunctionType(param, result);
}
{
// RI32
param = new ValueTypeVector();
Expand Down
47 changes: 43 additions & 4 deletions src/shell/Shell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "wabt/wast-lexer.h"
#include "wabt/wast-parser.h"
#include "wabt/binary-writer.h"
#include "string-view-lite/string_view.h"

struct spectestseps : std::numpunct<char> {
char do_thousands_sep() const { return '_'; }
Expand All @@ -39,6 +40,7 @@ struct ArgParser {

static bool useJIT = false;
static int jitVerbose = 0;
static bool shareHostEnv = false;

using namespace Walrus;

Expand Down Expand Up @@ -999,11 +1001,12 @@ static void runExports(Store* store, const std::string& filename, const std::vec
&data);
}

static void parseArguments(int argc, char* argv[], ArgParser& argParser)
static void parseArguments(int argc, char* argv[], ArgParser& argParser, std::vector<uvwasi_preopen_s>& preopenDirs)
{
const std::vector<nonstd::string_view> args(argv + 1, argv + argc);

for (auto it = args.begin(); it != args.end(); ++it) {
auto it = args.begin();
while (it != args.end()) {
if (*it == "--run-export") {
if (*it == args.back()) {
fprintf(stderr, "error: --run-export requires an argument\n");
Expand All @@ -1018,6 +1021,40 @@ static void parseArguments(int argc, char* argv[], ArgParser& argParser)
jitVerbose = 1;
} else if (*it == "--jit-verbose-color") {
jitVerbose = 2;
} else if (*it == "--mapdirs") {
it++;
while (it != args.end() && nonstd::to_string(*it).find("--") == std::string::npos) {
if (it + 1 == args.end()) {
break;
}

uvwasi_preopen_s preopen;
preopen.real_path = reinterpret_cast<char*>(calloc(1, it->length() + 1));
it->nonstd::sv_lite::string_view::copy(const_cast<char*>(preopen.real_path), it->length());

it++;

preopen.mapped_path = reinterpret_cast<char*>(calloc(1, it->length() + 1));
it->nonstd::sv_lite::string_view::copy(const_cast<char*>(preopen.mapped_path), it->length());
preopenDirs.push_back(preopen);
it++;
}
it--;
} else if (*it == "--env") {
shareHostEnv = true;
} else if (*it == "--help" || *it == "-h") {
fprintf(stdout, "Run a WebAssembly wasm, wat or wast file.\n\n");
fprintf(stdout, "Usage: walrus [OPTIONS] <INPUT>\n\n");
fprintf(stdout, "OPTIONS:\n");
fprintf(stdout, "\t-h, --help\n\t\tShow this message then exit.\n\n");
fprintf(stdout, "\t--jit\n\t\tEnable just-in-time interpretation.\n\n");
fprintf(stdout, "\t--jit-verbose\n\t\tEnable verbose output for just-in-time interpretation.\n\n");
fprintf(stdout, "\t--jit-verbose-color\n\t\tEnable colored verbose output for just-in-time interpretation.\n\n");
fprintf(stdout, "\t--mapdirs <HOST_DIR> <VIRTUAL_DIR>\n\t\tMap real directories to virtual ones for WASI functions to use.\n\t\tExample: ./walrus test.wasm --mapdirs this/real/directory/ this/virtual/directory\n\n");
fprintf(stdout, "\t--env\n\t\tShare host environment to walrus WASI.\n\n");


exit(0);
} else {
auto arg = nonstd::to_string(*it);
if (endsWith(arg, "wat") || endsWith(arg, "wast") || endsWith(arg, "wasm")) {
Expand All @@ -1027,6 +1064,7 @@ static void parseArguments(int argc, char* argv[], ArgParser& argParser)
exit(1);
}
}
++it;
}

if (argParser.fileNames.empty()) {
Expand Down Expand Up @@ -1055,12 +1093,13 @@ int main(int argc, char* argv[])

Engine* engine = new Engine();
Store* store = new Store(engine);
WASI* wasi = new WASI();

std::vector<uvwasi_preopen_s> preopenDirs;
SpecTestFunctionTypes functionTypes;
ArgParser argParser;

parseArguments(argc, argv, argParser);
parseArguments(argc, argv, argParser, preopenDirs);
WASI* wasi = new WASI(preopenDirs, shareHostEnv);

for (const auto& filePath : argParser.fileNames) {
FILE* fp = fopen(filePath.data(), "r");
Expand Down
41 changes: 41 additions & 0 deletions src/wasi/Environ.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace Walrus {

void WASI::environ_sizes_get(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t count = argv[0].asI32();
uint32_t buf = argv[1].asI32();

uvwasi_size_t* uvCount = reinterpret_cast<uvwasi_size_t*>(instance->memory(0)->buffer() + count);
uvwasi_size_t* uvBufSize = reinterpret_cast<uvwasi_size_t*>(instance->memory(0)->buffer() + buf);

result[0] = Value(static_cast<uint16_t>(uvwasi_environ_sizes_get(WASI::m_uvwasi, uvCount, uvBufSize)));
}

void WASI::environ_get(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t env = argv[0].asI32();
uint32_t environBuf = argv[1].asI32();

char** uvEnviron = reinterpret_cast<char**>(instance->memory(0)->buffer() + env);
char* uvEnvironBuf = reinterpret_cast<char*>(instance->memory(0)->buffer() + environBuf);

result[0] = Value(static_cast<uint16_t>(uvwasi_environ_get(WASI::m_uvwasi, uvEnviron, uvEnvironBuf)));
}

} // namespace Walrus
47 changes: 43 additions & 4 deletions src/wasi/Fd.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,52 @@ void WASI::fd_write(ExecutionState& state, Value* argv, Value* result, Instance*
std::vector<uvwasi_ciovec_t> iovs(iovcnt);
for (uint32_t i = 0; i < iovcnt; i++) {
iovs[i].buf = instance->memory(0)->buffer() + *reinterpret_cast<uint32_t*>(instance->memory(0)->buffer() + iovptr + i * 8);
iovs[i].buf_len = *(instance->memory(0)->buffer() + iovptr + 4 + i * 8);
iovs[i].buf_len = *reinterpret_cast<uint32_t*>(instance->memory(0)->buffer() + iovptr + 4 + i * 8);
}

uvwasi_size_t out_addr = *(instance->memory(0)->buffer() + out);
uvwasi_size_t* out_addr = (uvwasi_size_t*)(instance->memory(0)->buffer() + out);

result[0] = Value(static_cast<int16_t>(uvwasi_fd_write(WASI::m_uvwasi, fd, iovs.data(), iovs.size(), &out_addr)));
*(instance->memory(0)->buffer() + out) = out_addr;
result[0] = Value(static_cast<int16_t>(uvwasi_fd_write(WASI::m_uvwasi, fd, iovs.data(), iovs.size(), out_addr)));
*(instance->memory(0)->buffer() + out) = *out_addr;
}

void WASI::fd_read(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t fd = argv[0].asI32();
uint32_t iovptr = argv[1].asI32();
uint32_t iovcnt = argv[2].asI32();
uint32_t out = argv[3].asI32();

std::vector<uvwasi_iovec_t> iovs(iovcnt);
for (uint32_t i = 0; i < iovcnt; i++) {
iovs[i].buf = instance->memory(0)->buffer() + *reinterpret_cast<uint32_t*>(instance->memory(0)->buffer() + iovptr + i * 8);
iovs[i].buf_len = *reinterpret_cast<uint32_t*>(instance->memory(0)->buffer() + iovptr + 4 + i * 8);
}

uvwasi_size_t* out_addr = (uvwasi_size_t*)(instance->memory(0)->buffer() + out);

result[0] = Value(static_cast<int16_t>(uvwasi_fd_read(WASI::m_uvwasi, fd, iovs.data(), iovs.size(), out_addr)));
*(instance->memory(0)->buffer() + out) = *out_addr;
}

void WASI::fd_close(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t fd = argv[0].asI32();

result[0] = Value(static_cast<int16_t>(uvwasi_fd_close(WASI::m_uvwasi, fd)));
}

void WASI::fd_seek(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t fd = argv[0].asI32();
uint64_t fileDelta = argv[1].asI32();
uint32_t whence = argv[2].asI32();
uint64_t newOffset = argv[3].asI32();

uvwasi_filesize_t out_addr = *(instance->memory(0)->buffer() + newOffset);

result[0] = Value(static_cast<int16_t>(uvwasi_fd_seek(WASI::m_uvwasi, fd, fileDelta, whence, &out_addr)));
*(instance->memory(0)->buffer() + newOffset) = out_addr;
}

} // namespace Walrus
48 changes: 48 additions & 0 deletions src/wasi/Path.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2023-present Samsung Electronics Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace Walrus {

void WASI::path_open(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t fd = argv[0].asI32();
uint32_t dirflags = argv[1].asI32();
uint32_t path_offset = argv[2].asI32();
uint32_t len = argv[3].asI32();
uint32_t oflags = argv[4].asI32();
uint64_t rights = argv[5].asI64();
uint64_t right_inheriting = argv[6].asI64();
uint32_t fdflags = argv[7].asI32();
uint32_t ret_fd_offset = argv[8].asI32();

uvwasi_fd_t* ret_fd = reinterpret_cast<uvwasi_fd_t*>(instance->memory(0)->buffer() + ret_fd_offset);

const char* path = reinterpret_cast<char*>(instance->memory(0)->buffer() + path_offset);

result[0] = Value(static_cast<uint16_t>(
uvwasi_path_open(WASI::m_uvwasi,
fd,
dirflags,
path,
len,
oflags,
rights,
right_inheriting,
fdflags,
ret_fd)));
}

} // namespace Walrus
65 changes: 62 additions & 3 deletions src/wasi/Wasi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#include "wasi/Wasi.h"
#include "wasi/Fd.h"
#include "wasi/Path.h"
#include "wasi/Environ.h"

// https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md

Expand Down Expand Up @@ -93,11 +95,10 @@ void WASI::fillWasiFuncTable()
#undef WASI_FUNC_TABLE
}

WASI::WASI()
WASI::WASI(std::vector<uvwasi_preopen_s>& preopenDirs, bool shareHostEnv)
{
fillWasiFuncTable();

uvwasi_t uvwasi;
WASI::m_uvwasi = reinterpret_cast<uvwasi_t*>(malloc(sizeof(uvwasi_t)));

uvwasi_options_t init_options;
Expand All @@ -108,12 +109,70 @@ WASI::WASI()
init_options.argc = 0;
init_options.argv = nullptr;
init_options.envp = nullptr;
init_options.preopenc = 0;
if (shareHostEnv) {
std::vector<std::string> variables = {
// Common Unix environment variables.
"PATH",
"LIB",
"PWD",
"SHELL",
"TERM",
"HOME",
"LOGNAME",
"HOSTNAME",
"UID",
"TEMP",
"EDITOR"
"LANG",
"LC_TIME",
// Common Windows environment variables.
"APPDATA",
"USERPROFILE",
"USERDOMAIN",
"windir",
"ProgramFiles",
"OS"
"LOCALAPPDATA",
"SystemRoot",
"SystemDrive",
};

char** envp = (char**)malloc(sizeof(char**) * variables.size());

size_t j = 0;
for (size_t i = 0; i < variables.size(); i++) {
if (getenv(variables[i].c_str()) == nullptr) {
continue;
}

size_t length = strlen(variables[i].c_str());
length += strlen(getenv(variables[i].c_str()));
length += 2;
envp[j] = (char*)malloc(length);
strcpy(envp[j], variables[i].c_str());
envp[j][variables[i].size()] = '=';
strcpy(envp[j] + variables[i].size() + 1, getenv(variables[i].c_str()));
envp[j][length - 1] = '\0';
j++;
}
init_options.envp = const_cast<const char**>(envp);
}
init_options.preopenc = preopenDirs.size();
if (init_options.preopenc > 0) {
init_options.preopens = reinterpret_cast<uvwasi_preopen_t*>(calloc(init_options.preopenc, sizeof(uvwasi_preopen_s)));
}
for (unsigned i = 0; i < preopenDirs.size(); i++) {
init_options.preopens[i].mapped_path = preopenDirs[i].mapped_path;
init_options.preopens[i].real_path = preopenDirs[i].real_path;
}
init_options.preopen_socketc = 0;
init_options.allocator = nullptr;

uvwasi_errno_t err = uvwasi_init(WASI::m_uvwasi, &init_options);
assert(err == UVWASI_ESUCCESS);
if (init_options.preopenc > 0) {
free(init_options.preopens);
}
}

} // namespace Walrus
Loading

0 comments on commit 9c89d72

Please sign in to comment.