Skip to content

Commit fcd96bf

Browse files
cimacmillanwenyongh
authored andcommitted
Add memory watchpoint support for source debugger (#1762)
Allow to add watchpoints to variables for source debugging. For instance: `breakpoint set variable var` will pause WAMR execution when the address at var is written to. Can also set read/write watchpoints by passing r/w flags. This will pause execution when the address at var is read: `watchpoint set variable -w read var` Add two linked lists for read/write watchpoints. When the debug message handler receives a watchpoint request, it adds/removes to one/both of these lists. In the interpreter, when an address is read or stored to, check whether the address is in these lists. If so, throw a sigtrap and suspend the process.
1 parent 0b48943 commit fcd96bf

File tree

4 files changed

+265
-25
lines changed

4 files changed

+265
-25
lines changed

core/iwasm/interpreter/wasm_interp_classic.c

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,35 @@ typedef float64 CellType_F64;
7070
goto unaligned_atomic; \
7171
} while (0)
7272

73+
#if WASM_ENABLE_DEBUG_INTERP != 0
74+
#define TRIGGER_WATCHPOINT_SIGTRAP() \
75+
do { \
76+
wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TRAP); \
77+
CHECK_SUSPEND_FLAGS(); \
78+
} while (0)
79+
80+
#define CHECK_WATCHPOINT(list, current_addr) \
81+
do { \
82+
WASMDebugWatchPoint *watchpoint = bh_list_first_elem(list); \
83+
while (watchpoint) { \
84+
WASMDebugWatchPoint *next = bh_list_elem_next(watchpoint); \
85+
if (watchpoint->addr <= current_addr \
86+
&& watchpoint->addr + watchpoint->length > current_addr) { \
87+
TRIGGER_WATCHPOINT_SIGTRAP(); \
88+
} \
89+
watchpoint = next; \
90+
} \
91+
} while (0)
92+
93+
#define CHECK_READ_WATCHPOINT(addr, offset) \
94+
CHECK_WATCHPOINT(watch_point_list_read, WASM_ADDR_OFFSET(addr + offset))
95+
#define CHECK_WRITE_WATCHPOINT(addr, offset) \
96+
CHECK_WATCHPOINT(watch_point_list_write, WASM_ADDR_OFFSET(addr + offset))
97+
#else
98+
#define CHECK_READ_WATCHPOINT(addr, offset)
99+
#define CHECK_WRITE_WATCHPOINT(addr, offset)
100+
#endif
101+
73102
static inline uint32
74103
rotl32(uint32 n, uint32 c)
75104
{
@@ -1127,6 +1156,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
11271156

11281157
#if WASM_ENABLE_DEBUG_INTERP != 0
11291158
uint8 *frame_ip_orig = NULL;
1159+
WASMDebugInstance *debug_instance = wasm_exec_env_get_instance(exec_env);
1160+
bh_list *watch_point_list_read = &debug_instance->watch_point_list_read;
1161+
bh_list *watch_point_list_write = &debug_instance->watch_point_list_write;
11301162
#endif
11311163

11321164
#if WASM_ENABLE_LABELS_AS_VALUES != 0
@@ -1792,6 +1824,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
17921824
addr = POP_I32();
17931825
CHECK_MEMORY_OVERFLOW(4);
17941826
PUSH_I32(LOAD_I32(maddr));
1827+
CHECK_READ_WATCHPOINT(addr, offset);
17951828
(void)flags;
17961829
HANDLE_OP_END();
17971830
}
@@ -1806,6 +1839,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
18061839
addr = POP_I32();
18071840
CHECK_MEMORY_OVERFLOW(8);
18081841
PUSH_I64(LOAD_I64(maddr));
1842+
CHECK_READ_WATCHPOINT(addr, offset);
18091843
(void)flags;
18101844
HANDLE_OP_END();
18111845
}
@@ -1819,6 +1853,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
18191853
addr = POP_I32();
18201854
CHECK_MEMORY_OVERFLOW(1);
18211855
PUSH_I32(sign_ext_8_32(*(int8 *)maddr));
1856+
CHECK_READ_WATCHPOINT(addr, offset);
18221857
(void)flags;
18231858
HANDLE_OP_END();
18241859
}
@@ -1832,6 +1867,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
18321867
addr = POP_I32();
18331868
CHECK_MEMORY_OVERFLOW(1);
18341869
PUSH_I32((uint32)(*(uint8 *)maddr));
1870+
CHECK_READ_WATCHPOINT(addr, offset);
18351871
(void)flags;
18361872
HANDLE_OP_END();
18371873
}
@@ -1845,6 +1881,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
18451881
addr = POP_I32();
18461882
CHECK_MEMORY_OVERFLOW(2);
18471883
PUSH_I32(sign_ext_16_32(LOAD_I16(maddr)));
1884+
CHECK_READ_WATCHPOINT(addr, offset);
18481885
(void)flags;
18491886
HANDLE_OP_END();
18501887
}
@@ -1858,6 +1895,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
18581895
addr = POP_I32();
18591896
CHECK_MEMORY_OVERFLOW(2);
18601897
PUSH_I32((uint32)(LOAD_U16(maddr)));
1898+
CHECK_READ_WATCHPOINT(addr, offset);
18611899
(void)flags;
18621900
HANDLE_OP_END();
18631901
}
@@ -1871,6 +1909,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
18711909
addr = POP_I32();
18721910
CHECK_MEMORY_OVERFLOW(1);
18731911
PUSH_I64(sign_ext_8_64(*(int8 *)maddr));
1912+
CHECK_READ_WATCHPOINT(addr, offset);
18741913
(void)flags;
18751914
HANDLE_OP_END();
18761915
}
@@ -1884,6 +1923,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
18841923
addr = POP_I32();
18851924
CHECK_MEMORY_OVERFLOW(1);
18861925
PUSH_I64((uint64)(*(uint8 *)maddr));
1926+
CHECK_READ_WATCHPOINT(addr, offset);
18871927
(void)flags;
18881928
HANDLE_OP_END();
18891929
}
@@ -1897,6 +1937,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
18971937
addr = POP_I32();
18981938
CHECK_MEMORY_OVERFLOW(2);
18991939
PUSH_I64(sign_ext_16_64(LOAD_I16(maddr)));
1940+
CHECK_READ_WATCHPOINT(addr, offset);
19001941
(void)flags;
19011942
HANDLE_OP_END();
19021943
}
@@ -1910,6 +1951,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
19101951
addr = POP_I32();
19111952
CHECK_MEMORY_OVERFLOW(2);
19121953
PUSH_I64((uint64)(LOAD_U16(maddr)));
1954+
CHECK_READ_WATCHPOINT(addr, offset);
19131955
(void)flags;
19141956
HANDLE_OP_END();
19151957
}
@@ -1924,6 +1966,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
19241966
addr = POP_I32();
19251967
CHECK_MEMORY_OVERFLOW(4);
19261968
PUSH_I64(sign_ext_32_64(LOAD_I32(maddr)));
1969+
CHECK_READ_WATCHPOINT(addr, offset);
19271970
(void)flags;
19281971
HANDLE_OP_END();
19291972
}
@@ -1937,6 +1980,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
19371980
addr = POP_I32();
19381981
CHECK_MEMORY_OVERFLOW(4);
19391982
PUSH_I64((uint64)(LOAD_U32(maddr)));
1983+
CHECK_READ_WATCHPOINT(addr, offset);
19401984
(void)flags;
19411985
HANDLE_OP_END();
19421986
}
@@ -1953,6 +1997,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
19531997
addr = POP_I32();
19541998
CHECK_MEMORY_OVERFLOW(4);
19551999
STORE_U32(maddr, frame_sp[1]);
2000+
CHECK_WRITE_WATCHPOINT(addr, offset);
19562001
(void)flags;
19572002
HANDLE_OP_END();
19582003
}
@@ -1969,6 +2014,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
19692014
CHECK_MEMORY_OVERFLOW(8);
19702015
PUT_I64_TO_ADDR((uint32 *)maddr,
19712016
GET_I64_FROM_ADDR(frame_sp + 1));
2017+
CHECK_WRITE_WATCHPOINT(addr, offset);
19722018
(void)flags;
19732019
HANDLE_OP_END();
19742020
}
@@ -1993,7 +2039,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
19932039
CHECK_MEMORY_OVERFLOW(2);
19942040
STORE_U16(maddr, (uint16)sval);
19952041
}
1996-
2042+
CHECK_WRITE_WATCHPOINT(addr, offset);
19972043
(void)flags;
19982044
HANDLE_OP_END();
19992045
}
@@ -2023,6 +2069,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
20232069
CHECK_MEMORY_OVERFLOW(4);
20242070
STORE_U32(maddr, (uint32)sval);
20252071
}
2072+
CHECK_WRITE_WATCHPOINT(addr, offset);
20262073
(void)flags;
20272074
HANDLE_OP_END();
20282075
}

core/iwasm/libraries/debug-engine/debug_engine.c

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,8 @@ wasm_debug_instance_create(WASMCluster *cluster, int32 port)
392392
}
393393

394394
bh_list_init(&instance->break_point_list);
395+
bh_list_init(&instance->watch_point_list_read);
396+
bh_list_init(&instance->watch_point_list_write);
395397

396398
instance->cluster = cluster;
397399
exec_env = bh_list_first_elem(&cluster->exec_env_list);
@@ -452,6 +454,23 @@ wasm_debug_instance_destroy_breakpoints(WASMDebugInstance *instance)
452454
}
453455
}
454456

457+
static void
458+
wasm_debug_instance_destroy_watchpoints(WASMDebugInstance *instance,
459+
bh_list *watchpoints)
460+
{
461+
WASMDebugWatchPoint *watchpoint, *next;
462+
463+
watchpoint = bh_list_first_elem(watchpoints);
464+
while (watchpoint) {
465+
next = bh_list_elem_next(watchpoint);
466+
467+
bh_list_remove(watchpoints, watchpoint);
468+
wasm_runtime_free(watchpoint);
469+
470+
watchpoint = next;
471+
}
472+
}
473+
455474
void
456475
wasm_debug_instance_destroy(WASMCluster *cluster)
457476
{
@@ -472,6 +491,10 @@ wasm_debug_instance_destroy(WASMCluster *cluster)
472491

473492
/* destroy all breakpoints */
474493
wasm_debug_instance_destroy_breakpoints(instance);
494+
wasm_debug_instance_destroy_watchpoints(
495+
instance, &instance->watch_point_list_read);
496+
wasm_debug_instance_destroy_watchpoints(
497+
instance, &instance->watch_point_list_write);
475498

476499
os_mutex_destroy(&instance->wait_lock);
477500
os_cond_destroy(&instance->wait_cond);
@@ -995,6 +1018,65 @@ wasm_debug_instance_remove_breakpoint(WASMDebugInstance *instance, uint64 addr,
9951018
return true;
9961019
}
9971020

1021+
static bool
1022+
add_watchpoint(bh_list *list, uint64 addr, uint64 length)
1023+
{
1024+
WASMDebugWatchPoint *watchpoint;
1025+
if (!(watchpoint = wasm_runtime_malloc(sizeof(WASMDebugWatchPoint)))) {
1026+
LOG_ERROR("WASM Debug Engine error: failed to allocate memory for "
1027+
"watchpoint");
1028+
return false;
1029+
}
1030+
memset(watchpoint, 0, sizeof(WASMDebugWatchPoint));
1031+
watchpoint->addr = addr;
1032+
watchpoint->length = length;
1033+
bh_list_insert(list, watchpoint);
1034+
return true;
1035+
}
1036+
1037+
static bool
1038+
remove_watchpoint(bh_list *list, uint64 addr, uint64 length)
1039+
{
1040+
WASMDebugWatchPoint *watchpoint = bh_list_first_elem(list);
1041+
while (watchpoint) {
1042+
WASMDebugWatchPoint *next = bh_list_elem_next(watchpoint);
1043+
if (watchpoint->addr == addr && watchpoint->length == length) {
1044+
bh_list_remove(list, watchpoint);
1045+
wasm_runtime_free(watchpoint);
1046+
}
1047+
watchpoint = next;
1048+
}
1049+
return true;
1050+
}
1051+
1052+
bool
1053+
wasm_debug_instance_watchpoint_write_add(WASMDebugInstance *instance,
1054+
uint64 addr, uint64 length)
1055+
{
1056+
return add_watchpoint(&instance->watch_point_list_write, addr, length);
1057+
}
1058+
1059+
bool
1060+
wasm_debug_instance_watchpoint_write_remove(WASMDebugInstance *instance,
1061+
uint64 addr, uint64 length)
1062+
{
1063+
return remove_watchpoint(&instance->watch_point_list_write, addr, length);
1064+
}
1065+
1066+
bool
1067+
wasm_debug_instance_watchpoint_read_add(WASMDebugInstance *instance,
1068+
uint64 addr, uint64 length)
1069+
{
1070+
return add_watchpoint(&instance->watch_point_list_read, addr, length);
1071+
}
1072+
1073+
bool
1074+
wasm_debug_instance_watchpoint_read_remove(WASMDebugInstance *instance,
1075+
uint64 addr, uint64 length)
1076+
{
1077+
return remove_watchpoint(&instance->watch_point_list_read, addr, length);
1078+
}
1079+
9981080
bool
9991081
wasm_debug_instance_on_failure(WASMDebugInstance *instance)
10001082
{

core/iwasm/libraries/debug-engine/debug_engine.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ typedef struct WASMDebugBreakPoint {
3636
uint64 orignal_data;
3737
} WASMDebugBreakPoint;
3838

39+
typedef struct WASMDebugWatchPoint {
40+
bh_list_link next;
41+
uint64 addr;
42+
uint64 length;
43+
} WASMDebugWatchPoint;
44+
3945
typedef enum debug_state_t {
4046
/* Debugger state conversion sequence:
4147
* DBG_LAUNCHING ---> APP_STOPPED <---> APP_RUNNING
@@ -56,6 +62,8 @@ struct WASMDebugInstance {
5662
struct WASMDebugInstance *next;
5763
WASMDebugControlThread *control_thread;
5864
bh_list break_point_list;
65+
bh_list watch_point_list_read;
66+
bh_list watch_point_list_write;
5967
WASMCluster *cluster;
6068
uint32 id;
6169
korp_tid current_tid;
@@ -184,6 +192,22 @@ bool
184192
wasm_debug_instance_remove_breakpoint(WASMDebugInstance *instance, uint64 addr,
185193
uint64 length);
186194

195+
bool
196+
wasm_debug_instance_watchpoint_write_add(WASMDebugInstance *instance,
197+
uint64 addr, uint64 length);
198+
199+
bool
200+
wasm_debug_instance_watchpoint_write_remove(WASMDebugInstance *instance,
201+
uint64 addr, uint64 length);
202+
203+
bool
204+
wasm_debug_instance_watchpoint_read_add(WASMDebugInstance *instance,
205+
uint64 addr, uint64 length);
206+
207+
bool
208+
wasm_debug_instance_watchpoint_read_remove(WASMDebugInstance *instance,
209+
uint64 addr, uint64 length);
210+
187211
bool
188212
wasm_debug_instance_on_failure(WASMDebugInstance *instance);
189213

0 commit comments

Comments
 (0)