[RFC PATCH v2 07/15] bpf tools: Convert arglist to bpf prologue

From: He Kuang
Date: Sun May 24 2015 - 04:30:13 EST


When all arguments in bpf config section are collected in register and
offset form, this patch will fetch them from bpf context register and
place them as bpf input parameters.

By bpf calling convention, we restrict the max fetched arg number to 4.

Bpf prologue is generated as the following steps:
1. alloc dst address in stack -> r1
2. set size -> r2
3. fetch base register and offset -> r3
4. call BPF_FUNC_probe_read
5. loop 1
6. save intermediate result and process next arg
7. restore intermediate result to arg2~5

Signed-off-by: He Kuang <hekuang@xxxxxxxxxx>
---
tools/lib/bpf/Build | 2 +-
tools/lib/bpf/gen_prologue.c | 108 +++++++++++++++++++++++++++++++++++++++++++
tools/lib/bpf/libbpf.h | 10 ++++
3 files changed, 119 insertions(+), 1 deletion(-)
create mode 100644 tools/lib/bpf/gen_prologue.c

diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build
index d874975..c910805 100644
--- a/tools/lib/bpf/Build
+++ b/tools/lib/bpf/Build
@@ -1 +1 @@
-libbpf-y := libbpf.o bpf.o
+libbpf-y := libbpf.o bpf.o gen_prologue.o
diff --git a/tools/lib/bpf/gen_prologue.c b/tools/lib/bpf/gen_prologue.c
new file mode 100644
index 0000000..ca8aa1c
--- /dev/null
+++ b/tools/lib/bpf/gen_prologue.c
@@ -0,0 +1,108 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <dwarf-regs.h>
+#include <debug.h>
+
+#include "libbpf.h"
+#include "bpf.h"
+
+#define BPF_REG_SIZE (8)
+
+unsigned int bpf_prologue_arg_deref(int offset, int stack_index, int depth,
+ char *new_prog, bool last)
+{
+ struct bpf_insn tmp_insns[6] = {};
+ struct bpf_insn *insn = tmp_insns;
+ unsigned int size;
+
+ if (!depth) {
+ /* base register */
+ if (offset < 0)
+ return 0;
+
+ /* load ctx to r3 */
+ *insn++ = BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_CTX, offset);
+
+ if (!last) {
+ /* r7 for stack space */
+ *insn++ = BPF_MOV64_REG(BPF_REG_7, BPF_REG_FP);
+ *insn++ = BPF_ALU64_IMM(BPF_ADD, BPF_REG_7,
+ -BPF_REG_SIZE * stack_index);
+ /* clear stack */
+ *insn++ = BPF_STX_MEM(BPF_DW, BPF_REG_FP, BPF_REG_8,
+ -BPF_REG_SIZE * stack_index);
+ } else {
+ /* store r3 to stack */
+ *insn++ = BPF_STX_MEM(BPF_DW, BPF_REG_FP, BPF_REG_3,
+ -BPF_REG_SIZE * stack_index);
+ }
+ } else {
+ /* refs */
+ /* r3 += offset */
+ *insn++ = BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, offset);
+
+ /* r2 = size */
+ *insn++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_2, 0x0008);
+
+ /* r1 = r7 */
+ *insn++ = BPF_MOV64_REG(BPF_REG_1, BPF_REG_7);
+
+ /* call BPF_FUNC_probe_read
+ * r1: ptr to stack
+ * r2: stack size
+ * r3: unsafe ptr
+ */
+ *insn++ = BPF_EMIT_CALL(BPF_FUNC_probe_read);
+
+ if (!last)
+ /* fetch stack intermediate to r3 */
+ *insn++ = BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_FP,
+ -BPF_REG_SIZE * stack_index);
+ }
+
+ size = sizeof(*insn) * (insn - tmp_insns);
+ if (new_prog)
+ memcpy(new_prog, tmp_insns, size);
+
+ return size;
+}
+
+unsigned int bpf_prologue_begin(char *new_prog)
+{
+ struct bpf_insn *new_insn;
+
+ new_insn = (struct bpf_insn *)new_prog;
+
+ if (new_insn) {
+ /* save arg1 to ctx */
+ *new_insn++ = BPF_MOV64_REG(BPF_REG_CTX, BPF_REG_ARG1);
+ /* set r8 to 0 */
+ *new_insn++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_8, 0);
+ } else
+ new_insn += 2;
+
+ return (char *)new_insn - new_prog;
+}
+
+unsigned int bpf_prologue_end(char *new_prog, int nargs)
+{
+ struct bpf_insn *new_insn;
+ int i;
+
+ new_insn = (struct bpf_insn *)new_prog;
+
+ nargs = min(BPF_PROLOGUE_NRARGS_MAX, nargs);
+ for (i = 0; i < nargs; i++) {
+ /* result in stack, move to r2~r5 */
+ if (new_prog)
+ *new_insn = BPF_LDX_MEM(BPF_DW,
+ BPF_REG_ARG2 + i,
+ BPF_REG_FP,
+ -BPF_REG_SIZE * (i + 1));
+ new_insn++;
+ }
+
+ return (char *)new_insn - new_prog;
+}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 31ff5d9..cf22a6a 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -63,4 +63,14 @@ struct bpf_map_def {
unsigned int max_entries;
};

+#define BPF_PROLOGUE_NRARGS_MAX (4)
+
+unsigned int bpf_prologue_begin(char *new_prog);
+unsigned int bpf_prologue_end(char *new_prog, int nargs);
+unsigned int bpf_prologue_arg_deref(int offset,
+ int stack_index,
+ int depth,
+ char *new_prog,
+ bool last);
+
#endif
--
1.8.5.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/