diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 606ffa05c..64024ce07 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1511,7 +1511,9 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function, #if WASM_ENABLE_DUMP_CALL_STACK != 0 if (!ret) { - aot_dump_call_stack(exec_env); + if (aot_create_call_stack(exec_env)) { + aot_dump_call_stack(exec_env, true, NULL, 0); + } } #endif @@ -1568,7 +1570,9 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function, #if WASM_ENABLE_DUMP_CALL_STACK != 0 if (aot_get_exception(module_inst)) { - aot_dump_call_stack(exec_env); + if (aot_create_call_stack(exec_env)) { + aot_dump_call_stack(exec_env, true, NULL, 0); + } } #endif @@ -3018,38 +3022,24 @@ aot_free_frame(WASMExecEnv *exec_env) || (WASM_ENABLE_PERF_PROFILING != 0) */ #if WASM_ENABLE_DUMP_CALL_STACK != 0 -void -aot_dump_call_stack(WASMExecEnv *exec_env) +bool +aot_create_call_stack(struct WASMExecEnv *exec_env) { AOTFrame *cur_frame = (AOTFrame *)exec_env->cur_frame, *first_frame = cur_frame; AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst; - const char *func_name; uint32 n = 0; - os_printf("\n"); while (cur_frame) { - func_name = - get_func_name_from_index(module_inst, cur_frame->func_index); - - /* function name not exported, print number instead */ - if (func_name == NULL) { - os_printf("#%02d $f%d \n", n, cur_frame->func_index); - } - else { - os_printf("#%02d %s \n", n, func_name); - } - cur_frame = cur_frame->prev_frame; n++; } - os_printf("\n"); /* release previous stack frames and create new ones */ if (!bh_vector_destroy(module_inst->frames.ptr) || !bh_vector_init(module_inst->frames.ptr, n, sizeof(WASMCApiFrame), false)) { - return; + return false; } cur_frame = first_frame; @@ -3059,14 +3049,85 @@ aot_dump_call_stack(WASMExecEnv *exec_env) frame.module_offset = 0; frame.func_index = cur_frame->func_index; frame.func_offset = 0; + frame.func_name_wp = + get_func_name_from_index(module_inst, cur_frame->func_index); if (!bh_vector_append(module_inst->frames.ptr, &frame)) { bh_vector_destroy(module_inst->frames.ptr); - return; + return false; } cur_frame = cur_frame->prev_frame; } + + return true; +} + +#define PRINT_OR_DUMP() \ + do { \ + total_len += \ + wasm_runtime_dump_line_buf_impl(line_buf, print, &buf, &len); \ + if ((!print) && buf && (len == 0)) { \ + return total_len; \ + } \ + } while (0) + +uint32 +aot_dump_call_stack(WASMExecEnv *exec_env, bool print, char *buf, uint32 len) +{ + AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst; + uint32 n = 0, total_len = 0, total_frames; + /* reserve 256 bytes for line buffer, any line longer than 256 bytes + * will be truncated */ + char line_buf[256]; + + if (!module_inst->frames.ptr) { + return 0; + } + + total_frames = bh_vector_size(module_inst->frames.ptr); + if (total_frames == 0) { + return 0; + } + + snprintf(line_buf, sizeof(line_buf), "\n"); + PRINT_OR_DUMP(); + + while (n < total_frames) { + WASMCApiFrame frame = { 0 }; + uint32 line_length, i; + + if (!bh_vector_get(module_inst->frames.ptr, n, &frame)) { + return 0; + } + + /* function name not exported, print number instead */ + if (frame.func_name_wp == NULL) { + line_length = snprintf(line_buf, sizeof(line_buf), "#%02d $f%d\n", + n, frame.func_index); + } + else { + line_length = snprintf(line_buf, sizeof(line_buf), "#%02d %s\n", n, + frame.func_name_wp); + } + + if (line_length >= sizeof(line_buf)) { + uint32 line_buffer_len = sizeof(line_buf); + /* If line too long, ensure the last character is '\n' */ + for (i = line_buffer_len - 5; i < line_buffer_len - 2; i++) { + line_buf[i] = '.'; + } + line_buf[line_buffer_len - 2] = '\n'; + } + + PRINT_OR_DUMP(); + + n++; + } + snprintf(line_buf, sizeof(line_buf), "\n"); + PRINT_OR_DUMP(); + + return total_len + 1; } #endif /* end of WASM_ENABLE_DUMP_CALL_STACK */ diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 0aa4edeae..c3838b585 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -731,8 +731,24 @@ aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index); void aot_free_frame(WASMExecEnv *exec_env); -void -aot_dump_call_stack(WASMExecEnv *exec_env); +bool +aot_create_call_stack(struct WASMExecEnv *exec_env); + +/** + * @brief Dump wasm call stack or get the size + * + * @param exec_env the execution environment + * @param print whether to print to stdout or not + * @param buf buffer to store the dumped content + * @param len length of the buffer + * + * @return when print is true, return the bytes printed out to stdout; when + * print is false and buf is NULL, return the size required to store the + * callstack content; when print is false and buf is not NULL, return the size + * dumped to the buffer, 0 means error and data in buf may be invalid + */ +uint32 +aot_dump_call_stack(WASMExecEnv *exec_env, bool print, char *buf, uint32 len); void aot_dump_perf_profiling(const AOTModuleInstance *module_inst); diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index ca8d02d25..fea9987a3 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -3049,7 +3049,7 @@ fail: || defined(BUILD_TARGET_RISCV32_ILP32D) \ || defined(BUILD_TARGET_RISCV32_ILP32) || defined(BUILD_TARGET_ARC) typedef void (*GenericFunctionPointer)(); -int64 +void invokeNative(GenericFunctionPointer f, uint32 *args, uint32 n_stacks); typedef float64 (*Float64FuncPtr)(GenericFunctionPointer, uint32 *, uint32); @@ -3058,13 +3058,16 @@ typedef int64 (*Int64FuncPtr)(GenericFunctionPointer, uint32 *, uint32); typedef int32 (*Int32FuncPtr)(GenericFunctionPointer, uint32 *, uint32); typedef void (*VoidFuncPtr)(GenericFunctionPointer, uint32 *, uint32); -static Float64FuncPtr invokeNative_Float64 = +static volatile Float64FuncPtr invokeNative_Float64 = (Float64FuncPtr)(uintptr_t)invokeNative; -static Float32FuncPtr invokeNative_Float32 = +static volatile Float32FuncPtr invokeNative_Float32 = (Float32FuncPtr)(uintptr_t)invokeNative; -static Int64FuncPtr invokeNative_Int64 = (Int64FuncPtr)(uintptr_t)invokeNative; -static Int32FuncPtr invokeNative_Int32 = (Int32FuncPtr)(uintptr_t)invokeNative; -static VoidFuncPtr invokeNative_Void = (VoidFuncPtr)(uintptr_t)invokeNative; +static volatile Int64FuncPtr invokeNative_Int64 = + (Int64FuncPtr)(uintptr_t)invokeNative; +static volatile Int32FuncPtr invokeNative_Int32 = + (Int32FuncPtr)(uintptr_t)invokeNative; +static volatile VoidFuncPtr invokeNative_Void = + (VoidFuncPtr)(uintptr_t)invokeNative; #if defined(BUILD_TARGET_ARM_VFP) || defined(BUILD_TARGET_THUMB_VFP) #define MAX_REG_INTS 4 @@ -3520,7 +3523,7 @@ fail: || defined(BUILD_TARGET_THUMB) || defined(BUILD_TARGET_MIPS) \ || defined(BUILD_TARGET_XTENSA) typedef void (*GenericFunctionPointer)(); -int64 +void invokeNative(GenericFunctionPointer f, uint32 *args, uint32 sz); typedef float64 (*Float64FuncPtr)(GenericFunctionPointer f, uint32 *, uint32); @@ -3529,13 +3532,16 @@ typedef int64 (*Int64FuncPtr)(GenericFunctionPointer f, uint32 *, uint32); typedef int32 (*Int32FuncPtr)(GenericFunctionPointer f, uint32 *, uint32); typedef void (*VoidFuncPtr)(GenericFunctionPointer f, uint32 *, uint32); -static Int64FuncPtr invokeNative_Int64 = (Int64FuncPtr)invokeNative; -static Int32FuncPtr invokeNative_Int32 = (Int32FuncPtr)(uintptr_t)invokeNative; -static Float64FuncPtr invokeNative_Float64 = +static volatile Int64FuncPtr invokeNative_Int64 = + (Int64FuncPtr)(uintptr_t)invokeNative; +static volatile Int32FuncPtr invokeNative_Int32 = + (Int32FuncPtr)(uintptr_t)invokeNative; +static volatile Float64FuncPtr invokeNative_Float64 = (Float64FuncPtr)(uintptr_t)invokeNative; -static Float32FuncPtr invokeNative_Float32 = +static volatile Float32FuncPtr invokeNative_Float32 = (Float32FuncPtr)(uintptr_t)invokeNative; -static VoidFuncPtr invokeNative_Void = (VoidFuncPtr)(uintptr_t)invokeNative; +static volatile VoidFuncPtr invokeNative_Void = + (VoidFuncPtr)(uintptr_t)invokeNative; static inline void word_copy(uint32 *dest, uint32 *src, unsigned num) @@ -3762,19 +3768,8 @@ typedef uint32x4_t __m128i; #endif /* end of WASM_ENABLE_SIMD != 0 */ typedef void (*GenericFunctionPointer)(); -#if defined(__APPLE__) || defined(__MACH__) -/** - * Define the return type as 'void' in MacOS, since after converting - * 'int64 invokeNative' into 'float64 invokeNative_Float64', the - * return value passing might be invalid, the caller reads the return - * value from register rax but not xmm0. - */ void invokeNative(GenericFunctionPointer f, uint64 *args, uint64 n_stacks); -#else -int64 -invokeNative(GenericFunctionPointer f, uint64 *args, uint64 n_stacks); -#endif typedef float64 (*Float64FuncPtr)(GenericFunctionPointer, uint64 *, uint64); typedef float32 (*Float32FuncPtr)(GenericFunctionPointer, uint64 *, uint64); @@ -3782,13 +3777,16 @@ typedef int64 (*Int64FuncPtr)(GenericFunctionPointer, uint64 *, uint64); typedef int32 (*Int32FuncPtr)(GenericFunctionPointer, uint64 *, uint64); typedef void (*VoidFuncPtr)(GenericFunctionPointer, uint64 *, uint64); -static Float64FuncPtr invokeNative_Float64 = +static volatile Float64FuncPtr invokeNative_Float64 = (Float64FuncPtr)(uintptr_t)invokeNative; -static Float32FuncPtr invokeNative_Float32 = +static volatile Float32FuncPtr invokeNative_Float32 = (Float32FuncPtr)(uintptr_t)invokeNative; -static Int64FuncPtr invokeNative_Int64 = (Int64FuncPtr)(uintptr_t)invokeNative; -static Int32FuncPtr invokeNative_Int32 = (Int32FuncPtr)(uintptr_t)invokeNative; -static VoidFuncPtr invokeNative_Void = (VoidFuncPtr)(uintptr_t)invokeNative; +static volatile Int64FuncPtr invokeNative_Int64 = + (Int64FuncPtr)(uintptr_t)invokeNative; +static volatile Int32FuncPtr invokeNative_Int32 = + (Int32FuncPtr)(uintptr_t)invokeNative; +static volatile VoidFuncPtr invokeNative_Void = + (VoidFuncPtr)(uintptr_t)invokeNative; #if WASM_ENABLE_SIMD != 0 typedef v128 (*V128FuncPtr)(GenericFunctionPointer, uint64 *, uint64); @@ -4527,6 +4525,30 @@ wasm_externref_retain(uint32 externref_idx) #endif /* end of WASM_ENABLE_REF_TYPES */ #if WASM_ENABLE_DUMP_CALL_STACK != 0 +uint32 +wasm_runtime_dump_line_buf_impl(const char *line_buf, bool dump_or_print, + char **buf, uint32 *len) +{ + if (dump_or_print) { + return (uint32)os_printf("%s", line_buf); + } + else if (*buf) { + uint32 dump_len; + + dump_len = snprintf(*buf, *len, "%s", line_buf); + if (dump_len >= *len) { + dump_len = *len; + } + + *len = *len - dump_len; + *buf = *buf + dump_len; + return dump_len; + } + else { + return strlen(line_buf); + } +} + void wasm_runtime_dump_call_stack(WASMExecEnv *exec_env) { @@ -4534,15 +4556,56 @@ wasm_runtime_dump_call_stack(WASMExecEnv *exec_env) wasm_exec_env_get_module_inst(exec_env); #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) { - wasm_interp_dump_call_stack(exec_env); + wasm_interp_dump_call_stack(exec_env, true, NULL, 0); } #endif #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT) { - aot_dump_call_stack(exec_env); + aot_dump_call_stack(exec_env, true, NULL, 0); } #endif } + +uint32 +wasm_runtime_get_call_stack_buf_size(wasm_exec_env_t exec_env) +{ + WASMModuleInstanceCommon *module_inst = + wasm_exec_env_get_module_inst(exec_env); + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + return wasm_interp_dump_call_stack(exec_env, false, NULL, 0); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + return aot_dump_call_stack(exec_env, false, NULL, 0); + } +#endif + + return 0; +} + +uint32 +wasm_runtime_dump_call_stack_to_buf(wasm_exec_env_t exec_env, char *buf, + uint32 len) +{ + WASMModuleInstanceCommon *module_inst = + wasm_exec_env_get_module_inst(exec_env); + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + return wasm_interp_dump_call_stack(exec_env, false, buf, len); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + return aot_dump_call_stack(exec_env, false, buf, len); + } +#endif + + return 0; +} #endif /* end of WASM_ENABLE_DUMP_CALL_STACK */ bool diff --git a/core/iwasm/common/wasm_runtime_common.h b/core/iwasm/common/wasm_runtime_common.h index 7ef8f69c1..87a2e4aaf 100644 --- a/core/iwasm/common/wasm_runtime_common.h +++ b/core/iwasm/common/wasm_runtime_common.h @@ -404,6 +404,7 @@ typedef struct wasm_frame_t { uint32 module_offset; uint32 func_index; uint32 func_offset; + const char *func_name_wp; } WASMCApiFrame; /* See wasm_export.h for description */ @@ -803,6 +804,28 @@ void wasm_externref_cleanup(WASMModuleInstanceCommon *module_inst); #endif /* end of WASM_ENABLE_REF_TYPES */ +#if WASM_ENABLE_DUMP_CALL_STACK != 0 +/** + * @brief Internal implementation for dumping or printing callstack line + * + * @note if dump_or_print is true, then print to stdout directly; + * if dump_or_print is false, but *buf is NULL, then return the length of the + * line; + * if dump_or_print is false, and *buf is not NULL, then dump content to + * the memory pointed by *buf, and adjust *buf and *len according to actual + * bytes dumped, and return the actual dumped length + * + * @param line_buf current line to dump or print + * @param dump_or_print whether to print to stdout or dump to buf + * @param buf [INOUT] pointer to the buffer + * @param len [INOUT] pointer to remaining length + * @return bytes printed to stdout or dumped to buf + */ +uint32 +wasm_runtime_dump_line_buf_impl(const char *line_buf, bool dump_or_print, + char **buf, uint32 *len); +#endif /* end of WASM_ENABLE_DUMP_CALL_STACK != 0 */ + /* Get module of the current exec_env */ WASMModuleCommon * wasm_exec_env_get_module(WASMExecEnv *exec_env); diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 9b1481d72..ed7a865b8 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -919,6 +919,7 @@ wasm_runtime_get_function_attachment(wasm_exec_env_t exec_env); */ WASM_RUNTIME_API_EXTERN void wasm_runtime_set_user_data(wasm_exec_env_t exec_env, void *user_data); + /** * Get the user data within execution environment. * @@ -963,7 +964,7 @@ WASM_RUNTIME_API_EXTERN void wasm_runtime_set_max_thread_num(uint32_t num); /** - * spawn a new exec_env, the spawned exec_env + * Spawn a new exec_env, the spawned exec_env * can be used in other threads * * @param num the original exec_env @@ -982,7 +983,7 @@ WASM_RUNTIME_API_EXTERN void wasm_runtime_destroy_spawned_exec_env(wasm_exec_env_t exec_env); /** - * spawn a thread from the given exec_env + * Spawn a thread from the given exec_env * * @param exec_env the original exec_env * @param tid thread id to be returned to the caller @@ -996,7 +997,7 @@ wasm_runtime_spawn_thread(wasm_exec_env_t exec_env, wasm_thread_t *tid, wasm_thread_callback_t callback, void *arg); /** - * waits a spawned thread to terminate + * Waits a spawned thread to terminate * * @param tid thread id * @param retval if not NULL, output the return value of the thread @@ -1046,13 +1047,41 @@ WASM_RUNTIME_API_EXTERN bool wasm_externref_retain(uint32_t externref_idx); /** - * dump the call stack + * Dump the call stack to stdout * * @param exec_env the execution environment */ WASM_RUNTIME_API_EXTERN void wasm_runtime_dump_call_stack(wasm_exec_env_t exec_env); +/** + * Get the size required to store the call stack contents, including + * the space for terminating null byte ('\0') + * + * @param exec_env the execution environment + * + * @return size required to store the contents, 0 means error + */ +WASM_RUNTIME_API_EXTERN uint32_t +wasm_runtime_get_call_stack_buf_size(wasm_exec_env_t exec_env); + +/** + * Dump the call stack to buffer. + * + * @note this function is not thread-safe, please only use this API + * when the exec_env is not executing + * + * @param exec_env the execution environment + * @param buf buffer to store the dumped content + * @param len length of the buffer + * + * @return bytes dumped to the buffer, including the terminating null + * byte ('\0'), 0 means error and data in buf may be invalid + */ +WASM_RUNTIME_API_EXTERN uint32_t +wasm_runtime_dump_call_stack_to_buf(wasm_exec_env_t exec_env, char *buf, + uint32_t len); + /** * Get a custom section by name * diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index 0c97df44d..7510698eb 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -3834,7 +3834,9 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, } else { #if WASM_ENABLE_DUMP_CALL_STACK != 0 - wasm_interp_dump_call_stack(exec_env); + if (wasm_interp_create_call_stack(exec_env)) { + wasm_interp_dump_call_stack(exec_env, true, NULL, 0); + } #endif LOG_DEBUG("meet an exception %s", wasm_get_exception(module_inst)); } diff --git a/core/iwasm/interpreter/wasm_interp_fast.c b/core/iwasm/interpreter/wasm_interp_fast.c index b64609d7a..45e8401bc 100644 --- a/core/iwasm/interpreter/wasm_interp_fast.c +++ b/core/iwasm/interpreter/wasm_interp_fast.c @@ -3847,7 +3847,9 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, } else { #if WASM_ENABLE_DUMP_CALL_STACK != 0 - wasm_interp_dump_call_stack(exec_env); + if (wasm_interp_create_call_stack(exec_env)) { + wasm_interp_dump_call_stack(exec_env, true, NULL, 0); + } #endif } diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index c6b77f0a7..deba92dca 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -2485,8 +2485,8 @@ wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module_inst, || (WASM_ENABLE_MEMORY_TRACING != 0) */ #if WASM_ENABLE_DUMP_CALL_STACK != 0 -void -wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env) +bool +wasm_interp_create_call_stack(struct WASMExecEnv *exec_env) { WASMModuleInstance *module_inst = (WASMModuleInstance *)wasm_exec_env_get_module_inst(exec_env); @@ -2507,12 +2507,12 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env) if (!bh_vector_destroy(module_inst->frames) || !bh_vector_init(module_inst->frames, n, sizeof(WASMCApiFrame), false)) { - return; + return false; } cur_frame = first_frame; n = 0; - os_printf("\n"); + while (cur_frame) { WASMCApiFrame frame = { 0 }; WASMFunctionInstance *func_inst = cur_frame->function; @@ -2560,20 +2560,86 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env) } } - /* function name not exported, print number instead */ - if (func_name == NULL) { - os_printf("#%02d $f%d \n", n, func_inst - module_inst->functions); - } - else { - os_printf("#%02d %s \n", n, func_name); - } + frame.func_name_wp = func_name; - /* keep print */ - bh_vector_append(module_inst->frames, &frame); + if (!bh_vector_append(module_inst->frames, &frame)) { + bh_vector_destroy(module_inst->frames); + return false; + } cur_frame = cur_frame->prev_frame; n++; } - os_printf("\n"); + + return true; +} + +#define PRINT_OR_DUMP() \ + do { \ + total_len += \ + wasm_runtime_dump_line_buf_impl(line_buf, print, &buf, &len); \ + if ((!print) && buf && (len == 0)) { \ + return total_len; \ + } \ + } while (0) + +uint32 +wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env, bool print, char *buf, + uint32 len) +{ + WASMModuleInstance *module_inst = + (WASMModuleInstance *)wasm_exec_env_get_module_inst(exec_env); + uint32 n = 0, total_len = 0, total_frames; + /* reserve 256 bytes for line buffer, any line longer than 256 bytes + * will be truncated */ + char line_buf[256]; + + if (!module_inst->frames) { + return 0; + } + + total_frames = bh_vector_size(module_inst->frames); + if (total_frames == 0) { + return 0; + } + + snprintf(line_buf, sizeof(line_buf), "\n"); + PRINT_OR_DUMP(); + + while (n < total_frames) { + WASMCApiFrame frame = { 0 }; + uint32 line_length, i; + + if (!bh_vector_get(module_inst->frames, n, &frame)) { + return 0; + } + + /* function name not exported, print number instead */ + if (frame.func_name_wp == NULL) { + line_length = snprintf(line_buf, sizeof(line_buf), "#%02d $f%d\n", + n, frame.func_index); + } + else { + line_length = snprintf(line_buf, sizeof(line_buf), "#%02d %s\n", n, + frame.func_name_wp); + } + + if (line_length >= sizeof(line_buf)) { + uint32 line_buffer_len = sizeof(line_buf); + /* If line too long, ensure the last character is '\n' */ + for (i = line_buffer_len - 5; i < line_buffer_len - 2; i++) { + line_buf[i] = '.'; + } + line_buf[line_buffer_len - 2] = '\n'; + } + + PRINT_OR_DUMP(); + + n++; + } + snprintf(line_buf, sizeof(line_buf), "\n"); + PRINT_OR_DUMP(); + + return total_len + 1; } #endif /* end of WASM_ENABLE_DUMP_CALL_STACK */ diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index ccdf538aa..c780e6a11 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -432,8 +432,25 @@ wasm_get_table_inst(const WASMModuleInstance *module_inst, const uint32 tbl_idx) } #if WASM_ENABLE_DUMP_CALL_STACK != 0 -void -wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env); +bool +wasm_interp_create_call_stack(struct WASMExecEnv *exec_env); + +/** + * @brief Dump wasm call stack or get the size + * + * @param exec_env the execution environment + * @param print whether to print to stdout or not + * @param buf buffer to store the dumped content + * @param len length of the buffer + * + * @return when print is true, return the bytes printed out to stdout; when + * print is false and buf is NULL, return the size required to store the + * callstack content; when print is false and buf is not NULL, return the size + * dumped to the buffer, 0 means error and data in buf may be invalid + */ +uint32 +wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env, bool print, char *buf, + uint32 len); #endif const uint8 * diff --git a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h index 5ffcb6b37..47b65ca82 100644 --- a/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h +++ b/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h @@ -51,11 +51,17 @@ #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 #ifndef __APPLE__ #define CONFIG_HAS_POSIX_FALLOCATE 1