Skip to content

Commit 636cf0e

Browse files
committed
replay: Support watch point event for variables
$ cat watch-test.c int global = 7; void foo(void) { global = 42; } int main(void) { foo(); return 0; } $ uftrace -W var:global a.out # DURATION TID FUNCTION [ 11752] | __monstartup() { [ 11752] | /* watch:var (global=7) */ 9.139 us [ 11752] | } /* __monstartup */ 0.450 us [ 11752] | __cxa_atexit(); [ 11752] | main() { [ 11752] | foo() { [ 11752] | /* watch:var (global=42) */ 2.190 us [ 11752] | } /* foo */ 3.447 us [ 11752] | } /* main */ Signed-off-by: Namhyung Kim <[email protected]>
1 parent 92924b1 commit 636cf0e

File tree

7 files changed

+138
-15
lines changed

7 files changed

+138
-15
lines changed

cmds/dump.c

+14-1
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,20 @@ static void pr_retval(struct uftrace_fstack_args *args)
497497
static void pr_event(struct uftrace_task_reader *task, unsigned evt_id)
498498
{
499499
char *evt_name = event_get_name(task->h, evt_id);
500-
char *evt_data = event_get_data_str(evt_id, task->args.data, false);
500+
struct uftrace_symbol *sym = NULL;
501+
char *evt_data;
502+
503+
if (evt_id == EVENT_ID_WATCH_VAR) {
504+
unsigned long long addr = 0;
505+
506+
if (data_is_lp64(task->h))
507+
memcpy(&addr, task->args.data, 8);
508+
else
509+
memcpy(&addr, task->args.data, 4);
510+
511+
sym = task_find_sym_addr(&task->h->sessions, task, task->ustack.time, addr);
512+
}
513+
evt_data = event_get_data_str(task->h, evt_id, task->args.data, task->args.len, sym, false);
501514

502515
pr_out(" %s", evt_name);
503516
if (evt_data)

cmds/replay.c

+20-3
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,6 @@ static void print_event(struct uftrace_task_reader *task, struct uftrace_record
280280
{
281281
unsigned evt_id = urec->addr;
282282
char *evt_name = event_get_name(task->h, evt_id);
283-
char *evt_data = event_get_data_str(evt_id, task->args.data, true);
284283

285284
if (evt_id == EVENT_ID_EXTERN_DATA) {
286285
pr_color(color, "%s: %s", evt_name, (char *)task->args.data);
@@ -290,14 +289,32 @@ static void print_event(struct uftrace_task_reader *task, struct uftrace_record
290289
pr_color(color, "%s", evt_name);
291290
}
292291
else {
292+
char *evt_data;
293+
struct uftrace_symbol *sym = NULL;
294+
295+
if (evt_id == EVENT_ID_WATCH_VAR) {
296+
unsigned long long addr = 0;
297+
298+
if (data_is_lp64(task->h))
299+
memcpy(&addr, task->args.data, 8);
300+
else
301+
memcpy(&addr, task->args.data, 4);
302+
303+
sym = task_find_sym_addr(&task->h->sessions, task, task->ustack.time, addr);
304+
}
305+
306+
evt_data = event_get_data_str(task->h, evt_id, task->args.data, task->args.len, sym,
307+
true);
308+
293309
pr_color(color, "%s", evt_name);
294310

295-
if (evt_data)
311+
if (evt_data) {
296312
pr_color(color, " (%s)", evt_data);
313+
free(evt_data);
314+
}
297315
}
298316

299317
free(evt_name);
300-
free(evt_data);
301318
}
302319

303320
static int print_flat_rstack(struct uftrace_data *handle, struct uftrace_task_reader *task,

cmds/script.c

+14-1
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,22 @@ static int run_script_for_rstack(struct uftrace_data *handle, struct uftrace_tas
123123
.timestamp = rstack->time,
124124
.address = rstack->addr,
125125
};
126+
struct uftrace_symbol *watch_sym = NULL;
127+
128+
if (rstack->addr == EVENT_ID_WATCH_VAR) {
129+
unsigned long long addr = 0;
130+
131+
if (data_is_lp64(task->h))
132+
memcpy(&addr, task->args.data, 8);
133+
else
134+
memcpy(&addr, task->args.data, 4);
135+
136+
watch_sym = task_find_sym_addr(sessions, task, rstack->time, addr);
137+
}
126138

127139
sc_ctx.name = event_get_name(handle, rstack->addr);
128-
sc_ctx.argbuf = event_get_data_str(rstack->addr, task->args.data, false);
140+
sc_ctx.argbuf = event_get_data_str(handle, rstack->addr, task->args.data,
141+
task->args.len, watch_sym, false);
129142

130143
script_uftrace_event(&sc_ctx);
131144

uftrace.h

+10
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,16 @@ struct uftrace_event {
641641
char *event;
642642
};
643643

644+
struct uftrace_watch_event {
645+
union {
646+
int cpu;
647+
struct {
648+
uint64_t addr;
649+
uint64_t data;
650+
} var;
651+
};
652+
};
653+
644654
#define HTML_HEADER \
645655
"<html>\n" \
646656
"<head></head>\n" \

utils/event.c

+35-5
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ char *event_get_name(struct uftrace_data *handle, unsigned evt_id)
118118
case EVENT_ID_WATCH_CPU:
119119
xasprintf(&evt_name, "watch:cpu");
120120
break;
121+
case EVENT_ID_WATCH_VAR:
122+
xasprintf(&evt_name, "watch:var");
123+
break;
121124
default:
122125
xasprintf(&evt_name, "builtin_event:%u", evt_id);
123126
break;
@@ -140,14 +143,18 @@ char *event_get_name(struct uftrace_data *handle, unsigned evt_id)
140143

141144
/**
142145
* event_get_data_str - convert event data to a string
146+
* @handle - handle to uftrace data
143147
* @evt_id - event id
144148
* @data - raw event data
149+
* @len - length of event data
150+
* @sym - associated symbol (if any)
145151
* @verbose - whether it needs the verbose format
146152
*
147153
* This function returns a string of event name matching to @evt_id.
148154
* Callers must free the returned string.
149155
*/
150-
char *event_get_data_str(unsigned evt_id, void *data, bool verbose)
156+
char *event_get_data_str(struct uftrace_data *handle, unsigned evt_id, void *data, int len,
157+
struct uftrace_symbol *sym, bool verbose)
151158
{
152159
char *str = NULL;
153160
const char *diff = "";
@@ -158,7 +165,7 @@ char *event_get_data_str(unsigned evt_id, void *data, bool verbose)
158165
struct uftrace_pmu_cycle cycle;
159166
struct uftrace_pmu_cache cache;
160167
struct uftrace_pmu_branch branch;
161-
int cpu;
168+
struct uftrace_watch_event watch;
162169
} u;
163170

164171
switch (evt_id) {
@@ -237,8 +244,28 @@ char *event_get_data_str(unsigned evt_id, void *data, bool verbose)
237244
break;
238245

239246
case EVENT_ID_WATCH_CPU:
240-
memcpy(&u.cpu, data, sizeof(u.cpu));
241-
xasprintf(&str, "cpu=%d", u.cpu);
247+
memcpy(&u.watch, data, sizeof(u.watch.cpu));
248+
xasprintf(&str, "cpu=%d", u.watch.cpu);
249+
break;
250+
251+
case EVENT_ID_WATCH_VAR:
252+
u.watch.var.addr = 0;
253+
u.watch.var.data = 0;
254+
255+
if (data_is_lp64(handle)) {
256+
memcpy(&u.watch.var.addr, data, 8);
257+
memcpy(&u.watch.var.data, data + 8, len - 8);
258+
}
259+
else {
260+
memcpy(&u.watch.var.addr, data, 4);
261+
memcpy(&u.watch.var.data, data + 4, len - 4);
262+
}
263+
264+
if (sym)
265+
xasprintf(&str, "%s=%" PRIx64, sym->name, u.watch.var.data);
266+
else
267+
xasprintf(&str, "[%#" PRIx64 "]=%" PRIx64, u.watch.var.addr,
268+
u.watch.var.data);
242269
break;
243270

244271
default:
@@ -339,6 +366,7 @@ TEST_CASE(event_name)
339366
{ EVENT_ID_READ_PMU_CACHE, "read:pmu-cache" },
340367
{ EVENT_ID_DIFF_PMU_CACHE, "diff:pmu-cache" },
341368
{ EVENT_ID_WATCH_CPU, "watch:cpu" },
369+
{ EVENT_ID_WATCH_VAR, "watch:var" },
342370
};
343371

344372
pr_dbg("testing event name strings\n");
@@ -355,6 +383,7 @@ TEST_CASE(event_data)
355383
{
356384
char msg[] = "this is external data.";
357385
char comm[] = "taskname";
386+
struct uftrace_data handle = {};
358387
struct uftrace_page_fault pgfault = { 1977, 1102 };
359388
struct uftrace_pmu_cycle cycle = { 1024, 2048 };
360389
int cpu = 123;
@@ -374,7 +403,8 @@ TEST_CASE(event_data)
374403

375404
pr_dbg("testing event data strings\n");
376405
for (i = 0; i < ARRAY_SIZE(expected); i++) {
377-
char *got = event_get_data_str(expected[i].evt_id, expected[i].data, true);
406+
char *got = event_get_data_str(&handle, expected[i].evt_id, expected[i].data, 0,
407+
NULL, true);
378408
TEST_STREQ(expected[i].str, got);
379409
free(got);
380410
}

utils/event.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <stdint.h>
66

77
struct uftrace_data;
8+
struct uftrace_symbol;
89

910
/* please see man proc(5) for /proc/[pid]/statm */
1011
struct uftrace_proc_statm {
@@ -34,7 +35,8 @@ struct uftrace_pmu_branch {
3435
};
3536

3637
char *event_get_name(struct uftrace_data *handle, unsigned evt_id);
37-
char *event_get_data_str(unsigned evt_id, void *data, bool verbose);
38+
char *event_get_data_str(struct uftrace_data *handle, unsigned evt_id, void *data, int len,
39+
struct uftrace_symbol *sym, bool verbose);
3840

3941
void finish_events_file(struct uftrace_data *handle);
4042
int read_events_file(struct uftrace_data *handle);

utils/fstack.c

+42-4
Original file line numberDiff line numberDiff line change
@@ -1388,6 +1388,37 @@ static int read_task_event_size(struct uftrace_task_reader *task, void *buf, siz
13881388
return 0;
13891389
}
13901390

1391+
static int read_task_watch_event(struct uftrace_task_reader *task,
1392+
struct uftrace_watch_event *watch, uint16_t *plen)
1393+
{
1394+
uint16_t len;
1395+
1396+
memset(&watch->var, 0, sizeof(watch->var));
1397+
1398+
if (fread(&len, sizeof(len), 1, task->fp) != 1)
1399+
return -1;
1400+
1401+
*plen = len;
1402+
1403+
if (data_is_lp64(task->h)) {
1404+
if (fread(&watch->var.addr, 8, 1, task->fp) != 1)
1405+
return -1;
1406+
1407+
len -= 8;
1408+
}
1409+
else {
1410+
if (fread(&watch->var.addr, 4, 1, task->fp) != 1)
1411+
return -1;
1412+
1413+
len -= 4;
1414+
}
1415+
1416+
if (fread(&watch->var.data, len, 1, task->fp) != 1)
1417+
return -1;
1418+
1419+
return 0;
1420+
}
1421+
13911422
static void save_task_event(struct uftrace_task_reader *task, void *buf, size_t buflen)
13921423
{
13931424
int rem;
@@ -1413,8 +1444,9 @@ int read_task_event(struct uftrace_task_reader *task, struct uftrace_record *rec
14131444
struct uftrace_pmu_cycle cycle;
14141445
struct uftrace_pmu_cache cache;
14151446
struct uftrace_pmu_branch branch;
1416-
int cpu;
1447+
struct uftrace_watch_event watch;
14171448
} u;
1449+
uint16_t len;
14181450

14191451
switch (rec->addr) {
14201452
case EVENT_ID_READ_PROC_STATM:
@@ -1484,12 +1516,18 @@ int read_task_event(struct uftrace_task_reader *task, struct uftrace_record *rec
14841516
break;
14851517

14861518
case EVENT_ID_WATCH_CPU:
1487-
if (read_task_event_size(task, &u.cpu, sizeof(u.cpu)) < 0)
1519+
if (read_task_event_size(task, &u.watch.cpu, sizeof(u.watch.cpu)) < 0)
14881520
return -1;
14891521
if (task->h->needs_byte_swap)
1490-
u.cpu = bswap_32(u.cpu);
1522+
u.watch.cpu = bswap_32(u.watch.cpu);
14911523

1492-
save_task_event(task, &u.cpu, sizeof(u.cpu));
1524+
save_task_event(task, &u.watch.cpu, sizeof(u.watch.cpu));
1525+
break;
1526+
1527+
case EVENT_ID_WATCH_VAR:
1528+
if (read_task_watch_event(task, &u.watch, &len) < 0)
1529+
return -1;
1530+
save_task_event(task, &u.watch, len);
14931531
break;
14941532

14951533
default:

0 commit comments

Comments
 (0)