From 1aef0a0803fc616671b8311cbbabe6fb5c9d9883 Mon Sep 17 00:00:00 2001 From: Ze Huang Date: Fri, 8 Aug 2025 14:29:47 +0800 Subject: [PATCH 1/7] dump: add markers for probe and ast sections Add explicit markers '-- probe' and '-- ast' in dump output to improve readability. Signed-off-by: Ze Huang --- src/ply/ply.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ply/ply.c b/src/ply/ply.c index 950540d..33b3a39 100644 --- a/src/ply/ply.c +++ b/src/ply/ply.c @@ -120,8 +120,10 @@ void dump(struct ply *ply) symtab_dump(&ply->globals, stdout); ply_probe_foreach(ply, pb) { + printf("\n\n-- probe\n"); printf("%s\n", pb->probe ? : ""); + printf("\n\n-- ast\n"); if (pb->ast) ast_fprint(stdout, pb->ast); else From 4ac0b3caa9a9bf645b15359daa178586b341e59a Mon Sep 17 00:00:00 2001 From: Ze Huang Date: Tue, 12 Aug 2025 13:44:49 +0800 Subject: [PATCH 2/7] built-in: add 'uptr' function to mark userland pointer Add a uptr(x) function that can mark a value as a userland pointer, causing e.g. str(uptr(arg0)) to do the right thing and not try to read the value as kernel memory. Signed-off-by: Stefan Schake Signed-off-by: Ze Huang --- include/ply/ir.h | 3 ++- src/libply/built-in/memory.c | 42 ++++++++++++++++++++++++++++++++---- src/libply/ir.c | 11 ++++++++-- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/include/ply/ir.h b/include/ply/ir.h index 72d208d..2584183 100644 --- a/include/ply/ir.h +++ b/include/ply/ir.h @@ -148,6 +148,7 @@ struct irstate { int dot:1; int lval:1; int stack:1; + int user:1; } hint; }; @@ -177,7 +178,7 @@ void ir_emit_sym_to_reg (struct ir *ir, uint16_t dst, struct sym *src); void ir_emit_reg_to_sym (struct ir *ir, struct sym *dst, uint16_t src); void ir_emit_sym_to_stack(struct ir *ir, ssize_t offset, struct sym *src); void ir_emit_sym_to_sym (struct ir *ir, struct sym *dst, struct sym *src); -void ir_emit_read_to_sym (struct ir *ir, struct sym *dst, uint16_t src); +void ir_emit_read_to_sym (struct ir *ir, struct sym *dst, uint16_t src, int user); void ir_emit_data (struct ir *ir, ssize_t dst, const char *src, size_t size); void ir_emit_memcpy(struct ir *ir, ssize_t dst, ssize_t src, size_t size); diff --git a/src/libply/built-in/memory.c b/src/libply/built-in/memory.c index fe222b5..ff64a65 100644 --- a/src/libply/built-in/memory.c +++ b/src/libply/built-in/memory.c @@ -140,7 +140,10 @@ static int str_ir_post(const struct func *func, struct node *n, ir_emit_ldbp(pb->ir, BPF_REG_1, n->sym->irs.stack); ir_emit_insn(ir, MOV_IMM((int32_t)type_sizeof(n->sym->type)), BPF_REG_2, 0); ir_emit_sym_to_reg(ir, BPF_REG_3, ptr->sym); - ir_emit_insn(ir, CALL(BPF_FUNC_probe_read_kernel_str), 0, 0); + if (ptr->sym->irs.hint.user) + ir_emit_insn(ir, CALL(BPF_FUNC_probe_read_user_str), 0, 0); + else + ir_emit_insn(ir, CALL(BPF_FUNC_probe_read_kernel_str), 0, 0); return 0; } @@ -153,7 +156,7 @@ static int mem_ir_post(const struct func *func, struct node *n, ir_init_sym(pb->ir, n->sym); ir_emit_sym_to_reg(pb->ir, BPF_REG_3, ptr->sym); - ir_emit_read_to_sym(pb->ir, n->sym, BPF_REG_3); + ir_emit_read_to_sym(pb->ir, n->sym, BPF_REG_3, ptr->sym->irs.hint.user); return 0; } @@ -222,6 +225,36 @@ static struct func str_func = { .ir_post = str_ir_post, }; +struct type t_uptr_func = { + .ttype = T_FUNC, + .func = { .type = &t_void, .args = f_1arg }, +}; + +static int uptr_ir_post(const struct func *func, struct node *n, + struct ply_probe *pb) +{ + struct node *child = n->expr.args; + + ir_init_sym(pb->ir, n->sym); + ir_emit_sym_to_sym(pb->ir, n->sym, child->sym); + n->sym->irs.hint.user = 1; + return 0; +} + +static int uptr_type_infer(const struct func *func, struct node *n) +{ + struct node *arg = n->expr.args; + + n->sym->type = arg->sym->type; + return 0; +} + +static struct func uptr_func = { + .name = "uptr", + .type = &t_uptr_func, + .type_infer = uptr_type_infer, + .ir_post = uptr_ir_post, +}; static int struct_deref_rewrite(const struct func *func, struct node *n, struct ply_probe *pb) @@ -424,7 +457,7 @@ static int deref_ir_post(const struct func *func, struct node *n, return 0; ir_emit_sym_to_reg(pb->ir, BPF_REG_0, ptr->sym); - ir_emit_read_to_sym(pb->ir, n->sym, BPF_REG_0); + ir_emit_read_to_sym(pb->ir, n->sym, BPF_REG_0, ptr->sym->irs.hint.user); return 0; } @@ -603,7 +636,7 @@ static int map_ir_post(const struct func *func, struct node *n, lhit = ir_alloc_label(pb->ir); ir_emit_insn(pb->ir, JMP_IMM(BPF_JEQ, 0, lmiss), BPF_REG_0, 0); - ir_emit_read_to_sym(pb->ir, n->sym, BPF_REG_0); + ir_emit_read_to_sym(pb->ir, n->sym, BPF_REG_0, 0); ir_emit_insn(pb->ir, JMP_IMM(BPF_JA, 0, lhit), 0, 0); ir_emit_label(pb->ir, lmiss); @@ -948,6 +981,7 @@ void memory_init(void) built_in_register(&strcmp_func); built_in_register(&str_func); built_in_register(&mem_func); + built_in_register(&uptr_func); built_in_register(&struct_deref_func); built_in_register(&struct_dot_func); built_in_register(&deref_func); diff --git a/src/libply/ir.c b/src/libply/ir.c index 8c546ab..f7f38d8 100644 --- a/src/libply/ir.c +++ b/src/libply/ir.c @@ -42,6 +42,10 @@ static const char *bpf_func_name(enum bpf_func_id id) return "probe_read_kernel"; case BPF_FUNC_probe_read_kernel_str: return "probe_read_kernel_str"; + case BPF_FUNC_probe_read_user: + return "probe_read_user"; + case BPF_FUNC_probe_read_user_str: + return "probe_read_user_str"; case BPF_FUNC_trace_printk: return "trace_printk"; default: @@ -405,7 +409,7 @@ void ir_emit_sym_to_sym(struct ir *ir, struct sym *dst, struct sym *src) } } -void ir_emit_read_to_sym(struct ir *ir, struct sym *dst, uint16_t src) +void ir_emit_read_to_sym(struct ir *ir, struct sym *dst, uint16_t src, int user) { struct irstate *irs = &dst->irs; @@ -416,7 +420,10 @@ void ir_emit_read_to_sym(struct ir *ir, struct sym *dst, uint16_t src) if (src != BPF_REG_3) ir_emit_insn(ir, MOV, BPF_REG_3, src); - ir_emit_insn(ir, CALL(BPF_FUNC_probe_read_kernel), 0, 0); + if (user) + ir_emit_insn(ir, CALL(BPF_FUNC_probe_read_user), 0, 0); + else + ir_emit_insn(ir, CALL(BPF_FUNC_probe_read_kernel), 0, 0); /* TODO if (r0) exit(r0); */ } From 0594542e1ae8d793153ae96c1bd51acd176256f5 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Tue, 19 Aug 2025 10:48:18 +0200 Subject: [PATCH 3/7] grammar: Abort when encountering invalid probes Before this change, an invalid probe would cause an error message to be emitted, but execution still proceeded. Make sure that we abort the entire session if all requested probes can not be used. --- src/libply/grammar.y | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libply/grammar.y b/src/libply/grammar.y index 792a732..9790bf3 100644 --- a/src/libply/grammar.y +++ b/src/libply/grammar.y @@ -61,8 +61,8 @@ probes ; probe -: PSPEC stmt { __ply_probe_alloc(ply, $1, $2); } -| PSPEC predicate { __ply_probe_alloc(ply, $1, $2); } +: PSPEC stmt { if (__ply_probe_alloc(ply, $1, $2)) YYABORT; } +| PSPEC predicate { if (__ply_probe_alloc(ply, $1, $2)) YYABORT; } ; /* Support dtrace-style predicates as well as normal if guards. I.e. From 629973b8b97450d9072b2a4ce2272b8901e4ba94 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Mon, 18 Aug 2025 13:29:09 +0200 Subject: [PATCH 4/7] begin/end: Remove some special casing around begin/end probes Add start/stop hooks to providers, and run BEGIN/END probes from there, rather than having a bunch of special cases sprinkled throughout libply.c. --- include/ply/provider.h | 2 ++ src/libply/libply.c | 62 +++++++++++++---------------------- src/libply/provider/special.c | 9 +++++ 3 files changed, 34 insertions(+), 39 deletions(-) diff --git a/include/ply/provider.h b/include/ply/provider.h index 67709a1..7db0e89 100644 --- a/include/ply/provider.h +++ b/include/ply/provider.h @@ -26,6 +26,8 @@ struct provider { int (*ir_pre) (struct ply_probe *); int (*ir_post) (struct ply_probe *); int (*attach) (struct ply_probe *); + int (*start) (struct ply_probe *); + int (*stop) (struct ply_probe *); int (*detach) (struct ply_probe *); }; diff --git a/src/libply/libply.c b/src/libply/libply.c index 2141cc2..f011986 100644 --- a/src/libply/libply.c +++ b/src/libply/libply.c @@ -243,7 +243,7 @@ static int ply_unload_detach(struct ply *ply) int err; ply_probe_foreach(ply, pb) { - if (pb->special) + if (!pb->provider->detach) continue; err = pb->provider->detach(pb); @@ -259,21 +259,8 @@ int ply_unload(struct ply *ply) struct ply_probe *pb; int err; - /* run END probe at last */ - ply_probe_foreach(ply, pb) { - if (!pb->special || strcmp(pb->provider->name, "END")) - continue; - - err = bpf_prog_test_run(pb->bpf_fd); - if (err) - return err; - - /* read buffer again for END trigger */ - if (ply->stdbuf) - buffer_loop((struct buffer *)ply->stdbuf->priv, 0); - } - - err = ply_unload_bpf(ply); + err = ply_unload_detach(ply); + err |= ply_unload_bpf(ply); err |= ply_unload_map(ply); return err; } @@ -382,23 +369,7 @@ static struct ply_return ply_load_attach(struct ply *ply) int err; ply_probe_foreach(ply, pb) { - if (!pb->special || strcmp(pb->provider->name, "BEGIN")) - continue; - - err = bpf_prog_test_run(pb->bpf_fd); - if (err) - goto err; - - /* read buffer for BEGIN trigger */ - if (ply->stdbuf) { - ret = buffer_loop((struct buffer *)ply->stdbuf->priv, 0); - if (ret.exit || ret.err) - return ret; - } - } - - ply_probe_foreach(ply, pb) { - if (pb->special) + if (!pb->provider->attach) continue; err = pb->provider->attach(pb); @@ -469,19 +440,32 @@ int ply_stop(struct ply *ply) return err; } - err = ply_unload_detach(ply); - if (err) - return err; + ply_probe_foreach(ply, pb) { + if (!pb->provider->stop) + continue; - /* flush existing buffer entries */ - if (ply->stdbuf) - buffer_loop((struct buffer *)ply->stdbuf->priv, 0); + err = pb->provider->stop(pb); + if (err) + return err; + } return 0; } int ply_start(struct ply *ply) { + struct ply_probe *pb; + int err; + + ply_probe_foreach(ply, pb) { + if (!pb->provider->start) + continue; + + err = pb->provider->start(pb); + if (err) + return err; + } + if (ply->group_fd < 0) return 0; diff --git a/src/libply/provider/special.c b/src/libply/provider/special.c index bc4f9b5..cc99d6c 100644 --- a/src/libply/provider/special.c +++ b/src/libply/provider/special.c @@ -9,6 +9,11 @@ #include #include +static int special_exec(struct ply_probe *pb) +{ + return bpf_prog_test_run(pb->bpf_fd); +} + static int special_sym_alloc(struct ply_probe *pb, struct node *n) { return -ENOENT; @@ -26,6 +31,8 @@ struct provider begin_provider = { .probe = special_probe, .sym_alloc = special_sym_alloc, + + .start = special_exec, }; struct provider end_provider = { @@ -34,4 +41,6 @@ struct provider end_provider = { .probe = special_probe, .sym_alloc = special_sym_alloc, + + .stop = special_exec, }; From b2498c9ae71720676a62db241dd8043cbcd64d0d Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Mon, 18 Aug 2025 13:31:25 +0200 Subject: [PATCH 5/7] ply: Fix SIGCHLD from inferior exit sporadically being lost Intermittently, a command like `ply -c "sleep 1" ''` would not terminate after the sleep process terminated. This was because the old logic relied on SIGCHLD being delivered to ply while blocked on ply_loop(). In other cases, it would be lost and the ply process would hang until terminated with a SIGINT or similar. Fix this by letting the user of libply get a copy of the fds to poll and then calling ply_service() whenever an event comes in. This way, we can fold in the signal monitoring into the main loop using a signalfd, which libply does not have to be aware of. --- include/ply/buffer.h | 7 +- include/ply/ply.h | 21 ++++- src/libply/built-in/buffer.c | 66 +++++++--------- src/libply/libply.c | 24 ++++-- src/ply/ply.c | 146 +++++++++++++++++++++++++++++++---- 5 files changed, 201 insertions(+), 63 deletions(-) diff --git a/include/ply/buffer.h b/include/ply/buffer.h index d4df3e9..43ed4f7 100644 --- a/include/ply/buffer.h +++ b/include/ply/buffer.h @@ -8,6 +8,7 @@ #define _PLY_BUFFER_H #include +#include #include @@ -34,8 +35,10 @@ void buffer_evh_register(struct buffer_evh *evh); struct buffer; -struct buffer *buffer_new(int mapfd); +struct ply_return buffer_service(struct buffer *buf, int ready, struct pollfd *fds); +void buffer_fill_pollset(struct buffer *buf, struct pollfd *fds); +nfds_t buffer_get_nfds(struct buffer *buf); -struct ply_return buffer_loop(struct buffer *buf, int timeout); +struct buffer *buffer_new(int mapfd); #endif /* _PLY_BUFFER_H */ diff --git a/include/ply/ply.h b/include/ply/ply.h index 7f38a76..8e37493 100644 --- a/include/ply/ply.h +++ b/include/ply/ply.h @@ -8,6 +8,7 @@ #define _PLY_H #include +#include #include "sym.h" #include "utils.h" @@ -23,6 +24,22 @@ struct ply_return { unsigned exit:1; }; +static inline void ply_return_fold(struct ply_return *ret, struct ply_return new) +{ + if (ret->err) + return; + + if (new.err) { + *ret = new; + return; + } + + if (ret->exit) + return; + + *ret = new; +} + /* api */ struct ply_probe { struct ply_probe *next, *prev; @@ -83,7 +100,9 @@ void ply_maps_print(struct ply *ply); void ply_map_print(struct ply *ply, struct sym *sym, FILE *fp); void ply_map_clear(struct ply *ply, struct sym *sym); -struct ply_return ply_loop(struct ply *ply); +struct ply_return ply_service(struct ply *ply, int ready, struct pollfd *fds); +nfds_t ply_get_nfds(struct ply *ply); +void ply_fill_pollset(struct ply *ply, struct pollfd *fds); int ply_start(struct ply *ply); int ply_stop(struct ply *ply); diff --git a/src/libply/built-in/buffer.c b/src/libply/built-in/buffer.c index 541e051..36bd7ad 100644 --- a/src/libply/built-in/buffer.c +++ b/src/libply/built-in/buffer.c @@ -153,43 +153,7 @@ struct ply_return buffer_q_drain(struct buffer_q *q) return ret; } -struct ply_return buffer_loop(struct buffer *buf, int timeout) -{ - struct ply_return ret; - uint32_t cpu; - int ready; - - for (;;) { - ready = poll(buf->poll, buf->ncpus, timeout); - if (ready < 0) { - ret.err = 1; - ret.val = errno; - return ret; - } - - if (timeout == -1) { - assert(ready); - } else if (ready == 0) { - ret.err = 0; - return ret; - } - - for (cpu = 0; ready && (cpu < buf->ncpus); cpu++) { - if (!(buf->poll[cpu].revents & POLLIN)) - continue; - - ret = buffer_q_drain(&buf->q[cpu]); - if (ret.err | ret.exit) - return ret; - - ready--; - } - } - - return ret; -} - -int buffer_q_init(struct buffer *buf, uint32_t cpu) +static int buffer_q_init(struct buffer *buf, uint32_t cpu) { struct perf_event_attr attr = { 0 }; struct buffer_q *q = &buf->q[cpu]; @@ -225,6 +189,34 @@ int buffer_q_init(struct buffer *buf, uint32_t cpu) return 0; } +struct ply_return buffer_service(struct buffer *buf, int ready, struct pollfd *fds) +{ + struct ply_return ret = {}; + uint32_t cpu; + + for (cpu = 0; ready && (cpu < buf->ncpus); cpu++) { + if (!(fds[cpu].revents & POLLIN)) + continue; + + ret = buffer_q_drain(&buf->q[cpu]); + ready--; + if (ret.err || ret.exit) + break; + } + + return ret; +} + +void buffer_fill_pollset(struct buffer *buf, struct pollfd *fds) +{ + memcpy(fds, buf->poll, buf->ncpus * sizeof(*fds)); +} + +nfds_t buffer_get_nfds(struct buffer *buf) +{ + return buf->ncpus; +} + struct buffer *buffer_new(int mapfd) { struct buffer *buf; diff --git a/src/libply/libply.c b/src/libply/libply.c index f011986..0e86e50 100644 --- a/src/libply/libply.c +++ b/src/libply/libply.c @@ -419,14 +419,26 @@ struct ply_return ply_load(struct ply *ply) } -struct ply_return ply_loop(struct ply *ply) +struct ply_return ply_service(struct ply *ply, int ready, struct pollfd *fds) { - if (!ply->stdbuf) { - pause(); - return (struct ply_return){ .err = 1, .val = EINTR }; - } + if (ply->stdbuf) + return buffer_service(ply->stdbuf->priv, ready, fds); + + return (struct ply_return){ .err = 0, .val = 0 }; +} + +nfds_t ply_get_nfds(struct ply *ply) +{ + if (ply->stdbuf) + return buffer_get_nfds(ply->stdbuf->priv); - return buffer_loop((struct buffer *)ply->stdbuf->priv, -1); + return 0; +} + +void ply_fill_pollset(struct ply *ply, struct pollfd *fds) +{ + if (ply->stdbuf) + buffer_fill_pollset(ply->stdbuf->priv, fds); } int ply_stop(struct ply *ply) diff --git a/src/ply/ply.c b/src/ply/ply.c index 33b3a39..d7fff80 100644 --- a/src/ply/ply.c +++ b/src/ply/ply.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -14,6 +15,7 @@ #include #include +#include #include #include @@ -215,25 +217,78 @@ int inferior_prep(const char *cmd, int *infpid, int *inftrig) return execl("/bin/sh", "sh", "-c", cmd, NULL); } -static int term_sig = 0; -static void term(int sig) +static sigset_t orig_sigmask; + +struct ply_return sig_handle(int fd) +{ + struct signalfd_siginfo si; + int status; + + if (read(fd, &si, sizeof(si)) != sizeof(si)) { + return (struct ply_return) { + .err = 1, + .val = -EIO, + }; + } + + switch (si.ssi_signo) { + case SIGCHLD: + _d("SIGCHLD\n"); + waitpid(0, &status, WNOHANG); + return (struct ply_return) { + .exit = 0, + .val = 0, + }; + case SIGINT: + _d("SIGINT\n"); + return (struct ply_return) { + .exit = 1, + .val = 1, + }; + } + + _e("Unexpected signal: %u\n", si.ssi_signo); + return (struct ply_return) { + .err = 1, + .val = -EINVAL, + }; +} + +void sig_exit(int fd) { - term_sig = sig; - return; + close(fd); + sigprocmask(SIG_SETMASK, &orig_sigmask, NULL); +} + +int sig_init(void) +{ + sigset_t mask; + int fd; + + sigemptyset(&mask); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGCHLD); + + if (sigprocmask(SIG_BLOCK, &mask, &orig_sigmask) == -1) + return -errno; + + fd = signalfd(-1, &mask, SFD_CLOEXEC); + if (fd == -1) + return -errno; + + return fd; } -static const struct sigaction term_action = { - .sa_handler = term, - .sa_flags = 0, -}; int main(int argc, char **argv) { - struct ply *ply; struct ply_return ret = { .err = 1 }; - int opt, infpid, inftrig; + int opt, infpid, inftrig, sfd, ready; + struct pollfd *fds = NULL; int f_dryrun, f_dump; - FILE *src; char *cmd = NULL; + struct ply *ply; + nfds_t nfds; + FILE *src; f_dryrun = f_dump = 0; while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) > 0) { @@ -306,18 +361,46 @@ int main(int argc, char **argv) if (f_dryrun) goto unload; + sfd = sig_init(); + if (sfd < 0) { + ret.val = sfd; + goto err; + } + + fds = malloc(sizeof(*fds)); + if (!fds) { + ret.val = -ENOMEM; + goto err; + } + + *fds = (struct pollfd) { + .fd = sfd, + .events = POLLIN, + }; + memlock_uncap(); ret = ply_load(ply); if (ret.exit || ret.err) goto err; + nfds = ply_get_nfds(ply); + if (nfds) { + fds = realloc(fds, (1 + nfds) * sizeof(*fds)); + if (!fds) { + ret = (struct ply_return) { + .err = 1, + .val = -ENOMEM, + }; + goto err; + } + + ply_fill_pollset(ply, &fds[1]); + } + ply_start(ply); _d("ply: active\n"); - sigaction(SIGINT, &term_action, NULL); - sigaction(SIGCHLD, &term_action, NULL); - if (cmd) { int err = 0; @@ -329,13 +412,42 @@ int main(int argc, char **argv) } } - ret = ply_loop(ply); - if (ret.err && (ret.val == EINTR) && term_sig) - ret.err = 0; + for (;;) { + ready = poll(fds, 1 + nfds, -1); + if (ready < 0) { + ret = (struct ply_return) { + .err = 1, + .val = errno, + }; + break; + } + + if (fds[0].revents & POLLIN) { + ret = sig_handle(sfd); + if (--ready == 0) + break; + } + + ply_return_fold(&ret, ply_service(ply, ready, &fds[1])); + if (ret.err || ret.exit) + break; + } + + sig_exit(sfd); + stop: _d("ply: deactivating\n"); ply_stop(ply); + /* END probes may generate events, so do a final poll for them + * before shutting down. + */ + ready = poll(&fds[1], nfds, 0); + if (ready > 0) + ply_return_fold(&ret, ply_service(ply, ready, &fds[1])); + + free(fds); + ply_maps_print(ply); unload: From f49917716edf0108c7e6ab9a9f9f2db30f980878 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Tue, 19 Aug 2025 12:45:58 +0200 Subject: [PATCH 6/7] test: Silence status output from dd processes --- test/rootfs/lib/ply/test.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/rootfs/lib/ply/test.sh b/test/rootfs/lib/ply/test.sh index 8135a6f..6bf3457 100755 --- a/test/rootfs/lib/ply/test.sh +++ b/test/rootfs/lib/ply/test.sh @@ -43,7 +43,7 @@ case=print && ply_simple 'print("test"); exit(0);' && \ case=wildcard ply -c \ - "dd if=/dev/zero of=/dev/null bs=1 count=100" \ + "dd if=/dev/zero of=/dev/null bs=1 count=100 status=none" \ "kprobe:vfs_*r[ei][at][de] { @[comm, caller] = count(); }" >/tmp/wildcard \ && \ cat /tmp/wildcard | awk ' @@ -56,7 +56,7 @@ cat /tmp/wildcard | awk ' if atomics_supported; then case=quantize ply -c \ - "dd if=/dev/zero of=/dev/null bs=10240 count=10" \ + "dd if=/dev/zero of=/dev/null bs=10240 count=10 status=none" \ 'kr:vfs_read if (!strcmp(comm, "dd")) { @["rdsz"] = quantize(retval); }' >/tmp/quantize \ @@ -66,7 +66,7 @@ if atomics_supported; then fi case=interval -ply -c 'for i in `seq 3`; do dd if=/dev/zero of=/dev/null count=10; sleep 1; done' \ +ply -c 'for i in `seq 3`; do dd if=/dev/zero of=/dev/null count=10 status=none; sleep 1; done' \ 'k:vfs_read { @[pid] = count(); } i:1 { print(@); clear(@); }' >/tmp/interval \ && \ From d458be31e1ad78abd82deb97dff291fbeec56f4d Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Tue, 12 Aug 2025 22:54:22 +0200 Subject: [PATCH 7/7] test: Add regression test for user pointers --- test/rootfs/lib/ply/test.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/rootfs/lib/ply/test.sh b/test/rootfs/lib/ply/test.sh index 6bf3457..4a36e7f 100755 --- a/test/rootfs/lib/ply/test.sh +++ b/test/rootfs/lib/ply/test.sh @@ -2,6 +2,11 @@ total_fails=0 +has_syscall() +{ + [ -e /sys/kernel/debug/tracing/events/syscalls/sys_enter_$1 ] +} + atomics_supported() { case $(uname -m) in @@ -99,4 +104,23 @@ cat /tmp/profile | awk -F': ' ' END { exit(count != 100); }' \ || fail "count should be 100 for profile provider test" "$(cat /tmp/profile)" +case=uptr + +# Check for all variants of open(2). NOTE: The original open() is +# _not_ always available (aarch64). +probes= +for open in open openat openat2; do + has_syscall $open || continue + + probes="${probes} + tracepoint:syscalls/sys_enter_${open} { + print(\"${open}\", str(uptr(data->filename))); + }" +done + +ply -c 'cat /etc/hostname >/dev/null' "${probes}" >/tmp/uptr \ +&& \ +grep -qe "/etc/hostname" /tmp/uptr \ +|| fail "open{,at,at2} , /etc/hostname" "$(cat /tmp/uptr)" + exit $total_fails