Re: [PATCH 16/31] perf tools: Add prologue for BPF programs for fetching arguments
On 2015/10/15 13:26, Namhyung Kim wrote: On Wed, Oct 14, 2015 at 12:41:27PM +, Wang Nan wrote: From: He Kuang This patch generates prologue for a BPF program which fetch arguments for it. With this patch, the program can have arguments as follow: SEC("lock_page=__lock_page page->flags") int lock_page(struct pt_regs *ctx, int err, unsigned long flags) { return 1; } This patch passes at most 3 arguments from r3, r4 and r5. r1 is still the ctx pointer. r2 is used to indicate the successfulness of dereferencing. This patch uses r6 to hold ctx (struct pt_regs) and r7 to hold stack pointer for result. Result of each arguments first store on stack: low address BPF_REG_FP - 24 ARG3 BPF_REG_FP - 16 ARG2 BPF_REG_FP - 8 ARG1 BPF_REG_FP high address Then loaded into r3, r4 and r5. The output prologue for offn(...off2(off1(reg should be: r6 <- r1 // save ctx into a callee saved register r7 <- fp r7 <- r7 - stack_offset// pointer to result slot /* load r3 with the offset in pt_regs of 'reg' */ (r7) <- r3 // make slot valid r3 <- r3 + off1// prepare to read unsafe pointer r2 <- 8 r1 <- r7 // result put onto stack call probe_read // read unsafe pointer jnei r0, 0, err // error checking r3 <- (r7) // read result r3 <- r3 + off2// prepare to read unsafe pointer r2 <- 8 r1 <- r7 call probe_read jnei r0, 0, err ... /* load r2, r3, r4 from stack */ goto success err: r2 <- 1 /* load r3, r4, r5 with 0 */ goto usercode success: r2 <- 0 usercode: r1 <- r6 // restore ctx // original user code If all of arguments reside in register (dereferencing is not required), gen_prologue_fastpath() will be used to create fast prologue: r3 <- (r1 + offset of reg1) r4 <- (r1 + offset of reg2) r5 <- (r1 + offset of reg3) r2 <- 0 P.S. eBPF calling convention is defined as: * r0- return value from in-kernel function, and exit value for eBPF program * r1 - r5 - arguments from eBPF program to in-kernel function * r6 - r9 - callee saved registers that in-kernel function will preserve * r10 - read-only frame pointer to access stack Signed-off-by: He Kuang Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3or...@163.com Cc: Arnaldo Carvalho de Melo Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngk...@git.kernel.org --- [SNIP] +int bpf__gen_prologue(struct probe_trace_arg *args, int nargs, + struct bpf_insn *new_prog, size_t *new_cnt, + size_t cnt_space) +{ + struct bpf_insn *success_code = NULL; + struct bpf_insn *error_code = NULL; + struct bpf_insn *user_code = NULL; + struct bpf_insn_pos pos; + bool fastpath = true; + int i; + + if (!new_prog || !new_cnt) + return -EINVAL; + + pos.begin = new_prog; + pos.end = new_prog + cnt_space; + pos.pos = new_prog; + + if (!nargs) { + ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 0), + ); + + if (check_pos()) + goto errout; + + *new_cnt = pos_get_cnt(); + return 0; + } + + if (nargs > BPF_PROLOGUE_MAX_ARGS) + nargs = BPF_PROLOGUE_MAX_ARGS; Wouldn't it be better to inform user if it ignored some arguments? Correct. I'd like to add a notification in next version: diff --git a/tools/perf/util/bpf-prologue.c b/tools/perf/util/bpf-prologue.c index e4adb18..36093d9 100644 --- a/tools/perf/util/bpf-prologue.c +++ b/tools/perf/util/bpf-prologue.c @@ -337,8 +337,10 @@ int bpf__gen_prologue(struct probe_trace_arg *args, int nargs, return 0; } - if (nargs > BPF_PROLOGUE_MAX_ARGS) + if (nargs > BPF_PROLOGUE_MAX_ARGS) { + pr_warning("bpf: prologue: too many arguments\n"); nargs = BPF_PROLOGUE_MAX_ARGS; + } if (cnt_space > BPF_MAXINSNS) cnt_space = BPF_MAXINSNS; Thank you. Thanks, Namhyung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 16/31] perf tools: Add prologue for BPF programs for fetching arguments
On 2015/10/15 13:26, Namhyung Kim wrote: On Wed, Oct 14, 2015 at 12:41:27PM +, Wang Nan wrote: From: He KuangThis patch generates prologue for a BPF program which fetch arguments for it. With this patch, the program can have arguments as follow: SEC("lock_page=__lock_page page->flags") int lock_page(struct pt_regs *ctx, int err, unsigned long flags) { return 1; } This patch passes at most 3 arguments from r3, r4 and r5. r1 is still the ctx pointer. r2 is used to indicate the successfulness of dereferencing. This patch uses r6 to hold ctx (struct pt_regs) and r7 to hold stack pointer for result. Result of each arguments first store on stack: low address BPF_REG_FP - 24 ARG3 BPF_REG_FP - 16 ARG2 BPF_REG_FP - 8 ARG1 BPF_REG_FP high address Then loaded into r3, r4 and r5. The output prologue for offn(...off2(off1(reg should be: r6 <- r1 // save ctx into a callee saved register r7 <- fp r7 <- r7 - stack_offset// pointer to result slot /* load r3 with the offset in pt_regs of 'reg' */ (r7) <- r3 // make slot valid r3 <- r3 + off1// prepare to read unsafe pointer r2 <- 8 r1 <- r7 // result put onto stack call probe_read // read unsafe pointer jnei r0, 0, err // error checking r3 <- (r7) // read result r3 <- r3 + off2// prepare to read unsafe pointer r2 <- 8 r1 <- r7 call probe_read jnei r0, 0, err ... /* load r2, r3, r4 from stack */ goto success err: r2 <- 1 /* load r3, r4, r5 with 0 */ goto usercode success: r2 <- 0 usercode: r1 <- r6 // restore ctx // original user code If all of arguments reside in register (dereferencing is not required), gen_prologue_fastpath() will be used to create fast prologue: r3 <- (r1 + offset of reg1) r4 <- (r1 + offset of reg2) r5 <- (r1 + offset of reg3) r2 <- 0 P.S. eBPF calling convention is defined as: * r0- return value from in-kernel function, and exit value for eBPF program * r1 - r5 - arguments from eBPF program to in-kernel function * r6 - r9 - callee saved registers that in-kernel function will preserve * r10 - read-only frame pointer to access stack Signed-off-by: He Kuang Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3or...@163.com Cc: Arnaldo Carvalho de Melo Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngk...@git.kernel.org --- [SNIP] +int bpf__gen_prologue(struct probe_trace_arg *args, int nargs, + struct bpf_insn *new_prog, size_t *new_cnt, + size_t cnt_space) +{ + struct bpf_insn *success_code = NULL; + struct bpf_insn *error_code = NULL; + struct bpf_insn *user_code = NULL; + struct bpf_insn_pos pos; + bool fastpath = true; + int i; + + if (!new_prog || !new_cnt) + return -EINVAL; + + pos.begin = new_prog; + pos.end = new_prog + cnt_space; + pos.pos = new_prog; + + if (!nargs) { + ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 0), + ); + + if (check_pos()) + goto errout; + + *new_cnt = pos_get_cnt(); + return 0; + } + + if (nargs > BPF_PROLOGUE_MAX_ARGS) + nargs = BPF_PROLOGUE_MAX_ARGS; Wouldn't it be better to inform user if it ignored some arguments? Correct. I'd like to add a notification in next version: diff --git a/tools/perf/util/bpf-prologue.c b/tools/perf/util/bpf-prologue.c index e4adb18..36093d9 100644 --- a/tools/perf/util/bpf-prologue.c +++ b/tools/perf/util/bpf-prologue.c @@ -337,8 +337,10 @@ int bpf__gen_prologue(struct probe_trace_arg *args, int nargs, return 0; } - if (nargs > BPF_PROLOGUE_MAX_ARGS) + if (nargs > BPF_PROLOGUE_MAX_ARGS) { + pr_warning("bpf: prologue: too many arguments\n"); nargs = BPF_PROLOGUE_MAX_ARGS; + } if (cnt_space > BPF_MAXINSNS) cnt_space = BPF_MAXINSNS; Thank you. Thanks, Namhyung -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of
Re: [PATCH 16/31] perf tools: Add prologue for BPF programs for fetching arguments
On Wed, Oct 14, 2015 at 12:41:27PM +, Wang Nan wrote: > From: He Kuang > > This patch generates prologue for a BPF program which fetch arguments > for it. With this patch, the program can have arguments as follow: > > SEC("lock_page=__lock_page page->flags") > int lock_page(struct pt_regs *ctx, int err, unsigned long flags) > { >return 1; > } > > This patch passes at most 3 arguments from r3, r4 and r5. r1 is still > the ctx pointer. r2 is used to indicate the successfulness of > dereferencing. > > This patch uses r6 to hold ctx (struct pt_regs) and r7 to hold stack > pointer for result. Result of each arguments first store on stack: > > low address > BPF_REG_FP - 24 ARG3 > BPF_REG_FP - 16 ARG2 > BPF_REG_FP - 8 ARG1 > BPF_REG_FP > high address > > Then loaded into r3, r4 and r5. > > The output prologue for offn(...off2(off1(reg should be: > > r6 <- r1 // save ctx into a callee saved register > r7 <- fp > r7 <- r7 - stack_offset // pointer to result slot > /* load r3 with the offset in pt_regs of 'reg' */ > (r7) <- r3 // make slot valid > r3 <- r3 + off1 // prepare to read unsafe pointer > r2 <- 8 > r1 <- r7 // result put onto stack > call probe_read // read unsafe pointer > jnei r0, 0, err // error checking > r3 <- (r7) // read result > r3 <- r3 + off2 // prepare to read unsafe pointer > r2 <- 8 > r1 <- r7 > call probe_read > jnei r0, 0, err > ... > /* load r2, r3, r4 from stack */ > goto success > err: > r2 <- 1 > /* load r3, r4, r5 with 0 */ > goto usercode > success: > r2 <- 0 > usercode: > r1 <- r6 // restore ctx > // original user code > > If all of arguments reside in register (dereferencing is not > required), gen_prologue_fastpath() will be used to create > fast prologue: > > r3 <- (r1 + offset of reg1) > r4 <- (r1 + offset of reg2) > r5 <- (r1 + offset of reg3) > r2 <- 0 > > P.S. > > eBPF calling convention is defined as: > > * r0 - return value from in-kernel function, and exit value > for eBPF program > * r1 - r5 - arguments from eBPF program to in-kernel function > * r6 - r9 - callee saved registers that in-kernel function will > preserve > * r10 - read-only frame pointer to access stack > > Signed-off-by: He Kuang > Signed-off-by: Wang Nan > Cc: Alexei Starovoitov > Cc: Brendan Gregg > Cc: Daniel Borkmann > Cc: David Ahern > Cc: He Kuang > Cc: Jiri Olsa > Cc: Kaixu Xia > Cc: Masami Hiramatsu > Cc: Namhyung Kim > Cc: Paul Mackerras > Cc: Peter Zijlstra > Cc: Zefan Li > Cc: pi3or...@163.com > Cc: Arnaldo Carvalho de Melo > Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngk...@git.kernel.org > --- [SNIP] > +int bpf__gen_prologue(struct probe_trace_arg *args, int nargs, > + struct bpf_insn *new_prog, size_t *new_cnt, > + size_t cnt_space) > +{ > + struct bpf_insn *success_code = NULL; > + struct bpf_insn *error_code = NULL; > + struct bpf_insn *user_code = NULL; > + struct bpf_insn_pos pos; > + bool fastpath = true; > + int i; > + > + if (!new_prog || !new_cnt) > + return -EINVAL; > + > + pos.begin = new_prog; > + pos.end = new_prog + cnt_space; > + pos.pos = new_prog; > + > + if (!nargs) { > + ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 0), > + ); > + > + if (check_pos()) > + goto errout; > + > + *new_cnt = pos_get_cnt(); > + return 0; > + } > + > + if (nargs > BPF_PROLOGUE_MAX_ARGS) > + nargs = BPF_PROLOGUE_MAX_ARGS; Wouldn't it be better to inform user if it ignored some arguments? Thanks, Namhyung > + if (cnt_space > BPF_MAXINSNS) > + cnt_space = BPF_MAXINSNS; > + > + /* First pass: validation */ > + for (i = 0; i < nargs; i++) { > + struct probe_trace_arg_ref *ref = args[i].ref; > + > + if (args[i].value[0] == '@') { > + /* TODO: fetch global variable */ > + pr_err("bpf: prologue: global %s%+ld not support\n", > + args[i].value, ref ? ref->offset : 0); > + return -ENOTSUP; > + } > + > + while (ref) { > + /* fastpath is true if all args has ref == NULL */ > + fastpath = false; > + > + /* > + * Instruction encodes immediate value using > + * s32, ref->offset is long. On systems which > + * can't fill long in s32, refuse to process if > + * ref->offset too large (or small). > + */ >
[PATCH 16/31] perf tools: Add prologue for BPF programs for fetching arguments
From: He Kuang This patch generates prologue for a BPF program which fetch arguments for it. With this patch, the program can have arguments as follow: SEC("lock_page=__lock_page page->flags") int lock_page(struct pt_regs *ctx, int err, unsigned long flags) { return 1; } This patch passes at most 3 arguments from r3, r4 and r5. r1 is still the ctx pointer. r2 is used to indicate the successfulness of dereferencing. This patch uses r6 to hold ctx (struct pt_regs) and r7 to hold stack pointer for result. Result of each arguments first store on stack: low address BPF_REG_FP - 24 ARG3 BPF_REG_FP - 16 ARG2 BPF_REG_FP - 8 ARG1 BPF_REG_FP high address Then loaded into r3, r4 and r5. The output prologue for offn(...off2(off1(reg should be: r6 <- r1 // save ctx into a callee saved register r7 <- fp r7 <- r7 - stack_offset// pointer to result slot /* load r3 with the offset in pt_regs of 'reg' */ (r7) <- r3 // make slot valid r3 <- r3 + off1// prepare to read unsafe pointer r2 <- 8 r1 <- r7 // result put onto stack call probe_read// read unsafe pointer jnei r0, 0, err// error checking r3 <- (r7) // read result r3 <- r3 + off2// prepare to read unsafe pointer r2 <- 8 r1 <- r7 call probe_read jnei r0, 0, err ... /* load r2, r3, r4 from stack */ goto success err: r2 <- 1 /* load r3, r4, r5 with 0 */ goto usercode success: r2 <- 0 usercode: r1 <- r6 // restore ctx // original user code If all of arguments reside in register (dereferencing is not required), gen_prologue_fastpath() will be used to create fast prologue: r3 <- (r1 + offset of reg1) r4 <- (r1 + offset of reg2) r5 <- (r1 + offset of reg3) r2 <- 0 P.S. eBPF calling convention is defined as: * r0- return value from in-kernel function, and exit value for eBPF program * r1 - r5 - arguments from eBPF program to in-kernel function * r6 - r9 - callee saved registers that in-kernel function will preserve * r10 - read-only frame pointer to access stack Signed-off-by: He Kuang Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3or...@163.com Cc: Arnaldo Carvalho de Melo Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngk...@git.kernel.org --- tools/perf/util/Build | 1 + tools/perf/util/bpf-prologue.c | 443 + tools/perf/util/bpf-prologue.h | 34 3 files changed, 478 insertions(+) create mode 100644 tools/perf/util/bpf-prologue.c create mode 100644 tools/perf/util/bpf-prologue.h diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 591b3fe..b9d56f2 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -88,6 +88,7 @@ libperf-y += parse-branch-options.o libperf-y += parse-regs-options.o libperf-$(CONFIG_LIBBPF) += bpf-loader.o +libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o libperf-$(CONFIG_LIBELF) += symbol-elf.o libperf-$(CONFIG_LIBELF) += probe-file.o libperf-$(CONFIG_LIBELF) += probe-event.o diff --git a/tools/perf/util/bpf-prologue.c b/tools/perf/util/bpf-prologue.c new file mode 100644 index 000..e4adb18 --- /dev/null +++ b/tools/perf/util/bpf-prologue.c @@ -0,0 +1,443 @@ +/* + * bpf-prologue.c + * + * Copyright (C) 2015 He Kuang + * Copyright (C) 2015 Wang Nan + * Copyright (C) 2015 Huawei Inc. + */ + +#include +#include "perf.h" +#include "debug.h" +#include "bpf-prologue.h" +#include "probe-finder.h" +#include +#include + +#define BPF_REG_SIZE 8 + +#define JMP_TO_ERROR_CODE -1 +#define JMP_TO_SUCCESS_CODE-2 +#define JMP_TO_USER_CODE -3 + +struct bpf_insn_pos { + struct bpf_insn *begin; + struct bpf_insn *end; + struct bpf_insn *pos; +}; + +static inline int +pos_get_cnt(struct bpf_insn_pos *pos) +{ + return pos->pos - pos->begin; +} + +static int +append_insn(struct bpf_insn new_insn, struct bpf_insn_pos *pos) +{ + if (!pos->pos) + return -ERANGE; + + if (pos->pos + 1 >= pos->end) { + pr_err("bpf prologue: prologue too long\n"); + pos->pos = NULL; + return -ERANGE; + } + + *(pos->pos)++ = new_insn; + return 0; +} + +static int +check_pos(struct bpf_insn_pos *pos) +{ + if (!pos->pos || pos->pos >= pos->end) + return -ERANGE; + return 0; +} + +/* Give it a shorter name */ +#define ins(i, p) append_insn((i), (p)) + +/* + * Give a register name (in 'reg'), generate instruction to + * load register into an eBPF register rd: + *
[PATCH 16/31] perf tools: Add prologue for BPF programs for fetching arguments
From: He KuangThis patch generates prologue for a BPF program which fetch arguments for it. With this patch, the program can have arguments as follow: SEC("lock_page=__lock_page page->flags") int lock_page(struct pt_regs *ctx, int err, unsigned long flags) { return 1; } This patch passes at most 3 arguments from r3, r4 and r5. r1 is still the ctx pointer. r2 is used to indicate the successfulness of dereferencing. This patch uses r6 to hold ctx (struct pt_regs) and r7 to hold stack pointer for result. Result of each arguments first store on stack: low address BPF_REG_FP - 24 ARG3 BPF_REG_FP - 16 ARG2 BPF_REG_FP - 8 ARG1 BPF_REG_FP high address Then loaded into r3, r4 and r5. The output prologue for offn(...off2(off1(reg should be: r6 <- r1 // save ctx into a callee saved register r7 <- fp r7 <- r7 - stack_offset// pointer to result slot /* load r3 with the offset in pt_regs of 'reg' */ (r7) <- r3 // make slot valid r3 <- r3 + off1// prepare to read unsafe pointer r2 <- 8 r1 <- r7 // result put onto stack call probe_read// read unsafe pointer jnei r0, 0, err// error checking r3 <- (r7) // read result r3 <- r3 + off2// prepare to read unsafe pointer r2 <- 8 r1 <- r7 call probe_read jnei r0, 0, err ... /* load r2, r3, r4 from stack */ goto success err: r2 <- 1 /* load r3, r4, r5 with 0 */ goto usercode success: r2 <- 0 usercode: r1 <- r6 // restore ctx // original user code If all of arguments reside in register (dereferencing is not required), gen_prologue_fastpath() will be used to create fast prologue: r3 <- (r1 + offset of reg1) r4 <- (r1 + offset of reg2) r5 <- (r1 + offset of reg3) r2 <- 0 P.S. eBPF calling convention is defined as: * r0- return value from in-kernel function, and exit value for eBPF program * r1 - r5 - arguments from eBPF program to in-kernel function * r6 - r9 - callee saved registers that in-kernel function will preserve * r10 - read-only frame pointer to access stack Signed-off-by: He Kuang Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3or...@163.com Cc: Arnaldo Carvalho de Melo Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngk...@git.kernel.org --- tools/perf/util/Build | 1 + tools/perf/util/bpf-prologue.c | 443 + tools/perf/util/bpf-prologue.h | 34 3 files changed, 478 insertions(+) create mode 100644 tools/perf/util/bpf-prologue.c create mode 100644 tools/perf/util/bpf-prologue.h diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 591b3fe..b9d56f2 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -88,6 +88,7 @@ libperf-y += parse-branch-options.o libperf-y += parse-regs-options.o libperf-$(CONFIG_LIBBPF) += bpf-loader.o +libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o libperf-$(CONFIG_LIBELF) += symbol-elf.o libperf-$(CONFIG_LIBELF) += probe-file.o libperf-$(CONFIG_LIBELF) += probe-event.o diff --git a/tools/perf/util/bpf-prologue.c b/tools/perf/util/bpf-prologue.c new file mode 100644 index 000..e4adb18 --- /dev/null +++ b/tools/perf/util/bpf-prologue.c @@ -0,0 +1,443 @@ +/* + * bpf-prologue.c + * + * Copyright (C) 2015 He Kuang + * Copyright (C) 2015 Wang Nan + * Copyright (C) 2015 Huawei Inc. + */ + +#include +#include "perf.h" +#include "debug.h" +#include "bpf-prologue.h" +#include "probe-finder.h" +#include +#include + +#define BPF_REG_SIZE 8 + +#define JMP_TO_ERROR_CODE -1 +#define JMP_TO_SUCCESS_CODE-2 +#define JMP_TO_USER_CODE -3 + +struct bpf_insn_pos { + struct bpf_insn *begin; + struct bpf_insn *end; + struct bpf_insn *pos; +}; + +static inline int +pos_get_cnt(struct bpf_insn_pos *pos) +{ + return pos->pos - pos->begin; +} + +static int +append_insn(struct bpf_insn new_insn, struct bpf_insn_pos *pos) +{ + if (!pos->pos) + return -ERANGE; + + if (pos->pos + 1 >= pos->end) { + pr_err("bpf prologue: prologue too long\n"); + pos->pos = NULL; + return -ERANGE; + } + + *(pos->pos)++
Re: [PATCH 16/31] perf tools: Add prologue for BPF programs for fetching arguments
On Wed, Oct 14, 2015 at 12:41:27PM +, Wang Nan wrote: > From: He Kuang> > This patch generates prologue for a BPF program which fetch arguments > for it. With this patch, the program can have arguments as follow: > > SEC("lock_page=__lock_page page->flags") > int lock_page(struct pt_regs *ctx, int err, unsigned long flags) > { >return 1; > } > > This patch passes at most 3 arguments from r3, r4 and r5. r1 is still > the ctx pointer. r2 is used to indicate the successfulness of > dereferencing. > > This patch uses r6 to hold ctx (struct pt_regs) and r7 to hold stack > pointer for result. Result of each arguments first store on stack: > > low address > BPF_REG_FP - 24 ARG3 > BPF_REG_FP - 16 ARG2 > BPF_REG_FP - 8 ARG1 > BPF_REG_FP > high address > > Then loaded into r3, r4 and r5. > > The output prologue for offn(...off2(off1(reg should be: > > r6 <- r1 // save ctx into a callee saved register > r7 <- fp > r7 <- r7 - stack_offset // pointer to result slot > /* load r3 with the offset in pt_regs of 'reg' */ > (r7) <- r3 // make slot valid > r3 <- r3 + off1 // prepare to read unsafe pointer > r2 <- 8 > r1 <- r7 // result put onto stack > call probe_read // read unsafe pointer > jnei r0, 0, err // error checking > r3 <- (r7) // read result > r3 <- r3 + off2 // prepare to read unsafe pointer > r2 <- 8 > r1 <- r7 > call probe_read > jnei r0, 0, err > ... > /* load r2, r3, r4 from stack */ > goto success > err: > r2 <- 1 > /* load r3, r4, r5 with 0 */ > goto usercode > success: > r2 <- 0 > usercode: > r1 <- r6 // restore ctx > // original user code > > If all of arguments reside in register (dereferencing is not > required), gen_prologue_fastpath() will be used to create > fast prologue: > > r3 <- (r1 + offset of reg1) > r4 <- (r1 + offset of reg2) > r5 <- (r1 + offset of reg3) > r2 <- 0 > > P.S. > > eBPF calling convention is defined as: > > * r0 - return value from in-kernel function, and exit value > for eBPF program > * r1 - r5 - arguments from eBPF program to in-kernel function > * r6 - r9 - callee saved registers that in-kernel function will > preserve > * r10 - read-only frame pointer to access stack > > Signed-off-by: He Kuang > Signed-off-by: Wang Nan > Cc: Alexei Starovoitov > Cc: Brendan Gregg > Cc: Daniel Borkmann > Cc: David Ahern > Cc: He Kuang > Cc: Jiri Olsa > Cc: Kaixu Xia > Cc: Masami Hiramatsu > Cc: Namhyung Kim > Cc: Paul Mackerras > Cc: Peter Zijlstra > Cc: Zefan Li > Cc: pi3or...@163.com > Cc: Arnaldo Carvalho de Melo > Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngk...@git.kernel.org > --- [SNIP] > +int bpf__gen_prologue(struct probe_trace_arg *args, int nargs, > + struct bpf_insn *new_prog, size_t *new_cnt, > + size_t cnt_space) > +{ > + struct bpf_insn *success_code = NULL; > + struct bpf_insn *error_code = NULL; > + struct bpf_insn *user_code = NULL; > + struct bpf_insn_pos pos; > + bool fastpath = true; > + int i; > + > + if (!new_prog || !new_cnt) > + return -EINVAL; > + > + pos.begin = new_prog; > + pos.end = new_prog + cnt_space; > + pos.pos = new_prog; > + > + if (!nargs) { > + ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 0), > + ); > + > + if (check_pos()) > + goto errout; > + > + *new_cnt = pos_get_cnt(); > + return 0; > + } > + > + if (nargs > BPF_PROLOGUE_MAX_ARGS) > + nargs = BPF_PROLOGUE_MAX_ARGS; Wouldn't it be better to inform user if it ignored some arguments? Thanks, Namhyung > + if (cnt_space > BPF_MAXINSNS) > + cnt_space = BPF_MAXINSNS; > + > + /* First pass: validation */ > + for (i = 0; i < nargs; i++) { > + struct probe_trace_arg_ref *ref = args[i].ref; > + > + if (args[i].value[0] == '@') { > + /* TODO: fetch global variable */ > + pr_err("bpf: prologue: global %s%+ld not support\n", > + args[i].value, ref ? ref->offset : 0); > + return -ENOTSUP; > + } > + > + while (ref) { > + /* fastpath is true if all args has ref == NULL */ > + fastpath =