mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2026-02-01 06:01:51 +00:00
Merge pull request #1084 from bytecodealliance/main
Merge main into dev/fast_jit
This commit is contained in:
commit
bb5389867f
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -23,4 +23,6 @@ product-mini/platforms/linux-sgx/enclave-sample/iwasm
|
|||
build_out
|
||||
tests/wamr-test-suites/workspace
|
||||
|
||||
!/test-tools/wamr-ide/VSCode-Extension/.vscode
|
||||
!/test-tools/wamr-ide/VSCode-Extension/.vscode
|
||||
|
||||
samples/socket-api/wasm-src/inc/pthread.h
|
||||
|
|
|
|||
|
|
@ -5800,6 +5800,22 @@ index c878a2ac4..ad5945b0a 100644
|
|||
// Don't allow the caching that lldb_private::Process::ReadMemory does since
|
||||
// we have it all cached in the trace files.
|
||||
return DoReadMemory(addr, buf, size, error);
|
||||
diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp
|
||||
index 896e647bb..f76307016 100644
|
||||
--- a/lldb/source/Target/ThreadPlanStepRange.cpp
|
||||
+++ b/lldb/source/Target/ThreadPlanStepRange.cpp
|
||||
@@ -334,7 +334,10 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() {
|
||||
// If we didn't find a branch, run to the end of the range.
|
||||
if (branch_index == UINT32_MAX) {
|
||||
uint32_t last_index = instructions->GetSize() - 1;
|
||||
- if (last_index - pc_index > 1) {
|
||||
+ /* This line causes the "step over was treated as step in" issue, we
|
||||
+ * modify it as a workaround */
|
||||
+ /* The origin line is: if (last_index - pc_index > 1) { */
|
||||
+ if (last_index - pc_index >= 1) {
|
||||
InstructionSP last_inst =
|
||||
instructions->GetInstructionAtIndex(last_index);
|
||||
size_t last_inst_size = last_inst->GetOpcode().GetByteSize();
|
||||
diff --git a/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp
|
||||
index 4ec2e25c7..24c88fe9a 100644
|
||||
--- a/lldb/source/Target/UnixSignals.cpp
|
||||
|
|
|
|||
|
|
@ -169,6 +169,15 @@
|
|||
#define WASM_ENABLE_DEBUG_INTERP 0
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_DEBUG_INTERP != 0
|
||||
#ifndef DEBUG_EXECUTION_MEMORY_SIZE
|
||||
/* 0x85000 is the size required by lldb, if this is changed to a smaller value,
|
||||
* then the debugger will not be able to evaluate user expressions, other
|
||||
* functionality such as breakpoint and stepping are not influenced by this */
|
||||
#define DEBUG_EXECUTION_MEMORY_SIZE 0x85000
|
||||
#endif
|
||||
#endif /* end of WASM_ENABLE_DEBUG_INTERP != 0 */
|
||||
|
||||
#ifndef WASM_ENABLE_DEBUG_AOT
|
||||
#define WASM_ENABLE_DEBUG_AOT 0
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1773,6 +1773,33 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
HANDLE_OP_END();
|
||||
}
|
||||
|
||||
/* constant instructions */
|
||||
HANDLE_OP(WASM_OP_F64_CONST)
|
||||
HANDLE_OP(WASM_OP_I64_CONST)
|
||||
{
|
||||
uint8 *orig_ip = frame_ip;
|
||||
|
||||
frame_ip += sizeof(uint64);
|
||||
addr_ret = GET_OFFSET();
|
||||
|
||||
bh_memcpy_s(frame_lp + addr_ret, sizeof(uint64), orig_ip,
|
||||
sizeof(uint64));
|
||||
HANDLE_OP_END();
|
||||
}
|
||||
|
||||
HANDLE_OP(WASM_OP_F32_CONST)
|
||||
HANDLE_OP(WASM_OP_I32_CONST)
|
||||
{
|
||||
uint8 *orig_ip = frame_ip;
|
||||
|
||||
frame_ip += sizeof(uint32);
|
||||
addr_ret = GET_OFFSET();
|
||||
|
||||
bh_memcpy_s(frame_lp + addr_ret, sizeof(uint32), orig_ip,
|
||||
sizeof(uint32));
|
||||
HANDLE_OP_END();
|
||||
}
|
||||
|
||||
/* comparison instructions of i32 */
|
||||
HANDLE_OP(WASM_OP_I32_EQZ)
|
||||
{
|
||||
|
|
@ -3496,10 +3523,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
|||
HANDLE_OP(WASM_OP_F64_LOAD)
|
||||
HANDLE_OP(EXT_OP_GET_LOCAL_FAST)
|
||||
HANDLE_OP(WASM_OP_GET_LOCAL)
|
||||
HANDLE_OP(WASM_OP_F64_CONST)
|
||||
HANDLE_OP(WASM_OP_I64_CONST)
|
||||
HANDLE_OP(WASM_OP_F32_CONST)
|
||||
HANDLE_OP(WASM_OP_I32_CONST)
|
||||
HANDLE_OP(WASM_OP_DROP)
|
||||
HANDLE_OP(WASM_OP_DROP_64)
|
||||
HANDLE_OP(WASM_OP_BLOCK)
|
||||
|
|
|
|||
|
|
@ -1828,7 +1828,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
|
|||
uint32 func_count;
|
||||
uint64 total_size;
|
||||
uint32 code_count = 0, code_size, type_index, i, j, k, local_type_index;
|
||||
uint32 local_count, local_set_count, sub_local_count;
|
||||
uint32 local_count, local_set_count, sub_local_count, local_cell_num;
|
||||
uint8 type;
|
||||
WASMFunction *func;
|
||||
|
||||
|
|
@ -1954,9 +1954,17 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
|
|||
|
||||
func->param_cell_num = func->func_type->param_cell_num;
|
||||
func->ret_cell_num = func->func_type->ret_cell_num;
|
||||
func->local_cell_num =
|
||||
local_cell_num =
|
||||
wasm_get_cell_num(func->local_types, func->local_count);
|
||||
|
||||
if (local_cell_num > UINT16_MAX) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"local count too large");
|
||||
return false;
|
||||
}
|
||||
|
||||
func->local_cell_num = (uint16)local_cell_num;
|
||||
|
||||
if (!init_function_local_offsets(func, error_buf, error_buf_size))
|
||||
return false;
|
||||
|
||||
|
|
@ -4408,8 +4416,8 @@ typedef struct WASMLoaderContext {
|
|||
/* const buffer */
|
||||
uint8 *const_buf;
|
||||
uint16 num_const;
|
||||
uint16 const_buf_size;
|
||||
uint16 const_cell_num;
|
||||
uint32 const_buf_size;
|
||||
|
||||
/* processed code */
|
||||
uint8 *p_code_compiled;
|
||||
|
|
@ -4619,38 +4627,45 @@ wasm_loader_ctx_destroy(WASMLoaderContext *ctx)
|
|||
}
|
||||
|
||||
static WASMLoaderContext *
|
||||
wasm_loader_ctx_init(WASMFunction *func)
|
||||
wasm_loader_ctx_init(WASMFunction *func, char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
WASMLoaderContext *loader_ctx =
|
||||
loader_malloc(sizeof(WASMLoaderContext), NULL, 0);
|
||||
loader_malloc(sizeof(WASMLoaderContext), error_buf, error_buf_size);
|
||||
if (!loader_ctx)
|
||||
return NULL;
|
||||
|
||||
loader_ctx->frame_ref_size = 32;
|
||||
if (!(loader_ctx->frame_ref_bottom = loader_ctx->frame_ref =
|
||||
loader_malloc(loader_ctx->frame_ref_size, NULL, 0)))
|
||||
if (!(loader_ctx->frame_ref_bottom = loader_ctx->frame_ref = loader_malloc(
|
||||
loader_ctx->frame_ref_size, error_buf, error_buf_size)))
|
||||
goto fail;
|
||||
loader_ctx->frame_ref_boundary = loader_ctx->frame_ref_bottom + 32;
|
||||
|
||||
loader_ctx->frame_csp_size = sizeof(BranchBlock) * 8;
|
||||
if (!(loader_ctx->frame_csp_bottom = loader_ctx->frame_csp =
|
||||
loader_malloc(loader_ctx->frame_csp_size, NULL, 0)))
|
||||
if (!(loader_ctx->frame_csp_bottom = loader_ctx->frame_csp = loader_malloc(
|
||||
loader_ctx->frame_csp_size, error_buf, error_buf_size)))
|
||||
goto fail;
|
||||
loader_ctx->frame_csp_boundary = loader_ctx->frame_csp_bottom + 8;
|
||||
|
||||
#if WASM_ENABLE_FAST_INTERP != 0
|
||||
loader_ctx->frame_offset_size = sizeof(int16) * 32;
|
||||
if (!(loader_ctx->frame_offset_bottom = loader_ctx->frame_offset =
|
||||
loader_malloc(loader_ctx->frame_offset_size, NULL, 0)))
|
||||
loader_malloc(loader_ctx->frame_offset_size, error_buf,
|
||||
error_buf_size)))
|
||||
goto fail;
|
||||
loader_ctx->frame_offset_boundary = loader_ctx->frame_offset_bottom + 32;
|
||||
|
||||
loader_ctx->num_const = 0;
|
||||
loader_ctx->const_buf_size = sizeof(Const) * 8;
|
||||
if (!(loader_ctx->const_buf =
|
||||
loader_malloc(loader_ctx->const_buf_size, NULL, 0)))
|
||||
if (!(loader_ctx->const_buf = loader_malloc(loader_ctx->const_buf_size,
|
||||
error_buf, error_buf_size)))
|
||||
goto fail;
|
||||
|
||||
if (func->param_cell_num >= (int32)INT16_MAX - func->local_cell_num) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"fast interpreter offset overflow");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
loader_ctx->start_dynamic_offset = loader_ctx->dynamic_offset =
|
||||
loader_ctx->max_dynamic_offset =
|
||||
func->param_cell_num + func->local_cell_num;
|
||||
|
|
@ -4930,6 +4945,24 @@ fail:
|
|||
LOG_OP("%d\t", value); \
|
||||
} while (0)
|
||||
|
||||
#define emit_uint64(ctx, value) \
|
||||
do { \
|
||||
wasm_loader_emit_const(ctx, &value, false); \
|
||||
LOG_OP("%lld\t", value); \
|
||||
} while (0)
|
||||
|
||||
#define emit_float32(ctx, value) \
|
||||
do { \
|
||||
wasm_loader_emit_const(ctx, &value, true); \
|
||||
LOG_OP("%f\t", value); \
|
||||
} while (0)
|
||||
|
||||
#define emit_float64(ctx, value) \
|
||||
do { \
|
||||
wasm_loader_emit_const(ctx, &value, false); \
|
||||
LOG_OP("%f\t", value); \
|
||||
} while (0)
|
||||
|
||||
static bool
|
||||
wasm_loader_ctx_reinit(WASMLoaderContext *ctx)
|
||||
{
|
||||
|
|
@ -4961,6 +4994,28 @@ wasm_loader_ctx_reinit(WASMLoaderContext *ctx)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
wasm_loader_emit_const(WASMLoaderContext *ctx, void *value, bool is_32_bit)
|
||||
{
|
||||
uint32 size = is_32_bit ? sizeof(uint32) : sizeof(uint64);
|
||||
|
||||
if (ctx->p_code_compiled) {
|
||||
#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
|
||||
bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0);
|
||||
#endif
|
||||
bh_memcpy_s(ctx->p_code_compiled,
|
||||
ctx->p_code_compiled_end - ctx->p_code_compiled, value,
|
||||
size);
|
||||
ctx->p_code_compiled += size;
|
||||
}
|
||||
else {
|
||||
#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
|
||||
bh_assert((ctx->code_compiled_size & 1) == 0);
|
||||
#endif
|
||||
ctx->code_compiled_size += size;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wasm_loader_emit_uint32(WASMLoaderContext *ctx, uint32 value)
|
||||
{
|
||||
|
|
@ -5290,8 +5345,12 @@ wasm_loader_push_frame_offset(WASMLoaderContext *ctx, uint8 type,
|
|||
emit_operand(ctx, ctx->dynamic_offset);
|
||||
*(ctx->frame_offset)++ = ctx->dynamic_offset;
|
||||
ctx->dynamic_offset++;
|
||||
if (ctx->dynamic_offset > ctx->max_dynamic_offset)
|
||||
if (ctx->dynamic_offset > ctx->max_dynamic_offset) {
|
||||
ctx->max_dynamic_offset = ctx->dynamic_offset;
|
||||
if (ctx->max_dynamic_offset >= INT16_MAX) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_32bit_type(type))
|
||||
|
|
@ -5305,10 +5364,19 @@ wasm_loader_push_frame_offset(WASMLoaderContext *ctx, uint8 type,
|
|||
ctx->frame_offset++;
|
||||
if (!disable_emit) {
|
||||
ctx->dynamic_offset++;
|
||||
if (ctx->dynamic_offset > ctx->max_dynamic_offset)
|
||||
if (ctx->dynamic_offset > ctx->max_dynamic_offset) {
|
||||
ctx->max_dynamic_offset = ctx->dynamic_offset;
|
||||
if (ctx->max_dynamic_offset >= INT16_MAX) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"fast interpreter offset overflow");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* This function should be in front of wasm_loader_pop_frame_ref
|
||||
|
|
@ -5429,8 +5497,11 @@ wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, void *value,
|
|||
int16 *offset, char *error_buf,
|
||||
uint32 error_buf_size)
|
||||
{
|
||||
int8 bytes_to_increase;
|
||||
int16 operand_offset = 0;
|
||||
Const *c;
|
||||
|
||||
/* Search existing constant */
|
||||
for (c = (Const *)ctx->const_buf;
|
||||
(uint8 *)c < ctx->const_buf + ctx->num_const * sizeof(Const); c++) {
|
||||
/* TODO: handle v128 type? */
|
||||
|
|
@ -5456,7 +5527,24 @@ wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, void *value,
|
|||
else
|
||||
operand_offset += 2;
|
||||
}
|
||||
|
||||
if ((uint8 *)c == ctx->const_buf + ctx->num_const * sizeof(Const)) {
|
||||
/* New constant, append to the const buffer */
|
||||
if ((type == VALUE_TYPE_F64) || (type == VALUE_TYPE_I64)) {
|
||||
bytes_to_increase = 2;
|
||||
}
|
||||
else {
|
||||
bytes_to_increase = 1;
|
||||
}
|
||||
|
||||
/* The max cell num of const buffer is 32768 since the valid index range
|
||||
* is -32768 ~ -1. Return an invalid index 0 to indicate the buffer is
|
||||
* full */
|
||||
if (ctx->const_cell_num > INT16_MAX - bytes_to_increase + 1) {
|
||||
*offset = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((uint8 *)c == ctx->const_buf + ctx->const_buf_size) {
|
||||
MEM_REALLOC(ctx->const_buf, ctx->const_buf_size,
|
||||
ctx->const_buf_size + 4 * sizeof(Const));
|
||||
|
|
@ -6386,8 +6474,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
|
|||
local_types = func->local_types;
|
||||
local_offsets = func->local_offsets;
|
||||
|
||||
if (!(loader_ctx = wasm_loader_ctx_init(func))) {
|
||||
set_error_buf(error_buf, error_buf_size, "allocate memory failed");
|
||||
if (!(loader_ctx = wasm_loader_ctx_init(func, error_buf, error_buf_size))) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
@ -7726,6 +7813,12 @@ re_scan:
|
|||
skip_label();
|
||||
disable_emit = true;
|
||||
GET_CONST_OFFSET(VALUE_TYPE_I32, i32_const);
|
||||
|
||||
if (operand_offset == 0) {
|
||||
disable_emit = false;
|
||||
emit_label(WASM_OP_I32_CONST);
|
||||
emit_uint32(loader_ctx, i32_const);
|
||||
}
|
||||
#else
|
||||
(void)i32_const;
|
||||
#endif
|
||||
|
|
@ -7738,6 +7831,12 @@ re_scan:
|
|||
skip_label();
|
||||
disable_emit = true;
|
||||
GET_CONST_OFFSET(VALUE_TYPE_I64, i64_const);
|
||||
|
||||
if (operand_offset == 0) {
|
||||
disable_emit = false;
|
||||
emit_label(WASM_OP_I64_CONST);
|
||||
emit_uint64(loader_ctx, i64_const);
|
||||
}
|
||||
#endif
|
||||
PUSH_I64();
|
||||
break;
|
||||
|
|
@ -7750,6 +7849,12 @@ re_scan:
|
|||
bh_memcpy_s((uint8 *)&f32_const, sizeof(float32), p_org,
|
||||
sizeof(float32));
|
||||
GET_CONST_F32_OFFSET(VALUE_TYPE_F32, f32_const);
|
||||
|
||||
if (operand_offset == 0) {
|
||||
disable_emit = false;
|
||||
emit_label(WASM_OP_F32_CONST);
|
||||
emit_float32(loader_ctx, f32_const);
|
||||
}
|
||||
#endif
|
||||
PUSH_F32();
|
||||
break;
|
||||
|
|
@ -7763,6 +7868,12 @@ re_scan:
|
|||
bh_memcpy_s((uint8 *)&f64_const, sizeof(float64), p_org,
|
||||
sizeof(float64));
|
||||
GET_CONST_F64_OFFSET(VALUE_TYPE_F64, f64_const);
|
||||
|
||||
if (operand_offset == 0) {
|
||||
disable_emit = false;
|
||||
emit_label(WASM_OP_F64_CONST);
|
||||
emit_float64(loader_ctx, f64_const);
|
||||
}
|
||||
#endif
|
||||
PUSH_F64();
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -914,7 +914,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
|
|||
uint32 func_count;
|
||||
uint64 total_size;
|
||||
uint32 code_count = 0, code_size, type_index, i, j, k, local_type_index;
|
||||
uint32 local_count, local_set_count, sub_local_count;
|
||||
uint32 local_count, local_set_count, sub_local_count, local_cell_num;
|
||||
uint8 type;
|
||||
WASMFunction *func;
|
||||
|
||||
|
|
@ -1005,8 +1005,11 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
|
|||
|
||||
func->param_cell_num = func->func_type->param_cell_num;
|
||||
func->ret_cell_num = func->func_type->ret_cell_num;
|
||||
func->local_cell_num =
|
||||
local_cell_num =
|
||||
wasm_get_cell_num(func->local_types, func->local_count);
|
||||
bh_assert(local_cell_num <= UINT16_MAX);
|
||||
|
||||
func->local_cell_num = (uint16)local_cell_num;
|
||||
|
||||
if (!init_function_local_offsets(func, error_buf, error_buf_size))
|
||||
return false;
|
||||
|
|
@ -2993,8 +2996,8 @@ typedef struct WASMLoaderContext {
|
|||
/* const buffer */
|
||||
uint8 *const_buf;
|
||||
uint16 num_const;
|
||||
uint16 const_buf_size;
|
||||
uint16 const_cell_num;
|
||||
uint32 const_buf_size;
|
||||
|
||||
/* processed code */
|
||||
uint8 *p_code_compiled;
|
||||
|
|
@ -3179,38 +3182,45 @@ wasm_loader_ctx_destroy(WASMLoaderContext *ctx)
|
|||
}
|
||||
|
||||
static WASMLoaderContext *
|
||||
wasm_loader_ctx_init(WASMFunction *func)
|
||||
wasm_loader_ctx_init(WASMFunction *func, char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
WASMLoaderContext *loader_ctx =
|
||||
loader_malloc(sizeof(WASMLoaderContext), NULL, 0);
|
||||
loader_malloc(sizeof(WASMLoaderContext), error_buf, error_buf_size);
|
||||
if (!loader_ctx)
|
||||
return false;
|
||||
return NULL;
|
||||
|
||||
loader_ctx->frame_ref_size = 32;
|
||||
if (!(loader_ctx->frame_ref_bottom = loader_ctx->frame_ref =
|
||||
loader_malloc(loader_ctx->frame_ref_size, NULL, 0)))
|
||||
if (!(loader_ctx->frame_ref_bottom = loader_ctx->frame_ref = loader_malloc(
|
||||
loader_ctx->frame_ref_size, error_buf, error_buf_size)))
|
||||
goto fail;
|
||||
loader_ctx->frame_ref_boundary = loader_ctx->frame_ref_bottom + 32;
|
||||
|
||||
loader_ctx->frame_csp_size = sizeof(BranchBlock) * 8;
|
||||
if (!(loader_ctx->frame_csp_bottom = loader_ctx->frame_csp =
|
||||
loader_malloc(loader_ctx->frame_csp_size, NULL, 0)))
|
||||
if (!(loader_ctx->frame_csp_bottom = loader_ctx->frame_csp = loader_malloc(
|
||||
loader_ctx->frame_csp_size, error_buf, error_buf_size)))
|
||||
goto fail;
|
||||
loader_ctx->frame_csp_boundary = loader_ctx->frame_csp_bottom + 8;
|
||||
|
||||
#if WASM_ENABLE_FAST_INTERP != 0
|
||||
loader_ctx->frame_offset_size = sizeof(int16) * 32;
|
||||
if (!(loader_ctx->frame_offset_bottom = loader_ctx->frame_offset =
|
||||
loader_malloc(loader_ctx->frame_offset_size, NULL, 0)))
|
||||
loader_malloc(loader_ctx->frame_offset_size, error_buf,
|
||||
error_buf_size)))
|
||||
goto fail;
|
||||
loader_ctx->frame_offset_boundary = loader_ctx->frame_offset_bottom + 32;
|
||||
|
||||
loader_ctx->num_const = 0;
|
||||
loader_ctx->const_buf_size = sizeof(Const) * 8;
|
||||
if (!(loader_ctx->const_buf =
|
||||
loader_malloc(loader_ctx->const_buf_size, NULL, 0)))
|
||||
if (!(loader_ctx->const_buf = loader_malloc(loader_ctx->const_buf_size,
|
||||
error_buf, error_buf_size)))
|
||||
goto fail;
|
||||
|
||||
if (func->param_cell_num >= (int32)INT16_MAX - func->local_cell_num) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"fast interpreter offset overflow");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
loader_ctx->start_dynamic_offset = loader_ctx->dynamic_offset =
|
||||
loader_ctx->max_dynamic_offset =
|
||||
func->param_cell_num + func->local_cell_num;
|
||||
|
|
@ -3463,6 +3473,24 @@ wasm_loader_pop_frame_csp(WASMLoaderContext *ctx, char *error_buf,
|
|||
LOG_OP("%d\t", value); \
|
||||
} while (0)
|
||||
|
||||
#define emit_uint64(ctx, value) \
|
||||
do { \
|
||||
wasm_loader_emit_const(ctx, &value, false); \
|
||||
LOG_OP("%lld\t", value); \
|
||||
} while (0)
|
||||
|
||||
#define emit_float32(ctx, value) \
|
||||
do { \
|
||||
wasm_loader_emit_const(ctx, &value, true); \
|
||||
LOG_OP("%f\t", value); \
|
||||
} while (0)
|
||||
|
||||
#define emit_float64(ctx, value) \
|
||||
do { \
|
||||
wasm_loader_emit_const(ctx, &value, false); \
|
||||
LOG_OP("%f\t", value); \
|
||||
} while (0)
|
||||
|
||||
static bool
|
||||
wasm_loader_ctx_reinit(WASMLoaderContext *ctx)
|
||||
{
|
||||
|
|
@ -3494,6 +3522,28 @@ wasm_loader_ctx_reinit(WASMLoaderContext *ctx)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
wasm_loader_emit_const(WASMLoaderContext *ctx, void *value, bool is_32_bit)
|
||||
{
|
||||
uint32 size = is_32_bit ? sizeof(uint32) : sizeof(uint64);
|
||||
|
||||
if (ctx->p_code_compiled) {
|
||||
#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
|
||||
bh_assert(((uintptr_t)ctx->p_code_compiled & 1) == 0);
|
||||
#endif
|
||||
bh_memcpy_s(ctx->p_code_compiled,
|
||||
ctx->p_code_compiled_end - ctx->p_code_compiled, value,
|
||||
size);
|
||||
ctx->p_code_compiled += size;
|
||||
}
|
||||
else {
|
||||
#if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
|
||||
bh_assert((ctx->code_compiled_size & 1) == 0);
|
||||
#endif
|
||||
ctx->code_compiled_size += size;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wasm_loader_emit_uint32(WASMLoaderContext *ctx, uint32 value)
|
||||
{
|
||||
|
|
@ -3825,8 +3875,10 @@ wasm_loader_push_frame_offset(WASMLoaderContext *ctx, uint8 type,
|
|||
emit_operand(ctx, ctx->dynamic_offset);
|
||||
*(ctx->frame_offset)++ = ctx->dynamic_offset;
|
||||
ctx->dynamic_offset++;
|
||||
if (ctx->dynamic_offset > ctx->max_dynamic_offset)
|
||||
if (ctx->dynamic_offset > ctx->max_dynamic_offset) {
|
||||
ctx->max_dynamic_offset = ctx->dynamic_offset;
|
||||
bh_assert(ctx->max_dynamic_offset < INT16_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_32bit_type(type))
|
||||
|
|
@ -3840,8 +3892,10 @@ wasm_loader_push_frame_offset(WASMLoaderContext *ctx, uint8 type,
|
|||
ctx->frame_offset++;
|
||||
if (!disable_emit) {
|
||||
ctx->dynamic_offset++;
|
||||
if (ctx->dynamic_offset > ctx->max_dynamic_offset)
|
||||
if (ctx->dynamic_offset > ctx->max_dynamic_offset) {
|
||||
ctx->max_dynamic_offset = ctx->dynamic_offset;
|
||||
bh_assert(ctx->max_dynamic_offset < INT16_MAX);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -3962,8 +4016,11 @@ wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, void *value,
|
|||
int16 *offset, char *error_buf,
|
||||
uint32 error_buf_size)
|
||||
{
|
||||
int8 bytes_to_increase;
|
||||
int16 operand_offset = 0;
|
||||
Const *c;
|
||||
|
||||
/* Search existing constant */
|
||||
for (c = (Const *)ctx->const_buf;
|
||||
(uint8 *)c < ctx->const_buf + ctx->num_const * sizeof(Const); c++) {
|
||||
if ((type == c->value_type)
|
||||
|
|
@ -3988,7 +4045,24 @@ wasm_loader_get_const_offset(WASMLoaderContext *ctx, uint8 type, void *value,
|
|||
else
|
||||
operand_offset += 1;
|
||||
}
|
||||
|
||||
if ((uint8 *)c == ctx->const_buf + ctx->num_const * sizeof(Const)) {
|
||||
/* New constant, append to the const buffer */
|
||||
if ((type == VALUE_TYPE_F64) || (type == VALUE_TYPE_I64)) {
|
||||
bytes_to_increase = 2;
|
||||
}
|
||||
else {
|
||||
bytes_to_increase = 1;
|
||||
}
|
||||
|
||||
/* The max cell num of const buffer is 32768 since the valid index range
|
||||
* is -32768 ~ -1. Return an invalid index 0 to indicate the buffer is
|
||||
* full */
|
||||
if (ctx->const_cell_num > INT16_MAX - bytes_to_increase + 1) {
|
||||
*offset = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((uint8 *)c == ctx->const_buf + ctx->const_buf_size) {
|
||||
MEM_REALLOC(ctx->const_buf, ctx->const_buf_size,
|
||||
ctx->const_buf_size + 4 * sizeof(Const));
|
||||
|
|
@ -4788,8 +4862,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
|
|||
local_types = func->local_types;
|
||||
local_offsets = func->local_offsets;
|
||||
|
||||
if (!(loader_ctx = wasm_loader_ctx_init(func))) {
|
||||
set_error_buf(error_buf, error_buf_size, "allocate memory failed");
|
||||
if (!(loader_ctx = wasm_loader_ctx_init(func, error_buf, error_buf_size))) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
@ -5977,6 +6050,12 @@ re_scan:
|
|||
skip_label();
|
||||
disable_emit = true;
|
||||
GET_CONST_OFFSET(VALUE_TYPE_I32, i32_const);
|
||||
|
||||
if (operand_offset == 0) {
|
||||
disable_emit = false;
|
||||
emit_label(WASM_OP_I32_CONST);
|
||||
emit_uint32(loader_ctx, i32_const);
|
||||
}
|
||||
#else
|
||||
(void)i32_const;
|
||||
#endif
|
||||
|
|
@ -5989,6 +6068,12 @@ re_scan:
|
|||
skip_label();
|
||||
disable_emit = true;
|
||||
GET_CONST_OFFSET(VALUE_TYPE_I64, i64_const);
|
||||
|
||||
if (operand_offset == 0) {
|
||||
disable_emit = false;
|
||||
emit_label(WASM_OP_I64_CONST);
|
||||
emit_uint64(loader_ctx, i64_const);
|
||||
}
|
||||
#endif
|
||||
PUSH_I64();
|
||||
break;
|
||||
|
|
@ -6001,6 +6086,12 @@ re_scan:
|
|||
bh_memcpy_s((uint8 *)&f32_const, sizeof(float32), p_org,
|
||||
sizeof(float32));
|
||||
GET_CONST_F32_OFFSET(VALUE_TYPE_F32, f32_const);
|
||||
|
||||
if (operand_offset == 0) {
|
||||
disable_emit = false;
|
||||
emit_label(WASM_OP_F32_CONST);
|
||||
emit_float32(loader_ctx, f32_const);
|
||||
}
|
||||
#endif
|
||||
PUSH_F32();
|
||||
break;
|
||||
|
|
@ -6014,6 +6105,12 @@ re_scan:
|
|||
bh_memcpy_s((uint8 *)&f64_const, sizeof(float64), p_org,
|
||||
sizeof(float64));
|
||||
GET_CONST_F64_OFFSET(VALUE_TYPE_F64, f64_const);
|
||||
|
||||
if (operand_offset == 0) {
|
||||
disable_emit = false;
|
||||
emit_label(WASM_OP_F64_CONST);
|
||||
emit_float64(loader_ctx, f64_const);
|
||||
}
|
||||
#endif
|
||||
PUSH_F64();
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -345,7 +345,8 @@ WASMDebugInstance *
|
|||
wasm_debug_instance_create(WASMCluster *cluster)
|
||||
{
|
||||
WASMDebugInstance *instance;
|
||||
WASMExecEnv *exec_env;
|
||||
WASMExecEnv *exec_env = NULL;
|
||||
wasm_module_inst_t module_inst = NULL;
|
||||
|
||||
if (!g_debug_engine || !g_debug_engine->active) {
|
||||
return NULL;
|
||||
|
|
@ -373,6 +374,24 @@ wasm_debug_instance_create(WASMCluster *cluster)
|
|||
|
||||
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)) {
|
||||
LOG_ERROR("WASM Debug Engine error: failed to create control thread");
|
||||
goto fail3;
|
||||
|
|
@ -1182,9 +1201,7 @@ wasm_debug_instance_mmap(WASMDebugInstance *instance, uint32 size,
|
|||
int32 map_port)
|
||||
{
|
||||
WASMExecEnv *exec_env;
|
||||
WASMModuleInstance *module_inst;
|
||||
uint32 offset;
|
||||
void *native_addr;
|
||||
uint32 offset = 0;
|
||||
(void)map_port;
|
||||
|
||||
if (!instance)
|
||||
|
|
@ -1194,15 +1211,23 @@ wasm_debug_instance_mmap(WASMDebugInstance *instance, uint32 size,
|
|||
if (!exec_env)
|
||||
return 0;
|
||||
|
||||
module_inst = (WASMModuleInstance *)exec_env->module_inst;
|
||||
if (instance->exec_mem_info.start_offset == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: malloc in wasi libc maybe not be thread safe, we hope LLDB will
|
||||
always ask for memory when threads stopped */
|
||||
offset = wasm_runtime_module_malloc((wasm_module_inst_t)module_inst, size,
|
||||
&native_addr);
|
||||
if (!offset)
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -1210,8 +1235,6 @@ bool
|
|||
wasm_debug_instance_ummap(WASMDebugInstance *instance, uint64 addr)
|
||||
{
|
||||
WASMExecEnv *exec_env;
|
||||
WASMModuleInstance *module_inst;
|
||||
uint32 offset;
|
||||
|
||||
if (!instance)
|
||||
return false;
|
||||
|
|
@ -1220,11 +1243,13 @@ wasm_debug_instance_ummap(WASMDebugInstance *instance, uint64 addr)
|
|||
if (!exec_env)
|
||||
return false;
|
||||
|
||||
module_inst = (WASMModuleInstance *)exec_env->module_inst;
|
||||
if (WASM_ADDR_TYPE(addr) == WasmMemory) {
|
||||
offset = WASM_ADDR_OFFSET(addr);
|
||||
wasm_runtime_module_free((wasm_module_inst_t)module_inst, offset);
|
||||
return true;
|
||||
if (instance->exec_mem_info.start_offset == 0) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
(void)addr;
|
||||
|
||||
/* Currently we don't support to free the execution memory, simply return
|
||||
* true here */
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@ typedef enum debug_state_t {
|
|||
APP_STOPPED
|
||||
} debug_state_t;
|
||||
|
||||
typedef struct WASMDebugExecutionMemory {
|
||||
uint32 start_offset;
|
||||
uint32 size;
|
||||
uint32 current_pos;
|
||||
} WASMDebugExecutionMemory;
|
||||
|
||||
typedef struct WASMDebugInstance {
|
||||
struct WASMDebugInstance *next;
|
||||
WASMDebugControlThread *control_thread;
|
||||
|
|
@ -60,6 +66,11 @@ typedef struct WASMDebugInstance {
|
|||
* 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;
|
||||
} WASMDebugInstance;
|
||||
|
||||
typedef enum WASMDebugEventKind {
|
||||
|
|
|
|||
|
|
@ -80,6 +80,12 @@ 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);
|
||||
|
||||
int
|
||||
socket(int domain, int type, int protocol);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <wasi/api.h>
|
||||
#include <wasi_socket_ext.h>
|
||||
|
|
@ -126,6 +127,10 @@ connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
|||
__wasi_addr_t wasi_addr = { 0 };
|
||||
__wasi_errno_t error;
|
||||
|
||||
if (NULL == addr) {
|
||||
HANDLE_ERROR(__WASI_ERRNO_INVAL)
|
||||
}
|
||||
|
||||
error = sockaddr_to_wasi_addr(addr, addrlen, &wasi_addr);
|
||||
HANDLE_ERROR(error)
|
||||
|
||||
|
|
@ -143,6 +148,79 @@ listen(int sockfd, int backlog)
|
|||
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;
|
||||
__wasi_roflags_t ro_flags;
|
||||
|
||||
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 = 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 = 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 = 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 = 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;
|
||||
}
|
||||
|
||||
int
|
||||
socket(int domain, int type, int protocol)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -60,119 +60,54 @@ wasm_runtime_module_realloc(wasm_module_inst_t module, uint32 ptr, uint32 size,
|
|||
|
||||
typedef int (*out_func_t)(int c, void *ctx);
|
||||
|
||||
enum pad_type {
|
||||
PAD_NONE,
|
||||
PAD_ZERO_BEFORE,
|
||||
PAD_SPACE_BEFORE,
|
||||
PAD_SPACE_AFTER,
|
||||
};
|
||||
|
||||
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) \
|
||||
goto fail; \
|
||||
#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)
|
||||
|
||||
/**
|
||||
* @brief Output an unsigned int in hex format
|
||||
*
|
||||
* Output an unsigned int on output installed by platform at init time. Should
|
||||
* be able to handle an unsigned int of any size, 32 or 64 bit.
|
||||
* @param num Number to output
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
static void
|
||||
_printf_hex_uint(out_func_t out, void *ctx, const uint64 num, bool is_u64,
|
||||
enum pad_type padding, int min_width)
|
||||
{
|
||||
int shift = sizeof(num) * 8;
|
||||
int found_largest_digit = 0;
|
||||
int remaining = 16; /* 16 digits max */
|
||||
int digits = 0;
|
||||
char nibble;
|
||||
/* 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 (fmt - fmt_start_addr + 2 >= fmt_buf_len) { \
|
||||
bh_assert(fmt - fmt_start_addr <= UINT32_MAX - 2); \
|
||||
fmt_buf_len = 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, fmt - fmt_start_addr + 1);
|
||||
/* clang-format on */
|
||||
|
||||
while (shift >= 4) {
|
||||
shift -= 4;
|
||||
nibble = (num >> shift) & 0xf;
|
||||
|
||||
if (nibble || found_largest_digit || shift == 0) {
|
||||
found_largest_digit = 1;
|
||||
nibble = (char)(nibble + (nibble > 9 ? 87 : 48));
|
||||
out((int)nibble, ctx);
|
||||
digits++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (remaining-- <= min_width) {
|
||||
if (padding == PAD_ZERO_BEFORE) {
|
||||
out('0', ctx);
|
||||
}
|
||||
else if (padding == PAD_SPACE_BEFORE) {
|
||||
out(' ', ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (padding == PAD_SPACE_AFTER) {
|
||||
remaining = min_width * 2 - digits;
|
||||
while (remaining-- > 0) {
|
||||
out(' ', ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Output an unsigned int in decimal format
|
||||
*
|
||||
* Output an unsigned int on output installed by platform at init time. Only
|
||||
* works with 32-bit values.
|
||||
* @param num Number to output
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
static void
|
||||
_printf_dec_uint(out_func_t out, void *ctx, const uint32 num,
|
||||
enum pad_type padding, int min_width)
|
||||
{
|
||||
uint32 pos = 999999999;
|
||||
uint32 remainder = num;
|
||||
int found_largest_digit = 0;
|
||||
int remaining = 10; /* 10 digits max */
|
||||
int digits = 1;
|
||||
|
||||
/* make sure we don't skip if value is zero */
|
||||
if (min_width <= 0) {
|
||||
min_width = 1;
|
||||
}
|
||||
|
||||
while (pos >= 9) {
|
||||
if (found_largest_digit || remainder > pos) {
|
||||
found_largest_digit = 1;
|
||||
out((int)((remainder / (pos + 1)) + 48), ctx);
|
||||
digits++;
|
||||
}
|
||||
else if (remaining <= min_width && padding < PAD_SPACE_AFTER) {
|
||||
out((int)(padding == PAD_ZERO_BEFORE ? '0' : ' '), ctx);
|
||||
digits++;
|
||||
}
|
||||
remaining--;
|
||||
remainder %= (pos + 1);
|
||||
pos /= 10;
|
||||
}
|
||||
out((int)(remainder + 48), ctx);
|
||||
|
||||
if (padding == PAD_SPACE_AFTER) {
|
||||
remaining = min_width - digits;
|
||||
while (remaining-- > 0) {
|
||||
out(' ', ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
#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)
|
||||
|
|
@ -187,10 +122,10 @@ _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 '%' */
|
||||
enum pad_type padding = PAD_NONE;
|
||||
int min_width = -1;
|
||||
int long_ctr = 0;
|
||||
uint8 *native_end_addr;
|
||||
const char *fmt_start_addr = NULL;
|
||||
bool is_signed;
|
||||
|
||||
if (!wasm_runtime_get_native_addr_range(module_inst, (uint8 *)ap, NULL,
|
||||
&native_end_addr))
|
||||
|
|
@ -205,23 +140,19 @@ _vprintf_wa(out_func_t out, void *ctx, const char *fmt, _va_list ap,
|
|||
}
|
||||
else {
|
||||
might_format = 1;
|
||||
min_width = -1;
|
||||
padding = PAD_NONE;
|
||||
long_ctr = 0;
|
||||
fmt_start_addr = fmt;
|
||||
is_signed = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (*fmt) {
|
||||
case '.':
|
||||
case '+':
|
||||
case '-':
|
||||
padding = PAD_SPACE_AFTER;
|
||||
goto still_might_format;
|
||||
|
||||
case ' ':
|
||||
case '#':
|
||||
case '0':
|
||||
if (min_width < 0 && padding == PAD_NONE) {
|
||||
padding = PAD_ZERO_BEFORE;
|
||||
goto still_might_format;
|
||||
}
|
||||
goto handle_1_to_9;
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
|
|
@ -231,17 +162,12 @@ _vprintf_wa(out_func_t out, void *ctx, const char *fmt, _va_list ap,
|
|||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
handle_1_to_9:
|
||||
if (min_width < 0) {
|
||||
min_width = *fmt - '0';
|
||||
}
|
||||
else {
|
||||
min_width = 10 * min_width + *fmt - '0';
|
||||
}
|
||||
case 't': /* ptrdiff_t */
|
||||
goto still_might_format;
|
||||
|
||||
if (padding == PAD_NONE) {
|
||||
padding = PAD_SPACE_BEFORE;
|
||||
}
|
||||
case 'j':
|
||||
/* intmax_t/uintmax_t */
|
||||
long_ctr = 2;
|
||||
goto still_might_format;
|
||||
|
||||
case 'l':
|
||||
|
|
@ -252,113 +178,108 @@ _vprintf_wa(out_func_t out, void *ctx, const char *fmt, _va_list ap,
|
|||
/* FIXME: do nothing for these modifiers */
|
||||
goto still_might_format;
|
||||
|
||||
case 'o':
|
||||
case 'd':
|
||||
case 'i':
|
||||
{
|
||||
int32 d;
|
||||
|
||||
if (long_ctr < 2) {
|
||||
CHECK_VA_ARG(ap, int32);
|
||||
d = _va_arg(ap, int32);
|
||||
}
|
||||
else {
|
||||
int64 lld;
|
||||
CHECK_VA_ARG(ap, int64);
|
||||
lld = _va_arg(ap, int64);
|
||||
if (lld > INT32_MAX || lld < INT32_MIN) {
|
||||
print_err(out, ctx);
|
||||
break;
|
||||
}
|
||||
d = (int32)lld;
|
||||
}
|
||||
|
||||
if (d < 0) {
|
||||
out((int)'-', ctx);
|
||||
d = -d;
|
||||
min_width--;
|
||||
}
|
||||
_printf_dec_uint(out, ctx, (uint32)d, padding, min_width);
|
||||
break;
|
||||
}
|
||||
case 'u':
|
||||
{
|
||||
uint32 u;
|
||||
|
||||
if (long_ctr < 2) {
|
||||
CHECK_VA_ARG(ap, uint32);
|
||||
u = _va_arg(ap, uint32);
|
||||
}
|
||||
else {
|
||||
uint64 llu;
|
||||
CHECK_VA_ARG(ap, uint64);
|
||||
llu = _va_arg(ap, uint64);
|
||||
if (llu > INT32_MAX) {
|
||||
print_err(out, ctx);
|
||||
break;
|
||||
}
|
||||
u = (uint32)llu;
|
||||
}
|
||||
_printf_dec_uint(out, ctx, u, padding, min_width);
|
||||
break;
|
||||
}
|
||||
case 'p':
|
||||
out('0', ctx);
|
||||
out('x', ctx);
|
||||
/* left-pad pointers with zeros */
|
||||
padding = PAD_ZERO_BEFORE;
|
||||
min_width = 8;
|
||||
is_signed = true;
|
||||
/* Fall through */
|
||||
case 'u':
|
||||
case 'p':
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'c':
|
||||
{
|
||||
uint64 x;
|
||||
bool is_ptr = (*fmt == 'p') ? true : false;
|
||||
char buf[64];
|
||||
PREPARE_TEMP_FORMAT();
|
||||
|
||||
if (long_ctr < 2) {
|
||||
CHECK_VA_ARG(ap, uint32);
|
||||
x = _va_arg(ap, uint32);
|
||||
|
||||
if (is_signed) {
|
||||
int32 d;
|
||||
d = _va_arg(ap, int32);
|
||||
n = snprintf(buf, sizeof(buf), fmt_buf, d);
|
||||
}
|
||||
else {
|
||||
uint32 u;
|
||||
u = _va_arg(ap, uint32);
|
||||
n = snprintf(buf, sizeof(buf), fmt_buf, u);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Make 8-byte aligned */
|
||||
ap = (_va_list)(((uintptr_t)ap + 7) & ~(uintptr_t)7);
|
||||
CHECK_VA_ARG(ap, uint64);
|
||||
x = _va_arg(ap, uint64);
|
||||
|
||||
if (is_signed) {
|
||||
int64 lld;
|
||||
lld = _va_arg(ap, int64);
|
||||
n = snprintf(buf, sizeof(buf), fmt_buf, lld);
|
||||
}
|
||||
else {
|
||||
uint64 llu;
|
||||
llu = _va_arg(ap, uint64);
|
||||
n = snprintf(buf, sizeof(buf), fmt_buf, llu);
|
||||
}
|
||||
}
|
||||
_printf_hex_uint(out, ctx, x, !is_ptr, padding, min_width);
|
||||
|
||||
OUTPUT_TEMP_FORMAT();
|
||||
break;
|
||||
}
|
||||
|
||||
case 's':
|
||||
{
|
||||
char *s;
|
||||
char buf_tmp[128], *buf = buf_tmp;
|
||||
char *start;
|
||||
uint32 s_offset;
|
||||
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);
|
||||
|
||||
while (*s)
|
||||
out((int)(*s++), ctx);
|
||||
str_len = strlen(start);
|
||||
if (str_len >= UINT32_MAX - 64) {
|
||||
print_err(out, ctx);
|
||||
if (fmt_buf != temp_fmt) {
|
||||
wasm_runtime_free(fmt_buf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (padding == PAD_SPACE_AFTER) {
|
||||
int remaining = min_width - (int32)(s - start);
|
||||
while (remaining-- > 0) {
|
||||
out(' ', ctx);
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'c':
|
||||
{
|
||||
int c;
|
||||
CHECK_VA_ARG(ap, int);
|
||||
c = _va_arg(ap, int);
|
||||
out(c, ctx);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -368,22 +289,31 @@ _vprintf_wa(out_func_t out, void *ctx, const char *fmt, _va_list ap,
|
|||
break;
|
||||
}
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'f':
|
||||
case 'F':
|
||||
{
|
||||
float64 f64;
|
||||
char buf[16], *s;
|
||||
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);
|
||||
snprintf(buf, sizeof(buf), "%f", f64);
|
||||
s = buf;
|
||||
while (*s)
|
||||
out((int)(*s++), ctx);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -112,7 +112,6 @@ wasi_args_get(wasm_exec_env_t exec_env, uint32 *argv_offsets, char *argv_buf)
|
|||
|
||||
for (i = 0; i < argc; i++)
|
||||
argv_offsets[i] = addr_native_to_app(argv[i]);
|
||||
argv_offsets[argc] = 0;
|
||||
|
||||
wasm_runtime_free(argv);
|
||||
return 0;
|
||||
|
|
@ -208,7 +207,6 @@ wasi_environ_get(wasm_exec_env_t exec_env, uint32 *environ_offsets,
|
|||
|
||||
for (i = 0; i < environ_count; i++)
|
||||
environ_offsets[i] = addr_native_to_app(environs[i]);
|
||||
environ_offsets[environ_count] = 0;
|
||||
|
||||
wasm_runtime_free(environs);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -131,7 +131,6 @@ wasi_args_get(wasm_exec_env_t exec_env, uint32 *argv_offsets, char *argv_buf)
|
|||
|
||||
for (i = 0; i < argc; i++)
|
||||
argv_offsets[i] = addr_native_to_app(argv[i]);
|
||||
argv_offsets[argc] = 0;
|
||||
|
||||
wasm_runtime_free(argv);
|
||||
return 0;
|
||||
|
|
@ -234,7 +233,6 @@ wasi_environ_get(wasm_exec_env_t exec_env, uint32 *environ_offsets,
|
|||
|
||||
for (i = 0; i < environ_count; i++)
|
||||
environ_offsets[i] = addr_native_to_app(environs[i]);
|
||||
environ_offsets[environ_count] = 0;
|
||||
|
||||
wasm_runtime_free(environs);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -9,21 +9,194 @@
|
|||
|
||||
#define TRACE_OCALL_FAIL() os_printf("ocall %s failed!\n", __FUNCTION__)
|
||||
|
||||
/** OCALLs prototypes **/
|
||||
int
|
||||
ocall_socket(int *p_ret, int domain, int type, int protocol);
|
||||
ocall_accept(int *p_ret, int sockfd, void *addr, uint32_t *addrlen,
|
||||
uint32_t addr_size);
|
||||
|
||||
int
|
||||
ocall_bind(int *p_ret, int sockfd, const void *addr, uint32_t addrlen);
|
||||
|
||||
int
|
||||
ocall_close(int *p_ret, int fd);
|
||||
|
||||
int
|
||||
ocall_connect(int *p_ret, int sockfd, void *addr, uint32_t addrlen);
|
||||
|
||||
int
|
||||
ocall_fcntl_long(int *p_ret, int fd, int cmd, long arg);
|
||||
|
||||
int
|
||||
ocall_getsockname(int *p_ret, int sockfd, void *addr, uint32_t *addrlen,
|
||||
uint32_t addr_size);
|
||||
|
||||
int
|
||||
ocall_getsockopt(int *p_ret, int sockfd, int level, int optname, void *val_buf,
|
||||
unsigned int val_buf_size, void *len_buf);
|
||||
|
||||
int
|
||||
ocall_sendmsg(ssize_t *p_ret, int sockfd, void *msg_buf,
|
||||
unsigned int msg_buf_size, int flags);
|
||||
ocall_listen(int *p_ret, int sockfd, int backlog);
|
||||
|
||||
int
|
||||
ocall_recv(int *p_ret, int sockfd, void *buf, size_t len, int flags);
|
||||
|
||||
int
|
||||
ocall_recvmsg(ssize_t *p_ret, int sockfd, void *msg_buf,
|
||||
unsigned int msg_buf_size, int flags);
|
||||
|
||||
int
|
||||
ocall_send(int *p_ret, int sockfd, const void *buf, size_t len, int flags);
|
||||
|
||||
int
|
||||
ocall_sendmsg(ssize_t *p_ret, int sockfd, void *msg_buf,
|
||||
unsigned int msg_buf_size, int flags);
|
||||
|
||||
int
|
||||
ocall_setsockopt(int *p_ret, int sockfd, int level, int optname, void *optval,
|
||||
unsigned int optlen);
|
||||
|
||||
int
|
||||
ocall_shutdown(int *p_ret, int sockfd, int how);
|
||||
|
||||
int
|
||||
ocall_socket(int *p_ret, int domain, int type, int protocol);
|
||||
/** OCALLs prototypes end **/
|
||||
|
||||
/** In-enclave implementation of POSIX functions **/
|
||||
static bool
|
||||
is_little_endian()
|
||||
{
|
||||
long i = 0x01020304;
|
||||
unsigned char *c = (unsigned char *)&i;
|
||||
return (*c == 0x04) ? true : false;
|
||||
}
|
||||
|
||||
static void
|
||||
swap32(uint8 *pData)
|
||||
{
|
||||
uint8 value = *pData;
|
||||
*pData = *(pData + 3);
|
||||
*(pData + 3) = value;
|
||||
|
||||
value = *(pData + 1);
|
||||
*(pData + 1) = *(pData + 2);
|
||||
*(pData + 2) = value;
|
||||
}
|
||||
|
||||
static void
|
||||
swap16(uint8 *pData)
|
||||
{
|
||||
uint8 value = *pData;
|
||||
*(pData) = *(pData + 1);
|
||||
*(pData + 1) = value;
|
||||
}
|
||||
|
||||
static uint32
|
||||
htonl(uint32 value)
|
||||
{
|
||||
uint32 ret;
|
||||
if (is_little_endian()) {
|
||||
ret = value;
|
||||
swap32((uint8 *)&ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint32
|
||||
ntohl(uint32 value)
|
||||
{
|
||||
return htonl(value);
|
||||
}
|
||||
|
||||
static uint16
|
||||
htons(uint16 value)
|
||||
{
|
||||
uint16 ret;
|
||||
if (is_little_endian()) {
|
||||
ret = value;
|
||||
swap16((uint8 *)&ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint16
|
||||
ntohs(uint16 value)
|
||||
{
|
||||
return htons(value);
|
||||
}
|
||||
|
||||
/* Coming from musl, under MIT license */
|
||||
static int
|
||||
__inet_aton(const char *s0, struct in_addr *dest)
|
||||
{
|
||||
const char *s = s0;
|
||||
unsigned char *d = (void *)dest;
|
||||
unsigned long a[4] = { 0 };
|
||||
char *z;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
a[i] = strtoul(s, &z, 0);
|
||||
if (z == s || (*z && *z != '.') || !isdigit(*s))
|
||||
return 0;
|
||||
if (!*z)
|
||||
break;
|
||||
s = z + 1;
|
||||
}
|
||||
if (i == 4)
|
||||
return 0;
|
||||
switch (i) {
|
||||
case 0:
|
||||
a[1] = a[0] & 0xffffff;
|
||||
a[0] >>= 24;
|
||||
case 1:
|
||||
a[2] = a[1] & 0xffff;
|
||||
a[1] >>= 16;
|
||||
case 2:
|
||||
a[3] = a[2] & 0xff;
|
||||
a[2] >>= 8;
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (a[i] > 255)
|
||||
return 0;
|
||||
d[i] = a[i];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Coming from musl, under MIT license */
|
||||
static int
|
||||
inet_addr(const char *p)
|
||||
{
|
||||
struct in_addr a;
|
||||
if (!__inet_aton(p, &a))
|
||||
return -1;
|
||||
return a.s_addr;
|
||||
}
|
||||
|
||||
static int
|
||||
inet_network(const char *p)
|
||||
{
|
||||
return ntohl(inet_addr(p));
|
||||
}
|
||||
/** In-enclave implementation of POSIX functions end **/
|
||||
|
||||
static int
|
||||
textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr_in *out)
|
||||
{
|
||||
assert(textual);
|
||||
|
||||
out->sin_family = AF_INET;
|
||||
out->sin_port = htons(port);
|
||||
out->sin_addr.s_addr = inet_addr(textual);
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
socket(int domain, int type, int protocol)
|
||||
{
|
||||
|
|
@ -232,67 +405,219 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
|
|||
unsigned int *addrlen)
|
||||
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
struct sockaddr addr_tmp;
|
||||
unsigned int len = sizeof(struct sockaddr);
|
||||
|
||||
if (ocall_accept(sock, server_sock, &addr_tmp, &len, len) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*sock < 0) {
|
||||
errno = get_errno();
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
int
|
||||
os_socket_bind(bh_socket_t socket, const char *host, int *port)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
struct sockaddr_in addr;
|
||||
struct linger ling;
|
||||
unsigned int socklen;
|
||||
int ret;
|
||||
|
||||
assert(host);
|
||||
assert(port);
|
||||
|
||||
ling.l_onoff = 1;
|
||||
ling.l_linger = 0;
|
||||
|
||||
if (ocall_fcntl_long(&ret, socket, F_SETFD, FD_CLOEXEC) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ocall_setsockopt(&ret, socket, SOL_SOCKET, SO_LINGER, &ling,
|
||||
sizeof(ling))
|
||||
!= SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
addr.sin_addr.s_addr = inet_addr(host);
|
||||
addr.sin_port = htons(*port);
|
||||
addr.sin_family = AF_INET;
|
||||
|
||||
if (ocall_bind(&ret, socket, &addr, sizeof(addr)) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
socklen = sizeof(addr);
|
||||
|
||||
if (ocall_getsockname(&ret, socket, (void *)&addr, &socklen, socklen)
|
||||
!= SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == -1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*port = ntohs(addr.sin_port);
|
||||
|
||||
return BHT_OK;
|
||||
|
||||
fail:
|
||||
errno = get_errno();
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_close(bh_socket_t socket)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
int ret;
|
||||
|
||||
if (ocall_close(&ret, socket) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
errno = get_errno();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_connect(bh_socket_t socket, const char *addr, int port)
|
||||
{}
|
||||
{
|
||||
struct sockaddr_in addr_in = { 0 };
|
||||
socklen_t addr_len = sizeof(struct sockaddr_in);
|
||||
int ret = 0;
|
||||
|
||||
if ((ret = textual_addr_to_sockaddr(addr, port, &addr_in)) < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ocall_connect(&ret, socket, &addr_in, addr_len) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
errno = get_errno();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_create(bh_socket_t *sock, int tcp_or_udp)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
if (!sock) {
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
if (1 == tcp_or_udp) {
|
||||
if (ocall_socket(sock, AF_INET, SOCK_STREAM, IPPROTO_TCP)
|
||||
!= SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == tcp_or_udp) {
|
||||
if (ocall_socket(sock, AF_INET, SOCK_DGRAM, 0) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (*sock == -1) {
|
||||
errno = get_errno();
|
||||
return BHT_ERROR;
|
||||
}
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_inet_network(const char *cp, uint32 *out)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
if (!cp)
|
||||
return BHT_ERROR;
|
||||
|
||||
*out = inet_network(cp);
|
||||
|
||||
return BHT_OK;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_listen(bh_socket_t socket, int max_client)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
int ret;
|
||||
|
||||
if (ocall_listen(&ret, socket, max_client) != SGX_SUCCESS) {
|
||||
TRACE_OCALL_FAIL();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
errno = get_errno();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_recv(bh_socket_t socket, void *buf, unsigned int len)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
int ret;
|
||||
|
||||
if (ocall_recv(&ret, socket, buf, len, 0) != SGX_SUCCESS) {
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
errno = get_errno();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_send(bh_socket_t socket, const void *buf, unsigned int len)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
int ret;
|
||||
|
||||
if (ocall_send(&ret, socket, buf, len, 0) != SGX_SUCCESS) {
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
errno = get_errno();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
os_socket_shutdown(bh_socket_t socket)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
return shutdown(socket, O_RDWR);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ extern "C" {
|
|||
|
||||
#define SOL_SOCKET 1
|
||||
|
||||
#define SO_TYPE 3
|
||||
#define SO_LINGER 13
|
||||
|
||||
#define SOCK_STREAM 1
|
||||
#define SOCK_DGRAM 2
|
||||
|
||||
#define SO_TYPE 3
|
||||
|
||||
#define MSG_OOB 0x0001
|
||||
#define MSG_PEEK 0x0002
|
||||
#define MSG_DONTROUTE 0x0004
|
||||
|
|
@ -44,6 +45,16 @@ extern "C" {
|
|||
#define SHUT_WR 1
|
||||
#define SHUT_RDWR 2
|
||||
|
||||
/* Address families. */
|
||||
#define AF_INET 2 /* IP protocol family. */
|
||||
|
||||
/* Standard well-defined IP protocols. */
|
||||
#define IPPROTO_TCP 6 /* Transmission Control Protocol. */
|
||||
|
||||
/* Types of sockets. */
|
||||
#define SOCK_DGRAM \
|
||||
2 /* Connectionless, unreliable datagrams of fixed maximum length. */
|
||||
|
||||
struct msghdr {
|
||||
void *msg_name;
|
||||
socklen_t msg_namelen;
|
||||
|
|
@ -54,6 +65,36 @@ struct msghdr {
|
|||
int msg_flags;
|
||||
};
|
||||
|
||||
/* Internet address. */
|
||||
struct in_addr {
|
||||
uint32_t s_addr;
|
||||
};
|
||||
typedef struct in_addr in_addr_t;
|
||||
|
||||
/* Structure describing an Internet socket address. */
|
||||
#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
|
||||
struct sockaddr_in {
|
||||
uint16_t sin_family;
|
||||
uint16_t sin_port; /* Port number. */
|
||||
struct in_addr sin_addr; /* Internet address. */
|
||||
|
||||
/* Pad to size of `struct sockaddr'. */
|
||||
unsigned char__pad[__SOCK_SIZE__ - sizeof(uint16_t) - sizeof(uint16_t)
|
||||
- sizeof(struct in_addr)];
|
||||
};
|
||||
|
||||
/* Structure used to manipulate the SO_LINGER option. */
|
||||
struct linger {
|
||||
int l_onoff; /* Nonzero to linger on close. */
|
||||
int l_linger; /* Time to linger. */
|
||||
};
|
||||
|
||||
/* Structure describing a generic socket address. */
|
||||
struct sockaddr {
|
||||
unsigned short int sa_family; /* Common data: address family and length. */
|
||||
char sa_data[14]; /* Address data. */
|
||||
};
|
||||
|
||||
int
|
||||
socket(int domain, int type, int protocol);
|
||||
|
||||
|
|
|
|||
|
|
@ -118,19 +118,34 @@ enclave {
|
|||
int ocall_pthread_rwlock_unlock([user_check]void *rwlock);
|
||||
|
||||
int ocall_get_errno();
|
||||
int ocall_socket(int domain, int type, int protocol);
|
||||
|
||||
/* sockets */
|
||||
int ocall_accept(int sockfd, [in, size=addr_size]void *addr,
|
||||
[in, size=4] uint32_t *addrlen, uint32_t addr_size);
|
||||
int ocall_bind(int sockfd, [in, size=addrlen]const void *addr,
|
||||
uint32_t addrlen);
|
||||
int ocall_connect(int sockfd, [in, size=addrlen]void *addr, uint32_t addrlen);
|
||||
int ocall_getsockname(int sockfd, [in, size=addr_size]void *addr,
|
||||
[in, out, size=4]uint32_t *addrlen, uint32_t addr_size);
|
||||
int ocall_getsockopt(int sockfd, int level, int optname,
|
||||
[out, size=val_buf_size]void *val_buf,
|
||||
unsigned int val_buf_size,
|
||||
[in, out, size=4]void *len_buf);
|
||||
ssize_t ocall_sendmsg(int sockfd,
|
||||
[in, size=msg_buf_size]void *msg_buf,
|
||||
unsigned int msg_buf_size,
|
||||
int flags);
|
||||
int ocall_listen(int sockfd, int backlog);
|
||||
int ocall_recv(int sockfd, [out, size=len]void *buf, size_t len, int flags);
|
||||
ssize_t ocall_recvmsg(int sockfd,
|
||||
[in, out, size=msg_buf_size]void *msg_buf,
|
||||
unsigned int msg_buf_size,
|
||||
int flags);
|
||||
int ocall_send(int sockfd, [in, size=len]const void *buf, size_t len, int flags);
|
||||
ssize_t ocall_sendmsg(int sockfd,
|
||||
[in, size=msg_buf_size]void *msg_buf,
|
||||
unsigned int msg_buf_size,
|
||||
int flags);
|
||||
int ocall_setsockopt(int sockfd, int level, int optname,
|
||||
[in, size=optlen]void *optval,
|
||||
unsigned int optlen);
|
||||
int ocall_shutdown(int sockfd, int how);
|
||||
int ocall_socket(int domain, int type, int protocol);
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
#include <sys/socket.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
int
|
||||
ocall_socket(int domain, int type, int protocol)
|
||||
|
|
@ -72,4 +74,53 @@ int
|
|||
ocall_shutdown(int sockfd, int how)
|
||||
{
|
||||
return shutdown(sockfd, how);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_setsockopt(int sockfd, int level, int optname, void *optval,
|
||||
unsigned int optlen)
|
||||
{
|
||||
return setsockopt(sockfd, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_bind(int sockfd, const void *addr, uint32_t addrlen)
|
||||
{
|
||||
return bind(sockfd, (const struct sockaddr *)addr, addrlen);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_getsockname(int sockfd, void *addr, uint32_t *addrlen, uint32_t addr_size)
|
||||
{
|
||||
return getsockname(sockfd, (struct sockaddr *)addr, addrlen);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_listen(int sockfd, int backlog)
|
||||
{
|
||||
return listen(sockfd, backlog);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_accept(int sockfd, void *addr, uint32_t *addrlen, uint32_t addr_size)
|
||||
{
|
||||
return accept(sockfd, (struct sockaddr *)addr, addrlen);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_recv(int sockfd, void *buf, size_t len, int flags)
|
||||
{
|
||||
return recv(sockfd, buf, len, flags);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_send(int sockfd, const void *buf, size_t len, int flags)
|
||||
{
|
||||
return send(sockfd, buf, len, flags);
|
||||
}
|
||||
|
||||
int
|
||||
ocall_connect(int sockfd, void *addr, uint32_t addrlen)
|
||||
{
|
||||
return connect(sockfd, (const struct sockaddr *)addr, addrlen);
|
||||
}
|
||||
|
|
@ -66,6 +66,9 @@ cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM
|
|||
#### **Enable shared memory feature**
|
||||
- **WAMR_BUILD_SHARED_MEMORY**=1/0, default to disable if not set
|
||||
|
||||
#### **Enable bulk memory feature**
|
||||
- **WAMR_BUILD_BULK_MEMORY**=1/0, default to disable if not set
|
||||
|
||||
#### **Enable thread manager**
|
||||
- **WAMR_BUILD_THREAD_MGR**=1/0, default to disable if not set
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ and `socket()`. Users can call those functions in WebAssembly code directly.
|
|||
Those WebAssembly socket calls will be dispatched to the imported
|
||||
functions and eventually will be implemented by host socket APIs.
|
||||
|
||||
This document introduces a way to support _Berkeley/Posix Socket APIs_ in
|
||||
This document introduces a way to support the _Berkeley/POSIX Socket API_ in
|
||||
WebAssembly code.
|
||||
|
||||
## Patch the native code
|
||||
|
|
@ -24,7 +24,7 @@ native source code.
|
|||
#endif
|
||||
```
|
||||
|
||||
`__wasi__` is a Marco defined by WASI. The host compiler will not enable it.
|
||||
`__wasi__` is a macro defined by WASI. The host compiler will not enable it.
|
||||
|
||||
## CMake files
|
||||
|
||||
|
|
@ -57,10 +57,25 @@ The _iwasm_ should be compiled with `WAMR_BUILD_LIBC_WASI=1`. By default, it is
|
|||
enabled.
|
||||
|
||||
_iwasm_ accepts address ranges via an option, `--addr-pool`, to implement
|
||||
the capability control. All IP address the WebAssebmly application may need to `bind()` or `connect()` should be announced first. Every IP address should be in CIRD notation.
|
||||
the capability control. All IP address the WebAssembly application may need to `bind()` or `connect()`
|
||||
should be announced first. Every IP address should be in CIRD notation.
|
||||
|
||||
```bash
|
||||
$ iwasm --addr-pool=1.2.3.4/15,2.3.4.6/16 socket_example.wasm
|
||||
```
|
||||
|
||||
Refer to [socket api sample](../samples/socket-api) for more details.
|
||||
|
||||
## Intel SGX support
|
||||
|
||||
WAMR also supports the socket API within Intel SGX enclaves.
|
||||
|
||||
The _iwasm_ should be compiled with `WAMR_BUILD_LIBC_WASI=1` and `WAMR_BUILD_LIB_PTHREAD=1`, which are enabled by default.
|
||||
|
||||
Similarly to running _iwasm_ outside of an enclave, the allowed address ranges are given via the option `--addr-pool`.
|
||||
|
||||
```bash
|
||||
$ iwasm --addr-pool=1.2.3.4/15,2.3.4.6/16 socket_example.wasm
|
||||
```
|
||||
|
||||
Refer to [socket api sample](../samples/socket-api) for the compilation of the Wasm applications and [_iwasm_ for Intel SGX](../product-mini/platforms/linux-sgx) for the Wasm runtime.
|
||||
|
|
@ -227,6 +227,10 @@ print_help()
|
|||
printf(" --dir=<dir> Grant wasi access to the given host directories\n");
|
||||
printf(" to the program, for example:\n");
|
||||
printf(" --dir=<dir1> --dir=<dir2>\n");
|
||||
printf(" --addr-pool= Grant wasi access to the given network addresses in\n");
|
||||
printf(" CIRD notation to the program, seperated with ',',\n");
|
||||
printf(" for example:\n");
|
||||
printf(" --addr-pool=1.2.3.4/15,2.3.4.5/16\n");
|
||||
printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n");
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -550,9 +554,10 @@ app_instance_func(void *wasm_module_inst, const char *func_name, int app_argc,
|
|||
static bool
|
||||
set_wasi_args(void *wasm_module, const char **dir_list, uint32_t dir_list_size,
|
||||
const char **env_list, uint32_t env_list_size, int stdinfd,
|
||||
int stdoutfd, int stderrfd, char **argv, uint32_t argc)
|
||||
int stdoutfd, int stderrfd, char **argv, uint32_t argc,
|
||||
const char **addr_pool, uint32_t addr_pool_size)
|
||||
{
|
||||
uint64_t ecall_args[10];
|
||||
uint64_t ecall_args[12];
|
||||
|
||||
ecall_args[0] = (uint64_t)(uintptr_t)wasm_module;
|
||||
ecall_args[1] = (uint64_t)(uintptr_t)dir_list;
|
||||
|
|
@ -564,9 +569,11 @@ set_wasi_args(void *wasm_module, const char **dir_list, uint32_t dir_list_size,
|
|||
ecall_args[7] = stderrfd;
|
||||
ecall_args[8] = (uint64_t)(uintptr_t)argv;
|
||||
ecall_args[9] = argc;
|
||||
ecall_args[10] = (uint64_t)(uintptr_t)addr_pool;
|
||||
ecall_args[11] = addr_pool_size;
|
||||
if (SGX_SUCCESS
|
||||
!= ecall_handle_command(g_eid, CMD_SET_WASI_ARGS, (uint8_t *)ecall_args,
|
||||
sizeof(uint64_t) * 10)) {
|
||||
sizeof(uint64_t) * 12)) {
|
||||
printf("Call ecall_handle_command() failed.\n");
|
||||
}
|
||||
|
||||
|
|
@ -590,6 +597,8 @@ main(int argc, char *argv[])
|
|||
uint32_t dir_list_size = 0;
|
||||
const char *env_list[8] = { NULL };
|
||||
uint32_t env_list_size = 0;
|
||||
const char *addr_pool[8] = { NULL };
|
||||
uint32_t addr_pool_size = 0;
|
||||
uint32_t max_thread_num = 4;
|
||||
|
||||
if (enclave_init(&g_eid) < 0) {
|
||||
|
|
@ -666,6 +675,26 @@ main(int argc, char *argv[])
|
|||
return print_help();
|
||||
}
|
||||
}
|
||||
/* TODO: parse the configuration file via --addr-pool-file */
|
||||
else if (!strncmp(argv[0], "--addr-pool=", strlen("--addr-pool="))) {
|
||||
/* like: --addr-pool=100.200.244.255/30 */
|
||||
char *token = NULL;
|
||||
|
||||
if ('\0' == argv[0][12])
|
||||
return print_help();
|
||||
|
||||
token = strtok(argv[0] + strlen("--addr-pool="), ",");
|
||||
while (token) {
|
||||
if (addr_pool_size >= sizeof(addr_pool) / sizeof(char *)) {
|
||||
printf("Only allow max address number %d\n",
|
||||
(int)(sizeof(addr_pool) / sizeof(char *)));
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr_pool[addr_pool_size++] = token;
|
||||
token = strtok(NULL, ";");
|
||||
}
|
||||
}
|
||||
else if (!strncmp(argv[0], "--max-threads=", 14)) {
|
||||
if (argv[0][14] == '\0')
|
||||
return print_help();
|
||||
|
|
@ -705,7 +734,8 @@ main(int argc, char *argv[])
|
|||
|
||||
/* Set wasi arguments */
|
||||
if (!set_wasi_args(wasm_module, dir_list, dir_list_size, env_list,
|
||||
env_list_size, 0, 1, 2, argv, argc)) {
|
||||
env_list_size, 0, 1, 2, argv, argc, addr_pool,
|
||||
addr_pool_size)) {
|
||||
printf("%s\n", "set wasi arguments failed.\n");
|
||||
goto fail3;
|
||||
}
|
||||
|
|
@ -771,6 +801,8 @@ wamr_pal_create_process(struct wamr_pal_create_process_args *args)
|
|||
uint32_t dir_list_size = 0;
|
||||
const char *env_list[8] = { NULL };
|
||||
uint32_t env_list_size = 0;
|
||||
const char *addr_pool[8] = { NULL };
|
||||
uint32_t addr_pool_size = 0;
|
||||
uint32_t max_thread_num = 4;
|
||||
char *wasm_files[16];
|
||||
void *wasm_module_inst[16];
|
||||
|
|
@ -845,7 +877,7 @@ wamr_pal_create_process(struct wamr_pal_create_process_args *args)
|
|||
/* Set wasi arguments */
|
||||
if (!set_wasi_args(wasm_module, dir_list, dir_list_size, env_list,
|
||||
env_list_size, stdinfd, stdoutfd, stderrfd, argv,
|
||||
argc)) {
|
||||
argc, addr_pool, addr_pool_size)) {
|
||||
printf("%s\n", "set wasi arguments failed.\n");
|
||||
unload_module(wasm_module);
|
||||
free(wasm_file_buf);
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ typedef struct EnclaveModule {
|
|||
uint32 wasi_dir_list_size;
|
||||
char **wasi_env_list;
|
||||
uint32 wasi_env_list_size;
|
||||
char **wasi_addr_pool_list;
|
||||
uint32 wasi_addr_pool_list_size;
|
||||
char **wasi_argv;
|
||||
uint32 wasi_argc;
|
||||
bool is_xip_file;
|
||||
|
|
@ -407,6 +409,8 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc)
|
|||
char **wasi_argv = *(char ***)args++;
|
||||
char *p, *p1;
|
||||
uint32 wasi_argc = *(uint32 *)args++;
|
||||
char **addr_pool_list = *(char ***)args++;
|
||||
uint32 addr_pool_list_size = *(uint32 *)args++;
|
||||
uint64 total_size = 0;
|
||||
int32 i, str_len;
|
||||
|
||||
|
|
@ -414,6 +418,7 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc)
|
|||
|
||||
total_size += sizeof(char *) * (uint64)dir_list_size
|
||||
+ sizeof(char *) * (uint64)env_list_size
|
||||
+ sizeof(char *) * (uint64)addr_pool_list_size
|
||||
+ sizeof(char *) * (uint64)wasi_argc;
|
||||
|
||||
for (i = 0; i < dir_list_size; i++) {
|
||||
|
|
@ -424,6 +429,10 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc)
|
|||
total_size += strlen(env_list[i]) + 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < addr_pool_list_size; i++) {
|
||||
total_size += strlen(addr_pool_list[i]) + 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < wasi_argc; i++) {
|
||||
total_size += strlen(wasi_argv[i]) + 1;
|
||||
}
|
||||
|
|
@ -436,7 +445,7 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc)
|
|||
}
|
||||
|
||||
p1 = p + sizeof(char *) * dir_list_size + sizeof(char *) * env_list_size
|
||||
+ sizeof(char *) * wasi_argc;
|
||||
+ sizeof(char *) * addr_pool_list_size + sizeof(char *) * wasi_argc;
|
||||
|
||||
if (dir_list_size > 0) {
|
||||
enclave_module->wasi_dir_list = (char **)p;
|
||||
|
|
@ -462,6 +471,18 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc)
|
|||
p += sizeof(char *) * env_list_size;
|
||||
}
|
||||
|
||||
if (addr_pool_list_size > 0) {
|
||||
enclave_module->wasi_addr_pool_list = (char **)p;
|
||||
enclave_module->wasi_addr_pool_list_size = addr_pool_list_size;
|
||||
for (i = 0; i < addr_pool_list_size; i++) {
|
||||
enclave_module->wasi_addr_pool_list[i] = p1;
|
||||
str_len = strlen(addr_pool_list[i]);
|
||||
bh_memcpy_s(p1, str_len + 1, addr_pool_list[i], str_len + 1);
|
||||
p1 += str_len + 1;
|
||||
}
|
||||
p += sizeof(char *) * addr_pool_list_size;
|
||||
}
|
||||
|
||||
if (wasi_argc > 0) {
|
||||
enclave_module->wasi_argv = (char **)p;
|
||||
enclave_module->wasi_argc = wasi_argc;
|
||||
|
|
@ -481,6 +502,11 @@ handle_cmd_set_wasi_args(uint64 *args, int32 argc)
|
|||
(stdinfd != -1) ? stdinfd : 0, (stdoutfd != -1) ? stdoutfd : 1,
|
||||
(stderrfd != -1) ? stderrfd : 2);
|
||||
|
||||
wasm_runtime_set_wasi_addr_pool(
|
||||
enclave_module->module,
|
||||
(const char **)enclave_module->wasi_addr_pool_list,
|
||||
addr_pool_list_size);
|
||||
|
||||
*args_org = true;
|
||||
}
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -89,14 +89,17 @@ ExternalProject_Add(wasm-app
|
|||
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy
|
||||
tcp_client.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build
|
||||
tcp_server.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build
|
||||
tcp_client.wasm.dump ${CMAKE_CURRENT_SOURCE_DIR}/build
|
||||
tcp_server.wasm.dump ${CMAKE_CURRENT_SOURCE_DIR}/build
|
||||
send_recv.wasm ${CMAKE_CURRENT_SOURCE_DIR}/build
|
||||
)
|
||||
|
||||
add_executable(tcp_server ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_server.c)
|
||||
target_link_libraries(tcp_server pthread)
|
||||
|
||||
add_executable(tcp_client ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/tcp_client.c)
|
||||
|
||||
add_executable(send_recv ${CMAKE_CURRENT_SOURCE_DIR}/wasm-src/send_recv.c)
|
||||
target_link_libraries(send_recv pthread)
|
||||
|
||||
############################################
|
||||
## Build iwasm with wasi and pthread support
|
||||
############################################
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
"socket-api" sample introduction
|
||||
================================
|
||||
# "socket-api" sample introduction
|
||||
|
||||
This sample demonstrates how to use WAMR socket-api to develop wasm network applications.
|
||||
Two wasm applications are provided: tcp-server and tcp-client, and this sample demonstrates
|
||||
|
|
@ -19,26 +18,30 @@ cmake ..
|
|||
make
|
||||
```
|
||||
|
||||
The file `tcp_server.wasm`, `tcp_client.wasm` and `iwasm` will be created.
|
||||
And also file `tcp_server` and `tcp_client` of native version are created.
|
||||
`iwasm` and three Wasm modules, `tcp_server.wasm`, `tcp_client.wasm`, `send_recv.wasm`
|
||||
will be generated. And their corresponding native version, `tcp_server`,
|
||||
`tcp_client`, `send_recv` are generated too.
|
||||
|
||||
Note that iwasm is built with libc-wasi and lib-pthread enabled.
|
||||
> Note that iwasm is built with libc-wasi and lib-pthread enabled.
|
||||
|
||||
## Run workload
|
||||
|
||||
Start the tcp server, which opens port 1234 and waits for clients to connect.
|
||||
|
||||
```bash
|
||||
cd build
|
||||
./iwasm --addr-pool=0.0.0.0/15 tcp_server.wasm
|
||||
```
|
||||
|
||||
Start the tcp client, which connects the server and receives message.
|
||||
|
||||
```bash
|
||||
cd build
|
||||
./iwasm --addr-pool=127.0.0.1/15 tcp_client.wasm
|
||||
```
|
||||
|
||||
The output of client is like:
|
||||
|
||||
```bash
|
||||
[Client] Create socket
|
||||
[Client] Connect socket
|
||||
|
|
@ -54,4 +57,29 @@ Say Hi from the Server
|
|||
[Client] BYE
|
||||
```
|
||||
|
||||
`send_recv.wasm` contains a thread as a server and a thread as a client. They
|
||||
send and receive data via 127.0.0.1:1234.
|
||||
|
||||
```bash
|
||||
$ ./iwasm --addr-pool=127.0.0.1/0 ./send_recv.wasm
|
||||
```
|
||||
|
||||
The output is:
|
||||
|
||||
```bash
|
||||
Server is online ...
|
||||
Client is running...
|
||||
Start receiving.
|
||||
Start sending.
|
||||
Send 106 bytes successfully!
|
||||
Receive 106 bytes successlly!
|
||||
Data:
|
||||
The stars shine down
|
||||
It brings us light
|
||||
Light comes down
|
||||
To make us paths
|
||||
It watches us
|
||||
And mourns for us
|
||||
```
|
||||
|
||||
Refer to [socket api document](../../doc/socket_api.md) for more details.
|
||||
|
|
|
|||
|
|
@ -78,3 +78,4 @@ endfunction()
|
|||
|
||||
compile_with_clang(tcp_server.c)
|
||||
compile_with_clang(tcp_client.c)
|
||||
compile_with_clang(send_recv.c)
|
||||
|
|
|
|||
209
samples/socket-api/wasm-src/send_recv.c
Normal file
209
samples/socket-api/wasm-src/send_recv.c
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#ifdef __wasi__
|
||||
#include <wasi_socket_ext.h>
|
||||
#endif
|
||||
|
||||
static pthread_mutex_t lock = { 0 };
|
||||
static pthread_cond_t cond = { 0 };
|
||||
static bool server_is_ready = false;
|
||||
|
||||
void *
|
||||
run_as_server(void *arg)
|
||||
{
|
||||
int sock = -1, on = 1;
|
||||
struct sockaddr_in addr = { 0 };
|
||||
int addrlen = 0;
|
||||
int new_sock = -1;
|
||||
char *buf[] = {
|
||||
"The stars shine down", "It brings us light", "Light comes down",
|
||||
"To make us paths", "It watches us", "And mourns for us",
|
||||
};
|
||||
struct iovec iov[] = {
|
||||
{ .iov_base = buf[0], .iov_len = strlen(buf[0]) + 1 },
|
||||
{ .iov_base = buf[1], .iov_len = strlen(buf[1]) + 1 },
|
||||
{ .iov_base = buf[2], .iov_len = strlen(buf[2]) + 1 },
|
||||
{ .iov_base = buf[3], .iov_len = strlen(buf[3]) + 1 },
|
||||
{ .iov_base = buf[4], .iov_len = strlen(buf[4]) + 1 },
|
||||
{ .iov_base = buf[5], .iov_len = strlen(buf[5]) + 1 },
|
||||
};
|
||||
struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 6 };
|
||||
ssize_t send_len = 0;
|
||||
|
||||
pthread_mutex_lock(&lock);
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
perror("Create a socket failed");
|
||||
goto RETURN;
|
||||
}
|
||||
|
||||
#ifndef __wasi__
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) {
|
||||
perror("Setsockopt failed");
|
||||
goto RETURN;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 0.0.0.0:1234 */
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(1234);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
addrlen = sizeof(addr);
|
||||
if (bind(sock, (struct sockaddr *)&addr, addrlen) < 0) {
|
||||
perror("Bind failed");
|
||||
goto UNLOCK_SHUTDOWN;
|
||||
}
|
||||
|
||||
if (listen(sock, 0) < 0) {
|
||||
perror("Listen failed");
|
||||
goto UNLOCK_SHUTDOWN;
|
||||
}
|
||||
|
||||
server_is_ready = true;
|
||||
pthread_cond_signal(&cond);
|
||||
pthread_mutex_unlock(&lock);
|
||||
|
||||
printf("Server is online ... \n");
|
||||
|
||||
new_sock = accept(sock, (struct sockaddr *)&addr, (socklen_t *)&addrlen);
|
||||
if (new_sock < 0) {
|
||||
perror("Accept failed");
|
||||
goto SHUTDOWN;
|
||||
}
|
||||
|
||||
printf("Start sending. \n");
|
||||
send_len = sendmsg(new_sock, &msg, 0);
|
||||
if (send_len < 0) {
|
||||
perror("Sendmsg failed");
|
||||
goto SHUTDOWN;
|
||||
}
|
||||
printf("Send %ld bytes successfully!\n", send_len);
|
||||
|
||||
SHUTDOWN:
|
||||
shutdown(sock, SHUT_RD);
|
||||
return NULL;
|
||||
|
||||
UNLOCK_SHUTDOWN:
|
||||
shutdown(sock, SHUT_RD);
|
||||
RETURN:
|
||||
pthread_mutex_unlock(&lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *
|
||||
run_as_client(void *arg)
|
||||
{
|
||||
int sock = -1;
|
||||
struct sockaddr_in addr = { 0 };
|
||||
char buf[256] = { 0 };
|
||||
struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) };
|
||||
struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
|
||||
ssize_t recv_len = 0;
|
||||
|
||||
pthread_mutex_lock(&lock);
|
||||
while (false == server_is_ready) {
|
||||
pthread_cond_wait(&cond, &lock);
|
||||
}
|
||||
pthread_mutex_unlock(&lock);
|
||||
|
||||
printf("Client is running...\n");
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
perror("Create a socket failed");
|
||||
goto RETURN;
|
||||
}
|
||||
|
||||
/* 127.0.0.1:1234 */
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(1234);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("Connect failed");
|
||||
goto UNLOCK_SHUTDOWN;
|
||||
}
|
||||
|
||||
printf("Start receiving. \n");
|
||||
recv_len = recvmsg(sock, &msg, 0);
|
||||
if (recv_len < 0) {
|
||||
perror("Recvmsg failed");
|
||||
goto SHUTDOWN;
|
||||
}
|
||||
|
||||
printf("Receive %ld bytes successlly!\n", recv_len);
|
||||
printf("Data:\n");
|
||||
|
||||
uint8_t i = 0;
|
||||
char *s = msg.msg_iov->iov_base;
|
||||
for (i = 0; i < 6; i++) {
|
||||
printf(" %s\n", s);
|
||||
s += strlen(s) + 1;
|
||||
}
|
||||
|
||||
SHUTDOWN:
|
||||
shutdown(sock, SHUT_RD);
|
||||
return NULL;
|
||||
|
||||
UNLOCK_SHUTDOWN:
|
||||
shutdown(sock, SHUT_RD);
|
||||
RETURN:
|
||||
pthread_mutex_unlock(&lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
pthread_t cs[2] = { 0 };
|
||||
uint8_t i = 0;
|
||||
int ret = EXIT_SUCCESS;
|
||||
|
||||
if (pthread_mutex_init(&lock, NULL)) {
|
||||
perror("Initialize mutex failed");
|
||||
ret = EXIT_FAILURE;
|
||||
goto RETURN;
|
||||
}
|
||||
|
||||
if (pthread_cond_init(&cond, NULL)) {
|
||||
perror("Initialize condition failed");
|
||||
ret = EXIT_FAILURE;
|
||||
goto DESTROY_MUTEX;
|
||||
}
|
||||
|
||||
if (pthread_create(&cs[0], NULL, run_as_server, NULL)) {
|
||||
perror("Create a server thread failed");
|
||||
ret = EXIT_FAILURE;
|
||||
goto DESTROY_COND;
|
||||
}
|
||||
|
||||
if (pthread_create(&cs[1], NULL, run_as_client, NULL)) {
|
||||
perror("Create a client thread failed");
|
||||
ret = EXIT_FAILURE;
|
||||
goto DESTROY_COND;
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
pthread_join(cs[i], NULL);
|
||||
}
|
||||
|
||||
DESTROY_COND:
|
||||
pthread_cond_destroy(&cond);
|
||||
DESTROY_MUTEX:
|
||||
pthread_mutex_destroy(&lock);
|
||||
RETURN:
|
||||
return ret;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user