Skip to content

Commit 471cac4

Browse files
Enable dump call stack to a buffer (#1244)
Enable dump call stack to a buffer, use API `wasm_runtime_get_call_stack_buf_size` to get the required buffer size and use API `wasm_runtime_dump_call_stack_to_buf` to dump call stack to a buffer
1 parent 53b775a commit 471cac4

File tree

9 files changed

+324
-43
lines changed

9 files changed

+324
-43
lines changed

core/iwasm/aot/aot_runtime.c

Lines changed: 81 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,7 +1511,9 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
15111511

15121512
#if WASM_ENABLE_DUMP_CALL_STACK != 0
15131513
if (!ret) {
1514-
aot_dump_call_stack(exec_env);
1514+
if (aot_create_call_stack(exec_env)) {
1515+
aot_dump_call_stack(exec_env, true, NULL, 0);
1516+
}
15151517
}
15161518
#endif
15171519

@@ -1568,7 +1570,9 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function,
15681570

15691571
#if WASM_ENABLE_DUMP_CALL_STACK != 0
15701572
if (aot_get_exception(module_inst)) {
1571-
aot_dump_call_stack(exec_env);
1573+
if (aot_create_call_stack(exec_env)) {
1574+
aot_dump_call_stack(exec_env, true, NULL, 0);
1575+
}
15721576
}
15731577
#endif
15741578

@@ -3018,38 +3022,24 @@ aot_free_frame(WASMExecEnv *exec_env)
30183022
|| (WASM_ENABLE_PERF_PROFILING != 0) */
30193023

30203024
#if WASM_ENABLE_DUMP_CALL_STACK != 0
3021-
void
3022-
aot_dump_call_stack(WASMExecEnv *exec_env)
3025+
bool
3026+
aot_create_call_stack(struct WASMExecEnv *exec_env)
30233027
{
30243028
AOTFrame *cur_frame = (AOTFrame *)exec_env->cur_frame,
30253029
*first_frame = cur_frame;
30263030
AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst;
3027-
const char *func_name;
30283031
uint32 n = 0;
30293032

3030-
os_printf("\n");
30313033
while (cur_frame) {
3032-
func_name =
3033-
get_func_name_from_index(module_inst, cur_frame->func_index);
3034-
3035-
/* function name not exported, print number instead */
3036-
if (func_name == NULL) {
3037-
os_printf("#%02d $f%d \n", n, cur_frame->func_index);
3038-
}
3039-
else {
3040-
os_printf("#%02d %s \n", n, func_name);
3041-
}
3042-
30433034
cur_frame = cur_frame->prev_frame;
30443035
n++;
30453036
}
3046-
os_printf("\n");
30473037

30483038
/* release previous stack frames and create new ones */
30493039
if (!bh_vector_destroy(module_inst->frames.ptr)
30503040
|| !bh_vector_init(module_inst->frames.ptr, n, sizeof(WASMCApiFrame),
30513041
false)) {
3052-
return;
3042+
return false;
30533043
}
30543044

30553045
cur_frame = first_frame;
@@ -3059,14 +3049,85 @@ aot_dump_call_stack(WASMExecEnv *exec_env)
30593049
frame.module_offset = 0;
30603050
frame.func_index = cur_frame->func_index;
30613051
frame.func_offset = 0;
3052+
frame.func_name_wp =
3053+
get_func_name_from_index(module_inst, cur_frame->func_index);
30623054

30633055
if (!bh_vector_append(module_inst->frames.ptr, &frame)) {
30643056
bh_vector_destroy(module_inst->frames.ptr);
3065-
return;
3057+
return false;
30663058
}
30673059

30683060
cur_frame = cur_frame->prev_frame;
30693061
}
3062+
3063+
return true;
3064+
}
3065+
3066+
#define PRINT_OR_DUMP() \
3067+
do { \
3068+
total_len += \
3069+
wasm_runtime_dump_line_buf_impl(line_buf, print, &buf, &len); \
3070+
if ((!print) && buf && (len == 0)) { \
3071+
return total_len; \
3072+
} \
3073+
} while (0)
3074+
3075+
uint32
3076+
aot_dump_call_stack(WASMExecEnv *exec_env, bool print, char *buf, uint32 len)
3077+
{
3078+
AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst;
3079+
uint32 n = 0, total_len = 0, total_frames;
3080+
/* reserve 256 bytes for line buffer, any line longer than 256 bytes
3081+
* will be truncated */
3082+
char line_buf[256];
3083+
3084+
if (!module_inst->frames.ptr) {
3085+
return 0;
3086+
}
3087+
3088+
total_frames = bh_vector_size(module_inst->frames.ptr);
3089+
if (total_frames == 0) {
3090+
return 0;
3091+
}
3092+
3093+
snprintf(line_buf, sizeof(line_buf), "\n");
3094+
PRINT_OR_DUMP();
3095+
3096+
while (n < total_frames) {
3097+
WASMCApiFrame frame = { 0 };
3098+
uint32 line_length, i;
3099+
3100+
if (!bh_vector_get(module_inst->frames.ptr, n, &frame)) {
3101+
return 0;
3102+
}
3103+
3104+
/* function name not exported, print number instead */
3105+
if (frame.func_name_wp == NULL) {
3106+
line_length = snprintf(line_buf, sizeof(line_buf), "#%02d $f%d\n",
3107+
n, frame.func_index);
3108+
}
3109+
else {
3110+
line_length = snprintf(line_buf, sizeof(line_buf), "#%02d %s\n", n,
3111+
frame.func_name_wp);
3112+
}
3113+
3114+
if (line_length >= sizeof(line_buf)) {
3115+
uint32 line_buffer_len = sizeof(line_buf);
3116+
/* If line too long, ensure the last character is '\n' */
3117+
for (i = line_buffer_len - 5; i < line_buffer_len - 2; i++) {
3118+
line_buf[i] = '.';
3119+
}
3120+
line_buf[line_buffer_len - 2] = '\n';
3121+
}
3122+
3123+
PRINT_OR_DUMP();
3124+
3125+
n++;
3126+
}
3127+
snprintf(line_buf, sizeof(line_buf), "\n");
3128+
PRINT_OR_DUMP();
3129+
3130+
return total_len + 1;
30703131
}
30713132
#endif /* end of WASM_ENABLE_DUMP_CALL_STACK */
30723133

core/iwasm/aot/aot_runtime.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -731,8 +731,24 @@ aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index);
731731
void
732732
aot_free_frame(WASMExecEnv *exec_env);
733733

734-
void
735-
aot_dump_call_stack(WASMExecEnv *exec_env);
734+
bool
735+
aot_create_call_stack(struct WASMExecEnv *exec_env);
736+
737+
/**
738+
* @brief Dump wasm call stack or get the size
739+
*
740+
* @param exec_env the execution environment
741+
* @param print whether to print to stdout or not
742+
* @param buf buffer to store the dumped content
743+
* @param len length of the buffer
744+
*
745+
* @return when print is true, return the bytes printed out to stdout; when
746+
* print is false and buf is NULL, return the size required to store the
747+
* callstack content; when print is false and buf is not NULL, return the size
748+
* dumped to the buffer, 0 means error and data in buf may be invalid
749+
*/
750+
uint32
751+
aot_dump_call_stack(WASMExecEnv *exec_env, bool print, char *buf, uint32 len);
736752

737753
void
738754
aot_dump_perf_profiling(const AOTModuleInstance *module_inst);

core/iwasm/common/wasm_runtime_common.c

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4527,22 +4527,87 @@ wasm_externref_retain(uint32 externref_idx)
45274527
#endif /* end of WASM_ENABLE_REF_TYPES */
45284528

45294529
#if WASM_ENABLE_DUMP_CALL_STACK != 0
4530+
uint32
4531+
wasm_runtime_dump_line_buf_impl(const char *line_buf, bool dump_or_print,
4532+
char **buf, uint32 *len)
4533+
{
4534+
if (dump_or_print) {
4535+
return (uint32)os_printf("%s", line_buf);
4536+
}
4537+
else if (*buf) {
4538+
uint32 dump_len;
4539+
4540+
dump_len = snprintf(*buf, *len, "%s", line_buf);
4541+
if (dump_len >= *len) {
4542+
dump_len = *len;
4543+
}
4544+
4545+
*len = *len - dump_len;
4546+
*buf = *buf + dump_len;
4547+
return dump_len;
4548+
}
4549+
else {
4550+
return strlen(line_buf);
4551+
}
4552+
}
4553+
45304554
void
45314555
wasm_runtime_dump_call_stack(WASMExecEnv *exec_env)
45324556
{
45334557
WASMModuleInstanceCommon *module_inst =
45344558
wasm_exec_env_get_module_inst(exec_env);
45354559
#if WASM_ENABLE_INTERP != 0
45364560
if (module_inst->module_type == Wasm_Module_Bytecode) {
4537-
wasm_interp_dump_call_stack(exec_env);
4561+
wasm_interp_dump_call_stack(exec_env, true, NULL, 0);
45384562
}
45394563
#endif
45404564
#if WASM_ENABLE_AOT != 0
45414565
if (module_inst->module_type == Wasm_Module_AoT) {
4542-
aot_dump_call_stack(exec_env);
4566+
aot_dump_call_stack(exec_env, true, NULL, 0);
45434567
}
45444568
#endif
45454569
}
4570+
4571+
uint32
4572+
wasm_runtime_get_call_stack_buf_size(wasm_exec_env_t exec_env)
4573+
{
4574+
WASMModuleInstanceCommon *module_inst =
4575+
wasm_exec_env_get_module_inst(exec_env);
4576+
4577+
#if WASM_ENABLE_INTERP != 0
4578+
if (module_inst->module_type == Wasm_Module_Bytecode) {
4579+
return wasm_interp_dump_call_stack(exec_env, false, NULL, 0);
4580+
}
4581+
#endif
4582+
#if WASM_ENABLE_AOT != 0
4583+
if (module_inst->module_type == Wasm_Module_AoT) {
4584+
return aot_dump_call_stack(exec_env, false, NULL, 0);
4585+
}
4586+
#endif
4587+
4588+
return 0;
4589+
}
4590+
4591+
uint32
4592+
wasm_runtime_dump_call_stack_to_buf(wasm_exec_env_t exec_env, char *buf,
4593+
uint32 len)
4594+
{
4595+
WASMModuleInstanceCommon *module_inst =
4596+
wasm_exec_env_get_module_inst(exec_env);
4597+
4598+
#if WASM_ENABLE_INTERP != 0
4599+
if (module_inst->module_type == Wasm_Module_Bytecode) {
4600+
return wasm_interp_dump_call_stack(exec_env, false, buf, len);
4601+
}
4602+
#endif
4603+
#if WASM_ENABLE_AOT != 0
4604+
if (module_inst->module_type == Wasm_Module_AoT) {
4605+
return aot_dump_call_stack(exec_env, false, buf, len);
4606+
}
4607+
#endif
4608+
4609+
return 0;
4610+
}
45464611
#endif /* end of WASM_ENABLE_DUMP_CALL_STACK */
45474612

45484613
bool

core/iwasm/common/wasm_runtime_common.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ typedef struct wasm_frame_t {
404404
uint32 module_offset;
405405
uint32 func_index;
406406
uint32 func_offset;
407+
const char *func_name_wp;
407408
} WASMCApiFrame;
408409

409410
/* See wasm_export.h for description */
@@ -803,6 +804,28 @@ void
803804
wasm_externref_cleanup(WASMModuleInstanceCommon *module_inst);
804805
#endif /* end of WASM_ENABLE_REF_TYPES */
805806

807+
#if WASM_ENABLE_DUMP_CALL_STACK != 0
808+
/**
809+
* @brief Internal implementation for dumping or printing callstack line
810+
*
811+
* @note if dump_or_print is true, then print to stdout directly;
812+
* if dump_or_print is false, but *buf is NULL, then return the length of the
813+
* line;
814+
* if dump_or_print is false, and *buf is not NULL, then dump content to
815+
* the memory pointed by *buf, and adjust *buf and *len according to actual
816+
* bytes dumped, and return the actual dumped length
817+
*
818+
* @param line_buf current line to dump or print
819+
* @param dump_or_print whether to print to stdout or dump to buf
820+
* @param buf [INOUT] pointer to the buffer
821+
* @param len [INOUT] pointer to remaining length
822+
* @return bytes printed to stdout or dumped to buf
823+
*/
824+
uint32
825+
wasm_runtime_dump_line_buf_impl(const char *line_buf, bool dump_or_print,
826+
char **buf, uint32 *len);
827+
#endif /* end of WASM_ENABLE_DUMP_CALL_STACK != 0 */
828+
806829
/* Get module of the current exec_env */
807830
WASMModuleCommon *
808831
wasm_exec_env_get_module(WASMExecEnv *exec_env);

core/iwasm/include/wasm_export.h

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,7 @@ wasm_runtime_get_function_attachment(wasm_exec_env_t exec_env);
919919
*/
920920
WASM_RUNTIME_API_EXTERN void
921921
wasm_runtime_set_user_data(wasm_exec_env_t exec_env, void *user_data);
922+
922923
/**
923924
* Get the user data within execution environment.
924925
*
@@ -963,7 +964,7 @@ WASM_RUNTIME_API_EXTERN void
963964
wasm_runtime_set_max_thread_num(uint32_t num);
964965

965966
/**
966-
* spawn a new exec_env, the spawned exec_env
967+
* Spawn a new exec_env, the spawned exec_env
967968
* can be used in other threads
968969
*
969970
* @param num the original exec_env
@@ -982,7 +983,7 @@ WASM_RUNTIME_API_EXTERN void
982983
wasm_runtime_destroy_spawned_exec_env(wasm_exec_env_t exec_env);
983984

984985
/**
985-
* spawn a thread from the given exec_env
986+
* Spawn a thread from the given exec_env
986987
*
987988
* @param exec_env the original exec_env
988989
* @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,
996997
wasm_thread_callback_t callback, void *arg);
997998

998999
/**
999-
* waits a spawned thread to terminate
1000+
* Waits a spawned thread to terminate
10001001
*
10011002
* @param tid thread id
10021003
* @param retval if not NULL, output the return value of the thread
@@ -1046,13 +1047,41 @@ WASM_RUNTIME_API_EXTERN bool
10461047
wasm_externref_retain(uint32_t externref_idx);
10471048

10481049
/**
1049-
* dump the call stack
1050+
* Dump the call stack to stdout
10501051
*
10511052
* @param exec_env the execution environment
10521053
*/
10531054
WASM_RUNTIME_API_EXTERN void
10541055
wasm_runtime_dump_call_stack(wasm_exec_env_t exec_env);
10551056

1057+
/**
1058+
* Get the size required to store the call stack contents, including
1059+
* the space for terminating null byte ('\0')
1060+
*
1061+
* @param exec_env the execution environment
1062+
*
1063+
* @return size required to store the contents, 0 means error
1064+
*/
1065+
WASM_RUNTIME_API_EXTERN uint32_t
1066+
wasm_runtime_get_call_stack_buf_size(wasm_exec_env_t exec_env);
1067+
1068+
/**
1069+
* Dump the call stack to buffer.
1070+
*
1071+
* @note this function is not thread-safe, please only use this API
1072+
* when the exec_env is not executing
1073+
*
1074+
* @param exec_env the execution environment
1075+
* @param buf buffer to store the dumped content
1076+
* @param len length of the buffer
1077+
*
1078+
* @return bytes dumped to the buffer, including the terminating null
1079+
* byte ('\0'), 0 means error and data in buf may be invalid
1080+
*/
1081+
WASM_RUNTIME_API_EXTERN uint32_t
1082+
wasm_runtime_dump_call_stack_to_buf(wasm_exec_env_t exec_env, char *buf,
1083+
uint32_t len);
1084+
10561085
/**
10571086
* Get a custom section by name
10581087
*

core/iwasm/interpreter/wasm_interp_classic.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3834,7 +3834,9 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
38343834
}
38353835
else {
38363836
#if WASM_ENABLE_DUMP_CALL_STACK != 0
3837-
wasm_interp_dump_call_stack(exec_env);
3837+
if (wasm_interp_create_call_stack(exec_env)) {
3838+
wasm_interp_dump_call_stack(exec_env, true, NULL, 0);
3839+
}
38383840
#endif
38393841
LOG_DEBUG("meet an exception %s", wasm_get_exception(module_inst));
38403842
}

0 commit comments

Comments
 (0)