diff options
Diffstat (limited to 'src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries')
122 files changed, 24445 insertions, 0 deletions
diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.c new file mode 100644 index 000000000..1b3db1d49 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.c @@ -0,0 +1,1433 @@ +/* + * Copyright (C) 2021 Ant Group. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "debug_engine.h" +#include "gdbserver.h" +#include "handler.h" +#include "bh_platform.h" +#include "wasm_interp.h" +#include "wasm_opcode.h" +#include "wasm_runtime.h" + +static const uint8 break_instr[] = { DEBUG_OP_BREAK }; + +typedef struct WASMDebugEngine { + struct WASMDebugEngine *next; + WASMDebugControlThread *control_thread; + char ip_addr[128]; + int32 process_base_port; + bh_list debug_instance_list; + korp_mutex instance_list_lock; +} WASMDebugEngine; + +void +on_thread_stop_event(WASMDebugInstance *debug_inst, WASMExecEnv *exec_env) +{ + os_mutex_lock(&debug_inst->wait_lock); + debug_inst->stopped_thread = exec_env; + + if (debug_inst->current_state == DBG_LAUNCHING) { + /* In launching phase, send a signal so that handle_threadstop_request + * can be woken up */ + os_cond_signal(&debug_inst->wait_cond); + } + os_mutex_unlock(&debug_inst->wait_lock); +} + +void +on_thread_exit_event(WASMDebugInstance *debug_inst, WASMExecEnv *exec_env) +{ + os_mutex_lock(&debug_inst->wait_lock); + + /* DBG_LAUNCHING: exit when debugger detached, + * DBG_ERROR: exit when debugger error */ + if (debug_inst->current_state != DBG_LAUNCHING + && debug_inst->current_state != DBG_ERROR) { + /* only when exit normally the debugger thread will participate in + * teardown phase */ + debug_inst->stopped_thread = exec_env; + } + + os_mutex_unlock(&debug_inst->wait_lock); +} + +static WASMDebugEngine *g_debug_engine; + +static uint32 current_instance_id = 1; + +static uint32 +allocate_instance_id() +{ + uint32 id; + + bh_assert(g_debug_engine); + + os_mutex_lock(&g_debug_engine->instance_list_lock); + id = current_instance_id++; + os_mutex_unlock(&g_debug_engine->instance_list_lock); + + return id; +} + +static bool +is_thread_running(WASMDebugControlThread *control_thread) +{ + return control_thread->status == RUNNING; +} + +static bool +is_thread_stopped(WASMDebugControlThread *control_thread) +{ + return control_thread->status == STOPPED; +} + +static bool +is_thread_detached(WASMDebugControlThread *control_thread) +{ + return control_thread->status == DETACHED; +} + +static void * +control_thread_routine(void *arg) +{ + WASMDebugInstance *debug_inst = (WASMDebugInstance *)arg; + WASMDebugControlThread *control_thread = NULL; + + control_thread = debug_inst->control_thread; + bh_assert(control_thread); + + os_mutex_lock(&debug_inst->wait_lock); + + control_thread->status = RUNNING; + + debug_inst->id = allocate_instance_id(); + + control_thread->debug_engine = g_debug_engine; + control_thread->debug_instance = debug_inst; + bh_strcpy_s(control_thread->ip_addr, sizeof(control_thread->ip_addr), + g_debug_engine->ip_addr); + if (control_thread->port == -1) { + control_thread->port = + (g_debug_engine->process_base_port == 0) + ? 0 + : g_debug_engine->process_base_port + debug_inst->id - 1; + } + + LOG_WARNING("control thread of debug object %p start\n", debug_inst); + + control_thread->server = + wasm_create_gdbserver(control_thread->ip_addr, &control_thread->port); + + if (!control_thread->server) { + LOG_ERROR("Failed to create debug server\n"); + control_thread->port = 0; + os_cond_signal(&debug_inst->wait_cond); + os_mutex_unlock(&debug_inst->wait_lock); + return NULL; + } + + control_thread->server->thread = control_thread; + + /* + * wasm gdbserver created, the execution thread + * doesn't need to wait for the debugger connection, + * so we wake up the execution thread before listen + */ + os_cond_signal(&debug_inst->wait_cond); + os_mutex_unlock(&debug_inst->wait_lock); + + if (!wasm_gdbserver_listen(control_thread->server)) { + LOG_ERROR("Failed while listening for debugger\n"); + goto fail; + } + + /* outer infinite loop: try to connect with the debugger */ + while (true) { + /* wait lldb client to connect */ + if (!wasm_gdbserver_accept(control_thread->server)) { + LOG_ERROR("Failed while accepting debugger connection\n"); + goto fail; + } + + control_thread->status = RUNNING; + /* when reattached, send signal */ + wasm_cluster_send_signal_all(debug_inst->cluster, WAMR_SIG_SINGSTEP); + + /* inner infinite loop: keep serving until detach */ + while (true) { + os_mutex_lock(&control_thread->wait_lock); + if (is_thread_running(control_thread)) { + /* send thread stop reply */ + if (debug_inst->stopped_thread + && debug_inst->current_state == APP_RUNNING) { + uint32 status; + korp_tid tid; + + status = (uint32)debug_inst->stopped_thread->current_status + ->signal_flag; + tid = debug_inst->stopped_thread->handle; + + if (debug_inst->stopped_thread->current_status + ->running_status + == STATUS_EXIT) { + /* If the thread exits, report "W00" if it's the last + * thread in the cluster, otherwise ignore this event */ + status = 0; + + /* By design, all the other threads should have been + * stopped at this moment, so it is safe to access the + * exec_env_list.len without lock */ + if (debug_inst->cluster->exec_env_list.len != 1) { + debug_inst->stopped_thread = NULL; + /* The exiting thread may wait for the signal */ + os_cond_signal(&debug_inst->wait_cond); + os_mutex_unlock(&control_thread->wait_lock); + continue; + } + } + + wasm_debug_instance_set_cur_thread( + debug_inst, debug_inst->stopped_thread->handle); + + send_thread_stop_status(control_thread->server, status, + tid); + + debug_inst->current_state = APP_STOPPED; + debug_inst->stopped_thread = NULL; + + if (status == 0) { + /* The exiting thread may wait for the signal */ + os_cond_signal(&debug_inst->wait_cond); + } + } + + /* Processing incoming requests */ + if (!wasm_gdbserver_handle_packet(control_thread->server)) { + control_thread->status = STOPPED; + LOG_ERROR("An error occurs when handling a packet\n"); + os_mutex_unlock(&control_thread->wait_lock); + goto fail; + } + } + else if (is_thread_detached(control_thread)) { + os_mutex_unlock(&control_thread->wait_lock); + break; + } + else if (is_thread_stopped(control_thread)) { + os_mutex_unlock(&control_thread->wait_lock); + return NULL; + } + os_mutex_unlock(&control_thread->wait_lock); + } + } +fail: + wasm_debug_instance_on_failure(debug_inst); + LOG_VERBOSE("control thread of debug object [%p] stopped with failure\n", + debug_inst); + return NULL; +} + +static WASMDebugControlThread * +wasm_debug_control_thread_create(WASMDebugInstance *debug_instance, int32 port) +{ + WASMDebugControlThread *control_thread; + + if (!(control_thread = + wasm_runtime_malloc(sizeof(WASMDebugControlThread)))) { + LOG_ERROR("WASM Debug Engine error: failed to allocate memory"); + return NULL; + } + memset(control_thread, 0, sizeof(WASMDebugControlThread)); + control_thread->port = port; + + if (os_mutex_init(&control_thread->wait_lock) != 0) + goto fail; + + debug_instance->control_thread = control_thread; + + os_mutex_lock(&debug_instance->wait_lock); + + if (0 + != os_thread_create(&control_thread->tid, control_thread_routine, + debug_instance, APP_THREAD_STACK_SIZE_DEFAULT)) { + os_mutex_unlock(&debug_instance->wait_lock); + goto fail1; + } + + /* wait until the debug control thread ready */ + os_cond_wait(&debug_instance->wait_cond, &debug_instance->wait_lock); + os_mutex_unlock(&debug_instance->wait_lock); + if (!control_thread->server) { + os_thread_join(control_thread->tid, NULL); + goto fail1; + } + + os_mutex_lock(&g_debug_engine->instance_list_lock); + /* create control thread success, append debug instance to debug engine */ + bh_list_insert(&g_debug_engine->debug_instance_list, debug_instance); + os_mutex_unlock(&g_debug_engine->instance_list_lock); + + /* If we set WAMR_SIG_STOP here, the VSCode debugger adaptor will raise an + * exception in the UI. We use WAMR_SIG_SINGSTEP to avoid this exception for + * better user experience */ + wasm_cluster_send_signal_all(debug_instance->cluster, WAMR_SIG_SINGSTEP); + + return control_thread; + +fail1: + os_mutex_destroy(&control_thread->wait_lock); +fail: + wasm_runtime_free(control_thread); + return NULL; +} + +static void +wasm_debug_control_thread_destroy(WASMDebugInstance *debug_instance) +{ + WASMDebugControlThread *control_thread = debug_instance->control_thread; + + LOG_VERBOSE("stopping control thread of debug object [%p]\n", + debug_instance); + control_thread->status = STOPPED; + os_mutex_lock(&control_thread->wait_lock); + wasm_close_gdbserver(control_thread->server); + os_mutex_unlock(&control_thread->wait_lock); + os_thread_join(control_thread->tid, NULL); + wasm_runtime_free(control_thread->server); + + os_mutex_destroy(&control_thread->wait_lock); + wasm_runtime_free(control_thread); +} + +static WASMDebugEngine * +wasm_debug_engine_create() +{ + WASMDebugEngine *engine; + + if (!(engine = wasm_runtime_malloc(sizeof(WASMDebugEngine)))) { + LOG_ERROR("WASM Debug Engine error: failed to allocate memory"); + return NULL; + } + memset(engine, 0, sizeof(WASMDebugEngine)); + + if (os_mutex_init(&engine->instance_list_lock) != 0) { + wasm_runtime_free(engine); + LOG_ERROR("WASM Debug Engine error: failed to init mutex"); + return NULL; + } + + /* reset current instance id */ + current_instance_id = 1; + + bh_list_init(&engine->debug_instance_list); + return engine; +} + +void +wasm_debug_engine_destroy() +{ + if (g_debug_engine) { + wasm_debug_handler_deinit(); + os_mutex_destroy(&g_debug_engine->instance_list_lock); + wasm_runtime_free(g_debug_engine); + g_debug_engine = NULL; + } +} + +bool +wasm_debug_engine_init(char *ip_addr, int32 process_port) +{ + if (wasm_debug_handler_init() != 0) { + return false; + } + + if (g_debug_engine == NULL) { + g_debug_engine = wasm_debug_engine_create(); + } + + if (g_debug_engine) { + g_debug_engine->process_base_port = + (process_port > 0) ? process_port : 0; + if (ip_addr) + snprintf(g_debug_engine->ip_addr, sizeof(g_debug_engine->ip_addr), + "%s", ip_addr); + else + snprintf(g_debug_engine->ip_addr, sizeof(g_debug_engine->ip_addr), + "%s", "127.0.0.1"); + } + else { + wasm_debug_handler_deinit(); + } + + return g_debug_engine != NULL ? true : false; +} + +/* A debug Instance is a debug "process" in gdb remote protocol + and bound to a runtime cluster */ +WASMDebugInstance * +wasm_debug_instance_create(WASMCluster *cluster, int32 port) +{ + WASMDebugInstance *instance; + WASMExecEnv *exec_env = NULL; + wasm_module_inst_t module_inst = NULL; + + if (!g_debug_engine) { + return NULL; + } + + if (!(instance = wasm_runtime_malloc(sizeof(WASMDebugInstance)))) { + LOG_ERROR("WASM Debug Engine error: failed to allocate memory"); + return NULL; + } + memset(instance, 0, sizeof(WASMDebugInstance)); + + if (os_mutex_init(&instance->wait_lock) != 0) { + goto fail1; + } + + if (os_cond_init(&instance->wait_cond) != 0) { + goto fail2; + } + + bh_list_init(&instance->break_point_list); + bh_list_init(&instance->watch_point_list_read); + bh_list_init(&instance->watch_point_list_write); + + instance->cluster = cluster; + exec_env = bh_list_first_elem(&cluster->exec_env_list); + bh_assert(exec_env); + + instance->current_tid = exec_env->handle; + + module_inst = wasm_runtime_get_module_inst(exec_env); + bh_assert(module_inst); + + /* Allocate linear memory for evaluating expressions during debugging. If + * the allocation failed, the debugger will not be able to evaluate + * expressions */ + instance->exec_mem_info.size = DEBUG_EXECUTION_MEMORY_SIZE; + instance->exec_mem_info.start_offset = wasm_runtime_module_malloc( + module_inst, instance->exec_mem_info.size, NULL); + if (instance->exec_mem_info.start_offset == 0) { + LOG_WARNING( + "WASM Debug Engine warning: failed to allocate linear memory for " + "execution. \n" + "Will not be able to evaluate expressions during " + "debugging"); + } + instance->exec_mem_info.current_pos = instance->exec_mem_info.start_offset; + + if (!wasm_debug_control_thread_create(instance, port)) { + LOG_ERROR("WASM Debug Engine error: failed to create control thread"); + goto fail3; + } + + wasm_cluster_set_debug_inst(cluster, instance); + + return instance; + +fail3: + os_cond_destroy(&instance->wait_cond); +fail2: + os_mutex_destroy(&instance->wait_lock); +fail1: + wasm_runtime_free(instance); + + return NULL; +} + +static void +wasm_debug_instance_destroy_breakpoints(WASMDebugInstance *instance) +{ + WASMDebugBreakPoint *breakpoint, *next_bp; + + breakpoint = bh_list_first_elem(&instance->break_point_list); + while (breakpoint) { + next_bp = bh_list_elem_next(breakpoint); + + bh_list_remove(&instance->break_point_list, breakpoint); + wasm_runtime_free(breakpoint); + + breakpoint = next_bp; + } +} + +static void +wasm_debug_instance_destroy_watchpoints(WASMDebugInstance *instance, + bh_list *watchpoints) +{ + WASMDebugWatchPoint *watchpoint, *next; + + watchpoint = bh_list_first_elem(watchpoints); + while (watchpoint) { + next = bh_list_elem_next(watchpoint); + + bh_list_remove(watchpoints, watchpoint); + wasm_runtime_free(watchpoint); + + watchpoint = next; + } +} + +void +wasm_debug_instance_destroy(WASMCluster *cluster) +{ + WASMDebugInstance *instance = NULL; + + if (!g_debug_engine) { + return; + } + + instance = cluster->debug_inst; + if (instance) { + /* destroy control thread */ + wasm_debug_control_thread_destroy(instance); + + os_mutex_lock(&g_debug_engine->instance_list_lock); + bh_list_remove(&g_debug_engine->debug_instance_list, instance); + os_mutex_unlock(&g_debug_engine->instance_list_lock); + + /* destroy all breakpoints */ + wasm_debug_instance_destroy_breakpoints(instance); + wasm_debug_instance_destroy_watchpoints( + instance, &instance->watch_point_list_read); + wasm_debug_instance_destroy_watchpoints( + instance, &instance->watch_point_list_write); + + os_mutex_destroy(&instance->wait_lock); + os_cond_destroy(&instance->wait_cond); + + wasm_runtime_free(instance); + cluster->debug_inst = NULL; + } +} + +WASMExecEnv * +wasm_debug_instance_get_current_env(WASMDebugInstance *instance) +{ + WASMExecEnv *exec_env = NULL; + + if (instance) { + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + while (exec_env) { + if (exec_env->handle == instance->current_tid) + break; + exec_env = bh_list_elem_next(exec_env); + } + } + return exec_env; +} + +#if WASM_ENABLE_LIBC_WASI != 0 +bool +wasm_debug_instance_get_current_object_name(WASMDebugInstance *instance, + char name_buffer[], uint32 len) +{ + WASMExecEnv *exec_env; + WASIArguments *wasi_args; + WASMModuleInstance *module_inst; + + if (!instance) + return false; + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (!exec_env) + return false; + + module_inst = (WASMModuleInstance *)exec_env->module_inst; + wasi_args = &module_inst->module->wasi_args; + if (wasi_args && wasi_args->argc > 0) { + char *argv_name = wasi_args->argv[0]; + uint32 name_len = (uint32)strlen(argv_name); + + printf("the module name is %s\n", argv_name); + if (len - 1 >= name_len) + bh_strcpy_s(name_buffer, len, argv_name); + else + bh_strcpy_s(name_buffer, len, argv_name + (name_len + 1 - len)); + return true; + } + return false; +} +#endif + +uint64 +wasm_debug_instance_get_pid(WASMDebugInstance *instance) +{ + if (instance != NULL) { + return (uint64)instance->id; + } + return (uint64)0; +} + +korp_tid +wasm_debug_instance_get_tid(WASMDebugInstance *instance) +{ + if (instance != NULL) { + return instance->current_tid; + } + return (korp_tid)(uintptr_t)0; +} + +uint32 +wasm_debug_instance_get_tids(WASMDebugInstance *instance, korp_tid tids[], + uint32 len) +{ + WASMExecEnv *exec_env; + uint32 i = 0, threads_num = 0; + + if (!instance) + return 0; + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + while (exec_env && i < len) { + /* Some threads may not be ready */ + if (exec_env->handle != 0) { + tids[i++] = exec_env->handle; + threads_num++; + } + exec_env = bh_list_elem_next(exec_env); + } + LOG_VERBOSE("find %d tids\n", threads_num); + return threads_num; +} + +uint32 +wasm_debug_instance_get_thread_status(WASMDebugInstance *instance, korp_tid tid) +{ + WASMExecEnv *exec_env = NULL; + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + while (exec_env) { + if (exec_env->handle == tid) { + return (uint32)exec_env->current_status->signal_flag; + } + exec_env = bh_list_elem_next(exec_env); + } + + return 0; +} + +void +wasm_debug_instance_set_cur_thread(WASMDebugInstance *instance, korp_tid tid) +{ + instance->current_tid = tid; +} + +uint64 +wasm_debug_instance_get_pc(WASMDebugInstance *instance) +{ + WASMExecEnv *exec_env; + + if (!instance) + return 0; + + exec_env = wasm_debug_instance_get_current_env(instance); + if ((exec_env != NULL) && (exec_env->cur_frame != NULL) + && (exec_env->cur_frame->ip != NULL)) { + WASMModuleInstance *module_inst = + (WASMModuleInstance *)exec_env->module_inst; + return WASM_ADDR( + WasmObj, instance->id, + (exec_env->cur_frame->ip - module_inst->module->load_addr)); + } + return 0; +} + +uint64 +wasm_debug_instance_get_load_addr(WASMDebugInstance *instance) +{ + WASMExecEnv *exec_env; + + if (!instance) + return WASM_ADDR(WasmInvalid, 0, 0); + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (exec_env) { + return WASM_ADDR(WasmObj, instance->id, 0); + } + + return WASM_ADDR(WasmInvalid, 0, 0); +} + +WASMDebugMemoryInfo * +wasm_debug_instance_get_memregion(WASMDebugInstance *instance, uint64 addr) +{ + WASMDebugMemoryInfo *mem_info; + WASMExecEnv *exec_env; + WASMModuleInstance *module_inst; + WASMMemoryInstance *memory; + uint32 num_bytes_per_page; + uint32 linear_mem_size = 0; + + if (!instance) + return NULL; + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (!exec_env) + return NULL; + + if (!(mem_info = wasm_runtime_malloc(sizeof(WASMDebugMemoryInfo)))) { + LOG_ERROR("WASM Debug Engine error: failed to allocate memory"); + return NULL; + } + memset(mem_info, 0, sizeof(WASMDebugMemoryInfo)); + mem_info->start = WASM_ADDR(WasmInvalid, 0, 0); + mem_info->size = 0; + mem_info->name[0] = '\0'; + mem_info->permisson[0] = '\0'; + + module_inst = (WASMModuleInstance *)exec_env->module_inst; + + switch (WASM_ADDR_TYPE(addr)) { + case WasmObj: + if (WASM_ADDR_OFFSET(addr) < module_inst->module->load_size) { + mem_info->start = WASM_ADDR(WasmObj, instance->id, 0); + mem_info->size = module_inst->module->load_size; + snprintf(mem_info->name, sizeof(mem_info->name), "%s", + "module"); + snprintf(mem_info->permisson, sizeof(mem_info->permisson), "%s", + "rx"); + } + break; + case WasmMemory: + { + memory = wasm_get_default_memory(module_inst); + + if (memory) { + num_bytes_per_page = memory->num_bytes_per_page; + linear_mem_size = num_bytes_per_page * memory->cur_page_count; + } + if (WASM_ADDR_OFFSET(addr) < linear_mem_size) { + mem_info->start = WASM_ADDR(WasmMemory, instance->id, 0); + mem_info->size = linear_mem_size; + snprintf(mem_info->name, sizeof(mem_info->name), "%s", + "memory"); + snprintf(mem_info->permisson, sizeof(mem_info->permisson), "%s", + "rw"); + } + break; + } + default: + mem_info->start = WASM_ADDR(WasmInvalid, 0, 0); + mem_info->size = 0; + } + return mem_info; +} + +void +wasm_debug_instance_destroy_memregion(WASMDebugInstance *instance, + WASMDebugMemoryInfo *mem_info) +{ + wasm_runtime_free(mem_info); +} + +bool +wasm_debug_instance_get_obj_mem(WASMDebugInstance *instance, uint64 offset, + char *buf, uint64 *size) +{ + WASMExecEnv *exec_env; + WASMModuleInstance *module_inst; + WASMDebugBreakPoint *breakpoint; + WASMFastOPCodeNode *fast_opcode; + + if (!instance) + return false; + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (!exec_env) + return false; + + module_inst = (WASMModuleInstance *)exec_env->module_inst; + + if (offset + *size > module_inst->module->load_size) { + LOG_VERBOSE("wasm_debug_instance_get_data_mem size over flow!\n"); + *size = module_inst->module->load_size >= offset + ? module_inst->module->load_size - offset + : 0; + } + + bh_memcpy_s(buf, (uint32)*size, module_inst->module->load_addr + offset, + (uint32)*size); + + breakpoint = bh_list_first_elem(&instance->break_point_list); + while (breakpoint) { + if (offset <= breakpoint->addr && breakpoint->addr < offset + *size) { + bh_memcpy_s(buf + (breakpoint->addr - offset), sizeof(break_instr), + &breakpoint->orignal_data, sizeof(break_instr)); + } + breakpoint = bh_list_elem_next(breakpoint); + } + + fast_opcode = bh_list_first_elem(&module_inst->module->fast_opcode_list); + while (fast_opcode) { + if (offset <= fast_opcode->offset + && fast_opcode->offset < offset + *size) { + *(uint8 *)(buf + (fast_opcode->offset - offset)) = + fast_opcode->orig_op; + } + fast_opcode = bh_list_elem_next(fast_opcode); + } + + return true; +} + +bool +wasm_debug_instance_get_linear_mem(WASMDebugInstance *instance, uint64 offset, + char *buf, uint64 *size) +{ + WASMExecEnv *exec_env; + WASMModuleInstance *module_inst; + WASMMemoryInstance *memory; + uint32 num_bytes_per_page; + uint32 linear_mem_size; + + if (!instance) + return false; + + exec_env = wasm_debug_instance_get_current_env(instance); + if (!exec_env) + return false; + + module_inst = (WASMModuleInstance *)exec_env->module_inst; + memory = wasm_get_default_memory(module_inst); + if (memory) { + num_bytes_per_page = memory->num_bytes_per_page; + linear_mem_size = num_bytes_per_page * memory->cur_page_count; + if (offset + *size > linear_mem_size) { + LOG_VERBOSE("wasm_debug_instance_get_linear_mem size over flow!\n"); + *size = linear_mem_size >= offset ? linear_mem_size - offset : 0; + } + bh_memcpy_s(buf, (uint32)*size, memory->memory_data + offset, + (uint32)*size); + return true; + } + return false; +} + +bool +wasm_debug_instance_set_linear_mem(WASMDebugInstance *instance, uint64 offset, + char *buf, uint64 *size) +{ + WASMExecEnv *exec_env; + WASMModuleInstance *module_inst; + WASMMemoryInstance *memory; + uint32 num_bytes_per_page; + uint32 linear_mem_size; + + if (!instance) + return false; + + exec_env = wasm_debug_instance_get_current_env(instance); + if (!exec_env) + return false; + + module_inst = (WASMModuleInstance *)exec_env->module_inst; + memory = wasm_get_default_memory(module_inst); + if (memory) { + num_bytes_per_page = memory->num_bytes_per_page; + linear_mem_size = num_bytes_per_page * memory->cur_page_count; + if (offset + *size > linear_mem_size) { + LOG_VERBOSE("wasm_debug_instance_get_linear_mem size over flow!\n"); + *size = linear_mem_size >= offset ? linear_mem_size - offset : 0; + } + bh_memcpy_s(memory->memory_data + offset, (uint32)*size, buf, + (uint32)*size); + return true; + } + return false; +} + +bool +wasm_debug_instance_get_mem(WASMDebugInstance *instance, uint64 addr, char *buf, + uint64 *size) +{ + switch (WASM_ADDR_TYPE(addr)) { + case WasmMemory: + return wasm_debug_instance_get_linear_mem( + instance, WASM_ADDR_OFFSET(addr), buf, size); + break; + case WasmObj: + return wasm_debug_instance_get_obj_mem( + instance, WASM_ADDR_OFFSET(addr), buf, size); + break; + default: + return false; + } +} + +bool +wasm_debug_instance_set_mem(WASMDebugInstance *instance, uint64 addr, char *buf, + uint64 *size) +{ + switch (WASM_ADDR_TYPE(addr)) { + case WasmMemory: + return wasm_debug_instance_set_linear_mem( + instance, WASM_ADDR_OFFSET(addr), buf, size); + break; + case WasmObj: + default: + return false; + } +} + +WASMDebugInstance * +wasm_exec_env_get_instance(WASMExecEnv *exec_env) +{ + WASMDebugInstance *instance = NULL; + + if (!g_debug_engine) { + return NULL; + } + + os_mutex_lock(&g_debug_engine->instance_list_lock); + instance = bh_list_first_elem(&g_debug_engine->debug_instance_list); + while (instance) { + if (instance->cluster == exec_env->cluster) + break; + instance = bh_list_elem_next(instance); + } + + os_mutex_unlock(&g_debug_engine->instance_list_lock); + return instance; +} + +uint32 +wasm_debug_instance_get_call_stack_pcs(WASMDebugInstance *instance, + korp_tid tid, uint64 buf[], uint64 size) +{ + WASMExecEnv *exec_env; + struct WASMInterpFrame *frame; + uint32 i = 0; + + if (!instance) + return 0; + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + while (exec_env) { + if (exec_env->handle == tid) { + WASMModuleInstance *module_inst = + (WASMModuleInstance *)exec_env->module_inst; + frame = exec_env->cur_frame; + while (frame && i < size) { + if (frame->ip != NULL) { + buf[i++] = + WASM_ADDR(WasmObj, instance->id, + (frame->ip - module_inst->module->load_addr)); + } + frame = frame->prev_frame; + } + return i; + } + exec_env = bh_list_elem_next(exec_env); + } + return 0; +} + +bool +wasm_debug_instance_add_breakpoint(WASMDebugInstance *instance, uint64 addr, + uint64 length) +{ + WASMExecEnv *exec_env; + WASMModuleInstance *module_inst; + uint64 offset; + + if (!instance) + return false; + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (!exec_env) + return false; + + module_inst = (WASMModuleInstance *)exec_env->module_inst; + if (WASM_ADDR_TYPE(addr) != WasmObj) + return false; + + offset = WASM_ADDR_OFFSET(addr); + + if (length >= sizeof(break_instr)) { + if (offset + sizeof(break_instr) <= module_inst->module->load_size) { + WASMDebugBreakPoint *breakpoint; + if (!(breakpoint = + wasm_runtime_malloc(sizeof(WASMDebugBreakPoint)))) { + LOG_ERROR("WASM Debug Engine error: failed to allocate memory"); + return false; + } + memset(breakpoint, 0, sizeof(WASMDebugBreakPoint)); + breakpoint->addr = offset; + /* TODO: how to if more than one breakpoints are set + at the same addr? */ + bh_memcpy_s(&breakpoint->orignal_data, (uint32)sizeof(break_instr), + module_inst->module->load_addr + offset, + (uint32)sizeof(break_instr)); + + bh_memcpy_s(module_inst->module->load_addr + offset, + (uint32)sizeof(break_instr), break_instr, + (uint32)sizeof(break_instr)); + + bh_list_insert(&instance->break_point_list, breakpoint); + return true; + } + } + return false; +} + +bool +wasm_debug_instance_remove_breakpoint(WASMDebugInstance *instance, uint64 addr, + uint64 length) +{ + WASMExecEnv *exec_env; + WASMModuleInstance *module_inst; + uint64 offset; + + if (!instance) + return false; + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (!exec_env) + return false; + + module_inst = (WASMModuleInstance *)exec_env->module_inst; + + if (WASM_ADDR_TYPE(addr) != WasmObj) + return false; + offset = WASM_ADDR_OFFSET(addr); + + if (length >= sizeof(break_instr)) { + if (offset + sizeof(break_instr) <= module_inst->module->load_size) { + WASMDebugBreakPoint *breakpoint = + bh_list_first_elem(&instance->break_point_list); + while (breakpoint) { + WASMDebugBreakPoint *next_break = bh_list_elem_next(breakpoint); + if (breakpoint->addr == offset) { + /* TODO: how to if more than one breakpoints are set + at the same addr? */ + bh_memcpy_s(module_inst->module->load_addr + offset, + (uint32)sizeof(break_instr), + &breakpoint->orignal_data, + (uint32)sizeof(break_instr)); + bh_list_remove(&instance->break_point_list, breakpoint); + wasm_runtime_free(breakpoint); + } + breakpoint = next_break; + } + } + } + return true; +} + +static bool +add_watchpoint(bh_list *list, uint64 addr, uint64 length) +{ + WASMDebugWatchPoint *watchpoint; + if (!(watchpoint = wasm_runtime_malloc(sizeof(WASMDebugWatchPoint)))) { + LOG_ERROR("WASM Debug Engine error: failed to allocate memory for " + "watchpoint"); + return false; + } + memset(watchpoint, 0, sizeof(WASMDebugWatchPoint)); + watchpoint->addr = addr; + watchpoint->length = length; + bh_list_insert(list, watchpoint); + return true; +} + +static bool +remove_watchpoint(bh_list *list, uint64 addr, uint64 length) +{ + WASMDebugWatchPoint *watchpoint = bh_list_first_elem(list); + while (watchpoint) { + WASMDebugWatchPoint *next = bh_list_elem_next(watchpoint); + if (watchpoint->addr == addr && watchpoint->length == length) { + bh_list_remove(list, watchpoint); + wasm_runtime_free(watchpoint); + } + watchpoint = next; + } + return true; +} + +bool +wasm_debug_instance_watchpoint_write_add(WASMDebugInstance *instance, + uint64 addr, uint64 length) +{ + return add_watchpoint(&instance->watch_point_list_write, addr, length); +} + +bool +wasm_debug_instance_watchpoint_write_remove(WASMDebugInstance *instance, + uint64 addr, uint64 length) +{ + return remove_watchpoint(&instance->watch_point_list_write, addr, length); +} + +bool +wasm_debug_instance_watchpoint_read_add(WASMDebugInstance *instance, + uint64 addr, uint64 length) +{ + return add_watchpoint(&instance->watch_point_list_read, addr, length); +} + +bool +wasm_debug_instance_watchpoint_read_remove(WASMDebugInstance *instance, + uint64 addr, uint64 length) +{ + return remove_watchpoint(&instance->watch_point_list_read, addr, length); +} + +bool +wasm_debug_instance_on_failure(WASMDebugInstance *instance) +{ + WASMExecEnv *exec_env; + + if (!instance) + return false; + + os_mutex_lock(&instance->wait_lock); + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (!exec_env) { + os_mutex_unlock(&instance->wait_lock); + return false; + } + + if (instance->stopped_thread == NULL + && instance->current_state == DBG_LAUNCHING) { + /* if fail in start stage: may need wait for main thread to notify it */ + os_cond_wait(&instance->wait_cond, &instance->wait_lock); + } + instance->current_state = DBG_ERROR; + instance->stopped_thread = NULL; + + /* terminate the wasm execution thread */ + while (exec_env) { + /* Resume all threads so they can receive the TERM signal */ + os_mutex_lock(&exec_env->wait_lock); + wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM); + exec_env->current_status->running_status = STATUS_RUNNING; + os_cond_signal(&exec_env->wait_cond); + os_mutex_unlock(&exec_env->wait_lock); + exec_env = bh_list_elem_next(exec_env); + } + os_mutex_unlock(&instance->wait_lock); + + return true; +} + +bool +wasm_debug_instance_continue(WASMDebugInstance *instance) +{ + WASMExecEnv *exec_env; + + if (!instance) + return false; + + if (instance->current_state == APP_RUNNING) { + LOG_VERBOSE("Already in running state, ignore continue request"); + return false; + } + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (!exec_env) + return false; + + while (exec_env) { + wasm_cluster_thread_continue(exec_env); + exec_env = bh_list_elem_next(exec_env); + } + + instance->current_state = APP_RUNNING; + + return true; +} + +bool +wasm_debug_instance_interrupt_all_threads(WASMDebugInstance *instance) +{ + WASMExecEnv *exec_env; + + if (!instance) + return false; + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (!exec_env) + return false; + + while (exec_env) { + wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TRAP); + exec_env = bh_list_elem_next(exec_env); + } + return true; +} + +bool +wasm_debug_instance_detach(WASMDebugInstance *instance) +{ + WASMExecEnv *exec_env; + + if (!instance) + return false; + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (!exec_env) + return false; + + wasm_gdbserver_detach(instance->control_thread->server); + + while (exec_env) { + if (instance->current_state == APP_STOPPED) { + /* Resume all threads since remote debugger detached*/ + wasm_cluster_thread_continue(exec_env); + } + exec_env = bh_list_elem_next(exec_env); + } + + /* relaunch, accept new debug connection */ + instance->current_state = DBG_LAUNCHING; + instance->control_thread->status = DETACHED; + instance->stopped_thread = NULL; + + return true; +} + +bool +wasm_debug_instance_kill(WASMDebugInstance *instance) +{ + WASMExecEnv *exec_env; + + if (!instance) + return false; + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (!exec_env) + return false; + + while (exec_env) { + wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM); + if (instance->current_state == APP_STOPPED) { + /* Resume all threads so they can receive the TERM signal */ + os_mutex_lock(&exec_env->wait_lock); + exec_env->current_status->running_status = STATUS_RUNNING; + os_cond_signal(&exec_env->wait_cond); + os_mutex_unlock(&exec_env->wait_lock); + } + exec_env = bh_list_elem_next(exec_env); + } + + instance->current_state = APP_RUNNING; + return true; +} + +bool +wasm_debug_instance_singlestep(WASMDebugInstance *instance, korp_tid tid) +{ + WASMExecEnv *exec_env; + + if (!instance) + return false; + + if (instance->current_state == APP_RUNNING) { + LOG_VERBOSE("Already in running state, ignore step request"); + return false; + } + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (!exec_env) + return false; + + while (exec_env) { + if (exec_env->handle == tid || tid == (korp_tid)(uintptr_t)~0LL) { + wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_SINGSTEP); + wasm_cluster_thread_step(exec_env); + } + exec_env = bh_list_elem_next(exec_env); + } + + instance->current_state = APP_RUNNING; + + return true; +} + +bool +wasm_debug_instance_get_local(WASMDebugInstance *instance, int32 frame_index, + int32 local_index, char buf[], int32 *size) +{ + WASMExecEnv *exec_env; + struct WASMInterpFrame *frame; + WASMFunctionInstance *cur_func; + uint8 local_type = 0xFF; + uint32 local_offset; + int32 param_count; + int32 fi = 0; + + if (!instance) + return false; + + exec_env = wasm_debug_instance_get_current_env(instance); + if (!exec_env) + return false; + + frame = exec_env->cur_frame; + while (frame && fi++ != frame_index) { + frame = frame->prev_frame; + } + + if (!frame) + return false; + cur_func = frame->function; + if (!cur_func) + return false; + + param_count = cur_func->param_count; + + if (local_index >= param_count + cur_func->local_count) + return false; + + local_offset = cur_func->local_offsets[local_index]; + if (local_index < param_count) + local_type = cur_func->param_types[local_index]; + else if (local_index < cur_func->local_count + param_count) + local_type = cur_func->local_types[local_index - param_count]; + + switch (local_type) { + case VALUE_TYPE_I32: + case VALUE_TYPE_F32: + *size = 4; + bh_memcpy_s(buf, 4, (char *)(frame->lp + local_offset), 4); + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + *size = 8; + bh_memcpy_s(buf, 8, (char *)(frame->lp + local_offset), 8); + break; + default: + *size = 0; + break; + } + return true; +} + +bool +wasm_debug_instance_get_global(WASMDebugInstance *instance, int32 frame_index, + int32 global_index, char buf[], int32 *size) +{ + WASMExecEnv *exec_env; + struct WASMInterpFrame *frame; + WASMModuleInstance *module_inst; + WASMGlobalInstance *globals, *global; + uint8 *global_addr; + uint8 global_type = 0xFF; + uint8 *global_data; + int32 fi = 0; + + if (!instance) + return false; + + exec_env = wasm_debug_instance_get_current_env(instance); + if (!exec_env) + return false; + + frame = exec_env->cur_frame; + while (frame && fi++ != frame_index) { + frame = frame->prev_frame; + } + + if (!frame) + return false; + + module_inst = (WASMModuleInstance *)exec_env->module_inst; + global_data = module_inst->global_data; + globals = module_inst->e->globals; + + if ((global_index < 0) + || ((uint32)global_index >= module_inst->e->global_count)) { + return false; + } + global = globals + global_index; + +#if WASM_ENABLE_MULTI_MODULE == 0 + global_addr = global_data + global->data_offset; +#else + global_addr = global->import_global_inst + ? global->import_module_inst->global_data + + global->import_global_inst->data_offset + : global_data + global->data_offset; +#endif + global_type = global->type; + + switch (global_type) { + case VALUE_TYPE_I32: + case VALUE_TYPE_F32: + *size = 4; + bh_memcpy_s(buf, 4, (char *)(global_addr), 4); + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + *size = 8; + bh_memcpy_s(buf, 8, (char *)(global_addr), 8); + break; + default: + *size = 0; + break; + } + return true; +} + +uint64 +wasm_debug_instance_mmap(WASMDebugInstance *instance, uint32 size, + int32 map_prot) +{ + WASMExecEnv *exec_env; + uint32 offset = 0; + (void)map_prot; + + if (!instance) + return 0; + + exec_env = wasm_debug_instance_get_current_env(instance); + if (!exec_env) + return 0; + + if (instance->exec_mem_info.start_offset == 0) { + return 0; + } + + if ((uint64)instance->exec_mem_info.current_pos + - instance->exec_mem_info.start_offset + size + <= (uint64)instance->exec_mem_info.size) { + offset = instance->exec_mem_info.current_pos; + instance->exec_mem_info.current_pos += size; + } + + if (offset == 0) { + LOG_WARNING("the memory may be not enough for debug, try use larger " + "--heap-size"); + return 0; + } + + return WASM_ADDR(WasmMemory, 0, offset); +} + +bool +wasm_debug_instance_ummap(WASMDebugInstance *instance, uint64 addr) +{ + WASMExecEnv *exec_env; + + if (!instance) + return false; + + exec_env = wasm_debug_instance_get_current_env(instance); + if (!exec_env) + return false; + + if (instance->exec_mem_info.start_offset == 0) { + return false; + } + + (void)addr; + + /* Currently we don't support to free the execution memory, simply return + * true here */ + return true; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.cmake b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.cmake new file mode 100644 index 000000000..914ddd639 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.cmake @@ -0,0 +1,12 @@ +# Copyright (C) 2021 Ant Group. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (DEBUG_ENGINE_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions (-DWASM_ENABLE_DEBUG_INTERP=1) + +include_directories(${DEBUG_ENGINE_DIR}) + +file (GLOB source_all ${DEBUG_ENGINE_DIR}/*.c) + +set (DEBUG_ENGINE_SOURCE ${source_all}) diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.h new file mode 100644 index 000000000..e12f827bd --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.h @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2021 Ant Group. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _DEBUG_ENGINE_H +#define _DEBUG_ENGINE_H + +#include "bh_list.h" +#include "gdbserver.h" +#include "thread_manager.h" + +typedef enum WASMDebugControlThreadStatus { + RUNNING, + DETACHED, + STOPPED, +} WASMDebugControlThreadStatus; + +struct WASMDebugEngine; +struct WASMDebugInstance; + +typedef struct WASMDebugControlThread { + WASMGDBServer *server; + korp_tid tid; + korp_mutex wait_lock; + char ip_addr[128]; + int port; + WASMDebugControlThreadStatus status; + struct WASMDebugEngine *debug_engine; + struct WASMDebugInstance *debug_instance; +} WASMDebugControlThread; + +typedef struct WASMDebugBreakPoint { + struct WASMDebugBreakPoint *next; + uint64 addr; + uint64 orignal_data; +} WASMDebugBreakPoint; + +typedef struct WASMDebugWatchPoint { + bh_list_link next; + uint64 addr; + uint64 length; +} WASMDebugWatchPoint; + +typedef enum debug_state_t { + /* Debugger state conversion sequence: + * DBG_LAUNCHING ---> APP_STOPPED <---> APP_RUNNING + */ + DBG_LAUNCHING, + APP_RUNNING, + APP_STOPPED, + DBG_ERROR +} debug_state_t; + +typedef struct WASMDebugExecutionMemory { + uint32 start_offset; + uint32 size; + uint32 current_pos; +} WASMDebugExecutionMemory; + +struct WASMDebugInstance { + struct WASMDebugInstance *next; + WASMDebugControlThread *control_thread; + bh_list break_point_list; + bh_list watch_point_list_read; + bh_list watch_point_list_write; + WASMCluster *cluster; + uint32 id; + korp_tid current_tid; + korp_mutex wait_lock; + korp_cond wait_cond; + /* Last stopped thread, it should be set to NULL when sending + * out the thread stop reply */ + WASMExecEnv *volatile stopped_thread; + /* Currently status of the debug instance, it will be set to + * RUNNING when receiving STEP/CONTINUE commands, and set to + * STOPPED when any thread stopped */ + volatile debug_state_t current_state; + /* Execution memory info. During debugging, the debug client may request to + * malloc a memory space to evaluate user expressions. We preserve a buffer + * during creating debug instance, and use a simple bump pointer allocator + * to serve lldb's memory request */ + WASMDebugExecutionMemory exec_mem_info; +}; + +typedef enum WASMDebugEventKind { + BREAK_POINT_ADD, + BREAK_POINT_REMOVE +} WASMDebugEventKind; + +typedef struct WASMDebugEvent { + WASMDebugEventKind kind; + unsigned char metadata[0]; +} WASMDebugEvent; + +typedef struct WASMDebugMemoryInfo { + uint64 start; + uint64 size; + char name[128]; + char permisson[4]; +} WASMDebugMemoryInfo; + +typedef enum WasmAddressType { + WasmMemory = 0x00, + WasmObj = 0x01, + WasmInvalid = 0x03 +} WasmAddressType; + +#define WASM_ADDR(type, id, offset) \ + (((uint64)type << 62) | ((uint64)0 << 32) | ((uint64)offset << 0)) + +#define WASM_ADDR_TYPE(addr) (((addr)&0xC000000000000000) >> 62) +#define WASM_ADDR_OFFSET(addr) (((addr)&0x00000000FFFFFFFF)) + +#define INVALIED_ADDR (0xFFFFFFFFFFFFFFFF) + +void +on_thread_stop_event(WASMDebugInstance *debug_inst, WASMExecEnv *exec_env); + +void +on_thread_exit_event(WASMDebugInstance *debug_inst, WASMExecEnv *exec_env); + +WASMDebugInstance * +wasm_debug_instance_create(WASMCluster *cluster, int32 port); + +void +wasm_debug_instance_destroy(WASMCluster *cluster); + +WASMDebugInstance * +wasm_exec_env_get_instance(WASMExecEnv *exec_env); + +bool +wasm_debug_engine_init(char *ip_addr, int32 process_port); + +void +wasm_debug_engine_destroy(); + +WASMExecEnv * +wasm_debug_instance_get_current_env(WASMDebugInstance *instance); + +uint64 +wasm_debug_instance_get_pid(WASMDebugInstance *instance); + +korp_tid +wasm_debug_instance_get_tid(WASMDebugInstance *instance); + +uint32 +wasm_debug_instance_get_tids(WASMDebugInstance *instance, korp_tid tids[], + uint32 len); + +void +wasm_debug_instance_set_cur_thread(WASMDebugInstance *instance, korp_tid tid); + +uint64 +wasm_debug_instance_get_pc(WASMDebugInstance *instance); + +uint64 +wasm_debug_instance_get_load_addr(WASMDebugInstance *instance); + +WASMDebugMemoryInfo * +wasm_debug_instance_get_memregion(WASMDebugInstance *instance, uint64 addr); + +void +wasm_debug_instance_destroy_memregion(WASMDebugInstance *instance, + WASMDebugMemoryInfo *mem_info); + +bool +wasm_debug_instance_get_obj_mem(WASMDebugInstance *instance, uint64 addr, + char *buf, uint64 *size); + +bool +wasm_debug_instance_get_linear_mem(WASMDebugInstance *instance, uint64 addr, + char *buf, uint64 *size); + +bool +wasm_debug_instance_get_mem(WASMDebugInstance *instance, uint64 addr, char *buf, + uint64 *size); + +bool +wasm_debug_instance_set_mem(WASMDebugInstance *instance, uint64 addr, char *buf, + uint64 *size); + +uint32 +wasm_debug_instance_get_call_stack_pcs(WASMDebugInstance *instance, + korp_tid tid, uint64 buf[], uint64 size); + +bool +wasm_debug_instance_add_breakpoint(WASMDebugInstance *instance, uint64 addr, + uint64 length); + +bool +wasm_debug_instance_remove_breakpoint(WASMDebugInstance *instance, uint64 addr, + uint64 length); + +bool +wasm_debug_instance_watchpoint_write_add(WASMDebugInstance *instance, + uint64 addr, uint64 length); + +bool +wasm_debug_instance_watchpoint_write_remove(WASMDebugInstance *instance, + uint64 addr, uint64 length); + +bool +wasm_debug_instance_watchpoint_read_add(WASMDebugInstance *instance, + uint64 addr, uint64 length); + +bool +wasm_debug_instance_watchpoint_read_remove(WASMDebugInstance *instance, + uint64 addr, uint64 length); + +bool +wasm_debug_instance_on_failure(WASMDebugInstance *instance); + +bool +wasm_debug_instance_interrupt_all_threads(WASMDebugInstance *instance); + +bool +wasm_debug_instance_continue(WASMDebugInstance *instance); + +bool +wasm_debug_instance_detach(WASMDebugInstance *instance); + +bool +wasm_debug_instance_kill(WASMDebugInstance *instance); + +uint32 +wasm_debug_instance_get_thread_status(WASMDebugInstance *instance, + korp_tid tid); + +bool +wasm_debug_instance_singlestep(WASMDebugInstance *instance, korp_tid tid); + +bool +wasm_debug_instance_get_local(WASMDebugInstance *instance, int32 frame_index, + int32 local_index, char buf[], int32 *size); + +bool +wasm_debug_instance_get_global(WASMDebugInstance *instance, int32 frame_index, + int32 global_index, char buf[], int32 *size); + +#if WASM_ENABLE_LIBC_WASI != 0 +bool +wasm_debug_instance_get_current_object_name(WASMDebugInstance *instance, + char name_buffer[], uint32 len); +#endif + +uint64 +wasm_debug_instance_mmap(WASMDebugInstance *instance, uint32 size, + int32 map_prot); + +bool +wasm_debug_instance_ummap(WASMDebugInstance *instance, uint64 addr); +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/gdbserver.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/gdbserver.c new file mode 100644 index 000000000..fbd876ac3 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/gdbserver.c @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2021 Ant Group. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_platform.h" +#include "gdbserver.h" +#include "handler.h" +#include "packets.h" +#include "utils.h" + +typedef void (*PacketHandler)(WASMGDBServer *server, char *payload); + +struct packet_handler_elem { + char request; + PacketHandler handler; +}; + +#define DEL_HANDLER(r, h) [r] = { .request = r, .handler = h } + +static const struct packet_handler_elem packet_handler_table[255] = { + DEL_HANDLER('Q', handle_general_set), + DEL_HANDLER('q', handle_general_query), + DEL_HANDLER('v', handle_v_packet), + DEL_HANDLER('?', handle_threadstop_request), + DEL_HANDLER('H', handle_set_current_thread), + DEL_HANDLER('p', handle_get_register), + DEL_HANDLER('j', handle_get_json_request), + DEL_HANDLER('m', handle_get_read_memory), + DEL_HANDLER('M', handle_get_write_memory), + DEL_HANDLER('x', handle_get_read_binary_memory), + DEL_HANDLER('Z', handle_add_break), + DEL_HANDLER('z', handle_remove_break), + DEL_HANDLER('c', handle_continue_request), + DEL_HANDLER('k', handle_kill_request), + DEL_HANDLER('_', handle____request), + DEL_HANDLER('D', handle_detach_request), +}; + +WASMGDBServer * +wasm_create_gdbserver(const char *host, int32 *port) +{ + bh_socket_t listen_fd = (bh_socket_t)-1; + WASMGDBServer *server; + + bh_assert(port); + + if (!(server = wasm_runtime_malloc(sizeof(WASMGDBServer)))) { + LOG_ERROR("wasm gdb server error: failed to allocate memory"); + return NULL; + } + + memset(server, 0, sizeof(WASMGDBServer)); + + if (!(server->receive_ctx = + wasm_runtime_malloc(sizeof(rsp_recv_context_t)))) { + LOG_ERROR("wasm gdb server error: failed to allocate memory"); + goto fail; + } + + memset(server->receive_ctx, 0, sizeof(rsp_recv_context_t)); + + if (0 != os_socket_create(&listen_fd, true, true)) { + LOG_ERROR("wasm gdb server error: create socket failed"); + goto fail; + } + + if (0 != os_socket_bind(listen_fd, host, port)) { + LOG_ERROR("wasm gdb server error: socket bind failed"); + goto fail; + } + + LOG_WARNING("Debug server listening on %s:%" PRIu32 "\n", host, *port); + server->listen_fd = listen_fd; + + return server; + +fail: + if (listen_fd >= 0) { + os_socket_shutdown(listen_fd); + os_socket_close(listen_fd); + } + if (server->receive_ctx) + wasm_runtime_free(server->receive_ctx); + if (server) + wasm_runtime_free(server); + return NULL; +} + +bool +wasm_gdbserver_listen(WASMGDBServer *server) +{ + int32 ret; + + ret = os_socket_listen(server->listen_fd, 1); + if (ret != 0) { + LOG_ERROR("wasm gdb server error: socket listen failed"); + goto fail; + } + + LOG_VERBOSE("listen for gdb client"); + return true; + +fail: + os_socket_shutdown(server->listen_fd); + os_socket_close(server->listen_fd); + return false; +} + +bool +wasm_gdbserver_accept(WASMGDBServer *server) +{ + + bh_socket_t sockt_fd = (bh_socket_t)-1; + + LOG_VERBOSE("waiting for gdb client to connect..."); + + os_socket_accept(server->listen_fd, &sockt_fd, NULL, NULL); + if (sockt_fd < 0) { + LOG_ERROR("wasm gdb server error: socket accept failed"); + goto fail; + } + + LOG_VERBOSE("accept gdb client"); + server->socket_fd = sockt_fd; + server->noack = false; + return true; + +fail: + os_socket_shutdown(server->listen_fd); + os_socket_close(server->listen_fd); + return false; +} + +void +wasm_gdbserver_detach(WASMGDBServer *server) +{ + if (server->socket_fd > 0) { + os_socket_shutdown(server->socket_fd); + os_socket_close(server->socket_fd); + } +} + +void +wasm_close_gdbserver(WASMGDBServer *server) +{ + if (server->receive_ctx) { + wasm_runtime_free(server->receive_ctx); + } + if (server->socket_fd > 0) { + os_socket_shutdown(server->socket_fd); + os_socket_close(server->socket_fd); + } + if (server->listen_fd > 0) { + os_socket_shutdown(server->listen_fd); + os_socket_close(server->listen_fd); + } +} + +static inline void +handle_packet(WASMGDBServer *server, char request, char *payload) +{ + if (packet_handler_table[(int)request].handler != NULL) + packet_handler_table[(int)request].handler(server, payload); +} + +static void +process_packet(WASMGDBServer *server) +{ + uint8 *inbuf = (uint8 *)server->receive_ctx->receive_buffer; + char request; + char *payload = NULL; + + request = inbuf[0]; + + if (request == '\0') { + LOG_VERBOSE("ignore empty request"); + return; + } + + payload = (char *)&inbuf[1]; + + LOG_VERBOSE("receive request:%c %s\n", request, payload); + handle_packet(server, request, payload); +} + +static inline void +push_byte(rsp_recv_context_t *ctx, unsigned char ch, bool checksum) +{ + if (ctx->receive_index >= sizeof(ctx->receive_buffer)) { + LOG_ERROR("RSP message buffer overflow"); + bh_assert(false); + return; + } + + ctx->receive_buffer[ctx->receive_index++] = ch; + + if (checksum) { + ctx->check_sum += ch; + } +} + +/** + * The packet layout is: + * 1. Normal packet: + * '$' + payload + '#' + checksum(2bytes) + * ^ + * packetend + * 2. Interrupt: + * 0x03 + */ + +/* return: + * 0: incomplete message received + * 1: complete message received + * 2: interrupt message received + */ +static int +on_rsp_byte_arrive(unsigned char ch, rsp_recv_context_t *ctx) +{ + if (ctx->phase == Phase_Idle) { + ctx->receive_index = 0; + ctx->check_sum = 0; + + if (ch == 0x03) { + LOG_VERBOSE("Receive interrupt package"); + return 2; + } + else if (ch == '$') { + ctx->phase = Phase_Payload; + } + + return 0; + } + else if (ctx->phase == Phase_Payload) { + if (ch == '#') { + ctx->phase = Phase_Checksum; + push_byte(ctx, ch, false); + } + else { + push_byte(ctx, ch, true); + } + + return 0; + } + else if (ctx->phase == Phase_Checksum) { + ctx->size_in_phase++; + push_byte(ctx, ch, false); + + if (ctx->size_in_phase == 2) { + ctx->size_in_phase = 0; + + bh_assert(ctx->receive_index >= 3); + + if ((hex(ctx->receive_buffer[ctx->receive_index - 2]) << 4 + | hex(ctx->receive_buffer[ctx->receive_index - 1])) + != ctx->check_sum) { + LOG_WARNING("RSP package checksum error, ignore it"); + ctx->phase = Phase_Idle; + return 0; + } + else { + /* Change # to \0 */ + ctx->receive_buffer[ctx->receive_index - 3] = '\0'; + ctx->phase = Phase_Idle; + return 1; + } + } + + return 0; + } + + /* Should never reach here */ + bh_assert(false); + return 0; +} + +bool +wasm_gdbserver_handle_packet(WASMGDBServer *server) +{ + int32 n; + char buf[1024]; + + if (os_socket_settimeout(server->socket_fd, 1000) != 0) { + LOG_ERROR("Set socket recv timeout failed"); + return false; + } + + n = os_socket_recv(server->socket_fd, buf, sizeof(buf)); + + if (n == 0) { + handle_detach_request(server, NULL); + LOG_VERBOSE("Debugger disconnected, waiting for debugger reconnection"); + return true; + } + else if (n < 0) { +#if defined(BH_PLATFORM_WINDOWS) + if (WSAGetLastError() == WSAETIMEDOUT) +#else + if (errno == EAGAIN || errno == EWOULDBLOCK) +#endif + { + /* No bytes arrived */ + return true; + } + else { + LOG_ERROR("Socket receive error"); + return false; + } + } + else { + int32 i, ret; + + for (i = 0; i < n; i++) { + ret = on_rsp_byte_arrive(buf[i], server->receive_ctx); + + if (ret == 1) { + if (!server->noack) + write_data_raw(server, (uint8 *)"+", 1); + + process_packet(server); + } + else if (ret == 2) { + handle_interrupt(server); + } + } + } + + return true; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/gdbserver.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/gdbserver.h new file mode 100644 index 000000000..9e279a2e6 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/gdbserver.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2021 Ant Group. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _GDB_SERVER_H +#define _GDB_SERVER_H + +#include "bh_platform.h" + +#define PACKET_BUF_SIZE 0x8000 + +enum GDBStoppointType { + eStoppointInvalid = -1, + eBreakpointSoftware = 0, + eBreakpointHardware, + eWatchpointWrite, + eWatchpointRead, + eWatchpointReadWrite +}; + +typedef enum rsp_recv_phase_t { + Phase_Idle, + Phase_Payload, + Phase_Checksum +} rsp_recv_phase_t; + +/* Remote Serial Protocol Receive Context */ +typedef struct rsp_recv_context_t { + rsp_recv_phase_t phase; + uint16 receive_index; + uint16 size_in_phase; + uint8 check_sum; + /* RSP packet should not be too long */ + char receive_buffer[1024]; +} rsp_recv_context_t; + +typedef struct WasmDebugPacket { + unsigned char buf[PACKET_BUF_SIZE]; + uint32 size; +} WasmDebugPacket; + +struct WASMDebugControlThread; +typedef struct WASMGDBServer { + bh_socket_t listen_fd; + bh_socket_t socket_fd; + WasmDebugPacket pkt; + bool noack; + struct WASMDebugControlThread *thread; + rsp_recv_context_t *receive_ctx; +} WASMGDBServer; + +WASMGDBServer * +wasm_create_gdbserver(const char *host, int32 *port); + +bool +wasm_gdbserver_listen(WASMGDBServer *server); + +bool +wasm_gdbserver_accept(WASMGDBServer *server); + +void +wasm_gdbserver_detach(WASMGDBServer *server); + +void +wasm_close_gdbserver(WASMGDBServer *server); + +bool +wasm_gdbserver_handle_packet(WASMGDBServer *server); +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/handler.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/handler.c new file mode 100644 index 000000000..8d451b1a3 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/handler.c @@ -0,0 +1,876 @@ +/* + * Copyright (C) 2021 Ant Group. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_platform.h" +#include "handler.h" +#include "debug_engine.h" +#include "packets.h" +#include "utils.h" +#include "wasm_runtime.h" + +/* + * Note: A moderate MAX_PACKET_SIZE is ok because + * LLDB queries our buffer size (via qSupported PacketSize) + * and limits packet sizes accordingly. + */ + +#if defined(DEBUG_MAX_PACKET_SIZE) +#define MAX_PACKET_SIZE DEBUG_MAX_PACKET_SIZE +#else +#define MAX_PACKET_SIZE (4096) +#endif + +/* + * Note: It's assumed that MAX_PACKET_SIZE is reasonably large. + * See GetWorkingDir, WasmCallStack, etc. + */ +#if MAX_PACKET_SIZE < PATH_MAX || MAX_PACKET_SIZE < (2048 + 1) +#error MAX_PACKET_SIZE is too small +#endif + +static char *tmpbuf; +static korp_mutex tmpbuf_lock; + +int +wasm_debug_handler_init() +{ + int ret; + tmpbuf = wasm_runtime_malloc(MAX_PACKET_SIZE); + if (tmpbuf == NULL) { + LOG_ERROR("debug-engine: Packet buffer allocation failure"); + return BHT_ERROR; + } + ret = os_mutex_init(&tmpbuf_lock); + if (ret != BHT_OK) { + wasm_runtime_free(tmpbuf); + tmpbuf = NULL; + } + return ret; +} + +void +wasm_debug_handler_deinit() +{ + wasm_runtime_free(tmpbuf); + tmpbuf = NULL; + os_mutex_destroy(&tmpbuf_lock); +} + +void +handle_interrupt(WASMGDBServer *server) +{ + wasm_debug_instance_interrupt_all_threads(server->thread->debug_instance); +} + +void +handle_general_set(WASMGDBServer *server, char *payload) +{ + const char *name; + char *args; + + args = strchr(payload, ':'); + if (args) + *args++ = '\0'; + + name = payload; + LOG_VERBOSE("%s:%s\n", __FUNCTION__, payload); + + if (!strcmp(name, "StartNoAckMode")) { + server->noack = true; + write_packet(server, "OK"); + } + if (!strcmp(name, "ThreadSuffixSupported")) { + write_packet(server, ""); + } + if (!strcmp(name, "ListThreadsInStopReply")) { + write_packet(server, ""); + } + if (!strcmp(name, "EnableErrorStrings")) { + write_packet(server, "OK"); + } +} + +static void +process_xfer(WASMGDBServer *server, const char *name, char *args) +{ + const char *mode = args; + + args = strchr(args, ':'); + if (args) + *args++ = '\0'; + + if (!strcmp(name, "libraries") && !strcmp(mode, "read")) { + // TODO: how to get current wasm file name? + uint64 addr = wasm_debug_instance_get_load_addr( + (WASMDebugInstance *)server->thread->debug_instance); + os_mutex_lock(&tmpbuf_lock); +#if WASM_ENABLE_LIBC_WASI != 0 + char objname[128]; + if (!wasm_debug_instance_get_current_object_name( + (WASMDebugInstance *)server->thread->debug_instance, objname, + 128)) { + objname[0] = 0; /* use an empty string */ + } + snprintf(tmpbuf, MAX_PACKET_SIZE, + "l<library-list><library name=\"%s\"><section " + "address=\"0x%" PRIx64 "\"/></library></library-list>", + objname, addr); +#else + snprintf(tmpbuf, MAX_PACKET_SIZE, + "l<library-list><library name=\"%s\"><section " + "address=\"0x%" PRIx64 "\"/></library></library-list>", + "nobody.wasm", addr); +#endif + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); + } +} + +void +process_wasm_local(WASMGDBServer *server, char *args) +{ + int32 frame_index; + int32 local_index; + char buf[16]; + int32 size = 16; + bool ret; + + os_mutex_lock(&tmpbuf_lock); + snprintf(tmpbuf, MAX_PACKET_SIZE, "E01"); + if (sscanf(args, "%" PRId32 ";%" PRId32, &frame_index, &local_index) == 2) { + ret = wasm_debug_instance_get_local( + (WASMDebugInstance *)server->thread->debug_instance, frame_index, + local_index, buf, &size); + if (ret && size > 0) { + mem2hex(buf, tmpbuf, size); + } + } + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); +} + +void +process_wasm_global(WASMGDBServer *server, char *args) +{ + int32 frame_index; + int32 global_index; + char buf[16]; + int32 size = 16; + bool ret; + + os_mutex_lock(&tmpbuf_lock); + snprintf(tmpbuf, MAX_PACKET_SIZE, "E01"); + if (sscanf(args, "%" PRId32 ";%" PRId32, &frame_index, &global_index) + == 2) { + ret = wasm_debug_instance_get_global( + (WASMDebugInstance *)server->thread->debug_instance, frame_index, + global_index, buf, &size); + if (ret && size > 0) { + mem2hex(buf, tmpbuf, size); + } + } + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); +} + +void +handle_general_query(WASMGDBServer *server, char *payload) +{ + const char *name; + char *args; + char triple[256]; + + args = strchr(payload, ':'); + if (args) + *args++ = '\0'; + name = payload; + LOG_VERBOSE("%s:%s\n", __FUNCTION__, payload); + + if (!strcmp(name, "C")) { + uint64 pid, tid; + pid = wasm_debug_instance_get_pid( + (WASMDebugInstance *)server->thread->debug_instance); + tid = (uint64)(uintptr_t)wasm_debug_instance_get_tid( + (WASMDebugInstance *)server->thread->debug_instance); + + os_mutex_lock(&tmpbuf_lock); + snprintf(tmpbuf, MAX_PACKET_SIZE, "QCp%" PRIx64 ".%" PRIx64 "", pid, + tid); + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); + } + if (!strcmp(name, "Supported")) { + os_mutex_lock(&tmpbuf_lock); + snprintf(tmpbuf, MAX_PACKET_SIZE, + "qXfer:libraries:read+;PacketSize=%" PRIx32 ";", + MAX_PACKET_SIZE); + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); + } + + if (!strcmp(name, "Xfer")) { + name = args; + + if (!args) { + LOG_ERROR("payload parse error during handle_general_query"); + return; + } + + args = strchr(args, ':'); + + if (args) { + *args++ = '\0'; + process_xfer(server, name, args); + } + } + + if (!strcmp(name, "HostInfo")) { + mem2hex("wasm32-wamr-wasi-wasm", triple, + strlen("wasm32-wamr-wasi-wasm")); + + os_mutex_lock(&tmpbuf_lock); + snprintf(tmpbuf, MAX_PACKET_SIZE, + "vendor:wamr;ostype:wasi;arch:wasm32;" + "triple:%s;endian:little;ptrsize:4;", + triple); + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); + } + if (!strcmp(name, "ModuleInfo")) { + write_packet(server, ""); + } + if (!strcmp(name, "GetWorkingDir")) { + os_mutex_lock(&tmpbuf_lock); + if (getcwd(tmpbuf, PATH_MAX)) + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); + } + if (!strcmp(name, "QueryGDBServer")) { + write_packet(server, ""); + } + if (!strcmp(name, "VAttachOrWaitSupported")) { + write_packet(server, ""); + } + if (!strcmp(name, "ProcessInfo")) { + // Todo: process id parent-pid + uint64 pid; + pid = wasm_debug_instance_get_pid( + (WASMDebugInstance *)server->thread->debug_instance); + mem2hex("wasm32-wamr-wasi-wasm", triple, + strlen("wasm32-wamr-wasi-wasm")); + + os_mutex_lock(&tmpbuf_lock); + snprintf(tmpbuf, MAX_PACKET_SIZE, + "pid:%" PRIx64 ";parent-pid:%" PRIx64 + ";vendor:wamr;ostype:wasi;arch:wasm32;" + "triple:%s;endian:little;ptrsize:4;", + pid, pid, triple); + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); + } + if (!strcmp(name, "RegisterInfo0")) { + os_mutex_lock(&tmpbuf_lock); + snprintf( + tmpbuf, MAX_PACKET_SIZE, + "name:pc;alt-name:pc;bitsize:64;offset:0;encoding:uint;format:hex;" + "set:General Purpose Registers;gcc:16;dwarf:16;generic:pc;"); + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); + } + else if (!strncmp(name, "RegisterInfo", strlen("RegisterInfo"))) { + write_packet(server, "E45"); + } + if (!strcmp(name, "StructuredDataPlugins")) { + write_packet(server, ""); + } + + if (args && (!strcmp(name, "MemoryRegionInfo"))) { + uint64 addr = strtoll(args, NULL, 16); + WASMDebugMemoryInfo *mem_info = wasm_debug_instance_get_memregion( + (WASMDebugInstance *)server->thread->debug_instance, addr); + if (mem_info) { + char name_buf[256]; + mem2hex(mem_info->name, name_buf, strlen(mem_info->name)); + + os_mutex_lock(&tmpbuf_lock); + snprintf(tmpbuf, MAX_PACKET_SIZE, + "start:%" PRIx64 ";size:%" PRIx64 + ";permissions:%s;name:%s;", + (uint64)mem_info->start, mem_info->size, + mem_info->permisson, name_buf); + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); + + wasm_debug_instance_destroy_memregion( + (WASMDebugInstance *)server->thread->debug_instance, mem_info); + } + } + + if (!strcmp(name, "WasmData")) { + } + + if (!strcmp(name, "WasmMem")) { + } + + if (!strcmp(name, "Symbol")) { + write_packet(server, ""); + } + + if (args && (!strcmp(name, "WasmCallStack"))) { + uint64 tid = strtoll(args, NULL, 16); + uint64 buf[1024 / sizeof(uint64)]; + uint32 count = wasm_debug_instance_get_call_stack_pcs( + (WASMDebugInstance *)server->thread->debug_instance, + (korp_tid)(uintptr_t)tid, buf, 1024 / sizeof(uint64)); + + if (count > 0) { + os_mutex_lock(&tmpbuf_lock); + mem2hex((char *)buf, tmpbuf, count * sizeof(uint64)); + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); + } + else + write_packet(server, ""); + } + + if (args && (!strcmp(name, "WasmLocal"))) { + process_wasm_local(server, args); + } + + if (args && (!strcmp(name, "WasmGlobal"))) { + process_wasm_global(server, args); + } + + if (!strcmp(name, "Offsets")) { + write_packet(server, ""); + } + + if (!strncmp(name, "ThreadStopInfo", strlen("ThreadStopInfo"))) { + int32 prefix_len = strlen("ThreadStopInfo"); + uint64 tid_number = strtoll(name + prefix_len, NULL, 16); + korp_tid tid = (korp_tid)(uintptr_t)tid_number; + uint32 status; + + status = wasm_debug_instance_get_thread_status( + server->thread->debug_instance, tid); + + send_thread_stop_status(server, status, tid); + } + + if (!strcmp(name, "WatchpointSupportInfo")) { + os_mutex_lock(&tmpbuf_lock); + // Any uint32 is OK for the watchpoint support + snprintf(tmpbuf, MAX_PACKET_SIZE, "num:32;"); + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); + } +} + +void +send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid) +{ + int32 len = 0; + uint64 pc; + korp_tid tids[20]; + char pc_string[17]; + uint32 tids_count, i = 0; + uint32 gdb_status = status; + WASMExecEnv *exec_env; + const char *exception; + + if (status == 0) { + os_mutex_lock(&tmpbuf_lock); + snprintf(tmpbuf, MAX_PACKET_SIZE, "W%02x", status); + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); + return; + } + tids_count = wasm_debug_instance_get_tids( + (WASMDebugInstance *)server->thread->debug_instance, tids, 20); + pc = wasm_debug_instance_get_pc( + (WASMDebugInstance *)server->thread->debug_instance); + + if (status == WAMR_SIG_SINGSTEP) { + gdb_status = WAMR_SIG_TRAP; + } + + os_mutex_lock(&tmpbuf_lock); + // TODO: how name a wasm thread? + len += snprintf(tmpbuf, MAX_PACKET_SIZE, "T%02xthread:%" PRIx64 ";name:%s;", + gdb_status, (uint64)(uintptr_t)tid, "nobody"); + if (tids_count > 0) { + len += snprintf(tmpbuf + len, MAX_PACKET_SIZE - len, "threads:"); + while (i < tids_count) { + if (i == tids_count - 1) + len += snprintf(tmpbuf + len, MAX_PACKET_SIZE - len, + "%" PRIx64 ";", (uint64)(uintptr_t)tids[i]); + else + len += snprintf(tmpbuf + len, MAX_PACKET_SIZE - len, + "%" PRIx64 ",", (uint64)(uintptr_t)tids[i]); + i++; + } + } + mem2hex((void *)&pc, pc_string, 8); + pc_string[8 * 2] = '\0'; + + exec_env = wasm_debug_instance_get_current_env( + (WASMDebugInstance *)server->thread->debug_instance); + bh_assert(exec_env); + + exception = + wasm_runtime_get_exception(wasm_runtime_get_module_inst(exec_env)); + if (exception) { + /* When exception occurs, use reason:exception so the description can be + * correctly processed by LLDB */ + uint32 exception_len = strlen(exception); + len += + snprintf(tmpbuf + len, MAX_PACKET_SIZE - len, + "thread-pcs:%" PRIx64 ";00:%s;reason:%s;description:", pc, + pc_string, "exception"); + /* The description should be encoded as HEX */ + for (i = 0; i < exception_len; i++) { + len += snprintf(tmpbuf + len, MAX_PACKET_SIZE - len, "%02x", + exception[i]); + } + len += snprintf(tmpbuf + len, MAX_PACKET_SIZE - len, ";"); + } + else { + if (status == WAMR_SIG_TRAP) { + len += snprintf(tmpbuf + len, MAX_PACKET_SIZE - len, + "thread-pcs:%" PRIx64 ";00:%s;reason:%s;", pc, + pc_string, "breakpoint"); + } + else if (status == WAMR_SIG_SINGSTEP) { + len += snprintf(tmpbuf + len, MAX_PACKET_SIZE - len, + "thread-pcs:%" PRIx64 ";00:%s;reason:%s;", pc, + pc_string, "trace"); + } + else if (status > 0) { + len += snprintf(tmpbuf + len, MAX_PACKET_SIZE - len, + "thread-pcs:%" PRIx64 ";00:%s;reason:%s;", pc, + pc_string, "signal"); + } + } + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); +} + +void +handle_v_packet(WASMGDBServer *server, char *payload) +{ + const char *name; + char *args; + + args = strchr(payload, ';'); + if (args) + *args++ = '\0'; + name = payload; + LOG_VERBOSE("%s:%s\n", __FUNCTION__, payload); + + if (!strcmp("Cont?", name)) + write_packet(server, "vCont;c;C;s;S;"); + + if (!strcmp("Cont", name)) { + if (args) { + if (args[0] == 's' || args[0] == 'c') { + char *numstring = strchr(args, ':'); + if (numstring) { + uint64 tid_number; + korp_tid tid; + + *numstring++ = '\0'; + tid_number = strtoll(numstring, NULL, 16); + tid = (korp_tid)(uintptr_t)tid_number; + wasm_debug_instance_set_cur_thread( + (WASMDebugInstance *)server->thread->debug_instance, + tid); + + if (args[0] == 's') { + wasm_debug_instance_singlestep( + (WASMDebugInstance *)server->thread->debug_instance, + tid); + } + else { + wasm_debug_instance_continue( + (WASMDebugInstance *) + server->thread->debug_instance); + } + } + } + } + } +} + +void +handle_threadstop_request(WASMGDBServer *server, char *payload) +{ + korp_tid tid; + uint32 status; + WASMDebugInstance *debug_inst = + (WASMDebugInstance *)server->thread->debug_instance; + bh_assert(debug_inst); + + /* According to + https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#Packets, the "?" + package should be sent when connection is first established to query the + reason the target halted */ + bh_assert(debug_inst->current_state == DBG_LAUNCHING); + + /* Waiting for the stop event */ + os_mutex_lock(&debug_inst->wait_lock); + while (!debug_inst->stopped_thread) { + os_cond_wait(&debug_inst->wait_cond, &debug_inst->wait_lock); + } + os_mutex_unlock(&debug_inst->wait_lock); + + tid = debug_inst->stopped_thread->handle; + status = (uint32)debug_inst->stopped_thread->current_status->signal_flag; + + wasm_debug_instance_set_cur_thread(debug_inst, tid); + + send_thread_stop_status(server, status, tid); + + debug_inst->current_state = APP_STOPPED; + debug_inst->stopped_thread = NULL; +} + +void +handle_set_current_thread(WASMGDBServer *server, char *payload) +{ + LOG_VERBOSE("%s:%s\n", __FUNCTION__, payload); + if ('g' == *payload++) { + uint64 tid = strtoll(payload, NULL, 16); + if (tid > 0) + wasm_debug_instance_set_cur_thread( + (WASMDebugInstance *)server->thread->debug_instance, + (korp_tid)(uintptr_t)tid); + } + write_packet(server, "OK"); +} + +void +handle_get_register(WASMGDBServer *server, char *payload) +{ + uint64 regdata; + int32 i = strtol(payload, NULL, 16); + + if (i != 0) { + write_packet(server, "E01"); + return; + } + regdata = wasm_debug_instance_get_pc( + (WASMDebugInstance *)server->thread->debug_instance); + + os_mutex_lock(&tmpbuf_lock); + mem2hex((void *)®data, tmpbuf, 8); + tmpbuf[8 * 2] = '\0'; + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); +} + +void +handle_get_json_request(WASMGDBServer *server, char *payload) +{ + char *args; + + args = strchr(payload, ':'); + if (args) + *args++ = '\0'; + write_packet(server, ""); +} + +void +handle_get_read_binary_memory(WASMGDBServer *server, char *payload) +{ + write_packet(server, ""); +} + +void +handle_get_read_memory(WASMGDBServer *server, char *payload) +{ + uint64 maddr, mlen; + bool ret; + + os_mutex_lock(&tmpbuf_lock); + snprintf(tmpbuf, MAX_PACKET_SIZE, "%s", ""); + if (sscanf(payload, "%" SCNx64 ",%" SCNx64, &maddr, &mlen) == 2) { + char *buff; + + if (mlen * 2 > MAX_PACKET_SIZE) { + LOG_ERROR("Buffer overflow!"); + mlen = MAX_PACKET_SIZE / 2; + } + + buff = wasm_runtime_malloc(mlen); + if (buff) { + ret = wasm_debug_instance_get_mem( + (WASMDebugInstance *)server->thread->debug_instance, maddr, + buff, &mlen); + if (ret) { + mem2hex(buff, tmpbuf, mlen); + } + wasm_runtime_free(buff); + } + } + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); +} + +void +handle_get_write_memory(WASMGDBServer *server, char *payload) +{ + size_t hex_len; + int32 offset, act_len; + uint64 maddr, mlen; + char *buff; + bool ret; + + os_mutex_lock(&tmpbuf_lock); + snprintf(tmpbuf, MAX_PACKET_SIZE, "%s", ""); + if (sscanf(payload, "%" SCNx64 ",%" SCNx64 ":%n", &maddr, &mlen, &offset) + == 2) { + payload += offset; + hex_len = strlen(payload); + act_len = hex_len / 2 < mlen ? hex_len / 2 : mlen; + + buff = wasm_runtime_malloc(act_len); + if (buff) { + hex2mem(payload, buff, act_len); + ret = wasm_debug_instance_set_mem( + (WASMDebugInstance *)server->thread->debug_instance, maddr, + buff, &mlen); + if (ret) { + snprintf(tmpbuf, MAX_PACKET_SIZE, "%s", "OK"); + } + wasm_runtime_free(buff); + } + } + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); +} + +void +handle_breakpoint_software_add(WASMGDBServer *server, uint64 addr, + size_t length) +{ + bool ret = wasm_debug_instance_add_breakpoint( + (WASMDebugInstance *)server->thread->debug_instance, addr, length); + write_packet(server, ret ? "OK" : "EO1"); +} + +void +handle_breakpoint_software_remove(WASMGDBServer *server, uint64 addr, + size_t length) +{ + bool ret = wasm_debug_instance_remove_breakpoint( + (WASMDebugInstance *)server->thread->debug_instance, addr, length); + write_packet(server, ret ? "OK" : "EO1"); +} + +void +handle_watchpoint_write_add(WASMGDBServer *server, uint64 addr, size_t length) +{ + bool ret = wasm_debug_instance_watchpoint_write_add( + (WASMDebugInstance *)server->thread->debug_instance, addr, length); + write_packet(server, ret ? "OK" : "EO1"); +} + +void +handle_watchpoint_write_remove(WASMGDBServer *server, uint64 addr, + size_t length) +{ + bool ret = wasm_debug_instance_watchpoint_write_remove( + (WASMDebugInstance *)server->thread->debug_instance, addr, length); + write_packet(server, ret ? "OK" : "EO1"); +} + +void +handle_watchpoint_read_add(WASMGDBServer *server, uint64 addr, size_t length) +{ + bool ret = wasm_debug_instance_watchpoint_read_add( + (WASMDebugInstance *)server->thread->debug_instance, addr, length); + write_packet(server, ret ? "OK" : "EO1"); +} + +void +handle_watchpoint_read_remove(WASMGDBServer *server, uint64 addr, size_t length) +{ + bool ret = wasm_debug_instance_watchpoint_read_remove( + (WASMDebugInstance *)server->thread->debug_instance, addr, length); + write_packet(server, ret ? "OK" : "EO1"); +} + +void +handle_add_break(WASMGDBServer *server, char *payload) +{ + int arg_c; + size_t type, length; + uint64 addr; + + if ((arg_c = sscanf(payload, "%zx,%" SCNx64 ",%zx", &type, &addr, &length)) + != 3) { + LOG_ERROR("Unsupported number of add break arguments %d", arg_c); + write_packet(server, ""); + return; + } + + switch (type) { + case eBreakpointSoftware: + handle_breakpoint_software_add(server, addr, length); + break; + case eWatchpointWrite: + handle_watchpoint_write_add(server, addr, length); + break; + case eWatchpointRead: + handle_watchpoint_read_add(server, addr, length); + break; + case eWatchpointReadWrite: + handle_watchpoint_write_add(server, addr, length); + handle_watchpoint_read_add(server, addr, length); + break; + default: + LOG_ERROR("Unsupported breakpoint type %zu", type); + write_packet(server, ""); + break; + } +} + +void +handle_remove_break(WASMGDBServer *server, char *payload) +{ + int arg_c; + size_t type, length; + uint64 addr; + + if ((arg_c = sscanf(payload, "%zx,%" SCNx64 ",%zx", &type, &addr, &length)) + != 3) { + LOG_ERROR("Unsupported number of remove break arguments %d", arg_c); + write_packet(server, ""); + return; + } + + switch (type) { + case eBreakpointSoftware: + handle_breakpoint_software_remove(server, addr, length); + break; + case eWatchpointWrite: + handle_watchpoint_write_remove(server, addr, length); + break; + case eWatchpointRead: + handle_watchpoint_read_remove(server, addr, length); + break; + case eWatchpointReadWrite: + handle_watchpoint_write_remove(server, addr, length); + handle_watchpoint_read_remove(server, addr, length); + break; + default: + LOG_ERROR("Unsupported breakpoint type %zu", type); + write_packet(server, ""); + break; + } +} + +void +handle_continue_request(WASMGDBServer *server, char *payload) +{ + wasm_debug_instance_continue( + (WASMDebugInstance *)server->thread->debug_instance); +} + +void +handle_kill_request(WASMGDBServer *server, char *payload) +{ + wasm_debug_instance_kill( + (WASMDebugInstance *)server->thread->debug_instance); +} + +static void +handle_malloc(WASMGDBServer *server, char *payload) +{ + char *args; + uint64 addr, size; + int32 map_prot = MMAP_PROT_NONE; + + args = strstr(payload, ","); + if (args) { + *args++ = '\0'; + } + else { + LOG_ERROR("Payload parse error during handle malloc"); + return; + } + + os_mutex_lock(&tmpbuf_lock); + snprintf(tmpbuf, MAX_PACKET_SIZE, "%s", "E03"); + + size = strtoll(payload, NULL, 16); + if (size > 0) { + while (*args) { + if (*args == 'r') { + map_prot |= MMAP_PROT_READ; + } + if (*args == 'w') { + map_prot |= MMAP_PROT_WRITE; + } + if (*args == 'x') { + map_prot |= MMAP_PROT_EXEC; + } + args++; + } + addr = wasm_debug_instance_mmap( + (WASMDebugInstance *)server->thread->debug_instance, size, + map_prot); + if (addr) { + snprintf(tmpbuf, MAX_PACKET_SIZE, "%" PRIx64, addr); + } + } + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); +} + +static void +handle_free(WASMGDBServer *server, char *payload) +{ + uint64 addr; + bool ret; + + os_mutex_lock(&tmpbuf_lock); + snprintf(tmpbuf, MAX_PACKET_SIZE, "%s", "E03"); + addr = strtoll(payload, NULL, 16); + + ret = wasm_debug_instance_ummap( + (WASMDebugInstance *)server->thread->debug_instance, addr); + if (ret) { + snprintf(tmpbuf, MAX_PACKET_SIZE, "%s", "OK"); + } + + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); +} + +void +handle____request(WASMGDBServer *server, char *payload) +{ + char *args; + + if (payload[0] == 'M') { + args = payload + 1; + handle_malloc(server, args); + } + if (payload[0] == 'm') { + args = payload + 1; + handle_free(server, args); + } +} + +void +handle_detach_request(WASMGDBServer *server, char *payload) +{ + if (payload != NULL) { + write_packet(server, "OK"); + } + wasm_debug_instance_detach( + (WASMDebugInstance *)server->thread->debug_instance); +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/handler.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/handler.h new file mode 100644 index 000000000..af2566da5 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/handler.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2021 Ant Group. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef HANDLER_H +#define HANDLER_H + +#include "gdbserver.h" + +int +wasm_debug_handler_init(); + +void +wasm_debug_handler_deinit(); + +void +handle_interrupt(WASMGDBServer *server); + +void +handle_general_set(WASMGDBServer *server, char *payload); + +void +handle_general_query(WASMGDBServer *server, char *payload); + +void +handle_v_packet(WASMGDBServer *server, char *payload); + +void +handle_threadstop_request(WASMGDBServer *server, char *payload); + +void +handle_set_current_thread(WASMGDBServer *server, char *payload); + +void +handle_get_register(WASMGDBServer *server, char *payload); + +void +handle_get_json_request(WASMGDBServer *server, char *payload); + +void +handle_get_read_binary_memory(WASMGDBServer *server, char *payload); + +void +handle_get_read_memory(WASMGDBServer *server, char *payload); + +void +handle_get_write_memory(WASMGDBServer *server, char *payload); + +void +handle_add_break(WASMGDBServer *server, char *payload); + +void +handle_remove_break(WASMGDBServer *server, char *payload); + +void +handle_continue_request(WASMGDBServer *server, char *payload); + +void +handle_kill_request(WASMGDBServer *server, char *payload); + +void +handle____request(WASMGDBServer *server, char *payload); + +void +handle_detach_request(WASMGDBServer *server, char *payload); + +void +send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid); +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/packets.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/packets.c new file mode 100644 index 000000000..1bdb3d2ce --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/packets.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2021 Ant Group. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_platform.h" +#include "packets.h" +#include "gdbserver.h" + +void +write_data_raw(WASMGDBServer *gdbserver, const uint8 *data, ssize_t len) +{ + ssize_t nwritten; + + nwritten = os_socket_send(gdbserver->socket_fd, data, len); + if (nwritten < 0) { + LOG_ERROR("Write error\n"); + exit(-2); + } +} + +void +write_hex(WASMGDBServer *gdbserver, unsigned long hex) +{ + char buf[32]; + size_t len; + + len = snprintf(buf, sizeof(buf) - 1, "%02lx", hex); + write_data_raw(gdbserver, (uint8 *)buf, len); +} + +void +write_packet_bytes(WASMGDBServer *gdbserver, const uint8 *data, + size_t num_bytes) +{ + uint8 checksum; + size_t i; + + write_data_raw(gdbserver, (uint8 *)"$", 1); + for (i = 0, checksum = 0; i < num_bytes; ++i) + checksum += data[i]; + write_data_raw(gdbserver, (uint8 *)data, num_bytes); + write_data_raw(gdbserver, (uint8 *)"#", 1); + write_hex(gdbserver, checksum); +} + +void +write_packet(WASMGDBServer *gdbserver, const char *data) +{ + LOG_VERBOSE("send replay:%s", data); + write_packet_bytes(gdbserver, (const uint8 *)data, strlen(data)); +} + +void +write_binary_packet(WASMGDBServer *gdbserver, const char *pfx, + const uint8 *data, ssize_t num_bytes) +{ + uint8 *buf; + ssize_t pfx_num_chars = strlen(pfx); + ssize_t buf_num_bytes = 0, total_size; + int32 i; + + total_size = 2 * num_bytes + pfx_num_chars; + buf = wasm_runtime_malloc(total_size); + if (!buf) { + LOG_ERROR("Failed to allocate memory for binary packet"); + return; + } + + memset(buf, 0, total_size); + memcpy(buf, pfx, pfx_num_chars); + buf_num_bytes += pfx_num_chars; + + for (i = 0; i < num_bytes; ++i) { + uint8 b = data[i]; + switch (b) { + case '#': + case '$': + case '}': + case '*': + buf[buf_num_bytes++] = '}'; + buf[buf_num_bytes++] = b ^ 0x20; + break; + default: + buf[buf_num_bytes++] = b; + break; + } + } + write_packet_bytes(gdbserver, buf, buf_num_bytes); + wasm_runtime_free(buf); +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/packets.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/packets.h new file mode 100644 index 000000000..b35889394 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/packets.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2021 Ant Group. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef PACKETS_H +#define PACKETS_H + +#include "gdbserver.h" + +void +write_data_raw(WASMGDBServer *gdbserver, const uint8 *data, ssize_t len); + +void +write_packet(WASMGDBServer *gdbserver, const char *data); + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/utils.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/utils.c new file mode 100644 index 000000000..4d9299c1b --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/utils.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 Ant Group. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "utils.h" + +static const char hexchars[] = "0123456789abcdef"; + +int32 +hex(char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +char * +mem2hex(char *mem, char *buf, int32 count) +{ + uint8 ch; + + for (int i = 0; i < count; i++) { + ch = *(mem++); + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + return (buf); +} + +char * +hex2mem(char *buf, char *mem, int32 count) +{ + uint8 ch; + + for (int i = 0; i < count; i++) { + ch = hex(*buf++) << 4; + ch = ch + hex(*buf++); + *(mem++) = ch; + } + return (mem); +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/utils.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/utils.h new file mode 100644 index 000000000..1c7580859 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/utils.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2021 Ant Group. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef UTILS_H +#define UTILS_H + +#include "bh_platform.h" + +int32 +hex(char ch); + +char * +mem2hex(char *mem, char *buf, int32 count); + +char * +hex2mem(char *buf, char *mem, int32 count); + +int32 +unescape(char *msg, int32 len); + +#endif /* UTILS_H */ diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-pthread/SConscript b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-pthread/SConscript new file mode 100644 index 000000000..d03936c2f --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-pthread/SConscript @@ -0,0 +1,20 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * + +cwd = GetCurrentDir() + +src = Split(''' +libc_pthread_wrapper.c +''') + +CPPPATH = [cwd] + + +group = DefineGroup('iwasm_libc_pthread', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-pthread/lib_pthread.cmake b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-pthread/lib_pthread.cmake new file mode 100644 index 000000000..134edf0e8 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-pthread/lib_pthread.cmake @@ -0,0 +1,17 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (LIB_PTHREAD_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions (-DWASM_ENABLE_LIB_PTHREAD=1) + +if (WAMR_BUILD_LIB_PTHREAD_SEMAPHORE EQUAL 1) +add_definitions (-DWASM_ENABLE_LIB_PTHREAD_SEMAPHORE=1) +endif() + +include_directories(${LIB_PTHREAD_DIR}) + +file (GLOB source_all ${LIB_PTHREAD_DIR}/*.c) + +set (LIB_PTHREAD_SOURCE ${source_all}) + diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c new file mode 100644 index 000000000..206479c2a --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -0,0 +1,1331 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_common.h" +#include "bh_log.h" +#include "wasm_export.h" +#include "../interpreter/wasm.h" +#include "../common/wasm_runtime_common.h" +#include "thread_manager.h" + +#if WASM_ENABLE_INTERP != 0 +#include "wasm_runtime.h" +#endif + +#if WASM_ENABLE_AOT != 0 +#include "aot_runtime.h" +#endif + +#define WAMR_PTHREAD_KEYS_MAX 32 + +/* clang-format off */ +#define get_module(exec_env) \ + wasm_exec_env_get_module(exec_env) + +#define get_module_inst(exec_env) \ + wasm_runtime_get_module_inst(exec_env) + +#define get_thread_arg(exec_env) \ + wasm_exec_env_get_thread_arg(exec_env) + +#define get_wasi_ctx(module_inst) \ + wasm_runtime_get_wasi_ctx(module_inst) + +#define validate_app_addr(offset, size) \ + wasm_runtime_validate_app_addr(module_inst, offset, size) + +#define validate_native_addr(addr, size) \ + wasm_runtime_validate_native_addr(module_inst, addr, size) + +#define addr_app_to_native(offset) \ + wasm_runtime_addr_app_to_native(module_inst, offset) + +#define addr_native_to_app(ptr) \ + wasm_runtime_addr_native_to_app(module_inst, ptr) +/* clang-format on */ + +enum { + T_THREAD, + T_MUTEX, + T_COND, + T_SEM, +}; + +enum thread_status_t { + THREAD_INIT, + THREAD_RUNNING, + THREAD_CANCELLED, + THREAD_EXIT, +}; + +enum mutex_status_t { + MUTEX_CREATED, + MUTEX_DESTROYED, +}; + +enum cond_status_t { + COND_CREATED, + COND_DESTROYED, +}; + +enum sem_status_t { + SEM_CREATED, + SEM_CLOSED, + SEM_DESTROYED, +}; + +typedef struct ThreadKeyValueNode { + bh_list_link l; + wasm_exec_env_t exec_env; + int32 thread_key_values[WAMR_PTHREAD_KEYS_MAX]; +} ThreadKeyValueNode; + +typedef struct KeyData { + int32 destructor_func; + bool is_created; +} KeyData; + +typedef struct ClusterInfoNode { + bh_list_link l; + WASMCluster *cluster; + HashMap *thread_info_map; + /* Key data list */ + KeyData key_data_list[WAMR_PTHREAD_KEYS_MAX]; + korp_mutex key_data_list_lock; + /* Every node contains the key value list for a thread */ + bh_list thread_list_head; + bh_list *thread_list; +} ClusterInfoNode; + +typedef struct ThreadInfoNode { + wasm_exec_env_t parent_exec_env; + wasm_exec_env_t exec_env; + /* the id returned to app */ + uint32 handle; + /* type can be [THREAD | MUTEX | CONDITION] */ + uint32 type; + /* Thread status, this variable should be volatile + as its value may be changed in different threads */ + volatile uint32 status; + bool joinable; + union { + korp_tid thread; + korp_mutex *mutex; + korp_cond *cond; +#if WASM_ENABLE_LIB_PTHREAD_SEMAPHORE != 0 + korp_sem *sem; +#endif + /* A copy of the thread return value */ + void *ret; + } u; +} ThreadInfoNode; + +typedef struct { + ThreadInfoNode *info_node; + /* table elem index of the app's entry function */ + uint32 elem_index; + /* arg of the app's entry function */ + uint32 arg; + wasm_module_inst_t module_inst; +} ThreadRoutineArgs; + +typedef struct { + uint32 handle; + ThreadInfoNode *node; +} SemCallbackArgs; + +static bh_list cluster_info_list; +#if WASM_ENABLE_LIB_PTHREAD_SEMAPHORE != 0 +static HashMap *sem_info_map; +#endif +static korp_mutex thread_global_lock; +static uint32 handle_id = 1; + +static void +lib_pthread_destroy_callback(WASMCluster *cluster); + +static uint32 +thread_handle_hash(void *handle) +{ + return (uint32)(uintptr_t)handle; +} + +static bool +thread_handle_equal(void *h1, void *h2) +{ + return (uint32)(uintptr_t)h1 == (uint32)(uintptr_t)h2 ? true : false; +} + +static void +thread_info_destroy(void *node) +{ + ThreadInfoNode *info_node = (ThreadInfoNode *)node; + + os_mutex_lock(&thread_global_lock); + if (info_node->type == T_MUTEX) { + if (info_node->status != MUTEX_DESTROYED) + os_mutex_destroy(info_node->u.mutex); + wasm_runtime_free(info_node->u.mutex); + } + else if (info_node->type == T_COND) { + if (info_node->status != COND_DESTROYED) + os_cond_destroy(info_node->u.cond); + wasm_runtime_free(info_node->u.cond); + } +#if WASM_ENABLE_LIB_PTHREAD_SEMAPHORE != 0 + else if (info_node->type == T_SEM) { + if (info_node->status != SEM_DESTROYED) + os_sem_close(info_node->u.sem); + } +#endif + wasm_runtime_free(info_node); + os_mutex_unlock(&thread_global_lock); +} + +bool +lib_pthread_init() +{ + if (0 != os_mutex_init(&thread_global_lock)) + return false; + bh_list_init(&cluster_info_list); + if (!wasm_cluster_register_destroy_callback(lib_pthread_destroy_callback)) { + os_mutex_destroy(&thread_global_lock); + return false; + } +#if WASM_ENABLE_LIB_PTHREAD_SEMAPHORE != 0 + if (!(sem_info_map = bh_hash_map_create( + 32, true, (HashFunc)wasm_string_hash, + (KeyEqualFunc)wasm_string_equal, NULL, thread_info_destroy))) { + os_mutex_destroy(&thread_global_lock); + return false; + } +#endif + return true; +} + +void +lib_pthread_destroy() +{ +#if WASM_ENABLE_LIB_PTHREAD_SEMAPHORE != 0 + bh_hash_map_destroy(sem_info_map); +#endif + os_mutex_destroy(&thread_global_lock); +} + +static ClusterInfoNode * +get_cluster_info(WASMCluster *cluster) +{ + ClusterInfoNode *node; + + os_mutex_lock(&thread_global_lock); + node = bh_list_first_elem(&cluster_info_list); + + while (node) { + if (cluster == node->cluster) { + os_mutex_unlock(&thread_global_lock); + return node; + } + node = bh_list_elem_next(node); + } + os_mutex_unlock(&thread_global_lock); + + return NULL; +} + +static KeyData * +key_data_list_lookup(wasm_exec_env_t exec_env, int32 key) +{ + ClusterInfoNode *node; + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + + if ((node = get_cluster_info(cluster))) { + return (key >= 0 && key < WAMR_PTHREAD_KEYS_MAX + && node->key_data_list[key].is_created) + ? &(node->key_data_list[key]) + : NULL; + } + + return NULL; +} + +/** + * Lookup the thread key value node for a thread, create a new one if failed + * This design will reduce the memory usage. If the thread doesn't use the + * local storage, it will not occupy memory space. + */ +static int32 * +key_value_list_lookup_or_create(wasm_exec_env_t exec_env, ClusterInfoNode *info, + int32 key) +{ + KeyData *key_node; + ThreadKeyValueNode *data; + + /* Check if the key is valid */ + key_node = key_data_list_lookup(exec_env, key); + if (!key_node) { + return NULL; + } + + /* Find key values node */ + data = bh_list_first_elem(info->thread_list); + while (data) { + if (data->exec_env == exec_env) + return data->thread_key_values; + data = bh_list_elem_next(data); + } + + /* If not found, create a new node for this thread */ + if (!(data = wasm_runtime_malloc(sizeof(ThreadKeyValueNode)))) + return NULL; + memset(data, 0, sizeof(ThreadKeyValueNode)); + data->exec_env = exec_env; + + if (bh_list_insert(info->thread_list, data) != 0) { + wasm_runtime_free(data); + return NULL; + } + + return data->thread_key_values; +} + +static void +call_key_destructor(wasm_exec_env_t exec_env) +{ + int32 i; + uint32 destructor_index; + KeyData *key_node; + ThreadKeyValueNode *value_node; + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + ClusterInfoNode *info = get_cluster_info(cluster); + + if (!info) { + return; + } + + value_node = bh_list_first_elem(info->thread_list); + while (value_node) { + if (value_node->exec_env == exec_env) + break; + value_node = bh_list_elem_next(value_node); + } + + /* This thread hasn't created key value node */ + if (!value_node) + return; + + /* Destroy key values */ + for (i = 0; i < WAMR_PTHREAD_KEYS_MAX; i++) { + if (value_node->thread_key_values[i] != 0) { + int32 value = value_node->thread_key_values[i]; + os_mutex_lock(&info->key_data_list_lock); + + if ((key_node = key_data_list_lookup(exec_env, i))) + destructor_index = key_node->destructor_func; + else + destructor_index = 0; + os_mutex_unlock(&info->key_data_list_lock); + + /* reset key value */ + value_node->thread_key_values[i] = 0; + + /* Call the destructor func provided by app */ + if (destructor_index) { + uint32 argv[1]; + + argv[0] = value; + wasm_runtime_call_indirect(exec_env, destructor_index, 1, argv); + } + } + } + + bh_list_remove(info->thread_list, value_node); + wasm_runtime_free(value_node); +} + +static void +destroy_thread_key_value_list(bh_list *list) +{ + ThreadKeyValueNode *node, *next; + + /* There should be only one node for main thread */ + bh_assert(list->len <= 1); + + if (list->len) { + node = bh_list_first_elem(list); + while (node) { + next = bh_list_elem_next(node); + call_key_destructor(node->exec_env); + node = next; + } + } +} + +static ClusterInfoNode * +create_cluster_info(WASMCluster *cluster) +{ + ClusterInfoNode *node; + bh_list_status ret; + + if (!(node = wasm_runtime_malloc(sizeof(ClusterInfoNode)))) { + return NULL; + } + memset(node, 0, sizeof(ClusterInfoNode)); + + node->thread_list = &node->thread_list_head; + ret = bh_list_init(node->thread_list); + bh_assert(ret == BH_LIST_SUCCESS); + + if (os_mutex_init(&node->key_data_list_lock) != 0) { + wasm_runtime_free(node); + return NULL; + } + + node->cluster = cluster; + if (!(node->thread_info_map = bh_hash_map_create( + 32, true, (HashFunc)thread_handle_hash, + (KeyEqualFunc)thread_handle_equal, NULL, thread_info_destroy))) { + os_mutex_destroy(&node->key_data_list_lock); + wasm_runtime_free(node); + return NULL; + } + os_mutex_lock(&thread_global_lock); + ret = bh_list_insert(&cluster_info_list, node); + bh_assert(ret == BH_LIST_SUCCESS); + os_mutex_unlock(&thread_global_lock); + + (void)ret; + return node; +} + +static bool +destroy_cluster_info(WASMCluster *cluster) +{ + ClusterInfoNode *node = get_cluster_info(cluster); + if (node) { + bh_hash_map_destroy(node->thread_info_map); + destroy_thread_key_value_list(node->thread_list); + os_mutex_destroy(&node->key_data_list_lock); + + /* Remove from the cluster info list */ + os_mutex_lock(&thread_global_lock); + bh_list_remove(&cluster_info_list, node); + wasm_runtime_free(node); + os_mutex_unlock(&thread_global_lock); + return true; + } + return false; +} + +static void +lib_pthread_destroy_callback(WASMCluster *cluster) +{ + destroy_cluster_info(cluster); +} + +static void +delete_thread_info_node(ThreadInfoNode *thread_info) +{ + ClusterInfoNode *node; + bool ret; + WASMCluster *cluster = wasm_exec_env_get_cluster(thread_info->exec_env); + + if ((node = get_cluster_info(cluster))) { + ret = bh_hash_map_remove(node->thread_info_map, + (void *)(uintptr_t)thread_info->handle, NULL, + NULL); + (void)ret; + } + + thread_info_destroy(thread_info); +} + +static bool +append_thread_info_node(ThreadInfoNode *thread_info) +{ + ClusterInfoNode *node; + WASMCluster *cluster = wasm_exec_env_get_cluster(thread_info->exec_env); + + if (!(node = get_cluster_info(cluster))) { + if (!(node = create_cluster_info(cluster))) { + return false; + } + } + + if (!bh_hash_map_insert(node->thread_info_map, + (void *)(uintptr_t)thread_info->handle, + thread_info)) { + return false; + } + + return true; +} + +static ThreadInfoNode * +get_thread_info(wasm_exec_env_t exec_env, uint32 handle) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + ClusterInfoNode *info = get_cluster_info(cluster); + + if (!info) { + return NULL; + } + + return bh_hash_map_find(info->thread_info_map, (void *)(uintptr_t)handle); +} + +static uint32 +allocate_handle() +{ + uint32 id; + os_mutex_lock(&thread_global_lock); + id = handle_id++; + os_mutex_unlock(&thread_global_lock); + return id; +} + +static void * +pthread_start_routine(void *arg) +{ + wasm_exec_env_t exec_env = (wasm_exec_env_t)arg; + wasm_exec_env_t parent_exec_env; + ThreadRoutineArgs *routine_args = exec_env->thread_arg; + ThreadInfoNode *info_node = routine_args->info_node; + uint32 argv[1]; + + parent_exec_env = info_node->parent_exec_env; + os_mutex_lock(&parent_exec_env->wait_lock); + info_node->exec_env = exec_env; + info_node->u.thread = exec_env->handle; + if (!append_thread_info_node(info_node)) { + delete_thread_info_node(info_node); + os_cond_signal(&parent_exec_env->wait_cond); + os_mutex_unlock(&parent_exec_env->wait_lock); + return NULL; + } + + info_node->status = THREAD_RUNNING; + os_cond_signal(&parent_exec_env->wait_cond); + os_mutex_unlock(&parent_exec_env->wait_lock); + + wasm_exec_env_set_thread_info(exec_env); + argv[0] = routine_args->arg; + + if (!wasm_runtime_call_indirect(exec_env, routine_args->elem_index, 1, + argv)) { + /* Exception has already been spread during throwing */ + } + + /* destroy pthread key values */ + call_key_destructor(exec_env); + + wasm_runtime_free(routine_args); + + /* if the thread is joinable, store the result in its info node, + if the other threads join this thread after exited, then we + can return the stored result */ + if (!info_node->joinable) { + delete_thread_info_node(info_node); + } + else { + info_node->u.ret = (void *)(uintptr_t)argv[0]; +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (exec_env->suspend_flags.flags & 0x08) + /* argv[0] isn't set after longjmp(1) to + invoke_native_with_hw_bound_check */ + info_node->u.ret = exec_env->thread_ret_value; +#endif + /* Update node status after ret value was set */ + info_node->status = THREAD_EXIT; + } + + return (void *)(uintptr_t)argv[0]; +} + +static int +pthread_create_wrapper(wasm_exec_env_t exec_env, + uint32 *thread, /* thread_handle */ + const void *attr, /* not supported */ + uint32 elem_index, /* entry function */ + uint32 arg) /* arguments buffer */ +{ + wasm_module_t module = get_module(exec_env); + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasm_module_inst_t new_module_inst = NULL; + ThreadInfoNode *info_node = NULL; + ThreadRoutineArgs *routine_args = NULL; + uint32 thread_handle; + uint32 stack_size = 8192; + int32 ret = -1; +#if WASM_ENABLE_LIBC_WASI != 0 + WASIContext *wasi_ctx; +#endif + + bh_assert(module); + bh_assert(module_inst); + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + stack_size = + ((WASMModuleInstance *)module_inst)->default_wasm_stack_size; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + stack_size = + ((AOTModuleInstance *)module_inst)->default_wasm_stack_size; + } +#endif + + if (!(new_module_inst = wasm_runtime_instantiate_internal( + module, true, exec_env, stack_size, 0, NULL, 0))) + return -1; + + /* Set custom_data to new module instance */ + wasm_runtime_set_custom_data_internal( + new_module_inst, wasm_runtime_get_custom_data(module_inst)); + +#if WASM_ENABLE_LIBC_WASI != 0 + wasi_ctx = get_wasi_ctx(module_inst); + if (wasi_ctx) + wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx); +#endif + + if (!(wasm_cluster_dup_c_api_imports(new_module_inst, module_inst))) + goto fail; + + if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode)))) + goto fail; + + memset(info_node, 0, sizeof(ThreadInfoNode)); + thread_handle = allocate_handle(); + info_node->parent_exec_env = exec_env; + info_node->handle = thread_handle; + info_node->type = T_THREAD; + info_node->status = THREAD_INIT; + info_node->joinable = true; + + if (!(routine_args = wasm_runtime_malloc(sizeof(ThreadRoutineArgs)))) + goto fail; + + routine_args->arg = arg; + routine_args->elem_index = elem_index; + routine_args->info_node = info_node; + routine_args->module_inst = new_module_inst; + + os_mutex_lock(&exec_env->wait_lock); + ret = + wasm_cluster_create_thread(exec_env, new_module_inst, true, + pthread_start_routine, (void *)routine_args); + if (ret != 0) { + os_mutex_unlock(&exec_env->wait_lock); + goto fail; + } + + /* Wait for the thread routine to assign the exec_env to + thread_info_node, otherwise the exec_env in the thread + info node may be NULL in the next pthread API call */ + os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); + os_mutex_unlock(&exec_env->wait_lock); + + if (thread) + *thread = thread_handle; + + return 0; + +fail: + if (new_module_inst) + wasm_runtime_deinstantiate_internal(new_module_inst, true); + if (info_node) + wasm_runtime_free(info_node); + if (routine_args) + wasm_runtime_free(routine_args); + return ret; +} + +static int32 +pthread_join_wrapper(wasm_exec_env_t exec_env, uint32 thread, + int32 retval_offset) /* void **retval */ +{ + uint32 *ret; + int32 join_ret; + void **retval; + ThreadInfoNode *node; + wasm_module_inst_t module_inst; + wasm_exec_env_t target_exec_env; + + module_inst = get_module_inst(exec_env); + + /* validate addr, we can use current thread's + module instance here as the memory is shared */ + if (!validate_app_addr(retval_offset, sizeof(int32))) { + /* Join failed, but we don't want to terminate all threads, + do not spread exception here */ + wasm_runtime_set_exception(module_inst, NULL); + return -1; + } + + retval = (void **)addr_app_to_native(retval_offset); + + node = get_thread_info(exec_env, thread); + if (!node) { + /* The thread has exited and not joinable, return 0 to app */ + return 0; + } + + target_exec_env = node->exec_env; + bh_assert(target_exec_env); + + if (node->status != THREAD_EXIT) { + /* if the thread is still running, call the platforms join API */ + join_ret = wasm_cluster_join_thread(target_exec_env, (void **)&ret); + } + else { + /* if the thread has exited, return stored results */ + + /* this thread must be joinable, otherwise the + info_node should be destroyed once exit */ + bh_assert(node->joinable); + join_ret = 0; + ret = node->u.ret; + } + + if (retval_offset != 0) + *(uint32 *)retval = (uint32)(uintptr_t)ret; + + return join_ret; +} + +static int32 +pthread_detach_wrapper(wasm_exec_env_t exec_env, uint32 thread) +{ + ThreadInfoNode *node; + wasm_exec_env_t target_exec_env; + + node = get_thread_info(exec_env, thread); + if (!node) + return 0; + + node->joinable = false; + + target_exec_env = node->exec_env; + bh_assert(target_exec_env != NULL); + + return wasm_cluster_detach_thread(target_exec_env); +} + +static int32 +pthread_cancel_wrapper(wasm_exec_env_t exec_env, uint32 thread) +{ + ThreadInfoNode *node; + wasm_exec_env_t target_exec_env; + + node = get_thread_info(exec_env, thread); + if (!node) + return 0; + + node->status = THREAD_CANCELLED; + node->joinable = false; + + target_exec_env = node->exec_env; + bh_assert(target_exec_env != NULL); + + return wasm_cluster_cancel_thread(target_exec_env); +} + +static int32 +pthread_self_wrapper(wasm_exec_env_t exec_env) +{ + ThreadRoutineArgs *args = get_thread_arg(exec_env); + /* If thread_arg is NULL, it's the exec_env of the main thread, + return id 0 to app */ + if (!args) + return 0; + + return args->info_node->handle; +} + +/* emcc use __pthread_self rather than pthread_self */ +static int32 +__pthread_self_wrapper(wasm_exec_env_t exec_env) +{ + return pthread_self_wrapper(exec_env); +} + +static void +pthread_exit_wrapper(wasm_exec_env_t exec_env, int32 retval_offset) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + ThreadRoutineArgs *args = get_thread_arg(exec_env); + /* Currently exit main thread is not allowed */ + if (!args) + return; + +#if defined(OS_ENABLE_HW_BOUND_CHECK) && !defined(BH_PLATFORM_WINDOWS) + /* If hardware bound check enabled, don't deinstantiate module inst + and thread info node here for AoT module, as they will be freed + in pthread_start_routine */ + if (exec_env->jmpbuf_stack_top) { + wasm_cluster_exit_thread(exec_env, (void *)(uintptr_t)retval_offset); + } +#endif + + /* destroy pthread key values */ + call_key_destructor(exec_env); + + /* routine exit, destroy instance */ + wasm_runtime_deinstantiate_internal(module_inst, true); + + if (!args->info_node->joinable) { + delete_thread_info_node(args->info_node); + } + else { + args->info_node->u.ret = (void *)(uintptr_t)retval_offset; + /* Update node status after ret value was set */ + args->info_node->status = THREAD_EXIT; + } + + wasm_runtime_free(args); + + wasm_cluster_exit_thread(exec_env, (void *)(uintptr_t)retval_offset); +} + +static int32 +pthread_mutex_init_wrapper(wasm_exec_env_t exec_env, uint32 *mutex, void *attr) +{ + korp_mutex *pmutex; + ThreadInfoNode *info_node; + + if (!(pmutex = wasm_runtime_malloc(sizeof(korp_mutex)))) { + return -1; + } + + if (os_mutex_init(pmutex) != 0) { + goto fail1; + } + + if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode)))) + goto fail2; + + memset(info_node, 0, sizeof(ThreadInfoNode)); + info_node->exec_env = exec_env; + info_node->handle = allocate_handle(); + info_node->type = T_MUTEX; + info_node->u.mutex = pmutex; + info_node->status = MUTEX_CREATED; + + if (!append_thread_info_node(info_node)) + goto fail3; + + /* Return the mutex handle to app */ + if (mutex) + *(uint32 *)mutex = info_node->handle; + + return 0; + +fail3: + delete_thread_info_node(info_node); +fail2: + os_mutex_destroy(pmutex); +fail1: + wasm_runtime_free(pmutex); + + return -1; +} + +static int32 +pthread_mutex_lock_wrapper(wasm_exec_env_t exec_env, uint32 *mutex) +{ + ThreadInfoNode *info_node = get_thread_info(exec_env, *mutex); + if (!info_node || info_node->type != T_MUTEX) + return -1; + + return os_mutex_lock(info_node->u.mutex); +} + +static int32 +pthread_mutex_unlock_wrapper(wasm_exec_env_t exec_env, uint32 *mutex) +{ + ThreadInfoNode *info_node = get_thread_info(exec_env, *mutex); + if (!info_node || info_node->type != T_MUTEX) + return -1; + + return os_mutex_unlock(info_node->u.mutex); +} + +static int32 +pthread_mutex_destroy_wrapper(wasm_exec_env_t exec_env, uint32 *mutex) +{ + int32 ret_val; + ThreadInfoNode *info_node = get_thread_info(exec_env, *mutex); + if (!info_node || info_node->type != T_MUTEX) + return -1; + + ret_val = os_mutex_destroy(info_node->u.mutex); + + info_node->status = MUTEX_DESTROYED; + delete_thread_info_node(info_node); + + return ret_val; +} + +static int32 +pthread_cond_init_wrapper(wasm_exec_env_t exec_env, uint32 *cond, void *attr) +{ + korp_cond *pcond; + ThreadInfoNode *info_node; + + if (!(pcond = wasm_runtime_malloc(sizeof(korp_cond)))) { + return -1; + } + + if (os_cond_init(pcond) != 0) { + goto fail1; + } + + if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode)))) + goto fail2; + + memset(info_node, 0, sizeof(ThreadInfoNode)); + info_node->exec_env = exec_env; + info_node->handle = allocate_handle(); + info_node->type = T_COND; + info_node->u.cond = pcond; + info_node->status = COND_CREATED; + + if (!append_thread_info_node(info_node)) + goto fail3; + + /* Return the cond handle to app */ + if (cond) + *(uint32 *)cond = info_node->handle; + + return 0; + +fail3: + delete_thread_info_node(info_node); +fail2: + os_cond_destroy(pcond); +fail1: + wasm_runtime_free(pcond); + + return -1; +} + +static int32 +pthread_cond_wait_wrapper(wasm_exec_env_t exec_env, uint32 *cond, uint32 *mutex) +{ + ThreadInfoNode *cond_info_node, *mutex_info_node; + + cond_info_node = get_thread_info(exec_env, *cond); + if (!cond_info_node || cond_info_node->type != T_COND) + return -1; + + mutex_info_node = get_thread_info(exec_env, *mutex); + if (!mutex_info_node || mutex_info_node->type != T_MUTEX) + return -1; + + return os_cond_wait(cond_info_node->u.cond, mutex_info_node->u.mutex); +} + +/** + * Currently we don't support struct timespec in built-in libc, + * so the pthread_cond_timedwait use useconds instead + */ +static int32 +pthread_cond_timedwait_wrapper(wasm_exec_env_t exec_env, uint32 *cond, + uint32 *mutex, uint64 useconds) +{ + ThreadInfoNode *cond_info_node, *mutex_info_node; + + cond_info_node = get_thread_info(exec_env, *cond); + if (!cond_info_node || cond_info_node->type != T_COND) + return -1; + + mutex_info_node = get_thread_info(exec_env, *mutex); + if (!mutex_info_node || mutex_info_node->type != T_MUTEX) + return -1; + + return os_cond_reltimedwait(cond_info_node->u.cond, + mutex_info_node->u.mutex, useconds); +} + +static int32 +pthread_cond_signal_wrapper(wasm_exec_env_t exec_env, uint32 *cond) +{ + ThreadInfoNode *info_node = get_thread_info(exec_env, *cond); + if (!info_node || info_node->type != T_COND) + return -1; + + return os_cond_signal(info_node->u.cond); +} + +static int32 +pthread_cond_broadcast_wrapper(wasm_exec_env_t exec_env, uint32 *cond) +{ + ThreadInfoNode *info_node = get_thread_info(exec_env, *cond); + if (!info_node || info_node->type != T_COND) + return -1; + + return os_cond_broadcast(info_node->u.cond); +} + +static int32 +pthread_cond_destroy_wrapper(wasm_exec_env_t exec_env, uint32 *cond) +{ + int32 ret_val; + ThreadInfoNode *info_node = get_thread_info(exec_env, *cond); + if (!info_node || info_node->type != T_COND) + return -1; + + ret_val = os_cond_destroy(info_node->u.cond); + + info_node->status = COND_DESTROYED; + delete_thread_info_node(info_node); + + return ret_val; +} + +static int32 +pthread_key_create_wrapper(wasm_exec_env_t exec_env, int32 *key, + int32 destructor_elem_index) +{ + uint32 i; + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + ClusterInfoNode *info = get_cluster_info(cluster); + + if (!info) { + /* The user may call pthread_key_create in main thread, + in this case the cluster info hasn't been created */ + if (!(info = create_cluster_info(cluster))) { + return -1; + } + } + + os_mutex_lock(&info->key_data_list_lock); + for (i = 0; i < WAMR_PTHREAD_KEYS_MAX; i++) { + if (!info->key_data_list[i].is_created) { + break; + } + } + + if (i == WAMR_PTHREAD_KEYS_MAX) { + os_mutex_unlock(&info->key_data_list_lock); + return -1; + } + + info->key_data_list[i].destructor_func = destructor_elem_index; + info->key_data_list[i].is_created = true; + *key = i; + os_mutex_unlock(&info->key_data_list_lock); + + return 0; +} + +static int32 +pthread_setspecific_wrapper(wasm_exec_env_t exec_env, int32 key, + int32 value_offset) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + ClusterInfoNode *info = get_cluster_info(cluster); + int32 *key_values; + + if (!info) + return -1; + + os_mutex_lock(&info->key_data_list_lock); + + key_values = key_value_list_lookup_or_create(exec_env, info, key); + if (!key_values) { + os_mutex_unlock(&info->key_data_list_lock); + return -1; + } + + key_values[key] = value_offset; + os_mutex_unlock(&info->key_data_list_lock); + + return 0; +} + +static int32 +pthread_getspecific_wrapper(wasm_exec_env_t exec_env, int32 key) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + ClusterInfoNode *info = get_cluster_info(cluster); + int32 ret, *key_values; + + if (!info) + return 0; + + os_mutex_lock(&info->key_data_list_lock); + + key_values = key_value_list_lookup_or_create(exec_env, info, key); + if (!key_values) { + os_mutex_unlock(&info->key_data_list_lock); + return 0; + } + + ret = key_values[key]; + os_mutex_unlock(&info->key_data_list_lock); + + return ret; +} + +static int32 +pthread_key_delete_wrapper(wasm_exec_env_t exec_env, int32 key) +{ + KeyData *data; + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + ClusterInfoNode *info = get_cluster_info(cluster); + + if (!info) + return -1; + + os_mutex_lock(&info->key_data_list_lock); + data = key_data_list_lookup(exec_env, key); + if (!data) { + os_mutex_unlock(&info->key_data_list_lock); + return -1; + } + + memset(data, 0, sizeof(KeyData)); + os_mutex_unlock(&info->key_data_list_lock); + + return 0; +} + +/** + * Currently the memory allocator doesn't support alloc specific aligned + * space, we wrap posix_memalign to simply malloc memory + */ +static int32 +posix_memalign_wrapper(wasm_exec_env_t exec_env, void **memptr, int32 align, + int32 size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + void *p = NULL; + + *((int32 *)memptr) = module_malloc(size, (void **)&p); + if (!p) + return -1; + + return 0; +} + +#if WASM_ENABLE_LIB_PTHREAD_SEMAPHORE != 0 + +static int32 +sem_open_wrapper(wasm_exec_env_t exec_env, const char *name, int32 oflags, + int32 mode, int32 val) +{ + korp_sem *psem = NULL; + ThreadInfoNode *info_node = NULL; + + /** + * For RTOS, global semaphore map is safe for share the same semaphore + * between task/pthread. + * For Unix like system, it's dedicated for multiple processes. + */ + + if ((info_node = bh_hash_map_find(sem_info_map, (void *)name))) { + return info_node->handle; + } + + if (!(psem = os_sem_open(name, oflags, mode, val))) { + goto fail1; + } + + if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode)))) + goto fail2; + + memset(info_node, 0, sizeof(ThreadInfoNode)); + info_node->exec_env = exec_env; + info_node->handle = allocate_handle(); + info_node->type = T_SEM; + info_node->u.sem = psem; + info_node->status = SEM_CREATED; + + if (!bh_hash_map_insert(sem_info_map, (void *)name, info_node)) + goto fail3; + + return info_node->handle; + +fail3: + wasm_runtime_free(info_node); +fail2: + os_sem_close(psem); +fail1: + return -1; +} + +void +sem_fetch_cb(void *key, void *value, void *user_data) +{ + (void)key; + SemCallbackArgs *args = user_data; + ThreadInfoNode *info_node = value; + if (args->handle == info_node->handle && info_node->status == SEM_CREATED) { + args->node = info_node; + } +} + +static int32 +sem_close_wrapper(wasm_exec_env_t exec_env, uint32 sem) +{ + (void)exec_env; + int ret = -1; + SemCallbackArgs args = { sem, NULL }; + + bh_hash_map_traverse(sem_info_map, sem_fetch_cb, &args); + + if (args.node) { + ret = os_sem_close(args.node->u.sem); + if (ret == 0) { + args.node->status = SEM_CLOSED; + } + } + + return ret; +} + +static int32 +sem_wait_wrapper(wasm_exec_env_t exec_env, uint32 sem) +{ + (void)exec_env; + SemCallbackArgs args = { sem, NULL }; + + bh_hash_map_traverse(sem_info_map, sem_fetch_cb, &args); + + if (args.node) { + return os_sem_wait(args.node->u.sem); + } + + return -1; +} + +static int32 +sem_trywait_wrapper(wasm_exec_env_t exec_env, uint32 sem) +{ + (void)exec_env; + SemCallbackArgs args = { sem, NULL }; + + bh_hash_map_traverse(sem_info_map, sem_fetch_cb, &args); + + if (args.node) { + return os_sem_trywait(args.node->u.sem); + } + + return -1; +} + +static int32 +sem_post_wrapper(wasm_exec_env_t exec_env, uint32 sem) +{ + (void)exec_env; + SemCallbackArgs args = { sem, NULL }; + + bh_hash_map_traverse(sem_info_map, sem_fetch_cb, &args); + + if (args.node) { + return os_sem_post(args.node->u.sem); + } + + return -1; +} + +static int32 +sem_getvalue_wrapper(wasm_exec_env_t exec_env, uint32 sem, int32 *sval) +{ + int32 ret = -1; + wasm_module_inst_t module_inst = get_module_inst(exec_env); + + (void)exec_env; + SemCallbackArgs args = { sem, NULL }; + + if (validate_native_addr(sval, sizeof(int32))) { + + bh_hash_map_traverse(sem_info_map, sem_fetch_cb, &args); + + if (args.node) { + ret = os_sem_getvalue(args.node->u.sem, sval); + } + } + return ret; +} + +static int32 +sem_unlink_wrapper(wasm_exec_env_t exec_env, const char *name) +{ + (void)exec_env; + int32 ret_val; + + ThreadInfoNode *info_node = bh_hash_map_find(sem_info_map, (void *)name); + if (!info_node || info_node->type != T_SEM) + return -1; + + if (info_node->status != SEM_CLOSED) { + ret_val = os_sem_close(info_node->u.sem); + if (ret_val != 0) { + return ret_val; + } + } + + ret_val = os_sem_unlink(name); + + if (ret_val == 0) { + bh_hash_map_remove(sem_info_map, (void *)name, NULL, NULL); + info_node->status = SEM_DESTROYED; + thread_info_destroy(info_node); + } + return ret_val; +} + +#endif + +/* clang-format off */ +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, func_name##_wrapper, signature, NULL } +/* clang-format on */ + +static NativeSymbol native_symbols_lib_pthread[] = { + REG_NATIVE_FUNC(pthread_create, "(**ii)i"), + REG_NATIVE_FUNC(pthread_join, "(ii)i"), + REG_NATIVE_FUNC(pthread_detach, "(i)i"), + REG_NATIVE_FUNC(pthread_cancel, "(i)i"), + REG_NATIVE_FUNC(pthread_self, "()i"), + REG_NATIVE_FUNC(__pthread_self, "()i"), + REG_NATIVE_FUNC(pthread_exit, "(i)"), + REG_NATIVE_FUNC(pthread_mutex_init, "(**)i"), + REG_NATIVE_FUNC(pthread_mutex_lock, "(*)i"), + REG_NATIVE_FUNC(pthread_mutex_unlock, "(*)i"), + REG_NATIVE_FUNC(pthread_mutex_destroy, "(*)i"), + REG_NATIVE_FUNC(pthread_cond_init, "(**)i"), + REG_NATIVE_FUNC(pthread_cond_wait, "(**)i"), + REG_NATIVE_FUNC(pthread_cond_timedwait, "(**I)i"), + REG_NATIVE_FUNC(pthread_cond_signal, "(*)i"), + REG_NATIVE_FUNC(pthread_cond_broadcast, "(*)i"), + REG_NATIVE_FUNC(pthread_cond_destroy, "(*)i"), + REG_NATIVE_FUNC(pthread_key_create, "(*i)i"), + REG_NATIVE_FUNC(pthread_setspecific, "(ii)i"), + REG_NATIVE_FUNC(pthread_getspecific, "(i)i"), + REG_NATIVE_FUNC(pthread_key_delete, "(i)i"), + REG_NATIVE_FUNC(posix_memalign, "(*ii)i"), +#if WASM_ENABLE_LIB_PTHREAD_SEMAPHORE != 0 + REG_NATIVE_FUNC(sem_open, "($iii)i"), + REG_NATIVE_FUNC(sem_close, "(i)i"), + REG_NATIVE_FUNC(sem_wait, "(i)i"), + REG_NATIVE_FUNC(sem_trywait, "(i)i"), + REG_NATIVE_FUNC(sem_post, "(i)i"), + REG_NATIVE_FUNC(sem_getvalue, "(i*)i"), + REG_NATIVE_FUNC(sem_unlink, "($)i"), +#endif +}; + +uint32 +get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis) +{ + *p_lib_pthread_apis = native_symbols_lib_pthread; + return sizeof(native_symbols_lib_pthread) / sizeof(NativeSymbol); +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats.cmake b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats.cmake new file mode 100644 index 000000000..b773c837e --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats.cmake @@ -0,0 +1,43 @@ +# Copyright (c) 2022 Intel Corporation +# Copyright (c) 2020-2021 Alibaba Cloud +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (LIB_RATS_DIR ${CMAKE_CURRENT_LIST_DIR}) + +if ("$ENV{SGX_SSL_DIR}" STREQUAL "") + set (SGX_SSL_DIR "/opt/intel/sgxssl") +else() + set (SGX_SSL_DIR $ENV{SGX_SSL_DIR}) +endif() + +if (NOT EXISTS ${SGX_SSL_DIR}) + message(FATAL_ERROR "Can not find SGX_SSL, please install it first") +endif() + +add_definitions (-DWASM_ENABLE_LIB_RATS=1) + +include_directories(${LIB_RATS_DIR} ${SGX_SSL_DIR}/include) + +include(FetchContent) + +set(RATS_BUILD_MODE "sgx" + CACHE INTERNAL "Select build mode for librats(host|occlum|sgx|wasm)") +set(RATS_INSTALL_PATH "${CMAKE_BINARY_DIR}/librats" CACHE INTERNAL "") + +FetchContent_Declare( + librats + GIT_REPOSITORY https://github.com/inclavare-containers/librats + GIT_TAG master +) +FetchContent_GetProperties(librats) +if (NOT librats_POPULATED) + message("-- Fetching librats ..") + FetchContent_Populate(librats) + include_directories("${librats_SOURCE_DIR}/include") + add_subdirectory(${librats_SOURCE_DIR} ${librats_BINARY_DIR} EXCLUDE_FROM_ALL) + +endif() + +file (GLOB source_all ${LIB_RATS_DIR}/*.c) + +set (LIB_RATS_SOURCE ${source_all})
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_common.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_common.h new file mode 100644 index 000000000..929e105f0 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_common.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 Intel Corporation + * Copyright (c) 2020-2021 Alibaba Cloud + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _RATS_WAMR_COMMON_H +#define _RATS_WAMR_COMMON_H + +#include <stdint.h> +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define SGX_QUOTE_MAX_SIZE 8192 +#define SGX_USER_DATA_SIZE 64 +#define SGX_MEASUREMENT_SIZE 32 + +/* clang-format off */ +typedef struct rats_sgx_evidence { + uint8_t quote[SGX_QUOTE_MAX_SIZE]; /* The quote of the Enclave */ + uint32_t quote_size; /* The size of the quote */ + uint8_t user_data[SGX_USER_DATA_SIZE]; /* The custom data in the quote */ + uint32_t product_id; /* Product ID of the Enclave */ + uint8_t mr_enclave[SGX_MEASUREMENT_SIZE]; /* The MRENCLAVE of the Enclave */ + uint32_t security_version; /* Security Version of the Enclave */ + uint8_t mr_signer[SGX_MEASUREMENT_SIZE]; /* The MRSIGNER of the Enclave */ + uint64_t att_flags; /* Flags of the Enclave in attributes */ + uint64_t att_xfrm; /* XSAVE Feature Request Mask */ +} rats_sgx_evidence_t; +/* clang-format on */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_wrapper.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_wrapper.c new file mode 100644 index 000000000..59d61f4c8 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_wrapper.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2022 Intel Corporation + * Copyright (c) 2020-2021 Alibaba Cloud + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include <stdio.h> +#include <stdlib.h> +#include <librats/api.h> +#include <string.h> +#include <openssl/sha.h> + +#include "sgx_quote_3.h" +#include "wasm_export.h" +#include "bh_common.h" +#include "lib_rats_common.h" + +static int +librats_collect_wrapper(wasm_exec_env_t exec_env, char **evidence_json, + const char *buffer, uint32_t buffer_size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasm_module_t module = wasm_runtime_get_module(module_inst); + char *wasm_module_hash = wasm_runtime_get_module_hash(module); + + char *json, *str_ret; + uint32_t str_ret_offset; + uint8_t final_hash[SHA256_DIGEST_LENGTH]; + + SHA256_CTX sha256; + SHA256_Init(&sha256); + SHA256_Update(&sha256, wasm_module_hash, SHA256_DIGEST_LENGTH); + if (buffer != NULL) + SHA256_Update(&sha256, buffer, buffer_size); + SHA256_Final(final_hash, &sha256); + + int ret_code = librats_collect_evidence_to_json(final_hash, &json); + if (ret_code != 0) { + return ret_code; + } + + uint32_t json_size = strlen(json) + 1; + str_ret_offset = module_malloc(json_size, (void **)&str_ret); + if (!str_ret_offset) { + free(json); + return (int)RATS_ATTESTER_ERR_NO_MEM; + } + bh_memcpy_s(str_ret, json_size, json, json_size); + *((int *)evidence_json) = str_ret_offset; + free(json); + + return 0; +} + +static int +librats_verify_wrapper(wasm_exec_env_t exec_env, const char *evidence_json, + uint32_t evidence_size, const uint8_t *hash, + uint32_t hash_size) +{ + return librats_verify_evidence_from_json(evidence_json, hash); +} + +static int +librats_parse_evidence_wrapper(wasm_exec_env_t exec_env, + const char *evidence_json, uint32_t json_size, + rats_sgx_evidence_t *evidence, + uint32_t evidence_size) +{ + attestation_evidence_t att_ev; + + if (get_evidence_from_json(evidence_json, &att_ev) != 0) { + return -1; + } + + // Only supports parsing sgx evidence currently + if (strcmp(att_ev.type, "sgx_ecdsa") != 0) { + return -1; + } + + sgx_quote3_t *quote_ptr = (sgx_quote3_t *)att_ev.ecdsa.quote; + bh_memcpy_s(evidence->quote, att_ev.ecdsa.quote_len, att_ev.ecdsa.quote, + att_ev.ecdsa.quote_len); + evidence->quote_size = att_ev.ecdsa.quote_len; + bh_memcpy_s(evidence->user_data, SGX_REPORT_DATA_SIZE, + quote_ptr->report_body.report_data.d, SGX_REPORT_DATA_SIZE); + bh_memcpy_s(evidence->mr_enclave, sizeof(sgx_measurement_t), + quote_ptr->report_body.mr_enclave.m, sizeof(sgx_measurement_t)); + bh_memcpy_s(evidence->mr_signer, sizeof(sgx_measurement_t), + quote_ptr->report_body.mr_signer.m, sizeof(sgx_measurement_t)); + evidence->product_id = quote_ptr->report_body.isv_prod_id; + evidence->security_version = quote_ptr->report_body.isv_svn; + evidence->att_flags = quote_ptr->report_body.attributes.flags; + evidence->att_xfrm = quote_ptr->report_body.attributes.flags; + + return 0; +} + +/* clang-format off */ +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, func_name##_wrapper, signature, NULL } +/* clang-format on */ + +static NativeSymbol native_symbols_lib_rats[] = { + REG_NATIVE_FUNC(librats_collect, "(**~)i"), + REG_NATIVE_FUNC(librats_verify, "(*~*~)i"), + REG_NATIVE_FUNC(librats_parse_evidence, "(*~*~)i") +}; + +uint32_t +get_lib_rats_export_apis(NativeSymbol **p_lib_rats_apis) +{ + *p_lib_rats_apis = native_symbols_lib_rats; + return sizeof(native_symbols_lib_rats) / sizeof(NativeSymbol); +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_wrapper.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_wrapper.h new file mode 100644 index 000000000..e334983e9 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_wrapper.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022 Intel Corporation + * Copyright (c) 2020-2021 Alibaba Cloud + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _RATS_WAMR_API_H +#define _RATS_WAMR_API_H + +#include <stdint.h> +#include <string.h> + +#include "lib_rats_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int +librats_collect(char **evidence_json, const char *buffer, uint32_t buffer_size); + +int +librats_verify(const char *evidence_json, uint32_t evidence_size, + const uint8_t *hash, uint32_t hash_size); + +int +librats_parse_evidence(const char *evidence_json, uint32_t json_size, + rats_sgx_evidence_t *evidence, uint32_t evidence_size); + +#define librats_collect(evidence_json, buffer) \ + librats_collect(evidence_json, buffer, buffer ? strlen(buffer) + 1 : 0) + +#define librats_verify(evidence_json, hash) \ + librats_verify(evidence_json, \ + evidence_json ? strlen(evidence_json) + 1 : 0, hash, \ + hash ? strlen((const char *)hash) + 1 : 0) + +#define librats_parse_evidence(evidence_json, evidence) \ + librats_parse_evidence(evidence_json, \ + evidence_json ? strlen(evidence_json) + 1 : 0, \ + evidence, sizeof(rats_sgx_evidence_t)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h new file mode 100644 index 000000000..c9a07eb72 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h @@ -0,0 +1,999 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WASI_SOCKET_EXT_H_ +#define _WASI_SOCKET_EXT_H_ + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +/*Be a part of <wasi/api.h>*/ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + SOCKET_DGRAM = 0, + SOCKET_STREAM, +} __wasi_sock_type_t; + +typedef uint16_t __wasi_ip_port_t; + +typedef enum { IPv4 = 0, IPv6 } __wasi_addr_type_t; + +/* + n0.n1.n2.n3 + Example: + IP Address: 127.0.0.1 + Structure: {n0: 127, n1: 0, n2: 0, n3: 1} +*/ +typedef struct __wasi_addr_ip4_t { + uint8_t n0; + uint8_t n1; + uint8_t n2; + uint8_t n3; +} __wasi_addr_ip4_t; + +typedef struct __wasi_addr_ip4_port_t { + __wasi_addr_ip4_t addr; + __wasi_ip_port_t port; /* host byte order */ +} __wasi_addr_ip4_port_t; + +/* + n0:n1:n2:n3:h0:h1:h2:h3, each 16bit value uses host byte order + Example (little-endian system) + IP Address fe80::3ba2:893b:4be0:e3dd + Structure: { + n0: 0xfe80, n1:0x0, n2: 0x0, n3: 0x0, + h0: 0x3ba2, h1: 0x893b, h2: 0x4be0, h3: 0xe3dd + } +*/ +typedef struct __wasi_addr_ip6_t { + uint16_t n0; + uint16_t n1; + uint16_t n2; + uint16_t n3; + uint16_t h0; + uint16_t h1; + uint16_t h2; + uint16_t h3; +} __wasi_addr_ip6_t; + +typedef struct __wasi_addr_ip6_port_t { + __wasi_addr_ip6_t addr; + __wasi_ip_port_t port; /* host byte order */ +} __wasi_addr_ip6_port_t; + +typedef struct __wasi_addr_ip_t { + __wasi_addr_type_t kind; + union { + __wasi_addr_ip4_t ip4; + __wasi_addr_ip6_t ip6; + } addr; +} __wasi_addr_ip_t; + +typedef struct __wasi_addr_t { + __wasi_addr_type_t kind; + union { + __wasi_addr_ip4_port_t ip4; + __wasi_addr_ip6_port_t ip6; + } addr; +} __wasi_addr_t; + +typedef enum { INET4 = 0, INET6 } __wasi_address_family_t; + +typedef struct __wasi_addr_info_t { + __wasi_addr_t addr; + __wasi_sock_type_t type; +} __wasi_addr_info_t; + +typedef struct __wasi_addr_info_hints_t { + __wasi_sock_type_t type; + __wasi_address_family_t family; + // this is to workaround lack of optional parameters + uint8_t hints_enabled; +} __wasi_addr_info_hints_t; + +#ifdef __wasi__ +/** + * Reimplement below POSIX APIs with __wasi_sock_XXX functions. + * + * Keep sync with + * <sys/socket.h> + * <sys/types.h> + */ +#define SO_REUSEADDR 2 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_KEEPALIVE 9 +#define SO_LINGER 13 +#define SO_REUSEPORT 15 +#define SO_RCVTIMEO 20 +#define SO_SNDTIMEO 21 + +#define TCP_NODELAY 1 +#define TCP_KEEPIDLE 4 +#define TCP_KEEPINTVL 5 +#define TCP_QUICKACK 12 +#define TCP_FASTOPEN_CONNECT 30 + +#define IP_TTL 2 +#define IP_MULTICAST_TTL 33 +#define IP_MULTICAST_LOOP 34 +#define IP_ADD_MEMBERSHIP 35 +#define IP_DROP_MEMBERSHIP 36 + +#define IPV6_MULTICAST_LOOP 19 +#define IPV6_JOIN_GROUP 20 +#define IPV6_LEAVE_GROUP 21 +#define IPV6_V6ONLY 26 + +struct addrinfo { + int ai_flags; /* Input flags. */ + int ai_family; /* Protocol family for socket. */ + int ai_socktype; /* Socket type. */ + int ai_protocol; /* Protocol for socket. */ + socklen_t ai_addrlen; /* Length of socket address. */ + struct sockaddr *ai_addr; /* Socket address for socket. */ + char *ai_canonname; /* Canonical name for service location. */ + struct addrinfo *ai_next; /* Pointer to next in list. */ +}; + +#ifndef __WASI_RIGHTS_SOCK_ACCEPT +int +accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); +#endif + +int +bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); + +int +connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); + +int +listen(int sockfd, int backlog); + +ssize_t +recvmsg(int sockfd, struct msghdr *msg, int flags); + +ssize_t +sendmsg(int sockfd, const struct msghdr *msg, int flags); + +ssize_t +sendto(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen); + +ssize_t +recvfrom(int sockfd, void *buf, size_t len, int flags, + struct sockaddr *src_addr, socklen_t *addrlen); + +int +socket(int domain, int type, int protocol); + +int +getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen); + +int +getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen); + +int +getsockopt(int sockfd, int level, int optname, void *__restrict optval, + socklen_t *__restrict optlen); + +int +setsockopt(int sockfd, int level, int optname, const void *optval, + socklen_t optlen); + +int +getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, + struct addrinfo **res); + +void +freeaddrinfo(struct addrinfo *res); +#endif + +/** + * __wasi_sock_accept was introduced in wasi-sdk v15. To + * temporarily maintain backward compatibility with the old + * wasi-sdk, we explicitly add that implementation here so it works + * with older versions of the SDK. + */ +#ifndef __WASI_RIGHTS_SOCK_ACCEPT +/** + * Accept a connection on a socket + * Note: This is similar to `accept` + */ +int32_t +__imported_wasi_snapshot_preview1_sock_accept(int32_t arg0, int32_t arg1, + int32_t arg2) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_accept"))); + +static inline __wasi_errno_t +__wasi_sock_accept(__wasi_fd_t fd, __wasi_fdflags_t flags, __wasi_fd_t *fd_new) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_accept( + (int32_t)fd, (int32_t)flags, (int32_t)fd_new); +} +#endif + +/** + * Returns the local address to which the socket is bound. + * + * Note: This is similar to `getsockname` in POSIX + * + * When successful, the contents of the output buffer consist of an IP address, + * either IP4 or IP6. + */ +int32_t +__imported_wasi_snapshot_preview1_sock_addr_local(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_addr_local"))); + +static inline __wasi_errno_t +__wasi_sock_addr_local(__wasi_fd_t fd, __wasi_addr_t *addr) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_addr_local( + (int32_t)fd, (int32_t)addr); +} + +/** + * Returns the remote address to which the socket is connected to. + * + * Note: This is similar to `getpeername` in POSIX + * + * When successful, the contents of the output buffer consist of an IP address, + * either IP4 or IP6. + */ +int32_t +__imported_wasi_snapshot_preview1_sock_addr_remote(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_addr_remote"))); + +static inline __wasi_errno_t +__wasi_sock_addr_remote(__wasi_fd_t fd, __wasi_addr_t *addr) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_addr_remote( + (int32_t)fd, (int32_t)addr); +} + +/** + * Resolve a hostname and a service to one or more IP addresses. Service is + * optional and you can pass empty string in most cases, it is used as a hint + * for protocol. + * + * Note: This is similar to `getaddrinfo` in POSIX + * + * When successful, the contents of the output buffer consist of a sequence of + * IPv4 and/or IPv6 addresses. Each address entry consists of a wasi_addr_t + * object. + * + * This function fills the output buffer as much as possible, truncating the + * entries that didn't fit into the buffer. A number of available addresses + * will be returned through the last parameter. + */ +int32_t +__imported_wasi_snapshot_preview1_sock_addr_resolve(int32_t arg0, int32_t arg1, + int32_t arg2, int32_t arg3, + int32_t arg4, int32_t arg5) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_addr_resolve"))); + +static inline __wasi_errno_t +__wasi_sock_addr_resolve(const char *host, const char *service, + __wasi_addr_info_hints_t *hints, + __wasi_addr_info_t *addr_info, + __wasi_size_t addr_info_size, + __wasi_size_t *max_info_size) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_addr_resolve( + (int32_t)host, (int32_t)service, (int32_t)hints, (int32_t)addr_info, + (int32_t)addr_info_size, (int32_t)max_info_size); +} + +/** + * Bind a socket + * Note: This is similar to `bind` in POSIX using PF_INET + */ +int32_t +__imported_wasi_snapshot_preview1_sock_bind(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_bind"))); + +static inline __wasi_errno_t +__wasi_sock_bind(__wasi_fd_t fd, __wasi_addr_t *addr) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_bind( + (int32_t)fd, (int32_t)addr); +} + +/** + * Send data to a specific target + * Note: This is similar to `sendto` in POSIX + */ +int32_t +__imported_wasi_snapshot_preview1_sock_send_to(int32_t arg0, int32_t arg1, + int32_t arg2, int32_t arg3, + int32_t arg4, int32_t arg5) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_send_to"))); + +static inline __wasi_errno_t +__wasi_sock_send_to(__wasi_fd_t fd, const __wasi_ciovec_t *si_data, + uint32_t si_data_len, __wasi_siflags_t si_flags, + const __wasi_addr_t *dest_addr, uint32_t *so_data_len) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_send_to( + (int32_t)fd, (int32_t)si_data, (int32_t)si_data_len, (int32_t)si_flags, + (uint32_t)dest_addr, (uint32_t)so_data_len); +} + +/** + * Receives data from a socket + * Note: This is similar to `recvfrom` in POSIX + */ +int32_t +__imported_wasi_snapshot_preview1_sock_recv_from(int32_t arg0, int32_t arg1, + int32_t arg2, int32_t arg3, + int32_t arg4, int32_t arg5) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_recv_from"))); + +static inline __wasi_errno_t +__wasi_sock_recv_from(__wasi_fd_t fd, __wasi_ciovec_t *ri_data, + uint32_t ri_data_len, __wasi_riflags_t ri_flags, + __wasi_addr_t *src_addr, uint32_t *ro_data_len) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_recv_from( + (int32_t)fd, (int32_t)ri_data, (int32_t)ri_data_len, (int32_t)ri_flags, + (uint32_t)src_addr, (uint32_t)ro_data_len); +} + +/** + * Close a socket (this is an alias for `fd_close`) + * Note: This is similar to `close` in POSIX. + */ +int32_t +__imported_wasi_snapshot_preview1_sock_close(int32_t arg0) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_close"))); + +static inline __wasi_errno_t +__wasi_sock_close(__wasi_fd_t fd) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_close( + (int32_t)fd); +} + +/** + * Initiate a connection on a socket to the specified address + * Note: This is similar to `connect` in POSIX + */ + +int32_t +__imported_wasi_snapshot_preview1_sock_connect(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_connect"))); + +static inline __wasi_errno_t +__wasi_sock_connect(__wasi_fd_t fd, __wasi_addr_t *addr) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_connect( + (int32_t)fd, (int32_t)addr); +} +/** + * Retrieve the size of the receive buffer + * Note: This is similar to `getsockopt` in POSIX for SO_RCVBUF + */ + +int32_t +__imported_wasi_snapshot_preview1_sock_get_recv_buf_size(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_recv_buf_size"))); + +static inline __wasi_errno_t +__wasi_sock_get_recv_buf_size(__wasi_fd_t fd, __wasi_size_t *size) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_recv_buf_size((int32_t)fd, + (int32_t)size); +} +/** + * Retrieve status of address reuse on a socket + * Note: This is similar to `getsockopt` in POSIX for SO_REUSEADDR + */ +int32_t +__imported_wasi_snapshot_preview1_sock_get_reuse_addr(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_reuse_addr"))); + +static inline __wasi_errno_t +__wasi_sock_get_reuse_addr(__wasi_fd_t fd, bool *reuse) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_reuse_addr((int32_t)fd, + (int32_t)reuse); +} + +/** + * Retrieve status of port reuse on a socket + * Note: This is similar to `getsockopt` in POSIX for SO_REUSEPORT + */ +int32_t +__imported_wasi_snapshot_preview1_sock_get_reuse_port(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_reuse_port"))); + +static inline __wasi_errno_t +__wasi_sock_get_reuse_port(__wasi_fd_t fd, bool *reuse) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_reuse_port((int32_t)fd, + (int32_t)reuse); +} + +/** + * Retrieve the size of the send buffer + * Note: This is similar to `getsockopt` in POSIX for SO_SNDBUF + */ +int32_t +__imported_wasi_snapshot_preview1_sock_get_send_buf_size(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_send_buf_size"))); + +static inline __wasi_errno_t +__wasi_sock_get_send_buf_size(__wasi_fd_t fd, __wasi_size_t *size) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_send_buf_size((int32_t)fd, + (int32_t)size); +} + +/** + * Listen for connections on a socket + * Note: This is similar to `listen` + */ +int32_t +__imported_wasi_snapshot_preview1_sock_listen(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_listen"))); + +static inline __wasi_errno_t +__wasi_sock_listen(__wasi_fd_t fd, __wasi_size_t backlog) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_listen( + (int32_t)fd, (int32_t)backlog); +} + +/** + * Open a socket + + * The first argument to this function is a handle to an + * address pool. The address pool determines what actions can + * be performed and at which addresses they can be performed to. + + * The address pool cannot be re-assigned. You will need to close + * the socket and open a new one to use a different address pool. + + * Note: This is similar to `socket` in POSIX using PF_INET + */ + +int32_t +__imported_wasi_snapshot_preview1_sock_open(int32_t arg0, int32_t arg1, + int32_t arg2, int32_t arg3) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_open"))); + +static inline __wasi_errno_t +__wasi_sock_open(__wasi_fd_t fd, __wasi_address_family_t af, + __wasi_sock_type_t socktype, __wasi_fd_t *sockfd) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_open( + (int32_t)fd, (int32_t)af, (int32_t)socktype, (int32_t)sockfd); +} + +/** + * Set size of receive buffer + * Note: This is similar to `setsockopt` in POSIX for SO_RCVBUF + */ +int32_t +__imported_wasi_snapshot_preview1_sock_set_recv_buf_size(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_recv_buf_size"))); + +static inline __wasi_errno_t +__wasi_sock_set_recv_buf_size(__wasi_fd_t fd, __wasi_size_t size) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_recv_buf_size((int32_t)fd, + (int32_t)size); +} + +/** + * Enable/disable address reuse on a socket + * Note: This is similar to `setsockopt` in POSIX for SO_REUSEADDR + */ +int32_t +__imported_wasi_snapshot_preview1_sock_set_reuse_addr(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_reuse_addr"))); + +static inline __wasi_errno_t +__wasi_sock_set_reuse_addr(__wasi_fd_t fd, bool reuse) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_reuse_addr((int32_t)fd, + (int32_t)reuse); +} + +/** + * Enable port reuse on a socket + * Note: This is similar to `setsockopt` in POSIX for SO_REUSEPORT + */ +int32_t +__imported_wasi_snapshot_preview1_sock_set_reuse_port(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_reuse_port"))); + +static inline __wasi_errno_t +__wasi_sock_set_reuse_port(__wasi_fd_t fd, bool reuse) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_reuse_port((int32_t)fd, + (int32_t)reuse); +} + +/** + * Set size of send buffer + * Note: This is similar to `setsockopt` in POSIX for SO_SNDBUF + */ +int32_t +__imported_wasi_snapshot_preview1_sock_set_send_buf_size(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_send_buf_size"))); + +static inline __wasi_errno_t +__wasi_sock_set_send_buf_size(__wasi_fd_t fd, __wasi_size_t buf_len) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_send_buf_size( + (int32_t)fd, (int32_t)buf_len); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_recv_timeout(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_recv_timeout"))); + +static inline __wasi_errno_t +__wasi_sock_get_recv_timeout(__wasi_fd_t fd, uint64_t *timeout_us) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_recv_timeout( + (int32_t)fd, (int32_t)timeout_us); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_recv_timeout(int32_t arg0, + int64_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_recv_timeout"))); + +static inline __wasi_errno_t +__wasi_sock_set_recv_timeout(__wasi_fd_t fd, uint64_t timeout_us) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_recv_timeout( + (int32_t)fd, (int64_t)timeout_us); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_send_timeout(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_send_timeout"))); + +static inline __wasi_errno_t +__wasi_sock_get_send_timeout(__wasi_fd_t fd, uint64_t *timeout_us) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_send_timeout( + (int32_t)fd, (int32_t)timeout_us); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_send_timeout(int32_t arg0, + int64_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_send_timeout"))); + +static inline __wasi_errno_t +__wasi_sock_set_send_timeout(__wasi_fd_t fd, uint64_t timeout_us) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_send_timeout( + (int32_t)fd, (int64_t)timeout_us); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_keep_alive(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_keep_alive"))); + +static inline __wasi_errno_t +__wasi_sock_set_keep_alive(__wasi_fd_t fd, bool option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_keep_alive((int32_t)fd, + (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_keep_alive(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_keep_alive"))); + +static inline __wasi_errno_t +__wasi_sock_get_keep_alive(__wasi_fd_t fd, bool *option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_keep_alive((int32_t)fd, + (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_linger(int32_t arg0, int32_t arg1, + int32_t arg2) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_linger"))); + +static inline __wasi_errno_t +__wasi_sock_set_linger(__wasi_fd_t fd, bool is_enabled, int linger_s) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_set_linger( + (int32_t)fd, (int32_t)is_enabled, (int32_t)linger_s); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_linger(int32_t arg0, int32_t arg1, + int32_t arg2) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_linger"))); + +static inline __wasi_errno_t +__wasi_sock_get_linger(__wasi_fd_t fd, bool *is_enabled, int *linger_s) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_get_linger( + (int32_t)fd, (int32_t)is_enabled, (int32_t)linger_s); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_tcp_keep_idle(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_tcp_keep_idle"))); + +static inline __wasi_errno_t +__wasi_sock_set_tcp_keep_idle(__wasi_fd_t fd, uint32_t time_s) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_tcp_keep_idle( + (int32_t)fd, (int32_t)time_s); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_tcp_keep_idle(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_tcp_keep_idle"))); + +static inline __wasi_errno_t +__wasi_sock_get_tcp_keep_idle(__wasi_fd_t fd, uint32_t *time_s) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_tcp_keep_idle( + (int32_t)fd, (int32_t)time_s); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_tcp_keep_intvl(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_tcp_keep_intvl"))); + +static inline __wasi_errno_t +__wasi_sock_set_tcp_keep_intvl(__wasi_fd_t fd, uint32_t time_s) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_tcp_keep_intvl( + (int32_t)fd, (int32_t)time_s); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_tcp_keep_intvl(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_tcp_keep_intvl"))); + +static inline __wasi_errno_t +__wasi_sock_get_tcp_keep_intvl(__wasi_fd_t fd, uint32_t *time_s) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_tcp_keep_intvl( + (int32_t)fd, (int32_t)time_s); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_tcp_fastopen_connect(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_tcp_fastopen_connect"))); + +static inline __wasi_errno_t +__wasi_sock_set_tcp_fastopen_connect(__wasi_fd_t fd, bool option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_tcp_fastopen_connect( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_tcp_fastopen_connect(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_tcp_fastopen_connect"))); + +static inline __wasi_errno_t +__wasi_sock_get_tcp_fastopen_connect(__wasi_fd_t fd, bool *option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_tcp_fastopen_connect( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_ip_multicast_loop(int32_t arg0, + int32_t arg1, + int32_t arg2) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_ip_multicast_loop"))); + +static inline __wasi_errno_t +__wasi_sock_set_ip_multicast_loop(__wasi_fd_t fd, bool ipv6, bool option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_ip_multicast_loop( + (int32_t)fd, (int32_t)ipv6, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_ip_multicast_loop(int32_t arg0, + int32_t arg1, + int32_t arg2) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_ip_multicast_loop"))); + +static inline __wasi_errno_t +__wasi_sock_get_ip_multicast_loop(__wasi_fd_t fd, bool ipv6, bool *option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_ip_multicast_loop( + (int32_t)fd, (int32_t)ipv6, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_ip_multicast_ttl(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_ip_multicast_ttl"))); + +static inline __wasi_errno_t +__wasi_sock_set_ip_multicast_ttl(__wasi_fd_t fd, uint8_t option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_ip_multicast_ttl( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_ip_multicast_ttl(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_ip_multicast_ttl"))); + +static inline __wasi_errno_t +__wasi_sock_get_ip_multicast_ttl(__wasi_fd_t fd, uint8_t *option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_ip_multicast_ttl( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_ip_add_membership(int32_t arg0, + int32_t arg1, + int32_t arg2) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_ip_add_membership"))); + +static inline __wasi_errno_t +__wasi_sock_set_ip_add_membership(__wasi_fd_t fd, + __wasi_addr_ip_t *imr_multiaddr, + uint32_t imr_interface) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_ip_add_membership( + (int32_t)fd, (int32_t)imr_multiaddr, (int32_t)imr_interface); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_ip_drop_membership(int32_t arg0, + int32_t arg1, + int32_t arg2) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_ip_drop_membership"))); + +static inline __wasi_errno_t +__wasi_sock_set_ip_drop_membership(__wasi_fd_t fd, + __wasi_addr_ip_t *imr_multiaddr, + uint32_t imr_interface) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_ip_drop_membership( + (int32_t)fd, (int32_t)imr_multiaddr, (int32_t)imr_interface); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_broadcast(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_broadcast"))); + +static inline __wasi_errno_t +__wasi_sock_set_broadcast(__wasi_fd_t fd, bool option) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_set_broadcast( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_broadcast(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_broadcast"))); + +static inline __wasi_errno_t +__wasi_sock_get_broadcast(__wasi_fd_t fd, bool *option) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_get_broadcast( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_tcp_no_delay(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_tcp_no_delay"))); + +static inline __wasi_errno_t +__wasi_sock_set_tcp_no_delay(__wasi_fd_t fd, bool option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_tcp_no_delay( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_tcp_no_delay(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_tcp_no_delay"))); + +static inline __wasi_errno_t +__wasi_sock_get_tcp_no_delay(__wasi_fd_t fd, bool *option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_tcp_no_delay( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_tcp_quick_ack(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_tcp_quick_ack"))); + +static inline __wasi_errno_t +__wasi_sock_set_tcp_quick_ack(__wasi_fd_t fd, bool option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_set_tcp_quick_ack( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_tcp_quick_ack(int32_t arg0, + int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_tcp_quick_ack"))); + +static inline __wasi_errno_t +__wasi_sock_get_tcp_quick_ack(__wasi_fd_t fd, bool *option) +{ + return (__wasi_errno_t) + __imported_wasi_snapshot_preview1_sock_get_tcp_quick_ack( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_ip_ttl(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_ip_ttl"))); + +static inline __wasi_errno_t +__wasi_sock_set_ip_ttl(__wasi_fd_t fd, uint8_t option) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_set_ip_ttl( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_ip_ttl(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_ip_ttl"))); + +static inline __wasi_errno_t +__wasi_sock_get_ip_ttl(__wasi_fd_t fd, uint8_t *option) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_get_ip_ttl( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_set_ipv6_only(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_set_ipv6_only"))); + +static inline __wasi_errno_t +__wasi_sock_set_ipv6_only(__wasi_fd_t fd, bool option) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_set_ipv6_only( + (int32_t)fd, (int32_t)option); +} + +int32_t +__imported_wasi_snapshot_preview1_sock_get_ipv6_only(int32_t arg0, int32_t arg1) + __attribute__((__import_module__("wasi_snapshot_preview1"), + __import_name__("sock_get_ipv6_only"))); + +static inline __wasi_errno_t +__wasi_sock_get_ipv6_only(__wasi_fd_t fd, bool *option) +{ + return (__wasi_errno_t)__imported_wasi_snapshot_preview1_sock_get_ipv6_only( + (int32_t)fd, (int32_t)option); +} +/** + * TODO: modify recv() and send() + * since don't want to re-compile the wasi-libc, + * we tend to keep original implentations of recv() and send(). + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake new file mode 100644 index 000000000..209b0c4c9 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake @@ -0,0 +1,9 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 2.8...3.16) + +project(socket_wasi_ext) + +add_library(${PROJECT_NAME} STATIC ${CMAKE_CURRENT_LIST_DIR}/src/wasi/wasi_socket_ext.c) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/inc/) diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c new file mode 100644 index 000000000..defbc6efe --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c @@ -0,0 +1,1009 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include <assert.h> +#include <errno.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <wasi/api.h> +#include <wasi_socket_ext.h> + +#define HANDLE_ERROR(error) \ + if (error != __WASI_ERRNO_SUCCESS) { \ + errno = error; \ + return -1; \ + } + +static void +ipv4_addr_to_wasi_ip4_addr(uint32_t addr_num, __wasi_addr_ip4_t *out) +{ + addr_num = ntohl(addr_num); + out->n0 = (addr_num & 0xFF000000) >> 24; + out->n1 = (addr_num & 0x00FF0000) >> 16; + out->n2 = (addr_num & 0x0000FF00) >> 8; + out->n3 = (addr_num & 0x000000FF); +} + +/* addr_num and port are in network order */ +static void +ipv4_addr_to_wasi_addr(uint32_t addr_num, uint16_t port, __wasi_addr_t *out) +{ + out->kind = IPv4; + out->addr.ip4.port = ntohs(port); + ipv4_addr_to_wasi_ip4_addr(addr_num, &(out->addr.ip4.addr)); +} + +static void +ipv6_addr_to_wasi_ipv6_addr(uint16_t *addr, __wasi_addr_ip6_t *out) +{ + out->n0 = ntohs(addr[0]); + out->n1 = ntohs(addr[1]); + out->n2 = ntohs(addr[2]); + out->n3 = ntohs(addr[3]); + out->h0 = ntohs(addr[4]); + out->h1 = ntohs(addr[5]); + out->h2 = ntohs(addr[6]); + out->h3 = ntohs(addr[7]); +} + +static void +ipv6_addr_to_wasi_addr(uint16_t *addr, uint16_t port, __wasi_addr_t *out) +{ + out->kind = IPv6; + out->addr.ip6.port = ntohs(port); + ipv6_addr_to_wasi_ipv6_addr(addr, &(out->addr.ip6.addr)); +} + +static __wasi_errno_t +sockaddr_to_wasi_addr(const struct sockaddr *sock_addr, socklen_t addrlen, + __wasi_addr_t *wasi_addr) +{ + __wasi_errno_t ret = __WASI_ERRNO_SUCCESS; + if (AF_INET == sock_addr->sa_family) { + assert(sizeof(struct sockaddr_in) <= addrlen); + + ipv4_addr_to_wasi_addr( + ((struct sockaddr_in *)sock_addr)->sin_addr.s_addr, + ((struct sockaddr_in *)sock_addr)->sin_port, wasi_addr); + } + else if (AF_INET6 == sock_addr->sa_family) { + assert(sizeof(struct sockaddr_in6) <= addrlen); + ipv6_addr_to_wasi_addr( + (uint16_t *)((struct sockaddr_in6 *)sock_addr)->sin6_addr.s6_addr, + ((struct sockaddr_in6 *)sock_addr)->sin6_port, wasi_addr); + } + else { + ret = __WASI_ERRNO_AFNOSUPPORT; + } + + return ret; +} + +static __wasi_errno_t +wasi_addr_to_sockaddr(const __wasi_addr_t *wasi_addr, + struct sockaddr *sock_addr, socklen_t *addrlen) +{ + switch (wasi_addr->kind) { + case IPv4: + { + struct sockaddr_in sock_addr_in; + uint32_t s_addr; + + memset(&sock_addr_in, 0, sizeof(sock_addr_in)); + + s_addr = (wasi_addr->addr.ip4.addr.n0 << 24) + | (wasi_addr->addr.ip4.addr.n1 << 16) + | (wasi_addr->addr.ip4.addr.n2 << 8) + | wasi_addr->addr.ip4.addr.n3; + + sock_addr_in.sin_family = AF_INET; + sock_addr_in.sin_addr.s_addr = htonl(s_addr); + sock_addr_in.sin_port = htons(wasi_addr->addr.ip4.port); + memcpy(sock_addr, &sock_addr_in, sizeof(sock_addr_in)); + + *addrlen = sizeof(sock_addr_in); + break; + } + case IPv6: + { + struct sockaddr_in6 sock_addr_in6; + + memset(&sock_addr_in6, 0, sizeof(sock_addr_in6)); + + uint16_t *addr_buf = (uint16_t *)sock_addr_in6.sin6_addr.s6_addr; + + addr_buf[0] = htons(wasi_addr->addr.ip6.addr.n0); + addr_buf[1] = htons(wasi_addr->addr.ip6.addr.n1); + addr_buf[2] = htons(wasi_addr->addr.ip6.addr.n2); + addr_buf[3] = htons(wasi_addr->addr.ip6.addr.n3); + addr_buf[4] = htons(wasi_addr->addr.ip6.addr.h0); + addr_buf[5] = htons(wasi_addr->addr.ip6.addr.h1); + addr_buf[6] = htons(wasi_addr->addr.ip6.addr.h2); + addr_buf[7] = htons(wasi_addr->addr.ip6.addr.h3); + + sock_addr_in6.sin6_family = AF_INET6; + sock_addr_in6.sin6_port = htons(wasi_addr->addr.ip6.port); + memcpy(sock_addr, &sock_addr_in6, sizeof(sock_addr_in6)); + + *addrlen = sizeof(sock_addr_in6); + break; + } + default: + return __WASI_ERRNO_AFNOSUPPORT; + } + return __WASI_ERRNO_SUCCESS; +} + +int +accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) +{ + __wasi_addr_t wasi_addr; + __wasi_fd_t new_sockfd; + __wasi_errno_t error; + + memset(&wasi_addr, 0, sizeof(wasi_addr)); + + error = __wasi_sock_accept(sockfd, 0, &new_sockfd); + HANDLE_ERROR(error) + + if (getpeername(new_sockfd, addr, addrlen) == -1) { + return -1; + } + + return new_sockfd; +} + +int +bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + __wasi_addr_t wasi_addr; + __wasi_errno_t error; + + memset(&wasi_addr, 0, sizeof(wasi_addr)); + + error = sockaddr_to_wasi_addr(addr, addrlen, &wasi_addr); + HANDLE_ERROR(error) + + error = __wasi_sock_bind(sockfd, &wasi_addr); + HANDLE_ERROR(error) + + return __WASI_ERRNO_SUCCESS; +} + +int +connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + __wasi_addr_t wasi_addr; + __wasi_errno_t error; + + memset(&wasi_addr, 0, sizeof(wasi_addr)); + + if (NULL == addr) { + HANDLE_ERROR(__WASI_ERRNO_INVAL) + } + + error = sockaddr_to_wasi_addr(addr, addrlen, &wasi_addr); + HANDLE_ERROR(error) + + error = __wasi_sock_connect(sockfd, &wasi_addr); + HANDLE_ERROR(error) + + return __WASI_ERRNO_SUCCESS; +} + +int +listen(int sockfd, int backlog) +{ + __wasi_errno_t error = __wasi_sock_listen(sockfd, backlog); + HANDLE_ERROR(error) + return __WASI_ERRNO_SUCCESS; +} + +ssize_t +recvmsg(int sockfd, struct msghdr *msg, int flags) +{ + // Prepare input parameters. + __wasi_iovec_t *ri_data = NULL; + size_t i = 0; + size_t ro_datalen = 0; + __wasi_roflags_t ro_flags = 0; + + if (NULL == msg) { + HANDLE_ERROR(__WASI_ERRNO_INVAL) + } + + // Validate flags. + if (flags != 0) { + HANDLE_ERROR(__WASI_ERRNO_NOPROTOOPT) + } + + // __wasi_ciovec_t -> struct iovec + if (!(ri_data = (__wasi_iovec_t *)malloc(sizeof(__wasi_iovec_t) + * msg->msg_iovlen))) { + HANDLE_ERROR(__WASI_ERRNO_NOMEM) + } + + for (i = 0; i < msg->msg_iovlen; i++) { + ri_data[i].buf = (uint8_t *)msg->msg_iov[i].iov_base; + ri_data[i].buf_len = msg->msg_iov[i].iov_len; + } + + // Perform system call. + __wasi_errno_t error = __wasi_sock_recv(sockfd, ri_data, msg->msg_iovlen, 0, + &ro_datalen, &ro_flags); + free(ri_data); + HANDLE_ERROR(error) + + return ro_datalen; +} + +ssize_t +sendmsg(int sockfd, const struct msghdr *msg, int flags) +{ + // Prepare input parameters. + __wasi_ciovec_t *si_data = NULL; + size_t so_datalen = 0; + size_t i = 0; + + if (NULL == msg) { + HANDLE_ERROR(__WASI_ERRNO_INVAL) + } + + // This implementation does not support any flags. + if (flags != 0) { + HANDLE_ERROR(__WASI_ERRNO_NOPROTOOPT) + } + + // struct iovec -> __wasi_ciovec_t + if (!(si_data = (__wasi_ciovec_t *)malloc(sizeof(__wasi_ciovec_t) + * msg->msg_iovlen))) { + HANDLE_ERROR(__WASI_ERRNO_NOMEM) + } + + for (i = 0; i < msg->msg_iovlen; i++) { + si_data[i].buf = (uint8_t *)msg->msg_iov[i].iov_base; + si_data[i].buf_len = msg->msg_iov[i].iov_len; + } + + // Perform system call. + __wasi_errno_t error = + __wasi_sock_send(sockfd, si_data, msg->msg_iovlen, 0, &so_datalen); + free(si_data); + HANDLE_ERROR(error) + + return so_datalen; +} + +ssize_t +sendto(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) +{ + // Prepare input parameters. + __wasi_ciovec_t iov = { .buf = (uint8_t *)buf, .buf_len = len }; + uint32_t so_datalen = 0; + __wasi_addr_t wasi_addr; + __wasi_errno_t error; + size_t si_data_len = 1; + __wasi_siflags_t si_flags = 0; + + // This implementation does not support any flags. + if (flags != 0) { + HANDLE_ERROR(__WASI_ERRNO_NOPROTOOPT) + } + + error = sockaddr_to_wasi_addr(dest_addr, addrlen, &wasi_addr); + HANDLE_ERROR(error); + + // Perform system call. + error = __wasi_sock_send_to(sockfd, &iov, si_data_len, si_flags, &wasi_addr, + &so_datalen); + HANDLE_ERROR(error) + + return so_datalen; +} + +ssize_t +recvfrom(int sockfd, void *buf, size_t len, int flags, + struct sockaddr *src_addr, socklen_t *addrlen) +{ + // Prepare input parameters. + __wasi_ciovec_t iov = { .buf = (uint8_t *)buf, .buf_len = len }; + uint32_t so_datalen = 0; + __wasi_addr_t wasi_addr; + __wasi_errno_t error; + size_t si_data_len = 1; + __wasi_siflags_t si_flags = 0; + + // This implementation does not support any flags. + if (flags != 0) { + HANDLE_ERROR(__WASI_ERRNO_NOPROTOOPT) + } + + if (!src_addr) { + return recv(sockfd, buf, len, flags); + } + + // Perform system call. + error = __wasi_sock_recv_from(sockfd, &iov, si_data_len, si_flags, + &wasi_addr, &so_datalen); + HANDLE_ERROR(error); + + error = wasi_addr_to_sockaddr(&wasi_addr, src_addr, addrlen); + HANDLE_ERROR(error); + + return so_datalen; +} + +int +socket(int domain, int type, int protocol) +{ + // the stub of address pool fd + __wasi_fd_t poolfd = -1; + __wasi_fd_t sockfd; + __wasi_errno_t error; + __wasi_address_family_t af; + __wasi_sock_type_t socktype; + + if (AF_INET == domain) { + af = INET4; + } + else if (AF_INET6 == domain) { + af = INET6; + } + else { + return __WASI_ERRNO_NOPROTOOPT; + } + + if (SOCK_DGRAM == type) { + socktype = SOCKET_DGRAM; + } + else if (SOCK_STREAM == type) { + socktype = SOCKET_STREAM; + } + else { + return __WASI_ERRNO_NOPROTOOPT; + } + + error = __wasi_sock_open(poolfd, af, socktype, &sockfd); + HANDLE_ERROR(error) + + return sockfd; +} + +int +getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) +{ + __wasi_addr_t wasi_addr; + __wasi_errno_t error; + + memset(&wasi_addr, 0, sizeof(wasi_addr)); + + error = __wasi_sock_addr_local(sockfd, &wasi_addr); + HANDLE_ERROR(error) + + error = wasi_addr_to_sockaddr(&wasi_addr, addr, addrlen); + HANDLE_ERROR(error) + + return __WASI_ERRNO_SUCCESS; +} + +int +getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) +{ + __wasi_addr_t wasi_addr; + __wasi_errno_t error; + + memset(&wasi_addr, 0, sizeof(wasi_addr)); + + error = __wasi_sock_addr_remote(sockfd, &wasi_addr); + HANDLE_ERROR(error) + + error = wasi_addr_to_sockaddr(&wasi_addr, addr, addrlen); + HANDLE_ERROR(error) + + return __WASI_ERRNO_SUCCESS; +} + +struct aibuf { + struct addrinfo ai; + union sa { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa; +}; + +static __wasi_errno_t +addrinfo_hints_to_wasi_hints(const struct addrinfo *hints, + __wasi_addr_info_hints_t *wasi_hints) +{ + if (hints) { + wasi_hints->hints_enabled = 1; + + switch (hints->ai_family) { + case AF_INET: + wasi_hints->family = INET4; + break; + case AF_INET6: + wasi_hints->family = INET6; + break; + default: + return __WASI_ERRNO_AFNOSUPPORT; + } + switch (hints->ai_socktype) { + case SOCK_STREAM: + wasi_hints->type = SOCKET_STREAM; + break; + case SOCK_DGRAM: + wasi_hints->type = SOCKET_DGRAM; + break; + default: + return __WASI_ERRNO_NOTSUP; + } + + if (hints->ai_protocol != 0) { + return __WASI_ERRNO_NOTSUP; + } + + if (hints->ai_flags != 0) { + return __WASI_ERRNO_NOTSUP; + } + } + else { + wasi_hints->hints_enabled = 0; + } + + return __WASI_ERRNO_SUCCESS; +} + +static __wasi_errno_t +wasi_addr_info_to_addr_info(const __wasi_addr_info_t *addr_info, + struct addrinfo *ai) +{ + ai->ai_socktype = + addr_info->type == SOCKET_DGRAM ? SOCK_DGRAM : SOCK_STREAM; + ai->ai_protocol = 0; + ai->ai_canonname = NULL; + + if (addr_info->addr.kind == IPv4) { + ai->ai_family = AF_INET; + ai->ai_addrlen = sizeof(struct sockaddr_in); + } + else { + ai->ai_family = AF_INET6; + ai->ai_addrlen = sizeof(struct sockaddr_in6); + } + + return wasi_addr_to_sockaddr(&addr_info->addr, ai->ai_addr, + &ai->ai_addrlen); // TODO err handling +} + +int +getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, + struct addrinfo **res) +{ + __wasi_addr_info_hints_t wasi_hints; + __wasi_addr_info_t *addr_info = NULL; + __wasi_size_t addr_info_size, i; + __wasi_size_t max_info_size = 16; + __wasi_errno_t error; + struct aibuf *aibuf_res; + + error = addrinfo_hints_to_wasi_hints(hints, &wasi_hints); + HANDLE_ERROR(error) + + do { + if (addr_info) + free(addr_info); + + addr_info_size = max_info_size; + addr_info = (__wasi_addr_info_t *)malloc(addr_info_size + * sizeof(__wasi_addr_info_t)); + + if (!addr_info) { + HANDLE_ERROR(__WASI_ERRNO_NOMEM) + } + + error = __wasi_sock_addr_resolve(node, service == NULL ? "" : service, + &wasi_hints, addr_info, addr_info_size, + &max_info_size); + if (error != __WASI_ERRNO_SUCCESS) { + free(addr_info); + HANDLE_ERROR(error); + } + } while (max_info_size > addr_info_size); + + if (addr_info_size == 0) { + free(addr_info); + *res = NULL; + return __WASI_ERRNO_SUCCESS; + } + + aibuf_res = + (struct aibuf *)calloc(1, addr_info_size * sizeof(struct aibuf)); + if (!aibuf_res) { + free(addr_info); + HANDLE_ERROR(__WASI_ERRNO_NOMEM) + } + + *res = &aibuf_res[0].ai; + + if (addr_info_size) { + addr_info_size = max_info_size; + } + + for (i = 0; i < addr_info_size; i++) { + struct addrinfo *ai = &aibuf_res[i].ai; + ai->ai_addr = (struct sockaddr *)&aibuf_res[i].sa; + + error = wasi_addr_info_to_addr_info(&addr_info[i], ai); + if (error != __WASI_ERRNO_SUCCESS) { + free(addr_info); + free(aibuf_res); + HANDLE_ERROR(error) + } + ai->ai_next = i == addr_info_size - 1 ? NULL : &aibuf_res[i + 1].ai; + } + + free(addr_info); + + return __WASI_ERRNO_SUCCESS; +} + +void +freeaddrinfo(struct addrinfo *res) +{ + /* res is a pointer to a first field in the first element + * of aibuf array allocated in getaddrinfo, therefore this call + * frees the memory of the entire array. */ + free(res); +} + +static struct timeval +time_us_to_timeval(uint64_t time_us) +{ + struct timeval tv; + tv.tv_sec = time_us / 1000000UL; + tv.tv_usec = time_us % 1000000UL; + return tv; +} + +static uint64_t +timeval_to_time_us(struct timeval tv) +{ + return (tv.tv_sec * 1000000UL) + tv.tv_usec; +} + +static int +get_sol_socket_option(int sockfd, int optname, void *__restrict optval, + socklen_t *__restrict optlen) +{ + __wasi_errno_t error; + uint64_t timeout_us; + bool is_linger_enabled; + int linger_s; + + switch (optname) { + case SO_RCVTIMEO: + assert(*optlen == sizeof(struct timeval)); + error = __wasi_sock_get_recv_timeout(sockfd, &timeout_us); + HANDLE_ERROR(error); + *(struct timeval *)optval = time_us_to_timeval(timeout_us); + return error; + case SO_SNDTIMEO: + assert(*optlen == sizeof(struct timeval)); + error = __wasi_sock_get_send_timeout(sockfd, &timeout_us); + HANDLE_ERROR(error); + *(struct timeval *)optval = time_us_to_timeval(timeout_us); + return error; + case SO_SNDBUF: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_send_buf_size(sockfd, (size_t *)optval); + HANDLE_ERROR(error); + return error; + case SO_RCVBUF: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_recv_buf_size(sockfd, (size_t *)optval); + HANDLE_ERROR(error); + return error; + case SO_KEEPALIVE: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_keep_alive(sockfd, (bool *)optval); + HANDLE_ERROR(error); + return error; + case SO_REUSEADDR: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_reuse_addr(sockfd, (bool *)optval); + HANDLE_ERROR(error); + return error; + case SO_REUSEPORT: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_reuse_port(sockfd, (bool *)optval); + HANDLE_ERROR(error); + return error; + case SO_LINGER: + assert(*optlen == sizeof(struct linger)); + error = + __wasi_sock_get_linger(sockfd, &is_linger_enabled, &linger_s); + HANDLE_ERROR(error); + ((struct linger *)optval)->l_onoff = (int)is_linger_enabled; + ((struct linger *)optval)->l_linger = linger_s; + return error; + case SO_BROADCAST: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_broadcast(sockfd, (bool *)optval); + HANDLE_ERROR(error); + return error; + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +static int +get_ipproto_tcp_option(int sockfd, int optname, void *__restrict optval, + socklen_t *__restrict optlen) +{ + __wasi_errno_t error; + switch (optname) { + case TCP_KEEPIDLE: + assert(*optlen == sizeof(uint32_t)); + error = __wasi_sock_get_tcp_keep_idle(sockfd, (uint32_t *)optval); + HANDLE_ERROR(error); + return error; + case TCP_KEEPINTVL: + assert(*optlen == sizeof(uint32_t)); + error = __wasi_sock_get_tcp_keep_intvl(sockfd, (uint32_t *)optval); + HANDLE_ERROR(error); + return error; + case TCP_FASTOPEN_CONNECT: + assert(*optlen == sizeof(int)); + error = + __wasi_sock_get_tcp_fastopen_connect(sockfd, (bool *)optval); + HANDLE_ERROR(error); + return error; + case TCP_NODELAY: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_tcp_no_delay(sockfd, (bool *)optval); + HANDLE_ERROR(error); + return error; + case TCP_QUICKACK: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_tcp_quick_ack(sockfd, (bool *)optval); + HANDLE_ERROR(error); + return error; + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +static int +get_ipproto_ip_option(int sockfd, int optname, void *__restrict optval, + socklen_t *__restrict optlen) +{ + __wasi_errno_t error; + + switch (optname) { + case IP_MULTICAST_LOOP: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_ip_multicast_loop(sockfd, false, + (bool *)optval); + HANDLE_ERROR(error); + return error; + case IP_TTL: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_ip_ttl(sockfd, (uint8_t *)optval); + HANDLE_ERROR(error); + return error; + case IP_MULTICAST_TTL: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_ip_multicast_ttl(sockfd, (uint8_t *)optval); + HANDLE_ERROR(error); + return error; + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +static int +get_ipproto_ipv6_option(int sockfd, int optname, void *__restrict optval, + socklen_t *__restrict optlen) +{ + __wasi_errno_t error; + + switch (optname) { + case IPV6_V6ONLY: + assert(*optlen == sizeof(int)); + error = __wasi_sock_get_ipv6_only(sockfd, (bool *)optval); + HANDLE_ERROR(error); + return error; + case IPV6_MULTICAST_LOOP: + assert(*optlen == sizeof(int)); + error = + __wasi_sock_get_ip_multicast_loop(sockfd, true, (bool *)optval); + HANDLE_ERROR(error); + return error; + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +int +getsockopt(int sockfd, int level, int optname, void *__restrict optval, + socklen_t *__restrict optlen) +{ + __wasi_errno_t error; + + switch (level) { + case SOL_SOCKET: + return get_sol_socket_option(sockfd, optname, optval, optlen); + case IPPROTO_TCP: + return get_ipproto_tcp_option(sockfd, optname, optval, optlen); + case IPPROTO_IP: + return get_ipproto_ip_option(sockfd, optname, optval, optlen); + case IPPROTO_IPV6: + return get_ipproto_ipv6_option(sockfd, optname, optval, optlen); + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +static int +set_sol_socket_option(int sockfd, int optname, const void *optval, + socklen_t optlen) +{ + __wasi_errno_t error; + uint64_t timeout_us; + + switch (optname) { + case SO_RCVTIMEO: + { + assert(optlen == sizeof(struct timeval)); + timeout_us = timeval_to_time_us(*(struct timeval *)optval); + error = __wasi_sock_set_recv_timeout(sockfd, timeout_us); + HANDLE_ERROR(error); + return error; + } + case SO_SNDTIMEO: + { + assert(optlen == sizeof(struct timeval)); + timeout_us = timeval_to_time_us(*(struct timeval *)optval); + error = __wasi_sock_set_send_timeout(sockfd, timeout_us); + HANDLE_ERROR(error); + return error; + } + case SO_SNDBUF: + { + assert(optlen == sizeof(int)); + error = __wasi_sock_set_send_buf_size(sockfd, *(size_t *)optval); + HANDLE_ERROR(error); + return error; + } + case SO_RCVBUF: + { + assert(optlen == sizeof(int)); + error = __wasi_sock_set_recv_buf_size(sockfd, *(size_t *)optval); + HANDLE_ERROR(error); + return error; + } + case SO_KEEPALIVE: + { + assert(optlen == sizeof(int)); + error = __wasi_sock_set_keep_alive(sockfd, *(bool *)optval); + HANDLE_ERROR(error); + return error; + } + case SO_REUSEADDR: + { + assert(optlen == sizeof(int)); + error = __wasi_sock_set_reuse_addr(sockfd, *(bool *)optval); + HANDLE_ERROR(error); + return error; + } + case SO_REUSEPORT: + { + assert(optlen == sizeof(int)); + error = __wasi_sock_set_reuse_port(sockfd, *(bool *)optval); + HANDLE_ERROR(error); + return error; + } + case SO_LINGER: + { + assert(optlen == sizeof(struct linger)); + struct linger *linger_opt = ((struct linger *)optval); + error = __wasi_sock_set_linger(sockfd, (bool)linger_opt->l_onoff, + linger_opt->l_linger); + HANDLE_ERROR(error); + return error; + } + case SO_BROADCAST: + { + assert(optlen == sizeof(int)); + error = __wasi_sock_set_broadcast(sockfd, *(bool *)optval); + HANDLE_ERROR(error); + return error; + } + default: + { + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } + } +} + +static int +set_ipproto_tcp_option(int sockfd, int optname, const void *optval, + socklen_t optlen) +{ + __wasi_errno_t error; + + switch (optname) { + case TCP_NODELAY: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_tcp_no_delay(sockfd, *(bool *)optval); + HANDLE_ERROR(error); + return error; + case TCP_KEEPIDLE: + assert(optlen == sizeof(uint32_t)); + error = __wasi_sock_set_tcp_keep_idle(sockfd, *(uint32_t *)optval); + HANDLE_ERROR(error); + return error; + case TCP_KEEPINTVL: + assert(optlen == sizeof(uint32_t)); + error = __wasi_sock_set_tcp_keep_intvl(sockfd, *(uint32_t *)optval); + HANDLE_ERROR(error); + return error; + case TCP_FASTOPEN_CONNECT: + assert(optlen == sizeof(int)); + error = + __wasi_sock_set_tcp_fastopen_connect(sockfd, *(bool *)optval); + HANDLE_ERROR(error); + return error; + case TCP_QUICKACK: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_tcp_quick_ack(sockfd, *(bool *)optval); + HANDLE_ERROR(error); + return error; + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +static int +set_ipproto_ip_option(int sockfd, int optname, const void *optval, + socklen_t optlen) +{ + __wasi_errno_t error; + __wasi_addr_ip_t imr_multiaddr; + struct ip_mreq *ip_mreq_opt; + + switch (optname) { + case IP_MULTICAST_LOOP: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_ip_multicast_loop(sockfd, false, + *(bool *)optval); + HANDLE_ERROR(error); + return error; + case IP_ADD_MEMBERSHIP: + assert(optlen == sizeof(struct ip_mreq)); + ip_mreq_opt = (struct ip_mreq *)optval; + imr_multiaddr.kind = IPv4; + ipv4_addr_to_wasi_ip4_addr(ip_mreq_opt->imr_multiaddr.s_addr, + &imr_multiaddr.addr.ip4); + error = __wasi_sock_set_ip_add_membership( + sockfd, &imr_multiaddr, ip_mreq_opt->imr_interface.s_addr); + HANDLE_ERROR(error); + return error; + case IP_DROP_MEMBERSHIP: + assert(optlen == sizeof(struct ip_mreq)); + ip_mreq_opt = (struct ip_mreq *)optval; + imr_multiaddr.kind = IPv4; + ipv4_addr_to_wasi_ip4_addr(ip_mreq_opt->imr_multiaddr.s_addr, + &imr_multiaddr.addr.ip4); + error = __wasi_sock_set_ip_drop_membership( + sockfd, &imr_multiaddr, ip_mreq_opt->imr_interface.s_addr); + HANDLE_ERROR(error); + return error; + case IP_TTL: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_ip_ttl(sockfd, *(uint8_t *)optval); + HANDLE_ERROR(error); + return error; + case IP_MULTICAST_TTL: + assert(optlen == sizeof(int)); + error = + __wasi_sock_set_ip_multicast_ttl(sockfd, *(uint8_t *)optval); + HANDLE_ERROR(error); + return error; + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +static int +set_ipproto_ipv6_option(int sockfd, int optname, const void *optval, + socklen_t optlen) +{ + __wasi_errno_t error; + struct ipv6_mreq *ipv6_mreq_opt; + __wasi_addr_ip_t imr_multiaddr; + + switch (optname) { + case IPV6_V6ONLY: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_ipv6_only(sockfd, *(bool *)optval); + HANDLE_ERROR(error); + return error; + case IPV6_MULTICAST_LOOP: + assert(optlen == sizeof(int)); + error = __wasi_sock_set_ip_multicast_loop(sockfd, true, + *(bool *)optval); + HANDLE_ERROR(error); + return error; + case IPV6_JOIN_GROUP: + assert(optlen == sizeof(struct ipv6_mreq)); + ipv6_mreq_opt = (struct ipv6_mreq *)optval; + imr_multiaddr.kind = IPv6; + ipv6_addr_to_wasi_ipv6_addr( + (uint16_t *)ipv6_mreq_opt->ipv6mr_multiaddr.s6_addr, + &imr_multiaddr.addr.ip6); + error = __wasi_sock_set_ip_add_membership( + sockfd, &imr_multiaddr, ipv6_mreq_opt->ipv6mr_interface); + HANDLE_ERROR(error); + return error; + case IPV6_LEAVE_GROUP: + assert(optlen == sizeof(struct ipv6_mreq)); + ipv6_mreq_opt = (struct ipv6_mreq *)optval; + imr_multiaddr.kind = IPv6; + ipv6_addr_to_wasi_ipv6_addr( + (uint16_t *)ipv6_mreq_opt->ipv6mr_multiaddr.s6_addr, + &imr_multiaddr.addr.ip6); + error = __wasi_sock_set_ip_drop_membership( + sockfd, &imr_multiaddr, ipv6_mreq_opt->ipv6mr_interface); + HANDLE_ERROR(error); + return error; + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} + +int +setsockopt(int sockfd, int level, int optname, const void *optval, + socklen_t optlen) +{ + __wasi_errno_t error; + + switch (level) { + case SOL_SOCKET: + return set_sol_socket_option(sockfd, optname, optval, optlen); + case IPPROTO_TCP: + return set_ipproto_tcp_option(sockfd, optname, optval, optlen); + case IPPROTO_IP: + return set_ipproto_ip_option(sockfd, optname, optval, optlen); + case IPPROTO_IPV6: + return set_ipproto_ipv6_option(sockfd, optname, optval, optlen); + default: + error = __WASI_ERRNO_NOTSUP; + HANDLE_ERROR(error); + return error; + } +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/build.sh b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/build.sh new file mode 100755 index 000000000..24f5ee676 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/build.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set -eo pipefail +CC="${CC:=/opt/wasi-sdk/bin/clang}" +files=("tcp_udp.c" "nslookup.c") + +for file in "${files[@]}" +do + echo $file + $CC \ + --target=wasm32-wasi-threads \ + -I../inc \ + ../src/wasi/wasi_socket_ext.c -pthread -ftls-model=local-exec \ + -Wl,--allow-undefined \ + -Wl,--strip-all,--no-entry \ + -Wl,--export=__heap_base \ + -Wl,--export=__data_end \ + -Wl,--shared-memory,--max-memory=10485760 \ + -Wl,--export=malloc \ + -Wl,--export=free \ + -o "${file%.*}.wasm" "$file" +done
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/nslookup.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/nslookup.c new file mode 100644 index 000000000..37150f1eb --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/nslookup.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include <assert.h> +#include <string.h> +#ifdef __wasi__ +#include <wasi/api.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <wasi_socket_ext.h> +#else +#include <netdb.h> +#endif + +void +test_nslookup(int af) +{ + struct addrinfo *res; + int count = 0; + struct addrinfo hints; + char *url = "google-public-dns-a.google.com"; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + int ret = getaddrinfo(url, 0, &hints, &res); + assert(ret == 0); + struct addrinfo *address = res; + while (address) { + assert(address->ai_family == af); + assert(address->ai_socktype == SOCK_STREAM); + count++; + address = address->ai_next; + } + + assert(count > 0); + freeaddrinfo(res); +} + +int +main() +{ + test_nslookup(AF_INET); /* for ipv4 */ + test_nslookup(AF_INET6); /* for ipv6 */ + + return 0; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/tcp_udp.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/tcp_udp.c new file mode 100644 index 000000000..49231de89 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/tcp_udp.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ +#include <unistd.h> +#include <string.h> +#include <assert.h> +#ifdef __wasi__ +#include <wasi/api.h> +#include <sys/socket.h> +#include <wasi_socket_ext.h> +#endif +#include <arpa/inet.h> +#include <pthread.h> +#define SERVER_MSG "Message from server." +#define PORT 8989 +pthread_mutex_t mut; +pthread_cond_t cond; +int server_init_complete = 0; +char buffer[sizeof(SERVER_MSG) + 1]; + +struct socket_info { + union { + struct sockaddr_in addr_ipv4; + struct sockaddr_in6 addr_ipv6; + } addr; + int sock; +}; + +struct thread_args { + int family; + int protocol; +}; + +struct socket_info +init_socket_addr(int family, int protocol) +{ + int sock = socket(family, protocol, 0); + assert(sock != -1); + + struct socket_info info; + if (family == AF_INET) { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(PORT); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + info.addr.addr_ipv4 = addr; + } + else if (family == AF_INET6) { + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(PORT); + addr.sin6_addr = in6addr_loopback; + info.addr.addr_ipv6 = addr; + } + info.sock = sock; + return info; +} + +void +assert_thread_args(struct thread_args *args) +{ + assert(args->family == AF_INET || args->family == AF_INET6); + assert(args->protocol == SOCK_STREAM || args->protocol == SOCK_DGRAM); +} + +void * +server(void *arg) +{ + server_init_complete = 0; + struct thread_args *args = (struct thread_args *)arg; + assert_thread_args(args); + + struct socket_info init_server_sock = + init_socket_addr(args->family, args->protocol); + + int server_sock = init_server_sock.sock; + socklen_t addr_size; + struct sockaddr_storage client_addr; + strcpy(buffer, SERVER_MSG); + + struct sockaddr *server_addr = (struct sockaddr *)&init_server_sock.addr; + int ret = bind(server_sock, server_addr, + args->family == AF_INET ? sizeof(struct sockaddr_in) + : sizeof(struct sockaddr_in6)); + assert(ret == 0); + + (args->protocol == SOCK_STREAM) && listen(server_sock, 1); + pthread_mutex_lock(&mut); + server_init_complete = 1; + pthread_mutex_unlock(&mut); + pthread_cond_signal(&cond); + + addr_size = sizeof(client_addr); + if (args->protocol == SOCK_STREAM) { + int client_sock = + accept(server_sock, (struct sockaddr *)&client_addr, &addr_size); + assert(client_sock >= 0); + sendto(client_sock, buffer, strlen(buffer), 0, + (struct sockaddr *)&client_addr, addr_size); + + assert(close(client_sock) == 0); + } + else { + recvfrom(server_sock, buffer, sizeof(buffer), 0, + (struct sockaddr *)&client_addr, &addr_size); + sendto(server_sock, buffer, strlen(buffer), 0, + (struct sockaddr *)&client_addr, addr_size); + + assert(close(server_sock) == 0); + } + + return NULL; +} + +void * +client(void *arg) +{ + struct thread_args *args = (struct thread_args *)arg; + assert_thread_args(args); + + pthread_mutex_lock(&mut); + + while (server_init_complete == 0) { + pthread_cond_wait(&cond, &mut); + } + + struct socket_info init_client_sock = + init_socket_addr(args->family, args->protocol); + int sock = init_client_sock.sock; + pthread_mutex_unlock(&mut); + + if (args->family == AF_INET) { + struct sockaddr_in addr = init_client_sock.addr.addr_ipv4; + if (args->protocol == SOCK_STREAM) { + assert(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != -1); + } + else { + assert(sendto(sock, buffer, strlen(buffer), 0, + (struct sockaddr *)&addr, sizeof(addr)) + != -1); + } + } + else { + struct sockaddr_in6 addr = init_client_sock.addr.addr_ipv6; + if (args->protocol == SOCK_STREAM) { + assert(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != -1); + } + else { + assert(sendto(sock, buffer, strlen(buffer), 0, + (struct sockaddr *)&addr, sizeof(addr)) + != -1); + } + } + + recv(sock, buffer, sizeof(buffer), 0); + assert(strcmp(buffer, SERVER_MSG) == 0); + assert(close(sock) == 0); + return NULL; +} + +void +test_protocol(int family, int protocol) +{ + pthread_t server_thread, client_thread; + assert(pthread_cond_init(&cond, NULL) == 0); + assert(pthread_mutex_init(&mut, NULL) == 0); + + struct thread_args args = { family, protocol }; + assert(pthread_create(&server_thread, NULL, server, (void *)&args) == 0); + assert(pthread_create(&client_thread, NULL, client, (void *)&args) == 0); + assert(pthread_join(server_thread, NULL) == 0); + assert(pthread_join(client_thread, NULL) == 0); + + assert(pthread_mutex_destroy(&mut) == 0); + assert(pthread_cond_destroy(&cond) == 0); +} + +int +main(int argc, char **argv) +{ + /* test tcp with ipv4 and ipv6 */ + test_protocol(AF_INET, SOCK_STREAM); + test_protocol(AF_INET6, SOCK_STREAM); + + /* test udp with ipv4 and ipv6 */ + test_protocol(AF_INET, SOCK_DGRAM); + test_protocol(AF_INET6, SOCK_DGRAM); + + return 0; +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads.cmake b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads.cmake new file mode 100644 index 000000000..54d2ba902 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads.cmake @@ -0,0 +1,12 @@ +# Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (LIB_WASI_THREADS_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions (-DWASM_ENABLE_LIB_WASI_THREADS=1 -DWASM_ENABLE_HEAP_AUX_STACK_ALLOCATION=1) + +include_directories(${LIB_WASI_THREADS_DIR}) + +set (LIB_WASI_THREADS_SOURCE + ${LIB_WASI_THREADS_DIR}/lib_wasi_threads_wrapper.c + ${LIB_WASI_THREADS_DIR}/tid_allocator.c)
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c new file mode 100644 index 000000000..6b36c9073 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_log.h" +#include "thread_manager.h" +#include "tid_allocator.h" + +#if WASM_ENABLE_INTERP != 0 +#include "wasm_runtime.h" +#endif + +#if WASM_ENABLE_AOT != 0 +#include "aot_runtime.h" +#endif + +static const char *THREAD_START_FUNCTION = "wasi_thread_start"; +static korp_mutex thread_id_lock; +static TidAllocator tid_allocator; + +typedef struct { + /* app's entry function */ + wasm_function_inst_t start_func; + /* arg of the app's entry function */ + uint32 arg; + /* thread id passed to the app */ + int32 thread_id; +} ThreadStartArg; + +static int32 +allocate_thread_id() +{ + os_mutex_lock(&thread_id_lock); + int32 id = tid_allocator_get_tid(&tid_allocator); + os_mutex_unlock(&thread_id_lock); + + return id; +} + +void +deallocate_thread_id(int32 thread_id) +{ + os_mutex_lock(&thread_id_lock); + tid_allocator_release_tid(&tid_allocator, thread_id); + os_mutex_unlock(&thread_id_lock); +} + +static void * +thread_start(void *arg) +{ + wasm_exec_env_t exec_env = (wasm_exec_env_t)arg; + ThreadStartArg *thread_arg = exec_env->thread_arg; + uint32 argv[2]; + + wasm_exec_env_set_thread_info(exec_env); + argv[0] = thread_arg->thread_id; + argv[1] = thread_arg->arg; + + if (!wasm_runtime_call_wasm(exec_env, thread_arg->start_func, 2, argv)) { + /* Exception has already been spread during throwing */ + } + + // Routine exit + deallocate_thread_id(thread_arg->thread_id); + wasm_runtime_free(thread_arg); + exec_env->thread_arg = NULL; + + return NULL; +} + +static int32 +thread_spawn_wrapper(wasm_exec_env_t exec_env, uint32 start_arg) +{ + wasm_module_t module = wasm_exec_env_get_module(exec_env); + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasm_module_inst_t new_module_inst = NULL; + ThreadStartArg *thread_start_arg = NULL; + wasm_function_inst_t start_func; + int32 thread_id; + uint32 stack_size = 8192; + int32 ret = -1; +#if WASM_ENABLE_LIBC_WASI != 0 + WASIContext *wasi_ctx; +#endif + + bh_assert(module); + bh_assert(module_inst); + + stack_size = ((WASMModuleInstance *)module_inst)->default_wasm_stack_size; + + if (!(new_module_inst = wasm_runtime_instantiate_internal( + module, true, exec_env, stack_size, 0, NULL, 0))) + return -1; + + wasm_runtime_set_custom_data_internal( + new_module_inst, wasm_runtime_get_custom_data(module_inst)); + + if (!(wasm_cluster_dup_c_api_imports(new_module_inst, module_inst))) + goto thread_preparation_fail; + +#if WASM_ENABLE_LIBC_WASI != 0 + wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst); + if (wasi_ctx) + wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx); +#endif + + start_func = wasm_runtime_lookup_function(new_module_inst, + THREAD_START_FUNCTION, NULL); + if (!start_func) { + LOG_ERROR("Failed to find thread start function %s", + THREAD_START_FUNCTION); + goto thread_preparation_fail; + } + + if (!(thread_start_arg = wasm_runtime_malloc(sizeof(ThreadStartArg)))) { + LOG_ERROR("Runtime args allocation failed"); + goto thread_preparation_fail; + } + + thread_start_arg->thread_id = thread_id = allocate_thread_id(); + if (thread_id < 0) { + LOG_ERROR("Failed to get thread identifier"); + goto thread_preparation_fail; + } + thread_start_arg->arg = start_arg; + thread_start_arg->start_func = start_func; + + ret = wasm_cluster_create_thread(exec_env, new_module_inst, false, + thread_start, thread_start_arg); + if (ret != 0) { + LOG_ERROR("Failed to spawn a new thread"); + goto thread_spawn_fail; + } + + return thread_id; + +thread_spawn_fail: + deallocate_thread_id(thread_id); + +thread_preparation_fail: + if (new_module_inst) + wasm_runtime_deinstantiate_internal(new_module_inst, true); + if (thread_start_arg) + wasm_runtime_free(thread_start_arg); + + return -1; +} + +/* clang-format off */ +#define REG_NATIVE_FUNC(name, func_name, signature) \ + { name, func_name##_wrapper, signature, NULL } +/* clang-format on */ + +static NativeSymbol native_symbols_lib_wasi_threads[] = { REG_NATIVE_FUNC( + "thread-spawn", thread_spawn, "(i)i") }; + +uint32 +get_lib_wasi_threads_export_apis(NativeSymbol **p_lib_wasi_threads_apis) +{ + *p_lib_wasi_threads_apis = native_symbols_lib_wasi_threads; + return sizeof(native_symbols_lib_wasi_threads) / sizeof(NativeSymbol); +} + +bool +lib_wasi_threads_init(void) +{ + if (0 != os_mutex_init(&thread_id_lock)) + return false; + + if (!tid_allocator_init(&tid_allocator)) { + os_mutex_destroy(&thread_id_lock); + return false; + } + + return true; +} + +void +lib_wasi_threads_destroy(void) +{ + tid_allocator_deinit(&tid_allocator); + os_mutex_destroy(&thread_id_lock); +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/build.sh b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/build.sh new file mode 100755 index 000000000..32586c20c --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/build.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# +# Copyright (C) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +set -eo pipefail +CC=${CC:=/opt/wasi-sdk/bin/clang} +WAMR_DIR=../../../../.. + +for test_c in *.c; do + test_wasm="$(basename $test_c .c).wasm" + + if [ $test_wasm = "linear_memory_size_update.wasm" ]; then + thread_start_file="" + else + thread_start_file=$WAMR_DIR/samples/wasi-threads/wasm-apps/wasi_thread_start.S + fi + + echo "Compiling $test_c to $test_wasm" + $CC \ + -target wasm32-wasi-threads \ + -pthread -ftls-model=local-exec \ + -z stack-size=32768 \ + -Wl,--export=__heap_base \ + -Wl,--export=__data_end \ + -Wl,--shared-memory,--max-memory=1966080 \ + -Wl,--export=wasi_thread_start \ + -Wl,--export=malloc \ + -Wl,--export=free \ + -I $WAMR_DIR/samples/wasi-threads/wasm-apps \ + $thread_start_file \ + $test_c -o $test_wasm +done
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/common.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/common.h new file mode 100644 index 000000000..01ca932c5 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/common.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <stdbool.h> +#include <unistd.h> +#include <limits.h> + +#if USE_CUSTOM_SYNC_PRIMITIVES != 0 +#include "sync_primitives.h" +#else +#include <pthread.h> +#endif + +#include "wasi_thread_start.h" + +typedef enum { + BLOCKING_TASK_BUSY_WAIT, + BLOCKING_TASK_ATOMIC_WAIT, + BLOCKING_TASK_POLL_ONEOFF +} blocking_task_type_t; + +/* Parameter to change test behavior */ +static bool termination_by_trap; +static bool termination_in_main_thread; +static blocking_task_type_t blocking_task_type; + +#define NUM_THREADS 3 +static pthread_barrier_t barrier; + +typedef struct { + start_args_t base; + bool throw_exception; +} shared_t; + +void +run_long_task() +{ + if (blocking_task_type == BLOCKING_TASK_BUSY_WAIT) { + for (;;) { + } + } + else if (blocking_task_type == BLOCKING_TASK_ATOMIC_WAIT) { + __builtin_wasm_memory_atomic_wait32(0, 0, -1); + } + else { + sleep(UINT_MAX); + } +} + +void +start_job() +{ + /* Wait for all threads (including the main thread) to be ready */ + pthread_barrier_wait(&barrier); + run_long_task(); /* Task to be interrupted */ + assert(false && "Thread termination test failed"); +} + +void +terminate_process() +{ + /* Wait for all threads (including the main thread) to be ready */ + pthread_barrier_wait(&barrier); + + if (termination_by_trap) + __builtin_trap(); + else + __wasi_proc_exit(33); +} + +void +__wasi_thread_start_C(int thread_id, int *start_arg) +{ + shared_t *data = (shared_t *)start_arg; + + if (data->throw_exception) { + terminate_process(); + } + else { + start_job(); + } +} + +void +test_termination(bool trap, bool main, blocking_task_type_t task_type) +{ + termination_by_trap = trap; + termination_in_main_thread = main; + blocking_task_type = task_type; + + int thread_id = -1, i; + shared_t data[NUM_THREADS] = { 0 }; + assert(pthread_barrier_init(&barrier, NULL, NUM_THREADS + 1) == 0 + && "Failed to init barrier"); + + for (i = 0; i < NUM_THREADS; i++) { + /* No graceful memory free to simplify the test */ + assert(start_args_init(&data[i].base) + && "Failed to allocate thread's stack"); + } + + /* Create a thread that forces termination through trap or `proc_exit` */ + data[0].throw_exception = !termination_in_main_thread; + thread_id = __wasi_thread_spawn(&data[0]); + assert(thread_id > 0 && "Failed to create thread"); + + /* Create two additional threads to test exception propagation */ + data[1].throw_exception = false; + thread_id = __wasi_thread_spawn(&data[1]); + assert(thread_id > 0 && "Failed to create thread"); + data[2].throw_exception = false; + thread_id = __wasi_thread_spawn(&data[2]); + assert(thread_id > 0 && "Failed to create thread"); + + if (termination_in_main_thread) { + terminate_process(); + } + else { + start_job(); + } +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/create_threads_until_limit.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/create_threads_until_limit.c new file mode 100644 index 000000000..23ba5f627 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/create_threads_until_limit.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <stdbool.h> + +#include "wasi_thread_start.h" + +enum CONSTANTS { + MAX_NUM_THREADS = 4, /* Should be the same as "--max-threads" */ + NUM_RETRY = 5, + SECOND = 1000 * 1000 * 1000, /* 1 second */ + TIMEOUT = 10LL * SECOND +}; + +int g_count = 0; + +typedef struct { + start_args_t base; + int th_ready; + int th_continue; + int th_done; + bool no_ops; +} shared_t; + +void +__wasi_thread_start_C(int thread_id, int *start_arg) +{ + shared_t *data = (shared_t *)start_arg; + + if (data->no_ops) { + __builtin_wasm_memory_atomic_wait32(NULL, 0, 2 * SECOND); + return; + } + + __atomic_store_n(&data->th_ready, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&data->th_ready, 1); + + if (__builtin_wasm_memory_atomic_wait32(&data->th_continue, 0, TIMEOUT) + == 2) { + assert(false && "Wait should not time out"); + } + + __atomic_fetch_add(&g_count, 1, __ATOMIC_SEQ_CST); + + __atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&data->th_done, 1); +} + +int +main(int argc, char **argv) +{ + shared_t data[MAX_NUM_THREADS] = { 0 }; + int thread_ids[MAX_NUM_THREADS]; + + for (int i = 0; i < MAX_NUM_THREADS; i++) { + assert(start_args_init(&data[i].base)); + thread_ids[i] = __wasi_thread_spawn(&data[i]); + printf("Thread created with id=%d\n", thread_ids[i]); + assert(thread_ids[i] > 0 && "Thread creation failed"); + + for (int j = 0; j < i; j++) { + assert(thread_ids[i] != thread_ids[j] && "Duplicated TIDs"); + } + + if (__builtin_wasm_memory_atomic_wait32(&data[i].th_ready, 0, TIMEOUT) + == 2) { + assert(false && "Wait should not time out"); + } + } + + printf("Attempt to create thread when not possible\n"); + shared_t data_fail = { 0 }; + assert(start_args_init(&data_fail.base)); + int thread_id = __wasi_thread_spawn(&data_fail); + start_args_deinit(&data_fail.base); + assert(thread_id < 0 && "Thread creation should fail"); + + printf("Unlock created threads\n"); + for (int i = 0; i < MAX_NUM_THREADS; i++) { + __atomic_store_n(&data[i].th_continue, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&data[i].th_continue, 1); + } + + printf("Wait for threads to finish\n"); + for (int i = 0; i < MAX_NUM_THREADS; i++) { + if (__builtin_wasm_memory_atomic_wait32(&data[i].th_done, 0, TIMEOUT) + == 2) { + assert(false && "Wait should not time out"); + } + + start_args_deinit(&data[i].base); + } + + printf("Value of count after update: %d\n", g_count); + assert(g_count == (MAX_NUM_THREADS) + && "Global count not updated correctly"); + + /* --------------------------------------------------- */ + + printf("Create new threads without waiting from them to finish\n"); + shared_t data_no_join[MAX_NUM_THREADS] = { 0 }; + for (int i = 0; i < MAX_NUM_THREADS; i++) { + /* No graceful memory free to simplify the test */ + assert(start_args_init(&data_no_join[i].base)); + data_no_join[i].no_ops = true; + + int thread_id = -1; + for (int j = 0; j < NUM_RETRY && thread_id < 0; j++) { + thread_id = __wasi_thread_spawn(&data_no_join[i]); + if (thread_id < 0) + __builtin_wasm_memory_atomic_wait32(NULL, 0, SECOND); + } + + printf("Thread created with id=%d\n", thread_id); + assert(thread_id > 0 && "Thread creation should succeed"); + } + + return EXIT_SUCCESS; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/global_atomic.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/global_atomic.c new file mode 100644 index 000000000..a38e75364 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/global_atomic.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <stdbool.h> + +#include "wasi_thread_start.h" + +enum CONSTANTS { + NUM_THREADS = 4, + NUM_ITER = 1000, + SECOND = 1000 * 1000 * 1000, /* 1 second */ + TIMEOUT = 10LL * SECOND +}; + +int g_count = 0; + +typedef struct { + start_args_t base; + int th_done; +} shared_t; + +void +__wasi_thread_start_C(int thread_id, int *start_arg) +{ + shared_t *data = (shared_t *)start_arg; + + for (int i = 0; i < NUM_ITER; i++) + __atomic_fetch_add(&g_count, 1, __ATOMIC_SEQ_CST); + + __atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&data->th_done, 1); +} + +int +main(int argc, char **argv) +{ + shared_t data[NUM_THREADS] = { 0 }; + int thread_ids[NUM_THREADS]; + + for (int i = 0; i < NUM_THREADS; i++) { + assert(start_args_init(&data[i].base)); + thread_ids[i] = __wasi_thread_spawn(&data[i]); + assert(thread_ids[i] > 0 && "Thread creation failed"); + } + + printf("Wait for threads to finish\n"); + for (int i = 0; i < NUM_THREADS; i++) { + if (__builtin_wasm_memory_atomic_wait32(&data[i].th_done, 0, TIMEOUT) + == 2) { + assert(false && "Wait should not time out"); + } + + start_args_deinit(&data[i].base); + } + + printf("Value of count after update: %d\n", g_count); + assert(g_count == (NUM_THREADS * NUM_ITER) + && "Global count not updated correctly"); + + return EXIT_SUCCESS; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/global_lock.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/global_lock.c new file mode 100644 index 000000000..f81fca49b --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/global_lock.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <stdbool.h> + +#if USE_CUSTOM_SYNC_PRIMITIVES != 0 +#include "sync_primitives.h" +#else +#include <pthread.h> +#endif + +#include "wasi_thread_start.h" + +enum CONSTANTS { + NUM_THREADS = 4, + NUM_ITER = 200, + SECOND = 1000 * 1000 * 1000, /* 1 second */ + TIMEOUT = 10LL * SECOND +}; + +pthread_mutex_t mutex; +int g_count = 0; + +typedef struct { + start_args_t base; + int th_done; +} shared_t; + +void +__wasi_thread_start_C(int thread_id, int *start_arg) +{ + shared_t *data = (shared_t *)start_arg; + + for (int i = 0; i < NUM_ITER; i++) { + pthread_mutex_lock(&mutex); + g_count++; + pthread_mutex_unlock(&mutex); + } + + __atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&data->th_done, 1); +} + +int +main(int argc, char **argv) +{ + shared_t data[NUM_THREADS] = { 0 }; + int thread_ids[NUM_THREADS]; + + assert(pthread_mutex_init(&mutex, NULL) == 0 && "Failed to init mutex"); + + for (int i = 0; i < NUM_THREADS; i++) { + assert(start_args_init(&data[i].base)); + thread_ids[i] = __wasi_thread_spawn(&data[i]); + assert(thread_ids[i] > 0 && "Thread creation failed"); + } + + printf("Wait for threads to finish\n"); + for (int i = 0; i < NUM_THREADS; i++) { + if (__builtin_wasm_memory_atomic_wait32(&data[i].th_done, 0, TIMEOUT) + == 2) { + assert(false && "Wait should not time out"); + } + + start_args_deinit(&data[i].base); + } + + printf("Value of count after update: %d\n", g_count); + assert(g_count == (NUM_THREADS * NUM_ITER) + && "Global count not updated correctly"); + + assert(pthread_mutex_destroy(&mutex) == 0 && "Failed to destroy mutex"); + return EXIT_SUCCESS; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/linear_memory_size_update.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/linear_memory_size_update.c new file mode 100644 index 000000000..9dcb34a6c --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/linear_memory_size_update.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ +#include <stdlib.h> +#include <pthread.h> + +typedef enum { + APP_STARTED, + THREAD_STARTED, + MEMORY_ALLOCATED, +} app_state_t; +typedef struct { + + pthread_cond_t cond; + pthread_mutex_t mutex; + app_state_t state; + char *data; +} context_t; + +void +context_init(context_t *ctx) +{ + pthread_cond_init(&ctx->cond, NULL); + pthread_mutex_init(&ctx->mutex, NULL); + ctx->state = APP_STARTED; + ctx->data = NULL; +} + +void +context_destroy(context_t *ctx) +{ + pthread_cond_destroy(&ctx->cond); + pthread_mutex_destroy(&ctx->mutex); + if (ctx->data) { + free(ctx->data); + } +} + +void +context_set_state(context_t *ctx, app_state_t state) +{ + pthread_mutex_lock(&ctx->mutex); + ctx->state = state; + pthread_mutex_unlock(&ctx->mutex); + pthread_cond_signal(&ctx->cond); +} + +void +context_wait_for_state(context_t *ctx, app_state_t state) +{ + pthread_mutex_lock(&ctx->mutex); + while (ctx->state != state) { + pthread_cond_wait(&ctx->cond, &ctx->mutex); + } + pthread_mutex_unlock(&ctx->mutex); +} + +void * +fnc(void *p) +{ + context_t *ctx = (context_t *)p; + context_set_state(ctx, THREAD_STARTED); + + context_wait_for_state(ctx, MEMORY_ALLOCATED); + + // trigger memory.copy + __builtin_memcpy(ctx->data + 512 * 1024, ctx->data + 1024, 1024); + + return NULL; +} + +int +main() +{ + context_t ctx; + context_init(&ctx); + + pthread_t th; + pthread_create(&th, NULL, fnc, &ctx); + + context_wait_for_state(&ctx, THREAD_STARTED); + + // trigger memory.grow + ctx.data = calloc(1024 * 1024, 1); + + context_set_state(&ctx, MEMORY_ALLOCATED); + + pthread_join(th, NULL); + + context_destroy(&ctx); + + return 0; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.c new file mode 100644 index 000000000..19d3ec256 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include "common.h" + +int +main(int argc, char **argv) +{ + test_termination(false, true, BLOCKING_TASK_BUSY_WAIT); +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.json b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.json new file mode 100644 index 000000000..5370f6670 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.json @@ -0,0 +1,3 @@ +{ + "exit_code": 33 +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.c new file mode 100644 index 000000000..a667e9122 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include "common.h" + +int +main(int argc, char **argv) +{ + test_termination(false, true, BLOCKING_TASK_POLL_ONEOFF); +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.json b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.json new file mode 100644 index 000000000..5370f6670 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.json @@ -0,0 +1,3 @@ +{ + "exit_code": 33 +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.c new file mode 100644 index 000000000..dc8615adb --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include "common.h" + +int +main(int argc, char **argv) +{ + test_termination(false, true, BLOCKING_TASK_ATOMIC_WAIT); +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.json b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.json new file mode 100644 index 000000000..5370f6670 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.json @@ -0,0 +1,3 @@ +{ + "exit_code": 33 +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.c new file mode 100644 index 000000000..bb0ac8fa0 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include "common.h" + +int +main(int argc, char **argv) +{ + test_termination(true, true, BLOCKING_TASK_BUSY_WAIT); +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.json b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.json new file mode 100644 index 000000000..07689a105 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.json @@ -0,0 +1,3 @@ +{ + "exit_code": 1 +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.c new file mode 100644 index 000000000..a2c248882 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include "common.h" + +int +main(int argc, char **argv) +{ + test_termination(true, true, BLOCKING_TASK_POLL_ONEOFF); +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.json b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.json new file mode 100644 index 000000000..07689a105 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.json @@ -0,0 +1,3 @@ +{ + "exit_code": 1 +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.c new file mode 100644 index 000000000..0904f34bb --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include "common.h" + +int +main(int argc, char **argv) +{ + test_termination(true, true, BLOCKING_TASK_ATOMIC_WAIT); +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.json b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.json new file mode 100644 index 000000000..07689a105 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.json @@ -0,0 +1,3 @@ +{ + "exit_code": 1 +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.c new file mode 100644 index 000000000..71fdcb817 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include "common.h" + +int +main(int argc, char **argv) +{ + test_termination(false, false, BLOCKING_TASK_BUSY_WAIT); +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.json b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.json new file mode 100644 index 000000000..5370f6670 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.json @@ -0,0 +1,3 @@ +{ + "exit_code": 33 +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.c new file mode 100644 index 000000000..14352cf41 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include "common.h" + +int +main(int argc, char **argv) +{ + test_termination(false, false, BLOCKING_TASK_POLL_ONEOFF); +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.json b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.json new file mode 100644 index 000000000..5370f6670 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.json @@ -0,0 +1,3 @@ +{ + "exit_code": 33 +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.c new file mode 100644 index 000000000..0963aa02f --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include "common.h" + +int +main(int argc, char **argv) +{ + test_termination(false, false, BLOCKING_TASK_ATOMIC_WAIT); +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.json b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.json new file mode 100644 index 000000000..5370f6670 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.json @@ -0,0 +1,3 @@ +{ + "exit_code": 33 +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.c new file mode 100644 index 000000000..b3e3af7dc --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include "common.h" + +int +main(int argc, char **argv) +{ + test_termination(true, false, BLOCKING_TASK_BUSY_WAIT); +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.json b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.json new file mode 100644 index 000000000..07689a105 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.json @@ -0,0 +1,3 @@ +{ + "exit_code": 1 +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.c new file mode 100644 index 000000000..a68ae8be5 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include "common.h" + +int +main(int argc, char **argv) +{ + test_termination(true, false, BLOCKING_TASK_POLL_ONEOFF); +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.json b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.json new file mode 100644 index 000000000..07689a105 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.json @@ -0,0 +1,3 @@ +{ + "exit_code": 1 +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.c new file mode 100644 index 000000000..52c684a51 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include "common.h" + +int +main(int argc, char **argv) +{ + test_termination(true, false, BLOCKING_TASK_ATOMIC_WAIT); +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.json b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.json new file mode 100644 index 000000000..07689a105 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.json @@ -0,0 +1,3 @@ +{ + "exit_code": 1 +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/spawn_multiple_times.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/spawn_multiple_times.c new file mode 100644 index 000000000..24664c470 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/spawn_multiple_times.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <stdbool.h> + +#include "wasi_thread_start.h" + +enum CONSTANTS { + NUM_ITER = 50, + NUM_RETRY = 5, + SECOND = 1000 * 1000 * 1000, /* 1 second */ + TIMEOUT = 5LL * SECOND +}; + +typedef struct { + start_args_t base; + int th_done; +} shared_t; + +int g_count = 0; + +void +__wasi_thread_start_C(int thread_id, int *start_arg) +{ + shared_t *data = (shared_t *)start_arg; + + g_count++; + + __atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&data->th_done, 1); +} + +int +main(int argc, char **argv) +{ + shared_t data = { 0 }; + assert(start_args_init(&data.base) && "Stack allocation for thread failed"); + + for (int i = 0; i < NUM_ITER; i++) { + data.th_done = 0; + + printf("Creating thread\n"); + int thread_id = -1; + for (int j = 0; j < NUM_RETRY && thread_id < 0; j++) { + thread_id = __wasi_thread_spawn(&data); + if (thread_id < 0) + __builtin_wasm_memory_atomic_wait32(NULL, 0, SECOND); + } + assert(thread_id > 0 && "Thread creation should succeed"); + + printf("Waiting for thread to finish\n"); + if (__builtin_wasm_memory_atomic_wait32(&data.th_done, 0, TIMEOUT) + == 2) { + assert(false && "Wait should not time out"); + } + printf("Thread has finished\n"); + } + + assert(g_count == NUM_ITER && "Count has not been updated correctly"); + + start_args_deinit(&data.base); + return EXIT_SUCCESS; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/sync_primitives.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/sync_primitives.h new file mode 100644 index 000000000..4b7dac8ec --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/sync_primitives.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include <stdbool.h> + +/* Mutex */ + +typedef int pthread_mutex_t; + +int +pthread_mutex_init(pthread_mutex_t *mutex, void *unused) +{ + *mutex = 0; + return 0; +} + +int +pthread_mutex_destroy(pthread_mutex_t *mutex) +{ + return 0; +} + +static bool +try_pthread_mutex_lock(pthread_mutex_t *mutex) +{ + int expected = 0; + return __atomic_compare_exchange_n(mutex, &expected, 1, false, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); +} + +int +pthread_mutex_lock(pthread_mutex_t *mutex) +{ + while (!try_pthread_mutex_lock(mutex)) + __builtin_wasm_memory_atomic_wait32(mutex, 1, -1); + return 0; +} + +int +pthread_mutex_unlock(pthread_mutex_t *mutex) +{ + __atomic_store_n(mutex, 0, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(mutex, 1); + return 0; +} + +/* Barrier */ + +typedef struct { + int count; + int num_threads; + int mutex; + int ready; +} pthread_barrier_t; + +int +pthread_barrier_init(pthread_barrier_t *barrier, void *unused, int num_threads) +{ + barrier->count = 0; + barrier->num_threads = num_threads; + barrier->ready = 0; + pthread_mutex_init(&barrier->mutex, NULL); + + return 0; +} + +int +pthread_barrier_wait(pthread_barrier_t *barrier) +{ + bool no_wait = false; + int count; + + pthread_mutex_lock(&barrier->mutex); + count = barrier->count++; + if (barrier->count >= barrier->num_threads) { + no_wait = true; + barrier->count = 0; + } + pthread_mutex_unlock(&barrier->mutex); + + if (no_wait) { + __atomic_store_n(&barrier->ready, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&barrier->ready, count); + return 0; + } + + __builtin_wasm_memory_atomic_wait32(&barrier->ready, 0, -1); + return 0; +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/trap_after_main_thread_finishes.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/trap_after_main_thread_finishes.c new file mode 100644 index 000000000..69e125d40 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/trap_after_main_thread_finishes.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> + +#include "wasi_thread_start.h" + +enum CONSTANTS { + SECOND = 1000 * 1000 * 1000, /* 1 second */ + TIMEOUT = 1LL * SECOND +}; + +typedef struct { + start_args_t base; +} shared_t; + +void +__wasi_thread_start_C(int thread_id, int *start_arg) +{ + /* Wait so that the exception is raised after the main thread has finished + * already */ + __builtin_wasm_memory_atomic_wait32(NULL, 0, TIMEOUT); + __builtin_trap(); +} + +int +main(int argc, char **argv) +{ + shared_t data = { 0 }; + + assert(start_args_init(&data.base)); + int thread_id = __wasi_thread_spawn(&data); + assert(thread_id > 0 && "Thread creation failed"); + + return EXIT_SUCCESS; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/trap_after_main_thread_finishes.json b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/trap_after_main_thread_finishes.json new file mode 100644 index 000000000..9dc1e30d2 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/trap_after_main_thread_finishes.json @@ -0,0 +1,3 @@ +{ + "exit_code": 1 +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/update_shared_data_and_alloc_heap.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/update_shared_data_and_alloc_heap.c new file mode 100644 index 000000000..b7fb9afba --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/update_shared_data_and_alloc_heap.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef __wasi__ +#error This example only compiles to WASM/WASI target +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <stdbool.h> +#include <pthread.h> + +#include "wasi_thread_start.h" + +enum CONSTANTS { + NUM_THREADS = 4, + NUM_ITER = 30, + SECOND = 1000 * 1000 * 1000, /* 1 second */ + TIMEOUT = 10LL * SECOND +}; + +typedef struct { + start_args_t base; + int th_done; + int *count; + int iteration; + int *pval; +} shared_t; + +pthread_mutex_t mutex; +int *vals[NUM_THREADS]; + +void +__wasi_thread_start_C(int thread_id, int *start_arg) +{ + shared_t *data = (shared_t *)start_arg; + + for (int i = 0; i < NUM_ITER; i++) + __atomic_fetch_add(data->count, 1, __ATOMIC_SEQ_CST); + + *vals[data->iteration] = data->iteration; + + __atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&data->th_done, 1); +} + +int +main(int argc, char **argv) +{ + shared_t data[NUM_THREADS] = { 0 }; + int thread_ids[NUM_THREADS]; + int *count = calloc(1, sizeof(int)); + + assert(count != NULL && "Failed to call calloc"); + assert(pthread_mutex_init(&mutex, NULL) == 0 && "Failed to init mutex"); + + for (int i = 0; i < NUM_THREADS; i++) { + vals[i] = malloc(sizeof(int)); + assert(vals[i] != NULL && "Failed to call calloc"); + } + + for (int i = 0; i < NUM_THREADS; i++) { + assert(start_args_init(&data[i].base) + && "Stack allocation for thread failed"); + __atomic_store_n(&data[i].count, count, __ATOMIC_SEQ_CST); + data[i].iteration = i; + + thread_ids[i] = __wasi_thread_spawn(&data[i]); + assert(thread_ids[i] > 0 && "Thread creation failed"); + } + + printf("Wait for threads to finish\n"); + for (int i = 0; i < NUM_THREADS; i++) { + if (__builtin_wasm_memory_atomic_wait32(&data[i].th_done, 0, TIMEOUT) + == 2) { + assert(false && "Wait should not time out"); + } + + start_args_deinit(&data[i].base); + } + + assert(*count == (NUM_THREADS * NUM_ITER) && "Count not updated correctly"); + + for (int i = 0; i < NUM_THREADS; i++) { + printf("val=%d\n", *vals[i]); + assert(*vals[i] == i && "Value not updated correctly"); + free(vals[i]); + } + + free(count); + assert(pthread_mutex_destroy(&mutex) == 0 && "Failed to destroy mutex"); + + return EXIT_SUCCESS; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/tid_allocator.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/tid_allocator.c new file mode 100644 index 000000000..4d53da0c9 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/tid_allocator.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "tid_allocator.h" +#include "wasm_export.h" +#include "bh_log.h" + +bh_static_assert(TID_MIN <= TID_MAX); +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +bool +tid_allocator_init(TidAllocator *tid_allocator) +{ + tid_allocator->size = MIN(TID_ALLOCATOR_INIT_SIZE, TID_MAX - TID_MIN + 1); + tid_allocator->pos = tid_allocator->size; + tid_allocator->ids = + wasm_runtime_malloc(tid_allocator->size * sizeof(int32)); + if (tid_allocator->ids == NULL) + return false; + + for (int64 i = tid_allocator->pos - 1; i >= 0; i--) + tid_allocator->ids[i] = TID_MIN + (tid_allocator->pos - 1 - i); + + return true; +} + +void +tid_allocator_deinit(TidAllocator *tid_allocator) +{ + wasm_runtime_free(tid_allocator->ids); +} + +int32 +tid_allocator_get_tid(TidAllocator *tid_allocator) +{ + if (tid_allocator->pos == 0) { // Resize stack and push new thread ids + if (tid_allocator->size == TID_MAX - TID_MIN + 1) { + LOG_ERROR("Maximum thread identifier reached"); + return -1; + } + + uint32 old_size = tid_allocator->size; + uint32 new_size = MIN(tid_allocator->size * 2, TID_MAX - TID_MIN + 1); + if (new_size != TID_MAX - TID_MIN + 1 + && new_size / 2 != tid_allocator->size) { + LOG_ERROR("Overflow detected during new size calculation"); + return -1; + } + + size_t realloc_size = new_size * sizeof(int32); + if (realloc_size / sizeof(int32) != new_size) { + LOG_ERROR("Overflow detected during realloc"); + return -1; + } + int32 *tmp = wasm_runtime_realloc(tid_allocator->ids, realloc_size); + if (tmp == NULL) { + LOG_ERROR("Thread ID allocator realloc failed"); + return -1; + } + + tid_allocator->size = new_size; + tid_allocator->pos = new_size - old_size; + tid_allocator->ids = tmp; + for (int64 i = tid_allocator->pos - 1; i >= 0; i--) + tid_allocator->ids[i] = TID_MIN + (tid_allocator->size - 1 - i); + } + + // Pop available thread identifier from the stack + return tid_allocator->ids[--tid_allocator->pos]; +} + +void +tid_allocator_release_tid(TidAllocator *tid_allocator, int32 thread_id) +{ + // Release thread identifier by pushing it into the stack + bh_assert(tid_allocator->pos < tid_allocator->size); + tid_allocator->ids[tid_allocator->pos++] = thread_id; +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/tid_allocator.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/tid_allocator.h new file mode 100644 index 000000000..53af1719f --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/tid_allocator.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _TID_ALLOCATOR_H +#define _TID_ALLOCATOR_H + +#include "platform_common.h" + +#define TID_ALLOCATOR_INIT_SIZE CLUSTER_MAX_THREAD_NUM +enum { + TID_MIN = 1, + TID_MAX = 0x1FFFFFFF +}; // Reserved TIDs (WASI specification) + +/* Stack data structure to track available thread identifiers */ +typedef struct { + int32 *ids; // Array used to store the stack + uint32 size; // Stack capacity + uint32 pos; // Index of the element after the stack top +} TidAllocator; + +bool +tid_allocator_init(TidAllocator *tid_allocator); + +void +tid_allocator_deinit(TidAllocator *tid_allocator); + +int32 +tid_allocator_get_tid(TidAllocator *tid_allocator); + +void +tid_allocator_release_tid(TidAllocator *tid_allocator, int32 thread_id); + +#endif /* _TID_ALLOCATOR_H */
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-builtin/SConscript b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-builtin/SConscript new file mode 100644 index 000000000..8dd004382 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-builtin/SConscript @@ -0,0 +1,24 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * + +cwd = GetCurrentDir() + +#src = Split(''' +#libc_builtin_wrapper.c +#''') + +src = Glob('*.c') + +CPPDEFINES = ['WASM_ENABLE_LIBC_BUILTIN=1'] + +CPPPATH = [cwd] + + +group = DefineGroup('iwasm_libc_builtin', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES) + +Return('group') diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-builtin/libc_builtin.cmake b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-builtin/libc_builtin.cmake new file mode 100644 index 000000000..0838712b8 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-builtin/libc_builtin.cmake @@ -0,0 +1,13 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (LIBC_BUILTIN_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions (-DWASM_ENABLE_LIBC_BUILTIN=1) + +include_directories(${LIBC_BUILTIN_DIR}) + +file (GLOB source_all ${LIBC_BUILTIN_DIR}/*.c) + +set (LIBC_BUILTIN_SOURCE ${source_all}) + diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c new file mode 100644 index 000000000..55916deb4 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -0,0 +1,1123 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_common.h" +#include "bh_log.h" +#include "wasm_export.h" +#include "../interpreter/wasm.h" + +#if defined(_WIN32) || defined(_WIN32_) +#define strncasecmp _strnicmp +#define strcasecmp _stricmp +#endif + +void +wasm_runtime_set_exception(wasm_module_inst_t module, const char *exception); + +uint32 +wasm_runtime_module_realloc(wasm_module_inst_t module, uint32 ptr, uint32 size, + void **p_native_addr); + +/* clang-format off */ +#define get_module_inst(exec_env) \ + wasm_runtime_get_module_inst(exec_env) + +#define validate_app_addr(offset, size) \ + wasm_runtime_validate_app_addr(module_inst, offset, size) + +#define validate_app_str_addr(offset) \ + wasm_runtime_validate_app_str_addr(module_inst, offset) + +#define validate_native_addr(addr, size) \ + wasm_runtime_validate_native_addr(module_inst, addr, size) + +#define addr_app_to_native(offset) \ + wasm_runtime_addr_app_to_native(module_inst, offset) + +#define addr_native_to_app(ptr) \ + wasm_runtime_addr_native_to_app(module_inst, ptr) + +#define module_malloc(size, p_native_addr) \ + wasm_runtime_module_malloc(module_inst, size, p_native_addr) + +#define module_free(offset) \ + wasm_runtime_module_free(module_inst, offset) +/* clang-format on */ + +typedef int (*out_func_t)(int c, void *ctx); + +typedef char *_va_list; +#define _INTSIZEOF(n) (((uint32)sizeof(n) + 3) & (uint32)~3) +#define _va_arg(ap, t) (*(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))) + +#define CHECK_VA_ARG(ap, t) \ + do { \ + if ((uint8 *)ap + _INTSIZEOF(t) > native_end_addr) { \ + if (fmt_buf != temp_fmt) { \ + wasm_runtime_free(fmt_buf); \ + } \ + goto fail; \ + } \ + } while (0) + +/* clang-format off */ +#define PREPARE_TEMP_FORMAT() \ + char temp_fmt[32], *s, *fmt_buf = temp_fmt; \ + uint32 fmt_buf_len = (uint32)sizeof(temp_fmt); \ + int32 n; \ + \ + /* additional 2 bytes: one is the format char, \ + the other is `\0` */ \ + if ((uint32)(fmt - fmt_start_addr + 2) >= fmt_buf_len) { \ + bh_assert((uint32)(fmt - fmt_start_addr) <= \ + UINT32_MAX - 2); \ + fmt_buf_len = (uint32)(fmt - fmt_start_addr + 2); \ + if (!(fmt_buf = wasm_runtime_malloc(fmt_buf_len))) { \ + print_err(out, ctx); \ + break; \ + } \ + } \ + \ + memset(fmt_buf, 0, fmt_buf_len); \ + bh_memcpy_s(fmt_buf, fmt_buf_len, fmt_start_addr, \ + (uint32)(fmt - fmt_start_addr + 1)); +/* clang-format on */ + +#define OUTPUT_TEMP_FORMAT() \ + do { \ + if (n > 0) { \ + s = buf; \ + while (*s) \ + out((int)(*s++), ctx); \ + } \ + \ + if (fmt_buf != temp_fmt) { \ + wasm_runtime_free(fmt_buf); \ + } \ + } while (0) + +static void +print_err(out_func_t out, void *ctx) +{ + out('E', ctx); + out('R', ctx); + out('R', ctx); +} + +static bool +_vprintf_wa(out_func_t out, void *ctx, const char *fmt, _va_list ap, + wasm_module_inst_t module_inst) +{ + int might_format = 0; /* 1 if encountered a '%' */ + int long_ctr = 0; + uint8 *native_end_addr; + const char *fmt_start_addr = NULL; + + if (!wasm_runtime_get_native_addr_range(module_inst, (uint8 *)ap, NULL, + &native_end_addr)) + goto fail; + + /* fmt has already been adjusted if needed */ + + while (*fmt) { + if (!might_format) { + if (*fmt != '%') { + out((int)*fmt, ctx); + } + else { + might_format = 1; + long_ctr = 0; + fmt_start_addr = fmt; + } + } + else { + switch (*fmt) { + case '.': + case '+': + case '-': + case ' ': + case '#': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + goto still_might_format; + + case 't': /* ptrdiff_t */ + case 'z': /* size_t (32bit on wasm) */ + long_ctr = 1; + goto still_might_format; + + case 'j': + /* intmax_t/uintmax_t */ + long_ctr = 2; + goto still_might_format; + + case 'l': + long_ctr++; + /* Fall through */ + case 'h': + /* FIXME: do nothing for these modifiers */ + goto still_might_format; + + case 'o': + case 'd': + case 'i': + case 'u': + case 'p': + case 'x': + case 'X': + case 'c': + { + char buf[64]; + PREPARE_TEMP_FORMAT(); + + if (long_ctr < 2) { + int32 d; + + CHECK_VA_ARG(ap, uint32); + d = _va_arg(ap, int32); + + if (long_ctr == 1) { + uint32 fmt_end_idx = (uint32)(fmt - fmt_start_addr); + + if (fmt_buf[fmt_end_idx - 1] == 'l' + || fmt_buf[fmt_end_idx - 1] == 'z' + || fmt_buf[fmt_end_idx - 1] == 't') { + /* The %ld, %zd and %td should be treated as + * 32bit integer in wasm */ + fmt_buf[fmt_end_idx - 1] = fmt_buf[fmt_end_idx]; + fmt_buf[fmt_end_idx] = '\0'; + } + } + + n = snprintf(buf, sizeof(buf), fmt_buf, d); + } + else { + int64 lld; + + /* Make 8-byte aligned */ + ap = (_va_list)(((uintptr_t)ap + 7) & ~(uintptr_t)7); + CHECK_VA_ARG(ap, uint64); + lld = _va_arg(ap, int64); + n = snprintf(buf, sizeof(buf), fmt_buf, lld); + } + + OUTPUT_TEMP_FORMAT(); + break; + } + + case 's': + { + char buf_tmp[128], *buf = buf_tmp; + char *start; + uint32 s_offset, str_len, buf_len; + + PREPARE_TEMP_FORMAT(); + + CHECK_VA_ARG(ap, int32); + s_offset = _va_arg(ap, uint32); + + if (!validate_app_str_addr(s_offset)) { + if (fmt_buf != temp_fmt) { + wasm_runtime_free(fmt_buf); + } + return false; + } + + s = start = addr_app_to_native(s_offset); + + str_len = (uint32)strlen(start); + if (str_len >= UINT32_MAX - 64) { + print_err(out, ctx); + if (fmt_buf != temp_fmt) { + wasm_runtime_free(fmt_buf); + } + break; + } + + /* reserve 64 more bytes as there may be width description + * in the fmt */ + buf_len = str_len + 64; + + if (buf_len > (uint32)sizeof(buf_tmp)) { + if (!(buf = wasm_runtime_malloc(buf_len))) { + print_err(out, ctx); + if (fmt_buf != temp_fmt) { + wasm_runtime_free(fmt_buf); + } + break; + } + } + + n = snprintf(buf, buf_len, fmt_buf, + (s_offset == 0 && str_len == 0) ? NULL + : start); + + OUTPUT_TEMP_FORMAT(); + + if (buf != buf_tmp) { + wasm_runtime_free(buf); + } + + break; + } + + case '%': + { + out((int)'%', ctx); + break; + } + + case 'e': + case 'E': + case 'g': + case 'G': + case 'f': + case 'F': + { + float64 f64; + char buf[64]; + PREPARE_TEMP_FORMAT(); + + /* Make 8-byte aligned */ + ap = (_va_list)(((uintptr_t)ap + 7) & ~(uintptr_t)7); + CHECK_VA_ARG(ap, float64); + f64 = _va_arg(ap, float64); + n = snprintf(buf, sizeof(buf), fmt_buf, f64); + + OUTPUT_TEMP_FORMAT(); + break; + } + + case 'n': + /* print nothing */ + break; + + default: + out((int)'%', ctx); + out((int)*fmt, ctx); + break; + } + + might_format = 0; + } + + still_might_format: + ++fmt; + } + return true; + +fail: + wasm_runtime_set_exception(module_inst, "out of bounds memory access"); + return false; +} + +struct str_context { + char *str; + uint32 max; + uint32 count; +}; + +static int +sprintf_out(int c, struct str_context *ctx) +{ + if (!ctx->str || ctx->count >= ctx->max) { + ctx->count++; + return c; + } + + if (ctx->count == ctx->max - 1) { + ctx->str[ctx->count++] = '\0'; + } + else { + ctx->str[ctx->count++] = (char)c; + } + + return c; +} + +#ifndef BUILTIN_LIBC_BUFFERED_PRINTF +#define BUILTIN_LIBC_BUFFERED_PRINTF 0 +#endif + +#ifndef BUILTIN_LIBC_BUFFERED_PRINT_SIZE +#define BUILTIN_LIBC_BUFFERED_PRINT_SIZE 128 +#endif +#ifndef BUILTIN_LIBC_BUFFERED_PRINT_PREFIX +#define BUILTIN_LIBC_BUFFERED_PRINT_PREFIX +#endif + +#if BUILTIN_LIBC_BUFFERED_PRINTF != 0 + +BUILTIN_LIBC_BUFFERED_PRINT_PREFIX +static char print_buf[BUILTIN_LIBC_BUFFERED_PRINT_SIZE] = { 0 }; + +BUILTIN_LIBC_BUFFERED_PRINT_PREFIX +static int print_buf_size = 0; + +static int +printf_out(int c, struct str_context *ctx) +{ + if (c == '\n') { + print_buf[print_buf_size] = '\0'; + os_printf("%s\n", print_buf); + print_buf_size = 0; + } + else if (print_buf_size >= sizeof(print_buf) - 2) { + print_buf[print_buf_size++] = (char)c; + print_buf[print_buf_size] = '\0'; + os_printf("%s\n", print_buf); + print_buf_size = 0; + } + else { + print_buf[print_buf_size++] = (char)c; + } + ctx->count++; + return c; +} +#else +static int +printf_out(int c, struct str_context *ctx) +{ + os_printf("%c", c); + ctx->count++; + return c; +} +#endif + +static int +printf_wrapper(wasm_exec_env_t exec_env, const char *format, _va_list va_args) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + struct str_context ctx = { NULL, 0, 0 }; + + /* format has been checked by runtime */ + if (!validate_native_addr(va_args, sizeof(int32))) + return 0; + + if (!_vprintf_wa((out_func_t)printf_out, &ctx, format, va_args, + module_inst)) + return 0; + + return (int)ctx.count; +} + +static int +sprintf_wrapper(wasm_exec_env_t exec_env, char *str, const char *format, + _va_list va_args) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uint8 *native_end_offset; + struct str_context ctx; + + /* str and format have been checked by runtime */ + if (!validate_native_addr(va_args, sizeof(uint32))) + return 0; + + if (!wasm_runtime_get_native_addr_range(module_inst, (uint8 *)str, NULL, + &native_end_offset)) { + wasm_runtime_set_exception(module_inst, "out of bounds memory access"); + return false; + } + + ctx.str = str; + ctx.max = (uint32)(native_end_offset - (uint8 *)str); + ctx.count = 0; + + if (!_vprintf_wa((out_func_t)sprintf_out, &ctx, format, va_args, + module_inst)) + return 0; + + if (ctx.count < ctx.max) { + str[ctx.count] = '\0'; + } + + return (int)ctx.count; +} + +static int +snprintf_wrapper(wasm_exec_env_t exec_env, char *str, uint32 size, + const char *format, _va_list va_args) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + struct str_context ctx; + + /* str and format have been checked by runtime */ + if (!validate_native_addr(va_args, sizeof(uint32))) + return 0; + + ctx.str = str; + ctx.max = size; + ctx.count = 0; + + if (!_vprintf_wa((out_func_t)sprintf_out, &ctx, format, va_args, + module_inst)) + return 0; + + if (ctx.count < ctx.max) { + str[ctx.count] = '\0'; + } + + return (int)ctx.count; +} + +static int +puts_wrapper(wasm_exec_env_t exec_env, const char *str) +{ + return os_printf("%s\n", str); +} + +static int +putchar_wrapper(wasm_exec_env_t exec_env, int c) +{ + os_printf("%c", c); + return 1; +} + +static uint32 +strdup_wrapper(wasm_exec_env_t exec_env, const char *str) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + char *str_ret; + uint32 len; + uint32 str_ret_offset = 0; + + /* str has been checked by runtime */ + if (str) { + len = (uint32)strlen(str) + 1; + + str_ret_offset = module_malloc(len, (void **)&str_ret); + if (str_ret_offset) { + bh_memcpy_s(str_ret, len, str, len); + } + } + + return str_ret_offset; +} + +static uint32 +_strdup_wrapper(wasm_exec_env_t exec_env, const char *str) +{ + return strdup_wrapper(exec_env, str); +} + +static int32 +memcmp_wrapper(wasm_exec_env_t exec_env, const void *s1, const void *s2, + uint32 size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + + /* s2 has been checked by runtime */ + if (!validate_native_addr((void *)s1, size)) + return 0; + + return memcmp(s1, s2, size); +} + +static uint32 +memcpy_wrapper(wasm_exec_env_t exec_env, void *dst, const void *src, + uint32 size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uint32 dst_offset = addr_native_to_app(dst); + + if (size == 0) + return dst_offset; + + /* src has been checked by runtime */ + if (!validate_native_addr(dst, size)) + return dst_offset; + + bh_memcpy_s(dst, size, src, size); + return dst_offset; +} + +static uint32 +memmove_wrapper(wasm_exec_env_t exec_env, void *dst, void *src, uint32 size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uint32 dst_offset = addr_native_to_app(dst); + + if (size == 0) + return dst_offset; + + /* src has been checked by runtime */ + if (!validate_native_addr(dst, size)) + return dst_offset; + + memmove(dst, src, size); + return dst_offset; +} + +static uint32 +memset_wrapper(wasm_exec_env_t exec_env, void *s, int32 c, uint32 size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uint32 s_offset = addr_native_to_app(s); + + if (!validate_native_addr(s, size)) + return s_offset; + + memset(s, c, size); + return s_offset; +} + +static uint32 +strchr_wrapper(wasm_exec_env_t exec_env, const char *s, int32 c) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + char *ret; + + /* s has been checked by runtime */ + ret = strchr(s, c); + return ret ? addr_native_to_app(ret) : 0; +} + +static int32 +strcmp_wrapper(wasm_exec_env_t exec_env, const char *s1, const char *s2) +{ + /* s1 and s2 have been checked by runtime */ + return strcmp(s1, s2); +} + +static int32 +strncmp_wrapper(wasm_exec_env_t exec_env, const char *s1, const char *s2, + uint32 size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + + /* s2 has been checked by runtime */ + if (!validate_native_addr((void *)s1, size)) + return 0; + + return strncmp(s1, s2, size); +} + +static uint32 +strcpy_wrapper(wasm_exec_env_t exec_env, char *dst, const char *src) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uint32 len = (uint32)strlen(src) + 1; + + /* src has been checked by runtime */ + if (!validate_native_addr(dst, len)) + return 0; + +#ifndef BH_PLATFORM_WINDOWS + strncpy(dst, src, len); +#else + strncpy_s(dst, len, src, len); +#endif + return addr_native_to_app(dst); +} + +static uint32 +strncpy_wrapper(wasm_exec_env_t exec_env, char *dst, const char *src, + uint32 size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + + /* src has been checked by runtime */ + if (!validate_native_addr(dst, size)) + return 0; + +#ifndef BH_PLATFORM_WINDOWS + strncpy(dst, src, size); +#else + strncpy_s(dst, size, src, size); +#endif + return addr_native_to_app(dst); +} + +static uint32 +strlen_wrapper(wasm_exec_env_t exec_env, const char *s) +{ + /* s has been checked by runtime */ + return (uint32)strlen(s); +} + +static uint32 +malloc_wrapper(wasm_exec_env_t exec_env, uint32 size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + return module_malloc(size, NULL); +} + +static uint32 +calloc_wrapper(wasm_exec_env_t exec_env, uint32 nmemb, uint32 size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uint64 total_size = (uint64)nmemb * (uint64)size; + uint32 ret_offset = 0; + uint8 *ret_ptr; + + if (total_size >= UINT32_MAX) + return 0; + + ret_offset = module_malloc((uint32)total_size, (void **)&ret_ptr); + if (ret_offset) { + memset(ret_ptr, 0, (uint32)total_size); + } + + return ret_offset; +} + +static uint32 +realloc_wrapper(wasm_exec_env_t exec_env, uint32 ptr, uint32 new_size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + + return wasm_runtime_module_realloc(module_inst, ptr, new_size, NULL); +} + +static void +free_wrapper(wasm_exec_env_t exec_env, void *ptr) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + + if (!validate_native_addr(ptr, sizeof(uint32))) + return; + + module_free(addr_native_to_app(ptr)); +} + +static int32 +atoi_wrapper(wasm_exec_env_t exec_env, const char *s) +{ + /* s has been checked by runtime */ + return atoi(s); +} + +static void +exit_wrapper(wasm_exec_env_t exec_env, int32 status) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + char buf[32]; + snprintf(buf, sizeof(buf), "env.exit(%" PRId32 ")", status); + wasm_runtime_set_exception(module_inst, buf); +} + +static int32 +strtol_wrapper(wasm_exec_env_t exec_env, const char *nptr, char **endptr, + int32 base) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + int32 num = 0; + + /* nptr has been checked by runtime */ + if (!validate_native_addr(endptr, sizeof(uint32))) + return 0; + + num = (int32)strtol(nptr, endptr, base); + *(uint32 *)endptr = addr_native_to_app(*endptr); + + return num; +} + +static uint32 +strtoul_wrapper(wasm_exec_env_t exec_env, const char *nptr, char **endptr, + int32 base) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uint32 num = 0; + + /* nptr has been checked by runtime */ + if (!validate_native_addr(endptr, sizeof(uint32))) + return 0; + + num = (uint32)strtoul(nptr, endptr, base); + *(uint32 *)endptr = addr_native_to_app(*endptr); + + return num; +} + +static uint32 +memchr_wrapper(wasm_exec_env_t exec_env, const void *s, int32 c, uint32 n) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + void *res; + + if (!validate_native_addr((void *)s, n)) + return 0; + + res = memchr(s, c, n); + return addr_native_to_app(res); +} + +static int32 +strncasecmp_wrapper(wasm_exec_env_t exec_env, const char *s1, const char *s2, + uint32 n) +{ + /* s1 and s2 have been checked by runtime */ + return strncasecmp(s1, s2, n); +} + +static uint32 +strspn_wrapper(wasm_exec_env_t exec_env, const char *s, const char *accept) +{ + /* s and accept have been checked by runtime */ + return (uint32)strspn(s, accept); +} + +static uint32 +strcspn_wrapper(wasm_exec_env_t exec_env, const char *s, const char *reject) +{ + /* s and reject have been checked by runtime */ + return (uint32)strcspn(s, reject); +} + +static uint32 +strstr_wrapper(wasm_exec_env_t exec_env, const char *s, const char *find) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + /* s and find have been checked by runtime */ + char *res = strstr(s, find); + return addr_native_to_app(res); +} + +static int32 +isupper_wrapper(wasm_exec_env_t exec_env, int32 c) +{ + return isupper(c); +} + +static int32 +isalpha_wrapper(wasm_exec_env_t exec_env, int32 c) +{ + return isalpha(c); +} + +static int32 +isspace_wrapper(wasm_exec_env_t exec_env, int32 c) +{ + return isspace(c); +} + +static int32 +isgraph_wrapper(wasm_exec_env_t exec_env, int32 c) +{ + return isgraph(c); +} + +static int32 +isprint_wrapper(wasm_exec_env_t exec_env, int32 c) +{ + return isprint(c); +} + +static int32 +isdigit_wrapper(wasm_exec_env_t exec_env, int32 c) +{ + return isdigit(c); +} + +static int32 +isxdigit_wrapper(wasm_exec_env_t exec_env, int32 c) +{ + return isxdigit(c); +} + +static int32 +tolower_wrapper(wasm_exec_env_t exec_env, int32 c) +{ + return tolower(c); +} + +static int32 +toupper_wrapper(wasm_exec_env_t exec_env, int32 c) +{ + return toupper(c); +} + +static int32 +isalnum_wrapper(wasm_exec_env_t exec_env, int32 c) +{ + return isalnum(c); +} + +static uint32 +emscripten_memcpy_big_wrapper(wasm_exec_env_t exec_env, void *dst, + const void *src, uint32 size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uint32 dst_offset = addr_native_to_app(dst); + + /* src has been checked by runtime */ + if (!validate_native_addr(dst, size)) + return dst_offset; + + bh_memcpy_s(dst, size, src, size); + return dst_offset; +} + +static void +abort_wrapper(wasm_exec_env_t exec_env, int32 code) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + char buf[32]; + snprintf(buf, sizeof(buf), "env.abort(%" PRId32 ")", code); + wasm_runtime_set_exception(module_inst, buf); +} + +static void +abortStackOverflow_wrapper(wasm_exec_env_t exec_env, int32 code) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + char buf[32]; + snprintf(buf, sizeof(buf), "env.abortStackOverflow(%" PRId32 ")", code); + wasm_runtime_set_exception(module_inst, buf); +} + +static void +nullFunc_X_wrapper(wasm_exec_env_t exec_env, int32 code) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + char buf[32]; + snprintf(buf, sizeof(buf), "env.nullFunc_X(%" PRId32 ")", code); + wasm_runtime_set_exception(module_inst, buf); +} + +static uint32 +__cxa_allocate_exception_wrapper(wasm_exec_env_t exec_env, uint32 thrown_size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uint32 exception = module_malloc(thrown_size, NULL); + if (!exception) + return 0; + + return exception; +} + +static void +__cxa_begin_catch_wrapper(wasm_exec_env_t exec_env, void *exception_object) +{} + +static void +__cxa_throw_wrapper(wasm_exec_env_t exec_env, void *thrown_exception, + void *tinfo, uint32 table_elem_idx) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + char buf[32]; + + snprintf(buf, sizeof(buf), "%s", "exception thrown by stdc++"); + wasm_runtime_set_exception(module_inst, buf); +} + +struct timespec_app { + int64 tv_sec; + int32 tv_nsec; +}; + +static uint32 +clock_gettime_wrapper(wasm_exec_env_t exec_env, uint32 clk_id, + struct timespec_app *ts_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uint64 time; + + if (!validate_native_addr(ts_app, sizeof(struct timespec_app))) + return (uint32)-1; + + time = os_time_get_boot_microsecond(); + ts_app->tv_sec = time / 1000000; + ts_app->tv_nsec = (time % 1000000) * 1000; + + return (uint32)0; +} + +static uint64 +clock_wrapper(wasm_exec_env_t exec_env) +{ + /* Convert to nano seconds as CLOCKS_PER_SEC in wasi-sdk */ + + return os_time_get_boot_microsecond() * 1000; +} + +#if WASM_ENABLE_SPEC_TEST != 0 +static void +print_wrapper(wasm_exec_env_t exec_env) +{ + os_printf("in specttest.print()\n"); +} + +static void +print_i32_wrapper(wasm_exec_env_t exec_env, int32 i32) +{ + os_printf("in specttest.print_i32(%" PRId32 ")\n", i32); +} + +static void +print_i32_f32_wrapper(wasm_exec_env_t exec_env, int32 i32, float f32) +{ + os_printf("in specttest.print_i32_f32(%" PRId32 ", %f)\n", i32, f32); +} + +static void +print_f64_f64_wrapper(wasm_exec_env_t exec_env, double f64_1, double f64_2) +{ + os_printf("in specttest.print_f64_f64(%f, %f)\n", f64_1, f64_2); +} + +static void +print_f32_wrapper(wasm_exec_env_t exec_env, float f32) +{ + os_printf("in specttest.print_f32(%f)\n", f32); +} + +static void +print_f64_wrapper(wasm_exec_env_t exec_env, double f64) +{ + os_printf("in specttest.print_f64(%f)\n", f64); +} +#endif /* WASM_ENABLE_SPEC_TEST */ + +/* clang-format off */ +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, func_name##_wrapper, signature, NULL } +/* clang-format on */ + +static NativeSymbol native_symbols_libc_builtin[] = { + REG_NATIVE_FUNC(printf, "($*)i"), + REG_NATIVE_FUNC(sprintf, "($$*)i"), + REG_NATIVE_FUNC(snprintf, "(*~$*)i"), + { "vprintf", printf_wrapper, "($*)i", NULL }, + { "vsprintf", sprintf_wrapper, "($$*)i", NULL }, + { "vsnprintf", snprintf_wrapper, "(*~$*)i", NULL }, + REG_NATIVE_FUNC(puts, "($)i"), + REG_NATIVE_FUNC(putchar, "(i)i"), + REG_NATIVE_FUNC(memcmp, "(**~)i"), + REG_NATIVE_FUNC(memcpy, "(**~)i"), + REG_NATIVE_FUNC(memmove, "(**~)i"), + REG_NATIVE_FUNC(memset, "(*ii)i"), + REG_NATIVE_FUNC(strchr, "($i)i"), + REG_NATIVE_FUNC(strcmp, "($$)i"), + REG_NATIVE_FUNC(strcpy, "(*$)i"), + REG_NATIVE_FUNC(strlen, "($)i"), + REG_NATIVE_FUNC(strncmp, "(**~)i"), + REG_NATIVE_FUNC(strncpy, "(**~)i"), + REG_NATIVE_FUNC(malloc, "(i)i"), + REG_NATIVE_FUNC(realloc, "(ii)i"), + REG_NATIVE_FUNC(calloc, "(ii)i"), + REG_NATIVE_FUNC(strdup, "($)i"), + /* clang may introduce __strdup */ + REG_NATIVE_FUNC(_strdup, "($)i"), + REG_NATIVE_FUNC(free, "(*)"), + REG_NATIVE_FUNC(atoi, "($)i"), + REG_NATIVE_FUNC(exit, "(i)"), + REG_NATIVE_FUNC(strtol, "($*i)i"), + REG_NATIVE_FUNC(strtoul, "($*i)i"), + REG_NATIVE_FUNC(memchr, "(*ii)i"), + REG_NATIVE_FUNC(strncasecmp, "($$i)i"), + REG_NATIVE_FUNC(strspn, "($$)i"), + REG_NATIVE_FUNC(strcspn, "($$)i"), + REG_NATIVE_FUNC(strstr, "($$)i"), + REG_NATIVE_FUNC(isupper, "(i)i"), + REG_NATIVE_FUNC(isalpha, "(i)i"), + REG_NATIVE_FUNC(isspace, "(i)i"), + REG_NATIVE_FUNC(isgraph, "(i)i"), + REG_NATIVE_FUNC(isprint, "(i)i"), + REG_NATIVE_FUNC(isdigit, "(i)i"), + REG_NATIVE_FUNC(isxdigit, "(i)i"), + REG_NATIVE_FUNC(tolower, "(i)i"), + REG_NATIVE_FUNC(toupper, "(i)i"), + REG_NATIVE_FUNC(isalnum, "(i)i"), + REG_NATIVE_FUNC(emscripten_memcpy_big, "(**~)i"), + REG_NATIVE_FUNC(abort, "(i)"), + REG_NATIVE_FUNC(abortStackOverflow, "(i)"), + REG_NATIVE_FUNC(nullFunc_X, "(i)"), + REG_NATIVE_FUNC(__cxa_allocate_exception, "(i)i"), + REG_NATIVE_FUNC(__cxa_begin_catch, "(*)"), + REG_NATIVE_FUNC(__cxa_throw, "(**i)"), + REG_NATIVE_FUNC(clock_gettime, "(i*)i"), + REG_NATIVE_FUNC(clock, "()I"), +}; + +#if WASM_ENABLE_SPEC_TEST != 0 +static NativeSymbol native_symbols_spectest[] = { + REG_NATIVE_FUNC(print, "()"), + REG_NATIVE_FUNC(print_i32, "(i)"), + REG_NATIVE_FUNC(print_i32_f32, "(if)"), + REG_NATIVE_FUNC(print_f64_f64, "(FF)"), + REG_NATIVE_FUNC(print_f32, "(f)"), + REG_NATIVE_FUNC(print_f64, "(F)") +}; +#endif + +uint32 +get_libc_builtin_export_apis(NativeSymbol **p_libc_builtin_apis) +{ + *p_libc_builtin_apis = native_symbols_libc_builtin; + return sizeof(native_symbols_libc_builtin) / sizeof(NativeSymbol); +} + +#if WASM_ENABLE_SPEC_TEST != 0 +uint32 +get_spectest_export_apis(NativeSymbol **p_libc_builtin_apis) +{ + *p_libc_builtin_apis = native_symbols_spectest; + return sizeof(native_symbols_spectest) / sizeof(NativeSymbol); +} +#endif + +/************************************* + * Global Variables * + *************************************/ + +typedef struct WASMNativeGlobalDef { + const char *module_name; + const char *global_name; + uint8 type; + bool is_mutable; + WASMValue value; +} WASMNativeGlobalDef; + +static WASMNativeGlobalDef native_global_defs[] = { +#if WASM_ENABLE_SPEC_TEST != 0 + { "spectest", "global_i32", VALUE_TYPE_I32, false, .value.i32 = 666 }, + { "spectest", "global_i64", VALUE_TYPE_I64, false, .value.i64 = 666 }, + { "spectest", "global_f32", VALUE_TYPE_F32, false, .value.f32 = 666.6 }, + { "spectest", "global_f64", VALUE_TYPE_F64, false, .value.f64 = 666.6 }, + { "test", "global-i32", VALUE_TYPE_I32, false, .value.i32 = 0 }, + { "test", "global-f32", VALUE_TYPE_F32, false, .value.f32 = 0 }, + { "test", "global-mut-i32", VALUE_TYPE_I32, true, .value.i32 = 0 }, + { "test", "global-mut-i64", VALUE_TYPE_I64, true, .value.i64 = 0 }, +#endif + { "global", "NaN", VALUE_TYPE_F64, .value.u64 = 0x7FF8000000000000LL }, + { "global", "Infinity", VALUE_TYPE_F64, .value.u64 = 0x7FF0000000000000LL } +}; + +bool +wasm_native_lookup_libc_builtin_global(const char *module_name, + const char *global_name, + WASMGlobalImport *global) +{ + uint32 size = sizeof(native_global_defs) / sizeof(WASMNativeGlobalDef); + WASMNativeGlobalDef *global_def = native_global_defs; + WASMNativeGlobalDef *global_def_end = global_def + size; + + if (!module_name || !global_name || !global) + return false; + + /* Lookup constant globals which can be defined by table */ + while (global_def < global_def_end) { + if (!strcmp(global_def->module_name, module_name) + && !strcmp(global_def->global_name, global_name)) { + global->type = global_def->type; + global->is_mutable = global_def->is_mutable; + global->global_data_linked = global_def->value; + return true; + } + global_def++; + } + + return false; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-emcc/SConscript b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-emcc/SConscript new file mode 100644 index 000000000..432ed4a05 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-emcc/SConscript @@ -0,0 +1,19 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * + +cwd = GetCurrentDir() + +src = Split(''' +libc_emcc_wrapper.c +''') + +CPPPATH = [cwd] + +group = DefineGroup('iwasm_libc_emcc', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-emcc/libc_emcc.cmake b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-emcc/libc_emcc.cmake new file mode 100644 index 000000000..d237a16ee --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-emcc/libc_emcc.cmake @@ -0,0 +1,12 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (LIBC_EMCC_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions (-DWASM_ENABLE_LIBC_EMCC=1) + +include_directories(${LIBC_EMCC_DIR}) + +file (GLOB source_all ${LIBC_EMCC_DIR}/*.c) + +set (LIBC_EMCC_SOURCE ${source_all})
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c new file mode 100644 index 000000000..23c02aad3 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c @@ -0,0 +1,554 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_common.h" +#include "bh_log.h" +#include "wasm_export.h" +#include "../interpreter/wasm.h" +#if !defined(_DEFAULT_SOURCE) && !defined(BH_PLATFORM_LINUX_SGX) +#include "sys/syscall.h" +#endif + +/* clang-format off */ +#define get_module_inst(exec_env) \ + wasm_runtime_get_module_inst(exec_env) + +#define validate_app_addr(offset, size) \ + wasm_runtime_validate_app_addr(module_inst, offset, size) + +#define validate_app_str_addr(offset) \ + wasm_runtime_validate_app_str_addr(module_inst, offset) + +#define validate_native_addr(addr, size) \ + wasm_runtime_validate_native_addr(module_inst, addr, size) + +#define addr_app_to_native(offset) \ + wasm_runtime_addr_app_to_native(module_inst, offset) + +#define addr_native_to_app(ptr) \ + wasm_runtime_addr_native_to_app(module_inst, ptr) + +#define module_malloc(size, p_native_addr) \ + wasm_runtime_module_malloc(module_inst, size, p_native_addr) + +#define module_free(offset) \ + wasm_runtime_module_free(module_inst, offset) +/* clang-format on */ + +static void +invoke_viiii_wrapper(wasm_exec_env_t exec_env, uint32 elem_idx, int arg0, + int arg1, int arg2, int arg3) +{ + uint32 argv[4]; + bool ret; + + argv[0] = arg0; + argv[1] = arg1; + argv[2] = arg2; + argv[3] = arg3; + ret = wasm_runtime_call_indirect(exec_env, elem_idx, 4, argv); + (void)ret; +} + +static void +invoke_viii_wrapper(wasm_exec_env_t exec_env, uint32 elem_idx, int arg0, + int arg1, int arg2) +{ + uint32 argv[4]; + bool ret; + + argv[0] = arg0; + argv[1] = arg1; + argv[2] = arg2; + ret = wasm_runtime_call_indirect(exec_env, elem_idx, 3, argv); + (void)ret; +} + +static void +invoke_vii_wrapper(wasm_exec_env_t exec_env, uint32 elem_idx, int arg0, + int arg1) +{ + uint32 argv[4]; + bool ret; + + argv[0] = arg0; + argv[1] = arg1; + ret = wasm_runtime_call_indirect(exec_env, elem_idx, 2, argv); + (void)ret; +} + +static void +invoke_vi_wrapper(wasm_exec_env_t exec_env, uint32 elem_idx, int arg0) +{ + uint32 argv[4]; + bool ret; + + argv[0] = arg0; + ret = wasm_runtime_call_indirect(exec_env, elem_idx, 1, argv); + (void)ret; +} + +static int +invoke_iii_wrapper(wasm_exec_env_t exec_env, uint32 elem_idx, int arg0, + int arg1) +{ + uint32 argv[4]; + bool ret; + + argv[0] = arg0; + argv[1] = arg1; + ret = wasm_runtime_call_indirect(exec_env, elem_idx, 2, argv); + return ret ? argv[0] : 0; +} + +static int +invoke_ii_wrapper(wasm_exec_env_t exec_env, uint32 elem_idx, int arg0) +{ + uint32 argv[4]; + bool ret; + + argv[0] = arg0; + ret = wasm_runtime_call_indirect(exec_env, elem_idx, 1, argv); + return ret ? argv[0] : 0; +} + +struct timespec_emcc { + int tv_sec; + int tv_nsec; +}; + +struct stat_emcc { + unsigned st_dev; + int __st_dev_padding; + unsigned __st_ino_truncated; + unsigned st_mode; + unsigned st_nlink; + unsigned st_uid; + unsigned st_gid; + unsigned st_rdev; + int __st_rdev_padding; + int64 st_size; + int st_blksize; + int st_blocks; + struct timespec_emcc st_atim; + struct timespec_emcc st_mtim; + struct timespec_emcc st_ctim; + int64 st_ino; +}; + +static int +open_wrapper(wasm_exec_env_t exec_env, const char *pathname, int flags, + int mode) +{ + if (pathname == NULL) + return -1; + return open(pathname, flags, mode); +} + +static int +__sys_read_wrapper(wasm_exec_env_t exec_env, int fd, void *buf, uint32 count) +{ + return read(fd, buf, count); +} + +static void +statbuf_native2app(const struct stat *statbuf_native, + struct stat_emcc *statbuf_app) +{ + statbuf_app->st_dev = (unsigned)statbuf_native->st_dev; + statbuf_app->__st_ino_truncated = (unsigned)statbuf_native->st_ino; + statbuf_app->st_mode = (unsigned)statbuf_native->st_mode; + statbuf_app->st_nlink = (unsigned)statbuf_native->st_nlink; + statbuf_app->st_uid = (unsigned)statbuf_native->st_uid; + statbuf_app->st_gid = (unsigned)statbuf_native->st_gid; + statbuf_app->st_rdev = (unsigned)statbuf_native->st_rdev; + statbuf_app->st_size = (int64)statbuf_native->st_size; + statbuf_app->st_blksize = (unsigned)statbuf_native->st_blksize; + statbuf_app->st_blocks = (unsigned)statbuf_native->st_blocks; + statbuf_app->st_ino = (int64)statbuf_native->st_ino; + statbuf_app->st_atim.tv_sec = (int)statbuf_native->st_atim.tv_sec; + statbuf_app->st_atim.tv_nsec = (int)statbuf_native->st_atim.tv_nsec; + statbuf_app->st_mtim.tv_sec = (int)statbuf_native->st_mtim.tv_sec; + statbuf_app->st_mtim.tv_nsec = (int)statbuf_native->st_mtim.tv_nsec; + statbuf_app->st_ctim.tv_sec = (int)statbuf_native->st_ctim.tv_sec; + statbuf_app->st_ctim.tv_nsec = (int)statbuf_native->st_ctim.tv_nsec; +} + +static int +__sys_stat64_wrapper(wasm_exec_env_t exec_env, const char *pathname, + struct stat_emcc *statbuf_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + int ret; + struct stat statbuf; + + if (!validate_native_addr((void *)statbuf_app, sizeof(struct stat_emcc))) + return -1; + + if (pathname == NULL) + return -1; + + ret = stat(pathname, &statbuf); + if (ret == 0) + statbuf_native2app(&statbuf, statbuf_app); + return ret; +} + +static int +__sys_fstat64_wrapper(wasm_exec_env_t exec_env, int fd, + struct stat_emcc *statbuf_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + int ret; + struct stat statbuf; + + if (!validate_native_addr((void *)statbuf_app, sizeof(struct stat_emcc))) + return -1; + + if (fd <= 0) + return -1; + + ret = fstat(fd, &statbuf); + if (ret == 0) + statbuf_native2app(&statbuf, statbuf_app); + return ret; +} + +static int +mmap_wrapper(wasm_exec_env_t exec_env, void *addr, int length, int prot, + int flags, int fd, int64 offset) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uint32 buf_offset; + char *buf; + int size_read; + + buf_offset = module_malloc(length, (void **)&buf); + if (buf_offset == 0) + return -1; + + if (fd <= 0) + return -1; + + if (lseek(fd, offset, SEEK_SET) == -1) + return -1; + + size_read = read(fd, buf, length); + (void)size_read; + return buf_offset; +} + +static int +munmap_wrapper(wasm_exec_env_t exec_env, uint32 buf_offset, int length) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + module_free(buf_offset); + return 0; +} + +static int +__munmap_wrapper(wasm_exec_env_t exec_env, uint32 buf_offset, int length) +{ + return munmap_wrapper(exec_env, buf_offset, length); +} + +static int +getentropy_wrapper(wasm_exec_env_t exec_env, void *buffer, uint32 length) +{ + if (buffer == NULL) + return -1; +#if defined(_DEFAULT_SOURCE) || defined(BH_PLATFORM_LINUX_SGX) + return getentropy(buffer, length); +#else + return syscall(SYS_getrandom, buffer, length, 0); +#endif +} + +static int +setjmp_wrapper(wasm_exec_env_t exec_env, void *jmp_buf) +{ + os_printf("setjmp() called\n"); + return 0; +} + +static void +longjmp_wrapper(wasm_exec_env_t exec_env, void *jmp_buf, int val) +{ + os_printf("longjmp() called\n"); +} + +#if !defined(BH_PLATFORM_LINUX_SGX) +static FILE *file_list[32] = { 0 }; + +static int +get_free_file_slot() +{ + unsigned int i; + + for (i = 0; i < sizeof(file_list) / sizeof(FILE *); i++) { + if (file_list[i] == NULL) + return (int)i; + } + return -1; +} + +static int +fopen_wrapper(wasm_exec_env_t exec_env, const char *pathname, const char *mode) +{ + FILE *file; + int file_id; + + if (pathname == NULL || mode == NULL) + return 0; + + if ((file_id = get_free_file_slot()) == -1) + return 0; + + file = fopen(pathname, mode); + if (!file) + return 0; + + file_list[file_id] = file; + return file_id + 1; +} + +static uint32 +fread_wrapper(wasm_exec_env_t exec_env, void *ptr, uint32 size, uint32 nmemb, + int file_id) +{ + FILE *file; + + file_id = file_id - 1; + if ((unsigned)file_id >= sizeof(file_list) / sizeof(FILE *)) { + return 0; + } + if ((file = file_list[file_id]) == NULL) { + return 0; + } + return (uint32)fread(ptr, size, nmemb, file); +} + +static int +fseeko_wrapper(wasm_exec_env_t exec_env, int file_id, int64 offset, int whence) +{ + FILE *file; + + file_id = file_id - 1; + if ((unsigned)file_id >= sizeof(file_list) / sizeof(FILE *)) { + return -1; + } + if ((file = file_list[file_id]) == NULL) { + return -1; + } + return (uint32)fseek(file, offset, whence); +} + +static uint32 +emcc_fwrite_wrapper(wasm_exec_env_t exec_env, const void *ptr, uint32 size, + uint32 nmemb, int file_id) +{ + FILE *file; + + file_id = file_id - 1; + if ((unsigned)file_id >= sizeof(file_list) / sizeof(FILE *)) { + return 0; + } + if ((file = file_list[file_id]) == NULL) { + return 0; + } + return (uint32)fwrite(ptr, size, nmemb, file); +} + +static int +feof_wrapper(wasm_exec_env_t exec_env, int file_id) +{ + FILE *file; + + file_id = file_id - 1; + if ((unsigned)file_id >= sizeof(file_list) / sizeof(FILE *)) + return 1; + if ((file = file_list[file_id]) == NULL) + return 1; + return feof(file); +} + +static int +fclose_wrapper(wasm_exec_env_t exec_env, int file_id) +{ + FILE *file; + + file_id = file_id - 1; + if ((unsigned)file_id >= sizeof(file_list) / sizeof(FILE *)) + return -1; + if ((file = file_list[file_id]) == NULL) + return -1; + file_list[file_id] = NULL; + return fclose(file); +} + +static int +__sys_mkdir_wrapper(wasm_exec_env_t exec_env, const char *pathname, int mode) +{ + if (!pathname) + return -1; + return mkdir(pathname, mode); +} + +static int +__sys_rmdir_wrapper(wasm_exec_env_t exec_env, const char *pathname) +{ + if (!pathname) + return -1; + return rmdir(pathname); +} + +static int +__sys_unlink_wrapper(wasm_exec_env_t exec_env, const char *pathname) +{ + if (!pathname) + return -1; + return unlink(pathname); +} + +static uint32 +__sys_getcwd_wrapper(wasm_exec_env_t exec_env, char *buf, uint32 size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + char *ret; + + if (!buf) + return -1; + + ret = getcwd(buf, size); + return ret ? addr_native_to_app(ret) : 0; +} + +#include <sys/utsname.h> + +struct utsname_app { + char sysname[64]; + char nodename[64]; + char release[64]; + char version[64]; + char machine[64]; + char domainname[64]; +}; + +static int +__sys_uname_wrapper(wasm_exec_env_t exec_env, struct utsname_app *uname_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + struct utsname uname_native = { 0 }; + uint32 length; + + if (!validate_native_addr(uname_app, sizeof(struct utsname_app))) + return -1; + + if (uname(&uname_native) != 0) { + return -1; + } + + memset(uname_app, 0, sizeof(struct utsname_app)); + + length = strlen(uname_native.sysname); + if (length > sizeof(uname_app->sysname) - 1) + length = sizeof(uname_app->sysname) - 1; + bh_memcpy_s(uname_app->sysname, sizeof(uname_app->sysname), + uname_native.sysname, length); + + length = strlen(uname_native.nodename); + if (length > sizeof(uname_app->nodename) - 1) + length = sizeof(uname_app->nodename) - 1; + bh_memcpy_s(uname_app->nodename, sizeof(uname_app->nodename), + uname_native.nodename, length); + + length = strlen(uname_native.release); + if (length > sizeof(uname_app->release) - 1) + length = sizeof(uname_app->release) - 1; + bh_memcpy_s(uname_app->release, sizeof(uname_app->release), + uname_native.release, length); + + length = strlen(uname_native.version); + if (length > sizeof(uname_app->version) - 1) + length = sizeof(uname_app->version) - 1; + bh_memcpy_s(uname_app->version, sizeof(uname_app->version), + uname_native.version, length); + +#ifdef _GNU_SOURCE + length = strlen(uname_native.domainname); + if (length > sizeof(uname_app->domainname) - 1) + length = sizeof(uname_app->domainname) - 1; + bh_memcpy_s(uname_app->domainname, sizeof(uname_app->domainname), + uname_native.domainname, length); +#endif + + return 0; +} + +static void +emscripten_notify_memory_growth_wrapper(wasm_exec_env_t exec_env, int i) +{ + (void)i; +} + +static void +emscripten_thread_sleep_wrapper(wasm_exec_env_t exec_env, double timeout_ms) +{ + uint64 ms = (uint64)timeout_ms; + uint64 sec = ms / 1000, us = (ms % 1000) * 1000; + + if (sec > 0) + sleep(sec); + if (us > 0) + usleep(us); +} + +#endif /* end of BH_PLATFORM_LINUX_SGX */ + +/* clang-format off */ +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, func_name##_wrapper, signature, NULL } +/* clang-format off */ + +static NativeSymbol native_symbols_libc_emcc[] = { + REG_NATIVE_FUNC(invoke_viiii, "(iiiii)"), + REG_NATIVE_FUNC(invoke_viii, "(iiii)"), + REG_NATIVE_FUNC(invoke_vii, "(iii)"), + REG_NATIVE_FUNC(invoke_vi, "(ii)"), + REG_NATIVE_FUNC(invoke_iii, "(iii)i"), + REG_NATIVE_FUNC(invoke_ii, "(ii)i"), + REG_NATIVE_FUNC(open, "($ii)i"), + REG_NATIVE_FUNC(__sys_read, "(i*~)i"), + REG_NATIVE_FUNC(__sys_stat64, "($*)i"), + REG_NATIVE_FUNC(__sys_fstat64, "(i*)i"), + REG_NATIVE_FUNC(mmap, "(*iiiiI)i"), + REG_NATIVE_FUNC(munmap, "(ii)i"), + REG_NATIVE_FUNC(__munmap, "(ii)i"), + REG_NATIVE_FUNC(getentropy, "(*~)i"), + REG_NATIVE_FUNC(setjmp, "(*)i"), + REG_NATIVE_FUNC(longjmp, "(*i)"), +#if !defined(BH_PLATFORM_LINUX_SGX) + REG_NATIVE_FUNC(fopen, "($$)i"), + REG_NATIVE_FUNC(fread, "(*iii)i"), + REG_NATIVE_FUNC(fseeko, "(iIi)i"), + REG_NATIVE_FUNC(emcc_fwrite, "(*iii)i"), + REG_NATIVE_FUNC(feof, "(i)i"), + REG_NATIVE_FUNC(fclose, "(i)i"), + REG_NATIVE_FUNC(__sys_mkdir, "($i)i"), + REG_NATIVE_FUNC(__sys_rmdir, "($)i"), + REG_NATIVE_FUNC(__sys_unlink, "($)i"), + REG_NATIVE_FUNC(__sys_getcwd, "(*~)i"), + REG_NATIVE_FUNC(__sys_uname, "(*)i"), + REG_NATIVE_FUNC(emscripten_notify_memory_growth, "(i)"), + REG_NATIVE_FUNC(emscripten_thread_sleep, "(F)"), +#endif /* end of BH_PLATFORM_LINUX_SGX */ +}; + +uint32 +get_libc_emcc_export_apis(NativeSymbol **p_libc_emcc_apis) +{ + *p_libc_emcc_apis = native_symbols_libc_emcc; + return sizeof(native_symbols_libc_emcc) / sizeof(NativeSymbol); +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/LICENSE_LIBUV b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/LICENSE_LIBUV new file mode 100644 index 000000000..eb126dab3 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/LICENSE_LIBUV @@ -0,0 +1,66 @@ +libuv is licensed for use as follows: + +==== +Copyright (c) 2015-present libuv project contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. +==== + +This license applies to parts of libuv originating from the +https://github.com/joyent/libuv repository: + +==== + +Copyright Joyent, Inc. and other Node contributors. All rights reserved. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + +==== + +This license applies to all parts of libuv that are not externally +maintained libraries. + +The externally maintained libraries used by libuv are: + + - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license. + + - inet_pton and inet_ntop implementations, contained in src/inet.c, are + copyright the Internet Systems Consortium, Inc., and licensed under the ISC + license. + + - stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three + clause BSD license. + + - pthread-fixes.c, copyright Google Inc. and Sony Mobile Communications AB. + Three clause BSD license. diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/LICENSE_UVWASI b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/LICENSE_UVWASI new file mode 100644 index 000000000..dfb8546af --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/LICENSE_UVWASI @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Colin Ihrig and Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake new file mode 100644 index 000000000..e0c8afa21 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake @@ -0,0 +1,44 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (LIBC_WASI_DIR ${CMAKE_CURRENT_LIST_DIR}) + +set (LIBUV_VERSION v1.44.2) + +add_definitions (-DWASM_ENABLE_LIBC_WASI=1 -DWASM_ENABLE_UVWASI=1) + +include(FetchContent) + +## libuv +FetchContent_Declare( + libuv + GIT_REPOSITORY https://github.com/libuv/libuv.git + GIT_TAG ${LIBUV_VERSION} +) +FetchContent_GetProperties(libuv) +if (NOT libuv_POPULATED) + message("-- Fetching libuv ..") + FetchContent_Populate(libuv) + include_directories("${libuv_SOURCE_DIR}/include") + add_subdirectory(${libuv_SOURCE_DIR} ${libuv_BINARY_DIR} EXCLUDE_FROM_ALL) + set (UV_A_LIBS uv_a) + set_target_properties(uv_a PROPERTIES POSITION_INDEPENDENT_CODE 1) +endif() + +## uvwasi +FetchContent_Declare( + uvwasi + GIT_REPOSITORY https://github.com/nodejs/uvwasi.git + GIT_TAG main +) +FetchContent_GetProperties(uvwasi) +if (NOT uvwasi_POPULATED) + message("-- Fetching uvwasi ..") + FetchContent_Populate(uvwasi) + include_directories("${uvwasi_SOURCE_DIR}/include") + add_subdirectory(${uvwasi_SOURCE_DIR} ${uvwasi_BINARY_DIR} EXCLUDE_FROM_ALL) +endif() + +file (GLOB_RECURSE source_all ${LIBC_WASI_DIR}/*.c ${uvwasi_SOURCE_DIR}/src/*.c) + +set (LIBC_WASI_SOURCE ${source_all}) diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c new file mode 100644 index 000000000..504ff7f93 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c @@ -0,0 +1,1150 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "uvwasi.h" +#include "bh_platform.h" +#include "wasm_export.h" + +/* clang-format off */ +#define get_module_inst(exec_env) \ + wasm_runtime_get_module_inst(exec_env) + +#define validate_app_addr(offset, size) \ + wasm_runtime_validate_app_addr(module_inst, offset, size) + +#define validate_native_addr(addr, size) \ + wasm_runtime_validate_native_addr(module_inst, addr, size) + +#define addr_app_to_native(offset) \ + wasm_runtime_addr_app_to_native(module_inst, offset) + +#define addr_native_to_app(ptr) \ + wasm_runtime_addr_native_to_app(module_inst, ptr) + +#define module_malloc(size, p_native_addr) \ + wasm_runtime_module_malloc(module_inst, size, p_native_addr) + +#define module_free(offset) \ + wasm_runtime_module_free(module_inst, offset) +/* clang-format on */ + +#define wasi_errno_t uvwasi_errno_t +#define wasi_fd_t uvwasi_fd_t +#define wasi_clockid_t uvwasi_clockid_t +#define wasi_timestamp_t uvwasi_timestamp_t +#define wasi_filesize_t uvwasi_filesize_t +#define wasi_prestat_app_t uvwasi_prestat_app_t +#define wasi_filedelta_t uvwasi_filedelta_t +#define wasi_whence_t uvwasi_whence_t +#define wasi_fdflags_t uvwasi_fdflags_t +#define wasi_rights_t uvwasi_rights_t +#define wasi_advice_t uvwasi_advice_t +#define wasi_lookupflags_t uvwasi_lookupflags_t +#define wasi_preopentype_t uvwasi_preopentype_t +#define wasi_fdstat_t uvwasi_fdstat_t +#define wasi_oflags_t uvwasi_oflags_t +#define wasi_dircookie_t uvwasi_dircookie_t +#define wasi_filestat_t uvwasi_filestat_t +#define wasi_fstflags_t uvwasi_fstflags_t +#define wasi_subscription_t uvwasi_subscription_t +#define wasi_event_t uvwasi_event_t +#define wasi_exitcode_t uvwasi_exitcode_t +#define wasi_signal_t uvwasi_signal_t +#define wasi_riflags_t uvwasi_riflags_t +#define wasi_roflags_t uvwasi_roflags_t +#define wasi_siflags_t uvwasi_siflags_t +#define wasi_sdflags_t uvwasi_sdflags_t +#define wasi_iovec_t uvwasi_iovec_t +#define wasi_ciovec_t uvwasi_ciovec_t + +typedef struct wasi_prestat_app { + wasi_preopentype_t pr_type; + uint32 pr_name_len; +} wasi_prestat_app_t; + +typedef struct iovec_app { + uint32 buf_offset; + uint32 buf_len; +} iovec_app_t; + +typedef struct WASIContext { + uvwasi_t uvwasi; + uint32_t exit_code; +} WASIContext; + +void * +wasm_runtime_get_wasi_ctx(wasm_module_inst_t module_inst); + +static uvwasi_t * +get_wasi_ctx(wasm_module_inst_t module_inst) +{ + WASIContext *ctx = wasm_runtime_get_wasi_ctx(module_inst); + if (ctx == NULL) { + return NULL; + } + return &ctx->uvwasi; +} + +static wasi_errno_t +wasi_args_get(wasm_exec_env_t exec_env, uint32 *argv_offsets, char *argv_buf) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + uvwasi_size_t argc, argv_buf_size, i; + char **argv; + uint64 total_size; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + err = uvwasi_args_sizes_get(uvwasi, &argc, &argv_buf_size); + if (err) + return err; + + total_size = sizeof(int32) * ((uint64)argc + 1); + if (total_size >= UINT32_MAX + || !validate_native_addr(argv_offsets, (uint32)total_size) + || argv_buf_size >= UINT32_MAX + || !validate_native_addr(argv_buf, (uint32)argv_buf_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(char *) * ((uint64)argc + 1); + if (total_size >= UINT32_MAX + || !(argv = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + err = uvwasi_args_get(uvwasi, argv, argv_buf); + if (err) { + wasm_runtime_free(argv); + return err; + } + + for (i = 0; i < argc; i++) + argv_offsets[i] = addr_native_to_app(argv[i]); + + wasm_runtime_free(argv); + return 0; +} + +static wasi_errno_t +wasi_args_sizes_get(wasm_exec_env_t exec_env, uint32 *argc_app, + uint32 *argv_buf_size_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + uvwasi_size_t argc, argv_buf_size; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(argc_app, sizeof(uint32)) + || !validate_native_addr(argv_buf_size_app, sizeof(uint32))) + return (wasi_errno_t)-1; + + err = uvwasi_args_sizes_get(uvwasi, &argc, &argv_buf_size); + if (err) + return err; + + *argc_app = (uint32)argc; + *argv_buf_size_app = (uint32)argv_buf_size; + return 0; +} + +static wasi_errno_t +wasi_clock_res_get(wasm_exec_env_t exec_env, wasi_clockid_t clock_id, + wasi_timestamp_t *resolution) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!validate_native_addr(resolution, sizeof(wasi_timestamp_t))) + return (wasi_errno_t)-1; + + return uvwasi_clock_res_get(uvwasi, clock_id, resolution); +} + +static wasi_errno_t +wasi_clock_time_get(wasm_exec_env_t exec_env, wasi_clockid_t clock_id, + wasi_timestamp_t precision, wasi_timestamp_t *time) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!validate_native_addr(time, sizeof(wasi_timestamp_t))) + return (wasi_errno_t)-1; + + return uvwasi_clock_time_get(uvwasi, clock_id, precision, time); +} + +static wasi_errno_t +wasi_environ_get(wasm_exec_env_t exec_env, uint32 *environ_offsets, + char *environ_buf) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + uvwasi_size_t environ_count, environ_buf_size, i; + uint64 total_size; + char **environs; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + err = uvwasi_environ_sizes_get(uvwasi, &environ_count, &environ_buf_size); + if (err) + return err; + + if (environ_count == 0) + return 0; + + total_size = sizeof(int32) * ((uint64)environ_count + 1); + if (total_size >= UINT32_MAX + || !validate_native_addr(environ_offsets, (uint32)total_size) + || environ_buf_size >= UINT32_MAX + || !validate_native_addr(environ_buf, (uint32)environ_buf_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(char *) * (((uint64)environ_count + 1)); + + if (total_size >= UINT32_MAX + || !(environs = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + err = uvwasi_environ_get(uvwasi, environs, environ_buf); + if (err) { + wasm_runtime_free(environs); + return err; + } + + for (i = 0; i < environ_count; i++) + environ_offsets[i] = addr_native_to_app(environs[i]); + + wasm_runtime_free(environs); + return 0; +} + +static wasi_errno_t +wasi_environ_sizes_get(wasm_exec_env_t exec_env, uint32 *environ_count_app, + uint32 *environ_buf_size_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + uvwasi_size_t environ_count, environ_buf_size; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(environ_count_app, sizeof(uint32)) + || !validate_native_addr(environ_buf_size_app, sizeof(uint32))) + return (wasi_errno_t)-1; + + err = uvwasi_environ_sizes_get(uvwasi, &environ_count, &environ_buf_size); + if (err) + return err; + + *environ_count_app = (uint32)environ_count; + *environ_buf_size_app = (uint32)environ_buf_size; + return 0; +} + +static wasi_errno_t +wasi_fd_prestat_get(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_prestat_app_t *prestat_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + uvwasi_prestat_t prestat; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(prestat_app, sizeof(wasi_prestat_app_t))) + return (wasi_errno_t)-1; + + err = uvwasi_fd_prestat_get(uvwasi, fd, &prestat); + if (err) + return err; + + prestat_app->pr_type = prestat.pr_type; + prestat_app->pr_name_len = (uint32)prestat.u.dir.pr_name_len; + return 0; +} + +static wasi_errno_t +wasi_fd_prestat_dir_name(wasm_exec_env_t exec_env, wasi_fd_t fd, char *path, + uint32 path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_prestat_dir_name(uvwasi, fd, path, path_len); +} + +static wasi_errno_t +wasi_fd_close(wasm_exec_env_t exec_env, wasi_fd_t fd) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_close(uvwasi, fd); +} + +static wasi_errno_t +wasi_fd_datasync(wasm_exec_env_t exec_env, wasi_fd_t fd) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_datasync(uvwasi, fd); +} + +static wasi_errno_t +wasi_fd_pread(wasm_exec_env_t exec_env, wasi_fd_t fd, iovec_app_t *iovec_app, + uint32 iovs_len, wasi_filesize_t offset, uint32 *nread_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + wasi_iovec_t *iovec, *iovec_begin; + uint64 total_size; + uvwasi_size_t nread; + uint32 i; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + total_size = sizeof(iovec_app_t) * (uint64)iovs_len; + if (!validate_native_addr(nread_app, (uint32)sizeof(uint32)) + || total_size >= UINT32_MAX + || !validate_native_addr(iovec_app, (uint32)total_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(wasi_iovec_t) * (uint64)iovs_len; + if (total_size >= UINT32_MAX + || !(iovec_begin = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + iovec = iovec_begin; + for (i = 0; i < iovs_len; i++, iovec_app++, iovec++) { + if (!validate_app_addr(iovec_app->buf_offset, iovec_app->buf_len)) { + err = (wasi_errno_t)-1; + goto fail; + } + iovec->buf = (void *)addr_app_to_native(iovec_app->buf_offset); + iovec->buf_len = iovec_app->buf_len; + } + + err = uvwasi_fd_pread(uvwasi, fd, iovec_begin, iovs_len, offset, &nread); + if (err) + goto fail; + + *nread_app = (uint32)nread; + + /* success */ + err = 0; + +fail: + wasm_runtime_free(iovec_begin); + return err; +} + +static wasi_errno_t +wasi_fd_pwrite(wasm_exec_env_t exec_env, wasi_fd_t fd, + const iovec_app_t *iovec_app, uint32 iovs_len, + wasi_filesize_t offset, uint32 *nwritten_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + wasi_ciovec_t *ciovec, *ciovec_begin; + uint64 total_size; + uvwasi_size_t nwritten; + uint32 i; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + total_size = sizeof(iovec_app_t) * (uint64)iovs_len; + if (!validate_native_addr(nwritten_app, (uint32)sizeof(uint32)) + || total_size >= UINT32_MAX + || !validate_native_addr((void *)iovec_app, (uint32)total_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(wasi_ciovec_t) * (uint64)iovs_len; + if (total_size >= UINT32_MAX + || !(ciovec_begin = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + ciovec = ciovec_begin; + for (i = 0; i < iovs_len; i++, iovec_app++, ciovec++) { + if (!validate_app_addr(iovec_app->buf_offset, iovec_app->buf_len)) { + err = (wasi_errno_t)-1; + goto fail; + } + ciovec->buf = (char *)addr_app_to_native(iovec_app->buf_offset); + ciovec->buf_len = iovec_app->buf_len; + } + + err = + uvwasi_fd_pwrite(uvwasi, fd, ciovec_begin, iovs_len, offset, &nwritten); + if (err) + goto fail; + + *nwritten_app = (uint32)nwritten; + + /* success */ + err = 0; + +fail: + wasm_runtime_free(ciovec_begin); + return err; +} + +static wasi_errno_t +wasi_fd_read(wasm_exec_env_t exec_env, wasi_fd_t fd, + const iovec_app_t *iovec_app, uint32 iovs_len, uint32 *nread_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + wasi_iovec_t *iovec, *iovec_begin; + uint64 total_size; + uvwasi_size_t nread; + uint32 i; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + total_size = sizeof(iovec_app_t) * (uint64)iovs_len; + if (!validate_native_addr(nread_app, (uint32)sizeof(uint32)) + || total_size >= UINT32_MAX + || !validate_native_addr((void *)iovec_app, (uint32)total_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(wasi_iovec_t) * (uint64)iovs_len; + if (total_size >= UINT32_MAX + || !(iovec_begin = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + iovec = iovec_begin; + for (i = 0; i < iovs_len; i++, iovec_app++, iovec++) { + if (!validate_app_addr(iovec_app->buf_offset, iovec_app->buf_len)) { + err = (wasi_errno_t)-1; + goto fail; + } + iovec->buf = (void *)addr_app_to_native(iovec_app->buf_offset); + iovec->buf_len = iovec_app->buf_len; + } + + err = uvwasi_fd_read(uvwasi, fd, iovec_begin, iovs_len, &nread); + if (err) + goto fail; + + *nread_app = (uint32)nread; + + /* success */ + err = 0; + +fail: + wasm_runtime_free(iovec_begin); + return err; +} + +static wasi_errno_t +wasi_fd_renumber(wasm_exec_env_t exec_env, wasi_fd_t from, wasi_fd_t to) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_renumber(uvwasi, from, to); +} + +static wasi_errno_t +wasi_fd_seek(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_filedelta_t offset, + wasi_whence_t whence, wasi_filesize_t *newoffset) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(newoffset, sizeof(wasi_filesize_t))) + return (wasi_errno_t)-1; + + return uvwasi_fd_seek(uvwasi, fd, offset, whence, newoffset); +} + +static wasi_errno_t +wasi_fd_tell(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_filesize_t *newoffset) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(newoffset, sizeof(wasi_filesize_t))) + return (wasi_errno_t)-1; + + return uvwasi_fd_tell(uvwasi, fd, newoffset); +} + +static wasi_errno_t +wasi_fd_fdstat_get(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_fdstat_t *fdstat_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + wasi_fdstat_t fdstat; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(fdstat_app, sizeof(wasi_fdstat_t))) + return (wasi_errno_t)-1; + + err = uvwasi_fd_fdstat_get(uvwasi, fd, &fdstat); + if (err) + return err; + + memcpy(fdstat_app, &fdstat, sizeof(wasi_fdstat_t)); + return 0; +} + +static wasi_errno_t +wasi_fd_fdstat_set_flags(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_fdflags_t flags) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_fdstat_set_flags(uvwasi, fd, flags); +} + +static wasi_errno_t +wasi_fd_fdstat_set_rights(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_rights_t fs_rights_base, + wasi_rights_t fs_rights_inheriting) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_fdstat_set_rights(uvwasi, fd, fs_rights_base, + fs_rights_inheriting); +} + +static wasi_errno_t +wasi_fd_sync(wasm_exec_env_t exec_env, wasi_fd_t fd) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_sync(uvwasi, fd); +} + +static wasi_errno_t +wasi_fd_write(wasm_exec_env_t exec_env, wasi_fd_t fd, + const iovec_app_t *iovec_app, uint32 iovs_len, + uint32 *nwritten_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + wasi_ciovec_t *ciovec, *ciovec_begin; + uint64 total_size; + uvwasi_size_t nwritten; + uint32 i; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + total_size = sizeof(iovec_app_t) * (uint64)iovs_len; + if (!validate_native_addr(nwritten_app, (uint32)sizeof(uint32)) + || total_size >= UINT32_MAX + || !validate_native_addr((void *)iovec_app, (uint32)total_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(wasi_ciovec_t) * (uint64)iovs_len; + if (total_size >= UINT32_MAX + || !(ciovec_begin = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + ciovec = ciovec_begin; + for (i = 0; i < iovs_len; i++, iovec_app++, ciovec++) { + if (!validate_app_addr(iovec_app->buf_offset, iovec_app->buf_len)) { + err = (wasi_errno_t)-1; + goto fail; + } + ciovec->buf = (char *)addr_app_to_native(iovec_app->buf_offset); + ciovec->buf_len = iovec_app->buf_len; + } + +#ifndef BH_VPRINTF + err = uvwasi_fd_write(uvwasi, fd, ciovec_begin, iovs_len, &nwritten); +#else + /* redirect stdout/stderr output to BH_VPRINTF function */ + if (fd == 1 || fd == 2) { + int i; + const struct iovec *iov1 = (const struct iovec *)ciovec_begin; + + nwritten = 0; + for (i = 0; i < (int)iovs_len; i++, iov1++) { + if (iov1->iov_len > 0 && iov1->iov_base) { + char format[16]; + + /* make up format string "%.ns" */ + snprintf(format, sizeof(format), "%%.%ds", (int)iov1->iov_len); + nwritten += (uvwasi_size_t)os_printf(format, iov1->iov_base); + } + } + err = 0; + } + else { + err = uvwasi_fd_write(uvwasi, fd, ciovec_begin, iovs_len, &nwritten); + } +#endif /* end of BH_VPRINTF */ + + if (err) + goto fail; + + *nwritten_app = (uint32)nwritten; + + /* success */ + err = 0; + +fail: + wasm_runtime_free(ciovec_begin); + return err; +} + +static wasi_errno_t +wasi_fd_advise(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_filesize_t offset, + wasi_filesize_t len, wasi_advice_t advice) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_advise(uvwasi, fd, offset, len, advice); +} + +static wasi_errno_t +wasi_fd_allocate(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_filesize_t offset, + wasi_filesize_t len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_allocate(uvwasi, fd, offset, len); +} + +static wasi_errno_t +wasi_path_create_directory(wasm_exec_env_t exec_env, wasi_fd_t fd, + const char *path, uint32 path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_path_create_directory(uvwasi, fd, path, path_len); +} + +static wasi_errno_t +wasi_path_link(wasm_exec_env_t exec_env, wasi_fd_t old_fd, + wasi_lookupflags_t old_flags, const char *old_path, + uint32 old_path_len, wasi_fd_t new_fd, const char *new_path, + uint32 new_path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_path_link(uvwasi, old_fd, old_flags, old_path, old_path_len, + new_fd, new_path, new_path_len); +} + +static wasi_errno_t +wasi_path_open(wasm_exec_env_t exec_env, wasi_fd_t dirfd, + wasi_lookupflags_t dirflags, const char *path, uint32 path_len, + wasi_oflags_t oflags, wasi_rights_t fs_rights_base, + wasi_rights_t fs_rights_inheriting, wasi_fdflags_t fs_flags, + wasi_fd_t *fd_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + wasi_fd_t fd = (wasi_fd_t)-1; /* set fd_app -1 if path open failed */ + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(fd_app, sizeof(wasi_fd_t))) + return (wasi_errno_t)-1; + + err = uvwasi_path_open(uvwasi, dirfd, dirflags, path, path_len, oflags, + fs_rights_base, fs_rights_inheriting, fs_flags, &fd); + + *fd_app = fd; + return err; +} + +static wasi_errno_t +wasi_fd_readdir(wasm_exec_env_t exec_env, wasi_fd_t fd, void *buf, + uint32 buf_len, wasi_dircookie_t cookie, uint32 *bufused_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + uvwasi_size_t bufused; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(bufused_app, sizeof(uint32))) + return (wasi_errno_t)-1; + + err = uvwasi_fd_readdir(uvwasi, fd, buf, buf_len, cookie, &bufused); + if (err) + return err; + + *bufused_app = (uint32)bufused; + return 0; +} + +static wasi_errno_t +wasi_path_readlink(wasm_exec_env_t exec_env, wasi_fd_t fd, const char *path, + uint32 path_len, char *buf, uint32 buf_len, + uint32 *bufused_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + uvwasi_size_t bufused; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(bufused_app, sizeof(uint32))) + return (wasi_errno_t)-1; + + err = uvwasi_path_readlink(uvwasi, fd, path, path_len, buf, buf_len, + &bufused); + if (err) + return err; + + *bufused_app = (uint32)bufused; + return 0; +} + +static wasi_errno_t +wasi_path_rename(wasm_exec_env_t exec_env, wasi_fd_t old_fd, + const char *old_path, uint32 old_path_len, wasi_fd_t new_fd, + const char *new_path, uint32 new_path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_path_rename(uvwasi, old_fd, old_path, old_path_len, new_fd, + new_path, new_path_len); +} + +static wasi_errno_t +wasi_fd_filestat_get(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_filestat_t *filestat) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(filestat, sizeof(wasi_filestat_t))) + return (wasi_errno_t)-1; + + return uvwasi_fd_filestat_get(uvwasi, fd, filestat); +} + +static wasi_errno_t +wasi_fd_filestat_set_times(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_timestamp_t st_atim, wasi_timestamp_t st_mtim, + wasi_fstflags_t fstflags) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_filestat_set_times(uvwasi, fd, st_atim, st_mtim, fstflags); +} + +static wasi_errno_t +wasi_fd_filestat_set_size(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_filesize_t st_size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_fd_filestat_set_size(uvwasi, fd, st_size); +} + +static wasi_errno_t +wasi_path_filestat_get(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_lookupflags_t flags, const char *path, + uint32 path_len, wasi_filestat_t *filestat) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr(filestat, sizeof(wasi_filestat_t))) + return (wasi_errno_t)-1; + + return uvwasi_path_filestat_get(uvwasi, fd, flags, path, path_len, + filestat); +} + +static wasi_errno_t +wasi_path_filestat_set_times(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_lookupflags_t flags, const char *path, + uint32 path_len, wasi_timestamp_t st_atim, + wasi_timestamp_t st_mtim, wasi_fstflags_t fstflags) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_path_filestat_set_times(uvwasi, fd, flags, path, path_len, + st_atim, st_mtim, fstflags); +} + +static wasi_errno_t +wasi_path_symlink(wasm_exec_env_t exec_env, const char *old_path, + uint32 old_path_len, wasi_fd_t fd, const char *new_path, + uint32 new_path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_path_symlink(uvwasi, old_path, old_path_len, fd, new_path, + new_path_len); +} + +static wasi_errno_t +wasi_path_unlink_file(wasm_exec_env_t exec_env, wasi_fd_t fd, const char *path, + uint32 path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_path_unlink_file(uvwasi, fd, path, path_len); +} + +static wasi_errno_t +wasi_path_remove_directory(wasm_exec_env_t exec_env, wasi_fd_t fd, + const char *path, uint32 path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_path_remove_directory(uvwasi, fd, path, path_len); +} + +static wasi_errno_t +wasi_poll_oneoff(wasm_exec_env_t exec_env, const wasi_subscription_t *in, + wasi_event_t *out, uint32 nsubscriptions, uint32 *nevents_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + uvwasi_size_t nevents; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + if (!validate_native_addr((void *)in, sizeof(wasi_subscription_t)) + || !validate_native_addr(out, sizeof(wasi_event_t)) + || !validate_native_addr(nevents_app, sizeof(uint32))) + return (wasi_errno_t)-1; + + err = uvwasi_poll_oneoff(uvwasi, in, out, nsubscriptions, &nevents); + if (err) + return err; + + *nevents_app = (uint32)nevents; + return 0; +} + +static void +wasi_proc_exit(wasm_exec_env_t exec_env, wasi_exitcode_t rval) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + WASIContext *wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst); + /* Here throwing exception is just to let wasm app exit, + the upper layer should clear the exception and return + as normal */ + wasm_runtime_set_exception(module_inst, "wasi proc exit"); + wasi_ctx->exit_code = rval; +} + +static wasi_errno_t +wasi_proc_raise(wasm_exec_env_t exec_env, wasi_signal_t sig) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + char buf[32]; + + snprintf(buf, sizeof(buf), "%s%d", "wasi proc raise ", sig); + wasm_runtime_set_exception(module_inst, buf); + return 0; +} + +static wasi_errno_t +wasi_random_get(wasm_exec_env_t exec_env, void *buf, uint32 buf_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + return uvwasi_random_get(uvwasi, buf, buf_len); +} + +static wasi_errno_t +wasi_sock_recv(wasm_exec_env_t exec_env, wasi_fd_t sock, iovec_app_t *ri_data, + uint32 ri_data_len, wasi_riflags_t ri_flags, + uint32 *ro_datalen_app, wasi_roflags_t *ro_flags) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + wasi_iovec_t *iovec, *iovec_begin; + uint64 total_size; + uvwasi_size_t ro_datalen; + uint32 i; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + total_size = sizeof(iovec_app_t) * (uint64)ri_data_len; + if (!validate_native_addr(ro_datalen_app, (uint32)sizeof(uint32)) + || !validate_native_addr(ro_flags, (uint32)sizeof(wasi_roflags_t)) + || total_size >= UINT32_MAX + || !validate_native_addr(ri_data, (uint32)total_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(wasi_iovec_t) * (uint64)ri_data_len; + if (total_size >= UINT32_MAX + || !(iovec_begin = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + iovec = iovec_begin; + for (i = 0; i < ri_data_len; i++, ri_data++, iovec++) { + if (!validate_app_addr(ri_data->buf_offset, ri_data->buf_len)) { + err = (wasi_errno_t)-1; + goto fail; + } + iovec->buf = (void *)addr_app_to_native(ri_data->buf_offset); + iovec->buf_len = ri_data->buf_len; + } + + err = uvwasi_sock_recv(uvwasi, sock, iovec_begin, ri_data_len, ri_flags, + &ro_datalen, ro_flags); + if (err) + goto fail; + + *(uint32 *)ro_datalen_app = (uint32)ro_datalen; + + /* success */ + err = 0; + +fail: + wasm_runtime_free(iovec_begin); + return err; +} + +static wasi_errno_t +wasi_sock_send(wasm_exec_env_t exec_env, wasi_fd_t sock, + const iovec_app_t *si_data, uint32 si_data_len, + wasi_siflags_t si_flags, uint32 *so_datalen_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + wasi_ciovec_t *ciovec, *ciovec_begin; + uint64 total_size; + uvwasi_size_t so_datalen; + uint32 i; + wasi_errno_t err; + + if (!uvwasi) + return (wasi_errno_t)-1; + + total_size = sizeof(iovec_app_t) * (uint64)si_data_len; + if (!validate_native_addr(so_datalen_app, sizeof(uint32)) + || total_size >= UINT32_MAX + || !validate_native_addr((void *)si_data, (uint32)total_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(wasi_ciovec_t) * (uint64)si_data_len; + if (total_size >= UINT32_MAX + || !(ciovec_begin = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + ciovec = ciovec_begin; + for (i = 0; i < si_data_len; i++, si_data++, ciovec++) { + if (!validate_app_addr(si_data->buf_offset, si_data->buf_len)) { + err = (wasi_errno_t)-1; + goto fail; + } + ciovec->buf = (char *)addr_app_to_native(si_data->buf_offset); + ciovec->buf_len = si_data->buf_len; + } + + err = uvwasi_sock_send(uvwasi, sock, ciovec_begin, si_data_len, si_flags, + &so_datalen); + if (err) + goto fail; + + *so_datalen_app = (uint32)so_datalen; + + /* success */ + err = 0; + +fail: + wasm_runtime_free(ciovec_begin); + return err; +} + +static wasi_errno_t +wasi_sock_shutdown(wasm_exec_env_t exec_env, wasi_fd_t sock, wasi_sdflags_t how) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + if (!uvwasi) + return (wasi_errno_t)-1; + + return uvwasi_sock_shutdown(uvwasi, sock, how); +} + +static wasi_errno_t +wasi_sched_yield(wasm_exec_env_t exec_env) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + uvwasi_t *uvwasi = get_wasi_ctx(module_inst); + + return uvwasi_sched_yield(uvwasi); +} + +/* clang-format off */ +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, wasi_##func_name, signature, NULL } +/* clang-format on */ + +static NativeSymbol native_symbols_libc_wasi[] = { + REG_NATIVE_FUNC(args_get, "(**)i"), + REG_NATIVE_FUNC(args_sizes_get, "(**)i"), + REG_NATIVE_FUNC(clock_res_get, "(i*)i"), + REG_NATIVE_FUNC(clock_time_get, "(iI*)i"), + REG_NATIVE_FUNC(environ_get, "(**)i"), + REG_NATIVE_FUNC(environ_sizes_get, "(**)i"), + REG_NATIVE_FUNC(fd_prestat_get, "(i*)i"), + REG_NATIVE_FUNC(fd_prestat_dir_name, "(i*~)i"), + REG_NATIVE_FUNC(fd_close, "(i)i"), + REG_NATIVE_FUNC(fd_datasync, "(i)i"), + REG_NATIVE_FUNC(fd_pread, "(i*iI*)i"), + REG_NATIVE_FUNC(fd_pwrite, "(i*iI*)i"), + REG_NATIVE_FUNC(fd_read, "(i*i*)i"), + REG_NATIVE_FUNC(fd_renumber, "(ii)i"), + REG_NATIVE_FUNC(fd_seek, "(iIi*)i"), + REG_NATIVE_FUNC(fd_tell, "(i*)i"), + REG_NATIVE_FUNC(fd_fdstat_get, "(i*)i"), + REG_NATIVE_FUNC(fd_fdstat_set_flags, "(ii)i"), + REG_NATIVE_FUNC(fd_fdstat_set_rights, "(iII)i"), + REG_NATIVE_FUNC(fd_sync, "(i)i"), + REG_NATIVE_FUNC(fd_write, "(i*i*)i"), + REG_NATIVE_FUNC(fd_advise, "(iIIi)i"), + REG_NATIVE_FUNC(fd_allocate, "(iII)i"), + REG_NATIVE_FUNC(path_create_directory, "(i*~)i"), + REG_NATIVE_FUNC(path_link, "(ii*~i*~)i"), + REG_NATIVE_FUNC(path_open, "(ii*~iIIi*)i"), + REG_NATIVE_FUNC(fd_readdir, "(i*~I*)i"), + REG_NATIVE_FUNC(path_readlink, "(i*~*~*)i"), + REG_NATIVE_FUNC(path_rename, "(i*~i*~)i"), + REG_NATIVE_FUNC(fd_filestat_get, "(i*)i"), + REG_NATIVE_FUNC(fd_filestat_set_times, "(iIIi)i"), + REG_NATIVE_FUNC(fd_filestat_set_size, "(iI)i"), + REG_NATIVE_FUNC(path_filestat_get, "(ii*~*)i"), + REG_NATIVE_FUNC(path_filestat_set_times, "(ii*~IIi)i"), + REG_NATIVE_FUNC(path_symlink, "(*~i*~)i"), + REG_NATIVE_FUNC(path_unlink_file, "(i*~)i"), + REG_NATIVE_FUNC(path_remove_directory, "(i*~)i"), + REG_NATIVE_FUNC(poll_oneoff, "(**i*)i"), + REG_NATIVE_FUNC(proc_exit, "(i)"), + REG_NATIVE_FUNC(proc_raise, "(i)i"), + REG_NATIVE_FUNC(random_get, "(*~)i"), + REG_NATIVE_FUNC(sock_recv, "(i*ii**)i"), + REG_NATIVE_FUNC(sock_send, "(i*ii*)i"), + REG_NATIVE_FUNC(sock_shutdown, "(ii)i"), + REG_NATIVE_FUNC(sched_yield, "()i"), +}; + +uint32 +get_libc_wasi_export_apis(NativeSymbol **p_libc_wasi_apis) +{ + *p_libc_wasi_apis = native_symbols_libc_wasi; + return sizeof(native_symbols_libc_wasi) / sizeof(NativeSymbol); +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/SConscript b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/SConscript new file mode 100644 index 000000000..6ed3799e0 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/SConscript @@ -0,0 +1,34 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * +import os + +cwd = GetCurrentDir() + +src = Split(''' +''') + +CPPPATH = [cwd, + cwd+'/sandboxed-system-primitives/include', + cwd+'/sandboxed-system-primitives/src'] + +def addSrcFiles(arr, path): + for f in os.listdir(path): + fpath = os.path.join(path, f); + if os.path.isfile(fpath): + ext = os.path.splitext(fpath)[-1] + if ext == '.c' or ext == '.cpp': + arr += [fpath] + elif os.path.isdir(fpath): + addSrcFiles(arr, fpath) + + +addSrcFiles(src, cwd) + +group = DefineGroup('iwasm_libc_wasi', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/libc_wasi.cmake b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/libc_wasi.cmake new file mode 100644 index 000000000..d72c42a06 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/libc_wasi.cmake @@ -0,0 +1,13 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (LIBC_WASI_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions (-DWASM_ENABLE_LIBC_WASI=1) + +include_directories(${LIBC_WASI_DIR}/sandboxed-system-primitives/include + ${LIBC_WASI_DIR}/sandboxed-system-primitives/src) + +file (GLOB_RECURSE source_all ${LIBC_WASI_DIR}/*.c ) + +set (LIBC_WASI_SOURCE ${source_all}) diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c new file mode 100644 index 000000000..afb11925a --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -0,0 +1,2329 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "libc_wasi_wrapper.h" +#include "bh_platform.h" +#include "wasm_export.h" +#include "wasm_runtime_common.h" + +#if WASM_ENABLE_THREAD_MGR != 0 +#include "../../../thread-mgr/thread_manager.h" +#endif + +void +wasm_runtime_set_exception(wasm_module_inst_t module, const char *exception); + +/* clang-format off */ +#define get_module_inst(exec_env) \ + wasm_runtime_get_module_inst(exec_env) + +#define get_wasi_ctx(module_inst) \ + wasm_runtime_get_wasi_ctx(module_inst) + +#define validate_app_addr(offset, size) \ + wasm_runtime_validate_app_addr(module_inst, offset, size) + +#define validate_native_addr(addr, size) \ + wasm_runtime_validate_native_addr(module_inst, addr, size) + +#define addr_app_to_native(offset) \ + wasm_runtime_addr_app_to_native(module_inst, offset) + +#define addr_native_to_app(ptr) \ + wasm_runtime_addr_native_to_app(module_inst, ptr) + +#define module_malloc(size, p_native_addr) \ + wasm_runtime_module_malloc(module_inst, size, p_native_addr) + +#define module_free(offset) \ + wasm_runtime_module_free(module_inst, offset) +/* clang-format on */ + +typedef struct wasi_prestat_app { + wasi_preopentype_t pr_type; + uint32 pr_name_len; +} wasi_prestat_app_t; + +typedef struct iovec_app { + uint32 buf_offset; + uint32 buf_len; +} iovec_app_t; + +typedef struct WASIContext *wasi_ctx_t; + +wasi_ctx_t +wasm_runtime_get_wasi_ctx(wasm_module_inst_t module_inst); + +static inline uint64_t +min_uint64(uint64_t a, uint64_t b) +{ + return a > b ? b : a; +} + +static inline uint32_t +min_uint32(uint32_t a, uint32_t b) +{ + return a > b ? b : a; +} + +static inline struct fd_table * +wasi_ctx_get_curfds(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx) +{ + if (!wasi_ctx) + return NULL; + return wasi_ctx->curfds; +} + +static inline struct argv_environ_values * +wasi_ctx_get_argv_environ(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx) +{ + if (!wasi_ctx) + return NULL; + return wasi_ctx->argv_environ; +} + +static inline struct fd_prestats * +wasi_ctx_get_prestats(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx) +{ + if (!wasi_ctx) + return NULL; + return wasi_ctx->prestats; +} + +static inline struct addr_pool * +wasi_ctx_get_addr_pool(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx) +{ + if (!wasi_ctx) + return NULL; + return wasi_ctx->addr_pool; +} + +static inline char ** +wasi_ctx_get_ns_lookup_list(wasi_ctx_t wasi_ctx) +{ + if (!wasi_ctx) + return NULL; + return wasi_ctx->ns_lookup_list; +} + +static wasi_errno_t +wasi_args_get(wasm_exec_env_t exec_env, uint32 *argv_offsets, char *argv_buf) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct argv_environ_values *argv_environ = + wasi_ctx_get_argv_environ(module_inst, wasi_ctx); + size_t argc, argv_buf_size, i; + char **argv; + uint64 total_size; + wasi_errno_t err; + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + err = wasmtime_ssp_args_sizes_get(argv_environ, &argc, &argv_buf_size); + if (err) + return err; + + total_size = sizeof(int32) * ((uint64)argc + 1); + if (total_size >= UINT32_MAX + || !validate_native_addr(argv_offsets, (uint32)total_size) + || argv_buf_size >= UINT32_MAX + || !validate_native_addr(argv_buf, (uint32)argv_buf_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(char *) * ((uint64)argc + 1); + if (total_size >= UINT32_MAX + || !(argv = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + err = wasmtime_ssp_args_get(argv_environ, argv, argv_buf); + if (err) { + wasm_runtime_free(argv); + return err; + } + + for (i = 0; i < argc; i++) + argv_offsets[i] = addr_native_to_app(argv[i]); + + wasm_runtime_free(argv); + return 0; +} + +static wasi_errno_t +wasi_args_sizes_get(wasm_exec_env_t exec_env, uint32 *argc_app, + uint32 *argv_buf_size_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct argv_environ_values *argv_environ; + size_t argc, argv_buf_size; + wasi_errno_t err; + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + if (!validate_native_addr(argc_app, sizeof(uint32)) + || !validate_native_addr(argv_buf_size_app, sizeof(uint32))) + return (wasi_errno_t)-1; + + argv_environ = wasi_ctx->argv_environ; + + err = wasmtime_ssp_args_sizes_get(argv_environ, &argc, &argv_buf_size); + if (err) + return err; + + *argc_app = (uint32)argc; + *argv_buf_size_app = (uint32)argv_buf_size; + return 0; +} + +static wasi_errno_t +wasi_clock_res_get(wasm_exec_env_t exec_env, + wasi_clockid_t clock_id, /* uint32 clock_id */ + wasi_timestamp_t *resolution /* uint64 *resolution */) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + + if (!validate_native_addr(resolution, sizeof(wasi_timestamp_t))) + return (wasi_errno_t)-1; + + return wasmtime_ssp_clock_res_get(clock_id, resolution); +} + +static wasi_errno_t +wasi_clock_time_get(wasm_exec_env_t exec_env, + wasi_clockid_t clock_id, /* uint32 clock_id */ + wasi_timestamp_t precision, /* uint64 precision */ + wasi_timestamp_t *time /* uint64 *time */) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + + if (!validate_native_addr(time, sizeof(wasi_timestamp_t))) + return (wasi_errno_t)-1; + + return wasmtime_ssp_clock_time_get(clock_id, precision, time); +} + +static wasi_errno_t +wasi_environ_get(wasm_exec_env_t exec_env, uint32 *environ_offsets, + char *environ_buf) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct argv_environ_values *argv_environ = + wasi_ctx_get_argv_environ(module_inst, wasi_ctx); + size_t environ_count, environ_buf_size, i; + uint64 total_size; + char **environs; + wasi_errno_t err; + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + err = wasmtime_ssp_environ_sizes_get(argv_environ, &environ_count, + &environ_buf_size); + if (err) + return err; + + total_size = sizeof(int32) * ((uint64)environ_count + 1); + if (total_size >= UINT32_MAX + || !validate_native_addr(environ_offsets, (uint32)total_size) + || environ_buf_size >= UINT32_MAX + || !validate_native_addr(environ_buf, (uint32)environ_buf_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(char *) * (((uint64)environ_count + 1)); + + if (total_size >= UINT32_MAX + || !(environs = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + err = wasmtime_ssp_environ_get(argv_environ, environs, environ_buf); + if (err) { + wasm_runtime_free(environs); + return err; + } + + for (i = 0; i < environ_count; i++) + environ_offsets[i] = addr_native_to_app(environs[i]); + + wasm_runtime_free(environs); + return 0; +} + +static wasi_errno_t +wasi_environ_sizes_get(wasm_exec_env_t exec_env, uint32 *environ_count_app, + uint32 *environ_buf_size_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct argv_environ_values *argv_environ = + wasi_ctx_get_argv_environ(module_inst, wasi_ctx); + size_t environ_count, environ_buf_size; + wasi_errno_t err; + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + if (!validate_native_addr(environ_count_app, sizeof(uint32)) + || !validate_native_addr(environ_buf_size_app, sizeof(uint32))) + return (wasi_errno_t)-1; + + err = wasmtime_ssp_environ_sizes_get(argv_environ, &environ_count, + &environ_buf_size); + if (err) + return err; + + *environ_count_app = (uint32)environ_count; + *environ_buf_size_app = (uint32)environ_buf_size; + + return 0; +} + +static wasi_errno_t +wasi_fd_prestat_get(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_prestat_app_t *prestat_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx); + wasi_prestat_t prestat; + wasi_errno_t err; + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + if (!validate_native_addr(prestat_app, sizeof(wasi_prestat_app_t))) + return (wasi_errno_t)-1; + + err = wasmtime_ssp_fd_prestat_get(prestats, fd, &prestat); + if (err) + return err; + + prestat_app->pr_type = prestat.pr_type; + prestat_app->pr_name_len = (uint32)prestat.u.dir.pr_name_len; + return 0; +} + +static wasi_errno_t +wasi_fd_prestat_dir_name(wasm_exec_env_t exec_env, wasi_fd_t fd, char *path, + uint32 path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_fd_prestat_dir_name(prestats, fd, path, path_len); +} + +static wasi_errno_t +wasi_fd_close(wasm_exec_env_t exec_env, wasi_fd_t fd) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_fd_close(curfds, prestats, fd); +} + +static wasi_errno_t +wasi_fd_datasync(wasm_exec_env_t exec_env, wasi_fd_t fd) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_fd_datasync(curfds, fd); +} + +static wasi_errno_t +wasi_fd_pread(wasm_exec_env_t exec_env, wasi_fd_t fd, iovec_app_t *iovec_app, + uint32 iovs_len, wasi_filesize_t offset, uint32 *nread_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + wasi_iovec_t *iovec, *iovec_begin; + uint64 total_size; + size_t nread; + uint32 i; + wasi_errno_t err; + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + total_size = sizeof(iovec_app_t) * (uint64)iovs_len; + if (!validate_native_addr(nread_app, (uint32)sizeof(uint32)) + || total_size >= UINT32_MAX + || !validate_native_addr(iovec_app, (uint32)total_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(wasi_iovec_t) * (uint64)iovs_len; + if (total_size >= UINT32_MAX + || !(iovec_begin = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + iovec = iovec_begin; + + for (i = 0; i < iovs_len; i++, iovec_app++, iovec++) { + if (!validate_app_addr(iovec_app->buf_offset, iovec_app->buf_len)) { + err = (wasi_errno_t)-1; + goto fail; + } + iovec->buf = (void *)addr_app_to_native(iovec_app->buf_offset); + iovec->buf_len = iovec_app->buf_len; + } + + err = wasmtime_ssp_fd_pread(curfds, fd, iovec_begin, iovs_len, offset, + &nread); + if (err) + goto fail; + + *nread_app = (uint32)nread; + + /* success */ + err = 0; + +fail: + wasm_runtime_free(iovec_begin); + return err; +} + +static wasi_errno_t +wasi_fd_pwrite(wasm_exec_env_t exec_env, wasi_fd_t fd, + const iovec_app_t *iovec_app, uint32 iovs_len, + wasi_filesize_t offset, uint32 *nwritten_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + wasi_ciovec_t *ciovec, *ciovec_begin; + uint64 total_size; + size_t nwritten; + uint32 i; + wasi_errno_t err; + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + total_size = sizeof(iovec_app_t) * (uint64)iovs_len; + if (!validate_native_addr(nwritten_app, (uint32)sizeof(uint32)) + || total_size >= UINT32_MAX + || !validate_native_addr((void *)iovec_app, (uint32)total_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(wasi_ciovec_t) * (uint64)iovs_len; + if (total_size >= UINT32_MAX + || !(ciovec_begin = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + ciovec = ciovec_begin; + + for (i = 0; i < iovs_len; i++, iovec_app++, ciovec++) { + if (!validate_app_addr(iovec_app->buf_offset, iovec_app->buf_len)) { + err = (wasi_errno_t)-1; + goto fail; + } + ciovec->buf = (char *)addr_app_to_native(iovec_app->buf_offset); + ciovec->buf_len = iovec_app->buf_len; + } + + err = wasmtime_ssp_fd_pwrite(curfds, fd, ciovec_begin, iovs_len, offset, + &nwritten); + if (err) + goto fail; + + *nwritten_app = (uint32)nwritten; + + /* success */ + err = 0; + +fail: + wasm_runtime_free(ciovec_begin); + return err; +} + +static wasi_errno_t +wasi_fd_read(wasm_exec_env_t exec_env, wasi_fd_t fd, + const iovec_app_t *iovec_app, uint32 iovs_len, uint32 *nread_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + wasi_iovec_t *iovec, *iovec_begin; + uint64 total_size; + size_t nread; + uint32 i; + wasi_errno_t err; + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + total_size = sizeof(iovec_app_t) * (uint64)iovs_len; + if (!validate_native_addr(nread_app, (uint32)sizeof(uint32)) + || total_size >= UINT32_MAX + || !validate_native_addr((void *)iovec_app, (uint32)total_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(wasi_iovec_t) * (uint64)iovs_len; + if (total_size >= UINT32_MAX + || !(iovec_begin = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + iovec = iovec_begin; + + for (i = 0; i < iovs_len; i++, iovec_app++, iovec++) { + if (!validate_app_addr(iovec_app->buf_offset, iovec_app->buf_len)) { + err = (wasi_errno_t)-1; + goto fail; + } + iovec->buf = (void *)addr_app_to_native(iovec_app->buf_offset); + iovec->buf_len = iovec_app->buf_len; + } + + err = wasmtime_ssp_fd_read(curfds, fd, iovec_begin, iovs_len, &nread); + if (err) + goto fail; + + *nread_app = (uint32)nread; + + /* success */ + err = 0; + +fail: + wasm_runtime_free(iovec_begin); + return err; +} + +static wasi_errno_t +wasi_fd_renumber(wasm_exec_env_t exec_env, wasi_fd_t from, wasi_fd_t to) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_fd_renumber(curfds, prestats, from, to); +} + +static wasi_errno_t +wasi_fd_seek(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_filedelta_t offset, + wasi_whence_t whence, wasi_filesize_t *newoffset) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + if (!validate_native_addr(newoffset, sizeof(wasi_filesize_t))) + return (wasi_errno_t)-1; + + return wasmtime_ssp_fd_seek(curfds, fd, offset, whence, newoffset); +} + +static wasi_errno_t +wasi_fd_tell(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_filesize_t *newoffset) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + if (!validate_native_addr(newoffset, sizeof(wasi_filesize_t))) + return (wasi_errno_t)-1; + + return wasmtime_ssp_fd_tell(curfds, fd, newoffset); +} + +static wasi_errno_t +wasi_fd_fdstat_get(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_fdstat_t *fdstat_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + wasi_fdstat_t fdstat; + wasi_errno_t err; + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + if (!validate_native_addr(fdstat_app, sizeof(wasi_fdstat_t))) + return (wasi_errno_t)-1; + + err = wasmtime_ssp_fd_fdstat_get(curfds, fd, &fdstat); + if (err) + return err; + + memcpy(fdstat_app, &fdstat, sizeof(wasi_fdstat_t)); + return 0; +} + +static wasi_errno_t +wasi_fd_fdstat_set_flags(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_fdflags_t flags) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_fd_fdstat_set_flags(curfds, fd, flags); +} + +static wasi_errno_t +wasi_fd_fdstat_set_rights(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_rights_t fs_rights_base, + wasi_rights_t fs_rights_inheriting) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_fd_fdstat_set_rights(curfds, fd, fs_rights_base, + fs_rights_inheriting); +} + +static wasi_errno_t +wasi_fd_sync(wasm_exec_env_t exec_env, wasi_fd_t fd) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_fd_sync(curfds, fd); +} + +static wasi_errno_t +wasi_fd_write(wasm_exec_env_t exec_env, wasi_fd_t fd, + const iovec_app_t *iovec_app, uint32 iovs_len, + uint32 *nwritten_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + wasi_ciovec_t *ciovec, *ciovec_begin; + uint64 total_size; + size_t nwritten; + uint32 i; + wasi_errno_t err; + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + total_size = sizeof(iovec_app_t) * (uint64)iovs_len; + if (!validate_native_addr(nwritten_app, (uint32)sizeof(uint32)) + || total_size >= UINT32_MAX + || !validate_native_addr((void *)iovec_app, (uint32)total_size)) + return (wasi_errno_t)-1; + + total_size = sizeof(wasi_ciovec_t) * (uint64)iovs_len; + if (total_size >= UINT32_MAX + || !(ciovec_begin = wasm_runtime_malloc((uint32)total_size))) + return (wasi_errno_t)-1; + + ciovec = ciovec_begin; + + for (i = 0; i < iovs_len; i++, iovec_app++, ciovec++) { + if (!validate_app_addr(iovec_app->buf_offset, iovec_app->buf_len)) { + err = (wasi_errno_t)-1; + goto fail; + } + ciovec->buf = (char *)addr_app_to_native(iovec_app->buf_offset); + ciovec->buf_len = iovec_app->buf_len; + } + + err = wasmtime_ssp_fd_write(curfds, fd, ciovec_begin, iovs_len, &nwritten); + if (err) + goto fail; + + *nwritten_app = (uint32)nwritten; + + /* success */ + err = 0; + +fail: + wasm_runtime_free(ciovec_begin); + return err; +} + +static wasi_errno_t +wasi_fd_advise(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_filesize_t offset, + wasi_filesize_t len, wasi_advice_t advice) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_fd_advise(curfds, fd, offset, len, advice); +} + +static wasi_errno_t +wasi_fd_allocate(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_filesize_t offset, + wasi_filesize_t len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_fd_allocate(curfds, fd, offset, len); +} + +static wasi_errno_t +wasi_path_create_directory(wasm_exec_env_t exec_env, wasi_fd_t fd, + const char *path, uint32 path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_path_create_directory(curfds, fd, path, path_len); +} + +static wasi_errno_t +wasi_path_link(wasm_exec_env_t exec_env, wasi_fd_t old_fd, + wasi_lookupflags_t old_flags, const char *old_path, + uint32 old_path_len, wasi_fd_t new_fd, const char *new_path, + uint32 new_path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_path_link(curfds, prestats, old_fd, old_flags, old_path, + old_path_len, new_fd, new_path, new_path_len); +} + +static wasi_errno_t +wasi_path_open(wasm_exec_env_t exec_env, wasi_fd_t dirfd, + wasi_lookupflags_t dirflags, const char *path, uint32 path_len, + wasi_oflags_t oflags, wasi_rights_t fs_rights_base, + wasi_rights_t fs_rights_inheriting, wasi_fdflags_t fs_flags, + wasi_fd_t *fd_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + wasi_fd_t fd = (wasi_fd_t)-1; /* set fd_app -1 if path open failed */ + wasi_errno_t err; + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + if (!validate_native_addr(fd_app, sizeof(wasi_fd_t))) + return (wasi_errno_t)-1; + + err = wasmtime_ssp_path_open(curfds, dirfd, dirflags, path, path_len, + oflags, fs_rights_base, fs_rights_inheriting, + fs_flags, &fd); + + *fd_app = fd; + return err; +} + +static wasi_errno_t +wasi_fd_readdir(wasm_exec_env_t exec_env, wasi_fd_t fd, void *buf, + uint32 buf_len, wasi_dircookie_t cookie, uint32 *bufused_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + size_t bufused; + wasi_errno_t err; + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + if (!validate_native_addr(bufused_app, sizeof(uint32))) + return (wasi_errno_t)-1; + + err = wasmtime_ssp_fd_readdir(curfds, fd, buf, buf_len, cookie, &bufused); + if (err) + return err; + + *bufused_app = (uint32)bufused; + return 0; +} + +static wasi_errno_t +wasi_path_readlink(wasm_exec_env_t exec_env, wasi_fd_t fd, const char *path, + uint32 path_len, char *buf, uint32 buf_len, + uint32 *bufused_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + size_t bufused; + wasi_errno_t err; + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + if (!validate_native_addr(bufused_app, sizeof(uint32))) + return (wasi_errno_t)-1; + + err = wasmtime_ssp_path_readlink(curfds, fd, path, path_len, buf, buf_len, + &bufused); + if (err) + return err; + + *bufused_app = (uint32)bufused; + return 0; +} + +static wasi_errno_t +wasi_path_rename(wasm_exec_env_t exec_env, wasi_fd_t old_fd, + const char *old_path, uint32 old_path_len, wasi_fd_t new_fd, + const char *new_path, uint32 new_path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_path_rename(curfds, old_fd, old_path, old_path_len, + new_fd, new_path, new_path_len); +} + +static wasi_errno_t +wasi_fd_filestat_get(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_filestat_t *filestat) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + if (!validate_native_addr(filestat, sizeof(wasi_filestat_t))) + return (wasi_errno_t)-1; + + return wasmtime_ssp_fd_filestat_get(curfds, fd, filestat); +} + +static wasi_errno_t +wasi_fd_filestat_set_times(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_timestamp_t st_atim, wasi_timestamp_t st_mtim, + wasi_fstflags_t fstflags) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_fd_filestat_set_times(curfds, fd, st_atim, st_mtim, + fstflags); +} + +static wasi_errno_t +wasi_fd_filestat_set_size(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_filesize_t st_size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_fd_filestat_set_size(curfds, fd, st_size); +} + +static wasi_errno_t +wasi_path_filestat_get(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_lookupflags_t flags, const char *path, + uint32 path_len, wasi_filestat_t *filestat) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + if (!validate_native_addr(filestat, sizeof(wasi_filestat_t))) + return (wasi_errno_t)-1; + + return wasmtime_ssp_path_filestat_get(curfds, fd, flags, path, path_len, + filestat); +} + +static wasi_errno_t +wasi_path_filestat_set_times(wasm_exec_env_t exec_env, wasi_fd_t fd, + wasi_lookupflags_t flags, const char *path, + uint32 path_len, wasi_timestamp_t st_atim, + wasi_timestamp_t st_mtim, wasi_fstflags_t fstflags) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_path_filestat_set_times( + curfds, fd, flags, path, path_len, st_atim, st_mtim, fstflags); +} + +static wasi_errno_t +wasi_path_symlink(wasm_exec_env_t exec_env, const char *old_path, + uint32 old_path_len, wasi_fd_t fd, const char *new_path, + uint32 new_path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + struct fd_prestats *prestats = wasi_ctx_get_prestats(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_path_symlink(curfds, prestats, old_path, old_path_len, + fd, new_path, new_path_len); +} + +static wasi_errno_t +wasi_path_unlink_file(wasm_exec_env_t exec_env, wasi_fd_t fd, const char *path, + uint32 path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_path_unlink_file(curfds, fd, path, path_len); +} + +static wasi_errno_t +wasi_path_remove_directory(wasm_exec_env_t exec_env, wasi_fd_t fd, + const char *path, uint32 path_len) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + return wasmtime_ssp_path_remove_directory(curfds, fd, path, path_len); +} + +#if WASM_ENABLE_THREAD_MGR != 0 +static __wasi_timestamp_t +get_timeout_for_poll_oneoff(const wasi_subscription_t *in, + uint32 nsubscriptions) +{ + __wasi_timestamp_t timeout = (__wasi_timestamp_t)-1; + uint32 i = 0; + + for (i = 0; i < nsubscriptions; ++i) { + const __wasi_subscription_t *s = &in[i]; + if (s->u.type == __WASI_EVENTTYPE_CLOCK + && (s->u.u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) == 0) { + timeout = min_uint64(timeout, s->u.u.clock.timeout); + } + } + return timeout; +} + +static void +update_clock_subscription_data(wasi_subscription_t *in, uint32 nsubscriptions, + const wasi_timestamp_t new_timeout) +{ + uint32 i = 0; + for (i = 0; i < nsubscriptions; ++i) { + __wasi_subscription_t *s = &in[i]; + if (s->u.type == __WASI_EVENTTYPE_CLOCK) { + s->u.u.clock.timeout = new_timeout; + } + } +} + +static wasi_errno_t +execute_interruptible_poll_oneoff( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + const __wasi_subscription_t *in, __wasi_event_t *out, size_t nsubscriptions, + size_t *nevents, wasm_exec_env_t exec_env) +{ + if (nsubscriptions == 0) { + *nevents = 0; + return __WASI_ESUCCESS; + } + + wasi_errno_t err; + __wasi_timestamp_t elapsed = 0; + bool all_outs_are_type_clock; + uint32 i; + + const __wasi_timestamp_t timeout = get_timeout_for_poll_oneoff( + in, nsubscriptions), + time_quant = 1e9; + const uint64 size_to_copy = + nsubscriptions * (uint64)sizeof(wasi_subscription_t); + __wasi_subscription_t *in_copy = NULL; + + if (size_to_copy >= UINT32_MAX + || !(in_copy = (__wasi_subscription_t *)wasm_runtime_malloc( + (uint32)size_to_copy))) { + return __WASI_ENOMEM; + } + + bh_memcpy_s(in_copy, size_to_copy, in, size_to_copy); + + while (timeout == (__wasi_timestamp_t)-1 || elapsed <= timeout) { + /* update timeout for clock subscription events */ + update_clock_subscription_data( + in_copy, nsubscriptions, min_uint64(time_quant, timeout - elapsed)); + err = wasmtime_ssp_poll_oneoff(curfds, in_copy, out, nsubscriptions, + nevents); + elapsed += time_quant; + + if (err) { + wasm_runtime_free(in_copy); + return err; + } + + if (wasm_cluster_is_thread_terminated(exec_env)) { + wasm_runtime_free(in_copy); + return EINTR; + } + else if (*nevents > 0) { + all_outs_are_type_clock = true; + for (i = 0; i < *nevents; i++) { + if (out[i].type != __WASI_EVENTTYPE_CLOCK) { + all_outs_are_type_clock = false; + break; + } + } + + if (!all_outs_are_type_clock) { + wasm_runtime_free(in_copy); + return __WASI_ESUCCESS; + } + } + } + + wasm_runtime_free(in_copy); + return __WASI_ESUCCESS; +} +#endif + +static wasi_errno_t +wasi_poll_oneoff(wasm_exec_env_t exec_env, const wasi_subscription_t *in, + wasi_event_t *out, uint32 nsubscriptions, uint32 *nevents_app) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + size_t nevents = 0; + wasi_errno_t err; + + if (!wasi_ctx) + return (wasi_errno_t)-1; + + if (!validate_native_addr((void *)in, sizeof(wasi_subscription_t)) + || !validate_native_addr(out, sizeof(wasi_event_t)) + || !validate_native_addr(nevents_app, sizeof(uint32))) + return (wasi_errno_t)-1; + +#if WASM_ENABLE_THREAD_MGR == 0 + err = wasmtime_ssp_poll_oneoff(curfds, in, out, nsubscriptions, &nevents); +#else + err = execute_interruptible_poll_oneoff(curfds, in, out, nsubscriptions, + &nevents, exec_env); +#endif + if (err) + return err; + + *nevents_app = (uint32)nevents; + return 0; +} + +static void +wasi_proc_exit(wasm_exec_env_t exec_env, wasi_exitcode_t rval) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + /* Here throwing exception is just to let wasm app exit, + the upper layer should clear the exception and return + as normal */ + wasm_runtime_set_exception(module_inst, "wasi proc exit"); + wasi_ctx->exit_code = rval; +} + +static wasi_errno_t +wasi_proc_raise(wasm_exec_env_t exec_env, wasi_signal_t sig) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + char buf[32]; + snprintf(buf, sizeof(buf), "%s%d", "wasi proc raise ", sig); + wasm_runtime_set_exception(module_inst, buf); + + return 0; +} + +static wasi_errno_t +wasi_random_get(wasm_exec_env_t exec_env, void *buf, uint32 buf_len) +{ + return wasmtime_ssp_random_get(buf, buf_len); +} + +static wasi_errno_t +wasi_sock_accept(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_fdflags_t flags, + wasi_fd_t *fd_new) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasi_ssp_sock_accept(curfds, fd, flags, fd_new); +} + +static wasi_errno_t +wasi_sock_addr_local(wasm_exec_env_t exec_env, wasi_fd_t fd, + __wasi_addr_t *addr) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(addr, sizeof(__wasi_addr_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasi_ssp_sock_addr_local(curfds, fd, addr); +} + +static wasi_errno_t +wasi_sock_addr_remote(wasm_exec_env_t exec_env, wasi_fd_t fd, + __wasi_addr_t *addr) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(addr, sizeof(__wasi_addr_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasi_ssp_sock_addr_remote(curfds, fd, addr); +} + +static wasi_errno_t +wasi_sock_addr_resolve(wasm_exec_env_t exec_env, const char *host, + const char *service, __wasi_addr_info_hints_t *hints, + __wasi_addr_info_t *addr_info, + __wasi_size_t addr_info_size, + __wasi_size_t *max_info_size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + char **ns_lookup_list = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + ns_lookup_list = wasi_ctx_get_ns_lookup_list(wasi_ctx); + + return wasi_ssp_sock_addr_resolve(curfds, ns_lookup_list, host, service, + hints, addr_info, addr_info_size, + max_info_size); +} + +static wasi_errno_t +wasi_sock_bind(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_addr_t *addr) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + struct addr_pool *addr_pool = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + addr_pool = wasi_ctx_get_addr_pool(module_inst, wasi_ctx); + + return wasi_ssp_sock_bind(curfds, addr_pool, fd, addr); +} + +static wasi_errno_t +wasi_sock_close(wasm_exec_env_t exec_env, wasi_fd_t fd) +{ + return __WASI_ENOSYS; +} + +static wasi_errno_t +wasi_sock_connect(wasm_exec_env_t exec_env, wasi_fd_t fd, wasi_addr_t *addr) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + struct addr_pool *addr_pool = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + addr_pool = wasi_ctx_get_addr_pool(module_inst, wasi_ctx); + + return wasi_ssp_sock_connect(curfds, addr_pool, fd, addr); +} + +static wasi_errno_t +wasi_sock_get_broadcast(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool *is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_broadcast(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_get_keep_alive(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool *is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_keep_alive(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_get_linger(wasm_exec_env_t exec_env, wasi_fd_t fd, bool *is_enabled, + int *linger_s) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(is_enabled, sizeof(bool)) + || !validate_native_addr(linger_s, sizeof(int))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_linger(curfds, fd, is_enabled, linger_s); +} + +static wasi_errno_t +wasi_sock_get_recv_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, + size_t *size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(size, sizeof(wasi_size_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_recv_buf_size(curfds, fd, size); +} + +static wasi_errno_t +wasi_sock_get_recv_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint64_t *timeout_us) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(timeout_us, sizeof(uint64_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_recv_timeout(curfds, fd, timeout_us); +} + +static wasi_errno_t +wasi_sock_get_reuse_addr(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool *is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_reuse_addr(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_get_reuse_port(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool *is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_reuse_port(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_get_send_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, + size_t *size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(size, sizeof(__wasi_size_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_send_buf_size(curfds, fd, size); +} + +static wasi_errno_t +wasi_sock_get_send_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint64_t *timeout_us) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(timeout_us, sizeof(uint64_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_send_timeout(curfds, fd, timeout_us); +} + +static wasi_errno_t +wasi_sock_get_tcp_fastopen_connect(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool *is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_tcp_fastopen_connect(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_get_tcp_no_delay(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool *is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_tcp_no_delay(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_get_tcp_quick_ack(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool *is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_tcp_quick_ack(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_get_tcp_keep_idle(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint32_t *time_s) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(time_s, sizeof(uint32_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_tcp_keep_idle(curfds, fd, time_s); +} + +static wasi_errno_t +wasi_sock_get_tcp_keep_intvl(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint32_t *time_s) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(time_s, sizeof(uint32_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_tcp_keep_intvl(curfds, fd, time_s); +} + +static wasi_errno_t +wasi_sock_get_ip_multicast_loop(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool ipv6, bool *is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_ip_multicast_loop(curfds, fd, ipv6, + is_enabled); +} + +static wasi_errno_t +wasi_sock_get_ip_ttl(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8_t *ttl_s) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(ttl_s, sizeof(uint8_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_ip_ttl(curfds, fd, ttl_s); +} + +static wasi_errno_t +wasi_sock_get_ip_multicast_ttl(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint8_t *ttl_s) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(ttl_s, sizeof(uint8_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_ip_multicast_ttl(curfds, fd, ttl_s); +} + +static wasi_errno_t +wasi_sock_get_ipv6_only(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool *is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(is_enabled, sizeof(bool))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_get_ipv6_only(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_listen(wasm_exec_env_t exec_env, wasi_fd_t fd, uint32 backlog) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasi_ssp_sock_listen(curfds, fd, backlog); +} + +static wasi_errno_t +wasi_sock_open(wasm_exec_env_t exec_env, wasi_fd_t poolfd, + wasi_address_family_t af, wasi_sock_type_t socktype, + wasi_fd_t *sockfd) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasi_ssp_sock_open(curfds, poolfd, af, socktype, sockfd); +} + +static wasi_errno_t +wasi_sock_set_broadcast(wasm_exec_env_t exec_env, wasi_fd_t fd, bool is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_broadcast(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_set_keep_alive(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_keep_alive(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_set_linger(wasm_exec_env_t exec_env, wasi_fd_t fd, bool is_enabled, + int linger_s) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_linger(curfds, fd, is_enabled, linger_s); +} + +static wasi_errno_t +wasi_sock_set_recv_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, size_t size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_recv_buf_size(curfds, fd, size); +} + +static wasi_errno_t +wasi_sock_set_recv_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint64_t timeout_us) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_recv_timeout(curfds, fd, timeout_us); +} + +static wasi_errno_t +wasi_sock_set_reuse_addr(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_reuse_addr(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_set_reuse_port(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_reuse_port(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_set_send_buf_size(wasm_exec_env_t exec_env, wasi_fd_t fd, size_t size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_send_buf_size(curfds, fd, size); +} + +static wasi_errno_t +wasi_sock_set_send_timeout(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint64_t timeout_us) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_send_timeout(curfds, fd, timeout_us); +} + +static wasi_errno_t +wasi_sock_set_tcp_fastopen_connect(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_tcp_fastopen_connect(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_set_tcp_no_delay(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_tcp_no_delay(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_set_tcp_quick_ack(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_tcp_quick_ack(curfds, fd, is_enabled); +} + +static wasi_errno_t +wasi_sock_set_tcp_keep_idle(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint32_t time_s) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_tcp_keep_idle(curfds, fd, time_s); +} + +static wasi_errno_t +wasi_sock_set_tcp_keep_intvl(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint32_t time_s) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_tcp_keep_intvl(curfds, fd, time_s); +} + +static wasi_errno_t +wasi_sock_set_ip_multicast_loop(wasm_exec_env_t exec_env, wasi_fd_t fd, + bool ipv6, bool is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_ip_multicast_loop(curfds, fd, ipv6, + is_enabled); +} + +static wasi_errno_t +wasi_sock_set_ip_add_membership(wasm_exec_env_t exec_env, wasi_fd_t fd, + __wasi_addr_ip_t *imr_multiaddr, + uint32_t imr_interface) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(imr_multiaddr, sizeof(__wasi_addr_ip_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_ip_add_membership(curfds, fd, imr_multiaddr, + imr_interface); +} + +static wasi_errno_t +wasi_sock_set_ip_drop_membership(wasm_exec_env_t exec_env, wasi_fd_t fd, + __wasi_addr_ip_t *imr_multiaddr, + uint32_t imr_interface) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + if (!validate_native_addr(imr_multiaddr, sizeof(__wasi_addr_ip_t))) + return __WASI_EINVAL; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_ip_drop_membership(curfds, fd, imr_multiaddr, + imr_interface); +} + +static wasi_errno_t +wasi_sock_set_ip_ttl(wasm_exec_env_t exec_env, wasi_fd_t fd, uint8_t ttl_s) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_ip_ttl(curfds, fd, ttl_s); +} + +static wasi_errno_t +wasi_sock_set_ip_multicast_ttl(wasm_exec_env_t exec_env, wasi_fd_t fd, + uint8_t ttl_s) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_ip_multicast_ttl(curfds, fd, ttl_s); +} + +static wasi_errno_t +wasi_sock_set_ipv6_only(wasm_exec_env_t exec_env, wasi_fd_t fd, bool is_enabled) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = NULL; + + if (!wasi_ctx) + return __WASI_EACCES; + + curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + return wasmtime_ssp_sock_set_ipv6_only(curfds, fd, is_enabled); +} + +static wasi_errno_t +allocate_iovec_app_buffer(wasm_module_inst_t module_inst, + const iovec_app_t *data, uint32 data_len, + uint8 **buf_ptr, uint64 *buf_len) +{ + uint64 total_size = 0; + uint32 i; + uint8 *buf_begin = NULL; + + if (data_len == 0) { + return __WASI_EINVAL; + } + + total_size = sizeof(iovec_app_t) * (uint64)data_len; + if (total_size >= UINT32_MAX + || !validate_native_addr((void *)data, (uint32)total_size)) + return __WASI_EINVAL; + + for (total_size = 0, i = 0; i < data_len; i++, data++) { + total_size += data->buf_len; + } + + if (total_size == 0) { + return __WASI_EINVAL; + } + + if (total_size >= UINT32_MAX + || !(buf_begin = wasm_runtime_malloc((uint32)total_size))) { + return __WASI_ENOMEM; + } + + *buf_len = total_size; + *buf_ptr = buf_begin; + + return __WASI_ESUCCESS; +} + +static wasi_errno_t +copy_buffer_to_iovec_app(wasm_module_inst_t module_inst, uint8 *buf_begin, + uint32 buf_size, iovec_app_t *data, uint32 data_len, + uint32 size_to_copy) +{ + uint8 *buf = buf_begin; + uint32 i; + uint32 size_to_copy_into_iovec; + + if (buf_size < size_to_copy) { + return __WASI_EINVAL; + } + + for (i = 0; i < data_len; data++, i++) { + char *native_addr; + + if (!validate_app_addr(data->buf_offset, data->buf_len)) { + return __WASI_EINVAL; + } + + if (buf >= buf_begin + buf_size + || buf + data->buf_len < buf /* integer overflow */ + || buf + data->buf_len > buf_begin + buf_size + || size_to_copy == 0) { + break; + } + + /** + * If our app buffer size is smaller than the amount to be copied, + * only copy the amount in the app buffer. Otherwise, we fill the iovec + * buffer and reduce size to copy on the next iteration + */ + size_to_copy_into_iovec = min_uint32(data->buf_len, size_to_copy); + + native_addr = (void *)addr_app_to_native(data->buf_offset); + bh_memcpy_s(native_addr, size_to_copy_into_iovec, buf, + size_to_copy_into_iovec); + buf += size_to_copy_into_iovec; + size_to_copy -= size_to_copy_into_iovec; + } + + return __WASI_ESUCCESS; +} + +static wasi_errno_t +wasi_sock_recv_from(wasm_exec_env_t exec_env, wasi_fd_t sock, + iovec_app_t *ri_data, uint32 ri_data_len, + wasi_riflags_t ri_flags, __wasi_addr_t *src_addr, + uint32 *ro_data_len) +{ + /** + * ri_data_len is the length of a list of iovec_app_t, which head is + * ri_data. ro_data_len is the number of bytes received + **/ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + uint64 total_size; + uint8 *buf_begin = NULL; + wasi_errno_t err; + size_t recv_bytes = 0; + + if (!wasi_ctx) { + return __WASI_EINVAL; + } + + if (!validate_native_addr(ro_data_len, (uint32)sizeof(uint32))) + return __WASI_EINVAL; + + err = allocate_iovec_app_buffer(module_inst, ri_data, ri_data_len, + &buf_begin, &total_size); + if (err != __WASI_ESUCCESS) { + goto fail; + } + + memset(buf_begin, 0, total_size); + + *ro_data_len = 0; + err = wasmtime_ssp_sock_recv_from(curfds, sock, buf_begin, total_size, + ri_flags, src_addr, &recv_bytes); + if (err != __WASI_ESUCCESS) { + goto fail; + } + *ro_data_len = (uint32)recv_bytes; + + err = copy_buffer_to_iovec_app(module_inst, buf_begin, (uint32)total_size, + ri_data, ri_data_len, (uint32)recv_bytes); + +fail: + if (buf_begin) { + wasm_runtime_free(buf_begin); + } + return err; +} + +static wasi_errno_t +wasi_sock_recv(wasm_exec_env_t exec_env, wasi_fd_t sock, iovec_app_t *ri_data, + uint32 ri_data_len, wasi_riflags_t ri_flags, uint32 *ro_data_len, + wasi_roflags_t *ro_flags) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + __wasi_addr_t src_addr; + wasi_errno_t error; + + if (!validate_native_addr(ro_flags, (uint32)sizeof(wasi_roflags_t))) + return __WASI_EINVAL; + + error = wasi_sock_recv_from(exec_env, sock, ri_data, ri_data_len, ri_flags, + &src_addr, ro_data_len); + *ro_flags = ri_flags; + + return error; +} + +static wasi_errno_t +convert_iovec_app_to_buffer(wasm_module_inst_t module_inst, + const iovec_app_t *si_data, uint32 si_data_len, + uint8 **buf_ptr, uint64 *buf_len) +{ + uint32 i; + const iovec_app_t *si_data_orig = si_data; + uint8 *buf = NULL; + wasi_errno_t error; + + error = allocate_iovec_app_buffer(module_inst, si_data, si_data_len, + buf_ptr, buf_len); + if (error != __WASI_ESUCCESS) { + return error; + } + + buf = *buf_ptr; + si_data = si_data_orig; + for (i = 0; i < si_data_len; i++, si_data++) { + char *native_addr; + + if (!validate_app_addr(si_data->buf_offset, si_data->buf_len)) { + wasm_runtime_free(*buf_ptr); + return __WASI_EINVAL; + } + + native_addr = (char *)addr_app_to_native(si_data->buf_offset); + bh_memcpy_s(buf, si_data->buf_len, native_addr, si_data->buf_len); + buf += si_data->buf_len; + } + + return __WASI_ESUCCESS; +} + +static wasi_errno_t +wasi_sock_send(wasm_exec_env_t exec_env, wasi_fd_t sock, + const iovec_app_t *si_data, uint32 si_data_len, + wasi_siflags_t si_flags, uint32 *so_data_len) +{ + /** + * si_data_len is the length of a list of iovec_app_t, which head is + * si_data. so_data_len is the number of bytes sent + **/ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + uint64 buf_size = 0; + uint8 *buf = NULL; + wasi_errno_t err; + size_t send_bytes = 0; + + if (!wasi_ctx) { + return __WASI_EINVAL; + } + + if (!validate_native_addr(so_data_len, sizeof(uint32))) + return __WASI_EINVAL; + + err = convert_iovec_app_to_buffer(module_inst, si_data, si_data_len, &buf, + &buf_size); + if (err != __WASI_ESUCCESS) + return err; + + *so_data_len = 0; + err = wasmtime_ssp_sock_send(curfds, sock, buf, buf_size, &send_bytes); + *so_data_len = (uint32)send_bytes; + + wasm_runtime_free(buf); + + return err; +} + +static wasi_errno_t +wasi_sock_send_to(wasm_exec_env_t exec_env, wasi_fd_t sock, + const iovec_app_t *si_data, uint32 si_data_len, + wasi_siflags_t si_flags, const __wasi_addr_t *dest_addr, + uint32 *so_data_len) +{ + /** + * si_data_len is the length of a list of iovec_app_t, which head is + * si_data. so_data_len is the number of bytes sent + **/ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + uint64 buf_size = 0; + uint8 *buf = NULL; + wasi_errno_t err; + size_t send_bytes = 0; + struct addr_pool *addr_pool = wasi_ctx_get_addr_pool(module_inst, wasi_ctx); + + if (!wasi_ctx) { + return __WASI_EINVAL; + } + + if (!validate_native_addr(so_data_len, sizeof(uint32))) + return __WASI_EINVAL; + + err = convert_iovec_app_to_buffer(module_inst, si_data, si_data_len, &buf, + &buf_size); + if (err != __WASI_ESUCCESS) + return err; + + *so_data_len = 0; + err = wasmtime_ssp_sock_send_to(curfds, addr_pool, sock, buf, buf_size, + si_flags, dest_addr, &send_bytes); + *so_data_len = (uint32)send_bytes; + + wasm_runtime_free(buf); + + return err; +} + +static wasi_errno_t +wasi_sock_shutdown(wasm_exec_env_t exec_env, wasi_fd_t sock, wasi_sdflags_t how) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); + struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); + + if (!wasi_ctx) + return __WASI_EINVAL; + + return wasmtime_ssp_sock_shutdown(curfds, sock); +} + +static wasi_errno_t +wasi_sched_yield(wasm_exec_env_t exec_env) +{ + return wasmtime_ssp_sched_yield(); +} + +/* clang-format off */ +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, wasi_##func_name, signature, NULL } +/* clang-format on */ + +static NativeSymbol native_symbols_libc_wasi[] = { + REG_NATIVE_FUNC(args_get, "(**)i"), + REG_NATIVE_FUNC(args_sizes_get, "(**)i"), + REG_NATIVE_FUNC(clock_res_get, "(i*)i"), + REG_NATIVE_FUNC(clock_time_get, "(iI*)i"), + REG_NATIVE_FUNC(environ_get, "(**)i"), + REG_NATIVE_FUNC(environ_sizes_get, "(**)i"), + REG_NATIVE_FUNC(fd_prestat_get, "(i*)i"), + REG_NATIVE_FUNC(fd_prestat_dir_name, "(i*~)i"), + REG_NATIVE_FUNC(fd_close, "(i)i"), + REG_NATIVE_FUNC(fd_datasync, "(i)i"), + REG_NATIVE_FUNC(fd_pread, "(i*iI*)i"), + REG_NATIVE_FUNC(fd_pwrite, "(i*iI*)i"), + REG_NATIVE_FUNC(fd_read, "(i*i*)i"), + REG_NATIVE_FUNC(fd_renumber, "(ii)i"), + REG_NATIVE_FUNC(fd_seek, "(iIi*)i"), + REG_NATIVE_FUNC(fd_tell, "(i*)i"), + REG_NATIVE_FUNC(fd_fdstat_get, "(i*)i"), + REG_NATIVE_FUNC(fd_fdstat_set_flags, "(ii)i"), + REG_NATIVE_FUNC(fd_fdstat_set_rights, "(iII)i"), + REG_NATIVE_FUNC(fd_sync, "(i)i"), + REG_NATIVE_FUNC(fd_write, "(i*i*)i"), + REG_NATIVE_FUNC(fd_advise, "(iIIi)i"), + REG_NATIVE_FUNC(fd_allocate, "(iII)i"), + REG_NATIVE_FUNC(path_create_directory, "(i*~)i"), + REG_NATIVE_FUNC(path_link, "(ii*~i*~)i"), + REG_NATIVE_FUNC(path_open, "(ii*~iIIi*)i"), + REG_NATIVE_FUNC(fd_readdir, "(i*~I*)i"), + REG_NATIVE_FUNC(path_readlink, "(i*~*~*)i"), + REG_NATIVE_FUNC(path_rename, "(i*~i*~)i"), + REG_NATIVE_FUNC(fd_filestat_get, "(i*)i"), + REG_NATIVE_FUNC(fd_filestat_set_times, "(iIIi)i"), + REG_NATIVE_FUNC(fd_filestat_set_size, "(iI)i"), + REG_NATIVE_FUNC(path_filestat_get, "(ii*~*)i"), + REG_NATIVE_FUNC(path_filestat_set_times, "(ii*~IIi)i"), + REG_NATIVE_FUNC(path_symlink, "(*~i*~)i"), + REG_NATIVE_FUNC(path_unlink_file, "(i*~)i"), + REG_NATIVE_FUNC(path_remove_directory, "(i*~)i"), + REG_NATIVE_FUNC(poll_oneoff, "(**i*)i"), + REG_NATIVE_FUNC(proc_exit, "(i)"), + REG_NATIVE_FUNC(proc_raise, "(i)i"), + REG_NATIVE_FUNC(random_get, "(*~)i"), + REG_NATIVE_FUNC(sock_accept, "(ii*)i"), + REG_NATIVE_FUNC(sock_addr_local, "(i*)i"), + REG_NATIVE_FUNC(sock_addr_remote, "(i*)i"), + REG_NATIVE_FUNC(sock_addr_resolve, "($$**i*)i"), + REG_NATIVE_FUNC(sock_bind, "(i*)i"), + REG_NATIVE_FUNC(sock_close, "(i)i"), + REG_NATIVE_FUNC(sock_connect, "(i*)i"), + REG_NATIVE_FUNC(sock_get_broadcast, "(i*)i"), + REG_NATIVE_FUNC(sock_get_keep_alive, "(i*)i"), + REG_NATIVE_FUNC(sock_get_linger, "(i**)i"), + REG_NATIVE_FUNC(sock_get_recv_buf_size, "(i*)i"), + REG_NATIVE_FUNC(sock_get_recv_timeout, "(i*)i"), + REG_NATIVE_FUNC(sock_get_reuse_addr, "(i*)i"), + REG_NATIVE_FUNC(sock_get_reuse_port, "(i*)i"), + REG_NATIVE_FUNC(sock_get_send_buf_size, "(i*)i"), + REG_NATIVE_FUNC(sock_get_send_timeout, "(i*)i"), + REG_NATIVE_FUNC(sock_get_tcp_fastopen_connect, "(i*)i"), + REG_NATIVE_FUNC(sock_get_tcp_keep_idle, "(i*)i"), + REG_NATIVE_FUNC(sock_get_tcp_keep_intvl, "(i*)i"), + REG_NATIVE_FUNC(sock_get_tcp_no_delay, "(i*)i"), + REG_NATIVE_FUNC(sock_get_tcp_quick_ack, "(i*)i"), + REG_NATIVE_FUNC(sock_get_ip_multicast_loop, "(ii*)i"), + REG_NATIVE_FUNC(sock_get_ip_multicast_ttl, "(i*)i"), + REG_NATIVE_FUNC(sock_get_ip_ttl, "(i*)i"), + REG_NATIVE_FUNC(sock_get_ipv6_only, "(i*)i"), + REG_NATIVE_FUNC(sock_listen, "(ii)i"), + REG_NATIVE_FUNC(sock_open, "(iii*)i"), + REG_NATIVE_FUNC(sock_recv, "(i*ii**)i"), + REG_NATIVE_FUNC(sock_recv_from, "(i*ii**)i"), + REG_NATIVE_FUNC(sock_send, "(i*ii*)i"), + REG_NATIVE_FUNC(sock_send_to, "(i*ii**)i"), + REG_NATIVE_FUNC(sock_set_broadcast, "(ii)i"), + REG_NATIVE_FUNC(sock_set_keep_alive, "(ii)i"), + REG_NATIVE_FUNC(sock_set_linger, "(iii)i"), + REG_NATIVE_FUNC(sock_set_recv_buf_size, "(ii)i"), + REG_NATIVE_FUNC(sock_set_recv_timeout, "(iI)i"), + REG_NATIVE_FUNC(sock_set_reuse_addr, "(ii)i"), + REG_NATIVE_FUNC(sock_set_reuse_port, "(ii)i"), + REG_NATIVE_FUNC(sock_set_send_buf_size, "(ii)i"), + REG_NATIVE_FUNC(sock_set_send_timeout, "(iI)i"), + REG_NATIVE_FUNC(sock_set_tcp_fastopen_connect, "(ii)i"), + REG_NATIVE_FUNC(sock_set_tcp_keep_idle, "(ii)i"), + REG_NATIVE_FUNC(sock_set_tcp_keep_intvl, "(ii)i"), + REG_NATIVE_FUNC(sock_set_tcp_no_delay, "(ii)i"), + REG_NATIVE_FUNC(sock_set_tcp_quick_ack, "(ii)i"), + REG_NATIVE_FUNC(sock_set_ip_multicast_loop, "(iii)i"), + REG_NATIVE_FUNC(sock_set_ip_multicast_ttl, "(ii)i"), + REG_NATIVE_FUNC(sock_set_ip_add_membership, "(i*i)i"), + REG_NATIVE_FUNC(sock_set_ip_drop_membership, "(i*i)i"), + REG_NATIVE_FUNC(sock_set_ip_ttl, "(ii)i"), + REG_NATIVE_FUNC(sock_set_ipv6_only, "(ii)i"), + REG_NATIVE_FUNC(sock_shutdown, "(ii)i"), + REG_NATIVE_FUNC(sched_yield, "()i"), +}; + +uint32 +get_libc_wasi_export_apis(NativeSymbol **p_libc_wasi_apis) +{ + *p_libc_wasi_apis = native_symbols_libc_wasi; + return sizeof(native_symbols_libc_wasi) / sizeof(NativeSymbol); +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h new file mode 100644 index 000000000..be509576b --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _LIBC_WASI_WRAPPER_H +#define _LIBC_WASI_WRAPPER_H + +#include "wasmtime_ssp.h" +#include "posix.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef __wasi_address_family_t wasi_address_family_t; +typedef __wasi_addr_t wasi_addr_t; +typedef __wasi_advice_t wasi_advice_t; +typedef __wasi_ciovec_t wasi_ciovec_t; +typedef __wasi_clockid_t wasi_clockid_t; +typedef __wasi_dircookie_t wasi_dircookie_t; +typedef __wasi_errno_t wasi_errno_t; +typedef __wasi_event_t wasi_event_t; +typedef __wasi_exitcode_t wasi_exitcode_t; +typedef __wasi_fdflags_t wasi_fdflags_t; +typedef __wasi_fdstat_t wasi_fdstat_t; +typedef __wasi_fd_t wasi_fd_t; +typedef __wasi_filedelta_t wasi_filedelta_t; +typedef __wasi_filesize_t wasi_filesize_t; +typedef __wasi_filestat_t wasi_filestat_t; +typedef __wasi_filetype_t wasi_filetype_t; +typedef __wasi_fstflags_t wasi_fstflags_t; +typedef __wasi_iovec_t wasi_iovec_t; +typedef __wasi_ip_port_t wasi_ip_port_t; +typedef __wasi_lookupflags_t wasi_lookupflags_t; +typedef __wasi_oflags_t wasi_oflags_t; +typedef __wasi_preopentype_t wasi_preopentype_t; +typedef __wasi_prestat_t wasi_prestat_t; +typedef __wasi_riflags_t wasi_riflags_t; +typedef __wasi_rights_t wasi_rights_t; +typedef __wasi_roflags_t wasi_roflags_t; +typedef __wasi_sdflags_t wasi_sdflags_t; +typedef __wasi_siflags_t wasi_siflags_t; +typedef __wasi_signal_t wasi_signal_t; +typedef __wasi_size_t wasi_size_t; +typedef __wasi_sock_type_t wasi_sock_type_t; +typedef __wasi_subscription_t wasi_subscription_t; +typedef __wasi_timestamp_t wasi_timestamp_t; +typedef __wasi_whence_t wasi_whence_t; + +#ifdef __cplusplus +} +#endif + +#endif /* end of _LIBC_WASI_WRAPPER_H */
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/LICENSE b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/LICENSE new file mode 100644 index 000000000..83386f80a --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/LICENSE @@ -0,0 +1,7 @@ +Please see the LICENSE file in each top-level directory for the terms applicable to that directory and its relative sub-directories. + +The relevant directories and licenses are: + +src/ - BSD-2-Clause; see src/LICENSE for details +include/ - CC0 1.0 Universal (CC0 1.0) Public Domain Dedication +polyfill/clang/ - MIT; see the header of polyfill/clang/stdatomic.h for details diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/LICENSE b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/LICENSE new file mode 100644 index 000000000..0e259d42c --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/LICENSE @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h new file mode 100644 index 000000000..feadf2f95 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h @@ -0,0 +1,1508 @@ +/* + * Part of the Wasmtime Project, under the Apache License v2.0 with + * LLVM Exceptions. See + * https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE + * for license information. + * + * This file declares an interface similar to WASI, but augmented to expose + * some implementation details such as the curfds arguments that we pass + * around to avoid storing them in TLS. + */ + +/** + * The defitions of type, macro and structure in this file should be + * consistent with those in wasi-libc: + * https://github.com/WebAssembly/wasi-libc/blob/main/libc-bottom-half/headers/public/wasi/api.h + */ + +#ifndef WASMTIME_SSP_H +#define WASMTIME_SSP_H + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +/* clang-format off */ + +#ifdef __cplusplus +#ifndef _Static_assert +#define _Static_assert static_assert +#endif /* _Static_assert */ + +#ifndef _Alignof +#define _Alignof alignof +#endif /* _Alignof */ + +#ifndef _Noreturn +#define _Noreturn [[ noreturn ]] +#endif /* _Noreturn */ +extern "C" { +#endif + +_Static_assert(_Alignof(int8_t) == 1, "non-wasi data layout"); +_Static_assert(_Alignof(uint8_t) == 1, "non-wasi data layout"); +_Static_assert(_Alignof(int16_t) == 2, "non-wasi data layout"); +_Static_assert(_Alignof(uint16_t) == 2, "non-wasi data layout"); +_Static_assert(_Alignof(int32_t) == 4, "non-wasi data layout"); +_Static_assert(_Alignof(uint32_t) == 4, "non-wasi data layout"); +#if 0 +_Static_assert(_Alignof(int64_t) == 8, "non-wasi data layout"); +_Static_assert(_Alignof(uint64_t) == 8, "non-wasi data layout"); +#endif + +typedef uint32_t __wasi_size_t; +_Static_assert(_Alignof(__wasi_size_t) == 4, "non-wasi data layout"); + +typedef uint8_t __wasi_advice_t; +#define __WASI_ADVICE_NORMAL (0) +#define __WASI_ADVICE_SEQUENTIAL (1) +#define __WASI_ADVICE_RANDOM (2) +#define __WASI_ADVICE_WILLNEED (3) +#define __WASI_ADVICE_DONTNEED (4) +#define __WASI_ADVICE_NOREUSE (5) + +typedef uint32_t __wasi_clockid_t; +#define __WASI_CLOCK_REALTIME (0) +#define __WASI_CLOCK_MONOTONIC (1) +#define __WASI_CLOCK_PROCESS_CPUTIME_ID (2) +#define __WASI_CLOCK_THREAD_CPUTIME_ID (3) + +typedef uint64_t __wasi_device_t; + +typedef uint64_t __wasi_dircookie_t; +#define __WASI_DIRCOOKIE_START (0) + +typedef uint32_t __wasi_dirnamlen_t; + +typedef uint16_t __wasi_errno_t; +#define __WASI_ESUCCESS (0) +#define __WASI_E2BIG (1) +#define __WASI_EACCES (2) +#define __WASI_EADDRINUSE (3) +#define __WASI_EADDRNOTAVAIL (4) +#define __WASI_EAFNOSUPPORT (5) +#define __WASI_EAGAIN (6) +#define __WASI_EALREADY (7) +#define __WASI_EBADF (8) +#define __WASI_EBADMSG (9) +#define __WASI_EBUSY (10) +#define __WASI_ECANCELED (11) +#define __WASI_ECHILD (12) +#define __WASI_ECONNABORTED (13) +#define __WASI_ECONNREFUSED (14) +#define __WASI_ECONNRESET (15) +#define __WASI_EDEADLK (16) +#define __WASI_EDESTADDRREQ (17) +#define __WASI_EDOM (18) +#define __WASI_EDQUOT (19) +#define __WASI_EEXIST (20) +#define __WASI_EFAULT (21) +#define __WASI_EFBIG (22) +#define __WASI_EHOSTUNREACH (23) +#define __WASI_EIDRM (24) +#define __WASI_EILSEQ (25) +#define __WASI_EINPROGRESS (26) +#define __WASI_EINTR (27) +#define __WASI_EINVAL (28) +#define __WASI_EIO (29) +#define __WASI_EISCONN (30) +#define __WASI_EISDIR (31) +#define __WASI_ELOOP (32) +#define __WASI_EMFILE (33) +#define __WASI_EMLINK (34) +#define __WASI_EMSGSIZE (35) +#define __WASI_EMULTIHOP (36) +#define __WASI_ENAMETOOLONG (37) +#define __WASI_ENETDOWN (38) +#define __WASI_ENETRESET (39) +#define __WASI_ENETUNREACH (40) +#define __WASI_ENFILE (41) +#define __WASI_ENOBUFS (42) +#define __WASI_ENODEV (43) +#define __WASI_ENOENT (44) +#define __WASI_ENOEXEC (45) +#define __WASI_ENOLCK (46) +#define __WASI_ENOLINK (47) +#define __WASI_ENOMEM (48) +#define __WASI_ENOMSG (49) +#define __WASI_ENOPROTOOPT (50) +#define __WASI_ENOSPC (51) +#define __WASI_ENOSYS (52) +#define __WASI_ENOTCONN (53) +#define __WASI_ENOTDIR (54) +#define __WASI_ENOTEMPTY (55) +#define __WASI_ENOTRECOVERABLE (56) +#define __WASI_ENOTSOCK (57) +#define __WASI_ENOTSUP (58) +#define __WASI_ENOTTY (59) +#define __WASI_ENXIO (60) +#define __WASI_EOVERFLOW (61) +#define __WASI_EOWNERDEAD (62) +#define __WASI_EPERM (63) +#define __WASI_EPIPE (64) +#define __WASI_EPROTO (65) +#define __WASI_EPROTONOSUPPORT (66) +#define __WASI_EPROTOTYPE (67) +#define __WASI_ERANGE (68) +#define __WASI_EROFS (69) +#define __WASI_ESPIPE (70) +#define __WASI_ESRCH (71) +#define __WASI_ESTALE (72) +#define __WASI_ETIMEDOUT (73) +#define __WASI_ETXTBSY (74) +#define __WASI_EXDEV (75) +#define __WASI_ENOTCAPABLE (76) + +typedef uint16_t __wasi_eventrwflags_t; +#define __WASI_EVENT_FD_READWRITE_HANGUP (0x0001) + +typedef uint8_t __wasi_eventtype_t; +#define __WASI_EVENTTYPE_CLOCK (0) +#define __WASI_EVENTTYPE_FD_READ (1) +#define __WASI_EVENTTYPE_FD_WRITE (2) + +typedef uint32_t __wasi_exitcode_t; + +typedef uint32_t __wasi_fd_t; + +typedef uint16_t __wasi_fdflags_t; +#define __WASI_FDFLAG_APPEND (0x0001) +#define __WASI_FDFLAG_DSYNC (0x0002) +#define __WASI_FDFLAG_NONBLOCK (0x0004) +#define __WASI_FDFLAG_RSYNC (0x0008) +#define __WASI_FDFLAG_SYNC (0x0010) + +typedef int64_t __wasi_filedelta_t; + +typedef uint64_t __wasi_filesize_t; + +typedef uint8_t __wasi_filetype_t; +#define __WASI_FILETYPE_UNKNOWN (0) +#define __WASI_FILETYPE_BLOCK_DEVICE (1) +#define __WASI_FILETYPE_CHARACTER_DEVICE (2) +#define __WASI_FILETYPE_DIRECTORY (3) +#define __WASI_FILETYPE_REGULAR_FILE (4) +#define __WASI_FILETYPE_SOCKET_DGRAM (5) +#define __WASI_FILETYPE_SOCKET_STREAM (6) +#define __WASI_FILETYPE_SYMBOLIC_LINK (7) + +typedef uint16_t __wasi_fstflags_t; +#define __WASI_FILESTAT_SET_ATIM (0x0001) +#define __WASI_FILESTAT_SET_ATIM_NOW (0x0002) +#define __WASI_FILESTAT_SET_MTIM (0x0004) +#define __WASI_FILESTAT_SET_MTIM_NOW (0x0008) + +typedef uint64_t __wasi_inode_t; + +typedef uint64_t __wasi_linkcount_t __attribute__((aligned(8))); + +typedef uint32_t __wasi_lookupflags_t; +#define __WASI_LOOKUP_SYMLINK_FOLLOW (0x00000001) + +typedef uint16_t __wasi_oflags_t; +#define __WASI_O_CREAT (0x0001) +#define __WASI_O_DIRECTORY (0x0002) +#define __WASI_O_EXCL (0x0004) +#define __WASI_O_TRUNC (0x0008) + +typedef uint16_t __wasi_riflags_t; +#define __WASI_SOCK_RECV_PEEK (0x0001) +#define __WASI_SOCK_RECV_WAITALL (0x0002) + +typedef uint64_t __wasi_rights_t; + +/** + * Observe that WASI defines rights in the plural form + * TODO: refactor to use RIGHTS instead of RIGHT + */ +#define __WASI_RIGHT_FD_DATASYNC ((__wasi_rights_t)(UINT64_C(1) << 0)) +#define __WASI_RIGHT_FD_READ ((__wasi_rights_t)(UINT64_C(1) << 1)) +#define __WASI_RIGHT_FD_SEEK ((__wasi_rights_t)(UINT64_C(1) << 2)) +#define __WASI_RIGHT_FD_FDSTAT_SET_FLAGS ((__wasi_rights_t)(UINT64_C(1) << 3)) +#define __WASI_RIGHT_FD_SYNC ((__wasi_rights_t)(UINT64_C(1) << 4)) +#define __WASI_RIGHT_FD_TELL ((__wasi_rights_t)(UINT64_C(1) << 5)) +#define __WASI_RIGHT_FD_WRITE ((__wasi_rights_t)(UINT64_C(1) << 6)) +#define __WASI_RIGHT_FD_ADVISE ((__wasi_rights_t)(UINT64_C(1) << 7)) +#define __WASI_RIGHT_FD_ALLOCATE ((__wasi_rights_t)(UINT64_C(1) << 8)) +#define __WASI_RIGHT_PATH_CREATE_DIRECTORY ((__wasi_rights_t)(UINT64_C(1) << 9)) +#define __WASI_RIGHT_PATH_CREATE_FILE ((__wasi_rights_t)(UINT64_C(1) << 10)) +#define __WASI_RIGHT_PATH_LINK_SOURCE ((__wasi_rights_t)(UINT64_C(1) << 11)) +#define __WASI_RIGHT_PATH_LINK_TARGET ((__wasi_rights_t)(UINT64_C(1) << 12)) +#define __WASI_RIGHT_PATH_OPEN ((__wasi_rights_t)(UINT64_C(1) << 13)) +#define __WASI_RIGHT_FD_READDIR ((__wasi_rights_t)(UINT64_C(1) << 14)) +#define __WASI_RIGHT_PATH_READLINK ((__wasi_rights_t)(UINT64_C(1) << 15)) +#define __WASI_RIGHT_PATH_RENAME_SOURCE ((__wasi_rights_t)(UINT64_C(1) << 16)) +#define __WASI_RIGHT_PATH_RENAME_TARGET ((__wasi_rights_t)(UINT64_C(1) << 17)) +#define __WASI_RIGHT_PATH_FILESTAT_GET ((__wasi_rights_t)(UINT64_C(1) << 18)) +#define __WASI_RIGHT_PATH_FILESTAT_SET_SIZE ((__wasi_rights_t)(UINT64_C(1) << 19)) +#define __WASI_RIGHT_PATH_FILESTAT_SET_TIMES ((__wasi_rights_t)(UINT64_C(1) << 20)) +#define __WASI_RIGHT_FD_FILESTAT_GET ((__wasi_rights_t)(UINT64_C(1) << 21)) +#define __WASI_RIGHT_FD_FILESTAT_SET_SIZE ((__wasi_rights_t)(UINT64_C(1) << 22)) +#define __WASI_RIGHT_FD_FILESTAT_SET_TIMES ((__wasi_rights_t)(UINT64_C(1) << 23)) +#define __WASI_RIGHT_PATH_SYMLINK ((__wasi_rights_t)(UINT64_C(1) << 24)) +#define __WASI_RIGHT_PATH_REMOVE_DIRECTORY ((__wasi_rights_t)(UINT64_C(1) << 25)) +#define __WASI_RIGHT_PATH_UNLINK_FILE ((__wasi_rights_t)(UINT64_C(1) << 26)) +#define __WASI_RIGHT_POLL_FD_READWRITE ((__wasi_rights_t)(UINT64_C(1) << 27)) +#define __WASI_RIGHT_SOCK_CONNECT ((__wasi_rights_t)(UINT64_C(1) << 28)) +#define __WASI_RIGHT_SOCK_LISTEN ((__wasi_rights_t)(UINT64_C(1) << 29)) +#define __WASI_RIGHT_SOCK_BIND ((__wasi_rights_t)(UINT64_C(1) << 30)) +#define __WASI_RIGHT_SOCK_ACCEPT ((__wasi_rights_t)(UINT64_C(1) << 31)) +#define __WASI_RIGHT_SOCK_RECV ((__wasi_rights_t)(UINT64_C(1) << 32)) +#define __WASI_RIGHT_SOCK_SEND ((__wasi_rights_t)(UINT64_C(1) << 33)) +#define __WASI_RIGHT_SOCK_ADDR_LOCAL ((__wasi_rights_t)(UINT64_C(1) << 34)) +#define __WASI_RIGHT_SOCK_ADDR_REMOTE ((__wasi_rights_t)(UINT64_C(1) << 35)) +#define __WASI_RIGHT_SOCK_RECV_FROM ((__wasi_rights_t)(UINT64_C(1) << 36)) +#define __WASI_RIGHT_SOCK_SEND_TO ((__wasi_rights_t)(UINT64_C(1) << 37)) + +typedef uint16_t __wasi_roflags_t; +#define __WASI_SOCK_RECV_DATA_TRUNCATED (0x0001) + +typedef uint8_t __wasi_sdflags_t; +#define __WASI_SHUT_RD (0x01) +#define __WASI_SHUT_WR (0x02) + +typedef uint16_t __wasi_siflags_t; + +typedef uint8_t __wasi_signal_t; +// 0 is reserved; POSIX has special semantics for kill(pid, 0). +#define __WASI_SIGHUP (1) +#define __WASI_SIGINT (2) +#define __WASI_SIGQUIT (3) +#define __WASI_SIGILL (4) +#define __WASI_SIGTRAP (5) +#define __WASI_SIGABRT (6) +#define __WASI_SIGBUS (7) +#define __WASI_SIGFPE (8) +#define __WASI_SIGKILL (9) +#define __WASI_SIGUSR1 (10) +#define __WASI_SIGSEGV (11) +#define __WASI_SIGUSR2 (12) +#define __WASI_SIGPIPE (13) +#define __WASI_SIGALRM (14) +#define __WASI_SIGTERM (15) +#define __WASI_SIGCHLD (16) +#define __WASI_SIGCONT (17) +#define __WASI_SIGSTOP (18) +#define __WASI_SIGTSTP (19) +#define __WASI_SIGTTIN (20) +#define __WASI_SIGTTOU (21) +#define __WASI_SIGURG (22) +#define __WASI_SIGXCPU (23) +#define __WASI_SIGXFSZ (24) +#define __WASI_SIGVTALRM (25) +#define __WASI_SIGPROF (26) +#define __WASI_SIGWINCH (27) +#define __WASI_SIGPOLL (28) +#define __WASI_SIGPWR (29) +#define __WASI_SIGSYS (30) + +typedef uint16_t __wasi_subclockflags_t; +#define __WASI_SUBSCRIPTION_CLOCK_ABSTIME (0x0001) + +typedef uint64_t __wasi_timestamp_t; + +typedef uint64_t __wasi_userdata_t; + +typedef uint8_t __wasi_whence_t; +#define __WASI_WHENCE_SET (0) +#define __WASI_WHENCE_CUR (1) +#define __WASI_WHENCE_END (2) + +typedef uint8_t __wasi_preopentype_t; +#define __WASI_PREOPENTYPE_DIR (0) + +struct fd_table; +struct fd_prestats; +struct argv_environ_values; +struct addr_pool; + +typedef struct __wasi_dirent_t { + __wasi_dircookie_t d_next; + __wasi_inode_t d_ino; + __wasi_dirnamlen_t d_namlen; + __wasi_filetype_t d_type; +} __wasi_dirent_t __attribute__((aligned(8))); +_Static_assert(offsetof(__wasi_dirent_t, d_next) == 0, "non-wasi data layout"); +_Static_assert(offsetof(__wasi_dirent_t, d_ino) == 8, "non-wasi data layout"); +_Static_assert(offsetof(__wasi_dirent_t, d_namlen) == 16, "non-wasi data layout"); +_Static_assert(offsetof(__wasi_dirent_t, d_type) == 20, "non-wasi data layout"); +_Static_assert(sizeof(__wasi_dirent_t) == 24, "non-wasi data layout"); +_Static_assert(_Alignof(__wasi_dirent_t) == 8, "non-wasi data layout"); + +typedef struct __wasi_event_t { + __wasi_userdata_t userdata; + __wasi_errno_t error; + __wasi_eventtype_t type; + uint8_t __paddings[5]; + union __wasi_event_u { + struct __wasi_event_u_fd_readwrite_t { + __wasi_filesize_t nbytes; + __wasi_eventrwflags_t flags; + uint8_t __paddings[6]; + } fd_readwrite; + } u; +} __wasi_event_t __attribute__((aligned(8))); +_Static_assert(offsetof(__wasi_event_t, userdata) == 0, "non-wasi data layout"); +_Static_assert(offsetof(__wasi_event_t, error) == 8, "non-wasi data layout"); +_Static_assert(offsetof(__wasi_event_t, type) == 10, "non-wasi data layout"); +_Static_assert( + offsetof(__wasi_event_t, u.fd_readwrite.nbytes) == 16, "non-wasi data layout"); +_Static_assert( + offsetof(__wasi_event_t, u.fd_readwrite.flags) == 24, "non-wasi data layout"); +_Static_assert(sizeof(__wasi_event_t) == 32, "non-wasi data layout"); +_Static_assert(_Alignof(__wasi_event_t) == 8, "non-wasi data layout"); + +typedef struct __wasi_prestat_t { + __wasi_preopentype_t pr_type; + union __wasi_prestat_u { + struct __wasi_prestat_u_dir_t { + size_t pr_name_len; + } dir; + } u; +} __wasi_prestat_t; +_Static_assert(offsetof(__wasi_prestat_t, pr_type) == 0, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 4 || + offsetof(__wasi_prestat_t, u.dir.pr_name_len) == 4, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 8 || + offsetof(__wasi_prestat_t, u.dir.pr_name_len) == 8, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 4 || + sizeof(__wasi_prestat_t) == 8, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 8 || + sizeof(__wasi_prestat_t) == 16, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 4 || + _Alignof(__wasi_prestat_t) == 4, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 8 || + _Alignof(__wasi_prestat_t) == 8, "non-wasi data layout"); + +typedef struct __wasi_fdstat_t { + __wasi_filetype_t fs_filetype; + __wasi_fdflags_t fs_flags; + uint8_t __paddings[4]; + __wasi_rights_t fs_rights_base; + __wasi_rights_t fs_rights_inheriting; +} __wasi_fdstat_t __attribute__((aligned(8))); +_Static_assert( + offsetof(__wasi_fdstat_t, fs_filetype) == 0, "non-wasi data layout"); +_Static_assert(offsetof(__wasi_fdstat_t, fs_flags) == 2, "non-wasi data layout"); +_Static_assert( + offsetof(__wasi_fdstat_t, fs_rights_base) == 8, "non-wasi data layout"); +_Static_assert( + offsetof(__wasi_fdstat_t, fs_rights_inheriting) == 16, + "non-wasi data layout"); +_Static_assert(sizeof(__wasi_fdstat_t) == 24, "non-wasi data layout"); +_Static_assert(_Alignof(__wasi_fdstat_t) == 8, "non-wasi data layout"); + +typedef struct __wasi_filestat_t { + __wasi_device_t st_dev; + __wasi_inode_t st_ino; + __wasi_filetype_t st_filetype; + __wasi_linkcount_t st_nlink; + __wasi_filesize_t st_size; + __wasi_timestamp_t st_atim; + __wasi_timestamp_t st_mtim; + __wasi_timestamp_t st_ctim; +} __wasi_filestat_t __attribute__((aligned(8))); +_Static_assert(offsetof(__wasi_filestat_t, st_dev) == 0, "non-wasi data layout"); +_Static_assert(offsetof(__wasi_filestat_t, st_ino) == 8, "non-wasi data layout"); +_Static_assert( + offsetof(__wasi_filestat_t, st_filetype) == 16, "non-wasi data layout"); +_Static_assert( + offsetof(__wasi_filestat_t, st_nlink) == 24, "non-wasi data layout"); +_Static_assert( + offsetof(__wasi_filestat_t, st_size) == 32, "non-wasi data layout"); +_Static_assert( + offsetof(__wasi_filestat_t, st_atim) == 40, "non-wasi data layout"); +_Static_assert( + offsetof(__wasi_filestat_t, st_mtim) == 48, "non-wasi data layout"); +_Static_assert( + offsetof(__wasi_filestat_t, st_ctim) == 56, "non-wasi data layout"); +_Static_assert(sizeof(__wasi_filestat_t) == 64, "non-wasi data layout"); +_Static_assert(_Alignof(__wasi_filestat_t) == 8, "non-wasi data layout"); + +typedef struct __wasi_ciovec_t { + const void *buf; + size_t buf_len; +} __wasi_ciovec_t; +_Static_assert(offsetof(__wasi_ciovec_t, buf) == 0, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 4 || + offsetof(__wasi_ciovec_t, buf_len) == 4, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 8 || + offsetof(__wasi_ciovec_t, buf_len) == 8, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 4 || + sizeof(__wasi_ciovec_t) == 8, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 8 || + sizeof(__wasi_ciovec_t) == 16, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 4 || + _Alignof(__wasi_ciovec_t) == 4, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 8 || + _Alignof(__wasi_ciovec_t) == 8, "non-wasi data layout"); + +typedef struct __wasi_iovec_t { + void *buf; + size_t buf_len; +} __wasi_iovec_t; +_Static_assert(offsetof(__wasi_iovec_t, buf) == 0, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 4 || + offsetof(__wasi_iovec_t, buf_len) == 4, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 8 || + offsetof(__wasi_iovec_t, buf_len) == 8, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 4 || + sizeof(__wasi_iovec_t) == 8, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 8 || + sizeof(__wasi_iovec_t) == 16, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 4 || + _Alignof(__wasi_iovec_t) == 4, "non-wasi data layout"); +_Static_assert(sizeof(void *) != 8 || + _Alignof(__wasi_iovec_t) == 8, "non-wasi data layout"); + +/** + * The contents of a `subscription` when type is `eventtype::clock`. + */ +typedef struct __wasi_subscription_clock_t { + /** + * The clock against which to compare the timestamp. + */ + __wasi_clockid_t clock_id; + + uint8_t __paddings1[4]; + + /** + * The absolute or relative timestamp. + */ + __wasi_timestamp_t timeout; + + /** + * The amount of time that the implementation may wait additionally + * to coalesce with other events. + */ + __wasi_timestamp_t precision; + + /** + * Flags specifying whether the timeout is absolute or relative + */ + __wasi_subclockflags_t flags; + + uint8_t __paddings2[4]; + +} __wasi_subscription_clock_t __attribute__((aligned(8))); + +_Static_assert(sizeof(__wasi_subscription_clock_t) == 32, "witx calculated size"); +_Static_assert(_Alignof(__wasi_subscription_clock_t) == 8, "witx calculated align"); +_Static_assert(offsetof(__wasi_subscription_clock_t, clock_id) == 0, "witx calculated offset"); +_Static_assert(offsetof(__wasi_subscription_clock_t, timeout) == 8, "witx calculated offset"); +_Static_assert(offsetof(__wasi_subscription_clock_t, precision) == 16, "witx calculated offset"); +_Static_assert(offsetof(__wasi_subscription_clock_t, flags) == 24, "witx calculated offset"); + +/** + * The contents of a `subscription` when type is type is + * `eventtype::fd_read` or `eventtype::fd_write`. + */ +typedef struct __wasi_subscription_fd_readwrite_t { + /** + * The file descriptor on which to wait for it to become ready for reading or writing. + */ + __wasi_fd_t fd; + +} __wasi_subscription_fd_readwrite_t; + +_Static_assert(sizeof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated size"); +_Static_assert(_Alignof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated align"); +_Static_assert(offsetof(__wasi_subscription_fd_readwrite_t, fd) == 0, "witx calculated offset"); + +/** + * The contents of a `subscription`. + */ +typedef union __wasi_subscription_u_u_t { + __wasi_subscription_clock_t clock; + __wasi_subscription_fd_readwrite_t fd_readwrite; +} __wasi_subscription_u_u_t ; + +typedef struct __wasi_subscription_u_t { + __wasi_eventtype_t type; + __wasi_subscription_u_u_t u; +} __wasi_subscription_u_t __attribute__((aligned(8))); + +_Static_assert(sizeof(__wasi_subscription_u_t) == 40, "witx calculated size"); +_Static_assert(_Alignof(__wasi_subscription_u_t) == 8, "witx calculated align"); +_Static_assert(offsetof(__wasi_subscription_u_t, u) == 8, "witx calculated union offset"); +_Static_assert(sizeof(__wasi_subscription_u_u_t) == 32, "witx calculated union size"); +_Static_assert(_Alignof(__wasi_subscription_u_u_t) == 8, "witx calculated union align"); + +/** + * Subscription to an event. + */ +typedef struct __wasi_subscription_t { + /** + * User-provided value that is attached to the subscription in the + * implementation and returned through `event::userdata`. + */ + __wasi_userdata_t userdata; + + /** + * The type of the event to which to subscribe, and its contents + */ + __wasi_subscription_u_t u; + +} __wasi_subscription_t; + +_Static_assert(sizeof(__wasi_subscription_t) == 48, "witx calculated size"); +_Static_assert(_Alignof(__wasi_subscription_t) == 8, "witx calculated align"); +_Static_assert(offsetof(__wasi_subscription_t, userdata) == 0, "witx calculated offset"); +_Static_assert(offsetof(__wasi_subscription_t, u) == 8, "witx calculated offset"); + +/* keep syncing with wasi_socket_ext.h */ +typedef enum { + SOCKET_DGRAM = 0, + SOCKET_STREAM, +} __wasi_sock_type_t; + +typedef uint16_t __wasi_ip_port_t; + +typedef enum { IPv4 = 0, IPv6 } __wasi_addr_type_t; + +/* n0.n1.n2.n3 */ +typedef struct __wasi_addr_ip4_t { + uint8_t n0; + uint8_t n1; + uint8_t n2; + uint8_t n3; +} __wasi_addr_ip4_t; + +typedef struct __wasi_addr_ip4_port_t { + __wasi_addr_ip4_t addr; + __wasi_ip_port_t port; +} __wasi_addr_ip4_port_t; + +typedef struct __wasi_addr_ip6_t { + uint16_t n0; + uint16_t n1; + uint16_t n2; + uint16_t n3; + uint16_t h0; + uint16_t h1; + uint16_t h2; + uint16_t h3; +} __wasi_addr_ip6_t; + +typedef struct __wasi_addr_ip6_port_t { + __wasi_addr_ip6_t addr; + __wasi_ip_port_t port; +} __wasi_addr_ip6_port_t; + +typedef struct __wasi_addr_ip_t { + __wasi_addr_type_t kind; + union { + __wasi_addr_ip4_t ip4; + __wasi_addr_ip6_t ip6; + } addr; +} __wasi_addr_ip_t; + +typedef struct __wasi_addr_t { + __wasi_addr_type_t kind; + union { + __wasi_addr_ip4_port_t ip4; + __wasi_addr_ip6_port_t ip6; + } addr; +} __wasi_addr_t; + +typedef enum { INET4 = 0, INET6 } __wasi_address_family_t; + +typedef struct __wasi_addr_info_t { + __wasi_addr_t addr; + __wasi_sock_type_t type; +} __wasi_addr_info_t; + +typedef struct __wasi_addr_info_hints_t { + __wasi_sock_type_t type; + __wasi_address_family_t family; + // this is to workaround lack of optional parameters + uint8_t hints_enabled; +} __wasi_addr_info_hints_t; + +#if defined(WASMTIME_SSP_WASI_API) +#define WASMTIME_SSP_SYSCALL_NAME(name) \ + asm("__wasi_" #name) +#else +#define WASMTIME_SSP_SYSCALL_NAME(name) +#endif + +__wasi_errno_t wasmtime_ssp_args_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct argv_environ_values *arg_environ, +#endif + char **argv, + char *argv_buf +) WASMTIME_SSP_SYSCALL_NAME(args_get) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_args_sizes_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct argv_environ_values *arg_environ, +#endif + size_t *argc, + size_t *argv_buf_size +) WASMTIME_SSP_SYSCALL_NAME(args_sizes_get) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_clock_res_get( + __wasi_clockid_t clock_id, + __wasi_timestamp_t *resolution +) WASMTIME_SSP_SYSCALL_NAME(clock_res_get) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_clock_time_get( + __wasi_clockid_t clock_id, + __wasi_timestamp_t precision, + __wasi_timestamp_t *time +) WASMTIME_SSP_SYSCALL_NAME(clock_time_get) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_environ_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct argv_environ_values *arg_environ, +#endif + char **environ, + char *environ_buf +) WASMTIME_SSP_SYSCALL_NAME(environ_get) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_environ_sizes_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct argv_environ_values *arg_environ, +#endif + size_t *environ_count, + size_t *environ_buf_size +) WASMTIME_SSP_SYSCALL_NAME(environ_sizes_get) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_prestat_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_prestats *prestats, +#endif + __wasi_fd_t fd, + __wasi_prestat_t *buf +) WASMTIME_SSP_SYSCALL_NAME(fd_prestat_get) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_prestat_dir_name( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_prestats *prestats, +#endif + __wasi_fd_t fd, + char *path, + size_t path_len +) WASMTIME_SSP_SYSCALL_NAME(fd_prestat_dir_name) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_close( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, + struct fd_prestats *prestats, +#endif + __wasi_fd_t fd +) WASMTIME_SSP_SYSCALL_NAME(fd_close) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_datasync( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd +) WASMTIME_SSP_SYSCALL_NAME(fd_datasync) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_pread( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + const __wasi_iovec_t *iovs, + size_t iovs_len, + __wasi_filesize_t offset, + size_t *nread +) WASMTIME_SSP_SYSCALL_NAME(fd_pread) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_pwrite( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + const __wasi_ciovec_t *iovs, + size_t iovs_len, + __wasi_filesize_t offset, + size_t *nwritten +) WASMTIME_SSP_SYSCALL_NAME(fd_pwrite) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_read( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + const __wasi_iovec_t *iovs, + size_t iovs_len, + size_t *nread +) WASMTIME_SSP_SYSCALL_NAME(fd_read) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_renumber( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, + struct fd_prestats *prestats, +#endif + __wasi_fd_t from, + __wasi_fd_t to +) WASMTIME_SSP_SYSCALL_NAME(fd_renumber) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_seek( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + __wasi_filedelta_t offset, + __wasi_whence_t whence, + __wasi_filesize_t *newoffset +) WASMTIME_SSP_SYSCALL_NAME(fd_seek) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_tell( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + __wasi_filesize_t *newoffset +) WASMTIME_SSP_SYSCALL_NAME(fd_tell) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_fdstat_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + __wasi_fdstat_t *buf +) WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_get) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_fdstat_set_flags( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + __wasi_fdflags_t flags +) WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_set_flags) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_fdstat_set_rights( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting +) WASMTIME_SSP_SYSCALL_NAME(fd_fdstat_set_rights) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_sync( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd +) WASMTIME_SSP_SYSCALL_NAME(fd_sync) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_write( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + const __wasi_ciovec_t *iovs, + size_t iovs_len, + size_t *nwritten +) WASMTIME_SSP_SYSCALL_NAME(fd_write) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_advise( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + __wasi_filesize_t offset, + __wasi_filesize_t len, + __wasi_advice_t advice +) WASMTIME_SSP_SYSCALL_NAME(fd_advise) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_allocate( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + __wasi_filesize_t offset, + __wasi_filesize_t len +) WASMTIME_SSP_SYSCALL_NAME(fd_allocate) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_path_create_directory( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + const char *path, + size_t path_len +) WASMTIME_SSP_SYSCALL_NAME(path_create_directory) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_path_link( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, + struct fd_prestats *prestats, +#endif + __wasi_fd_t old_fd, + __wasi_lookupflags_t old_flags, + const char *old_path, + size_t old_path_len, + __wasi_fd_t new_fd, + const char *new_path, + size_t new_path_len +) WASMTIME_SSP_SYSCALL_NAME(path_link) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_path_open( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t dirfd, + __wasi_lookupflags_t dirflags, + const char *path, + size_t path_len, + __wasi_oflags_t oflags, + __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting, + __wasi_fdflags_t fs_flags, + __wasi_fd_t *fd +) WASMTIME_SSP_SYSCALL_NAME(path_open) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_readdir( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + void *buf, + size_t buf_len, + __wasi_dircookie_t cookie, + size_t *bufused +) WASMTIME_SSP_SYSCALL_NAME(fd_readdir) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_path_readlink( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + const char *path, + size_t path_len, + char *buf, + size_t buf_len, + size_t *bufused +) WASMTIME_SSP_SYSCALL_NAME(path_readlink) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_path_rename( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t old_fd, + const char *old_path, + size_t old_path_len, + __wasi_fd_t new_fd, + const char *new_path, + size_t new_path_len +) WASMTIME_SSP_SYSCALL_NAME(path_rename) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_filestat_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + __wasi_filestat_t *buf +) WASMTIME_SSP_SYSCALL_NAME(fd_filestat_get) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_filestat_set_times( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + __wasi_timestamp_t st_atim, + __wasi_timestamp_t st_mtim, + __wasi_fstflags_t fstflags +) WASMTIME_SSP_SYSCALL_NAME(fd_filestat_set_times) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_fd_filestat_set_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + __wasi_filesize_t st_size +) WASMTIME_SSP_SYSCALL_NAME(fd_filestat_set_size) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_path_filestat_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + __wasi_lookupflags_t flags, + const char *path, + size_t path_len, + __wasi_filestat_t *buf +) WASMTIME_SSP_SYSCALL_NAME(path_filestat_get) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_path_filestat_set_times( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + __wasi_lookupflags_t flags, + const char *path, + size_t path_len, + __wasi_timestamp_t st_atim, + __wasi_timestamp_t st_mtim, + __wasi_fstflags_t fstflags +) WASMTIME_SSP_SYSCALL_NAME(path_filestat_set_times) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_path_symlink( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, + struct fd_prestats *prestats, +#endif + const char *old_path, + size_t old_path_len, + __wasi_fd_t fd, + const char *new_path, + size_t new_path_len +) WASMTIME_SSP_SYSCALL_NAME(path_symlink) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_path_unlink_file( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + const char *path, + size_t path_len +) WASMTIME_SSP_SYSCALL_NAME(path_unlink_file) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_path_remove_directory( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, + const char *path, + size_t path_len +) WASMTIME_SSP_SYSCALL_NAME(path_remove_directory) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_poll_oneoff( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + const __wasi_subscription_t *in, + __wasi_event_t *out, + size_t nsubscriptions, + size_t *nevents +) WASMTIME_SSP_SYSCALL_NAME(poll_oneoff) __attribute__((__warn_unused_result__)); + +#if 0 +/** + * We throw exception in libc-wasi wrapper function wasi_proc_exit() + * but not call this function. + */ +_Noreturn void wasmtime_ssp_proc_exit( + __wasi_exitcode_t rval +) WASMTIME_SSP_SYSCALL_NAME(proc_exit); +#endif + +__wasi_errno_t wasmtime_ssp_proc_raise( + __wasi_signal_t sig +) WASMTIME_SSP_SYSCALL_NAME(proc_raise) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_random_get( + void *buf, + size_t buf_len +) WASMTIME_SSP_SYSCALL_NAME(random_get) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_accept( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_fdflags_t flags, __wasi_fd_t *fd_new +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_addr_local( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_addr_t *addr +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_addr_remote( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_addr_t *addr +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_open( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t poolfd, __wasi_address_family_t af, __wasi_sock_type_t socktype, + __wasi_fd_t *sockfd +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_bind( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct addr_pool *addr_pool, +#endif + __wasi_fd_t fd, __wasi_addr_t *addr +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_addr_resolve( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, char **ns_lookup_list, +#endif + const char *host, const char* service, + __wasi_addr_info_hints_t *hints, __wasi_addr_info_t *addr_info, + __wasi_size_t addr_info_size, __wasi_size_t *max_info_size +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_connect( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct addr_pool *addr_pool, +#endif + __wasi_fd_t fd, __wasi_addr_t *addr +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_get_recv_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t *size +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_get_reuse_addr( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t *reuse +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_get_reuse_port( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t *reuse +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_get_send_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t *size +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_set_recv_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t size +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_set_reuse_addr( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t reuse +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_set_reuse_port( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t reuse +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_set_send_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t size +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_listen( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t backlog +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_recv( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + void *buf, + size_t buf_len, + size_t *recv_len +) WASMTIME_SSP_SYSCALL_NAME(sock_recv) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_recv_from( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + void *buf, + size_t buf_len, + __wasi_riflags_t ri_flags, + __wasi_addr_t *src_addr, + size_t *recv_len +) WASMTIME_SSP_SYSCALL_NAME(sock_recv_from) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_send( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + const void *buf, + size_t buf_len, + size_t *sent_len +) WASMTIME_SSP_SYSCALL_NAME(sock_send) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_send_to( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct addr_pool *addr_pool, +#endif + __wasi_fd_t sock, + const void *buf, + size_t buf_len, + __wasi_siflags_t si_flags, + const __wasi_addr_t *dest_addr, + size_t *sent_len +) WASMTIME_SSP_SYSCALL_NAME(sock_send_to) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_shutdown( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock +) WASMTIME_SSP_SYSCALL_NAME(sock_shutdown) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_recv_timeout( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint64_t timeout_us +) WASMTIME_SSP_SYSCALL_NAME(sock_set_recv_timeout) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_recv_timeout( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint64_t *timeout_us +) WASMTIME_SSP_SYSCALL_NAME(sock_get_recv_timeout) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_send_timeout( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint64_t timeout_us +) WASMTIME_SSP_SYSCALL_NAME(sock_set_send_timeout) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_send_timeout( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint64_t *timeout_us +) WASMTIME_SSP_SYSCALL_NAME(sock_get_send_timeout) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_send_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + size_t bufsiz +) WASMTIME_SSP_SYSCALL_NAME(sock_set_send_buf_size) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_send_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + size_t *bufsiz +) WASMTIME_SSP_SYSCALL_NAME(sock_get_send_buf_size) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_recv_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + size_t bufsiz +) WASMTIME_SSP_SYSCALL_NAME(sock_set_recv_buf_size) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_recv_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + size_t *bufsiz +) WASMTIME_SSP_SYSCALL_NAME(sock_get_recv_buf_size) __attribute__((__warn_unused_result__)); + + +__wasi_errno_t wasmtime_ssp_sock_set_keep_alive( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_keep_alive) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_keep_alive( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_keep_alive) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_reuse_addr( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_reuse_addr) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_reuse_addr( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_addr) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_reuse_port( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_reuse_port) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_reuse_port( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_reuse_port) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_linger( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled, + int linger_s +) WASMTIME_SSP_SYSCALL_NAME(sock_set_linger) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_linger( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, bool *is_enabled, int *linger_s +) WASMTIME_SSP_SYSCALL_NAME(sock_get_linger) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_broadcast( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_broadcast) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_broadcast( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_broadcast) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_tcp_no_delay( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_no_delay) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_tcp_no_delay( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_no_delay) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_tcp_quick_ack( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_quick_ack) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_tcp_quick_ack( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_quick_ack) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_tcp_keep_idle( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint32_t time_s +) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_keep_idle) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_tcp_keep_idle( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint32_t *time_s +) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_keep_idle) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_tcp_keep_intvl( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint32_t time_s +) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_keep_intvl) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_tcp_keep_intvl( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint32_t *time_s +) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_keep_intvl) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_tcp_fastopen_connect( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_tcp_fastopen_connect) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_tcp_fastopen_connect( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_tcp_fastopen_connect) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_ip_multicast_loop( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool ipv6, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_multicast_loop) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_ip_multicast_loop( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool ipv6, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_loop) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_ip_add_membership( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + __wasi_addr_ip_t *imr_multiaddr, + uint32_t imr_interface +) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_add_membership) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_ip_drop_membership( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + __wasi_addr_ip_t *imr_multiaddr, + uint32_t imr_interface +) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_drop_membership) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_ip_ttl( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint8_t ttl_s +) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_ttl) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_ip_ttl( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint8_t *ttl_s +) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_ttl) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_ip_multicast_ttl( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint8_t ttl_s +) WASMTIME_SSP_SYSCALL_NAME(sock_set_ip_multicast_ttl) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_ip_multicast_ttl( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + uint8_t *ttl_s +) WASMTIME_SSP_SYSCALL_NAME(sock_get_ip_multicast_ttl) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_set_ipv6_only( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_set_ipv6_only) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sock_get_ipv6_only( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, + bool *is_enabled +) WASMTIME_SSP_SYSCALL_NAME(sock_get_ipv6_only) __attribute__((__warn_unused_result__)); + +__wasi_errno_t wasmtime_ssp_sched_yield(void) + WASMTIME_SSP_SYSCALL_NAME(sched_yield) __attribute__((__warn_unused_result__)); + +#ifdef __cplusplus +} +#endif + +#undef WASMTIME_SSP_SYSCALL_NAME + +/* clang-format on */ + +#endif /* end of WASMTIME_SSP_H */ diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/LICENSE b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/LICENSE new file mode 100644 index 000000000..04c6f48a2 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/LICENSE @@ -0,0 +1,24 @@ +All code is distributed under the following license: + + Copyright (c) 2015 Nuxi, https://nuxi.nl/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/README.md b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/README.md new file mode 100644 index 000000000..b4d55d803 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/README.md @@ -0,0 +1,14 @@ +This directory consists of selected files copied from the [src/libemulator] +directory in the [cloudabi-utils] repository, with minor modifications, +along with the accompanying LICENSE file from that repository. + +The modifications are marked with `WASMTIME_*` preprocessor macros. + +The files were copied at git revision +223dadc53248552db43e012c67ed08cf416a2b12 +which is dated +Tue Jun 25 17:22:07 2019 -0700 +. + +[libemulator]: https://github.com/NuxiNL/cloudabi-utils/tree/223dadc53248552db43e012c67ed08cf416a2b12/src/libemulator +[cloudabi-utils]: https://github.com/NuxiNL/cloudabi-utils diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/gnuc.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/gnuc.h new file mode 100644 index 000000000..70000ae0b --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/gnuc.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2023 Amazon.com, Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#if !defined(__GNUC_PREREQ) && (defined(__GNUC__) || defined(__GNUG__)) \ + && !defined(__clang__) && defined(__GNUC_MINOR__) +/* Depending on the platform the macro is defined in sys/features.h or + features.h Given the macro is simple, we re-implement it here instead of + dealing with two different paths. + */ +#define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h new file mode 100644 index 000000000..40b064b81 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h @@ -0,0 +1,265 @@ +// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM +// Exceptions. See +// https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license +// information. +// +// Significant parts of this file are derived from cloudabi-utils. See +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE +// for license information. +// +// The upstream file contains the following copyright notice: +// +// Copyright (c) 2016 Nuxi, https://nuxi.nl/ + +#ifndef LOCKING_H +#define LOCKING_H + +#include "ssp_config.h" + +#ifndef __has_extension +#define __has_extension(x) 0 +#endif + +#if __has_extension(c_thread_safety_attributes) +#define LOCK_ANNOTATE(x) __attribute__((x)) +#else +#define LOCK_ANNOTATE(x) +#endif + +/* Lock annotation macros. */ + +#define LOCKABLE LOCK_ANNOTATE(lockable) + +#define LOCKS_EXCLUSIVE(...) LOCK_ANNOTATE(exclusive_lock_function(__VA_ARGS__)) +#define LOCKS_SHARED(...) LOCK_ANNOTATE(shared_lock_function(__VA_ARGS__)) + +#define TRYLOCKS_EXCLUSIVE(...) \ + LOCK_ANNOTATE(exclusive_trylock_function(__VA_ARGS__)) +#define TRYLOCKS_SHARED(...) LOCK_ANNOTATE(shared_trylock_function(__VA_ARGS__)) + +#define UNLOCKS(...) LOCK_ANNOTATE(unlock_function(__VA_ARGS__)) + +#define REQUIRES_EXCLUSIVE(...) \ + LOCK_ANNOTATE(exclusive_locks_required(__VA_ARGS__)) +#define REQUIRES_SHARED(...) LOCK_ANNOTATE(shared_locks_required(__VA_ARGS__)) +#define REQUIRES_UNLOCKED(...) LOCK_ANNOTATE(locks_excluded(__VA_ARGS__)) + +#define NO_LOCK_ANALYSIS LOCK_ANNOTATE(no_thread_safety_analysis) + +/* Mutex that uses the lock annotations. */ + +struct LOCKABLE mutex { + pthread_mutex_t object; +}; + +/* clang-format off */ +#define MUTEX_INITIALIZER \ + { PTHREAD_MUTEX_INITIALIZER } +/* clang-format on */ + +static inline bool +mutex_init(struct mutex *lock) REQUIRES_UNLOCKED(*lock) +{ + return pthread_mutex_init(&lock->object, NULL) == 0 ? true : false; +} + +static inline void +mutex_destroy(struct mutex *lock) REQUIRES_UNLOCKED(*lock) +{ + pthread_mutex_destroy(&lock->object); +} + +static inline void +mutex_lock(struct mutex *lock) LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS +{ + pthread_mutex_lock(&lock->object); +} + +static inline void +mutex_unlock(struct mutex *lock) UNLOCKS(*lock) NO_LOCK_ANALYSIS +{ + pthread_mutex_unlock(&lock->object); +} + +/* Read-write lock that uses the lock annotations. */ + +struct LOCKABLE rwlock { + pthread_rwlock_t object; +}; + +static inline bool +rwlock_init(struct rwlock *lock) REQUIRES_UNLOCKED(*lock) +{ + return pthread_rwlock_init(&lock->object, NULL) == 0 ? true : false; +} + +static inline void +rwlock_rdlock(struct rwlock *lock) LOCKS_SHARED(*lock) NO_LOCK_ANALYSIS +{ + pthread_rwlock_rdlock(&lock->object); +} + +static inline void +rwlock_wrlock(struct rwlock *lock) LOCKS_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS +{ + pthread_rwlock_wrlock(&lock->object); +} + +static inline void +rwlock_unlock(struct rwlock *lock) UNLOCKS(*lock) NO_LOCK_ANALYSIS +{ + pthread_rwlock_unlock(&lock->object); +} + +static inline void +rwlock_destroy(struct rwlock *lock) UNLOCKS(*lock) NO_LOCK_ANALYSIS +{ + pthread_rwlock_destroy(&lock->object); +} + +/* Condition variable that uses the lock annotations. */ + +struct LOCKABLE cond { + pthread_cond_t object; +#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK \ + || !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP + clockid_t clock; +#endif +}; + +static inline bool +cond_init_monotonic(struct cond *cond) +{ + bool ret = false; +#if CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK + pthread_condattr_t attr; + + if (pthread_condattr_init(&attr) != 0) + return false; + + if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) != 0) + goto fail; + + if (pthread_cond_init(&cond->object, &attr) != 0) + goto fail; + + ret = true; +fail: + pthread_condattr_destroy(&attr); +#else + if (pthread_cond_init(&cond->object, NULL) != 0) + return false; + ret = true; +#endif + +#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK \ + || !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP + cond->clock = CLOCK_MONOTONIC; +#endif + return ret; +} + +static inline bool +cond_init_realtime(struct cond *cond) +{ + if (pthread_cond_init(&cond->object, NULL) != 0) + return false; +#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK \ + || !CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP + cond->clock = CLOCK_REALTIME; +#endif + return true; +} + +static inline void +cond_destroy(struct cond *cond) +{ + pthread_cond_destroy(&cond->object); +} + +static inline void +cond_signal(struct cond *cond) +{ + pthread_cond_signal(&cond->object); +} + +#if !CONFIG_HAS_CLOCK_NANOSLEEP +static inline bool +cond_timedwait(struct cond *cond, struct mutex *lock, uint64_t timeout, + bool abstime) REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS +{ + int ret; + struct timespec ts = { + .tv_sec = (time_t)(timeout / 1000000000), + .tv_nsec = (long)(timeout % 1000000000), + }; + + if (abstime) { +#if !CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK + /** + * No native support for sleeping on monotonic clocks. Convert the + * timeout to a relative value and then to an absolute value for the + * realtime clock. + */ + if (cond->clock != CLOCK_REALTIME) { + struct timespec ts_monotonic; + struct timespec ts_realtime; + + clock_gettime(cond->clock, &ts_monotonic); + ts.tv_sec -= ts_monotonic.tv_sec; + ts.tv_nsec -= ts_monotonic.tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_nsec += 1000000000; + --ts.tv_sec; + } + + clock_gettime(CLOCK_REALTIME, &ts_realtime); + ts.tv_sec += ts_realtime.tv_sec; + ts.tv_nsec += ts_realtime.tv_nsec; + if (ts.tv_nsec >= 1000000000) { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + } +#endif + } + else { +#if CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP + /* Implementation supports relative timeouts. */ + ret = pthread_cond_timedwait_relative_np(&cond->object, &lock->object, + &ts); + bh_assert((ret == 0 || ret == ETIMEDOUT) + && "pthread_cond_timedwait_relative_np() failed"); + return ret == ETIMEDOUT; +#else + /* Convert to absolute timeout. */ + struct timespec ts_now; +#if CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK + clock_gettime(cond->clock, &ts_now); +#else + clock_gettime(CLOCK_REALTIME, &ts_now); +#endif + ts.tv_sec += ts_now.tv_sec; + ts.tv_nsec += ts_now.tv_nsec; + if (ts.tv_nsec >= 1000000000) { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } +#endif + } + + ret = pthread_cond_timedwait(&cond->object, &lock->object, &ts); + bh_assert((ret == 0 || ret == ETIMEDOUT) + && "pthread_cond_timedwait() failed"); + return ret == ETIMEDOUT; +} +#endif + +static inline void +cond_wait(struct cond *cond, struct mutex *lock) + REQUIRES_EXCLUSIVE(*lock) NO_LOCK_ANALYSIS +{ + pthread_cond_wait(&cond->object, &lock->object); +} + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c new file mode 100644 index 000000000..61e841836 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -0,0 +1,4072 @@ +// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM +// Exceptions. See +// https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license +// information. +// +// Significant parts of this file are derived from cloudabi-utils. See +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE +// for license information. +// +// The upstream file contains the following copyright notice: +// +// Copyright (c) 2016-2018 Nuxi, https://nuxi.nl/ + +#include "ssp_config.h" +#include "bh_platform.h" +#include "wasmtime_ssp.h" +#include "locking.h" +#include "posix.h" +#include "random.h" +#include "refcount.h" +#include "rights.h" +#include "str.h" + +#if 0 /* TODO: -std=gnu99 causes compile error, comment them first */ +// struct iovec must have the same layout as __wasi_iovec_t. +static_assert(offsetof(struct iovec, iov_base) == + offsetof(__wasi_iovec_t, buf), + "Offset mismatch"); +static_assert(sizeof(((struct iovec *)0)->iov_base) == + sizeof(((__wasi_iovec_t *)0)->buf), + "Size mismatch"); +static_assert(offsetof(struct iovec, iov_len) == + offsetof(__wasi_iovec_t, buf_len), + "Offset mismatch"); +static_assert(sizeof(((struct iovec *)0)->iov_len) == + sizeof(((__wasi_iovec_t *)0)->buf_len), + "Size mismatch"); +static_assert(sizeof(struct iovec) == sizeof(__wasi_iovec_t), + "Size mismatch"); + +// struct iovec must have the same layout as __wasi_ciovec_t. +static_assert(offsetof(struct iovec, iov_base) == + offsetof(__wasi_ciovec_t, buf), + "Offset mismatch"); +static_assert(sizeof(((struct iovec *)0)->iov_base) == + sizeof(((__wasi_ciovec_t *)0)->buf), + "Size mismatch"); +static_assert(offsetof(struct iovec, iov_len) == + offsetof(__wasi_ciovec_t, buf_len), + "Offset mismatch"); +static_assert(sizeof(((struct iovec *)0)->iov_len) == + sizeof(((__wasi_ciovec_t *)0)->buf_len), + "Size mismatch"); +static_assert(sizeof(struct iovec) == sizeof(__wasi_ciovec_t), + "Size mismatch"); +#endif + +#if defined(WASMTIME_SSP_STATIC_CURFDS) +static __thread struct fd_table *curfds; +static __thread struct fd_prestats *prestats; +static __thread struct argv_environ_values *argv_environ; +static __thread struct addr_pool *addr_pool; +#endif + +// Converts a POSIX error code to a CloudABI error code. +static __wasi_errno_t +convert_errno(int error) +{ + static const __wasi_errno_t errors[] = { +#define X(v) [v] = __WASI_##v + X(E2BIG), + X(EACCES), + X(EADDRINUSE), + X(EADDRNOTAVAIL), + X(EAFNOSUPPORT), + X(EAGAIN), + X(EALREADY), + X(EBADF), + X(EBADMSG), + X(EBUSY), + X(ECANCELED), + X(ECHILD), + X(ECONNABORTED), + X(ECONNREFUSED), + X(ECONNRESET), + X(EDEADLK), + X(EDESTADDRREQ), + X(EDOM), + X(EDQUOT), + X(EEXIST), + X(EFAULT), + X(EFBIG), + X(EHOSTUNREACH), + X(EIDRM), + X(EILSEQ), + X(EINPROGRESS), + X(EINTR), + X(EINVAL), + X(EIO), + X(EISCONN), + X(EISDIR), + X(ELOOP), + X(EMFILE), + X(EMLINK), + X(EMSGSIZE), + X(EMULTIHOP), + X(ENAMETOOLONG), + X(ENETDOWN), + X(ENETRESET), + X(ENETUNREACH), + X(ENFILE), + X(ENOBUFS), + X(ENODEV), + X(ENOENT), + X(ENOEXEC), + X(ENOLCK), + X(ENOLINK), + X(ENOMEM), + X(ENOMSG), + X(ENOPROTOOPT), + X(ENOSPC), + X(ENOSYS), +#ifdef ENOTCAPABLE + X(ENOTCAPABLE), +#endif + X(ENOTCONN), + X(ENOTDIR), + X(ENOTEMPTY), + X(ENOTRECOVERABLE), + X(ENOTSOCK), + X(ENOTSUP), + X(ENOTTY), + X(ENXIO), + X(EOVERFLOW), + X(EOWNERDEAD), + X(EPERM), + X(EPIPE), + X(EPROTO), + X(EPROTONOSUPPORT), + X(EPROTOTYPE), + X(ERANGE), + X(EROFS), + X(ESPIPE), + X(ESRCH), + X(ESTALE), + X(ETIMEDOUT), + X(ETXTBSY), + X(EXDEV), +#undef X +#if EOPNOTSUPP != ENOTSUP + [EOPNOTSUPP] = __WASI_ENOTSUP, +#endif +#if EWOULDBLOCK != EAGAIN + [EWOULDBLOCK] = __WASI_EAGAIN, +#endif + }; + if (error < 0 || (size_t)error >= sizeof(errors) / sizeof(errors[0]) + || errors[error] == 0) + return __WASI_ENOSYS; + return errors[error]; +} + +static bool +ns_lookup_list_search(char **list, const char *host) +{ + size_t host_len = strlen(host), suffix_len; + + while (*list) { + if (*list[0] == '*') { + suffix_len = strlen(*list) - 1; + if (suffix_len <= host_len + && strncmp(host + host_len - suffix_len, *list + 1, suffix_len) + == 0) { + return true; + } + } + else { + if (strcmp(*list, host) == 0) { + return true; + } + } + list++; + } + + return false; +} + +// Converts a POSIX timespec to a CloudABI timestamp. +static __wasi_timestamp_t +convert_timespec(const struct timespec *ts) +{ + if (ts->tv_sec < 0) + return 0; + if ((__wasi_timestamp_t)ts->tv_sec >= UINT64_MAX / 1000000000) + return UINT64_MAX; + return (__wasi_timestamp_t)ts->tv_sec * 1000000000 + + (__wasi_timestamp_t)ts->tv_nsec; +} + +// Converts a CloudABI clock identifier to a POSIX clock identifier. +static bool +convert_clockid(__wasi_clockid_t in, clockid_t *out) +{ + switch (in) { + case __WASI_CLOCK_MONOTONIC: + *out = CLOCK_MONOTONIC; + return true; +#if defined(CLOCK_PROCESS_CPUTIME_ID) + case __WASI_CLOCK_PROCESS_CPUTIME_ID: + *out = CLOCK_PROCESS_CPUTIME_ID; + return true; +#endif + case __WASI_CLOCK_REALTIME: + *out = CLOCK_REALTIME; + return true; +#if defined(CLOCK_THREAD_CPUTIME_ID) + case __WASI_CLOCK_THREAD_CPUTIME_ID: + *out = CLOCK_THREAD_CPUTIME_ID; + return true; +#endif + default: + return false; + } +} + +static void +wasi_addr_to_bh_sockaddr(const __wasi_addr_t *wasi_addr, + bh_sockaddr_t *sockaddr) +{ + if (wasi_addr->kind == IPv4) { + sockaddr->addr_bufer.ipv4 = (wasi_addr->addr.ip4.addr.n0 << 24) + | (wasi_addr->addr.ip4.addr.n1 << 16) + | (wasi_addr->addr.ip4.addr.n2 << 8) + | wasi_addr->addr.ip4.addr.n3; + sockaddr->is_ipv4 = true; + sockaddr->port = wasi_addr->addr.ip4.port; + } + else { + sockaddr->addr_bufer.ipv6[0] = wasi_addr->addr.ip6.addr.n0; + sockaddr->addr_bufer.ipv6[1] = wasi_addr->addr.ip6.addr.n1; + sockaddr->addr_bufer.ipv6[2] = wasi_addr->addr.ip6.addr.n2; + sockaddr->addr_bufer.ipv6[3] = wasi_addr->addr.ip6.addr.n3; + sockaddr->addr_bufer.ipv6[4] = wasi_addr->addr.ip6.addr.h0; + sockaddr->addr_bufer.ipv6[5] = wasi_addr->addr.ip6.addr.h1; + sockaddr->addr_bufer.ipv6[6] = wasi_addr->addr.ip6.addr.h2; + sockaddr->addr_bufer.ipv6[7] = wasi_addr->addr.ip6.addr.h3; + sockaddr->is_ipv4 = false; + sockaddr->port = wasi_addr->addr.ip6.port; + } +} + +// Converts an IPv6 binary address object to WASI address object. +static void +bh_sockaddr_to_wasi_addr(const bh_sockaddr_t *sockaddr, + __wasi_addr_t *wasi_addr) +{ + if (sockaddr->is_ipv4) { + wasi_addr->kind = IPv4; + wasi_addr->addr.ip4.port = sockaddr->port; + wasi_addr->addr.ip4.addr.n0 = + (sockaddr->addr_bufer.ipv4 & 0xFF000000) >> 24; + wasi_addr->addr.ip4.addr.n1 = + (sockaddr->addr_bufer.ipv4 & 0x00FF0000) >> 16; + wasi_addr->addr.ip4.addr.n2 = + (sockaddr->addr_bufer.ipv4 & 0x0000FF00) >> 8; + wasi_addr->addr.ip4.addr.n3 = (sockaddr->addr_bufer.ipv4 & 0x000000FF); + } + else { + wasi_addr->kind = IPv6; + wasi_addr->addr.ip6.port = sockaddr->port; + wasi_addr->addr.ip6.addr.n0 = sockaddr->addr_bufer.ipv6[0]; + wasi_addr->addr.ip6.addr.n1 = sockaddr->addr_bufer.ipv6[1]; + wasi_addr->addr.ip6.addr.n2 = sockaddr->addr_bufer.ipv6[2]; + wasi_addr->addr.ip6.addr.n3 = sockaddr->addr_bufer.ipv6[3]; + wasi_addr->addr.ip6.addr.h0 = sockaddr->addr_bufer.ipv6[4]; + wasi_addr->addr.ip6.addr.h1 = sockaddr->addr_bufer.ipv6[5]; + wasi_addr->addr.ip6.addr.h2 = sockaddr->addr_bufer.ipv6[6]; + wasi_addr->addr.ip6.addr.h3 = sockaddr->addr_bufer.ipv6[7]; + } +} + +static void +wasi_addr_ip_to_bh_ip_addr_buffer(__wasi_addr_ip_t *addr, + bh_ip_addr_buffer_t *out) +{ + if (addr->kind == IPv4) { + out->ipv4 = htonl((addr->addr.ip4.n0 << 24) | (addr->addr.ip4.n1 << 16) + | (addr->addr.ip4.n2 << 8) | addr->addr.ip4.n3); + } + else { + out->ipv6[0] = htons(addr->addr.ip6.n0); + out->ipv6[1] = htons(addr->addr.ip6.n1); + out->ipv6[2] = htons(addr->addr.ip6.n2); + out->ipv6[3] = htons(addr->addr.ip6.n3); + out->ipv6[4] = htons(addr->addr.ip6.h0); + out->ipv6[5] = htons(addr->addr.ip6.h1); + out->ipv6[6] = htons(addr->addr.ip6.h2); + out->ipv6[7] = htons(addr->addr.ip6.h3); + } +} + +__wasi_errno_t +wasmtime_ssp_clock_res_get(__wasi_clockid_t clock_id, + __wasi_timestamp_t *resolution) +{ + clockid_t nclock_id; + if (!convert_clockid(clock_id, &nclock_id)) + return __WASI_EINVAL; + struct timespec ts; + if (clock_getres(nclock_id, &ts) < 0) + return convert_errno(errno); + *resolution = convert_timespec(&ts); + return 0; +} + +__wasi_errno_t +wasmtime_ssp_clock_time_get(__wasi_clockid_t clock_id, + __wasi_timestamp_t precision, + __wasi_timestamp_t *time) +{ + clockid_t nclock_id; + if (!convert_clockid(clock_id, &nclock_id)) + return __WASI_EINVAL; + struct timespec ts; + if (clock_gettime(nclock_id, &ts) < 0) + return convert_errno(errno); + *time = convert_timespec(&ts); + return 0; +} + +struct fd_prestat { + const char *dir; +}; + +bool +fd_prestats_init(struct fd_prestats *pt) +{ + if (!rwlock_init(&pt->lock)) + return false; + pt->prestats = NULL; + pt->size = 0; + pt->used = 0; +#if defined(WASMTIME_SSP_STATIC_CURFDS) + prestats = pt; +#endif + return true; +} + +// Grows the preopened resource table to a required lower bound and a +// minimum number of free preopened resource table entries. +static bool +fd_prestats_grow(struct fd_prestats *pt, size_t min, size_t incr) + REQUIRES_EXCLUSIVE(pt->lock) +{ + if (pt->size <= min || pt->size < (pt->used + incr) * 2) { + // Keep on doubling the table size until we've met our constraints. + size_t size = pt->size == 0 ? 1 : pt->size; + while (size <= min || size < (pt->used + incr) * 2) + size *= 2; + + // Grow the file descriptor table's allocation. + struct fd_prestat *prestats = + wasm_runtime_malloc((uint32)(sizeof(*prestats) * size)); + if (prestats == NULL) + return false; + + if (pt->prestats && pt->size > 0) { + bh_memcpy_s(prestats, (uint32)(sizeof(*prestats) * size), + pt->prestats, (uint32)(sizeof(*prestats) * pt->size)); + } + + if (pt->prestats) + wasm_runtime_free(pt->prestats); + + // Mark all new file descriptors as unused. + for (size_t i = pt->size; i < size; ++i) + prestats[i].dir = NULL; + pt->prestats = prestats; + pt->size = size; + } + return true; +} + +// Inserts a preopened resource record into the preopened resource table. +bool +fd_prestats_insert(struct fd_prestats *pt, const char *dir, __wasi_fd_t fd) +{ + // Grow the preopened resource table if needed. + rwlock_wrlock(&pt->lock); + if (!fd_prestats_grow(pt, fd, 1)) { + rwlock_unlock(&pt->lock); + return false; + } + + pt->prestats[fd].dir = bh_strdup(dir); + rwlock_unlock(&pt->lock); + + if (pt->prestats[fd].dir == NULL) + return false; + + return true; +} + +// Looks up a preopened resource table entry by number. +static __wasi_errno_t +fd_prestats_get_entry(struct fd_prestats *pt, __wasi_fd_t fd, + struct fd_prestat **ret) REQUIRES_SHARED(pt->lock) +{ + // Test for file descriptor existence. + if (fd >= pt->size) + return __WASI_EBADF; + struct fd_prestat *prestat = &pt->prestats[fd]; + if (prestat->dir == NULL) + return __WASI_EBADF; + + *ret = prestat; + return 0; +} + +struct fd_object { + struct refcount refcount; + __wasi_filetype_t type; + int number; + + union { + // Data associated with directory file descriptors. + struct { + struct mutex lock; // Lock to protect members below. + DIR *handle; // Directory handle. + __wasi_dircookie_t offset; // Offset of the directory. + } directory; + }; +}; + +struct fd_entry { + struct fd_object *object; + __wasi_rights_t rights_base; + __wasi_rights_t rights_inheriting; +}; + +bool +fd_table_init(struct fd_table *ft) +{ + if (!rwlock_init(&ft->lock)) + return false; + ft->entries = NULL; + ft->size = 0; + ft->used = 0; +#if defined(WASMTIME_SSP_STATIC_CURFDS) + curfds = ft; +#endif + return true; +} + +// Looks up a file descriptor table entry by number and required rights. +static __wasi_errno_t +fd_table_get_entry(struct fd_table *ft, __wasi_fd_t fd, + __wasi_rights_t rights_base, + __wasi_rights_t rights_inheriting, struct fd_entry **ret) + REQUIRES_SHARED(ft->lock) +{ + // Test for file descriptor existence. + if (fd >= ft->size) + return __WASI_EBADF; + struct fd_entry *fe = &ft->entries[fd]; + if (fe->object == NULL) + return __WASI_EBADF; + + // Validate rights. + if ((~fe->rights_base & rights_base) != 0 + || (~fe->rights_inheriting & rights_inheriting) != 0) + return __WASI_ENOTCAPABLE; + *ret = fe; + return 0; +} + +// Grows the file descriptor table to a required lower bound and a +// minimum number of free file descriptor table entries. +static bool +fd_table_grow(struct fd_table *ft, size_t min, size_t incr) + REQUIRES_EXCLUSIVE(ft->lock) +{ + if (ft->size <= min || ft->size < (ft->used + incr) * 2) { + // Keep on doubling the table size until we've met our constraints. + size_t size = ft->size == 0 ? 1 : ft->size; + while (size <= min || size < (ft->used + incr) * 2) + size *= 2; + + // Grow the file descriptor table's allocation. + struct fd_entry *entries = + wasm_runtime_malloc((uint32)(sizeof(*entries) * size)); + if (entries == NULL) + return false; + + if (ft->entries && ft->size > 0) { + bh_memcpy_s(entries, (uint32)(sizeof(*entries) * size), ft->entries, + (uint32)(sizeof(*entries) * ft->size)); + } + + if (ft->entries) + wasm_runtime_free(ft->entries); + + // Mark all new file descriptors as unused. + for (size_t i = ft->size; i < size; ++i) + entries[i].object = NULL; + ft->entries = entries; + ft->size = size; + } + return true; +} + +// Allocates a new file descriptor object. +static __wasi_errno_t +fd_object_new(__wasi_filetype_t type, struct fd_object **fo) + TRYLOCKS_SHARED(0, (*fo)->refcount) +{ + *fo = wasm_runtime_malloc(sizeof(**fo)); + if (*fo == NULL) + return __WASI_ENOMEM; + refcount_init(&(*fo)->refcount, 1); + (*fo)->type = type; + (*fo)->number = -1; + return 0; +} + +// Attaches a file descriptor to the file descriptor table. +static void +fd_table_attach(struct fd_table *ft, __wasi_fd_t fd, struct fd_object *fo, + __wasi_rights_t rights_base, __wasi_rights_t rights_inheriting) + REQUIRES_EXCLUSIVE(ft->lock) CONSUMES(fo->refcount) +{ + assert(ft->size > fd && "File descriptor table too small"); + struct fd_entry *fe = &ft->entries[fd]; + assert(fe->object == NULL + && "Attempted to overwrite an existing descriptor"); + fe->object = fo; + fe->rights_base = rights_base; + fe->rights_inheriting = rights_inheriting; + ++ft->used; + assert(ft->size >= ft->used * 2 && "File descriptor too full"); +} + +// Detaches a file descriptor from the file descriptor table. +static void +fd_table_detach(struct fd_table *ft, __wasi_fd_t fd, struct fd_object **fo) + REQUIRES_EXCLUSIVE(ft->lock) PRODUCES((*fo)->refcount) +{ + assert(ft->size > fd && "File descriptor table too small"); + struct fd_entry *fe = &ft->entries[fd]; + *fo = fe->object; + assert(*fo != NULL && "Attempted to detach nonexistent descriptor"); + fe->object = NULL; + assert(ft->used > 0 && "Reference count mismatch"); + --ft->used; +} + +// Determines the type of a file descriptor and its maximum set of +// rights that should be attached to it. +static __wasi_errno_t +fd_determine_type_rights(int fd, __wasi_filetype_t *type, + __wasi_rights_t *rights_base, + __wasi_rights_t *rights_inheriting) +{ + struct stat sb; + if (fstat(fd, &sb) < 0) + return convert_errno(errno); + if (S_ISBLK(sb.st_mode)) { + *type = __WASI_FILETYPE_BLOCK_DEVICE; + *rights_base = RIGHTS_BLOCK_DEVICE_BASE; + *rights_inheriting = RIGHTS_BLOCK_DEVICE_INHERITING; + } + else if (S_ISCHR(sb.st_mode)) { + *type = __WASI_FILETYPE_CHARACTER_DEVICE; +#if CONFIG_HAS_ISATTY + if (isatty(fd)) { + *rights_base = RIGHTS_TTY_BASE; + *rights_inheriting = RIGHTS_TTY_INHERITING; + } + else +#endif + { + *rights_base = RIGHTS_CHARACTER_DEVICE_BASE; + *rights_inheriting = RIGHTS_CHARACTER_DEVICE_INHERITING; + } + } + else if (S_ISDIR(sb.st_mode)) { + *type = __WASI_FILETYPE_DIRECTORY; + *rights_base = RIGHTS_DIRECTORY_BASE; + *rights_inheriting = RIGHTS_DIRECTORY_INHERITING; + } + else if (S_ISREG(sb.st_mode)) { + *type = __WASI_FILETYPE_REGULAR_FILE; + *rights_base = RIGHTS_REGULAR_FILE_BASE; + *rights_inheriting = RIGHTS_REGULAR_FILE_INHERITING; + } + else if (S_ISSOCK(sb.st_mode)) { + int socktype; + socklen_t socktypelen = sizeof(socktype); + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &socktype, &socktypelen) < 0) + return convert_errno(errno); + switch (socktype) { + case SOCK_DGRAM: + *type = __WASI_FILETYPE_SOCKET_DGRAM; + break; + case SOCK_STREAM: + *type = __WASI_FILETYPE_SOCKET_STREAM; + break; + default: + return __WASI_EINVAL; + } + *rights_base = RIGHTS_SOCKET_BASE; + *rights_inheriting = RIGHTS_SOCKET_INHERITING; + } + else if (S_ISFIFO(sb.st_mode)) { + *type = __WASI_FILETYPE_SOCKET_STREAM; + *rights_base = RIGHTS_SOCKET_BASE; + *rights_inheriting = RIGHTS_SOCKET_INHERITING; + } + else { + return __WASI_EINVAL; + } + + // Strip off read/write bits based on the access mode. + switch (fcntl(fd, F_GETFL) & O_ACCMODE) { + case O_RDONLY: + *rights_base &= ~(__wasi_rights_t)__WASI_RIGHT_FD_WRITE; + break; + case O_WRONLY: + *rights_base &= ~(__wasi_rights_t)__WASI_RIGHT_FD_READ; + break; + } + return 0; +} + +// Returns the underlying file descriptor number of a file descriptor +// object. This function can only be applied to objects that have an +// underlying file descriptor number. +static int +fd_number(const struct fd_object *fo) +{ + int number = fo->number; + assert(number >= 0 && "fd_number() called on virtual file descriptor"); + return number; +} + +#define CLOSE_NON_STD_FD(fd) \ + do { \ + if (fd > 2) \ + close(fd); \ + } while (0) + +// Lowers the reference count on a file descriptor object. When the +// reference count reaches zero, its resources are cleaned up. +static void +fd_object_release(struct fd_object *fo) UNLOCKS(fo->refcount) +{ + if (refcount_release(&fo->refcount)) { + switch (fo->type) { + case __WASI_FILETYPE_DIRECTORY: + // For directories we may keep track of a DIR object. Calling + // closedir() on it also closes the underlying file descriptor. + mutex_destroy(&fo->directory.lock); + if (fo->directory.handle == NULL) { + CLOSE_NON_STD_FD(fd_number(fo)); + } + else { + closedir(fo->directory.handle); + } + break; + default: + CLOSE_NON_STD_FD(fd_number(fo)); + break; + } + wasm_runtime_free(fo); + } +} + +// Inserts an already existing file descriptor into the file descriptor +// table. +bool +fd_table_insert_existing(struct fd_table *ft, __wasi_fd_t in, int out) +{ + __wasi_filetype_t type; + __wasi_rights_t rights_base, rights_inheriting; + struct fd_object *fo; + __wasi_errno_t error; + + error = + fd_determine_type_rights(out, &type, &rights_base, &rights_inheriting); + if (error != 0) { +#ifdef BH_PLATFORM_EGO + /** + * since it is an already opened file and we can assume the opened file + * has all necessary rights no matter how to get + */ + if (error != __WASI_ENOTSUP) + return false; +#else + return false; +#endif + } + + error = fd_object_new(type, &fo); + if (error != 0) + return false; + fo->number = out; + if (type == __WASI_FILETYPE_DIRECTORY) { + if (!mutex_init(&fo->directory.lock)) { + fd_object_release(fo); + return false; + } + fo->directory.handle = NULL; + } + + // Grow the file descriptor table if needed. + rwlock_wrlock(&ft->lock); + if (!fd_table_grow(ft, in, 1)) { + rwlock_unlock(&ft->lock); + fd_object_release(fo); + return false; + } + + fd_table_attach(ft, in, fo, rights_base, rights_inheriting); + rwlock_unlock(&ft->lock); + return true; +} + +// Picks an unused slot from the file descriptor table. +static __wasi_fd_t +fd_table_unused(struct fd_table *ft) REQUIRES_SHARED(ft->lock) +{ + assert(ft->size > ft->used && "File descriptor table has no free slots"); + for (;;) { + __wasi_fd_t fd = (__wasi_fd_t)random_uniform(ft->size); + if (ft->entries[fd].object == NULL) + return fd; + } +} + +// Inserts a file descriptor object into an unused slot of the file +// descriptor table. +static __wasi_errno_t +fd_table_insert(struct fd_table *ft, struct fd_object *fo, + __wasi_rights_t rights_base, __wasi_rights_t rights_inheriting, + __wasi_fd_t *out) REQUIRES_UNLOCKED(ft->lock) + UNLOCKS(fo->refcount) +{ + // Grow the file descriptor table if needed. + rwlock_wrlock(&ft->lock); + if (!fd_table_grow(ft, 0, 1)) { + rwlock_unlock(&ft->lock); + fd_object_release(fo); + return convert_errno(errno); + } + + *out = fd_table_unused(ft); + fd_table_attach(ft, *out, fo, rights_base, rights_inheriting); + rwlock_unlock(&ft->lock); + return 0; +} + +// Inserts a numerical file descriptor into the file descriptor table. +static __wasi_errno_t +fd_table_insert_fd(struct fd_table *ft, int in, __wasi_filetype_t type, + __wasi_rights_t rights_base, + __wasi_rights_t rights_inheriting, __wasi_fd_t *out) + REQUIRES_UNLOCKED(ft->lock) +{ + struct fd_object *fo; + + __wasi_errno_t error = fd_object_new(type, &fo); + if (error != 0) { + close(in); + return error; + } + + fo->number = in; + if (type == __WASI_FILETYPE_DIRECTORY) { + if (!mutex_init(&fo->directory.lock)) { + fd_object_release(fo); + return (__wasi_errno_t)-1; + } + fo->directory.handle = NULL; + } + return fd_table_insert(ft, fo, rights_base, rights_inheriting, out); +} + +__wasi_errno_t +wasmtime_ssp_fd_prestat_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_prestats *prestats, +#endif + __wasi_fd_t fd, __wasi_prestat_t *buf) +{ + rwlock_rdlock(&prestats->lock); + struct fd_prestat *prestat; + __wasi_errno_t error = fd_prestats_get_entry(prestats, fd, &prestat); + if (error != 0) { + rwlock_unlock(&prestats->lock); + return error; + } + + *buf = (__wasi_prestat_t){ + .pr_type = __WASI_PREOPENTYPE_DIR, + }; + + buf->u.dir.pr_name_len = strlen(prestat->dir); + + rwlock_unlock(&prestats->lock); + + return 0; +} + +__wasi_errno_t +wasmtime_ssp_fd_prestat_dir_name( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_prestats *prestats, +#endif + __wasi_fd_t fd, char *path, size_t path_len) +{ + rwlock_rdlock(&prestats->lock); + struct fd_prestat *prestat; + __wasi_errno_t error = fd_prestats_get_entry(prestats, fd, &prestat); + if (error != 0) { + rwlock_unlock(&prestats->lock); + return error; + } + if (path_len != strlen(prestat->dir)) { + rwlock_unlock(&prestats->lock); + return EINVAL; + } + + bh_memcpy_s(path, (uint32)path_len, prestat->dir, (uint32)path_len); + + rwlock_unlock(&prestats->lock); + + return 0; +} + +__wasi_errno_t +wasmtime_ssp_fd_close( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct fd_prestats *prestats, +#endif + __wasi_fd_t fd) +{ + // Don't allow closing a pre-opened resource. + // TODO: Eventually, we do want to permit this, once libpreopen in + // userspace is capable of removing entries from its tables as well. + { + rwlock_rdlock(&prestats->lock); + struct fd_prestat *prestat; + __wasi_errno_t error = fd_prestats_get_entry(prestats, fd, &prestat); + rwlock_unlock(&prestats->lock); + if (error == 0) { + return __WASI_ENOTSUP; + } + } + + // Validate the file descriptor. + struct fd_table *ft = curfds; + rwlock_wrlock(&ft->lock); + struct fd_entry *fe; + __wasi_errno_t error = fd_table_get_entry(ft, fd, 0, 0, &fe); + if (error != 0) { + rwlock_unlock(&ft->lock); + return error; + } + + // Remove it from the file descriptor table. + struct fd_object *fo; + fd_table_detach(ft, fd, &fo); + rwlock_unlock(&ft->lock); + fd_object_release(fo); + return 0; +} + +// Look up a file descriptor object in a locked file descriptor table +// and increases its reference count. +static __wasi_errno_t +fd_object_get_locked(struct fd_object **fo, struct fd_table *ft, __wasi_fd_t fd, + __wasi_rights_t rights_base, + __wasi_rights_t rights_inheriting) + TRYLOCKS_EXCLUSIVE(0, (*fo)->refcount) REQUIRES_EXCLUSIVE(ft->lock) +{ + // Test whether the file descriptor number is valid. + struct fd_entry *fe; + __wasi_errno_t error = + fd_table_get_entry(ft, fd, rights_base, rights_inheriting, &fe); + if (error != 0) + return error; + + // Increase the reference count on the file descriptor object. A copy + // of the rights are also stored, so callers can still access those if + // needed. + *fo = fe->object; + refcount_acquire(&(*fo)->refcount); + return 0; +} + +// Temporarily locks the file descriptor table to look up a file +// descriptor object, increases its reference count and drops the lock. +static __wasi_errno_t +fd_object_get(struct fd_table *curfds, struct fd_object **fo, __wasi_fd_t fd, + __wasi_rights_t rights_base, __wasi_rights_t rights_inheriting) + TRYLOCKS_EXCLUSIVE(0, (*fo)->refcount) +{ + struct fd_table *ft = curfds; + rwlock_rdlock(&ft->lock); + __wasi_errno_t error = + fd_object_get_locked(fo, ft, fd, rights_base, rights_inheriting); + rwlock_unlock(&ft->lock); + return error; +} + +__wasi_errno_t +wasmtime_ssp_fd_datasync( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd) +{ + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_DATASYNC, 0); + if (error != 0) + return error; + +#if CONFIG_HAS_FDATASYNC + int ret = fdatasync(fd_number(fo)); +#else + int ret = fsync(fd_number(fo)); +#endif + fd_object_release(fo); + if (ret < 0) + return convert_errno(errno); + return 0; +} + +__wasi_errno_t +wasmtime_ssp_fd_pread( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, const __wasi_iovec_t *iov, size_t iovcnt, + __wasi_filesize_t offset, size_t *nread) +{ + if (iovcnt == 0) + return __WASI_EINVAL; + + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_READ, 0); + if (error != 0) + return error; + +#if CONFIG_HAS_PREADV + ssize_t len = preadv(fd_number(fo), (const struct iovec *)iov, (int)iovcnt, + (off_t)offset); + fd_object_release(fo); + if (len < 0) + return convert_errno(errno); + *nread = (size_t)len; + return 0; +#else + if (iovcnt == 1) { + ssize_t len = pread(fd_number(fo), iov->buf, iov->buf_len, offset); + fd_object_release(fo); + if (len < 0) + return convert_errno(errno); + *nread = len; + return 0; + } + else { + // Allocate a single buffer to fit all data. + size_t totalsize = 0; + for (size_t i = 0; i < iovcnt; ++i) + totalsize += iov[i].buf_len; + char *buf = wasm_runtime_malloc(totalsize); + if (buf == NULL) { + fd_object_release(fo); + return __WASI_ENOMEM; + } + + // Perform a single read operation. + ssize_t len = pread(fd_number(fo), buf, totalsize, offset); + fd_object_release(fo); + if (len < 0) { + wasm_runtime_free(buf); + return convert_errno(errno); + } + + // Copy data back to vectors. + size_t bufoff = 0; + for (size_t i = 0; i < iovcnt; ++i) { + if (bufoff + iov[i].buf_len < (size_t)len) { + bh_memcpy_s(iov[i].buf, iov[i].buf_len, buf + bufoff, + iov[i].buf_len); + bufoff += iov[i].buf_len; + } + else { + bh_memcpy_s(iov[i].buf, iov[i].buf_len, buf + bufoff, + len - bufoff); + break; + } + } + wasm_runtime_free(buf); + *nread = len; + return 0; + } +#endif +} + +__wasi_errno_t +wasmtime_ssp_fd_pwrite( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, const __wasi_ciovec_t *iov, size_t iovcnt, + __wasi_filesize_t offset, size_t *nwritten) +{ + if (iovcnt == 0) + return __WASI_EINVAL; + + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_WRITE, 0); + if (error != 0) + return error; + + ssize_t len; +#if CONFIG_HAS_PWRITEV + len = pwritev(fd_number(fo), (const struct iovec *)iov, (int)iovcnt, + (off_t)offset); +#else + if (iovcnt == 1) { + len = pwrite(fd_number(fo), iov->buf, iov->buf_len, offset); + } + else { + // Allocate a single buffer to fit all data. + size_t totalsize = 0; + for (size_t i = 0; i < iovcnt; ++i) + totalsize += iov[i].buf_len; + char *buf = wasm_runtime_malloc(totalsize); + if (buf == NULL) { + fd_object_release(fo); + return __WASI_ENOMEM; + } + size_t bufoff = 0; + for (size_t i = 0; i < iovcnt; ++i) { + bh_memcpy_s(buf + bufoff, totalsize - bufoff, iov[i].buf, + iov[i].buf_len); + bufoff += iov[i].buf_len; + } + + // Perform a single write operation. + len = pwrite(fd_number(fo), buf, totalsize, offset); + wasm_runtime_free(buf); + } +#endif + fd_object_release(fo); + if (len < 0) + return convert_errno(errno); + *nwritten = (size_t)len; + return 0; +} + +__wasi_errno_t +wasmtime_ssp_fd_read( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, const __wasi_iovec_t *iov, size_t iovcnt, size_t *nread) +{ + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_READ, 0); + if (error != 0) + return error; + + ssize_t len = readv(fd_number(fo), (const struct iovec *)iov, (int)iovcnt); + fd_object_release(fo); + if (len < 0) + return convert_errno(errno); + *nread = (size_t)len; + return 0; +} + +__wasi_errno_t +wasmtime_ssp_fd_renumber( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct fd_prestats *prestats, +#endif + __wasi_fd_t from, __wasi_fd_t to) +{ + // Don't allow renumbering over a pre-opened resource. + // TODO: Eventually, we do want to permit this, once libpreopen in + // userspace is capable of removing entries from its tables as well. + { + rwlock_rdlock(&prestats->lock); + struct fd_prestat *prestat; + __wasi_errno_t error = fd_prestats_get_entry(prestats, to, &prestat); + if (error != 0) { + error = fd_prestats_get_entry(prestats, from, &prestat); + } + rwlock_unlock(&prestats->lock); + if (error == 0) { + return __WASI_ENOTSUP; + } + } + + struct fd_table *ft = curfds; + rwlock_wrlock(&ft->lock); + struct fd_entry *fe_from; + __wasi_errno_t error = fd_table_get_entry(ft, from, 0, 0, &fe_from); + if (error != 0) { + rwlock_unlock(&ft->lock); + return error; + } + struct fd_entry *fe_to; + error = fd_table_get_entry(ft, to, 0, 0, &fe_to); + if (error != 0) { + rwlock_unlock(&ft->lock); + return error; + } + + struct fd_object *fo; + fd_table_detach(ft, to, &fo); + refcount_acquire(&fe_from->object->refcount); + fd_table_attach(ft, to, fe_from->object, fe_from->rights_base, + fe_from->rights_inheriting); + fd_object_release(fo); + + // Remove the old fd from the file descriptor table. + fd_table_detach(ft, from, &fo); + fd_object_release(fo); + --ft->used; + + rwlock_unlock(&ft->lock); + return 0; +} + +__wasi_errno_t +wasmtime_ssp_fd_seek( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_filedelta_t offset, __wasi_whence_t whence, + __wasi_filesize_t *newoffset) +{ + int nwhence; + switch (whence) { + case __WASI_WHENCE_CUR: + nwhence = SEEK_CUR; + break; + case __WASI_WHENCE_END: + nwhence = SEEK_END; + break; + case __WASI_WHENCE_SET: + nwhence = SEEK_SET; + break; + default: + return __WASI_EINVAL; + } + + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, + offset == 0 && whence == __WASI_WHENCE_CUR + ? __WASI_RIGHT_FD_TELL + : __WASI_RIGHT_FD_SEEK | __WASI_RIGHT_FD_TELL, + 0); + if (error != 0) + return error; + + off_t ret = lseek(fd_number(fo), offset, nwhence); + fd_object_release(fo); + if (ret < 0) + return convert_errno(errno); + *newoffset = (__wasi_filesize_t)ret; + return 0; +} + +__wasi_errno_t +wasmtime_ssp_fd_tell( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_filesize_t *newoffset) +{ + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_TELL, 0); + if (error != 0) + return error; + + off_t ret = lseek(fd_number(fo), 0, SEEK_CUR); + fd_object_release(fo); + if (ret < 0) + return convert_errno(errno); + *newoffset = (__wasi_filesize_t)ret; + return 0; +} + +__wasi_errno_t +wasmtime_ssp_fd_fdstat_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_fdstat_t *buf) +{ + struct fd_table *ft = curfds; + rwlock_rdlock(&ft->lock); + struct fd_entry *fe; + __wasi_errno_t error = fd_table_get_entry(ft, fd, 0, 0, &fe); + if (error != 0) { + rwlock_unlock(&ft->lock); + return error; + } + + // Extract file descriptor type and rights. + struct fd_object *fo = fe->object; + *buf = (__wasi_fdstat_t){ + .fs_filetype = fo->type, + .fs_rights_base = fe->rights_base, + .fs_rights_inheriting = fe->rights_inheriting, + }; + + // Fetch file descriptor flags. + int ret; + switch (fo->type) { + default: + ret = fcntl(fd_number(fo), F_GETFL); + break; + } + rwlock_unlock(&ft->lock); + if (ret < 0) + return convert_errno(errno); + + if ((ret & O_APPEND) != 0) + buf->fs_flags |= __WASI_FDFLAG_APPEND; +#ifdef O_DSYNC + if ((ret & O_DSYNC) != 0) + buf->fs_flags |= __WASI_FDFLAG_DSYNC; +#endif + if ((ret & O_NONBLOCK) != 0) + buf->fs_flags |= __WASI_FDFLAG_NONBLOCK; +#ifdef O_RSYNC + if ((ret & O_RSYNC) != 0) + buf->fs_flags |= __WASI_FDFLAG_RSYNC; +#endif + if ((ret & O_SYNC) != 0) + buf->fs_flags |= __WASI_FDFLAG_SYNC; + return 0; +} + +__wasi_errno_t +wasmtime_ssp_fd_fdstat_set_flags( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_fdflags_t fs_flags) +{ + int noflags = 0; + if ((fs_flags & __WASI_FDFLAG_APPEND) != 0) + noflags |= O_APPEND; + if ((fs_flags & __WASI_FDFLAG_DSYNC) != 0) +#ifdef O_DSYNC + noflags |= O_DSYNC; +#else + noflags |= O_SYNC; +#endif + if ((fs_flags & __WASI_FDFLAG_NONBLOCK) != 0) + noflags |= O_NONBLOCK; + if ((fs_flags & __WASI_FDFLAG_RSYNC) != 0) +#ifdef O_RSYNC + noflags |= O_RSYNC; +#else + noflags |= O_SYNC; +#endif + if ((fs_flags & __WASI_FDFLAG_SYNC) != 0) + noflags |= O_SYNC; + + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_FDSTAT_SET_FLAGS, 0); + if (error != 0) + return error; + + int ret = fcntl(fd_number(fo), F_SETFL, noflags); + fd_object_release(fo); + if (ret < 0) + return convert_errno(errno); + return 0; +} + +__wasi_errno_t +wasmtime_ssp_fd_fdstat_set_rights( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting) +{ + struct fd_table *ft = curfds; + rwlock_wrlock(&ft->lock); + struct fd_entry *fe; + __wasi_errno_t error = + fd_table_get_entry(ft, fd, fs_rights_base, fs_rights_inheriting, &fe); + if (error != 0) { + rwlock_unlock(&ft->lock); + return error; + } + + // Restrict the rights on the file descriptor. + fe->rights_base = fs_rights_base; + fe->rights_inheriting = fs_rights_inheriting; + rwlock_unlock(&ft->lock); + return 0; +} + +__wasi_errno_t +wasmtime_ssp_fd_sync( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd) +{ + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_SYNC, 0); + if (error != 0) + return error; + + int ret = fsync(fd_number(fo)); + fd_object_release(fo); + if (ret < 0) + return convert_errno(errno); + return 0; +} + +__wasi_errno_t +wasmtime_ssp_fd_write( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, const __wasi_ciovec_t *iov, size_t iovcnt, size_t *nwritten) +{ + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_WRITE, 0); + if (error != 0) + return error; + +#ifndef BH_VPRINTF + ssize_t len = writev(fd_number(fo), (const struct iovec *)iov, (int)iovcnt); +#else + ssize_t len = 0; + /* redirect stdout/stderr output to BH_VPRINTF function */ + if (fd_number(fo) == 1 || fd_number(fo) == 2) { + int i; + const struct iovec *iov1 = (const struct iovec *)iov; + + for (i = 0; i < (int)iovcnt; i++, iov1++) { + if (iov1->iov_len > 0 && iov1->iov_base) { + char format[16]; + + /* make up format string "%.ns" */ + snprintf(format, sizeof(format), "%%.%ds", (int)iov1->iov_len); + len += (ssize_t)os_printf(format, iov1->iov_base); + } + } + } + else { + len = writev(fd_number(fo), (const struct iovec *)iov, (int)iovcnt); + } +#endif /* end of BH_VPRINTF */ + fd_object_release(fo); + if (len < 0) + return convert_errno(errno); + *nwritten = (size_t)len; + return 0; +} + +__wasi_errno_t +wasmtime_ssp_fd_advise( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_filesize_t offset, __wasi_filesize_t len, + __wasi_advice_t advice) +{ +#ifdef POSIX_FADV_NORMAL + int nadvice; + switch (advice) { + case __WASI_ADVICE_DONTNEED: + nadvice = POSIX_FADV_DONTNEED; + break; + case __WASI_ADVICE_NOREUSE: + nadvice = POSIX_FADV_NOREUSE; + break; + case __WASI_ADVICE_NORMAL: + nadvice = POSIX_FADV_NORMAL; + break; + case __WASI_ADVICE_RANDOM: + nadvice = POSIX_FADV_RANDOM; + break; + case __WASI_ADVICE_SEQUENTIAL: + nadvice = POSIX_FADV_SEQUENTIAL; + break; + case __WASI_ADVICE_WILLNEED: + nadvice = POSIX_FADV_WILLNEED; + break; + default: + return __WASI_EINVAL; + } + + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_ADVISE, 0); + if (error != 0) + return error; + + int ret = posix_fadvise(fd_number(fo), (off_t)offset, (off_t)len, nadvice); + fd_object_release(fo); + if (ret != 0) + return convert_errno(ret); + return 0; +#else + // Advisory information can safely be ignored if unsupported. + switch (advice) { + case __WASI_ADVICE_DONTNEED: + case __WASI_ADVICE_NOREUSE: + case __WASI_ADVICE_NORMAL: + case __WASI_ADVICE_RANDOM: + case __WASI_ADVICE_SEQUENTIAL: + case __WASI_ADVICE_WILLNEED: + break; + default: + return __WASI_EINVAL; + } + + // At least check for file descriptor existence. + struct fd_table *ft = curfds; + rwlock_rdlock(&ft->lock); + struct fd_entry *fe; + __wasi_errno_t error = + fd_table_get_entry(ft, fd, __WASI_RIGHT_FD_ADVISE, 0, &fe); + rwlock_unlock(&ft->lock); + return error; +#endif +} + +__wasi_errno_t +wasmtime_ssp_fd_allocate( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_filesize_t offset, __wasi_filesize_t len) +{ + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_ALLOCATE, 0); + if (error != 0) + return error; + +#if CONFIG_HAS_POSIX_FALLOCATE + int ret = posix_fallocate(fd_number(fo), (off_t)offset, (off_t)len); +#else + // At least ensure that the file is grown to the right size. + // TODO(ed): See if this can somehow be implemented without any race + // conditions. We may end up shrinking the file right now. + struct stat sb; + int ret = fstat(fd_number(fo), &sb); + off_t newsize = (off_t)(offset + len); + if (ret == 0 && sb.st_size < newsize) + ret = ftruncate(fd_number(fo), newsize); +#endif + + fd_object_release(fo); + if (ret != 0) + return convert_errno(ret); + return 0; +} + +// Reads the entire contents of a symbolic link, returning the contents +// in an allocated buffer. The allocated buffer is large enough to fit +// at least one extra byte, so the caller may append a trailing slash to +// it. This is needed by path_get(). +static char * +readlinkat_dup(int fd, const char *path, size_t *p_len) +{ + char *buf = NULL; + size_t len = 32; + size_t len_org = len; + + for (;;) { + char *newbuf = wasm_runtime_malloc((uint32)len); + + if (newbuf == NULL) { + if (buf) + wasm_runtime_free(buf); + return NULL; + } + + if (buf != NULL) { + bh_memcpy_s(newbuf, (uint32)len, buf, (uint32)len_org); + wasm_runtime_free(buf); + } + + buf = newbuf; + ssize_t ret = readlinkat(fd, path, buf, len); + if (ret < 0) { + wasm_runtime_free(buf); + return NULL; + } + if ((size_t)ret + 1 < len) { + buf[ret] = '\0'; + *p_len = len; + return buf; + } + len_org = len; + len *= 2; + } +} + +// Lease to a directory, so a path underneath it can be accessed. +// +// This structure is used by system calls that operate on pathnames. In +// this environment, pathnames always consist of a pair of a file +// descriptor representing the directory where the lookup needs to start +// and the actual pathname string. +struct path_access { + int fd; // Directory file descriptor. + const char *path; // Pathname. + bool follow; // Whether symbolic links should be followed. + char *path_start; // Internal: pathname to free. + struct fd_object *fd_object; // Internal: directory file descriptor object. +}; + +// Creates a lease to a file descriptor and pathname pair. If the +// operating system does not implement Capsicum, it also normalizes the +// pathname to ensure the target path is placed underneath the +// directory. +static __wasi_errno_t +path_get(struct fd_table *curfds, struct path_access *pa, __wasi_fd_t fd, + __wasi_lookupflags_t flags, const char *upath, size_t upathlen, + __wasi_rights_t rights_base, __wasi_rights_t rights_inheriting, + bool needs_final_component) + TRYLOCKS_EXCLUSIVE(0, pa->fd_object->refcount) +{ + char *path = str_nullterminate(upath, upathlen); + if (path == NULL) + return convert_errno(errno); + + // Fetch the directory file descriptor. + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, rights_base, rights_inheriting); + if (error != 0) { + wasm_runtime_free(path); + return error; + } + +#if CONFIG_HAS_CAP_ENTER + // Rely on the kernel to constrain access to automatically constrain + // access to files stored underneath this directory. + pa->fd = fd_number(fo); + pa->path = pa->path_start = path; + pa->follow = (flags & __WASI_LOOKUP_SYMLINK_FOLLOW) != 0; + pa->fd_object = fo; + return 0; +#else + // The implementation provides no mechanism to constrain lookups to a + // directory automatically. Emulate this logic by resolving the + // pathname manually. + + // Stack of directory file descriptors. Index 0 always corresponds + // with the directory provided to this function. Entering a directory + // causes a file descriptor to be pushed, while handling ".." entries + // causes an entry to be popped. Index 0 cannot be popped, as this + // would imply escaping the base directory. + int fds[128]; + fds[0] = fd_number(fo); + size_t curfd = 0; + + // Stack of pathname strings used for symlink expansion. By using a + // stack, there is no need to concatenate any pathname strings while + // expanding symlinks. + char *paths[32]; + char *paths_start[32]; + paths[0] = paths_start[0] = path; + size_t curpath = 0; + size_t expansions = 0; + char *symlink; + size_t symlink_len; + + for (;;) { + // Extract the next pathname component from 'paths[curpath]', null + // terminate it and store it in 'file'. 'ends_with_slashes' stores + // whether the pathname component is followed by one or more + // trailing slashes, as this requires it to be a directory. + char *file = paths[curpath]; + char *file_end = file + strcspn(file, "/"); + paths[curpath] = file_end + strspn(file_end, "/"); + bool ends_with_slashes = *file_end == '/'; + *file_end = '\0'; + + // Test for empty pathname strings and absolute paths. + if (file == file_end) { + error = ends_with_slashes ? __WASI_ENOTCAPABLE : __WASI_ENOENT; + goto fail; + } + + if (strcmp(file, ".") == 0) { + // Skip component. + } + else if (strcmp(file, "..") == 0) { + // Pop a directory off the stack. + if (curfd == 0) { + // Attempted to go to parent directory of the directory file + // descriptor. + error = __WASI_ENOTCAPABLE; + goto fail; + } + close(fds[curfd--]); + } + else if (curpath > 0 || *paths[curpath] != '\0' + || (ends_with_slashes && !needs_final_component)) { + // A pathname component whose name we're not interested in that is + // followed by a slash or is followed by other pathname + // components. In other words, a pathname component that must be a + // directory. First attempt to obtain a directory file descriptor + // for it. + int newdir = +#ifdef O_SEARCH + openat(fds[curfd], file, O_SEARCH | O_DIRECTORY | O_NOFOLLOW); +#else + openat(fds[curfd], file, O_RDONLY | O_DIRECTORY | O_NOFOLLOW); +#endif + if (newdir != -1) { + // Success. Push it onto the directory stack. + if (curfd + 1 == sizeof(fds) / sizeof(fds[0])) { + close(newdir); + error = __WASI_ENAMETOOLONG; + goto fail; + } + fds[++curfd] = newdir; + } + else { + // Failed to open it. Attempt symlink expansion. + if (errno != ELOOP && errno != EMLINK && errno != ENOTDIR) { + error = convert_errno(errno); + goto fail; + } + symlink = readlinkat_dup(fds[curfd], file, &symlink_len); + if (symlink != NULL) + goto push_symlink; + + // readlink returns EINVAL if the path isn't a symlink. In that + // case, it's more informative to return ENOTDIR. + if (errno == EINVAL) + errno = ENOTDIR; + + error = convert_errno(errno); + goto fail; + } + } + else { + // The final pathname component. Depending on whether it ends with + // a slash or the symlink-follow flag is set, perform symlink + // expansion. + if (ends_with_slashes + || (flags & __WASI_LOOKUP_SYMLINK_FOLLOW) != 0) { + symlink = readlinkat_dup(fds[curfd], file, &symlink_len); + if (symlink != NULL) + goto push_symlink; + if (errno != EINVAL && errno != ENOENT) { + error = convert_errno(errno); + goto fail; + } + } + + // Not a symlink, meaning we're done. Return the filename, + // together with the directory containing this file. + // + // If the file was followed by a trailing slash, we must retain + // it, to ensure system calls properly return ENOTDIR. + // Unfortunately, this opens up a race condition, because this + // means that users of path_get() will perform symlink expansion a + // second time. There is nothing we can do to mitigate this, as + // far as I know. + if (ends_with_slashes) + *file_end = '/'; + pa->path = file; + pa->path_start = paths_start[0]; + goto success; + } + + if (*paths[curpath] == '\0') { + if (curpath == 0) { + // No further pathname components to process. We may end up here + // when called on paths like ".", "a/..", but also if the path + // had trailing slashes and the caller is not interested in the + // name of the pathname component. + wasm_runtime_free(paths_start[0]); + pa->path = "."; + pa->path_start = NULL; + goto success; + } + + // Finished expanding symlink. Continue processing along the + // original path. + wasm_runtime_free(paths_start[curpath--]); + } + continue; + + push_symlink: + // Prevent infinite loops by placing an upper limit on the number of + // symlink expansions. + if (++expansions == 128) { + wasm_runtime_free(symlink); + error = __WASI_ELOOP; + goto fail; + } + + if (*paths[curpath] == '\0') { + // The original path already finished processing. Replace it by + // this symlink entirely. + wasm_runtime_free(paths_start[curpath]); + } + else if (curpath + 1 == sizeof(paths) / sizeof(paths[0])) { + // Too many nested symlinks. Stop processing. + wasm_runtime_free(symlink); + error = __WASI_ELOOP; + goto fail; + } + else { + // The original path still has components left. Retain the + // components that remain, so we can process them afterwards. + ++curpath; + } + + // Append a trailing slash to the symlink if the path leading up to + // it also contained one. Otherwise we would not throw ENOTDIR if + // the target is not a directory. + if (ends_with_slashes) + bh_strcat_s(symlink, (uint32)symlink_len, "/"); + paths[curpath] = paths_start[curpath] = symlink; + } + +success: + // Return the lease. Close all directories, except the one the caller + // needs to use. + for (size_t i = 1; i < curfd; ++i) + close(fds[i]); + pa->fd = fds[curfd]; + pa->follow = false; + pa->fd_object = fo; + return 0; + +fail: + // Failure. Free all resources. + for (size_t i = 1; i <= curfd; ++i) + close(fds[i]); + for (size_t i = 0; i <= curpath; ++i) + wasm_runtime_free(paths_start[i]); + fd_object_release(fo); + return error; +#endif +} + +static __wasi_errno_t +path_get_nofollow(struct fd_table *curfds, struct path_access *pa, + __wasi_fd_t fd, const char *path, size_t pathlen, + __wasi_rights_t rights_base, + __wasi_rights_t rights_inheriting, bool needs_final_component) + TRYLOCKS_EXCLUSIVE(0, pa->fd_object->refcount) +{ + __wasi_lookupflags_t flags = 0; + return path_get(curfds, pa, fd, flags, path, pathlen, rights_base, + rights_inheriting, needs_final_component); +} + +static void +path_put(struct path_access *pa) UNLOCKS(pa->fd_object->refcount) +{ + if (pa->path_start) + wasm_runtime_free(pa->path_start); + if (fd_number(pa->fd_object) != pa->fd) + close(pa->fd); + fd_object_release(pa->fd_object); +} + +__wasi_errno_t +wasmtime_ssp_path_create_directory( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, const char *path, size_t pathlen) +{ + struct path_access pa; + __wasi_errno_t error = + path_get_nofollow(curfds, &pa, fd, path, pathlen, + __WASI_RIGHT_PATH_CREATE_DIRECTORY, 0, true); + if (error != 0) + return error; + + int ret = mkdirat(pa.fd, pa.path, 0777); + path_put(&pa); + if (ret < 0) + return convert_errno(errno); + return 0; +} + +static bool +validate_path(const char *path, struct fd_prestats *pt) +{ + size_t i; + char path_resolved[PATH_MAX], prestat_dir_resolved[PATH_MAX]; + char *path_real, *prestat_dir_real; + + if (!(path_real = realpath(path, path_resolved))) + /* path doesn't exist, creating a link to this file + is allowed: if this file is to be created in + the future, WASI will strictly check whether it + can be created or not. */ + return true; + + for (i = 0; i < pt->size; i++) { + if (pt->prestats[i].dir) { + if (!(prestat_dir_real = + realpath(pt->prestats[i].dir, prestat_dir_resolved))) + return false; + if (!strncmp(path_real, prestat_dir_real, strlen(prestat_dir_real))) + return true; + } + } + + return false; +} + +__wasi_errno_t +wasmtime_ssp_path_link( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct fd_prestats *prestats, +#endif + __wasi_fd_t old_fd, __wasi_lookupflags_t old_flags, const char *old_path, + size_t old_path_len, __wasi_fd_t new_fd, const char *new_path, + size_t new_path_len) +{ + struct path_access old_pa; + __wasi_errno_t error = + path_get(curfds, &old_pa, old_fd, old_flags, old_path, old_path_len, + __WASI_RIGHT_PATH_LINK_SOURCE, 0, false); + if (error != 0) + return error; + + struct path_access new_pa; + error = path_get_nofollow(curfds, &new_pa, new_fd, new_path, new_path_len, + __WASI_RIGHT_PATH_LINK_TARGET, 0, true); + if (error != 0) { + path_put(&old_pa); + return error; + } + + rwlock_rdlock(&prestats->lock); + if (!validate_path(old_pa.path, prestats) + || !validate_path(new_pa.path, prestats)) { + rwlock_unlock(&prestats->lock); + return __WASI_EBADF; + } + rwlock_unlock(&prestats->lock); + + int ret = linkat(old_pa.fd, old_pa.path, new_pa.fd, new_pa.path, + old_pa.follow ? AT_SYMLINK_FOLLOW : 0); + if (ret < 0 && errno == ENOTSUP && !old_pa.follow) { + // OS X doesn't allow creating hardlinks to symbolic links. + // Duplicate the symbolic link instead. + size_t target_len; + char *target = readlinkat_dup(old_pa.fd, old_pa.path, &target_len); + if (target != NULL) { + bh_assert(target[target_len] == '\0'); + rwlock_rdlock(&prestats->lock); + if (!validate_path(target, prestats)) { + rwlock_unlock(&prestats->lock); + wasm_runtime_free(target); + return __WASI_EBADF; + } + rwlock_unlock(&prestats->lock); + ret = symlinkat(target, new_pa.fd, new_pa.path); + wasm_runtime_free(target); + } + } + path_put(&old_pa); + path_put(&new_pa); + if (ret < 0) + return convert_errno(errno); + return 0; +} + +__wasi_errno_t +wasmtime_ssp_path_open( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t dirfd, __wasi_lookupflags_t dirflags, const char *path, + size_t pathlen, __wasi_oflags_t oflags, __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting, __wasi_fdflags_t fs_flags, + __wasi_fd_t *fd) +{ + // Rights that should be installed on the new file descriptor. + __wasi_rights_t rights_base = fs_rights_base; + __wasi_rights_t rights_inheriting = fs_rights_inheriting; + + // Which open() mode should be used to satisfy the needed rights. + bool read = + (rights_base & (__WASI_RIGHT_FD_READ | __WASI_RIGHT_FD_READDIR)) != 0; + bool write = + (rights_base + & (__WASI_RIGHT_FD_DATASYNC | __WASI_RIGHT_FD_WRITE + | __WASI_RIGHT_FD_ALLOCATE | __WASI_RIGHT_FD_FILESTAT_SET_SIZE)) + != 0; + int noflags = write ? read ? O_RDWR : O_WRONLY : O_RDONLY; + + // Which rights are needed on the directory file descriptor. + __wasi_rights_t needed_base = __WASI_RIGHT_PATH_OPEN; + __wasi_rights_t needed_inheriting = rights_base | rights_inheriting; + + // Convert open flags. + if ((oflags & __WASI_O_CREAT) != 0) { + noflags |= O_CREAT; + needed_base |= __WASI_RIGHT_PATH_CREATE_FILE; + } + if ((oflags & __WASI_O_DIRECTORY) != 0) + noflags |= O_DIRECTORY; + if ((oflags & __WASI_O_EXCL) != 0) + noflags |= O_EXCL; + if ((oflags & __WASI_O_TRUNC) != 0) { + noflags |= O_TRUNC; + needed_base |= __WASI_RIGHT_PATH_FILESTAT_SET_SIZE; + } + + // Convert file descriptor flags. + if ((fs_flags & __WASI_FDFLAG_APPEND) != 0) + noflags |= O_APPEND; + if ((fs_flags & __WASI_FDFLAG_DSYNC) != 0) { +#ifdef O_DSYNC + noflags |= O_DSYNC; +#else + noflags |= O_SYNC; +#endif + needed_inheriting |= __WASI_RIGHT_FD_DATASYNC; + } + if ((fs_flags & __WASI_FDFLAG_NONBLOCK) != 0) + noflags |= O_NONBLOCK; + if ((fs_flags & __WASI_FDFLAG_RSYNC) != 0) { +#ifdef O_RSYNC + noflags |= O_RSYNC; +#else + noflags |= O_SYNC; +#endif + needed_inheriting |= __WASI_RIGHT_FD_SYNC; + } + if ((fs_flags & __WASI_FDFLAG_SYNC) != 0) { + noflags |= O_SYNC; + needed_inheriting |= __WASI_RIGHT_FD_SYNC; + } + if (write && (noflags & (O_APPEND | O_TRUNC)) == 0) + needed_inheriting |= __WASI_RIGHT_FD_SEEK; + + struct path_access pa; + __wasi_errno_t error = + path_get(curfds, &pa, dirfd, dirflags, path, pathlen, needed_base, + needed_inheriting, (oflags & __WASI_O_CREAT) != 0); + if (error != 0) + return error; + if (!pa.follow) + noflags |= O_NOFOLLOW; + + int nfd = openat(pa.fd, pa.path, noflags, 0666); + if (nfd < 0) { + int openat_errno = errno; + // Linux returns ENXIO instead of EOPNOTSUPP when opening a socket. + if (openat_errno == ENXIO) { + struct stat sb; + int ret = fstatat(pa.fd, pa.path, &sb, + pa.follow ? 0 : AT_SYMLINK_NOFOLLOW); + path_put(&pa); + return ret == 0 && S_ISSOCK(sb.st_mode) ? __WASI_ENOTSUP + : __WASI_ENXIO; + } + // Linux returns ENOTDIR instead of ELOOP when using + // O_NOFOLLOW|O_DIRECTORY on a symlink. + if (openat_errno == ENOTDIR + && (noflags & (O_NOFOLLOW | O_DIRECTORY)) != 0) { + struct stat sb; + int ret = fstatat(pa.fd, pa.path, &sb, AT_SYMLINK_NOFOLLOW); + if (S_ISLNK(sb.st_mode)) { + path_put(&pa); + return __WASI_ELOOP; + } + (void)ret; + } + path_put(&pa); + // FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on + // a symlink. + if (!pa.follow && openat_errno == EMLINK) + return __WASI_ELOOP; + return convert_errno(openat_errno); + } + path_put(&pa); + + // Determine the type of the new file descriptor and which rights + // contradict with this type. + __wasi_filetype_t type; + __wasi_rights_t max_base, max_inheriting; + error = fd_determine_type_rights(nfd, &type, &max_base, &max_inheriting); + if (error != 0) { + close(nfd); + return error; + } + + { + struct stat sb; + + if (fstat(nfd, &sb) < 0) { + close(nfd); + return convert_errno(errno); + } + + if (S_ISDIR(sb.st_mode)) + rights_base |= (__wasi_rights_t)RIGHTS_DIRECTORY_BASE; + else if (S_ISREG(sb.st_mode)) + rights_base |= (__wasi_rights_t)RIGHTS_REGULAR_FILE_BASE; + } + + return fd_table_insert_fd(curfds, nfd, type, rights_base & max_base, + rights_inheriting & max_inheriting, fd); +} + +// Copies out directory entry metadata or filename, potentially +// truncating it in the process. +static void +fd_readdir_put(void *buf, size_t bufsize, size_t *bufused, const void *elem, + size_t elemsize) +{ + size_t bufavail = bufsize - *bufused; + if (elemsize > bufavail) + elemsize = bufavail; + bh_memcpy_s((char *)buf + *bufused, (uint32)bufavail, elem, + (uint32)elemsize); + *bufused += elemsize; +} + +__wasi_errno_t +wasmtime_ssp_fd_readdir( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, void *buf, size_t nbyte, __wasi_dircookie_t cookie, + size_t *bufused) +{ + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_READDIR, 0); + if (error != 0) { + return error; + } + + // Create a directory handle if none has been opened yet. + mutex_lock(&fo->directory.lock); + DIR *dp = fo->directory.handle; + if (dp == NULL) { + dp = fdopendir(fd_number(fo)); + if (dp == NULL) { + mutex_unlock(&fo->directory.lock); + fd_object_release(fo); + return convert_errno(errno); + } + fo->directory.handle = dp; + fo->directory.offset = __WASI_DIRCOOKIE_START; + } + + // Seek to the right position if the requested offset does not match + // the current offset. + if (fo->directory.offset != cookie) { + if (cookie == __WASI_DIRCOOKIE_START) + rewinddir(dp); + else + seekdir(dp, (long)cookie); + fo->directory.offset = cookie; + } + + *bufused = 0; + while (*bufused < nbyte) { + // Read the next directory entry. + errno = 0; + struct dirent *de = readdir(dp); + if (de == NULL) { + mutex_unlock(&fo->directory.lock); + fd_object_release(fo); + return errno == 0 || *bufused > 0 ? 0 : convert_errno(errno); + } + fo->directory.offset = (__wasi_dircookie_t)telldir(dp); + + // Craft a directory entry and copy that back. + size_t namlen = strlen(de->d_name); + __wasi_dirent_t cde = { + .d_next = fo->directory.offset, +#if CONFIG_HAS_D_INO + .d_ino = de->d_ino, +#else + .d_ino = 0, +#endif + .d_namlen = (uint32)namlen, + }; + switch (de->d_type) { + case DT_BLK: + cde.d_type = __WASI_FILETYPE_BLOCK_DEVICE; + break; + case DT_CHR: + cde.d_type = __WASI_FILETYPE_CHARACTER_DEVICE; + break; + case DT_DIR: + cde.d_type = __WASI_FILETYPE_DIRECTORY; + break; + case DT_FIFO: + cde.d_type = __WASI_FILETYPE_SOCKET_STREAM; + break; + case DT_LNK: + cde.d_type = __WASI_FILETYPE_SYMBOLIC_LINK; + break; + case DT_REG: + cde.d_type = __WASI_FILETYPE_REGULAR_FILE; + break; +#ifdef DT_SOCK + case DT_SOCK: + // Technically not correct, but good enough. + cde.d_type = __WASI_FILETYPE_SOCKET_STREAM; + break; +#endif + default: + cde.d_type = __WASI_FILETYPE_UNKNOWN; + break; + } + fd_readdir_put(buf, nbyte, bufused, &cde, sizeof(cde)); + fd_readdir_put(buf, nbyte, bufused, de->d_name, namlen); + } + mutex_unlock(&fo->directory.lock); + fd_object_release(fo); + return 0; +} + +__wasi_errno_t +wasmtime_ssp_path_readlink( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, const char *path, size_t pathlen, char *buf, size_t bufsize, + size_t *bufused) +{ + struct path_access pa; + __wasi_errno_t error = path_get_nofollow( + curfds, &pa, fd, path, pathlen, __WASI_RIGHT_PATH_READLINK, 0, false); + if (error != 0) + return error; + + // Linux requires that the buffer size is positive. whereas POSIX does + // not. Use a fake buffer to store the results if the size is zero. + char fakebuf[1]; + ssize_t len = readlinkat(pa.fd, pa.path, bufsize == 0 ? fakebuf : buf, + bufsize == 0 ? sizeof(fakebuf) : bufsize); + path_put(&pa); + if (len < 0) + return convert_errno(errno); + *bufused = (size_t)len < bufsize ? (size_t)len : bufsize; + return 0; +} + +__wasi_errno_t +wasmtime_ssp_path_rename( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t old_fd, const char *old_path, size_t old_path_len, + __wasi_fd_t new_fd, const char *new_path, size_t new_path_len) +{ + struct path_access old_pa; + __wasi_errno_t error = + path_get_nofollow(curfds, &old_pa, old_fd, old_path, old_path_len, + __WASI_RIGHT_PATH_RENAME_SOURCE, 0, true); + if (error != 0) + return error; + + struct path_access new_pa; + error = path_get_nofollow(curfds, &new_pa, new_fd, new_path, new_path_len, + __WASI_RIGHT_PATH_RENAME_TARGET, 0, true); + if (error != 0) { + path_put(&old_pa); + return error; + } + + int ret = renameat(old_pa.fd, old_pa.path, new_pa.fd, new_pa.path); + path_put(&old_pa); + path_put(&new_pa); + if (ret < 0) { + return convert_errno(errno); + } + return 0; +} + +// Converts a POSIX stat structure to a CloudABI filestat structure. +static void +convert_stat(const struct stat *in, __wasi_filestat_t *out) +{ + *out = (__wasi_filestat_t){ + .st_dev = in->st_dev, + .st_ino = in->st_ino, + .st_nlink = (__wasi_linkcount_t)in->st_nlink, + .st_size = (__wasi_filesize_t)in->st_size, + .st_atim = convert_timespec(&in->st_atim), + .st_mtim = convert_timespec(&in->st_mtim), + .st_ctim = convert_timespec(&in->st_ctim), + }; +} + +__wasi_errno_t +wasmtime_ssp_fd_filestat_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_filestat_t *buf) +{ + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_FILESTAT_GET, 0); + if (error != 0) + return error; + + int ret; + switch (fo->type) { + default: + { + struct stat sb; + ret = fstat(fd_number(fo), &sb); + convert_stat(&sb, buf); + break; + } + } + buf->st_filetype = fo->type; + fd_object_release(fo); + if (ret < 0) + return convert_errno(errno); + return 0; +} + +static void +convert_timestamp(__wasi_timestamp_t in, struct timespec *out) +{ + // Store sub-second remainder. +#if defined(__SYSCALL_SLONG_TYPE) + out->tv_nsec = (__SYSCALL_SLONG_TYPE)(in % 1000000000); +#else + out->tv_nsec = (long)(in % 1000000000); +#endif + in /= 1000000000; + + // Clamp to the maximum in case it would overflow our system's time_t. + out->tv_sec = (time_t)in < BH_TIME_T_MAX ? (time_t)in : BH_TIME_T_MAX; +} + +// Converts the provided timestamps and flags to a set of arguments for +// futimens() and utimensat(). +static void +convert_utimens_arguments(__wasi_timestamp_t st_atim, + __wasi_timestamp_t st_mtim, + __wasi_fstflags_t fstflags, struct timespec *ts) +{ + if ((fstflags & __WASI_FILESTAT_SET_ATIM_NOW) != 0) { + ts[0].tv_nsec = UTIME_NOW; + } + else if ((fstflags & __WASI_FILESTAT_SET_ATIM) != 0) { + convert_timestamp(st_atim, &ts[0]); + } + else { + ts[0].tv_nsec = UTIME_OMIT; + } + + if ((fstflags & __WASI_FILESTAT_SET_MTIM_NOW) != 0) { + ts[1].tv_nsec = UTIME_NOW; + } + else if ((fstflags & __WASI_FILESTAT_SET_MTIM) != 0) { + convert_timestamp(st_mtim, &ts[1]); + } + else { + ts[1].tv_nsec = UTIME_OMIT; + } +} + +__wasi_errno_t +wasmtime_ssp_fd_filestat_set_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_filesize_t st_size) +{ + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_FILESTAT_SET_SIZE, 0); + if (error != 0) + return error; + + int ret = ftruncate(fd_number(fo), (off_t)st_size); + fd_object_release(fo); + if (ret < 0) + return convert_errno(errno); + return 0; +} + +__wasi_errno_t +wasmtime_ssp_fd_filestat_set_times( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_timestamp_t st_atim, __wasi_timestamp_t st_mtim, + __wasi_fstflags_t fstflags) +{ + if ((fstflags + & ~(__WASI_FILESTAT_SET_ATIM | __WASI_FILESTAT_SET_ATIM_NOW + | __WASI_FILESTAT_SET_MTIM | __WASI_FILESTAT_SET_MTIM_NOW)) + != 0) + return __WASI_EINVAL; + + struct fd_object *fo; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_FD_FILESTAT_SET_TIMES, 0); + if (error != 0) + return error; + + struct timespec ts[2]; + convert_utimens_arguments(st_atim, st_mtim, fstflags, ts); + int ret = futimens(fd_number(fo), ts); + + fd_object_release(fo); + if (ret < 0) + return convert_errno(errno); + return 0; +} + +__wasi_errno_t +wasmtime_ssp_path_filestat_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_lookupflags_t flags, const char *path, + size_t pathlen, __wasi_filestat_t *buf) +{ + struct path_access pa; + __wasi_errno_t error = path_get(curfds, &pa, fd, flags, path, pathlen, + __WASI_RIGHT_PATH_FILESTAT_GET, 0, false); + if (error != 0) + return error; + + struct stat sb; + int ret = fstatat(pa.fd, pa.path, &sb, pa.follow ? 0 : AT_SYMLINK_NOFOLLOW); + path_put(&pa); + if (ret < 0) + return convert_errno(errno); + convert_stat(&sb, buf); + + // Convert the file type. In the case of sockets there is no way we + // can easily determine the exact socket type. + if (S_ISBLK(sb.st_mode)) + buf->st_filetype = __WASI_FILETYPE_BLOCK_DEVICE; + else if (S_ISCHR(sb.st_mode)) + buf->st_filetype = __WASI_FILETYPE_CHARACTER_DEVICE; + else if (S_ISDIR(sb.st_mode)) + buf->st_filetype = __WASI_FILETYPE_DIRECTORY; + else if (S_ISFIFO(sb.st_mode)) + buf->st_filetype = __WASI_FILETYPE_SOCKET_STREAM; + else if (S_ISLNK(sb.st_mode)) + buf->st_filetype = __WASI_FILETYPE_SYMBOLIC_LINK; + else if (S_ISREG(sb.st_mode)) + buf->st_filetype = __WASI_FILETYPE_REGULAR_FILE; + else if (S_ISSOCK(sb.st_mode)) + buf->st_filetype = __WASI_FILETYPE_SOCKET_STREAM; + return 0; +} + +__wasi_errno_t +wasmtime_ssp_path_filestat_set_times( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_lookupflags_t flags, const char *path, + size_t pathlen, __wasi_timestamp_t st_atim, __wasi_timestamp_t st_mtim, + __wasi_fstflags_t fstflags) +{ + if (((fstflags + & ~(__WASI_FILESTAT_SET_ATIM | __WASI_FILESTAT_SET_ATIM_NOW + | __WASI_FILESTAT_SET_MTIM | __WASI_FILESTAT_SET_MTIM_NOW)) + != 0) + /* ATIM & ATIM_NOW can't be set at the same time */ + || ((fstflags & __WASI_FILESTAT_SET_ATIM) != 0 + && (fstflags & __WASI_FILESTAT_SET_ATIM_NOW) != 0) + /* MTIM & MTIM_NOW can't be set at the same time */ + || ((fstflags & __WASI_FILESTAT_SET_MTIM) != 0 + && (fstflags & __WASI_FILESTAT_SET_MTIM_NOW) != 0)) + return __WASI_EINVAL; + + struct path_access pa; + __wasi_errno_t error = + path_get(curfds, &pa, fd, flags, path, pathlen, + __WASI_RIGHT_PATH_FILESTAT_SET_TIMES, 0, false); + if (error != 0) + return error; + + struct timespec ts[2]; + convert_utimens_arguments(st_atim, st_mtim, fstflags, ts); + int ret = + utimensat(pa.fd, pa.path, ts, pa.follow ? 0 : AT_SYMLINK_NOFOLLOW); + + path_put(&pa); + if (ret < 0) + return convert_errno(errno); + return 0; +} + +__wasi_errno_t +wasmtime_ssp_path_symlink( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct fd_prestats *prestats, +#endif + const char *old_path, size_t old_path_len, __wasi_fd_t fd, + const char *new_path, size_t new_path_len) +{ + char *target = str_nullterminate(old_path, old_path_len); + if (target == NULL) + return convert_errno(errno); + + struct path_access pa; + __wasi_errno_t error = + path_get_nofollow(curfds, &pa, fd, new_path, new_path_len, + __WASI_RIGHT_PATH_SYMLINK, 0, true); + if (error != 0) { + wasm_runtime_free(target); + return error; + } + + rwlock_rdlock(&prestats->lock); + if (!validate_path(target, prestats)) { + rwlock_unlock(&prestats->lock); + wasm_runtime_free(target); + return __WASI_EBADF; + } + rwlock_unlock(&prestats->lock); + + int ret = symlinkat(target, pa.fd, pa.path); + path_put(&pa); + wasm_runtime_free(target); + if (ret < 0) + return convert_errno(errno); + return 0; +} + +__wasi_errno_t +wasmtime_ssp_path_unlink_file( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, const char *path, size_t pathlen) +{ + struct path_access pa; + __wasi_errno_t error = path_get_nofollow( + curfds, &pa, fd, path, pathlen, __WASI_RIGHT_PATH_UNLINK_FILE, 0, true); + if (error != 0) + return error; + + int ret = unlinkat(pa.fd, pa.path, 0); +#ifndef __linux__ + // Non-Linux implementations may return EPERM when attempting to remove a + // directory without REMOVEDIR. While that's what POSIX specifies, it's + // less useful. Adjust this to EISDIR. It doesn't matter that this is not + // atomic with the unlinkat, because if the file is removed and a directory + // is created before fstatat sees it, we're racing with that change anyway + // and unlinkat could have legitimately seen the directory if the race had + // turned out differently. + if (ret < 0 && errno == EPERM) { + struct stat statbuf; + if (fstatat(pa.fd, pa.path, &statbuf, AT_SYMLINK_NOFOLLOW) == 0 + && S_ISDIR(statbuf.st_mode)) { + errno = EISDIR; + } + } +#endif + path_put(&pa); + if (ret < 0) { + return convert_errno(errno); + } + return 0; +} + +__wasi_errno_t +wasmtime_ssp_path_remove_directory( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, const char *path, size_t pathlen) +{ + struct path_access pa; + __wasi_errno_t error = + path_get_nofollow(curfds, &pa, fd, path, pathlen, + __WASI_RIGHT_PATH_REMOVE_DIRECTORY, 0, true); + if (error != 0) + return error; + + int ret = unlinkat(pa.fd, pa.path, AT_REMOVEDIR); +#ifndef __linux__ + // POSIX permits either EEXIST or ENOTEMPTY when the directory is not empty. + // Map it to ENOTEMPTY. + if (ret < 0 && errno == EEXIST) { + errno = ENOTEMPTY; + } +#endif + path_put(&pa); + if (ret < 0) { + return convert_errno(errno); + } + return 0; +} + +__wasi_errno_t +wasmtime_ssp_poll_oneoff( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + const __wasi_subscription_t *in, __wasi_event_t *out, size_t nsubscriptions, + size_t *nevents) NO_LOCK_ANALYSIS +{ + // Sleeping. + if (nsubscriptions == 1 && in[0].u.type == __WASI_EVENTTYPE_CLOCK) { + out[0] = (__wasi_event_t){ + .userdata = in[0].userdata, + .type = in[0].u.type, + }; +#if CONFIG_HAS_CLOCK_NANOSLEEP + clockid_t clock_id; + if (convert_clockid(in[0].u.u.clock.clock_id, &clock_id)) { + struct timespec ts; + convert_timestamp(in[0].u.u.clock.timeout, &ts); + int ret = clock_nanosleep( + clock_id, + (in[0].u.u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) != 0 + ? TIMER_ABSTIME + : 0, + &ts, NULL); + if (ret != 0) + out[0].error = convert_errno(ret); + } + else { + out[0].error = __WASI_ENOTSUP; + } +#else + switch (in[0].u.u.clock.clock_id) { + case __WASI_CLOCK_MONOTONIC: + if ((in[0].u.u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) + != 0) { + // TODO(ed): Implement. + fputs("Unimplemented absolute sleep on monotonic clock\n", + stderr); + out[0].error = __WASI_ENOSYS; + } + else { + // Perform relative sleeps on the monotonic clock also using + // nanosleep(). This is incorrect, but good enough for now. + struct timespec ts; + convert_timestamp(in[0].u.u.clock.timeout, &ts); + nanosleep(&ts, NULL); + } + break; + case __WASI_CLOCK_REALTIME: + if ((in[0].u.u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) + != 0) { + // Sleeping to an absolute point in time can only be done + // by waiting on a condition variable. + struct mutex mutex; + struct cond cond; + + if (!mutex_init(&mutex)) + return -1; + if (!cond_init_realtime(&cond)) { + mutex_destroy(&mutex); + return -1; + } + mutex_lock(&mutex); + cond_timedwait(&cond, &mutex, in[0].u.u.clock.timeout, + true); + mutex_unlock(&mutex); + mutex_destroy(&mutex); + cond_destroy(&cond); + } + else { + // Relative sleeps can be done using nanosleep(). + struct timespec ts; + convert_timestamp(in[0].u.u.clock.timeout, &ts); + nanosleep(&ts, NULL); + } + break; + default: + out[0].error = __WASI_ENOTSUP; + break; + } +#endif + *nevents = 1; + if (out[0].error != 0) + return convert_errno(out[0].error); + return 0; + } + + // Last option: call into poll(). This can only be done in case all + // subscriptions consist of __WASI_EVENTTYPE_FD_READ and + // __WASI_EVENTTYPE_FD_WRITE entries. There may be up to one + // __WASI_EVENTTYPE_CLOCK entry to act as a timeout. These are also + // the subscriptions generate by cloudlibc's poll() and select(). + struct fd_object **fos = + wasm_runtime_malloc((uint32)(nsubscriptions * sizeof(*fos))); + if (fos == NULL) + return __WASI_ENOMEM; + struct pollfd *pfds = + wasm_runtime_malloc((uint32)(nsubscriptions * sizeof(*pfds))); + if (pfds == NULL) { + wasm_runtime_free(fos); + return __WASI_ENOMEM; + } + + // Convert subscriptions to pollfd entries. Increase the reference + // count on the file descriptors to ensure they remain valid across + // the call to poll(). + struct fd_table *ft = curfds; + rwlock_rdlock(&ft->lock); + *nevents = 0; + const __wasi_subscription_t *clock_subscription = NULL; + for (size_t i = 0; i < nsubscriptions; ++i) { + const __wasi_subscription_t *s = &in[i]; + switch (s->u.type) { + case __WASI_EVENTTYPE_FD_READ: + case __WASI_EVENTTYPE_FD_WRITE: + { + __wasi_errno_t error = + fd_object_get_locked(&fos[i], ft, s->u.u.fd_readwrite.fd, + __WASI_RIGHT_POLL_FD_READWRITE, 0); + if (error == 0) { + // Proper file descriptor on which we can poll(). + pfds[i] = (struct pollfd){ + .fd = fd_number(fos[i]), + .events = s->u.type == __WASI_EVENTTYPE_FD_READ + ? POLLIN + : POLLOUT, + }; + } + else { + // Invalid file descriptor or rights missing. + fos[i] = NULL; + pfds[i] = (struct pollfd){ .fd = -1 }; + out[(*nevents)++] = (__wasi_event_t){ + .userdata = s->userdata, + .error = error, + .type = s->u.type, + }; + } + break; + } + case __WASI_EVENTTYPE_CLOCK: + if (clock_subscription == NULL + && (s->u.u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) + == 0) { + // Relative timeout. + fos[i] = NULL; + pfds[i] = (struct pollfd){ .fd = -1 }; + clock_subscription = s; + break; + } + // Fallthrough. + default: + // Unsupported event. + fos[i] = NULL; + pfds[i] = (struct pollfd){ .fd = -1 }; + out[(*nevents)++] = (__wasi_event_t){ + .userdata = s->userdata, + .error = __WASI_ENOSYS, + .type = s->u.type, + }; + break; + } + } + rwlock_unlock(&ft->lock); + + // Use a zero-second timeout in case we've already generated events in + // the loop above. + int timeout; + if (*nevents != 0) { + timeout = 0; + } + else if (clock_subscription != NULL) { + __wasi_timestamp_t ts = clock_subscription->u.u.clock.timeout / 1000000; + timeout = ts > INT_MAX ? -1 : (int)ts; + } + else { + timeout = -1; + } + int ret = poll(pfds, nsubscriptions, timeout); + + __wasi_errno_t error = 0; + if (ret == -1) { + error = convert_errno(errno); + } + else if (ret == 0 && *nevents == 0 && clock_subscription != NULL) { + // No events triggered. Trigger the clock event. + out[(*nevents)++] = (__wasi_event_t){ + .userdata = clock_subscription->userdata, + .type = __WASI_EVENTTYPE_CLOCK, + }; + } + else { + // Events got triggered. Don't trigger the clock event. + for (size_t i = 0; i < nsubscriptions; ++i) { + if (pfds[i].fd >= 0) { + __wasi_filesize_t nbytes = 0; + if (in[i].u.type == __WASI_EVENTTYPE_FD_READ) { + int l; + if (ioctl(fd_number(fos[i]), FIONREAD, &l) == 0) + nbytes = (__wasi_filesize_t)l; + } + if ((pfds[i].revents & POLLNVAL) != 0) { + // Bad file descriptor. This normally cannot occur, as + // referencing the file descriptor object will always ensure + // the descriptor is valid. Still, macOS may sometimes + // return this on FIFOs when reaching end-of-file. + out[(*nevents)++] = (__wasi_event_t){ + .userdata = in[i].userdata, +#ifdef __APPLE__ + .u.fd_readwrite.nbytes = nbytes, + .u.fd_readwrite.flags = + __WASI_EVENT_FD_READWRITE_HANGUP, +#else + .error = __WASI_EBADF, +#endif + .type = in[i].u.type, + }; + } + else if ((pfds[i].revents & POLLERR) != 0) { + // File descriptor is in an error state. + out[(*nevents)++] = (__wasi_event_t){ + .userdata = in[i].userdata, + .error = __WASI_EIO, + .type = in[i].u.type, + }; + } + else if ((pfds[i].revents & POLLHUP) != 0) { + // End-of-file. + out[(*nevents)++] = (__wasi_event_t){ + .userdata = in[i].userdata, + .type = in[i].u.type, + .u.fd_readwrite.nbytes = nbytes, + .u.fd_readwrite.flags = + __WASI_EVENT_FD_READWRITE_HANGUP, + }; + } + else if ((pfds[i].revents & (POLLIN | POLLOUT)) != 0) { + // Read or write possible. + out[(*nevents)++] = (__wasi_event_t){ + .userdata = in[i].userdata, + .type = in[i].u.type, + .u.fd_readwrite.nbytes = nbytes, + }; + } + } + } + } + + for (size_t i = 0; i < nsubscriptions; ++i) + if (fos[i] != NULL) + fd_object_release(fos[i]); + wasm_runtime_free(fos); + wasm_runtime_free(pfds); + return error; +} + +#if 0 +/** + * We throw exception in libc-wasi wrapper function wasi_proc_exit() + * but not call this function. + */ +void wasmtime_ssp_proc_exit( + __wasi_exitcode_t rval +) { + _Exit((int32)rval); +} +#endif + +__wasi_errno_t +wasmtime_ssp_proc_raise(__wasi_signal_t sig) +{ + static const int signals[] = { +#define X(v) [__WASI_##v] = v +#if defined(SIGABRT) + X(SIGABRT), +#endif +#if defined(SIGALRM) + X(SIGALRM), +#endif +#if defined(SIGBUS) + X(SIGBUS), +#endif +#if defined(SIGCHLD) + X(SIGCHLD), +#endif +#if defined(SIGCONT) + X(SIGCONT), +#endif +#if defined(SIGFPE) + X(SIGFPE), +#endif +#if defined(SIGHUP) + X(SIGHUP), +#endif +#if defined(SIGILL) + X(SIGILL), +#endif +#if defined(SIGINT) + X(SIGINT), +#endif +#if defined(SIGKILL) + X(SIGKILL), +#endif +#if defined(SIGPIPE) + X(SIGPIPE), +#endif +#if defined(SIGQUIT) + X(SIGQUIT), +#endif +#if defined(SIGSYS) + X(SIGSEGV), +#endif +#if defined(SIGSTOP) + X(SIGSTOP), +#endif +#if defined(SIGSYS) + X(SIGSYS), +#endif +#if defined(SIGTERM) + X(SIGTERM), +#endif +#if defined(SIGTRAP) + X(SIGTRAP), +#endif +#if defined(SIGTSTP) + X(SIGTSTP), +#endif +#if defined(SIGTTIN) + X(SIGTTIN), +#endif +#if defined(SIGTTOU) + X(SIGTTOU), +#endif +#if defined(SIGURG) + X(SIGURG), +#endif +#if defined(SIGUSR1) + X(SIGUSR1), +#endif +#if defined(SIGUSR2) + X(SIGUSR2), +#endif +#if defined(SIGVTALRM) + X(SIGVTALRM), +#endif +#if defined(SIGXCPU) + X(SIGXCPU), +#endif +#if defined(SIGXFSZ) + X(SIGXFSZ), +#endif +#undef X + }; + if (sig >= sizeof(signals) / sizeof(signals[0]) || signals[sig] == 0) + return __WASI_EINVAL; + +#if CONFIG_TLS_USE_GSBASE + // TLS on OS X depends on installing a SIGSEGV handler. Reset SIGSEGV + // to the default action before raising. + if (sig == __WASI_SIGSEGV) { + struct sigaction sa = { + .sa_handler = SIG_DFL, + }; + sigemptyset(&sa.sa_mask); + sigaction(SIGSEGV, &sa, NULL); + } +#endif + + if (raise(signals[sig]) < 0) + return convert_errno(errno); + return 0; +} + +__wasi_errno_t +wasmtime_ssp_random_get(void *buf, size_t nbyte) +{ + random_buf(buf, nbyte); + return 0; +} + +__wasi_errno_t +wasi_ssp_sock_accept( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_fdflags_t flags, __wasi_fd_t *fd_new) +{ + __wasi_filetype_t wasi_type; + __wasi_rights_t max_base, max_inheriting; + struct fd_object *fo; + bh_socket_t new_sock = -1; + int ret; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ACCEPT, 0); + if (error != __WASI_ESUCCESS) { + goto fail; + } + + ret = os_socket_accept(fd_number(fo), &new_sock, NULL, NULL); + fd_object_release(fo); + if (BHT_OK != ret) { + error = convert_errno(errno); + goto fail; + } + + error = fd_determine_type_rights(new_sock, &wasi_type, &max_base, + &max_inheriting); + if (error != __WASI_ESUCCESS) { + goto fail; + } + + error = fd_table_insert_fd(curfds, new_sock, wasi_type, max_base, + max_inheriting, fd_new); + if (error != __WASI_ESUCCESS) { + /* released in fd_table_insert_fd() */ + new_sock = -1; + goto fail; + } + + return __WASI_ESUCCESS; + +fail: + if (-1 != new_sock) { + os_socket_close(new_sock); + } + return error; +} + +__wasi_errno_t +wasi_ssp_sock_addr_local( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_addr_t *addr) +{ + struct fd_object *fo; + bh_sockaddr_t bh_addr; + int ret; + + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ADDR_LOCAL, 0); + if (error != __WASI_ESUCCESS) + return error; + + ret = os_socket_addr_local(fd_number(fo), &bh_addr); + fd_object_release(fo); + if (ret != BHT_OK) { + return convert_errno(errno); + } + + bh_sockaddr_to_wasi_addr(&bh_addr, addr); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_addr_remote( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_addr_t *addr) +{ + struct fd_object *fo; + bh_sockaddr_t bh_addr; + int ret; + + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_ADDR_LOCAL, 0); + if (error != __WASI_ESUCCESS) + return error; + + ret = os_socket_addr_remote(fd_number(fo), &bh_addr); + fd_object_release(fo); + if (ret != BHT_OK) { + return convert_errno(errno); + } + + bh_sockaddr_to_wasi_addr(&bh_addr, addr); + + return __WASI_ESUCCESS; +} + +static bool +wasi_addr_to_string(const __wasi_addr_t *addr, char *buf, size_t buflen) +{ + if (addr->kind == IPv4) { + const char *format = "%u.%u.%u.%u"; + + assert(buflen >= 16); + + snprintf(buf, buflen, format, addr->addr.ip4.addr.n0, + addr->addr.ip4.addr.n1, addr->addr.ip4.addr.n2, + addr->addr.ip4.addr.n3); + + return true; + } + else if (addr->kind == IPv6) { + const char *format = "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"; + __wasi_addr_ip6_t ipv6 = addr->addr.ip6.addr; + + assert(buflen >= 40); + + snprintf(buf, buflen, format, ipv6.n0, ipv6.n1, ipv6.n2, ipv6.n3, + ipv6.h0, ipv6.h1, ipv6.h2, ipv6.h3); + + return true; + } + + return false; +} + +__wasi_errno_t +wasi_ssp_sock_bind( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct addr_pool *addr_pool, +#endif + __wasi_fd_t fd, __wasi_addr_t *addr) +{ + char buf[48] = { 0 }; + struct fd_object *fo; + __wasi_errno_t error; + int port = addr->kind == IPv4 ? addr->addr.ip4.port : addr->addr.ip6.port; + int ret; + + if (!wasi_addr_to_string(addr, buf, sizeof(buf))) { + return __WASI_EPROTONOSUPPORT; + } + + if (!addr_pool_search(addr_pool, buf)) { + return __WASI_EACCES; + } + + error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_BIND, 0); + if (error != __WASI_ESUCCESS) + return error; + + ret = os_socket_bind(fd_number(fo), buf, &port); + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_addr_resolve( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, char **ns_lookup_list, +#endif + const char *host, const char *service, __wasi_addr_info_hints_t *hints, + __wasi_addr_info_t *addr_info, __wasi_size_t addr_info_size, + __wasi_size_t *max_info_size) +{ + bh_addr_info_t *wamr_addr_info = + wasm_runtime_malloc(addr_info_size * sizeof(bh_addr_info_t)); + uint8_t hints_is_ipv4 = hints->family == INET4; + uint8_t hints_is_tcp = hints->type == SOCKET_STREAM; + size_t _max_info_size; + size_t actual_info_size; + + if (!wamr_addr_info) { + return __WASI_ENOMEM; + } + + if (!ns_lookup_list_search(ns_lookup_list, host)) { + wasm_runtime_free(wamr_addr_info); + return __WASI_EACCES; + } + + int ret = os_socket_addr_resolve( + host, service, hints->hints_enabled ? &hints_is_tcp : NULL, + hints->hints_enabled ? &hints_is_ipv4 : NULL, wamr_addr_info, + addr_info_size, &_max_info_size); + + if (ret != BHT_OK) { + wasm_runtime_free(wamr_addr_info); + return convert_errno(errno); + } + + *max_info_size = _max_info_size; + actual_info_size = + addr_info_size < *max_info_size ? addr_info_size : *max_info_size; + + for (size_t i = 0; i < actual_info_size; i++) { + addr_info[i].type = + wamr_addr_info[i].is_tcp ? SOCKET_STREAM : SOCKET_DGRAM; + bh_sockaddr_to_wasi_addr(&wamr_addr_info[i].sockaddr, + &addr_info[i].addr); + } + + wasm_runtime_free(wamr_addr_info); + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_connect( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct addr_pool *addr_pool, +#endif + __wasi_fd_t fd, __wasi_addr_t *addr) +{ + char buf[48] = { 0 }; + struct fd_object *fo; + __wasi_errno_t error; + int ret; + + if (!wasi_addr_to_string(addr, buf, sizeof(buf))) { + return __WASI_EPROTONOSUPPORT; + } + + if (!addr_pool_search(addr_pool, buf)) { + return __WASI_EACCES; + } + + error = fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_BIND, 0); + if (error != __WASI_ESUCCESS) + return error; + + ret = os_socket_connect(fd_number(fo), buf, + addr->kind == IPv4 ? addr->addr.ip4.port + : addr->addr.ip6.port); + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_get_recv_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t *size) +{ + struct fd_object *fo; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); + if (error != __WASI_ESUCCESS) + return error; + + int optval; + socklen_t optlen = sizeof(optval); + + ret = getsockopt(fd_number(fo), SOL_SOCKET, SO_RCVBUF, &optval, &optlen); + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + *size = optval; + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_get_reuse_addr( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t *reuse) +{ + + struct fd_object *fo; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); + if (error != __WASI_ESUCCESS) + return error; + + int optval; + socklen_t optlen = sizeof(optval); + + ret = getsockopt(fd_number(fo), SOL_SOCKET, SO_REUSEADDR, &optval, &optlen); + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + *reuse = optval; + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_get_reuse_port( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t *reuse) +{ + struct fd_object *fo; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); + if (error != __WASI_ESUCCESS) + return error; + + int optval; + socklen_t optlen = sizeof(optval); + +#if defined(SO_REUSEPORT) /* NuttX doesn't have SO_REUSEPORT */ + ret = getsockopt(fd_number(fo), SOL_SOCKET, SO_REUSEPORT, &optval, &optlen); +#else + errno = ENOTSUP; + ret = BHT_ERROR; + optval = 0; +#endif /* defined(SO_REUSEPORT) */ + + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + *reuse = optval; + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_get_send_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t *size) +{ + struct fd_object *fo; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); + if (error != __WASI_ESUCCESS) + return error; + + int optval; + socklen_t optlen = sizeof(optval); + + ret = getsockopt(fd_number(fo), SOL_SOCKET, SO_SNDBUF, &optval, &optlen); + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + *size = optval; + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_listen( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t backlog) +{ + struct fd_object *fo; + int ret; + __wasi_errno_t error = + fd_object_get(curfds, &fo, fd, __WASI_RIGHT_SOCK_LISTEN, 0); + if (error != __WASI_ESUCCESS) + return error; + + ret = os_socket_listen(fd_number(fo), backlog); + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_open( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t poolfd, __wasi_address_family_t af, __wasi_sock_type_t socktype, + __wasi_fd_t *sockfd) +{ + bh_socket_t sock; + bool is_tcp = SOCKET_DGRAM == socktype ? false : true; + bool is_ipv4 = INET6 == af ? false : true; + int ret; + __wasi_filetype_t wasi_type; + __wasi_rights_t max_base, max_inheriting; + __wasi_errno_t error; + + (void)poolfd; + + ret = os_socket_create(&sock, is_ipv4, is_tcp); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + error = + fd_determine_type_rights(sock, &wasi_type, &max_base, &max_inheriting); + if (error != __WASI_ESUCCESS) { + os_socket_close(sock); + return error; + } + + if (SOCKET_DGRAM == socktype) { + assert(wasi_type == __WASI_FILETYPE_SOCKET_DGRAM); + } + else { + assert(wasi_type == __WASI_FILETYPE_SOCKET_STREAM); + } + + // TODO: base rights and inheriting rights ? + error = fd_table_insert_fd(curfds, sock, wasi_type, max_base, + max_inheriting, sockfd); + if (error != __WASI_ESUCCESS) { + return error; + } + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_set_recv_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t size) +{ + struct fd_object *fo; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); + if (error != __WASI_ESUCCESS) + return error; + + int optval = size; + + ret = setsockopt(fd_number(fo), SOL_SOCKET, SO_RCVBUF, &optval, + sizeof(optval)); + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_set_reuse_addr( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t reuse) +{ + struct fd_object *fo; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); + if (error != __WASI_ESUCCESS) + return error; + + int optval = reuse; + + ret = setsockopt(fd_number(fo), SOL_SOCKET, SO_REUSEADDR, &optval, + sizeof(optval)); + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_set_reuse_port( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t reuse) +{ + struct fd_object *fo; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); + if (error != __WASI_ESUCCESS) + return error; + + int optval = reuse; + +#if defined(SO_REUSEPORT) /* NuttX doesn't have SO_REUSEPORT */ + ret = setsockopt(fd_number(fo), SOL_SOCKET, SO_REUSEPORT, &optval, + sizeof(optval)); +#else + errno = ENOTSUP; + ret = BHT_ERROR; +#endif /* defined(SO_REUSEPORT) */ + + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_set_send_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t size) +{ + struct fd_object *fo; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); + if (error != __WASI_ESUCCESS) + return error; + + int optval = size; + + ret = setsockopt(fd_number(fo), SOL_SOCKET, SO_SNDBUF, &optval, + sizeof(optval)); + + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sock_recv( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, void *buf, size_t buf_len, size_t *recv_len) +{ + __wasi_addr_t src_addr; + + return wasmtime_ssp_sock_recv_from(curfds, sock, buf, buf_len, 0, &src_addr, + recv_len); +} + +__wasi_errno_t +wasmtime_ssp_sock_recv_from( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, void *buf, size_t buf_len, __wasi_riflags_t ri_flags, + __wasi_addr_t *src_addr, size_t *recv_len) +{ + struct fd_object *fo; + __wasi_errno_t error; + bh_sockaddr_t sockaddr; + int ret; + + error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_READ, 0); + if (error != 0) { + return error; + } + + ret = os_socket_recv_from(fd_number(fo), buf, buf_len, 0, &sockaddr); + fd_object_release(fo); + if (-1 == ret) { + return convert_errno(errno); + } + + bh_sockaddr_to_wasi_addr(&sockaddr, src_addr); + + *recv_len = (size_t)ret; + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sock_send( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, const void *buf, size_t buf_len, size_t *sent_len) +{ + struct fd_object *fo; + __wasi_errno_t error; + int ret; + + error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_WRITE, 0); + if (error != 0) { + return error; + } + + ret = os_socket_send(fd_number(fo), buf, buf_len); + fd_object_release(fo); + if (-1 == ret) { + return convert_errno(errno); + } + + *sent_len = (size_t)ret; + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sock_send_to( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, struct addr_pool *addr_pool, +#endif + __wasi_fd_t sock, const void *buf, size_t buf_len, + __wasi_siflags_t si_flags, const __wasi_addr_t *dest_addr, size_t *sent_len) +{ + char addr_buf[48] = { 0 }; + struct fd_object *fo; + __wasi_errno_t error; + int ret; + bh_sockaddr_t sockaddr; + + if (!wasi_addr_to_string(dest_addr, addr_buf, sizeof(addr_buf))) { + return __WASI_EPROTONOSUPPORT; + } + + if (!addr_pool_search(addr_pool, addr_buf)) { + return __WASI_EACCES; + } + + error = fd_object_get(curfds, &fo, sock, __WASI_RIGHT_FD_WRITE, 0); + if (error != 0) { + return error; + } + + wasi_addr_to_bh_sockaddr(dest_addr, &sockaddr); + + ret = os_socket_send_to(fd_number(fo), buf, buf_len, 0, &sockaddr); + fd_object_release(fo); + if (-1 == ret) { + return convert_errno(errno); + } + + *sent_len = (size_t)ret; + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sock_shutdown( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock) +{ + struct fd_object *fo; + __wasi_errno_t error; + int ret; + + error = fd_object_get(curfds, &fo, sock, 0, 0); + if (error != 0) + return error; + + ret = os_socket_shutdown(fd_number(fo)); + fd_object_release(fo); + if (BHT_OK != ret) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sched_yield(void) +{ + if (sched_yield() < 0) + return convert_errno(errno); + return 0; +} + +__wasi_errno_t +wasmtime_ssp_args_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct argv_environ_values *argv_environ, +#endif + char **argv, char *argv_buf) +{ + for (size_t i = 0; i < argv_environ->argc; ++i) { + argv[i] = + argv_buf + (argv_environ->argv_list[i] - argv_environ->argv_buf); + } + argv[argv_environ->argc] = NULL; + bh_memcpy_s(argv_buf, (uint32)argv_environ->argv_buf_size, + argv_environ->argv_buf, (uint32)argv_environ->argv_buf_size); + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_args_sizes_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct argv_environ_values *argv_environ, +#endif + size_t *argc, size_t *argv_buf_size) +{ + *argc = argv_environ->argc; + *argv_buf_size = argv_environ->argv_buf_size; + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_environ_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct argv_environ_values *argv_environ, +#endif + char **environ, char *environ_buf) +{ + for (size_t i = 0; i < argv_environ->environ_count; ++i) { + environ[i] = + environ_buf + + (argv_environ->environ_list[i] - argv_environ->environ_buf); + } + environ[argv_environ->environ_count] = NULL; + bh_memcpy_s(environ_buf, (uint32)argv_environ->environ_buf_size, + argv_environ->environ_buf, + (uint32)argv_environ->environ_buf_size); + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_environ_sizes_get( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct argv_environ_values *argv_environ, +#endif + size_t *environ_count, size_t *environ_buf_size) +{ + *environ_count = argv_environ->environ_count; + *environ_buf_size = argv_environ->environ_buf_size; + return __WASI_ESUCCESS; +} + +bool +argv_environ_init(struct argv_environ_values *argv_environ, char *argv_buf, + size_t argv_buf_size, char **argv_list, size_t argc, + char *environ_buf, size_t environ_buf_size, + char **environ_list, size_t environ_count) +{ + memset(argv_environ, 0, sizeof(struct argv_environ_values)); + + argv_environ->argv_buf = argv_buf; + argv_environ->argv_buf_size = argv_buf_size; + argv_environ->argv_list = argv_list; + argv_environ->argc = argc; + argv_environ->environ_buf = environ_buf; + argv_environ->environ_buf_size = environ_buf_size; + argv_environ->environ_list = environ_list; + argv_environ->environ_count = environ_count; + return true; +} + +void +argv_environ_destroy(struct argv_environ_values *argv_environ) +{} + +void +fd_table_destroy(struct fd_table *ft) +{ + if (ft->entries) { + for (uint32 i = 0; i < ft->size; i++) { + if (ft->entries[i].object != NULL) { + fd_object_release(ft->entries[i].object); + } + } + rwlock_destroy(&ft->lock); + wasm_runtime_free(ft->entries); + } +} + +void +fd_prestats_destroy(struct fd_prestats *pt) +{ + if (pt->prestats) { + for (uint32 i = 0; i < pt->size; i++) { + if (pt->prestats[i].dir != NULL) { + wasm_runtime_free((void *)pt->prestats[i].dir); + } + } + rwlock_destroy(&pt->lock); + wasm_runtime_free(pt->prestats); + } +} + +bool +addr_pool_init(struct addr_pool *addr_pool) +{ + memset(addr_pool, 0, sizeof(*addr_pool)); + + return true; +} + +bool +addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask) +{ + struct addr_pool *cur = addr_pool; + struct addr_pool *next; + bh_ip_addr_buffer_t target; + + if (!addr_pool) { + return false; + } + + if (!(next = wasm_runtime_malloc(sizeof(struct addr_pool)))) { + return false; + } + + next->next = NULL; + next->mask = mask; + + if (os_socket_inet_network(true, addr, &target) != BHT_OK) { + // If parsing IPv4 fails, try IPv6 + if (os_socket_inet_network(false, addr, &target) != BHT_OK) { + wasm_runtime_free(next); + return false; + } + next->type = IPv6; + bh_memcpy_s(next->addr.ip6, sizeof(next->addr.ip6), target.ipv6, + sizeof(target.ipv6)); + } + else { + next->type = IPv4; + next->addr.ip4 = target.ipv4; + } + + /* attach with */ + while (cur->next) { + cur = cur->next; + } + cur->next = next; + return true; +} + +static inline size_t +min(size_t a, size_t b) +{ + return a > b ? b : a; +} + +static void +init_address_mask(uint8_t *buf, size_t buflen, size_t mask) +{ + size_t element_size = sizeof(uint8_t) * 8; + + for (size_t i = 0; i < buflen; i++) { + if (mask <= i * element_size) { + buf[i] = 0; + } + else { + size_t offset = min(mask - i * element_size, element_size); + buf[i] = (~0u) << (element_size - offset); + } + } +} + +/* target must be in network byte order */ +static bool +compare_address(const struct addr_pool *addr_pool_entry, + bh_ip_addr_buffer_t *target) +{ + uint8_t maskbuf[16] = { 0 }; + uint8_t basebuf[16] = { 0 }; + size_t addr_size; + uint8_t max_addr_mask; + + if (addr_pool_entry->type == IPv4) { + uint32_t addr_ip4 = htonl(addr_pool_entry->addr.ip4); + bh_memcpy_s(basebuf, sizeof(addr_ip4), &addr_ip4, sizeof(addr_ip4)); + addr_size = 4; + } + else { + uint16_t partial_addr_ip6; + for (int i = 0; i < 8; i++) { + partial_addr_ip6 = htons(addr_pool_entry->addr.ip6[i]); + bh_memcpy_s(&basebuf[i * sizeof(partial_addr_ip6)], + sizeof(partial_addr_ip6), &partial_addr_ip6, + sizeof(partial_addr_ip6)); + } + addr_size = 16; + } + max_addr_mask = addr_size * 8; + + /* IPv4 0.0.0.0 or IPv6 :: means any address */ + if (basebuf[0] == 0 && !memcmp(basebuf, basebuf + 1, addr_size - 1)) { + return true; + } + + /* No support for invalid mask value */ + if (addr_pool_entry->mask > max_addr_mask) { + return false; + } + + init_address_mask(maskbuf, addr_size, addr_pool_entry->mask); + + for (size_t i = 0; i < addr_size; i++) { + uint8_t addr_mask = target->data[i] & maskbuf[i]; + uint8_t range_mask = basebuf[i] & maskbuf[i]; + if (addr_mask != range_mask) { + return false; + } + } + + return true; +} + +bool +addr_pool_search(struct addr_pool *addr_pool, const char *addr) +{ + struct addr_pool *cur = addr_pool->next; + bh_ip_addr_buffer_t target; + __wasi_addr_type_t addr_type; + + if (os_socket_inet_network(true, addr, &target) != BHT_OK) { + size_t i; + + if (os_socket_inet_network(false, addr, &target) != BHT_OK) { + return false; + } + addr_type = IPv6; + for (i = 0; i < sizeof(target.ipv6) / sizeof(target.ipv6[0]); i++) { + target.ipv6[i] = htons(target.ipv6[i]); + } + } + else { + addr_type = IPv4; + target.ipv4 = htonl(target.ipv4); + } + + while (cur) { + if (cur->type == addr_type && compare_address(cur, &target)) { + return true; + } + + cur = cur->next; + } + + return false; +} + +void +addr_pool_destroy(struct addr_pool *addr_pool) +{ + struct addr_pool *cur = addr_pool->next; + + while (cur) { + struct addr_pool *next = cur->next; + wasm_runtime_free(cur); + cur = next; + } +} + +#ifndef WASMTIME_SSP_STATIC_CURFDS +#define WASMTIME_SSP_PASSTHROUGH_FD_TABLE struct fd_table *curfds, +#else +#define WASMTIME_SSP_PASSTHROUGH_FD_TABLE +#endif + +// Defines a function that passes through the socket option to the OS +// implementation +#define WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(FUNC_NAME, OPTION_TYPE) \ + __wasi_errno_t wasmtime_ssp_sock_##FUNC_NAME( \ + WASMTIME_SSP_PASSTHROUGH_FD_TABLE __wasi_fd_t sock, \ + OPTION_TYPE option) \ + { \ + struct fd_object *fo; \ + __wasi_errno_t error; \ + int ret; \ + error = fd_object_get(curfds, &fo, sock, 0, 0); \ + if (error != 0) \ + return error; \ + ret = os_socket_##FUNC_NAME(fd_number(fo), option); \ + fd_object_release(fo); \ + if (BHT_OK != ret) \ + return convert_errno(errno); \ + return __WASI_ESUCCESS; \ + } + +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_send_timeout, uint64) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_send_timeout, uint64 *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_recv_timeout, uint64) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_recv_timeout, uint64 *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_send_buf_size, size_t) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_send_buf_size, size_t *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_recv_buf_size, size_t) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_recv_buf_size, size_t *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_broadcast, bool) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_broadcast, bool *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_keep_alive, bool) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_keep_alive, bool *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_reuse_addr, bool) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_reuse_addr, bool *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_reuse_port, bool) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_reuse_port, bool *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_no_delay, bool) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_no_delay, bool *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_quick_ack, bool) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_quick_ack, bool *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_keep_idle, uint32) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_keep_idle, uint32 *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_keep_intvl, uint32) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_keep_intvl, uint32 *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_tcp_fastopen_connect, bool) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_tcp_fastopen_connect, bool *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_ip_ttl, uint8_t) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_ip_ttl, uint8_t *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_ip_multicast_ttl, uint8_t) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_ip_multicast_ttl, uint8_t *) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(set_ipv6_only, bool) +WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION(get_ipv6_only, bool *) + +#undef WASMTIME_SSP_PASSTHROUGH_FD_TABLE +#undef WASMTIME_SSP_PASSTHROUGH_SOCKET_OPTION + +__wasi_errno_t +wasmtime_ssp_sock_set_linger( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, bool is_enabled, int linger_s) +{ + struct fd_object *fo; + __wasi_errno_t error; + int ret; + error = fd_object_get(curfds, &fo, sock, 0, 0); + if (error != 0) + return error; + + ret = os_socket_set_linger(fd_number(fo), is_enabled, linger_s); + fd_object_release(fo); + if (BHT_OK != ret) + return convert_errno(errno); + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sock_get_linger( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, bool *is_enabled, int *linger_s) +{ + struct fd_object *fo; + __wasi_errno_t error; + int ret; + error = fd_object_get(curfds, &fo, sock, 0, 0); + if (error != 0) + return error; + + ret = os_socket_get_linger(fd_number(fo), is_enabled, linger_s); + fd_object_release(fo); + if (BHT_OK != ret) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sock_set_ip_add_membership( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, __wasi_addr_ip_t *imr_multiaddr, uint32_t imr_interface) +{ + struct fd_object *fo; + __wasi_errno_t error; + int ret; + bh_ip_addr_buffer_t addr_info; + bool is_ipv6; + error = fd_object_get(curfds, &fo, sock, 0, 0); + if (error != 0) + return error; + + wasi_addr_ip_to_bh_ip_addr_buffer(imr_multiaddr, &addr_info); + is_ipv6 = imr_multiaddr->kind == IPv6; + ret = os_socket_set_ip_add_membership(fd_number(fo), &addr_info, + imr_interface, is_ipv6); + fd_object_release(fo); + if (BHT_OK != ret) + return convert_errno(errno); + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sock_set_ip_drop_membership( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, __wasi_addr_ip_t *imr_multiaddr, uint32_t imr_interface) +{ + struct fd_object *fo; + __wasi_errno_t error; + int ret; + bh_ip_addr_buffer_t addr_info; + bool is_ipv6; + error = fd_object_get(curfds, &fo, sock, 0, 0); + if (error != 0) + return error; + + wasi_addr_ip_to_bh_ip_addr_buffer(imr_multiaddr, &addr_info); + is_ipv6 = imr_multiaddr->kind == IPv6; + ret = os_socket_set_ip_drop_membership(fd_number(fo), &addr_info, + imr_interface, is_ipv6); + fd_object_release(fo); + if (BHT_OK != ret) + return convert_errno(errno); + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sock_set_ip_multicast_loop( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, bool ipv6, bool is_enabled) +{ + struct fd_object *fo; + __wasi_errno_t error; + int ret; + error = fd_object_get(curfds, &fo, sock, 0, 0); + if (error != 0) + return error; + + ret = os_socket_set_ip_multicast_loop(fd_number(fo), ipv6, is_enabled); + fd_object_release(fo); + if (BHT_OK != ret) + return convert_errno(errno); + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasmtime_ssp_sock_get_ip_multicast_loop( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t sock, bool ipv6, bool *is_enabled) +{ + struct fd_object *fo; + __wasi_errno_t error; + int ret; + error = fd_object_get(curfds, &fo, sock, 0, 0); + if (error != 0) + return error; + + ret = os_socket_get_ip_multicast_loop(fd_number(fo), ipv6, is_enabled); + fd_object_release(fo); + if (BHT_OK != ret) + return convert_errno(errno); + + return __WASI_ESUCCESS; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h new file mode 100644 index 000000000..7a593390a --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h @@ -0,0 +1,89 @@ +// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM +// Exceptions. See +// https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license +// information. +// +// Significant parts of this file are derived from cloudabi-utils. See +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE +// for license information. +// +// The upstream file contains the following copyright notice: +// +// Copyright (c) 2016-2018 Nuxi, https://nuxi.nl/ + +#ifndef POSIX_H +#define POSIX_H + +#include "bh_platform.h" +#include "locking.h" + +struct fd_entry; +struct fd_prestat; +struct syscalls; + +struct fd_table { + struct rwlock lock; + struct fd_entry *entries; + size_t size; + size_t used; +}; + +struct fd_prestats { + struct rwlock lock; + struct fd_prestat *prestats; + size_t size; + size_t used; +}; + +struct argv_environ_values { + const char *argv_buf; + size_t argv_buf_size; + char **argv_list; + size_t argc; + char *environ_buf; + size_t environ_buf_size; + char **environ_list; + size_t environ_count; +}; + +struct addr_pool { + /* addr and mask in host order */ + union { + uint32 ip4; + uint16 ip6[8]; + } addr; + struct addr_pool *next; + __wasi_addr_type_t type; + uint8 mask; +}; + +bool +fd_table_init(struct fd_table *); +bool +fd_table_insert_existing(struct fd_table *, __wasi_fd_t, int); +bool +fd_prestats_init(struct fd_prestats *); +bool +fd_prestats_insert(struct fd_prestats *, const char *, __wasi_fd_t); +bool +argv_environ_init(struct argv_environ_values *argv_environ, char *argv_buf, + size_t argv_buf_size, char **argv_list, size_t argc, + char *environ_buf, size_t environ_buf_size, + char **environ_list, size_t environ_count); +void +argv_environ_destroy(struct argv_environ_values *argv_environ); +void +fd_table_destroy(struct fd_table *ft); +void +fd_prestats_destroy(struct fd_prestats *pt); + +bool +addr_pool_init(struct addr_pool *); +bool +addr_pool_insert(struct addr_pool *, const char *, uint8 mask); +bool +addr_pool_search(struct addr_pool *, const char *); +void +addr_pool_destroy(struct addr_pool *); + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/queue.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/queue.h new file mode 100644 index 000000000..2d40bc3aa --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/queue.h @@ -0,0 +1,98 @@ +// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM +// Exceptions. See +// https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license +// information. +// +// Significant parts of this file are derived from cloudabi-utils. See +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE +// for license information. +// +// The upstream file contains the following copyright notice: +// +// Copyright (c) 2016 Nuxi, https://nuxi.nl/ + +#ifndef QUEUE_H +#define QUEUE_H + +// LIST: Double-linked list. + +#define LIST_HEAD(name, type) \ + struct name { \ + struct type *l_first; \ + } + +/* clang-format off */ +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } +/* clang-format on */ + +#define LIST_ENTRY(type) \ + struct { \ + struct type *l_next; \ + struct type **l_prev; \ + } + +#define LIST_FOREACH(var, head, field) \ + for ((var) = (head)->l_first; (var) != NULL; (var) = (var)->field.l_next) + +#define LIST_INIT(head) \ + do { \ + (head)->l_first = NULL; \ + } while (0) + +#define LIST_INSERT_HEAD(head, element, field) \ + do { \ + (element)->field.l_next = (head)->l_first; \ + if ((head)->l_first != NULL) \ + (head)->l_first->field.l_prev = &(element)->field.l_next; \ + (head)->l_first = (element); \ + (element)->field.l_prev = &(head)->l_first; \ + } while (0) + +#define LIST_REMOVE(element, field) \ + do { \ + if ((element)->field.l_next != NULL) \ + (element)->field.l_next->field.l_prev = (element)->field.l_prev; \ + *(element)->field.l_prev = (element)->field.l_next; \ + } while (0) + +// TAILQ: Double-linked list with tail pointer. + +#define TAILQ_HEAD(name, type) \ + struct name { \ + struct type *t_first; \ + struct type **t_last; \ + } + +#define TAILQ_ENTRY(type) \ + struct { \ + struct type *t_next; \ + struct type **t_prev; \ + } + +#define TAILQ_EMPTY(head) ((head)->t_first == NULL) +#define TAILQ_FIRST(head) ((head)->t_first) +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = (head)->t_first; (var) != NULL; (var) = (var)->field.t_next) +#define TAILQ_INIT(head) \ + do { \ + (head)->t_first = NULL; \ + (head)->t_last = &(head)->t_first; \ + } while (0) +#define TAILQ_INSERT_TAIL(head, elm, field) \ + do { \ + (elm)->field.t_next = NULL; \ + (elm)->field.t_prev = (head)->t_last; \ + *(head)->t_last = (elm); \ + (head)->t_last = &(elm)->field.t_next; \ + } while (0) +#define TAILQ_REMOVE(head, element, field) \ + do { \ + if ((element)->field.t_next != NULL) \ + (element)->field.t_next->field.t_prev = (element)->field.t_prev; \ + else \ + (head)->t_last = (element)->field.t_prev; \ + *(element)->field.t_prev = (element)->field.t_next; \ + } while (0) + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c new file mode 100644 index 000000000..01a1dab3a --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c @@ -0,0 +1,98 @@ +// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM +// Exceptions. See +// https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license +// information. +// +// Significant parts of this file are derived from cloudabi-utils. See +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE +// for license information. +// +// The upstream file contains the following copyright notice: +// +// Copyright (c) 2016 Nuxi, https://nuxi.nl/ + +#include "ssp_config.h" +#include "bh_platform.h" +#include "random.h" + +#if CONFIG_HAS_ARC4RANDOM_BUF + +void +random_buf(void *buf, size_t len) +{ + arc4random_buf(buf, len); +} + +#elif CONFIG_HAS_GETRANDOM + +#ifndef BH_PLATFORM_LINUX_SGX +#include <sys/random.h> +#endif + +void +random_buf(void *buf, size_t len) +{ + for (;;) { + ssize_t x = getrandom(buf, len, 0); + if (x < 0) { + if (errno == EINTR) + continue; + os_printf("getrandom failed: %s", strerror(errno)); + abort(); + } + if ((size_t)x == len) + return; + buf = (void *)((unsigned char *)buf + x); + len -= (size_t)x; + } +} + +#else + +static int urandom; + +static void +open_urandom(void) +{ + urandom = open("/dev/urandom", O_RDONLY); + if (urandom < 0) { + os_printf("Failed to open /dev/urandom\n"); + abort(); + } +} + +void +random_buf(void *buf, size_t len) +{ + static pthread_once_t open_once = PTHREAD_ONCE_INIT; + pthread_once(&open_once, open_urandom); + + if ((size_t)read(urandom, buf, len) != len) { + os_printf("Short read on /dev/urandom\n"); + abort(); + } +} + +#endif + +// Calculates a random number within the range [0, upper - 1] without +// any modulo bias. +// +// The function below repeatedly obtains a random number from +// arc4random() until it lies within the range [2^k % upper, 2^k). As +// this range has length k * upper, we can safely obtain a number +// without any modulo bias. +uintmax_t +random_uniform(uintmax_t upper) +{ + // Compute 2^k % upper + // == (2^k - upper) % upper + // == -upper % upper. + uintmax_t lower = -upper % upper; + for (;;) { + uintmax_t value; + random_buf(&value, sizeof(value)); + if (value >= lower) + return value % upper; + } +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h new file mode 100644 index 000000000..23c2da4db --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h @@ -0,0 +1,21 @@ +// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM +// Exceptions. See +// https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license +// information. +// +// Significant parts of this file are derived from cloudabi-utils. See +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE +// for license information. +// +// The upstream file contains the following copyright notice: +// +// Copyright (c) 2016 Nuxi, https://nuxi.nl/ + +#ifndef RANDOM_H +#define RANDOM_H + +void +random_buf(void *, size_t); +uintmax_t random_uniform(uintmax_t); + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h new file mode 100644 index 000000000..03b4b87ac --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h @@ -0,0 +1,139 @@ +// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM +// Exceptions. See +// https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license +// information. +// +// Significant parts of this file are derived from cloudabi-utils. See +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE +// for license information. +// +// The upstream file contains the following copyright notice: +// +// Copyright (c) 2016 Nuxi, https://nuxi.nl/ + +#ifndef REFCOUNT_H +#define REFCOUNT_H + +#include "bh_platform.h" +#include "locking.h" +#include "gnuc.h" + +#define PRODUCES(...) LOCKS_SHARED(__VA_ARGS__) NO_LOCK_ANALYSIS +#define CONSUMES(...) UNLOCKS(__VA_ARGS__) NO_LOCK_ANALYSIS + +#if CONFIG_HAS_STD_ATOMIC != 0 + +#include <stdatomic.h> + +/* Simple reference counter. */ +struct LOCKABLE refcount { + atomic_uint count; +}; + +/* Initialize the reference counter. */ +static inline void +refcount_init(struct refcount *r, unsigned int count) PRODUCES(*r) +{ + atomic_init(&r->count, count); +} + +/* Increment the reference counter. */ +static inline void +refcount_acquire(struct refcount *r) PRODUCES(*r) +{ + atomic_fetch_add_explicit(&r->count, 1, memory_order_acquire); +} + +/* Decrement the reference counter, returning whether the reference + dropped to zero. */ +static inline bool +refcount_release(struct refcount *r) CONSUMES(*r) +{ + int old = + (int)atomic_fetch_sub_explicit(&r->count, 1, memory_order_release); + bh_assert(old != 0 && "Reference count becoming negative"); + return old == 1; +} + +#elif defined(BH_PLATFORM_LINUX_SGX) + +#include <sgx_spinlock.h> + +/* Simple reference counter. */ +struct refcount { + sgx_spinlock_t lock; + unsigned int count; +}; + +/* Initialize the reference counter. */ +static inline void +refcount_init(struct refcount *r, unsigned int count) +{ + r->lock = SGX_SPINLOCK_INITIALIZER; + r->count = count; +} + +/* Increment the reference counter. */ +static inline void +refcount_acquire(struct refcount *r) +{ + sgx_spin_lock(&r->lock); + r->count++; + sgx_spin_unlock(&r->lock); +} + +/* Decrement the reference counter, returning whether the reference + dropped to zero. */ +static inline bool +refcount_release(struct refcount *r) +{ + int old; + sgx_spin_lock(&r->lock); + old = (int)r->count; + r->count--; + sgx_spin_unlock(&r->lock); + bh_assert(old != 0 && "Reference count becoming negative"); + return old == 1; +} + +#elif defined(__GNUC_PREREQ) + +#if __GNUC_PREREQ(4, 7) + +struct refcount { + unsigned int count; +}; + +/* Initialize the reference counter. */ +static inline void +refcount_init(struct refcount *r, unsigned int count) +{ + __atomic_store_n(&r->count, count, __ATOMIC_SEQ_CST); +} + +/* Increment the reference counter. */ +static inline void +refcount_acquire(struct refcount *r) +{ + __atomic_fetch_add(&r->count, 1, __ATOMIC_ACQUIRE); +} + +/* Decrement the reference counter, returning whether the reference + dropped to zero. */ +static inline bool +refcount_release(struct refcount *r) +{ + int old = (int)__atomic_fetch_sub(&r->count, 1, __ATOMIC_RELEASE); + bh_assert(old != 0 && "Reference count becoming negative"); + return old == 1; +} + +#else /* else of __GNUC_PREREQ (4.7) */ +#error "Reference counter isn't implemented" +#endif /* end of __GNUC_PREREQ (4.7) */ + +#else /* else of CONFIG_HAS_STD_ATOMIC */ +#error "Reference counter isn't implemented" +#endif /* end of CONFIG_HAS_STD_ATOMIC */ + +#endif /* end of REFCOUNT_H */ diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h new file mode 100644 index 000000000..4f5838159 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h @@ -0,0 +1,100 @@ +// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM +// Exceptions. See +// https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license +// information. +// +// Significant parts of this file are derived from cloudabi-utils. See +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE +// for license information. +// +// The upstream file contains the following copyright notice: +// +// Copyright (c) 2016 Nuxi, https://nuxi.nl/ + +#ifndef RIGHTS_H +#define RIGHTS_H + +/* clang-format off */ + +#define RIGHTS_ALL \ + (__WASI_RIGHT_FD_DATASYNC | __WASI_RIGHT_FD_READ | \ + __WASI_RIGHT_FD_SEEK | __WASI_RIGHT_FD_FDSTAT_SET_FLAGS | \ + __WASI_RIGHT_FD_SYNC | __WASI_RIGHT_FD_TELL | __WASI_RIGHT_FD_WRITE | \ + __WASI_RIGHT_FD_ADVISE | __WASI_RIGHT_FD_ALLOCATE | \ + __WASI_RIGHT_PATH_CREATE_DIRECTORY | __WASI_RIGHT_PATH_CREATE_FILE | \ + __WASI_RIGHT_PATH_LINK_SOURCE | __WASI_RIGHT_PATH_LINK_TARGET | \ + __WASI_RIGHT_PATH_OPEN | __WASI_RIGHT_FD_READDIR | \ + __WASI_RIGHT_PATH_READLINK | __WASI_RIGHT_PATH_RENAME_SOURCE | \ + __WASI_RIGHT_PATH_RENAME_TARGET | __WASI_RIGHT_PATH_FILESTAT_GET | \ + __WASI_RIGHT_PATH_FILESTAT_SET_SIZE | \ + __WASI_RIGHT_PATH_FILESTAT_SET_TIMES | \ + __WASI_RIGHT_FD_FILESTAT_GET | __WASI_RIGHT_FD_FILESTAT_SET_TIMES | \ + __WASI_RIGHT_FD_FILESTAT_SET_SIZE | \ + __WASI_RIGHT_PATH_SYMLINK | __WASI_RIGHT_PATH_UNLINK_FILE | \ + __WASI_RIGHT_PATH_REMOVE_DIRECTORY | \ + __WASI_RIGHT_POLL_FD_READWRITE | __WASI_RIGHT_SOCK_CONNECT | \ + __WASI_RIGHT_SOCK_LISTEN | __WASI_RIGHT_SOCK_BIND | \ + __WASI_RIGHT_SOCK_ACCEPT | __WASI_RIGHT_SOCK_RECV | \ + __WASI_RIGHT_SOCK_SEND | __WASI_RIGHT_SOCK_ADDR_LOCAL | \ + __WASI_RIGHT_SOCK_ADDR_REMOTE | __WASI_RIGHT_SOCK_RECV_FROM | \ + __WASI_RIGHT_SOCK_SEND_TO) + + +// Block and character device interaction is outside the scope of +// CloudABI. Simply allow everything. +#define RIGHTS_BLOCK_DEVICE_BASE RIGHTS_ALL +#define RIGHTS_BLOCK_DEVICE_INHERITING RIGHTS_ALL +#define RIGHTS_CHARACTER_DEVICE_BASE RIGHTS_ALL +#define RIGHTS_CHARACTER_DEVICE_INHERITING RIGHTS_ALL + +// Only allow directory operations on directories. Directories can only +// yield file descriptors to other directories and files. +#define RIGHTS_DIRECTORY_BASE \ + (__WASI_RIGHT_FD_FDSTAT_SET_FLAGS | __WASI_RIGHT_FD_SYNC | \ + __WASI_RIGHT_FD_ADVISE | __WASI_RIGHT_PATH_CREATE_DIRECTORY | \ + __WASI_RIGHT_PATH_CREATE_FILE | __WASI_RIGHT_PATH_LINK_SOURCE | \ + __WASI_RIGHT_PATH_LINK_TARGET | __WASI_RIGHT_PATH_OPEN | \ + __WASI_RIGHT_FD_READDIR | __WASI_RIGHT_PATH_READLINK | \ + __WASI_RIGHT_PATH_RENAME_SOURCE | __WASI_RIGHT_PATH_RENAME_TARGET | \ + __WASI_RIGHT_PATH_FILESTAT_GET | \ + __WASI_RIGHT_PATH_FILESTAT_SET_SIZE | \ + __WASI_RIGHT_PATH_FILESTAT_SET_TIMES | \ + __WASI_RIGHT_FD_FILESTAT_GET | __WASI_RIGHT_FD_FILESTAT_SET_TIMES | \ + __WASI_RIGHT_PATH_SYMLINK | __WASI_RIGHT_PATH_UNLINK_FILE | \ + __WASI_RIGHT_PATH_REMOVE_DIRECTORY | \ + __WASI_RIGHT_POLL_FD_READWRITE) +#define RIGHTS_DIRECTORY_INHERITING \ + (RIGHTS_DIRECTORY_BASE | RIGHTS_REGULAR_FILE_BASE) + +// Operations that apply to regular files. +#define RIGHTS_REGULAR_FILE_BASE \ + (__WASI_RIGHT_FD_DATASYNC | __WASI_RIGHT_FD_READ | \ + __WASI_RIGHT_FD_SEEK | __WASI_RIGHT_FD_FDSTAT_SET_FLAGS | \ + __WASI_RIGHT_FD_SYNC | __WASI_RIGHT_FD_TELL | __WASI_RIGHT_FD_WRITE | \ + __WASI_RIGHT_FD_ADVISE | __WASI_RIGHT_FD_ALLOCATE | \ + __WASI_RIGHT_FD_FILESTAT_GET | __WASI_RIGHT_FD_FILESTAT_SET_SIZE | \ + __WASI_RIGHT_FD_FILESTAT_SET_TIMES | __WASI_RIGHT_POLL_FD_READWRITE) +#define RIGHTS_REGULAR_FILE_INHERITING 0 + +// Operations that apply to sockets and socket pairs. +#define RIGHTS_SOCKET_BASE \ + (__WASI_RIGHT_FD_READ | __WASI_RIGHT_FD_FDSTAT_SET_FLAGS | \ + __WASI_RIGHT_FD_WRITE | __WASI_RIGHT_FD_FILESTAT_GET | \ + __WASI_RIGHT_POLL_FD_READWRITE | __WASI_RIGHT_SOCK_CONNECT | \ + __WASI_RIGHT_SOCK_LISTEN | __WASI_RIGHT_SOCK_BIND | \ + __WASI_RIGHT_SOCK_ACCEPT | __WASI_RIGHT_SOCK_RECV | \ + __WASI_RIGHT_SOCK_SEND | __WASI_RIGHT_SOCK_ADDR_LOCAL | \ + __WASI_RIGHT_SOCK_ADDR_REMOTE | __WASI_RIGHT_SOCK_RECV_FROM | \ + __WASI_RIGHT_SOCK_SEND_TO) +#define RIGHTS_SOCKET_INHERITING RIGHTS_ALL + +// Operations that apply to TTYs. +#define RIGHTS_TTY_BASE \ + (__WASI_RIGHT_FD_READ | __WASI_RIGHT_FD_FDSTAT_SET_FLAGS | \ + __WASI_RIGHT_FD_WRITE | __WASI_RIGHT_FD_FILESTAT_GET | \ + __WASI_RIGHT_POLL_FD_READWRITE) +#define RIGHTS_TTY_INHERITING 0 + +/* clang-format on */ + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h new file mode 100644 index 000000000..7f6e9b941 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h @@ -0,0 +1,143 @@ +// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM +// Exceptions. See +// https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license +// information. +// +// Significant parts of this file are derived from cloudabi-utils. See +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE +// for license information. +// +// The upstream file contains the following copyright notice: +// +// Copyright (c) 2016 Nuxi, https://nuxi.nl/ + +#ifndef SSP_CONFIG_H +#define SSP_CONFIG_H + +#include "gnuc.h" +#include <stdlib.h> + +#if defined(__FreeBSD__) || defined(__APPLE__) \ + || (defined(ANDROID) && __ANDROID_API__ < 28) +#define CONFIG_HAS_ARC4RANDOM_BUF 1 +#else +#define CONFIG_HAS_ARC4RANDOM_BUF 0 +#endif + +// On Linux, prefer to use getrandom, though it isn't available in +// GLIBC before 2.25. +#if (defined(__linux__) || defined(ESP_PLATFORM)) \ + && (!defined(__GLIBC__) || __GLIBC__ > 2 \ + || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) +#define CONFIG_HAS_GETRANDOM 1 +#else +#define CONFIG_HAS_GETRANDOM 0 +#endif + +#if defined(__CloudABI__) +#define CONFIG_HAS_CAP_ENTER 1 +#else +#define CONFIG_HAS_CAP_ENTER 0 +#endif + +#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__EMSCRIPTEN__) \ + && !defined(ESP_PLATFORM) && !defined(DISABLE_CLOCK_NANOSLEEP) +#define CONFIG_HAS_CLOCK_NANOSLEEP 1 +#else +#define CONFIG_HAS_CLOCK_NANOSLEEP 0 +#endif + +#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(ESP_PLATFORM) +#define CONFIG_HAS_FDATASYNC 1 +#else +#define CONFIG_HAS_FDATASYNC 0 +#endif + +/* + * For NuttX, CONFIG_HAS_ISATTY is provided by its platform header. + * (platform_internal.h) + */ +#ifndef __NuttX__ +#ifndef __CloudABI__ +#define CONFIG_HAS_ISATTY 1 +#else +#define CONFIG_HAS_ISATTY 0 +#endif +#endif + +#if !defined(__APPLE__) && !defined(ESP_PLATFORM) +#define CONFIG_HAS_POSIX_FALLOCATE 1 +#else +#define CONFIG_HAS_POSIX_FALLOCATE 0 +#endif + +#if !defined(__APPLE__) && !defined(ESP_PLATFORM) +#define CONFIG_HAS_PREADV 1 +#else +#define CONFIG_HAS_PREADV 0 +#endif + +#if defined(__APPLE__) || defined(__CloudABI__) +#define CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP 1 +#else +#define CONFIG_HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP 0 +#endif + +#if !defined(__APPLE__) && !defined(BH_PLATFORM_LINUX_SGX) +#define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 1 +#else +#define CONFIG_HAS_PTHREAD_CONDATTR_SETCLOCK 0 +#endif + +#if !defined(__APPLE__) && !defined(ESP_PLATFORM) +#define CONFIG_HAS_PWRITEV 1 +#else +#define CONFIG_HAS_PWRITEV 0 +#endif + +#ifdef __APPLE__ +#define st_atim st_atimespec +#define st_ctim st_ctimespec +#define st_mtim st_mtimespec +#endif + +#ifdef __APPLE__ +#define CONFIG_TLS_USE_GSBASE 1 +#else +#define CONFIG_TLS_USE_GSBASE 0 +#endif + +#if !defined(BH_PLATFORM_LINUX_SGX) +/* Clang's __GNUC_PREREQ macro has a different meaning than GCC one, +so we have to handle this case specially */ +#if defined(__clang__) +/* Clang provides stdatomic.h since 3.6.0 +See https://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html */ +#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6) +#define CONFIG_HAS_STD_ATOMIC 1 +#else +#define CONFIG_HAS_STD_ATOMIC 0 +#endif +#elif defined(__GNUC_PREREQ) +/* Even though older versions of GCC support C11, atomics were +not implemented until 4.9. See +https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58016 */ +#if __GNUC_PREREQ(4, 9) +#define CONFIG_HAS_STD_ATOMIC 1 +#else /* else of __GNUC_PREREQ(4, 9) */ +#define CONFIG_HAS_STD_ATOMIC 0 +#endif /* end of __GNUC_PREREQ(4, 9) */ +#else /* else of defined(__GNUC_PREREQ) */ +#define CONFIG_HAS_STD_ATOMIC 1 +#endif /* end of defined(__GNUC_PREREQ) */ +#else /* else of !defined(BH_PLATFORM_LINUX_SGX) */ +#define CONFIG_HAS_STD_ATOMIC 0 +#endif /* end of !defined(BH_PLATFORM_LINUX_SGX) */ + +#if !defined(__NuttX__) +#define CONFIG_HAS_D_INO 1 +#else +#define CONFIG_HAS_D_INO 0 +#endif + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c new file mode 100644 index 000000000..858d8d5e4 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c @@ -0,0 +1,47 @@ +// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM +// Exceptions. See +// https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license +// information. +// +// Significant parts of this file are derived from cloudabi-utils. See +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE +// for license information. +// +// The upstream file contains the following copyright notice: +// +// Copyright (c) 2016 Nuxi, https://nuxi.nl/ + +#include "ssp_config.h" +#include "bh_platform.h" +#include "str.h" + +static char * +bh_strndup(const char *s, size_t n) +{ + size_t l = strnlen(s, n); + char *s1 = wasm_runtime_malloc((uint32)(l + 1)); + + if (!s1) + return NULL; + bh_memcpy_s(s1, (uint32)(l + 1), s, (uint32)l); + s1[l] = 0; + return s1; +} + +char * +str_nullterminate(const char *s, size_t len) +{ + /* Copy string */ + char *ret = bh_strndup(s, len); + + if (ret == NULL) + return NULL; + + /* Ensure that it contains no null bytes within */ + if (strlen(ret) != len) { + wasm_runtime_free(ret); + errno = EILSEQ; + return NULL; + } + return ret; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.h new file mode 100644 index 000000000..7d633e5c8 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.h @@ -0,0 +1,22 @@ +// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM +// Exceptions. See +// https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license +// information. +// +// Significant parts of this file are derived from cloudabi-utils. See +// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE +// for license information. +// +// The upstream file contains the following copyright notice: +// +// Copyright (c) 2016 Nuxi, https://nuxi.nl/ + +#ifndef STR_H +#define STR_H + +#include "ssp_config.h" + +char * +str_nullterminate(const char *, size_t); + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/SConscript b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/SConscript new file mode 100644 index 000000000..65f561ae2 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/SConscript @@ -0,0 +1,19 @@ +# +# Copyright (c) 2021, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +from building import * + +cwd = GetCurrentDir() + +src = Split(''' +thread_manager.c +''') + +CPPPATH = [cwd] + +group = DefineGroup('iwasm_lib_thread_mgr', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_manager.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_manager.c new file mode 100644 index 000000000..9303eb3f5 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -0,0 +1,1351 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "thread_manager.h" + +#if WASM_ENABLE_INTERP != 0 +#include "../interpreter/wasm_runtime.h" +#endif +#if WASM_ENABLE_AOT != 0 +#include "../aot/aot_runtime.h" +#endif + +#if WASM_ENABLE_DEBUG_INTERP != 0 +#include "debug_engine.h" +#endif + +#if WASM_ENABLE_SHARED_MEMORY != 0 +#include "wasm_shared_memory.h" +#endif + +typedef struct { + bh_list_link l; + void (*destroy_cb)(WASMCluster *); +} DestroyCallBackNode; + +static bh_list destroy_callback_list_head; +static bh_list *const destroy_callback_list = &destroy_callback_list_head; + +static bh_list cluster_list_head; +static bh_list *const cluster_list = &cluster_list_head; +static korp_mutex cluster_list_lock; + +typedef void (*list_visitor)(void *, void *); + +static uint32 cluster_max_thread_num = CLUSTER_MAX_THREAD_NUM; + +/* Set the maximum thread number, if this function is not called, + the max thread num is defined by CLUSTER_MAX_THREAD_NUM */ +void +wasm_cluster_set_max_thread_num(uint32 num) +{ + if (num > 0) + cluster_max_thread_num = num; +} + +bool +thread_manager_init() +{ + if (bh_list_init(cluster_list) != 0) + return false; + if (os_mutex_init(&cluster_list_lock) != 0) + return false; + return true; +} + +void +thread_manager_destroy() +{ + WASMCluster *cluster = bh_list_first_elem(cluster_list); + WASMCluster *next; + while (cluster) { + next = bh_list_elem_next(cluster); + wasm_cluster_destroy(cluster); + cluster = next; + } + wasm_cluster_cancel_all_callbacks(); + os_mutex_destroy(&cluster_list_lock); +} + +static void +traverse_list(bh_list *l, list_visitor visitor, void *user_data) +{ + void *next, *node = bh_list_first_elem(l); + while (node) { + next = bh_list_elem_next(node); + visitor(node, user_data); + node = next; + } +} + +/* Assumes cluster->lock is locked */ +static bool +safe_traverse_exec_env_list(WASMCluster *cluster, list_visitor visitor, + void *user_data) +{ + Vector proc_nodes; + void *node; + bool ret = true; + + if (!bh_vector_init(&proc_nodes, cluster->exec_env_list.len, sizeof(void *), + false)) { + ret = false; + goto final; + } + + node = bh_list_first_elem(&cluster->exec_env_list); + + while (node) { + bool already_processed = false; + void *proc_node; + uint32 i; + for (i = 0; i < (uint32)bh_vector_size(&proc_nodes); i++) { + if (!bh_vector_get(&proc_nodes, i, &proc_node)) { + ret = false; + goto final; + } + if (proc_node == node) { + already_processed = true; + break; + } + } + if (already_processed) { + node = bh_list_elem_next(node); + continue; + } + + os_mutex_unlock(&cluster->lock); + visitor(node, user_data); + os_mutex_lock(&cluster->lock); + if (!bh_vector_append(&proc_nodes, &node)) { + ret = false; + goto final; + } + + node = bh_list_first_elem(&cluster->exec_env_list); + } + +final: + bh_vector_destroy(&proc_nodes); + + return ret; +} + +/* The caller must lock cluster->lock */ +static bool +allocate_aux_stack(WASMExecEnv *exec_env, uint32 *start, uint32 *size) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); +#if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION != 0 + WASMModuleInstanceCommon *module_inst = + wasm_exec_env_get_module_inst(exec_env); + uint32 stack_end; + + stack_end = wasm_runtime_module_malloc_internal(module_inst, exec_env, + cluster->stack_size, NULL); + *start = stack_end + cluster->stack_size; + *size = cluster->stack_size; + + return stack_end != 0; +#else + uint32 i; + + /* If the module doesn't have aux stack info, + it can't create any threads */ + if (!cluster->stack_segment_occupied) + return false; + + for (i = 0; i < cluster_max_thread_num; i++) { + if (!cluster->stack_segment_occupied[i]) { + if (start) + *start = cluster->stack_tops[i]; + if (size) + *size = cluster->stack_size; + cluster->stack_segment_occupied[i] = true; + return true; + } + } + + return false; +#endif +} + +/* The caller must lock cluster->lock */ +static bool +free_aux_stack(WASMExecEnv *exec_env, uint32 start) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + +#if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION != 0 + WASMModuleInstanceCommon *module_inst = + wasm_exec_env_get_module_inst(exec_env); + + if (!wasm_exec_env_is_aux_stack_managed_by_runtime(exec_env)) { + return true; + } + + bh_assert(start >= cluster->stack_size); + + wasm_runtime_module_free_internal(module_inst, exec_env, + start - cluster->stack_size); + + return true; +#else + uint32 i; + + for (i = 0; i < cluster_max_thread_num; i++) { + if (start == cluster->stack_tops[i]) { + cluster->stack_segment_occupied[i] = false; + return true; + } + } + return false; +#endif +} + +WASMCluster * +wasm_cluster_create(WASMExecEnv *exec_env) +{ + WASMCluster *cluster; + uint32 aux_stack_start, aux_stack_size; + + bh_assert(exec_env->cluster == NULL); + if (!(cluster = wasm_runtime_malloc(sizeof(WASMCluster)))) { + LOG_ERROR("thread manager error: failed to allocate memory"); + return NULL; + } + memset(cluster, 0, sizeof(WASMCluster)); + + exec_env->cluster = cluster; + + bh_list_init(&cluster->exec_env_list); + bh_list_insert(&cluster->exec_env_list, exec_env); + if (os_mutex_init(&cluster->lock) != 0) { + wasm_runtime_free(cluster); + LOG_ERROR("thread manager error: failed to init mutex"); + return NULL; + } + + /* Prepare the aux stack top and size for every thread */ + if (!wasm_exec_env_get_aux_stack(exec_env, &aux_stack_start, + &aux_stack_size)) { +#if WASM_ENABLE_LIB_WASI_THREADS == 0 + LOG_VERBOSE("No aux stack info for this module, can't create thread"); +#endif + + /* If the module don't have aux stack info, don't throw error here, + but remain stack_tops and stack_segment_occupied as NULL */ + os_mutex_lock(&cluster_list_lock); + if (bh_list_insert(cluster_list, cluster) != 0) { + os_mutex_unlock(&cluster_list_lock); + goto fail; + } + os_mutex_unlock(&cluster_list_lock); + + return cluster; + } + +#if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION != 0 + cluster->stack_size = aux_stack_size; +#else + cluster->stack_size = aux_stack_size / (cluster_max_thread_num + 1); + if (cluster->stack_size < WASM_THREAD_AUX_STACK_SIZE_MIN) { + goto fail; + } + /* Make stack size 16-byte aligned */ + cluster->stack_size = cluster->stack_size & (~15); +#endif + + /* Set initial aux stack top to the instance and + aux stack boundary to the main exec_env */ + if (!wasm_exec_env_set_aux_stack(exec_env, aux_stack_start, + cluster->stack_size)) + goto fail; + +#if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION == 0 + if (cluster_max_thread_num != 0) { + uint64 total_size = cluster_max_thread_num * sizeof(uint32); + uint32 i; + if (total_size >= UINT32_MAX + || !(cluster->stack_tops = + wasm_runtime_malloc((uint32)total_size))) { + goto fail; + } + memset(cluster->stack_tops, 0, (uint32)total_size); + + if (!(cluster->stack_segment_occupied = + wasm_runtime_malloc(cluster_max_thread_num * sizeof(bool)))) { + goto fail; + } + memset(cluster->stack_segment_occupied, 0, + cluster_max_thread_num * sizeof(bool)); + + /* Reserve space for main instance */ + aux_stack_start -= cluster->stack_size; + + for (i = 0; i < cluster_max_thread_num; i++) { + cluster->stack_tops[i] = aux_stack_start - cluster->stack_size * i; + } + } +#endif + + os_mutex_lock(&cluster_list_lock); + if (bh_list_insert(cluster_list, cluster) != 0) { + os_mutex_unlock(&cluster_list_lock); + goto fail; + } + os_mutex_unlock(&cluster_list_lock); + + return cluster; + +fail: + if (cluster) + wasm_cluster_destroy(cluster); + + return NULL; +} + +static void +destroy_cluster_visitor(void *node, void *user_data) +{ + DestroyCallBackNode *destroy_node = (DestroyCallBackNode *)node; + WASMCluster *cluster = (WASMCluster *)user_data; + + destroy_node->destroy_cb(cluster); +} + +void +wasm_cluster_destroy(WASMCluster *cluster) +{ + traverse_list(destroy_callback_list, destroy_cluster_visitor, + (void *)cluster); + + /* Remove the cluster from the cluster list */ + os_mutex_lock(&cluster_list_lock); + bh_list_remove(cluster_list, cluster); + os_mutex_unlock(&cluster_list_lock); + + os_mutex_destroy(&cluster->lock); + +#if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION == 0 + if (cluster->stack_tops) + wasm_runtime_free(cluster->stack_tops); + if (cluster->stack_segment_occupied) + wasm_runtime_free(cluster->stack_segment_occupied); +#endif + +#if WASM_ENABLE_DEBUG_INTERP != 0 + wasm_debug_instance_destroy(cluster); +#endif + + wasm_runtime_free(cluster); +} + +static void +free_node_visitor(void *node, void *user_data) +{ + wasm_runtime_free(node); +} + +void +wasm_cluster_cancel_all_callbacks() +{ + traverse_list(destroy_callback_list, free_node_visitor, NULL); + bh_list_init(destroy_callback_list); +} + +WASMCluster * +wasm_exec_env_get_cluster(WASMExecEnv *exec_env) +{ + return exec_env->cluster; +} + +/* The caller must lock cluster->lock */ +static bool +wasm_cluster_add_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env) +{ + bool ret = true; + + exec_env->cluster = cluster; + + if (cluster->exec_env_list.len == cluster_max_thread_num + 1) { + LOG_ERROR("thread manager error: " + "maximum number of threads exceeded"); + ret = false; + } + + if (ret && bh_list_insert(&cluster->exec_env_list, exec_env) != 0) + ret = false; + + return ret; +} + +static bool +wasm_cluster_del_exec_env_internal(WASMCluster *cluster, WASMExecEnv *exec_env, + bool can_destroy_cluster) +{ + bool ret = true; + bh_assert(exec_env->cluster == cluster); + +#if WASM_ENABLE_DEBUG_INTERP != 0 + /* Wait for debugger control thread to process the + stop event of this thread */ + if (cluster->debug_inst) { + /* lock the debug_inst->wait_lock so + other threads can't fire stop events */ + os_mutex_lock(&cluster->debug_inst->wait_lock); + while (cluster->debug_inst->stopped_thread == exec_env) { + /* either wakes up by signal or by 1-second timeout */ + os_cond_reltimedwait(&cluster->debug_inst->wait_cond, + &cluster->debug_inst->wait_lock, 1000000); + } + os_mutex_unlock(&cluster->debug_inst->wait_lock); + } +#endif + if (bh_list_remove(&cluster->exec_env_list, exec_env) != 0) + ret = false; + + if (can_destroy_cluster) { + if (cluster->exec_env_list.len == 0) { + /* exec_env_list empty, destroy the cluster */ + wasm_cluster_destroy(cluster); + } + } + else { + /* Don't destroy cluster as cluster->lock is being used */ + } + + return ret; +} + +/* The caller should lock cluster->lock for thread safety */ +bool +wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env) +{ + return wasm_cluster_del_exec_env_internal(cluster, exec_env, true); +} + +static WASMExecEnv * +wasm_cluster_search_exec_env(WASMCluster *cluster, + WASMModuleInstanceCommon *module_inst) +{ + WASMExecEnv *node = NULL; + + os_mutex_lock(&cluster->lock); + node = bh_list_first_elem(&cluster->exec_env_list); + while (node) { + if (node->module_inst == module_inst) { + os_mutex_unlock(&cluster->lock); + return node; + } + node = bh_list_elem_next(node); + } + + os_mutex_unlock(&cluster->lock); + return NULL; +} + +/* search the global cluster list to find if the given + module instance have a corresponding exec_env */ +WASMExecEnv * +wasm_clusters_search_exec_env(WASMModuleInstanceCommon *module_inst) +{ + WASMCluster *cluster = NULL; + WASMExecEnv *exec_env = NULL; + + os_mutex_lock(&cluster_list_lock); + cluster = bh_list_first_elem(cluster_list); + while (cluster) { + exec_env = wasm_cluster_search_exec_env(cluster, module_inst); + if (exec_env) { + os_mutex_unlock(&cluster_list_lock); + return exec_env; + } + cluster = bh_list_elem_next(cluster); + } + + os_mutex_unlock(&cluster_list_lock); + return NULL; +} + +WASMExecEnv * +wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasm_module_t module; + wasm_module_inst_t new_module_inst; +#if WASM_ENABLE_LIBC_WASI != 0 + WASIContext *wasi_ctx; +#endif + WASMExecEnv *new_exec_env; + uint32 aux_stack_start, aux_stack_size; + uint32 stack_size = 8192; + + if (!module_inst || !(module = wasm_exec_env_get_module(exec_env))) { + return NULL; + } + + os_mutex_lock(&cluster->lock); + + if (cluster->has_exception || cluster->processing) { + goto fail1; + } + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + stack_size = + ((WASMModuleInstance *)module_inst)->default_wasm_stack_size; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + stack_size = + ((AOTModuleInstance *)module_inst)->default_wasm_stack_size; + } +#endif + + if (!(new_module_inst = wasm_runtime_instantiate_internal( + module, true, exec_env, stack_size, 0, NULL, 0))) { + goto fail1; + } + + /* Set custom_data to new module instance */ + wasm_runtime_set_custom_data_internal( + new_module_inst, wasm_runtime_get_custom_data(module_inst)); + +#if WASM_ENABLE_LIBC_WASI != 0 + wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst); + wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx); +#endif + + new_exec_env = wasm_exec_env_create_internal(new_module_inst, + exec_env->wasm_stack_size); + if (!new_exec_env) + goto fail2; + + if (!allocate_aux_stack(exec_env, &aux_stack_start, &aux_stack_size)) { + LOG_ERROR("thread manager error: " + "failed to allocate aux stack space for new thread"); + goto fail3; + } + + /* Set aux stack for current thread */ + if (!wasm_exec_env_set_aux_stack(new_exec_env, aux_stack_start, + aux_stack_size)) { + goto fail4; + } + + /* Inherit suspend_flags of parent thread */ + new_exec_env->suspend_flags.flags = exec_env->suspend_flags.flags; + + if (!wasm_cluster_add_exec_env(cluster, new_exec_env)) + goto fail4; + + os_mutex_unlock(&cluster->lock); + + return new_exec_env; + +fail4: + /* free the allocated aux stack space */ + free_aux_stack(exec_env, aux_stack_start); +fail3: + wasm_exec_env_destroy_internal(new_exec_env); +fail2: + wasm_runtime_deinstantiate_internal(new_module_inst, true); +fail1: + os_mutex_unlock(&cluster->lock); + + return NULL; +} + +void +wasm_cluster_destroy_spawned_exec_env(WASMExecEnv *exec_env) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); + bh_assert(cluster != NULL); + + os_mutex_lock(&cluster->lock); + + /* Free aux stack space */ + free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom); + /* Remove exec_env */ + wasm_cluster_del_exec_env_internal(cluster, exec_env, false); + /* Destroy exec_env */ + wasm_exec_env_destroy_internal(exec_env); + /* Routine exit, destroy instance */ + wasm_runtime_deinstantiate_internal(module_inst, true); + + os_mutex_unlock(&cluster->lock); +} + +/* start routine of thread manager */ +static void * +thread_manager_start_routine(void *arg) +{ + void *ret; + WASMExecEnv *exec_env = (WASMExecEnv *)arg; + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + WASMModuleInstanceCommon *module_inst = + wasm_exec_env_get_module_inst(exec_env); + + bh_assert(cluster != NULL); + bh_assert(module_inst != NULL); + + os_mutex_lock(&exec_env->wait_lock); + exec_env->handle = os_self_thread(); + /* Notify the parent thread to continue running */ + os_cond_signal(&exec_env->wait_cond); + os_mutex_unlock(&exec_env->wait_lock); + + ret = exec_env->thread_start_routine(exec_env); + +#ifdef OS_ENABLE_HW_BOUND_CHECK + os_mutex_lock(&exec_env->wait_lock); + if (exec_env->suspend_flags.flags & 0x08) + ret = exec_env->thread_ret_value; + os_mutex_unlock(&exec_env->wait_lock); +#endif + + /* Routine exit */ + +#if WASM_ENABLE_DEBUG_INTERP != 0 + wasm_cluster_thread_exited(exec_env); +#endif + + os_mutex_lock(&cluster_list_lock); + + os_mutex_lock(&cluster->lock); + + /* Detach the native thread here to ensure the resources are freed */ + if (exec_env->wait_count == 0 && !exec_env->thread_is_detached) { + /* Only detach current thread when there is no other thread + joining it, otherwise let the system resources for the + thread be released after joining */ + os_thread_detach(exec_env->handle); + /* No need to set exec_env->thread_is_detached to true here + since we will exit soon */ + } + + /* Free aux stack space */ + free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom); + /* Remove exec_env */ + wasm_cluster_del_exec_env_internal(cluster, exec_env, false); + /* Destroy exec_env */ + wasm_exec_env_destroy_internal(exec_env); + /* Routine exit, destroy instance */ + wasm_runtime_deinstantiate_internal(module_inst, true); + + os_mutex_unlock(&cluster->lock); + + os_mutex_unlock(&cluster_list_lock); + + os_thread_exit(ret); + return ret; +} + +int32 +wasm_cluster_create_thread(WASMExecEnv *exec_env, + wasm_module_inst_t module_inst, bool alloc_aux_stack, + void *(*thread_routine)(void *), void *arg) +{ + WASMCluster *cluster; + WASMExecEnv *new_exec_env; + uint32 aux_stack_start = 0, aux_stack_size; + korp_tid tid; + + cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); + + os_mutex_lock(&cluster->lock); + + if (cluster->has_exception || cluster->processing) { + goto fail1; + } + + new_exec_env = + wasm_exec_env_create_internal(module_inst, exec_env->wasm_stack_size); + if (!new_exec_env) + goto fail1; + + if (alloc_aux_stack) { + if (!allocate_aux_stack(exec_env, &aux_stack_start, &aux_stack_size)) { + LOG_ERROR("thread manager error: " + "failed to allocate aux stack space for new thread"); + goto fail2; + } + + /* Set aux stack for current thread */ + if (!wasm_exec_env_set_aux_stack(new_exec_env, aux_stack_start, + aux_stack_size)) { + goto fail3; + } + } + else { + /* Disable aux stack */ + new_exec_env->aux_stack_boundary.boundary = 0; + new_exec_env->aux_stack_bottom.bottom = UINT32_MAX; + } + + /* Inherit suspend_flags of parent thread */ + new_exec_env->suspend_flags.flags = exec_env->suspend_flags.flags; + + if (!wasm_cluster_add_exec_env(cluster, new_exec_env)) + goto fail3; + + new_exec_env->thread_start_routine = thread_routine; + new_exec_env->thread_arg = arg; + + os_mutex_lock(&new_exec_env->wait_lock); + + if (0 + != os_thread_create(&tid, thread_manager_start_routine, + (void *)new_exec_env, + APP_THREAD_STACK_SIZE_DEFAULT)) { + os_mutex_unlock(&new_exec_env->wait_lock); + goto fail4; + } + + /* Wait until the new_exec_env->handle is set to avoid it is + illegally accessed after unlocking cluster->lock */ + os_cond_wait(&new_exec_env->wait_cond, &new_exec_env->wait_lock); + os_mutex_unlock(&new_exec_env->wait_lock); + + os_mutex_unlock(&cluster->lock); + + return 0; + +fail4: + wasm_cluster_del_exec_env_internal(cluster, new_exec_env, false); +fail3: + /* free the allocated aux stack space */ + if (alloc_aux_stack) + free_aux_stack(exec_env, aux_stack_start); +fail2: + wasm_exec_env_destroy_internal(new_exec_env); +fail1: + os_mutex_unlock(&cluster->lock); + + return -1; +} + +bool +wasm_cluster_dup_c_api_imports(WASMModuleInstanceCommon *module_inst_dst, + const WASMModuleInstanceCommon *module_inst_src) +{ + /* workaround about passing instantiate-linking information */ + CApiFuncImport **new_c_api_func_imports = NULL; + CApiFuncImport *c_api_func_imports; + uint32 import_func_count = 0; + uint32 size_in_bytes = 0; + +#if WASM_ENABLE_INTERP != 0 + if (module_inst_src->module_type == Wasm_Module_Bytecode) { + new_c_api_func_imports = + &(((WASMModuleInstance *)module_inst_dst)->e->c_api_func_imports); + c_api_func_imports = ((const WASMModuleInstance *)module_inst_src) + ->e->c_api_func_imports; + import_func_count = + ((WASMModule *)(((const WASMModuleInstance *)module_inst_src) + ->module)) + ->import_function_count; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst_src->module_type == Wasm_Module_AoT) { + AOTModuleInstanceExtra *e = + (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst_dst)->e; + new_c_api_func_imports = &(e->c_api_func_imports); + + e = (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst_src)->e; + c_api_func_imports = e->c_api_func_imports; + + import_func_count = + ((AOTModule *)(((AOTModuleInstance *)module_inst_src)->module)) + ->import_func_count; + } +#endif + + if (import_func_count != 0 && c_api_func_imports) { + size_in_bytes = sizeof(CApiFuncImport) * import_func_count; + *new_c_api_func_imports = wasm_runtime_malloc(size_in_bytes); + if (!(*new_c_api_func_imports)) + return false; + + bh_memcpy_s(*new_c_api_func_imports, size_in_bytes, c_api_func_imports, + size_in_bytes); + } + return true; +} + +#if WASM_ENABLE_DEBUG_INTERP != 0 +WASMCurrentEnvStatus * +wasm_cluster_create_exenv_status() +{ + WASMCurrentEnvStatus *status; + + if (!(status = wasm_runtime_malloc(sizeof(WASMCurrentEnvStatus)))) { + return NULL; + } + + status->step_count = 0; + status->signal_flag = 0; + status->running_status = 0; + return status; +} + +void +wasm_cluster_destroy_exenv_status(WASMCurrentEnvStatus *status) +{ + wasm_runtime_free(status); +} + +inline static bool +wasm_cluster_thread_is_running(WASMExecEnv *exec_env) +{ + return exec_env->current_status->running_status == STATUS_RUNNING + || exec_env->current_status->running_status == STATUS_STEP; +} + +void +wasm_cluster_clear_thread_signal(WASMExecEnv *exec_env) +{ + exec_env->current_status->signal_flag = 0; +} + +void +wasm_cluster_thread_send_signal(WASMExecEnv *exec_env, uint32 signo) +{ + exec_env->current_status->signal_flag = signo; +} + +static void +notify_debug_instance(WASMExecEnv *exec_env) +{ + WASMCluster *cluster; + + cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); + + if (!cluster->debug_inst) { + return; + } + + on_thread_stop_event(cluster->debug_inst, exec_env); +} + +static void +notify_debug_instance_exit(WASMExecEnv *exec_env) +{ + WASMCluster *cluster; + + cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); + + if (!cluster->debug_inst) { + return; + } + + on_thread_exit_event(cluster->debug_inst, exec_env); +} + +void +wasm_cluster_thread_waiting_run(WASMExecEnv *exec_env) +{ + exec_env->current_status->running_status = STATUS_STOP; + notify_debug_instance(exec_env); + + while (!wasm_cluster_thread_is_running(exec_env)) { + os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); + } +} + +void +wasm_cluster_send_signal_all(WASMCluster *cluster, uint32 signo) +{ + WASMExecEnv *exec_env = bh_list_first_elem(&cluster->exec_env_list); + while (exec_env) { + wasm_cluster_thread_send_signal(exec_env, signo); + exec_env = bh_list_elem_next(exec_env); + } +} + +void +wasm_cluster_thread_exited(WASMExecEnv *exec_env) +{ + exec_env->current_status->running_status = STATUS_EXIT; + notify_debug_instance_exit(exec_env); +} + +void +wasm_cluster_thread_continue(WASMExecEnv *exec_env) +{ + os_mutex_lock(&exec_env->wait_lock); + wasm_cluster_clear_thread_signal(exec_env); + exec_env->current_status->running_status = STATUS_RUNNING; + os_cond_signal(&exec_env->wait_cond); + os_mutex_unlock(&exec_env->wait_lock); +} + +void +wasm_cluster_thread_step(WASMExecEnv *exec_env) +{ + os_mutex_lock(&exec_env->wait_lock); + exec_env->current_status->running_status = STATUS_STEP; + os_cond_signal(&exec_env->wait_cond); + os_mutex_unlock(&exec_env->wait_lock); +} + +void +wasm_cluster_set_debug_inst(WASMCluster *cluster, WASMDebugInstance *inst) +{ + cluster->debug_inst = inst; +} + +#endif /* end of WASM_ENABLE_DEBUG_INTERP */ + +/* Check whether the exec_env is in one of all clusters, the caller + should add lock to the cluster list before calling us */ +static bool +clusters_have_exec_env(WASMExecEnv *exec_env) +{ + WASMCluster *cluster = bh_list_first_elem(cluster_list); + WASMExecEnv *node; + + while (cluster) { + os_mutex_lock(&cluster->lock); + node = bh_list_first_elem(&cluster->exec_env_list); + + while (node) { + if (node == exec_env) { + bh_assert(exec_env->cluster == cluster); + os_mutex_unlock(&cluster->lock); + return true; + } + node = bh_list_elem_next(node); + } + os_mutex_unlock(&cluster->lock); + + cluster = bh_list_elem_next(cluster); + } + + return false; +} + +int32 +wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val) +{ + korp_tid handle; + + os_mutex_lock(&cluster_list_lock); + + if (!clusters_have_exec_env(exec_env) || exec_env->thread_is_detached) { + /* Invalid thread, thread has exited or thread has been detached */ + if (ret_val) + *ret_val = NULL; + os_mutex_unlock(&cluster_list_lock); + return 0; + } + + os_mutex_lock(&exec_env->wait_lock); + exec_env->wait_count++; + handle = exec_env->handle; + os_mutex_unlock(&exec_env->wait_lock); + + os_mutex_unlock(&cluster_list_lock); + + return os_thread_join(handle, ret_val); +} + +int32 +wasm_cluster_detach_thread(WASMExecEnv *exec_env) +{ + int32 ret = 0; + + os_mutex_lock(&cluster_list_lock); + if (!clusters_have_exec_env(exec_env)) { + /* Invalid thread or the thread has exited */ + os_mutex_unlock(&cluster_list_lock); + return 0; + } + if (exec_env->wait_count == 0 && !exec_env->thread_is_detached) { + /* Only detach current thread when there is no other thread + joining it, otherwise let the system resources for the + thread be released after joining */ + ret = os_thread_detach(exec_env->handle); + exec_env->thread_is_detached = true; + } + os_mutex_unlock(&cluster_list_lock); + return ret; +} + +void +wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval) +{ + WASMCluster *cluster; + WASMModuleInstanceCommon *module_inst; + +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (exec_env->jmpbuf_stack_top) { + /* Store the return value in exec_env */ + exec_env->thread_ret_value = retval; + exec_env->suspend_flags.flags |= 0x08; + +#ifndef BH_PLATFORM_WINDOWS + /* Pop all jmpbuf_node except the last one */ + while (exec_env->jmpbuf_stack_top->prev) { + wasm_exec_env_pop_jmpbuf(exec_env); + } + os_longjmp(exec_env->jmpbuf_stack_top->jmpbuf, 1); + return; +#endif + } +#endif + + cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); +#if WASM_ENABLE_DEBUG_INTERP != 0 + wasm_cluster_clear_thread_signal(exec_env); + wasm_cluster_thread_exited(exec_env); +#endif + + /* App exit the thread, free the resources before exit native thread */ + + os_mutex_lock(&cluster_list_lock); + + os_mutex_lock(&cluster->lock); + + /* Detach the native thread here to ensure the resources are freed */ + if (exec_env->wait_count == 0 && !exec_env->thread_is_detached) { + /* Only detach current thread when there is no other thread + joining it, otherwise let the system resources for the + thread be released after joining */ + os_thread_detach(exec_env->handle); + /* No need to set exec_env->thread_is_detached to true here + since we will exit soon */ + } + + module_inst = exec_env->module_inst; + + /* Free aux stack space */ + free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom); + /* Remove exec_env */ + wasm_cluster_del_exec_env_internal(cluster, exec_env, false); + /* Destroy exec_env */ + wasm_exec_env_destroy_internal(exec_env); + /* Routine exit, destroy instance */ + wasm_runtime_deinstantiate_internal(module_inst, true); + + os_mutex_unlock(&cluster->lock); + + os_mutex_unlock(&cluster_list_lock); + + os_thread_exit(retval); +} + +static void +set_thread_cancel_flags(WASMExecEnv *exec_env) +{ + os_mutex_lock(&exec_env->wait_lock); + +#if WASM_ENABLE_DEBUG_INTERP != 0 + wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM); +#endif + exec_env->suspend_flags.flags |= 0x01; + + os_mutex_unlock(&exec_env->wait_lock); +} + +int32 +wasm_cluster_cancel_thread(WASMExecEnv *exec_env) +{ + os_mutex_lock(&cluster_list_lock); + + if (!exec_env->cluster) { + os_mutex_unlock(&cluster_list_lock); + return 0; + } + + if (!clusters_have_exec_env(exec_env)) { + /* Invalid thread or the thread has exited */ + goto final; + } + + set_thread_cancel_flags(exec_env); + +final: + os_mutex_unlock(&cluster_list_lock); + + return 0; +} + +static void +terminate_thread_visitor(void *node, void *user_data) +{ + WASMExecEnv *curr_exec_env = (WASMExecEnv *)node; + WASMExecEnv *exec_env = (WASMExecEnv *)user_data; + + if (curr_exec_env == exec_env) + return; + + wasm_cluster_cancel_thread(curr_exec_env); + wasm_cluster_join_thread(curr_exec_env, NULL); +} + +void +wasm_cluster_terminate_all(WASMCluster *cluster) +{ + os_mutex_lock(&cluster->lock); + cluster->processing = true; + + safe_traverse_exec_env_list(cluster, terminate_thread_visitor, NULL); + + cluster->processing = false; + os_mutex_unlock(&cluster->lock); +} + +void +wasm_cluster_terminate_all_except_self(WASMCluster *cluster, + WASMExecEnv *exec_env) +{ + os_mutex_lock(&cluster->lock); + cluster->processing = true; + + safe_traverse_exec_env_list(cluster, terminate_thread_visitor, + (void *)exec_env); + + cluster->processing = false; + os_mutex_unlock(&cluster->lock); +} + +static void +wait_for_thread_visitor(void *node, void *user_data) +{ + WASMExecEnv *curr_exec_env = (WASMExecEnv *)node; + WASMExecEnv *exec_env = (WASMExecEnv *)user_data; + + if (curr_exec_env == exec_env) + return; + + wasm_cluster_join_thread(curr_exec_env, NULL); +} + +void +wams_cluster_wait_for_all(WASMCluster *cluster) +{ + os_mutex_lock(&cluster->lock); + cluster->processing = true; + + safe_traverse_exec_env_list(cluster, wait_for_thread_visitor, NULL); + + cluster->processing = false; + os_mutex_unlock(&cluster->lock); +} + +void +wasm_cluster_wait_for_all_except_self(WASMCluster *cluster, + WASMExecEnv *exec_env) +{ + os_mutex_lock(&cluster->lock); + cluster->processing = true; + + safe_traverse_exec_env_list(cluster, wait_for_thread_visitor, + (void *)exec_env); + + cluster->processing = false; + os_mutex_unlock(&cluster->lock); +} + +bool +wasm_cluster_register_destroy_callback(void (*callback)(WASMCluster *)) +{ + DestroyCallBackNode *node; + + if (!(node = wasm_runtime_malloc(sizeof(DestroyCallBackNode)))) { + LOG_ERROR("thread manager error: failed to allocate memory"); + return false; + } + node->destroy_cb = callback; + bh_list_insert(destroy_callback_list, node); + return true; +} + +void +wasm_cluster_suspend_thread(WASMExecEnv *exec_env) +{ + /* Set the suspend flag */ + exec_env->suspend_flags.flags |= 0x02; +} + +static void +suspend_thread_visitor(void *node, void *user_data) +{ + WASMExecEnv *curr_exec_env = (WASMExecEnv *)node; + WASMExecEnv *exec_env = (WASMExecEnv *)user_data; + + if (curr_exec_env == exec_env) + return; + + wasm_cluster_suspend_thread(curr_exec_env); +} + +void +wasm_cluster_suspend_all(WASMCluster *cluster) +{ + os_mutex_lock(&cluster->lock); + traverse_list(&cluster->exec_env_list, suspend_thread_visitor, NULL); + os_mutex_unlock(&cluster->lock); +} + +void +wasm_cluster_suspend_all_except_self(WASMCluster *cluster, + WASMExecEnv *exec_env) +{ + os_mutex_lock(&cluster->lock); + traverse_list(&cluster->exec_env_list, suspend_thread_visitor, + (void *)exec_env); + os_mutex_unlock(&cluster->lock); +} + +void +wasm_cluster_resume_thread(WASMExecEnv *exec_env) +{ + exec_env->suspend_flags.flags &= ~0x02; + os_cond_signal(&exec_env->wait_cond); +} + +static void +resume_thread_visitor(void *node, void *user_data) +{ + WASMExecEnv *curr_exec_env = (WASMExecEnv *)node; + + wasm_cluster_resume_thread(curr_exec_env); +} + +void +wasm_cluster_resume_all(WASMCluster *cluster) +{ + os_mutex_lock(&cluster->lock); + traverse_list(&cluster->exec_env_list, resume_thread_visitor, NULL); + os_mutex_unlock(&cluster->lock); +} + +static void +set_exception_visitor(void *node, void *user_data) +{ + WASMExecEnv *curr_exec_env = (WASMExecEnv *)node; + WASMExecEnv *exec_env = (WASMExecEnv *)user_data; + WASMModuleInstanceCommon *module_inst = get_module_inst(exec_env); + WASMModuleInstance *wasm_inst = (WASMModuleInstance *)module_inst; + + if (curr_exec_env != exec_env) { + WASMModuleInstance *curr_wasm_inst = + (WASMModuleInstance *)get_module_inst(curr_exec_env); + + /* Only spread non "wasi proc exit" exception */ +#if WASM_ENABLE_SHARED_MEMORY != 0 + WASMSharedMemNode *shared_mem_node = wasm_module_get_shared_memory( + (WASMModuleCommon *)curr_wasm_inst->module); + if (shared_mem_node) + os_mutex_lock(&shared_mem_node->shared_mem_lock); +#endif + if (!strstr(wasm_inst->cur_exception, "wasi proc exit")) { + bh_memcpy_s(curr_wasm_inst->cur_exception, + sizeof(curr_wasm_inst->cur_exception), + wasm_inst->cur_exception, + sizeof(wasm_inst->cur_exception)); + } +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (shared_mem_node) + os_mutex_unlock(&shared_mem_node->shared_mem_lock); +#endif + + /* Terminate the thread so it can exit from dead loops */ + set_thread_cancel_flags(curr_exec_env); + } +} + +static void +clear_exception_visitor(void *node, void *user_data) +{ + WASMExecEnv *exec_env = (WASMExecEnv *)user_data; + WASMExecEnv *curr_exec_env = (WASMExecEnv *)node; + + if (curr_exec_env != exec_env) { + WASMModuleInstance *curr_wasm_inst = + (WASMModuleInstance *)get_module_inst(curr_exec_env); + +#if WASM_ENABLE_SHARED_MEMORY != 0 + WASMSharedMemNode *shared_mem_node = wasm_module_get_shared_memory( + (WASMModuleCommon *)curr_wasm_inst->module); + if (shared_mem_node) + os_mutex_lock(&shared_mem_node->shared_mem_lock); +#endif + curr_wasm_inst->cur_exception[0] = '\0'; +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (shared_mem_node) + os_mutex_unlock(&shared_mem_node->shared_mem_lock); +#endif + } +} + +void +wasm_cluster_spread_exception(WASMExecEnv *exec_env, bool clear) +{ + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); + + os_mutex_lock(&cluster->lock); + cluster->has_exception = !clear; + traverse_list(&cluster->exec_env_list, + clear ? clear_exception_visitor : set_exception_visitor, + exec_env); + os_mutex_unlock(&cluster->lock); +} + +static void +set_custom_data_visitor(void *node, void *user_data) +{ + WASMExecEnv *curr_exec_env = (WASMExecEnv *)node; + WASMModuleInstanceCommon *module_inst = get_module_inst(curr_exec_env); + + wasm_runtime_set_custom_data_internal(module_inst, user_data); +} + +void +wasm_cluster_spread_custom_data(WASMModuleInstanceCommon *module_inst, + void *custom_data) +{ + WASMExecEnv *exec_env = wasm_clusters_search_exec_env(module_inst); + + if (exec_env == NULL) { + /* Maybe threads have not been started yet. */ + wasm_runtime_set_custom_data_internal(module_inst, custom_data); + } + else { + WASMCluster *cluster; + + cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); + + os_mutex_lock(&cluster->lock); + traverse_list(&cluster->exec_env_list, set_custom_data_visitor, + custom_data); + os_mutex_unlock(&cluster->lock); + } +} + +bool +wasm_cluster_is_thread_terminated(WASMExecEnv *exec_env) +{ + os_mutex_lock(&exec_env->wait_lock); + bool is_thread_terminated = + (exec_env->suspend_flags.flags & 0x01) ? true : false; + os_mutex_unlock(&exec_env->wait_lock); + + return is_thread_terminated; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_manager.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_manager.h new file mode 100644 index 000000000..2060869c2 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_manager.h @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _THREAD_MANAGER_H +#define _THREAD_MANAGER_H + +#include "bh_common.h" +#include "bh_log.h" +#include "wasm_export.h" +#include "../interpreter/wasm.h" +#include "../common/wasm_runtime_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if WASM_ENABLE_DEBUG_INTERP != 0 +typedef struct WASMDebugInstance WASMDebugInstance; +#endif + +struct WASMCluster { + struct WASMCluster *next; + + korp_mutex lock; + bh_list exec_env_list; + +#if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION == 0 + /* The aux stack of a module with shared memory will be + divided into several segments. This array store the + stack top of different segments */ + uint32 *stack_tops; + /* Record which segments are occupied */ + bool *stack_segment_occupied; +#endif + /* Size of every stack segment */ + uint32 stack_size; + /* When has_exception == true, this cluster should refuse any spawn thread + * requests, this flag can be cleared by calling + * wasm_runtime_clear_exception on instances of any threads of this cluster + */ + bool has_exception; + /* When processing is true, this cluster should refuse any spawn thread + * requests. This is a short-lived state, must be cleared immediately once + * the processing finished. + * This is used to avoid dead lock when one thread waiting another thread + * with lock, see wams_cluster_wait_for_all and wasm_cluster_terminate_all + */ + bool processing; +#if WASM_ENABLE_DEBUG_INTERP != 0 + WASMDebugInstance *debug_inst; +#endif +}; + +void +wasm_cluster_set_max_thread_num(uint32 num); + +bool +thread_manager_init(); + +void +thread_manager_destroy(); + +/* Create cluster */ +WASMCluster * +wasm_cluster_create(WASMExecEnv *exec_env); + +/* Destroy cluster */ +void +wasm_cluster_destroy(WASMCluster *cluster); + +/* Get the cluster of the current exec_env */ +WASMCluster * +wasm_exec_env_get_cluster(WASMExecEnv *exec_env); + +/* Forward registered functions to a new thread */ +bool +wasm_cluster_dup_c_api_imports(WASMModuleInstanceCommon *module_inst_dst, + const WASMModuleInstanceCommon *module_inst_src); + +int32 +wasm_cluster_create_thread(WASMExecEnv *exec_env, + wasm_module_inst_t module_inst, bool alloc_aux_stack, + void *(*thread_routine)(void *), void *arg); + +int32 +wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val); + +int32 +wasm_cluster_detach_thread(WASMExecEnv *exec_env); + +int32 +wasm_cluster_cancel_thread(WASMExecEnv *exec_env); + +void +wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval); + +bool +wasm_cluster_register_destroy_callback(void (*callback)(WASMCluster *)); + +void +wasm_cluster_cancel_all_callbacks(); + +void +wasm_cluster_suspend_all(WASMCluster *cluster); + +void +wasm_cluster_suspend_all_except_self(WASMCluster *cluster, + WASMExecEnv *exec_env); + +void +wasm_cluster_suspend_thread(WASMExecEnv *exec_env); + +void +wasm_cluster_resume_thread(WASMExecEnv *exec_env); + +void +wasm_cluster_resume_all(WASMCluster *cluster); + +void +wasm_cluster_terminate_all(WASMCluster *cluster); + +void +wasm_cluster_terminate_all_except_self(WASMCluster *cluster, + WASMExecEnv *exec_env); + +void +wams_cluster_wait_for_all(WASMCluster *cluster); + +void +wasm_cluster_wait_for_all_except_self(WASMCluster *cluster, + WASMExecEnv *exec_env); + +bool +wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env); + +WASMExecEnv * +wasm_clusters_search_exec_env(WASMModuleInstanceCommon *module_inst); + +void +wasm_cluster_spread_exception(WASMExecEnv *exec_env, bool clear); + +WASMExecEnv * +wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env); + +void +wasm_cluster_destroy_spawned_exec_env(WASMExecEnv *exec_env); + +void +wasm_cluster_spread_custom_data(WASMModuleInstanceCommon *module_inst, + void *custom_data); + +bool +wasm_cluster_is_thread_terminated(WASMExecEnv *exec_env); + +#if WASM_ENABLE_DEBUG_INTERP != 0 +#define WAMR_SIG_TRAP (5) +#define WAMR_SIG_STOP (19) +#define WAMR_SIG_TERM (15) +#define WAMR_SIG_SINGSTEP (0x1ff) + +#define STATUS_RUNNING (0) +#define STATUS_STOP (1) +#define STATUS_EXIT (2) +#define STATUS_STEP (3) + +#define IS_WAMR_TERM_SIG(signo) ((signo) == WAMR_SIG_TERM) + +#define IS_WAMR_STOP_SIG(signo) \ + ((signo) == WAMR_SIG_STOP || (signo) == WAMR_SIG_TRAP) + +struct WASMCurrentEnvStatus { + uint64 signal_flag : 32; + uint64 step_count : 16; + uint64 running_status : 16; +}; + +WASMCurrentEnvStatus * +wasm_cluster_create_exenv_status(); + +void +wasm_cluster_destroy_exenv_status(WASMCurrentEnvStatus *status); + +void +wasm_cluster_send_signal_all(WASMCluster *cluster, uint32 signo); + +/* This function must be called with exec_env->wait_lock locked, otherwise we + * may miss the signal from debugger thread, see + * https://github.com/bytecodealliance/wasm-micro-runtime/issues/1860 */ +void +wasm_cluster_thread_waiting_run(WASMExecEnv *exec_env); + +void +wasm_cluster_wait_thread_status(WASMExecEnv *exec_env, uint32 *status); + +void +wasm_cluster_thread_exited(WASMExecEnv *exec_env); + +void +wasm_cluster_thread_continue(WASMExecEnv *exec_env); + +void +wasm_cluster_thread_send_signal(WASMExecEnv *exec_env, uint32 signo); + +void +wasm_cluster_thread_step(WASMExecEnv *exec_env); + +void +wasm_cluster_set_debug_inst(WASMCluster *cluster, WASMDebugInstance *inst); + +#endif /* end of WASM_ENABLE_DEBUG_INTERP != 0 */ + +#ifdef __cplusplus +} +#endif + +#endif /* end of _THREAD_MANAGER_H */ diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_mgr.cmake b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_mgr.cmake new file mode 100644 index 000000000..c37a336b4 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_mgr.cmake @@ -0,0 +1,13 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (THREAD_MGR_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions (-DWASM_ENABLE_THREAD_MGR=1) + +include_directories(${THREAD_MGR_DIR}) + +file (GLOB source_all ${THREAD_MGR_DIR}/*.c) + +set (THREAD_MGR_SOURCE ${source_all}) + diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/README.md b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/README.md new file mode 100644 index 000000000..ac737c281 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/README.md @@ -0,0 +1,96 @@ +# WASI-NN + +## How to use + +Enable WASI-NN in the WAMR by spefiying it in the cmake building configuration as follows, + +``` +set (WAMR_BUILD_WASI_NN 1) +``` + +The definition of the functions provided by WASI-NN is in the header file `core/iwasm/libraries/wasi-nn/wasi_nn.h`. + +By only including this file in your WASM application you will bind WASI-NN into your module. + +## Tests + +To run the tests we assume that the current directory is the root of the repository. + + +### Build the runtime + +Build the runtime image for your execution target type. + +`EXECUTION_TYPE` can be: +* `cpu` +* `nvidia-gpu` +* `vx-delegate` + +``` +EXECUTION_TYPE=cpu +docker build -t wasi-nn-${EXECUTION_TYPE} -f core/iwasm/libraries/wasi-nn/test/Dockerfile.${EXECUTION_TYPE} . +``` + + +### Build wasm app + +``` +docker build -t wasi-nn-compile -f core/iwasm/libraries/wasi-nn/test/Dockerfile.compile . +``` + +``` +docker run -v $PWD/core/iwasm/libraries/wasi-nn:/wasi-nn wasi-nn-compile +``` + + +### Run wasm app + +If all the tests have run properly you will the the following message in the terminal, + +``` +Tests: passed! +``` + +* CPU + +``` +docker run \ + -v $PWD/core/iwasm/libraries/wasi-nn/test:/assets wasi-nn-cpu \ + --dir=/assets \ + --env="TARGET=cpu" \ + /assets/test_tensorflow.wasm +``` + +* (NVIDIA) GPU + +``` +docker run \ + --runtime=nvidia \ + -v $PWD/core/iwasm/libraries/wasi-nn/test:/assets wasi-nn-nvidia-gpu \ + --dir=/assets \ + --env="TARGET=gpu" \ + /assets/test_tensorflow.wasm +``` + +* vx-delegate for NPU (x86 simulater) + +``` +docker run \ + -v $PWD/core/iwasm/libraries/wasi-nn/test:/assets wasi-nn-vx-delegate \ + --dir=/assets \ + --env="TARGET=gpu" \ + /assets/test_tensorflow.wasm +``` + + + +Requirements: +* [NVIDIA docker](https://github.com/NVIDIA/nvidia-docker). + +## What is missing + +Supported: + +* Graph encoding: `tensorflowlite`. +* Execution target: `cpu` and `gpu`. +* Tensor type: `fp32`. diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake new file mode 100644 index 000000000..bbeac3b14 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake @@ -0,0 +1,41 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + + +find_library(TENSORFLOW_LITE + NAMES tensorflow-lite +) + +if(NOT EXISTS ${TENSORFLOW_LITE}) + if (NOT EXISTS "${WAMR_ROOT_DIR}/core/deps/tensorflow-src") + execute_process(COMMAND ${WAMR_ROOT_DIR}/core/deps/install_tensorflow.sh + RESULT_VARIABLE TENSORFLOW_RESULT + ) + else () + message("Tensorflow is already downloaded.") + endif() + set(TENSORFLOW_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/tensorflow-src") + + if (WASI_NN_ENABLE_GPU EQUAL 1) + # Tensorflow specific: + # * https://www.tensorflow.org/lite/guide/build_cmake#available_options_to_build_tensorflow_lite + set (TFLITE_ENABLE_GPU ON) + endif () + + include_directories (${CMAKE_CURRENT_BINARY_DIR}/flatbuffers/include) + include_directories (${TENSORFLOW_SOURCE_DIR}) + add_subdirectory( + "${TENSORFLOW_SOURCE_DIR}/tensorflow/lite" + "${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite" EXCLUDE_FROM_ALL) + +else() + find_path(TENSORFLOW_LITE_INCLUDE_DIR + NAMES tensorflow/lite/interpreter.h + ) + find_path(FLATBUFFER_INCLUDE_DIR + NAMES flatbuffers/flatbuffers.h + ) + include_directories (${TENSORFLOW_LITE_INCLUDE_DIR}) + include_directories (${FLATBUFFER_INCLUDE_DIR}) +endif() + diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/logger.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/logger.h new file mode 100644 index 000000000..a196429a0 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/logger.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_LOGGER_H +#define WASI_NN_LOGGER_H + +#include <stdio.h> +#include <string.h> + +#define __FILENAME__ \ + (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) + +/* Disable a level by removing the define */ +#ifndef NN_LOG_LEVEL +/* + 0 -> debug, info, warn, err + 1 -> info, warn, err + 2 -> warn, err + 3 -> err + 4 -> NO LOGS +*/ +#define NN_LOG_LEVEL 0 +#endif + +// Definition of the levels +#if NN_LOG_LEVEL <= 3 +#define NN_ERR_PRINTF(fmt, ...) \ + do { \ + printf("[%s:%d ERROR] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define NN_ERR_PRINTF(fmt, ...) +#endif +#if NN_LOG_LEVEL <= 2 +#define NN_WARN_PRINTF(fmt, ...) \ + do { \ + printf("[%s:%d WARNING] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define NN_WARN_PRINTF(fmt, ...) +#endif +#if NN_LOG_LEVEL <= 1 +#define NN_INFO_PRINTF(fmt, ...) \ + do { \ + printf("[%s:%d INFO] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define NN_INFO_PRINTF(fmt, ...) +#endif +#if NN_LOG_LEVEL <= 0 +#define NN_DBG_PRINTF(fmt, ...) \ + do { \ + printf("[%s:%d DEBUG] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define NN_DBG_PRINTF(fmt, ...) +#endif + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.c new file mode 100644 index 000000000..fe04b657b --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasi_nn_app_native.h" + +static error +graph_builder_app_native(wasm_module_inst_t instance, + graph_builder_wasm *builder_wasm, + graph_builder *builder) +{ + if (!wasm_runtime_validate_app_addr(instance, builder_wasm->buf_offset, + builder_wasm->size * sizeof(uint8_t))) { + NN_ERR_PRINTF("builder_wasm->buf_offset is invalid"); + return invalid_argument; + } + + builder->buf = (uint8_t *)wasm_runtime_addr_app_to_native( + instance, builder_wasm->buf_offset); + builder->size = builder_wasm->size; + return success; +} + +error +graph_builder_array_app_native(wasm_module_inst_t instance, + graph_builder_array_wasm *builder_array_wasm, + graph_builder_array *builder_array) +{ + if (!wasm_runtime_validate_native_addr(instance, builder_array_wasm, + sizeof(graph_builder_array_wasm))) { + NN_ERR_PRINTF("builder_array_wasm is invalid"); + return invalid_argument; + } + + NN_DBG_PRINTF("Graph builder array contains %d elements", + builder_array_wasm->size); + + if (!wasm_runtime_validate_app_addr( + instance, builder_array_wasm->buf_offset, + builder_array_wasm->size * sizeof(graph_builder_wasm))) { + NN_ERR_PRINTF("builder_array_wasm->buf_offset is invalid"); + return invalid_argument; + } + + graph_builder_wasm *builder_wasm = + (graph_builder_wasm *)wasm_runtime_addr_app_to_native( + instance, builder_array_wasm->buf_offset); + + graph_builder *builder = (graph_builder *)wasm_runtime_malloc( + builder_array_wasm->size * sizeof(graph_builder)); + if (builder == NULL) + return missing_memory; + + for (uint32_t i = 0; i < builder_array_wasm->size; ++i) { + error res; + if (success + != (res = graph_builder_app_native(instance, &builder_wasm[i], + &builder[i]))) { + wasm_runtime_free(builder); + return res; + } + + NN_DBG_PRINTF("Graph builder %d contains %d elements", i, + builder->size); + } + + builder_array->buf = builder; + builder_array->size = builder_array_wasm->size; + return success; +} + +static error +tensor_data_app_native(wasm_module_inst_t instance, uint32_t total_elements, + tensor_wasm *input_tensor_wasm, tensor_data *data) +{ + if (!wasm_runtime_validate_app_addr( + instance, input_tensor_wasm->data_offset, total_elements)) { + NN_ERR_PRINTF("input_tensor_wasm->data_offset is invalid"); + return invalid_argument; + } + *data = (tensor_data)wasm_runtime_addr_app_to_native( + instance, input_tensor_wasm->data_offset); + return success; +} + +static error +tensor_dimensions_app_native(wasm_module_inst_t instance, + tensor_wasm *input_tensor_wasm, + tensor_dimensions **dimensions) +{ + if (!wasm_runtime_validate_app_addr(instance, + input_tensor_wasm->dimensions_offset, + sizeof(tensor_dimensions_wasm))) { + NN_ERR_PRINTF("input_tensor_wasm->dimensions_offset is invalid"); + return invalid_argument; + } + + tensor_dimensions_wasm *dimensions_wasm = + (tensor_dimensions_wasm *)wasm_runtime_addr_app_to_native( + instance, input_tensor_wasm->dimensions_offset); + + if (!wasm_runtime_validate_app_addr(instance, dimensions_wasm->buf_offset, + sizeof(tensor_dimensions))) { + NN_ERR_PRINTF("dimensions_wasm->buf_offset is invalid"); + return invalid_argument; + } + + *dimensions = + (tensor_dimensions *)wasm_runtime_malloc(sizeof(tensor_dimensions)); + if (dimensions == NULL) + return missing_memory; + + (*dimensions)->size = dimensions_wasm->size; + (*dimensions)->buf = (uint32_t *)wasm_runtime_addr_app_to_native( + instance, dimensions_wasm->buf_offset); + + NN_DBG_PRINTF("Number of dimensions: %d", (*dimensions)->size); + return success; +} + +error +tensor_app_native(wasm_module_inst_t instance, tensor_wasm *input_tensor_wasm, + tensor *input_tensor) +{ + NN_DBG_PRINTF("Converting tensor_wasm to tensor"); + if (!wasm_runtime_validate_native_addr(instance, input_tensor_wasm, + sizeof(tensor_wasm))) { + NN_ERR_PRINTF("input_tensor_wasm is invalid"); + return invalid_argument; + } + + error res; + + tensor_dimensions *dimensions = NULL; + if (success + != (res = tensor_dimensions_app_native(instance, input_tensor_wasm, + &dimensions))) { + NN_ERR_PRINTF("error when parsing dimensions"); + return res; + } + + uint32_t total_elements = 1; + for (uint32_t i = 0; i < dimensions->size; ++i) { + total_elements *= dimensions->buf[i]; + NN_DBG_PRINTF("Dimension %d: %d", i, dimensions->buf[i]); + } + NN_DBG_PRINTF("Tensor type: %d", input_tensor_wasm->type); + NN_DBG_PRINTF("Total number of elements: %d", total_elements); + + tensor_data data = NULL; + if (success + != (res = tensor_data_app_native(instance, total_elements, + input_tensor_wasm, &data))) { + wasm_runtime_free(dimensions); + return res; + } + + input_tensor->type = input_tensor_wasm->type; + input_tensor->dimensions = dimensions; + input_tensor->data = data; + return success; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.h new file mode 100644 index 000000000..15154bd31 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_APP_NATIVE +#define WASI_NN_APP_NATIVE + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <errno.h> +#include <string.h> + +#include "wasi_nn.h" +#include "logger.h" + +#include "bh_platform.h" +#include "wasm_export.h" + +typedef struct { + uint32_t buf_offset; + uint32_t size; +} graph_builder_wasm; + +typedef struct { + uint32_t buf_offset; + uint32_t size; +} graph_builder_array_wasm; + +typedef struct { + uint32_t buf_offset; + uint32_t size; +} tensor_dimensions_wasm; + +typedef struct { + uint32_t dimensions_offset; + tensor_type type; + uint32_t data_offset; +} tensor_wasm; + +error +graph_builder_array_app_native(wasm_module_inst_t instance, + graph_builder_array_wasm *builder, + graph_builder_array *builder_native); + +error +tensor_app_native(wasm_module_inst_t instance, tensor_wasm *input_tensor, + tensor *input_tensor_native); + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn.c new file mode 100644 index 000000000..466630f99 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn.c @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <assert.h> +#include <errno.h> +#include <string.h> + +#include "wasi_nn.h" +#include "wasi_nn_app_native.h" +#include "logger.h" +#include "wasi_nn_tensorflowlite.hpp" + +#include "bh_platform.h" +#include "wasm_export.h" +#include "wasm_runtime.h" +#include "aot_runtime.h" + +/* Definition of 'wasi_nn.h' structs in WASM app format (using offset) */ + +typedef error (*LOAD)(void *, graph_builder_array *, graph_encoding, + execution_target, graph *); +typedef error (*INIT_EXECUTION_CONTEXT)(void *, graph, + graph_execution_context *); +typedef error (*SET_INPUT)(void *, graph_execution_context, uint32_t, tensor *); +typedef error (*COMPUTE)(void *, graph_execution_context); +typedef error (*GET_OUTPUT)(void *, graph_execution_context, uint32_t, + tensor_data, uint32_t *); + +typedef struct { + LOAD load; + INIT_EXECUTION_CONTEXT init_execution_context; + SET_INPUT set_input; + COMPUTE compute; + GET_OUTPUT get_output; +} api_function; + +/* Global variables */ + +static api_function lookup[] = { + { NULL, NULL, NULL, NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL }, + { tensorflowlite_load, tensorflowlite_init_execution_context, + tensorflowlite_set_input, tensorflowlite_compute, + tensorflowlite_get_output } +}; + +/* Utils */ + +static bool +is_encoding_implemented(graph_encoding encoding) +{ + return lookup[encoding].load && lookup[encoding].init_execution_context + && lookup[encoding].set_input && lookup[encoding].compute + && lookup[encoding].get_output; +} + +static error +is_model_initialized(WASINNContext *wasi_nn_ctx) +{ + if (!wasi_nn_ctx->is_initialized) { + NN_ERR_PRINTF("Model not initialized."); + return runtime_error; + } + return success; +} + +WASINNContext * +wasm_runtime_get_wasi_nn_ctx(wasm_module_inst_t instance) +{ + WASINNContext *wasi_nn_ctx = NULL; +#if WASM_ENABLE_INTERP != 0 + if (instance->module_type == Wasm_Module_Bytecode) { + NN_DBG_PRINTF("Getting ctx from WASM"); + WASMModuleInstance *module_inst = (WASMModuleInstance *)instance; + wasi_nn_ctx = ((WASMModuleInstanceExtra *)module_inst->e)->wasi_nn_ctx; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (instance->module_type == Wasm_Module_AoT) { + NN_DBG_PRINTF("Getting ctx from AOT"); + AOTModuleInstance *module_inst = (AOTModuleInstance *)instance; + wasi_nn_ctx = ((AOTModuleInstanceExtra *)module_inst->e)->wasi_nn_ctx; + } +#endif + bh_assert(wasi_nn_ctx != NULL); + NN_DBG_PRINTF("Returning ctx"); + return wasi_nn_ctx; +} + +/* WASI-NN implementation */ + +error +wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_array_wasm *builder, + graph_encoding encoding, execution_target target, graph *g) +{ + NN_DBG_PRINTF("Running wasi_nn_load [encoding=%d, target=%d]...", encoding, + target); + + if (!is_encoding_implemented(encoding)) { + NN_ERR_PRINTF("Encoding not supported."); + return invalid_encoding; + } + + wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); + bh_assert(instance); + + error res; + graph_builder_array builder_native = { 0 }; + if (success + != (res = graph_builder_array_app_native(instance, builder, + &builder_native))) + return res; + + if (!wasm_runtime_validate_native_addr(instance, g, sizeof(graph))) { + NN_ERR_PRINTF("graph is invalid"); + res = invalid_argument; + goto fail; + } + + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); + res = lookup[encoding].load(wasi_nn_ctx->tflite_ctx, &builder_native, + encoding, target, g); + + NN_DBG_PRINTF("wasi_nn_load finished with status %d [graph=%d]", res, *g); + + wasi_nn_ctx->current_encoding = encoding; + wasi_nn_ctx->is_initialized = true; + +fail: + // XXX: Free intermediate structure pointers + if (builder_native.buf) + wasm_runtime_free(builder_native.buf); + + return res; +} + +error +wasi_nn_init_execution_context(wasm_exec_env_t exec_env, graph g, + graph_execution_context *ctx) +{ + NN_DBG_PRINTF("Running wasi_nn_init_execution_context [graph=%d]...", g); + + wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); + bh_assert(instance); + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); + + error res; + if (success != (res = is_model_initialized(wasi_nn_ctx))) + return res; + + if (!wasm_runtime_validate_native_addr(instance, ctx, + sizeof(graph_execution_context))) { + NN_ERR_PRINTF("ctx is invalid"); + return invalid_argument; + } + + res = lookup[wasi_nn_ctx->current_encoding].init_execution_context( + wasi_nn_ctx->tflite_ctx, g, ctx); + + NN_DBG_PRINTF( + "wasi_nn_init_execution_context finished with status %d [ctx=%d]", res, + *ctx); + return res; +} + +error +wasi_nn_set_input(wasm_exec_env_t exec_env, graph_execution_context ctx, + uint32_t index, tensor_wasm *input_tensor) +{ + NN_DBG_PRINTF("Running wasi_nn_set_input [ctx=%d, index=%d]...", ctx, + index); + + wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); + bh_assert(instance); + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); + + error res; + if (success != (res = is_model_initialized(wasi_nn_ctx))) + return res; + + tensor input_tensor_native = { 0 }; + if (success + != (res = tensor_app_native(instance, input_tensor, + &input_tensor_native))) + return res; + + res = lookup[wasi_nn_ctx->current_encoding].set_input( + wasi_nn_ctx->tflite_ctx, ctx, index, &input_tensor_native); + + // XXX: Free intermediate structure pointers + if (input_tensor_native.dimensions) + wasm_runtime_free(input_tensor_native.dimensions); + + NN_DBG_PRINTF("wasi_nn_set_input finished with status %d", res); + return res; +} + +error +wasi_nn_compute(wasm_exec_env_t exec_env, graph_execution_context ctx) +{ + NN_DBG_PRINTF("Running wasi_nn_compute [ctx=%d]...", ctx); + + wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); + bh_assert(instance); + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); + + error res; + if (success != (res = is_model_initialized(wasi_nn_ctx))) + return res; + + res = lookup[wasi_nn_ctx->current_encoding].compute(wasi_nn_ctx->tflite_ctx, + ctx); + NN_DBG_PRINTF("wasi_nn_compute finished with status %d", res); + return res; +} + +error +wasi_nn_get_output(wasm_exec_env_t exec_env, graph_execution_context ctx, + uint32_t index, tensor_data output_tensor, + uint32_t *output_tensor_size) +{ + NN_DBG_PRINTF("Running wasi_nn_get_output [ctx=%d, index=%d]...", ctx, + index); + + wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); + bh_assert(instance); + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); + + error res; + if (success != (res = is_model_initialized(wasi_nn_ctx))) + return res; + + if (!wasm_runtime_validate_native_addr(instance, output_tensor_size, + sizeof(uint32_t))) { + NN_ERR_PRINTF("output_tensor_size is invalid"); + return invalid_argument; + } + + res = lookup[wasi_nn_ctx->current_encoding].get_output( + wasi_nn_ctx->tflite_ctx, ctx, index, output_tensor, output_tensor_size); + NN_DBG_PRINTF("wasi_nn_get_output finished with status %d [data_size=%d]", + res, *output_tensor_size); + return res; +} + +/* Non-exposed public functions */ + +WASINNContext * +wasi_nn_initialize() +{ + NN_DBG_PRINTF("Initializing wasi-nn"); + WASINNContext *wasi_nn_ctx = + (WASINNContext *)wasm_runtime_malloc(sizeof(WASINNContext)); + if (wasi_nn_ctx == NULL) { + NN_ERR_PRINTF("Error when allocating memory for WASI-NN context"); + return NULL; + } + wasi_nn_ctx->is_initialized = true; + wasi_nn_ctx->current_encoding = 3; + tensorflowlite_initialize(&wasi_nn_ctx->tflite_ctx); + return wasi_nn_ctx; +} + +void +wasi_nn_destroy(WASINNContext *wasi_nn_ctx) +{ + if (wasi_nn_ctx == NULL) { + NN_ERR_PRINTF( + "Error when deallocating memory. WASI-NN context is NULL"); + return; + } + NN_DBG_PRINTF("Freeing wasi-nn"); + NN_DBG_PRINTF("-> is_initialized: %d", wasi_nn_ctx->is_initialized); + NN_DBG_PRINTF("-> current_encoding: %d", wasi_nn_ctx->current_encoding); + tensorflowlite_destroy(wasi_nn_ctx->tflite_ctx); + wasm_runtime_free(wasi_nn_ctx); +} + +/* Register WASI-NN in WAMR */ + +/* clang-format off */ +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, wasi_nn_##func_name, signature, NULL } +/* clang-format on */ + +static NativeSymbol native_symbols_wasi_nn[] = { + REG_NATIVE_FUNC(load, "(*ii*)i"), + REG_NATIVE_FUNC(init_execution_context, "(i*)i"), + REG_NATIVE_FUNC(set_input, "(ii*)i"), + REG_NATIVE_FUNC(compute, "(i)i"), + REG_NATIVE_FUNC(get_output, "(ii**)i"), +}; + +uint32_t +get_wasi_nn_export_apis(NativeSymbol **p_libc_wasi_apis) +{ + *p_libc_wasi_apis = native_symbols_wasi_nn; + return sizeof(native_symbols_wasi_nn) / sizeof(NativeSymbol); +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_private.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_private.h new file mode 100644 index 000000000..52d16bd1d --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_private.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_PRIVATE_H +#define WASI_NN_PRIVATE_H + +#include "wasi_nn_types.h" + +typedef struct { + bool is_initialized; + graph_encoding current_encoding; + void *tflite_ctx; +} WASINNContext; + +/** + * @brief Initialize wasi-nn + * + */ +WASINNContext * +wasi_nn_initialize(); +/** + * @brief Destroy wasi-nn on app exists + * + */ + +void +wasi_nn_destroy(WASINNContext *wasi_nn_ctx); + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp new file mode 100644 index 000000000..dfd21787c --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasi_nn.h" +#include "wasi_nn_tensorflowlite.hpp" +#include "logger.h" + +#include "bh_common.h" +#include "bh_platform.h" +#include "platform_common.h" + +#include <tensorflow/lite/interpreter.h> +#include <tensorflow/lite/kernels/register.h> +#include <tensorflow/lite/model.h> +#include <tensorflow/lite/optional_debug_tools.h> +#include <tensorflow/lite/error_reporter.h> + +#if defined(WASI_NN_ENABLE_GPU) +#include <tensorflow/lite/delegates/gpu/delegate.h> +#endif + +#if defined(WASI_NN_ENABLE_EXTERNAL_DELEGATE) +#include <tensorflow/lite/delegates/external/external_delegate.h> +#endif + +/* Maximum number of graphs per WASM instance */ +#define MAX_GRAPHS_PER_INST 10 +/* Maximum number of graph execution context per WASM instance*/ +#define MAX_GRAPH_EXEC_CONTEXTS_PER_INST 10 + +typedef struct { + std::unique_ptr<tflite::Interpreter> interpreter; +} Interpreter; + +typedef struct { + char *model_pointer; + std::unique_ptr<tflite::FlatBufferModel> model; + execution_target target; +} Model; + +typedef struct { + uint32_t current_models; + Model models[MAX_GRAPHS_PER_INST]; + uint32_t current_interpreters; + Interpreter interpreters[MAX_GRAPH_EXEC_CONTEXTS_PER_INST]; + korp_mutex g_lock; + TfLiteDelegate *delegate; +} TFLiteContext; + +/* Utils */ + +static error +initialize_g(TFLiteContext *tfl_ctx, graph *g) +{ + os_mutex_lock(&tfl_ctx->g_lock); + if (tfl_ctx->current_models == MAX_GRAPHS_PER_INST) { + os_mutex_unlock(&tfl_ctx->g_lock); + NN_ERR_PRINTF("Excedded max graphs per WASM instance"); + return runtime_error; + } + *g = tfl_ctx->current_models++; + os_mutex_unlock(&tfl_ctx->g_lock); + return success; +} +static error +initialize_graph_ctx(TFLiteContext *tfl_ctx, graph g, + graph_execution_context *ctx) +{ + os_mutex_lock(&tfl_ctx->g_lock); + if (tfl_ctx->current_interpreters == MAX_GRAPH_EXEC_CONTEXTS_PER_INST) { + os_mutex_unlock(&tfl_ctx->g_lock); + NN_ERR_PRINTF("Excedded max graph execution context per WASM instance"); + return runtime_error; + } + *ctx = tfl_ctx->current_interpreters++; + os_mutex_unlock(&tfl_ctx->g_lock); + return success; +} + +static error +is_valid_graph(TFLiteContext *tfl_ctx, graph g) +{ + if (g >= MAX_GRAPHS_PER_INST) { + NN_ERR_PRINTF("Invalid graph: %d >= %d.", g, MAX_GRAPHS_PER_INST); + return runtime_error; + } + if (tfl_ctx->models[g].model_pointer == NULL) { + NN_ERR_PRINTF("Context (model) non-initialized."); + return runtime_error; + } + if (tfl_ctx->models[g].model == NULL) { + NN_ERR_PRINTF("Context (tflite model) non-initialized."); + return runtime_error; + } + return success; +} + +static error +is_valid_graph_execution_context(TFLiteContext *tfl_ctx, + graph_execution_context ctx) +{ + if (ctx >= MAX_GRAPH_EXEC_CONTEXTS_PER_INST) { + NN_ERR_PRINTF("Invalid graph execution context: %d >= %d", ctx, + MAX_GRAPH_EXEC_CONTEXTS_PER_INST); + return runtime_error; + } + if (tfl_ctx->interpreters[ctx].interpreter == NULL) { + NN_ERR_PRINTF("Context (interpreter) non-initialized."); + return runtime_error; + } + return success; +} + +/* WASI-NN (tensorflow) implementation */ + +error +tensorflowlite_load(void *tflite_ctx, graph_builder_array *builder, + graph_encoding encoding, execution_target target, graph *g) +{ + TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; + + if (builder->size != 1) { + NN_ERR_PRINTF("Unexpected builder format."); + return invalid_argument; + } + + if (encoding != tensorflowlite) { + NN_ERR_PRINTF("Encoding is not tensorflowlite."); + return invalid_argument; + } + + if (target != cpu && target != gpu) { + NN_ERR_PRINTF("Only CPU and GPU target is supported."); + return invalid_argument; + } + + error res; + if (success != (res = initialize_g(tfl_ctx, g))) + return res; + + uint32_t size = builder->buf[0].size; + + // Save model + tfl_ctx->models[*g].model_pointer = (char *)wasm_runtime_malloc(size); + if (tfl_ctx->models[*g].model_pointer == NULL) { + NN_ERR_PRINTF("Error when allocating memory for model."); + return missing_memory; + } + + bh_memcpy_s(tfl_ctx->models[*g].model_pointer, size, builder->buf[0].buf, + size); + + // Save model flatbuffer + tfl_ctx->models[*g].model = + std::move(tflite::FlatBufferModel::BuildFromBuffer( + tfl_ctx->models[*g].model_pointer, size, NULL)); + + if (tfl_ctx->models[*g].model == NULL) { + NN_ERR_PRINTF("Loading model error."); + wasm_runtime_free(tfl_ctx->models[*g].model_pointer); + tfl_ctx->models[*g].model_pointer = NULL; + return missing_memory; + } + + // Save target + tfl_ctx->models[*g].target = target; + return success; +} + +error +tensorflowlite_init_execution_context(void *tflite_ctx, graph g, + graph_execution_context *ctx) +{ + TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; + + error res; + if (success != (res = is_valid_graph(tfl_ctx, g))) + return res; + + if (success != (res = initialize_graph_ctx(tfl_ctx, g, ctx))) + return res; + + // Build the interpreter with the InterpreterBuilder. + tflite::ops::builtin::BuiltinOpResolver resolver; + tflite::InterpreterBuilder tflite_builder(*tfl_ctx->models[g].model, + resolver); + tflite_builder(&tfl_ctx->interpreters[*ctx].interpreter); + if (tfl_ctx->interpreters[*ctx].interpreter == NULL) { + NN_ERR_PRINTF("Error when generating the interpreter."); + return missing_memory; + } + + bool use_default = false; + switch (tfl_ctx->models[g].target) { + case gpu: + { +#if defined(WASI_NN_ENABLE_GPU) + NN_WARN_PRINTF("GPU enabled."); + // https://www.tensorflow.org/lite/performance/gpu + TfLiteGpuDelegateOptionsV2 options = + TfLiteGpuDelegateOptionsV2Default(); + options.inference_preference = + TFLITE_GPU_INFERENCE_PREFERENCE_SUSTAINED_SPEED; + options.inference_priority1 = + TFLITE_GPU_INFERENCE_PRIORITY_MIN_LATENCY; + tfl_ctx->delegate = TfLiteGpuDelegateV2Create(&options); + if (tfl_ctx->delegate == NULL) { + NN_ERR_PRINTF("Error when generating GPU delegate."); + use_default = true; + return missing_memory; + } + if (tfl_ctx->interpreters[*ctx] + .interpreter->ModifyGraphWithDelegate(tfl_ctx->delegate) + != kTfLiteOk) { + NN_ERR_PRINTF("Error when enabling GPU delegate."); + use_default = true; + } +#elif defined(WASI_NN_ENABLE_EXTERNAL_DELEGATE) + NN_WARN_PRINTF("external delegation enabled."); + TfLiteExternalDelegateOptions options = + TfLiteExternalDelegateOptionsDefault(WASI_NN_EXT_DELEGATE_PATH); + tfl_ctx->delegate = TfLiteExternalDelegateCreate(&options); + if (tfl_ctx->delegate == NULL) { + NN_ERR_PRINTF("Error when generating External delegate."); + use_default = true; + return missing_memory; + } + if (tfl_ctx->interpreters[*ctx] + .interpreter->ModifyGraphWithDelegate(tfl_ctx->delegate) + != kTfLiteOk) { + NN_ERR_PRINTF("Error when enabling External delegate."); + use_default = true; + } +#else + NN_WARN_PRINTF("GPU not enabled."); + use_default = true; +#endif + break; + } + default: + use_default = true; + } + if (use_default) + NN_WARN_PRINTF("Default encoding is CPU."); + + tfl_ctx->interpreters[*ctx].interpreter->AllocateTensors(); + return success; +} + +error +tensorflowlite_set_input(void *tflite_ctx, graph_execution_context ctx, + uint32_t index, tensor *input_tensor) +{ + TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; + + error res; + if (success != (res = is_valid_graph_execution_context(tfl_ctx, ctx))) + return res; + + uint32_t num_tensors = + tfl_ctx->interpreters[ctx].interpreter->inputs().size(); + NN_DBG_PRINTF("Number of tensors (%d)", num_tensors); + if (index + 1 > num_tensors) { + return runtime_error; + } + + auto tensor = tfl_ctx->interpreters[ctx].interpreter->input_tensor(index); + if (tensor == NULL) { + NN_ERR_PRINTF("Missing memory"); + return missing_memory; + } + + uint32_t model_tensor_size = 1; + for (int i = 0; i < tensor->dims->size; ++i) + model_tensor_size *= (uint32_t)tensor->dims->data[i]; + + uint32_t input_tensor_size = 1; + for (uint32_t i = 0; i < input_tensor->dimensions->size; i++) + input_tensor_size *= (uint32_t)input_tensor->dimensions->buf[i]; + + if (model_tensor_size != input_tensor_size) { + NN_ERR_PRINTF("Input tensor shape from the model is different than the " + "one provided"); + return invalid_argument; + } + + auto *input = + tfl_ctx->interpreters[ctx].interpreter->typed_input_tensor<float>( + index); + if (input == NULL) + return missing_memory; + + bh_memcpy_s(input, model_tensor_size * sizeof(float), input_tensor->data, + model_tensor_size * sizeof(float)); + return success; +} + +error +tensorflowlite_compute(void *tflite_ctx, graph_execution_context ctx) +{ + TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; + + error res; + if (success != (res = is_valid_graph_execution_context(tfl_ctx, ctx))) + return res; + + tfl_ctx->interpreters[ctx].interpreter->Invoke(); + return success; +} + +error +tensorflowlite_get_output(void *tflite_ctx, graph_execution_context ctx, + uint32_t index, tensor_data output_tensor, + uint32_t *output_tensor_size) +{ + TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; + + error res; + if (success != (res = is_valid_graph_execution_context(tfl_ctx, ctx))) + return res; + + uint32_t num_output_tensors = + tfl_ctx->interpreters[ctx].interpreter->outputs().size(); + NN_DBG_PRINTF("Number of tensors (%d)", num_output_tensors); + + if (index + 1 > num_output_tensors) { + return runtime_error; + } + + auto tensor = tfl_ctx->interpreters[ctx].interpreter->output_tensor(index); + if (tensor == NULL) { + NN_ERR_PRINTF("Missing memory"); + return missing_memory; + } + + uint32_t model_tensor_size = 1; + for (int i = 0; i < (int)tensor->dims->size; ++i) + model_tensor_size *= (uint32_t)tensor->dims->data[i]; + + if (*output_tensor_size < model_tensor_size) { + NN_ERR_PRINTF("Insufficient memory to copy tensor %d", index); + return missing_memory; + } + + float *tensor_f = + tfl_ctx->interpreters[ctx].interpreter->typed_output_tensor<float>( + index); + for (uint32_t i = 0; i < model_tensor_size; ++i) + NN_DBG_PRINTF("output: %f", tensor_f[i]); + + *output_tensor_size = model_tensor_size; + bh_memcpy_s(output_tensor, model_tensor_size * sizeof(float), tensor_f, + model_tensor_size * sizeof(float)); + return success; +} + +void +tensorflowlite_initialize(void **tflite_ctx) +{ + TFLiteContext *tfl_ctx = new TFLiteContext(); + if (tfl_ctx == NULL) { + NN_ERR_PRINTF("Error when allocating memory for tensorflowlite."); + return; + } + + NN_DBG_PRINTF("Initializing models."); + tfl_ctx->current_models = 0; + for (int i = 0; i < MAX_GRAPHS_PER_INST; ++i) { + tfl_ctx->models[i].model_pointer = NULL; + } + NN_DBG_PRINTF("Initializing interpreters."); + tfl_ctx->current_interpreters = 0; + + if (os_mutex_init(&tfl_ctx->g_lock) != 0) { + NN_ERR_PRINTF("Error while initializing the lock"); + } + + tfl_ctx->delegate = NULL; + + *tflite_ctx = (void *)tfl_ctx; +} + +void +tensorflowlite_destroy(void *tflite_ctx) +{ + /* + TensorFlow Lite memory is internally managed by tensorflow + + Related issues: + * https://github.com/tensorflow/tensorflow/issues/15880 + */ + TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; + + if (tfl_ctx->delegate != NULL) { +#if defined(WASI_NN_ENABLE_GPU) + TfLiteGpuDelegateV2Delete(tfl_ctx->delegate); +#elif defined(WASI_NN_ENABLE_EXTERNAL_DELEGATE) + TfLiteExternalDelegateDelete(tfl_ctx->delegate); +#endif + } + + NN_DBG_PRINTF("Freeing memory."); + for (int i = 0; i < MAX_GRAPHS_PER_INST; ++i) { + tfl_ctx->models[i].model.reset(); + if (tfl_ctx->models[i].model_pointer) + wasm_runtime_free(tfl_ctx->models[i].model_pointer); + tfl_ctx->models[i].model_pointer = NULL; + } + for (int i = 0; i < MAX_GRAPH_EXEC_CONTEXTS_PER_INST; ++i) { + tfl_ctx->interpreters[i].interpreter.reset(); + } + os_mutex_destroy(&tfl_ctx->g_lock); + delete tfl_ctx; + NN_DBG_PRINTF("Memory free'd."); +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp new file mode 100644 index 000000000..9605420dd --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_TENSORFLOWLITE_HPP +#define WASI_NN_TENSORFLOWLITE_HPP + +#include "wasi_nn.h" + +#ifdef __cplusplus +extern "C" { +#endif + +error +tensorflowlite_load(void *tflite_ctx, graph_builder_array *builder, + graph_encoding encoding, execution_target target, graph *g); + +error +tensorflowlite_init_execution_context(void *tflite_ctx, graph g, + graph_execution_context *ctx); + +error +tensorflowlite_set_input(void *tflite_ctx, graph_execution_context ctx, + uint32_t index, tensor *input_tensor); + +error +tensorflowlite_compute(void *tflite_ctx, graph_execution_context ctx); + +error +tensorflowlite_get_output(void *tflite_ctx, graph_execution_context ctx, + uint32_t index, tensor_data output_tensor, + uint32_t *output_tensor_size); + +void +tensorflowlite_initialize(void **tflite_ctx); + +void +tensorflowlite_destroy(void *tflite_ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/CMakeLists.txt b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/CMakeLists.txt new file mode 100644 index 000000000..33fad71eb --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/CMakeLists.txt @@ -0,0 +1,173 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 2.9) + +project (iwasm) + +set (CMAKE_VERBOSE_MAKEFILE OFF) +# Reset default linker flags +set (CMAKE_C_STANDARD 99) +set (CMAKE_CXX_STANDARD 14) +set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +if (NOT DEFINED WAMR_BUILD_PLATFORM) + set (WAMR_BUILD_PLATFORM "linux") +endif () + +# Set WAMR_BUILD_TARGET, currently values supported: +# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", +# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" +if (NOT DEFINED WAMR_BUILD_TARGET) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") + set (WAMR_BUILD_TARGET "AARCH64") + elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + set (WAMR_BUILD_TARGET "RISCV64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) + # Build as X86_64 by default in 64-bit platform + set (WAMR_BUILD_TARGET "X86_64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 4) + # Build as X86_32 by default in 32-bit platform + set (WAMR_BUILD_TARGET "X86_32") + else () + message(SEND_ERROR "Unsupported build target platform!") + endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif () + +if (NOT DEFINED WAMR_BUILD_INTERP) + # Enable Interpreter by default + set (WAMR_BUILD_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_AOT) + # Enable AOT by default. + set (WAMR_BUILD_AOT 1) +endif () + +if (NOT DEFINED WAMR_BUILD_JIT) + # Disable JIT by default. + set (WAMR_BUILD_JIT 0) +endif () + +if (NOT DEFINED WAMR_BUILD_FAST_JIT) + # Disable Fast JIT by default + set (WAMR_BUILD_FAST_JIT 0) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) + # Enable libc builtin support by default + set (WAMR_BUILD_LIBC_BUILTIN 1) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_WASI) + # Enable libc wasi support by default + set (WAMR_BUILD_LIBC_WASI 1) +endif () + +if (NOT DEFINED WAMR_BUILD_FAST_INTERP) + # Enable fast interpreter + set (WAMR_BUILD_FAST_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_MULTI_MODULE) + # Disable multiple modules by default + set (WAMR_BUILD_MULTI_MODULE 0) +endif () + +if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD) + # Disable pthread library by default + set (WAMR_BUILD_LIB_PTHREAD 0) +endif () + +if (NOT DEFINED WAMR_BUILD_MINI_LOADER) + # Disable wasm mini loader by default + set (WAMR_BUILD_MINI_LOADER 0) +endif () + +if (NOT DEFINED WAMR_BUILD_SIMD) + # Enable SIMD by default + set (WAMR_BUILD_SIMD 1) +endif () + +if (NOT DEFINED WAMR_BUILD_REF_TYPES) + # Disable reference types by default + set (WAMR_BUILD_REF_TYPES 0) +endif () + +if (NOT DEFINED WAMR_BUILD_DEBUG_INTERP) + # Disable Debug feature by default + set (WAMR_BUILD_DEBUG_INTERP 0) +endif () + +if (WAMR_BUILD_DEBUG_INTERP EQUAL 1) + set (WAMR_BUILD_FAST_INTERP 0) + set (WAMR_BUILD_MINI_LOADER 0) + set (WAMR_BUILD_SIMD 0) +endif () + +set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../..) + +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) + +set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") + +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wshadow") +# set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wsign-conversion") + +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wno-unused") + +if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mindirect-branch-register") + # UNDEFINED BEHAVIOR, refer to https://en.cppreference.com/w/cpp/language/ub + if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT WAMR_BUILD_JIT EQUAL 1) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined \ + -fno-sanitize=bounds,bounds-strict,alignment \ + -fno-sanitize-recover") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined \ + -fno-sanitize=bounds,bounds-strict,alignment \ + -fno-sanitize-recover") + endif() + else () + # UNDEFINED BEHAVIOR, refer to https://en.cppreference.com/w/cpp/language/ub + if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT WAMR_BUILD_JIT EQUAL 1) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined \ + -fno-sanitize=bounds,alignment \ + -fno-sanitize-recover") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined \ + -fno-sanitize=bounds,alignment \ + -fno-sanitize-recover") + endif() + endif () +endif () + +# The following flags are to enhance security, but it may impact performance, +# we disable them by default. +#if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") +# set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftrapv -D_FORTIFY_SOURCE=2") +#endif () +#set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-strong --param ssp-buffer-size=4") +#set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-z,noexecstack,-z,relro,-z,now") + +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) + +add_executable (iwasm ${WAMR_ROOT_DIR}/product-mini/platforms/${WAMR_BUILD_PLATFORM}/main.c ${UNCOMMON_SHARED_SOURCE}) + +install (TARGETS iwasm DESTINATION bin) + +target_link_libraries (iwasm vmlib ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} ${TENSORFLOW_LIB} -lm -ldl -lpthread) + +add_library (libiwasm SHARED ${WAMR_RUNTIME_LIB_SOURCE}) + +install (TARGETS libiwasm DESTINATION lib) + +set_target_properties (libiwasm PROPERTIES OUTPUT_NAME iwasm) + +target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread) diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/build.sh b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/build.sh new file mode 100755 index 000000000..33879eaf7 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/build.sh @@ -0,0 +1,21 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# WASM application that uses WASI-NN + +/opt/wasi-sdk/bin/clang \ + -Wl,--allow-undefined \ + -Wl,--strip-all,--no-entry \ + --sysroot=/opt/wasi-sdk/share/wasi-sysroot \ + -I.. -I../src/utils \ + -o test_tensorflow.wasm \ + test_tensorflow.c utils.c + +# TFLite models to use in the tests + +cd models +python3 average.py +python3 max.py +python3 mult_dimension.py +python3 mult_outputs.py +python3 sum.py diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/average.py b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/average.py new file mode 100755 index 000000000..a21fe7520 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/average.py @@ -0,0 +1,16 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import tensorflow as tf +from utils import save_model + +model = tf.keras.Sequential([ + tf.keras.layers.InputLayer(input_shape=[5, 5, 1]), + tf.keras.layers.AveragePooling2D( + pool_size=(5, 5), strides=None, padding="valid", data_format=None) + +]) + +# Export model to tflite + +save_model(model, "average.tflite") diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/max.py b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/max.py new file mode 100755 index 000000000..a3ec45677 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/max.py @@ -0,0 +1,17 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import tensorflow as tf + +from utils import save_model + +model = tf.keras.Sequential([ + tf.keras.layers.InputLayer(input_shape=[5, 5, 1]), + tf.keras.layers.MaxPooling2D( + pool_size=(5, 5), strides=None, padding="valid", data_format=None) + +]) + +# Export model to tflite + +save_model(model, "max.tflite") diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/mult_dimension.py b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/mult_dimension.py new file mode 100644 index 000000000..f521a93af --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/mult_dimension.py @@ -0,0 +1,15 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import tensorflow as tf +from utils import save_model + +model = tf.keras.Sequential([ + tf.keras.layers.InputLayer(input_shape=[3, 3, 1]), + tf.keras.layers.Conv2D(1, (1, 1), kernel_initializer=tf.keras.initializers.Constant( + value=1), bias_initializer='zeros' + ) +]) +# Export model to tflite + +save_model(model, "mult_dim.tflite") diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/mult_outputs.py b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/mult_outputs.py new file mode 100755 index 000000000..98a50129c --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/mult_outputs.py @@ -0,0 +1,33 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import tensorflow as tf +import numpy as np +from keras.layers import AveragePooling2D, Conv2D + +from tensorflow.keras import Input, Model + +from utils import save_model + + +inputs = Input(shape=(4, 4, 1)) + +output1 = Conv2D(1, (4, 1), kernel_initializer=tf.keras.initializers.Constant( + value=1), bias_initializer='zeros' +)(inputs) +output2 = AveragePooling2D(pool_size=( + 4, 1), strides=None, padding="valid", data_format=None)(inputs) + +model = Model(inputs=inputs, outputs=[output1, output2]) + +inp = np.arange(16).reshape((1, 4, 4, 1)) + +print(inp) + +res = model.predict(inp) + +print(res) +print(res[0].shape) +print(res[1].shape) + +save_model(model, "mult_out.tflite") diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/sum.py b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/sum.py new file mode 100755 index 000000000..503125b34 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/sum.py @@ -0,0 +1,17 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import tensorflow as tf + +from utils import save_model + +model = tf.keras.Sequential([ + tf.keras.layers.InputLayer(input_shape=[5, 5, 1]), + tf.keras.layers.Conv2D(1, (5, 5), kernel_initializer=tf.keras.initializers.Constant( + value=1), bias_initializer='zeros' + ) +]) + +# Export model to tflite + +save_model(model, "sum.tflite") diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/utils.py b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/utils.py new file mode 100644 index 000000000..8335f05da --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/utils.py @@ -0,0 +1,13 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import tensorflow as tf +import pathlib + + +def save_model(model, filename): + converter = tf.lite.TFLiteConverter.from_keras_model(model) + tflite_model = converter.convert() + tflite_models_dir = pathlib.Path("./") + tflite_model_file = tflite_models_dir/filename + tflite_model_file.write_bytes(tflite_model) diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/requirements.txt b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/requirements.txt new file mode 100644 index 000000000..4cf2910db --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/requirements.txt @@ -0,0 +1 @@ +tensorflow==2.11.1
\ No newline at end of file diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c new file mode 100644 index 000000000..2fa516538 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include <math.h> + +#include "utils.h" +#include "logger.h" + +void +test_sum(execution_target target) +{ + int dims[] = { 1, 5, 5, 1 }; + input_info input = create_input(dims); + + uint32_t output_size = 0; + float *output = run_inference(target, input.input_tensor, input.dim, + &output_size, "/assets/models/sum.tflite", 1); + + assert(output_size == 1); + assert(fabs(output[0] - 300.0) < EPSILON); + + free(input.dim); + free(input.input_tensor); + free(output); +} + +void +test_max(execution_target target) +{ + int dims[] = { 1, 5, 5, 1 }; + input_info input = create_input(dims); + + uint32_t output_size = 0; + float *output = run_inference(target, input.input_tensor, input.dim, + &output_size, "/assets/models/max.tflite", 1); + + assert(output_size == 1); + assert(fabs(output[0] - 24.0) < EPSILON); + NN_INFO_PRINTF("Result: max is %f", output[0]); + + free(input.dim); + free(input.input_tensor); + free(output); +} + +void +test_average(execution_target target) +{ + int dims[] = { 1, 5, 5, 1 }; + input_info input = create_input(dims); + + uint32_t output_size = 0; + float *output = + run_inference(target, input.input_tensor, input.dim, &output_size, + "/assets/models/average.tflite", 1); + + assert(output_size == 1); + assert(fabs(output[0] - 12.0) < EPSILON); + NN_INFO_PRINTF("Result: average is %f", output[0]); + + free(input.dim); + free(input.input_tensor); + free(output); +} + +void +test_mult_dimensions(execution_target target) +{ + int dims[] = { 1, 3, 3, 1 }; + input_info input = create_input(dims); + + uint32_t output_size = 0; + float *output = + run_inference(target, input.input_tensor, input.dim, &output_size, + "/assets/models/mult_dim.tflite", 1); + + assert(output_size == 9); + for (int i = 0; i < 9; i++) + assert(fabs(output[i] - i) < EPSILON); + + free(input.dim); + free(input.input_tensor); + free(output); +} + +void +test_mult_outputs(execution_target target) +{ + int dims[] = { 1, 4, 4, 1 }; + input_info input = create_input(dims); + + uint32_t output_size = 0; + float *output = + run_inference(target, input.input_tensor, input.dim, &output_size, + "/assets/models/mult_out.tflite", 2); + + assert(output_size == 8); + // first tensor check + for (int i = 0; i < 4; i++) + assert(fabs(output[i] - (i * 4 + 24)) < EPSILON); + // second tensor check + for (int i = 0; i < 4; i++) + assert(fabs(output[i + 4] - (i + 6)) < EPSILON); + + free(input.dim); + free(input.input_tensor); + free(output); +} + +int +main() +{ + char *env = getenv("TARGET"); + if (env == NULL) { + NN_INFO_PRINTF("Usage:\n--env=\"TARGET=[cpu|gpu]\""); + return 1; + } + execution_target target; + if (strcmp(env, "cpu") == 0) + target = cpu; + else if (strcmp(env, "gpu") == 0) + target = gpu; + else { + NN_ERR_PRINTF("Wrong target!"); + return 1; + } + NN_INFO_PRINTF("################### Testing sum..."); + test_sum(target); + NN_INFO_PRINTF("################### Testing max..."); + test_max(target); + NN_INFO_PRINTF("################### Testing average..."); + test_average(target); + NN_INFO_PRINTF("################### Testing multiple dimensions..."); + test_mult_dimensions(target); + NN_INFO_PRINTF("################### Testing multiple outputs..."); + test_mult_outputs(target); + + NN_INFO_PRINTF("Tests: passed!"); + return 0; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/utils.c b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/utils.c new file mode 100644 index 000000000..e0704cab4 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/utils.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "utils.h" +#include "logger.h" + +#include <stdio.h> +#include <stdlib.h> + +error +wasm_load(char *model_name, graph *g, execution_target target) +{ + FILE *pFile = fopen(model_name, "r"); + if (pFile == NULL) + return invalid_argument; + + uint8_t *buffer; + size_t result; + + // allocate memory to contain the whole file: + buffer = (uint8_t *)malloc(sizeof(uint8_t) * MAX_MODEL_SIZE); + if (buffer == NULL) { + fclose(pFile); + return missing_memory; + } + + result = fread(buffer, 1, MAX_MODEL_SIZE, pFile); + if (result <= 0) { + fclose(pFile); + free(buffer); + return missing_memory; + } + + graph_builder_array arr; + + arr.size = 1; + arr.buf = (graph_builder *)malloc(sizeof(graph_builder)); + if (arr.buf == NULL) { + fclose(pFile); + free(buffer); + return missing_memory; + } + + arr.buf[0].size = result; + arr.buf[0].buf = buffer; + + error res = load(&arr, tensorflowlite, target, g); + + fclose(pFile); + free(buffer); + free(arr.buf); + return res; +} + +error +wasm_init_execution_context(graph g, graph_execution_context *ctx) +{ + return init_execution_context(g, ctx); +} + +error +wasm_set_input(graph_execution_context ctx, float *input_tensor, uint32_t *dim) +{ + tensor_dimensions dims; + dims.size = INPUT_TENSOR_DIMS; + dims.buf = (uint32_t *)malloc(dims.size * sizeof(uint32_t)); + if (dims.buf == NULL) + return missing_memory; + + tensor tensor; + tensor.dimensions = &dims; + for (int i = 0; i < tensor.dimensions->size; ++i) + tensor.dimensions->buf[i] = dim[i]; + tensor.type = fp32; + tensor.data = (uint8_t *)input_tensor; + error err = set_input(ctx, 0, &tensor); + + free(dims.buf); + return err; +} + +error +wasm_compute(graph_execution_context ctx) +{ + return compute(ctx); +} + +error +wasm_get_output(graph_execution_context ctx, uint32_t index, float *out_tensor, + uint32_t *out_size) +{ + return get_output(ctx, index, (uint8_t *)out_tensor, out_size); +} + +float * +run_inference(execution_target target, float *input, uint32_t *input_size, + uint32_t *output_size, char *model_name, + uint32_t num_output_tensors) +{ + graph graph; + if (wasm_load(model_name, &graph, target) != success) { + NN_ERR_PRINTF("Error when loading model."); + exit(1); + } + + graph_execution_context ctx; + if (wasm_init_execution_context(graph, &ctx) != success) { + NN_ERR_PRINTF("Error when initialixing execution context."); + exit(1); + } + + if (wasm_set_input(ctx, input, input_size) != success) { + NN_ERR_PRINTF("Error when setting input tensor."); + exit(1); + } + + if (wasm_compute(ctx) != success) { + NN_ERR_PRINTF("Error when running inference."); + exit(1); + } + + float *out_tensor = (float *)malloc(sizeof(float) * MAX_OUTPUT_TENSOR_SIZE); + if (out_tensor == NULL) { + NN_ERR_PRINTF("Error when allocating memory for output tensor."); + exit(1); + } + + uint32_t offset = 0; + for (int i = 0; i < num_output_tensors; ++i) { + *output_size = MAX_OUTPUT_TENSOR_SIZE - *output_size; + if (wasm_get_output(ctx, i, &out_tensor[offset], output_size) + != success) { + NN_ERR_PRINTF("Error when getting output."); + exit(1); + } + + offset += *output_size; + } + *output_size = offset; + return out_tensor; +} + +input_info +create_input(int *dims) +{ + input_info input = { .dim = NULL, .input_tensor = NULL, .elements = 1 }; + + input.dim = malloc(INPUT_TENSOR_DIMS * sizeof(uint32_t)); + if (input.dim) + for (int i = 0; i < INPUT_TENSOR_DIMS; ++i) { + input.dim[i] = dims[i]; + input.elements *= dims[i]; + } + + input.input_tensor = malloc(input.elements * sizeof(float)); + for (int i = 0; i < input.elements; ++i) + input.input_tensor[i] = i; + + return input; +} diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/utils.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/utils.h new file mode 100644 index 000000000..6373be542 --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/utils.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_UTILS +#define WASI_NN_UTILS + +#include <stdint.h> + +#include "wasi_nn.h" + +#define MAX_MODEL_SIZE 85000000 +#define MAX_OUTPUT_TENSOR_SIZE 200 +#define INPUT_TENSOR_DIMS 4 +#define EPSILON 1e-8 + +typedef struct { + float *input_tensor; + uint32_t *dim; + uint32_t elements; +} input_info; + +/* wasi-nn wrappers */ + +error +wasm_load(char *model_name, graph *g, execution_target target); + +error +wasm_init_execution_context(graph g, graph_execution_context *ctx); + +error +wasm_set_input(graph_execution_context ctx, float *input_tensor, uint32_t *dim); + +error +wasm_compute(graph_execution_context ctx); + +error +wasm_get_output(graph_execution_context ctx, uint32_t index, float *out_tensor, + uint32_t *out_size); + +/* Utils */ + +float * +run_inference(execution_target target, float *input, uint32_t *input_size, + uint32_t *output_size, char *model_name, + uint32_t num_output_tensors); + +input_info +create_input(int *dims); + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn.cmake b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn.cmake new file mode 100644 index 000000000..019782c2e --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn.cmake @@ -0,0 +1,22 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) + +# Find tensorflow-lite +find_package(tensorflow_lite REQUIRED) + +set (WASI_NN_DIR ${CMAKE_CURRENT_LIST_DIR}) + +include_directories (${WASI_NN_DIR}) +include_directories (${WASI_NN_DIR}/src) +include_directories (${WASI_NN_DIR}/src/utils) + +set ( + LIBC_WASI_NN_SOURCE + ${WASI_NN_DIR}/src/wasi_nn.c + ${WASI_NN_DIR}/src/wasi_nn_tensorflowlite.cpp + ${WASI_NN_DIR}/src/utils/wasi_nn_app_native.c +) + +set (TENSORFLOW_LIB tensorflow-lite) diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn.h new file mode 100644 index 000000000..2bf0a192c --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +/** + * Following definition from: + * [Oct 25th, 2022] + * https://github.com/WebAssembly/wasi-nn/blob/0f77c48ec195748990ff67928a4b3eef5f16c2de/wasi-nn.wit.md + */ + +#ifndef WASI_NN_H +#define WASI_NN_H + +#include <stdint.h> +#include "wasi_nn_types.h" + +/** + * @brief Load an opaque sequence of bytes to use for inference. + * + * @param builder Model builder. + * @param encoding Model encoding. + * @param target Execution target. + * @param g Graph. + * @return error Execution status. + */ +error +load(graph_builder_array *builder, graph_encoding encoding, + execution_target target, graph *g) + __attribute__((import_module("wasi_nn"))); + +/** + * INFERENCE + * + */ + +// Bind a `graph` to the input and output tensors for an inference. +typedef uint32_t graph_execution_context; + +/** + * @brief Create an execution instance of a loaded graph. + * + * @param g Graph. + * @param ctx Execution context. + * @return error Execution status. + */ +error +init_execution_context(graph g, graph_execution_context *ctx) + __attribute__((import_module("wasi_nn"))); + +/** + * @brief Define the inputs to use for inference. + * + * @param ctx Execution context. + * @param index Input tensor index. + * @param tensor Input tensor. + * @return error Execution status. + */ +error +set_input(graph_execution_context ctx, uint32_t index, tensor *tensor) + __attribute__((import_module("wasi_nn"))); + +/** + * @brief Compute the inference on the given inputs. + * + * @param ctx Execution context. + * @return error Execution status. + */ +error +compute(graph_execution_context ctx) __attribute__((import_module("wasi_nn"))); + +/** + * @brief Extract the outputs after inference. + * + * @param ctx Execution context. + * @param index Output tensor index. + * @param output_tensor Buffer where output tensor with index `index` is + * copied. + * @param output_tensor_size Pointer to `output_tensor` maximum size. + * After the function call it is updated with the + * copied number of bytes. + * @return error Execution status. + */ +error +get_output(graph_execution_context ctx, uint32_t index, + tensor_data output_tensor, uint32_t *output_tensor_size) + __attribute__((import_module("wasi_nn"))); + +#endif diff --git a/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn_types.h b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn_types.h new file mode 100644 index 000000000..a2cebe49e --- /dev/null +++ b/src/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn_types.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_TYPES_H +#define WASI_NN_TYPES_H + +/** + * ERRORS + * + */ + +// Error codes returned by functions in this API. +typedef enum { + // No error occurred. + success = 0, + // Caller module passed an invalid argument. + invalid_argument, + // Invalid encoding. + invalid_encoding, + // Caller module is missing a memory export. + missing_memory, + // Device or resource busy. + busy, + // Runtime Error. + runtime_error, +} error; + +/** + * TENSOR + * + */ + +// The dimensions of a tensor. +// +// The array length matches the tensor rank and each element in the array +// describes the size of each dimension. +typedef struct { + uint32_t *buf; + uint32_t size; +} tensor_dimensions; + +// The type of the elements in a tensor. +typedef enum { fp16 = 0, fp32, up8, ip32 } tensor_type; + +// The tensor data. +// +// Initially conceived as a sparse representation, each empty cell would be +// filled with zeros and the array length must match the product of all of the +// dimensions and the number of bytes in the type (e.g., a 2x2 tensor with +// 4-byte f32 elements would have a data array of length 16). Naturally, this +// representation requires some knowledge of how to lay out data in +// memory--e.g., using row-major ordering--and could perhaps be improved. +typedef uint8_t *tensor_data; + +// A tensor. +typedef struct { + // Describe the size of the tensor (e.g., 2x2x2x2 -> [2, 2, 2, 2]). To + // represent a tensor containing a single value, use `[1]` for the tensor + // dimensions. + tensor_dimensions *dimensions; + // Describe the type of element in the tensor (e.g., f32). + tensor_type type; + // Contains the tensor data. + tensor_data data; +} tensor; + +/** + * GRAPH + * + */ + +// The graph initialization data. +// +// This consists of an array of buffers because implementing backends may encode +// their graph IR in parts (e.g., OpenVINO stores its IR and weights +// separately). +typedef struct { + uint8_t *buf; + uint32_t size; +} graph_builder; + +typedef struct { + graph_builder *buf; + uint32_t size; +} graph_builder_array; + +// An execution graph for performing inference (i.e., a model). +typedef uint32_t graph; + +// Describes the encoding of the graph. This allows the API to be implemented by +// various backends that encode (i.e., serialize) their graph IR with different +// formats. +typedef enum { + openvino = 0, + onnx, + tensorflow, + pytorch, + tensorflowlite +} graph_encoding; + +// Define where the graph should be executed. +typedef enum execution_target { cpu = 0, gpu, tpu } execution_target; + +#endif |