Skip to content

Commit 68e4534

Browse files
author
Georgii Rylov
committed
Iterate callstack API
1 parent ba75b8f commit 68e4534

10 files changed

Lines changed: 154 additions & 2 deletions

File tree

core/iwasm/aot/aot_runtime.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "../common/wasm_runtime_common.h"
1111
#include "../common/wasm_memory.h"
1212
#include "../interpreter/wasm_runtime.h"
13+
#include <stdbool.h>
1314
#if WASM_ENABLE_SHARED_MEMORY != 0
1415
#include "../common/wasm_shared_memory.h"
1516
#endif
@@ -4104,6 +4105,48 @@ aot_frame_update_profile_info(WASMExecEnv *exec_env, bool alloc_frame)
41044105
#endif /* end of WASM_ENABLE_AOT_STACK_FRAME != 0 */
41054106

41064107
#if WASM_ENABLE_DUMP_CALL_STACK != 0
4108+
void
4109+
aot_iterate_callstack(WASMExecEnv *exec_env, const wasm_frame_callback frame_handler, void* user_data)
4110+
{
4111+
/*
4112+
* Note for devs: please refrain from such modifications inside of aot_iterate_callstack
4113+
* - any allocations/freeing memory
4114+
* - dereferencing any pointers other than: exec_env, exec_env->module_inst,
4115+
* exec_env->module_inst->module, pointers between stack's bottom and top_boundary
4116+
* For more details check wasm_iterate_callstack in wasm_export.h
4117+
*/
4118+
if (!is_tiny_frame(exec_env)) {
4119+
//TODO: support standard frames
4120+
return;
4121+
}
4122+
uint8* top_boundary = exec_env->wasm_stack.top_boundary;
4123+
uint8* top = exec_env->wasm_stack.top;
4124+
uint8* bottom = exec_env->wasm_stack.bottom;
4125+
4126+
bool is_top_index_in_range = top_boundary >= top && top >= (bottom + sizeof(AOTTinyFrame));
4127+
if (!is_top_index_in_range) {
4128+
return;
4129+
}
4130+
bool is_top_aligned_with_bottom = (unsigned long)(top - bottom) % sizeof(AOTTinyFrame) == 0;
4131+
if (!is_top_aligned_with_bottom) {
4132+
return;
4133+
}
4134+
4135+
AOTTinyFrame* frame = (AOTTinyFrame*)(top - sizeof(AOTTinyFrame));
4136+
WASMCApiFrame record_frame;
4137+
while (frame &&
4138+
(uint8_t*)frame >= bottom) {
4139+
record_frame.instance = exec_env->module_inst;
4140+
record_frame.module_offset = 0;
4141+
record_frame.func_index = frame->func_index;
4142+
record_frame.func_offset = frame->ip_offset;
4143+
if (!frame_handler(user_data, &record_frame)) {
4144+
break;
4145+
}
4146+
frame -= 1;
4147+
}
4148+
}
4149+
41074150
bool
41084151
aot_create_call_stack(struct WASMExecEnv *exec_env)
41094152
{

core/iwasm/aot/aot_runtime.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,9 @@ aot_frame_update_profile_info(WASMExecEnv *exec_env, bool alloc_frame);
777777
bool
778778
aot_create_call_stack(struct WASMExecEnv *exec_env);
779779

780+
void
781+
aot_iterate_callstack(WASMExecEnv *exec_env, const wasm_frame_callback frame_handler, void* user_data);
782+
780783
/**
781784
* @brief Dump wasm call stack or get the size
782785
*

core/iwasm/common/wasm_runtime_common.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "bh_common.h"
88
#include "bh_assert.h"
99
#include "bh_log.h"
10+
#include "wasm_export.h"
1011
#include "wasm_native.h"
1112
#include "wasm_runtime_common.h"
1213
#include "wasm_memory.h"
@@ -1740,6 +1741,33 @@ wasm_runtime_destroy_exec_env(WASMExecEnv *exec_env)
17401741
wasm_exec_env_destroy(exec_env);
17411742
}
17421743

1744+
void
1745+
wasm_iterate_callstack(const wasm_exec_env_t exec_env, const wasm_frame_callback frame_callback, void* user_data)
1746+
{
1747+
/*
1748+
* Note for devs: please refrain from such modifications inside of wasm_iterate_callstack
1749+
* - any allocations/freeing memory
1750+
* - dereferencing any pointers other than: exec_env, exec_env->module_inst,
1751+
* exec_env->module_inst->module, pointers between stack's bottom and top_boundary
1752+
* For more details check wasm_iterate_callstack in wasm_export.h
1753+
*/
1754+
#if WASM_ENABLE_DUMP_CALL_STACK
1755+
WASMModuleInstance* module_inst = (WASMModuleInstance *)get_module_inst(exec_env);
1756+
1757+
#if WASM_ENABLE_INTERP != 0
1758+
if (module_inst->module_type == Wasm_Module_Bytecode) {
1759+
wasm_interp_iterate_callstack(exec_env, frame_callback, user_data);
1760+
}
1761+
#endif
1762+
1763+
#if WASM_ENABLE_AOT != 0
1764+
if (module_inst->module_type == Wasm_Module_AoT) {
1765+
aot_iterate_callstack(exec_env, frame_callback, user_data);
1766+
}
1767+
#endif
1768+
#endif
1769+
}
1770+
17431771
bool
17441772
wasm_runtime_init_thread_env(void)
17451773
{

core/iwasm/common/wasm_runtime_common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,9 @@ wasm_runtime_create_exec_env(WASMModuleInstanceCommon *module_inst,
652652
WASM_RUNTIME_API_EXTERN void
653653
wasm_runtime_destroy_exec_env(WASMExecEnv *exec_env);
654654

655+
WASM_RUNTIME_API_EXTERN void
656+
wasm_iterate_callstack(const wasm_exec_env_t exec_env, const wasm_frame_callback frame_handler, void* user_data);
657+
655658
/* See wasm_export.h for description */
656659
WASM_RUNTIME_API_EXTERN WASMModuleInstanceCommon *
657660
wasm_runtime_get_module_inst(WASMExecEnv *exec_env);

core/iwasm/include/wasm_export.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ typedef WASMFunctionInstanceCommon *wasm_function_inst_t;
126126
struct WASMMemoryInstance;
127127
typedef struct WASMMemoryInstance *wasm_memory_inst_t;
128128

129+
struct wasm_frame_t;
130+
typedef struct wasm_frame_t * wasm_frame_ptr_t;
131+
129132
/* WASM section */
130133
typedef struct wasm_section_t {
131134
struct wasm_section_t *next;
@@ -864,6 +867,37 @@ wasm_runtime_create_exec_env(wasm_module_inst_t module_inst,
864867
WASM_RUNTIME_API_EXTERN void
865868
wasm_runtime_destroy_exec_env(wasm_exec_env_t exec_env);
866869

870+
871+
typedef bool (*wasm_frame_callback)(void*, wasm_frame_ptr_t);
872+
873+
/**
874+
* @brief Iterate over callstack frames and execute callback on it.
875+
*
876+
* Caution: This is not a thread-safe function. Ensure the exec_env
877+
* is suspended before calling it from another thread.
878+
*
879+
* Usage: In the callback to read frames fields use APIs
880+
* for wasm_frame_t from wasm_c_api.h
881+
*
882+
* Note: The function is async-signal-safe if called with verified arguments.
883+
* Meaning it's safe to call it from a signal handler even on a signal interruption
884+
* from another thread if next variables hold valid pointers
885+
* - exec_env
886+
* - exec_env->module_inst
887+
* - exec_env->module_inst->module
888+
*
889+
* Note for devs: please refrain from such modifications inside of this call
890+
* - any allocations/freeing memory
891+
* - dereferencing any pointers other than: exec_env, exec_env->module_inst,
892+
* exec_env->module_inst->module, pointers between stack's bottom and top_boundary
893+
*
894+
* @param exec_env the execution environment that containes frames
895+
* @param callback the callback function provided by the user
896+
* @param user_data context for callback provided by the user
897+
*/
898+
WASM_RUNTIME_API_EXTERN void
899+
wasm_iterate_callstack(const wasm_exec_env_t exec_env, const wasm_frame_callback callback, void *user_data);
900+
867901
/**
868902
* Get the singleton execution environment for the instance.
869903
*

core/iwasm/interpreter/wasm_interp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ typedef struct WASMInterpFrame {
2626
/* Instruction pointer of the bytecode array. */
2727
uint8 *ip;
2828

29+
uint32 func_index;
30+
2931
#if WASM_ENABLE_FAST_JIT != 0
3032
uint8 *jitted_return_addr;
3133
#endif

core/iwasm/interpreter/wasm_interp_classic.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1264,9 +1264,11 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
12641264
init_frame_refs(frame_ref, local_cell_num, cur_func);
12651265
#endif
12661266

1267+
cur_func_index = (uint32)(cur_func - module_inst->e->functions);
1268+
frame->func_index = cur_func_index;
1269+
12671270
wasm_exec_env_set_cur_frame(exec_env, frame);
12681271

1269-
cur_func_index = (uint32)(cur_func - module_inst->e->functions);
12701272
bh_assert(cur_func_index < module_inst->module->import_function_count);
12711273
if (!func_import->call_conv_wasm_c_api) {
12721274
native_func_pointer = module_inst->import_func_ptrs[cur_func_index];

core/iwasm/interpreter/wasm_interp_fast.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1205,9 +1205,11 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst,
12051205
init_frame_refs(frame->frame_ref, local_cell_num, cur_func);
12061206
#endif
12071207

1208+
cur_func_index = (uint32)(cur_func - module_inst->e->functions);
1209+
frame->func_index = cur_func_index;
1210+
12081211
wasm_exec_env_set_cur_frame(exec_env, frame);
12091212

1210-
cur_func_index = (uint32)(cur_func - module_inst->e->functions);
12111213
bh_assert(cur_func_index < module_inst->module->import_function_count);
12121214
if (!func_import->call_conv_wasm_c_api) {
12131215
native_func_pointer = module_inst->import_func_ptrs[cur_func_index];
@@ -6032,6 +6034,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
60326034

60336035
/* Initialize the interpreter context. */
60346036
frame->function = cur_func;
6037+
frame->func_index = (uint32)(cur_func - module->e->functions);
60356038
frame_ip = wasm_get_func_code(cur_func);
60366039
frame_ip_end = wasm_get_func_code_end(cur_func);
60376040

core/iwasm/interpreter/wasm_runtime.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include "wasm_runtime.h"
77
#include "wasm.h"
8+
#include "wasm_exec_env.h"
89
#include "wasm_loader.h"
910
#include "wasm_interp.h"
1011
#include "bh_common.h"
@@ -4196,6 +4197,35 @@ wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module_inst,
41964197
|| (WASM_ENABLE_MEMORY_TRACING != 0) */
41974198

41984199
#if WASM_ENABLE_DUMP_CALL_STACK != 0
4200+
uint32
4201+
wasm_interp_iterate_callstack(WASMExecEnv *exec_env, const wasm_frame_callback frame_handler, void* user_data)
4202+
{
4203+
/*
4204+
* Note for devs: please refrain from such modifications inside of wasm_interp_iterate_callstack
4205+
* - any allocations/freeing memory
4206+
* - dereferencing any pointers other than: exec_env, exec_env->module_inst,
4207+
* exec_env->module_inst->module, pointers between stack's bottom and top_boundary
4208+
* For more details check wasm_iterate_callstack in wasm_export.h
4209+
*/
4210+
WASMModuleInstance *module_inst = (WASMModuleInstance *)wasm_exec_env_get_module_inst(exec_env);
4211+
WASMInterpFrame* cur_frame = wasm_exec_env_get_cur_frame(exec_env);
4212+
uint8* top_boundary = exec_env->wasm_stack.top_boundary;
4213+
uint8* bottom = exec_env->wasm_stack.bottom;
4214+
4215+
WASMCApiFrame record_frame;
4216+
while (cur_frame &&
4217+
(uint8_t*)cur_frame >= bottom &&
4218+
(uint8_t*)cur_frame + sizeof(WASMInterpFrame) <= top_boundary) {
4219+
record_frame.instance = module_inst;
4220+
record_frame.module_offset = 0;
4221+
record_frame.func_index = cur_frame->func_index;
4222+
if (!frame_handler(user_data, &record_frame)) {
4223+
break;
4224+
}
4225+
cur_frame = cur_frame->prev_frame;
4226+
}
4227+
}
4228+
41994229
bool
42004230
wasm_interp_create_call_stack(struct WASMExecEnv *exec_env)
42014231
{

core/iwasm/interpreter/wasm_runtime.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,10 @@ wasm_get_table_inst(const WASMModuleInstance *module_inst, uint32 tbl_idx)
730730
}
731731

732732
#if WASM_ENABLE_DUMP_CALL_STACK != 0
733+
734+
uint32
735+
wasm_interp_iterate_callstack(WASMExecEnv *exec_env, const wasm_frame_callback frame_handler, void* user_data);
736+
733737
bool
734738
wasm_interp_create_call_stack(struct WASMExecEnv *exec_env);
735739

0 commit comments

Comments
 (0)