All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH bpf-next v3 0/2] libbpf: usdt arm arg parsing support
@ 2023-03-07 12:04 Puranjay Mohan
  2023-03-07 12:04 ` [PATCH bpf-next v3 1/2] libbpf: refactor parse_usdt_arg() to re-use code Puranjay Mohan
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Puranjay Mohan @ 2023-03-07 12:04 UTC (permalink / raw)
  To: andrii, ast, daniel, martin.lau, song, yhs, bpf, memxor; +Cc: Puranjay Mohan

This series add the support of the ARM architecture to libbpf USDT. This
involves implementing the parse_usdt_arg() function for ARM.

It was seen that the last part of parse_usdt_arg() is repeated for all architectures,
so, the first patch in this series refactors these functions and moved the post
processing to parse_usdt_spec()

Changes in V2[1] to V3:

- Use a tabular approach to find register offsets.
- Add the patch for refactoring parse_usdt_arg()

Puranjay Mohan (2):
  libbpf: refactor parse_usdt_arg() to re-use code
  libbpf: usdt arm arg parsing support

 tools/lib/bpf/usdt.c | 195 ++++++++++++++++++++++++++-----------------
 1 file changed, 118 insertions(+), 77 deletions(-)

-- 
2.39.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH bpf-next v3 1/2] libbpf: refactor parse_usdt_arg() to re-use code
  2023-03-07 12:04 [PATCH bpf-next v3 0/2] libbpf: usdt arm arg parsing support Puranjay Mohan
@ 2023-03-07 12:04 ` Puranjay Mohan
  2023-03-07 12:04 ` [PATCH bpf-next v3 2/2] libbpf: usdt arm arg parsing support Puranjay Mohan
  2023-03-07 23:40 ` [PATCH bpf-next v3 0/2] " patchwork-bot+netdevbpf
  2 siblings, 0 replies; 8+ messages in thread
From: Puranjay Mohan @ 2023-03-07 12:04 UTC (permalink / raw)
  To: andrii, ast, daniel, martin.lau, song, yhs, bpf, memxor; +Cc: Puranjay Mohan

The parse_usdt_arg() function is defined differently for each
architecture but the last part of the function is repeated
verbatim for each architecture.

Refactor parse_usdt_arg() to fill the arg_sz and then do the repeated
post-processing in parse_usdt_spec().

Signed-off-by: Puranjay Mohan <puranjay12@gmail.com>
---
 tools/lib/bpf/usdt.c | 123 +++++++++++++++----------------------------
 1 file changed, 42 insertions(+), 81 deletions(-)

diff --git a/tools/lib/bpf/usdt.c b/tools/lib/bpf/usdt.c
index 75b411fc2c77..293b7a37f8a1 100644
--- a/tools/lib/bpf/usdt.c
+++ b/tools/lib/bpf/usdt.c
@@ -1141,11 +1141,13 @@ static int parse_usdt_note(Elf *elf, const char *path, GElf_Nhdr *nhdr,
 	return 0;
 }
 
-static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg);
+static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz);
 
 static int parse_usdt_spec(struct usdt_spec *spec, const struct usdt_note *note, __u64 usdt_cookie)
 {
+	struct usdt_arg_spec *arg;
 	const char *s;
+	int arg_sz;
 	int len;
 
 	spec->usdt_cookie = usdt_cookie;
@@ -1159,10 +1161,25 @@ static int parse_usdt_spec(struct usdt_spec *spec, const struct usdt_note *note,
 			return -E2BIG;
 		}
 
-		len = parse_usdt_arg(s, spec->arg_cnt, &spec->args[spec->arg_cnt]);
+		arg = &spec->args[spec->arg_cnt];
+		len = parse_usdt_arg(s, spec->arg_cnt, arg, &arg_sz);
 		if (len < 0)
 			return len;
 
+		arg->arg_signed = arg_sz < 0;
+		if (arg_sz < 0)
+			arg_sz = -arg_sz;
+
+		switch (arg_sz) {
+		case 1: case 2: case 4: case 8:
+			arg->arg_bitshift = 64 - arg_sz * 8;
+			break;
+		default:
+			pr_warn("usdt: unsupported arg #%d (spec '%s') size: %d\n",
+				spec->arg_cnt, s, arg_sz);
+			return -EINVAL;
+		}
+
 		s += len;
 		spec->arg_cnt++;
 	}
@@ -1219,13 +1236,13 @@ static int calc_pt_regs_off(const char *reg_name)
 	return -ENOENT;
 }
 
-static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg)
+static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
 {
 	char reg_name[16];
-	int arg_sz, len, reg_off;
+	int len, reg_off;
 	long off;
 
-	if (sscanf(arg_str, " %d @ %ld ( %%%15[^)] ) %n", &arg_sz, &off, reg_name, &len) == 3) {
+	if (sscanf(arg_str, " %d @ %ld ( %%%15[^)] ) %n", arg_sz, &off, reg_name, &len) == 3) {
 		/* Memory dereference case, e.g., -4@-20(%rbp) */
 		arg->arg_type = USDT_ARG_REG_DEREF;
 		arg->val_off = off;
@@ -1233,7 +1250,7 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
 		if (reg_off < 0)
 			return reg_off;
 		arg->reg_off = reg_off;
-	} else if (sscanf(arg_str, " %d @ ( %%%15[^)] ) %n", &arg_sz, reg_name, &len) == 2) {
+	} else if (sscanf(arg_str, " %d @ ( %%%15[^)] ) %n", arg_sz, reg_name, &len) == 2) {
 		/* Memory dereference case without offset, e.g., 8@(%rsp) */
 		arg->arg_type = USDT_ARG_REG_DEREF;
 		arg->val_off = 0;
@@ -1241,7 +1258,7 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
 		if (reg_off < 0)
 			return reg_off;
 		arg->reg_off = reg_off;
-	} else if (sscanf(arg_str, " %d @ %%%15s %n", &arg_sz, reg_name, &len) == 2) {
+	} else if (sscanf(arg_str, " %d @ %%%15s %n", arg_sz, reg_name, &len) == 2) {
 		/* Register read case, e.g., -4@%eax */
 		arg->arg_type = USDT_ARG_REG;
 		arg->val_off = 0;
@@ -1250,7 +1267,7 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
 		if (reg_off < 0)
 			return reg_off;
 		arg->reg_off = reg_off;
-	} else if (sscanf(arg_str, " %d @ $%ld %n", &arg_sz, &off, &len) == 2) {
+	} else if (sscanf(arg_str, " %d @ $%ld %n", arg_sz, &off, &len) == 2) {
 		/* Constant value case, e.g., 4@$71 */
 		arg->arg_type = USDT_ARG_CONST;
 		arg->val_off = off;
@@ -1260,20 +1277,6 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
 		return -EINVAL;
 	}
 
-	arg->arg_signed = arg_sz < 0;
-	if (arg_sz < 0)
-		arg_sz = -arg_sz;
-
-	switch (arg_sz) {
-	case 1: case 2: case 4: case 8:
-		arg->arg_bitshift = 64 - arg_sz * 8;
-		break;
-	default:
-		pr_warn("usdt: unsupported arg #%d (spec '%s') size: %d\n",
-			arg_num, arg_str, arg_sz);
-		return -EINVAL;
-	}
-
 	return len;
 }
 
@@ -1281,13 +1284,13 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
 
 /* Do not support __s390__ for now, since user_pt_regs is broken with -m31. */
 
-static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg)
+static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
 {
 	unsigned int reg;
-	int arg_sz, len;
+	int len;
 	long off;
 
-	if (sscanf(arg_str, " %d @ %ld ( %%r%u ) %n", &arg_sz, &off, &reg, &len) == 3) {
+	if (sscanf(arg_str, " %d @ %ld ( %%r%u ) %n", arg_sz, &off, &reg, &len) == 3) {
 		/* Memory dereference case, e.g., -2@-28(%r15) */
 		arg->arg_type = USDT_ARG_REG_DEREF;
 		arg->val_off = off;
@@ -1296,7 +1299,7 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
 			return -EINVAL;
 		}
 		arg->reg_off = offsetof(user_pt_regs, gprs[reg]);
-	} else if (sscanf(arg_str, " %d @ %%r%u %n", &arg_sz, &reg, &len) == 2) {
+	} else if (sscanf(arg_str, " %d @ %%r%u %n", arg_sz, &reg, &len) == 2) {
 		/* Register read case, e.g., -8@%r0 */
 		arg->arg_type = USDT_ARG_REG;
 		arg->val_off = 0;
@@ -1305,7 +1308,7 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
 			return -EINVAL;
 		}
 		arg->reg_off = offsetof(user_pt_regs, gprs[reg]);
-	} else if (sscanf(arg_str, " %d @ %ld %n", &arg_sz, &off, &len) == 2) {
+	} else if (sscanf(arg_str, " %d @ %ld %n", arg_sz, &off, &len) == 2) {
 		/* Constant value case, e.g., 4@71 */
 		arg->arg_type = USDT_ARG_CONST;
 		arg->val_off = off;
@@ -1315,20 +1318,6 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
 		return -EINVAL;
 	}
 
-	arg->arg_signed = arg_sz < 0;
-	if (arg_sz < 0)
-		arg_sz = -arg_sz;
-
-	switch (arg_sz) {
-	case 1: case 2: case 4: case 8:
-		arg->arg_bitshift = 64 - arg_sz * 8;
-		break;
-	default:
-		pr_warn("usdt: unsupported arg #%d (spec '%s') size: %d\n",
-			arg_num, arg_str, arg_sz);
-		return -EINVAL;
-	}
-
 	return len;
 }
 
@@ -1348,13 +1337,13 @@ static int calc_pt_regs_off(const char *reg_name)
 	return -ENOENT;
 }
 
-static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg)
+static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
 {
 	char reg_name[16];
-	int arg_sz, len, reg_off;
+	int len, reg_off;
 	long off;
 
-	if (sscanf(arg_str, " %d @ \[ %15[a-z0-9], %ld ] %n", &arg_sz, reg_name, &off, &len) == 3) {
+	if (sscanf(arg_str, " %d @ \[ %15[a-z0-9], %ld ] %n", arg_sz, reg_name, &off, &len) == 3) {
 		/* Memory dereference case, e.g., -4@[sp, 96] */
 		arg->arg_type = USDT_ARG_REG_DEREF;
 		arg->val_off = off;
@@ -1362,7 +1351,7 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
 		if (reg_off < 0)
 			return reg_off;
 		arg->reg_off = reg_off;
-	} else if (sscanf(arg_str, " %d @ \[ %15[a-z0-9] ] %n", &arg_sz, reg_name, &len) == 2) {
+	} else if (sscanf(arg_str, " %d @ \[ %15[a-z0-9] ] %n", arg_sz, reg_name, &len) == 2) {
 		/* Memory dereference case, e.g., -4@[sp] */
 		arg->arg_type = USDT_ARG_REG_DEREF;
 		arg->val_off = 0;
@@ -1370,12 +1359,12 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
 		if (reg_off < 0)
 			return reg_off;
 		arg->reg_off = reg_off;
-	} else if (sscanf(arg_str, " %d @ %ld %n", &arg_sz, &off, &len) == 2) {
+	} else if (sscanf(arg_str, " %d @ %ld %n", arg_sz, &off, &len) == 2) {
 		/* Constant value case, e.g., 4@5 */
 		arg->arg_type = USDT_ARG_CONST;
 		arg->val_off = off;
 		arg->reg_off = 0;
-	} else if (sscanf(arg_str, " %d @ %15[a-z0-9] %n", &arg_sz, reg_name, &len) == 2) {
+	} else if (sscanf(arg_str, " %d @ %15[a-z0-9] %n", arg_sz, reg_name, &len) == 2) {
 		/* Register read case, e.g., -8@x4 */
 		arg->arg_type = USDT_ARG_REG;
 		arg->val_off = 0;
@@ -1388,20 +1377,6 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
 		return -EINVAL;
 	}
 
-	arg->arg_signed = arg_sz < 0;
-	if (arg_sz < 0)
-		arg_sz = -arg_sz;
-
-	switch (arg_sz) {
-	case 1: case 2: case 4: case 8:
-		arg->arg_bitshift = 64 - arg_sz * 8;
-		break;
-	default:
-		pr_warn("usdt: unsupported arg #%d (spec '%s') size: %d\n",
-			arg_num, arg_str, arg_sz);
-		return -EINVAL;
-	}
-
 	return len;
 }
 
@@ -1456,13 +1431,13 @@ static int calc_pt_regs_off(const char *reg_name)
 	return -ENOENT;
 }
 
-static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg)
+static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
 {
 	char reg_name[16];
-	int arg_sz, len, reg_off;
+	int len, reg_off;
 	long off;
 
-	if (sscanf(arg_str, " %d @ %ld ( %15[a-z0-9] ) %n", &arg_sz, &off, reg_name, &len) == 3) {
+	if (sscanf(arg_str, " %d @ %ld ( %15[a-z0-9] ) %n", arg_sz, &off, reg_name, &len) == 3) {
 		/* Memory dereference case, e.g., -8@-88(s0) */
 		arg->arg_type = USDT_ARG_REG_DEREF;
 		arg->val_off = off;
@@ -1470,12 +1445,12 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
 		if (reg_off < 0)
 			return reg_off;
 		arg->reg_off = reg_off;
-	} else if (sscanf(arg_str, " %d @ %ld %n", &arg_sz, &off, &len) == 2) {
+	} else if (sscanf(arg_str, " %d @ %ld %n", arg_sz, &off, &len) == 2) {
 		/* Constant value case, e.g., 4@5 */
 		arg->arg_type = USDT_ARG_CONST;
 		arg->val_off = off;
 		arg->reg_off = 0;
-	} else if (sscanf(arg_str, " %d @ %15[a-z0-9] %n", &arg_sz, reg_name, &len) == 2) {
+	} else if (sscanf(arg_str, " %d @ %15[a-z0-9] %n", arg_sz, reg_name, &len) == 2) {
 		/* Register read case, e.g., -8@a1 */
 		arg->arg_type = USDT_ARG_REG;
 		arg->val_off = 0;
@@ -1488,26 +1463,12 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
 		return -EINVAL;
 	}
 
-	arg->arg_signed = arg_sz < 0;
-	if (arg_sz < 0)
-		arg_sz = -arg_sz;
-
-	switch (arg_sz) {
-	case 1: case 2: case 4: case 8:
-		arg->arg_bitshift = 64 - arg_sz * 8;
-		break;
-	default:
-		pr_warn("usdt: unsupported arg #%d (spec '%s') size: %d\n",
-			arg_num, arg_str, arg_sz);
-		return -EINVAL;
-	}
-
 	return len;
 }
 
 #else
 
-static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg)
+static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
 {
 	pr_warn("usdt: libbpf doesn't support USDTs on current architecture\n");
 	return -ENOTSUP;
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH bpf-next v3 2/2] libbpf: usdt arm arg parsing support
  2023-03-07 12:04 [PATCH bpf-next v3 0/2] libbpf: usdt arm arg parsing support Puranjay Mohan
  2023-03-07 12:04 ` [PATCH bpf-next v3 1/2] libbpf: refactor parse_usdt_arg() to re-use code Puranjay Mohan
@ 2023-03-07 12:04 ` Puranjay Mohan
  2023-03-07 23:41   ` Andrii Nakryiko
  2023-03-07 23:40 ` [PATCH bpf-next v3 0/2] " patchwork-bot+netdevbpf
  2 siblings, 1 reply; 8+ messages in thread
From: Puranjay Mohan @ 2023-03-07 12:04 UTC (permalink / raw)
  To: andrii, ast, daniel, martin.lau, song, yhs, bpf, memxor; +Cc: Puranjay Mohan

Parsing of USDT arguments is architecture-specific; on arm it is
relatively easy since registers used are r[0-10], fp, ip, sp, lr,
pc. Format is slightly different compared to aarch64; forms are

- "size @ [ reg, #offset ]" for dereferences, for example
  "-8 @ [ sp, #76 ]" ; " -4 @ [ sp ]"
- "size @ reg" for register values; for example
  "-4@r0"
- "size @ #value" for raw values; for example
  "-8@#1"

Add support for parsing USDT arguments for ARM architecture.

To test the above changes QEMU's virt[1] board with cortex-a15
CPU was used. libbpf-bootstrap's usdt example[2] was modified to attach
to a test program with DTRACE_PROBE1/2/3/4... probes to test different
combinations.

[1] https://www.qemu.org/docs/master/system/arm/virt.html
[2] https://github.com/libbpf/libbpf-bootstrap/blob/master/examples/c/usdt.bpf.c

Signed-off-by: Puranjay Mohan <puranjay12@gmail.com>
---
 tools/lib/bpf/usdt.c | 80 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/tools/lib/bpf/usdt.c b/tools/lib/bpf/usdt.c
index 293b7a37f8a1..27a4589eda1c 100644
--- a/tools/lib/bpf/usdt.c
+++ b/tools/lib/bpf/usdt.c
@@ -1466,6 +1466,86 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
 	return len;
 }
 
+#elif defined(__arm__)
+
+static int calc_pt_regs_off(const char *reg_name)
+{
+	static struct {
+		const char *name;
+		size_t pt_regs_off;
+	} reg_map[] = {
+		{ "r0", offsetof(struct pt_regs, uregs[0]) },
+		{ "r1", offsetof(struct pt_regs, uregs[1]) },
+		{ "r2", offsetof(struct pt_regs, uregs[2]) },
+		{ "r3", offsetof(struct pt_regs, uregs[3]) },
+		{ "r4", offsetof(struct pt_regs, uregs[4]) },
+		{ "r5", offsetof(struct pt_regs, uregs[5]) },
+		{ "r6", offsetof(struct pt_regs, uregs[6]) },
+		{ "r7", offsetof(struct pt_regs, uregs[7]) },
+		{ "r8", offsetof(struct pt_regs, uregs[8]) },
+		{ "r9", offsetof(struct pt_regs, uregs[9]) },
+		{ "r10", offsetof(struct pt_regs, uregs[10]) },
+		{ "fp", offsetof(struct pt_regs, uregs[11]) },
+		{ "ip", offsetof(struct pt_regs, uregs[12]) },
+		{ "sp", offsetof(struct pt_regs, uregs[13]) },
+		{ "lr", offsetof(struct pt_regs, uregs[14]) },
+		{ "pc", offsetof(struct pt_regs, uregs[15]) },
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(reg_map); i++) {
+		if (strcmp(reg_name, reg_map[i].name) == 0)
+			return reg_map[i].pt_regs_off;
+	}
+
+	pr_warn("usdt: unrecognized register '%s'\n", reg_name);
+	return -ENOENT;
+}
+
+static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
+{
+	char reg_name[16];
+	int len, reg_off;
+	long off;
+
+	if (sscanf(arg_str, " %d @ \[ %15[a-z0-9], #%ld ] %n",
+		   arg_sz, reg_name, &off, &len) == 3) {
+		/* Memory dereference case, e.g., -4@[fp, #96] */
+		arg->arg_type = USDT_ARG_REG_DEREF;
+		arg->val_off = off;
+		reg_off = calc_pt_regs_off(reg_name);
+		if (reg_off < 0)
+			return reg_off;
+		arg->reg_off = reg_off;
+	} else if (sscanf(arg_str, " %d @ \[ %15[a-z0-9] ] %n", arg_sz, reg_name, &len) == 2) {
+		/* Memory dereference case, e.g., -4@[sp] */
+		arg->arg_type = USDT_ARG_REG_DEREF;
+		arg->val_off = 0;
+		reg_off = calc_pt_regs_off(reg_name);
+		if (reg_off < 0)
+			return reg_off;
+		arg->reg_off = reg_off;
+	} else if (sscanf(arg_str, " %d @ #%ld %n", arg_sz, &off, &len) == 2) {
+		/* Constant value case, e.g., 4@#5 */
+		arg->arg_type = USDT_ARG_CONST;
+		arg->val_off = off;
+		arg->reg_off = 0;
+	} else if (sscanf(arg_str, " %d @ %15[a-z0-9] %n", arg_sz, reg_name, &len) == 2) {
+		/* Register read case, e.g., -8@r4 */
+		arg->arg_type = USDT_ARG_REG;
+		arg->val_off = 0;
+		reg_off = calc_pt_regs_off(reg_name);
+		if (reg_off < 0)
+			return reg_off;
+		arg->reg_off = reg_off;
+	} else {
+		pr_warn("usdt: unrecognized arg #%d spec '%s'\n", arg_num, arg_str);
+		return -EINVAL;
+	}
+
+	return len;
+}
+
 #else
 
 static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH bpf-next v3 0/2] libbpf: usdt arm arg parsing support
  2023-03-07 12:04 [PATCH bpf-next v3 0/2] libbpf: usdt arm arg parsing support Puranjay Mohan
  2023-03-07 12:04 ` [PATCH bpf-next v3 1/2] libbpf: refactor parse_usdt_arg() to re-use code Puranjay Mohan
  2023-03-07 12:04 ` [PATCH bpf-next v3 2/2] libbpf: usdt arm arg parsing support Puranjay Mohan
@ 2023-03-07 23:40 ` patchwork-bot+netdevbpf
  2 siblings, 0 replies; 8+ messages in thread
From: patchwork-bot+netdevbpf @ 2023-03-07 23:40 UTC (permalink / raw)
  To: Puranjay Mohan; +Cc: andrii, ast, daniel, martin.lau, song, yhs, bpf, memxor

Hello:

This series was applied to bpf/bpf-next.git (master)
by Andrii Nakryiko <andrii@kernel.org>:

On Tue,  7 Mar 2023 12:04:38 +0000 you wrote:
> This series add the support of the ARM architecture to libbpf USDT. This
> involves implementing the parse_usdt_arg() function for ARM.
> 
> It was seen that the last part of parse_usdt_arg() is repeated for all architectures,
> so, the first patch in this series refactors these functions and moved the post
> processing to parse_usdt_spec()
> 
> [...]

Here is the summary with links:
  - [bpf-next,v3,1/2] libbpf: refactor parse_usdt_arg() to re-use code
    https://git.kernel.org/bpf/bpf-next/c/98e678e9bc58
  - [bpf-next,v3,2/2] libbpf: usdt arm arg parsing support
    https://git.kernel.org/bpf/bpf-next/c/720d93b60aec

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH bpf-next v3 2/2] libbpf: usdt arm arg parsing support
  2023-03-07 12:04 ` [PATCH bpf-next v3 2/2] libbpf: usdt arm arg parsing support Puranjay Mohan
@ 2023-03-07 23:41   ` Andrii Nakryiko
  2023-03-08  5:01     ` Puranjay Mohan
  0 siblings, 1 reply; 8+ messages in thread
From: Andrii Nakryiko @ 2023-03-07 23:41 UTC (permalink / raw)
  To: Puranjay Mohan; +Cc: andrii, ast, daniel, martin.lau, song, yhs, bpf, memxor

On Tue, Mar 7, 2023 at 4:04 AM Puranjay Mohan <puranjay12@gmail.com> wrote:
>
> Parsing of USDT arguments is architecture-specific; on arm it is
> relatively easy since registers used are r[0-10], fp, ip, sp, lr,
> pc. Format is slightly different compared to aarch64; forms are
>
> - "size @ [ reg, #offset ]" for dereferences, for example
>   "-8 @ [ sp, #76 ]" ; " -4 @ [ sp ]"
> - "size @ reg" for register values; for example
>   "-4@r0"
> - "size @ #value" for raw values; for example
>   "-8@#1"
>
> Add support for parsing USDT arguments for ARM architecture.
>
> To test the above changes QEMU's virt[1] board with cortex-a15
> CPU was used. libbpf-bootstrap's usdt example[2] was modified to attach
> to a test program with DTRACE_PROBE1/2/3/4... probes to test different
> combinations.
>
> [1] https://www.qemu.org/docs/master/system/arm/virt.html
> [2] https://github.com/libbpf/libbpf-bootstrap/blob/master/examples/c/usdt.bpf.c
>
> Signed-off-by: Puranjay Mohan <puranjay12@gmail.com>
> ---
>  tools/lib/bpf/usdt.c | 80 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 80 insertions(+)
>
> diff --git a/tools/lib/bpf/usdt.c b/tools/lib/bpf/usdt.c
> index 293b7a37f8a1..27a4589eda1c 100644
> --- a/tools/lib/bpf/usdt.c
> +++ b/tools/lib/bpf/usdt.c
> @@ -1466,6 +1466,86 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
>         return len;
>  }
>
> +#elif defined(__arm__)
> +
> +static int calc_pt_regs_off(const char *reg_name)
> +{
> +       static struct {
> +               const char *name;
> +               size_t pt_regs_off;
> +       } reg_map[] = {
> +               { "r0", offsetof(struct pt_regs, uregs[0]) },
> +               { "r1", offsetof(struct pt_regs, uregs[1]) },
> +               { "r2", offsetof(struct pt_regs, uregs[2]) },
> +               { "r3", offsetof(struct pt_regs, uregs[3]) },
> +               { "r4", offsetof(struct pt_regs, uregs[4]) },
> +               { "r5", offsetof(struct pt_regs, uregs[5]) },
> +               { "r6", offsetof(struct pt_regs, uregs[6]) },
> +               { "r7", offsetof(struct pt_regs, uregs[7]) },
> +               { "r8", offsetof(struct pt_regs, uregs[8]) },
> +               { "r9", offsetof(struct pt_regs, uregs[9]) },
> +               { "r10", offsetof(struct pt_regs, uregs[10]) },
> +               { "fp", offsetof(struct pt_regs, uregs[11]) },
> +               { "ip", offsetof(struct pt_regs, uregs[12]) },
> +               { "sp", offsetof(struct pt_regs, uregs[13]) },
> +               { "lr", offsetof(struct pt_regs, uregs[14]) },
> +               { "pc", offsetof(struct pt_regs, uregs[15]) },
> +       };
> +       int i;
> +
> +       for (i = 0; i < ARRAY_SIZE(reg_map); i++) {
> +               if (strcmp(reg_name, reg_map[i].name) == 0)
> +                       return reg_map[i].pt_regs_off;
> +       }
> +
> +       pr_warn("usdt: unrecognized register '%s'\n", reg_name);
> +       return -ENOENT;
> +}
> +
> +static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
> +{
> +       char reg_name[16];
> +       int len, reg_off;
> +       long off;
> +
> +       if (sscanf(arg_str, " %d @ \[ %15[a-z0-9], #%ld ] %n",

I've added space before , and applied to bpf-next.

Thanks, it's a nice clean up and wider architecture support!

BTW, I noticed that we don't support fp, ip, lr, and pc (only sp) for
__aarch64__, why such a difference between 32-bit and 64-bit arms?

> +                  arg_sz, reg_name, &off, &len) == 3) {
> +               /* Memory dereference case, e.g., -4@[fp, #96] */
> +               arg->arg_type = USDT_ARG_REG_DEREF;
> +               arg->val_off = off;
> +               reg_off = calc_pt_regs_off(reg_name);
> +               if (reg_off < 0)
> +                       return reg_off;
> +               arg->reg_off = reg_off;
> +       } else if (sscanf(arg_str, " %d @ \[ %15[a-z0-9] ] %n", arg_sz, reg_name, &len) == 2) {
> +               /* Memory dereference case, e.g., -4@[sp] */
> +               arg->arg_type = USDT_ARG_REG_DEREF;
> +               arg->val_off = 0;
> +               reg_off = calc_pt_regs_off(reg_name);
> +               if (reg_off < 0)
> +                       return reg_off;
> +               arg->reg_off = reg_off;
> +       } else if (sscanf(arg_str, " %d @ #%ld %n", arg_sz, &off, &len) == 2) {
> +               /* Constant value case, e.g., 4@#5 */
> +               arg->arg_type = USDT_ARG_CONST;
> +               arg->val_off = off;
> +               arg->reg_off = 0;
> +       } else if (sscanf(arg_str, " %d @ %15[a-z0-9] %n", arg_sz, reg_name, &len) == 2) {
> +               /* Register read case, e.g., -8@r4 */
> +               arg->arg_type = USDT_ARG_REG;
> +               arg->val_off = 0;
> +               reg_off = calc_pt_regs_off(reg_name);
> +               if (reg_off < 0)
> +                       return reg_off;
> +               arg->reg_off = reg_off;
> +       } else {
> +               pr_warn("usdt: unrecognized arg #%d spec '%s'\n", arg_num, arg_str);
> +               return -EINVAL;
> +       }
> +
> +       return len;
> +}
> +
>  #else
>
>  static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
> --
> 2.39.1
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH bpf-next v3 2/2] libbpf: usdt arm arg parsing support
  2023-03-07 23:41   ` Andrii Nakryiko
@ 2023-03-08  5:01     ` Puranjay Mohan
  2023-03-08 17:15       ` Andrii Nakryiko
  0 siblings, 1 reply; 8+ messages in thread
From: Puranjay Mohan @ 2023-03-08  5:01 UTC (permalink / raw)
  To: Andrii Nakryiko; +Cc: andrii, ast, daniel, martin.lau, song, yhs, bpf, memxor

Hi,
Thanks for applying the series.

On Wed, Mar 8, 2023 at 12:41 AM Andrii Nakryiko
<andrii.nakryiko@gmail.com> wrote:
>
> On Tue, Mar 7, 2023 at 4:04 AM Puranjay Mohan <puranjay12@gmail.com> wrote:
> >
> > Parsing of USDT arguments is architecture-specific; on arm it is
> > relatively easy since registers used are r[0-10], fp, ip, sp, lr,
> > pc. Format is slightly different compared to aarch64; forms are
> >
> > - "size @ [ reg, #offset ]" for dereferences, for example
> >   "-8 @ [ sp, #76 ]" ; " -4 @ [ sp ]"
> > - "size @ reg" for register values; for example
> >   "-4@r0"
> > - "size @ #value" for raw values; for example
> >   "-8@#1"
> >
> > Add support for parsing USDT arguments for ARM architecture.
> >
> > To test the above changes QEMU's virt[1] board with cortex-a15
> > CPU was used. libbpf-bootstrap's usdt example[2] was modified to attach
> > to a test program with DTRACE_PROBE1/2/3/4... probes to test different
> > combinations.
> >
> > [1] https://www.qemu.org/docs/master/system/arm/virt.html
> > [2] https://github.com/libbpf/libbpf-bootstrap/blob/master/examples/c/usdt.bpf.c
> >
> > Signed-off-by: Puranjay Mohan <puranjay12@gmail.com>
> > ---
> >  tools/lib/bpf/usdt.c | 80 ++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 80 insertions(+)
> >
> > diff --git a/tools/lib/bpf/usdt.c b/tools/lib/bpf/usdt.c
> > index 293b7a37f8a1..27a4589eda1c 100644
> > --- a/tools/lib/bpf/usdt.c
> > +++ b/tools/lib/bpf/usdt.c
> > @@ -1466,6 +1466,86 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
> >         return len;
> >  }
> >
> > +#elif defined(__arm__)
> > +
> > +static int calc_pt_regs_off(const char *reg_name)
> > +{
> > +       static struct {
> > +               const char *name;
> > +               size_t pt_regs_off;
> > +       } reg_map[] = {
> > +               { "r0", offsetof(struct pt_regs, uregs[0]) },
> > +               { "r1", offsetof(struct pt_regs, uregs[1]) },
> > +               { "r2", offsetof(struct pt_regs, uregs[2]) },
> > +               { "r3", offsetof(struct pt_regs, uregs[3]) },
> > +               { "r4", offsetof(struct pt_regs, uregs[4]) },
> > +               { "r5", offsetof(struct pt_regs, uregs[5]) },
> > +               { "r6", offsetof(struct pt_regs, uregs[6]) },
> > +               { "r7", offsetof(struct pt_regs, uregs[7]) },
> > +               { "r8", offsetof(struct pt_regs, uregs[8]) },
> > +               { "r9", offsetof(struct pt_regs, uregs[9]) },
> > +               { "r10", offsetof(struct pt_regs, uregs[10]) },
> > +               { "fp", offsetof(struct pt_regs, uregs[11]) },
> > +               { "ip", offsetof(struct pt_regs, uregs[12]) },
> > +               { "sp", offsetof(struct pt_regs, uregs[13]) },
> > +               { "lr", offsetof(struct pt_regs, uregs[14]) },
> > +               { "pc", offsetof(struct pt_regs, uregs[15]) },
> > +       };
> > +       int i;
> > +
> > +       for (i = 0; i < ARRAY_SIZE(reg_map); i++) {
> > +               if (strcmp(reg_name, reg_map[i].name) == 0)
> > +                       return reg_map[i].pt_regs_off;
> > +       }
> > +
> > +       pr_warn("usdt: unrecognized register '%s'\n", reg_name);
> > +       return -ENOENT;
> > +}
> > +
> > +static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
> > +{
> > +       char reg_name[16];
> > +       int len, reg_off;
> > +       long off;
> > +
> > +       if (sscanf(arg_str, " %d @ \[ %15[a-z0-9], #%ld ] %n",
>
> I've added space before , and applied to bpf-next.
>
> Thanks, it's a nice clean up and wider architecture support!
>
> BTW, I noticed that we don't support fp, ip, lr, and pc (only sp) for
> __aarch64__, why such a difference between 32-bit and 64-bit arms?

Actually, it is just a naming convention.
in AARCH64 R29 is FP and R30 is LR, etc. so, they are decoded with
that. Only SP is seperate.
in ARM the register names are explicitly named.

For ARM: https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst#machine-registers
For AARCH64: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#machine-registers

P.S.: For adding more BPF features for ARM, I feel the following
things are remaining:
1. Adding CI for ARM:
- Can you give me the steps needed to do this?
2. Implement BPF trampoline for ARM.
- This should be a little complicated and might need other dependent
features that might not be available in arm.
3.???

>
> > +                  arg_sz, reg_name, &off, &len) == 3) {
> > +               /* Memory dereference case, e.g., -4@[fp, #96] */
> > +               arg->arg_type = USDT_ARG_REG_DEREF;
> > +               arg->val_off = off;
> > +               reg_off = calc_pt_regs_off(reg_name);
> > +               if (reg_off < 0)
> > +                       return reg_off;
> > +               arg->reg_off = reg_off;
> > +       } else if (sscanf(arg_str, " %d @ \[ %15[a-z0-9] ] %n", arg_sz, reg_name, &len) == 2) {
> > +               /* Memory dereference case, e.g., -4@[sp] */
> > +               arg->arg_type = USDT_ARG_REG_DEREF;
> > +               arg->val_off = 0;
> > +               reg_off = calc_pt_regs_off(reg_name);
> > +               if (reg_off < 0)
> > +                       return reg_off;
> > +               arg->reg_off = reg_off;
> > +       } else if (sscanf(arg_str, " %d @ #%ld %n", arg_sz, &off, &len) == 2) {
> > +               /* Constant value case, e.g., 4@#5 */
> > +               arg->arg_type = USDT_ARG_CONST;
> > +               arg->val_off = off;
> > +               arg->reg_off = 0;
> > +       } else if (sscanf(arg_str, " %d @ %15[a-z0-9] %n", arg_sz, reg_name, &len) == 2) {
> > +               /* Register read case, e.g., -8@r4 */
> > +               arg->arg_type = USDT_ARG_REG;
> > +               arg->val_off = 0;
> > +               reg_off = calc_pt_regs_off(reg_name);
> > +               if (reg_off < 0)
> > +                       return reg_off;
> > +               arg->reg_off = reg_off;
> > +       } else {
> > +               pr_warn("usdt: unrecognized arg #%d spec '%s'\n", arg_num, arg_str);
> > +               return -EINVAL;
> > +       }
> > +
> > +       return len;
> > +}
> > +
> >  #else
> >
> >  static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
> > --
> > 2.39.1
> >



-- 
Thanks and Regards

Yours Truly,

Puranjay Mohan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH bpf-next v3 2/2] libbpf: usdt arm arg parsing support
  2023-03-08  5:01     ` Puranjay Mohan
@ 2023-03-08 17:15       ` Andrii Nakryiko
  2023-03-08 18:36         ` Puranjay Mohan
  0 siblings, 1 reply; 8+ messages in thread
From: Andrii Nakryiko @ 2023-03-08 17:15 UTC (permalink / raw)
  To: Puranjay Mohan, Manu Bretelle, Daniel Müller
  Cc: andrii, ast, daniel, martin.lau, song, yhs, bpf, memxor

On Tue, Mar 7, 2023 at 9:02 PM Puranjay Mohan <puranjay12@gmail.com> wrote:
>
> Hi,
> Thanks for applying the series.
>
> On Wed, Mar 8, 2023 at 12:41 AM Andrii Nakryiko
> <andrii.nakryiko@gmail.com> wrote:
> >
> > On Tue, Mar 7, 2023 at 4:04 AM Puranjay Mohan <puranjay12@gmail.com> wrote:
> > >
> > > Parsing of USDT arguments is architecture-specific; on arm it is
> > > relatively easy since registers used are r[0-10], fp, ip, sp, lr,
> > > pc. Format is slightly different compared to aarch64; forms are
> > >
> > > - "size @ [ reg, #offset ]" for dereferences, for example
> > >   "-8 @ [ sp, #76 ]" ; " -4 @ [ sp ]"
> > > - "size @ reg" for register values; for example
> > >   "-4@r0"
> > > - "size @ #value" for raw values; for example
> > >   "-8@#1"
> > >
> > > Add support for parsing USDT arguments for ARM architecture.
> > >
> > > To test the above changes QEMU's virt[1] board with cortex-a15
> > > CPU was used. libbpf-bootstrap's usdt example[2] was modified to attach
> > > to a test program with DTRACE_PROBE1/2/3/4... probes to test different
> > > combinations.
> > >
> > > [1] https://www.qemu.org/docs/master/system/arm/virt.html
> > > [2] https://github.com/libbpf/libbpf-bootstrap/blob/master/examples/c/usdt.bpf.c
> > >
> > > Signed-off-by: Puranjay Mohan <puranjay12@gmail.com>
> > > ---
> > >  tools/lib/bpf/usdt.c | 80 ++++++++++++++++++++++++++++++++++++++++++++
> > >  1 file changed, 80 insertions(+)
> > >
> > > diff --git a/tools/lib/bpf/usdt.c b/tools/lib/bpf/usdt.c
> > > index 293b7a37f8a1..27a4589eda1c 100644
> > > --- a/tools/lib/bpf/usdt.c
> > > +++ b/tools/lib/bpf/usdt.c
> > > @@ -1466,6 +1466,86 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
> > >         return len;
> > >  }
> > >
> > > +#elif defined(__arm__)
> > > +
> > > +static int calc_pt_regs_off(const char *reg_name)
> > > +{
> > > +       static struct {
> > > +               const char *name;
> > > +               size_t pt_regs_off;
> > > +       } reg_map[] = {
> > > +               { "r0", offsetof(struct pt_regs, uregs[0]) },
> > > +               { "r1", offsetof(struct pt_regs, uregs[1]) },
> > > +               { "r2", offsetof(struct pt_regs, uregs[2]) },
> > > +               { "r3", offsetof(struct pt_regs, uregs[3]) },
> > > +               { "r4", offsetof(struct pt_regs, uregs[4]) },
> > > +               { "r5", offsetof(struct pt_regs, uregs[5]) },
> > > +               { "r6", offsetof(struct pt_regs, uregs[6]) },
> > > +               { "r7", offsetof(struct pt_regs, uregs[7]) },
> > > +               { "r8", offsetof(struct pt_regs, uregs[8]) },
> > > +               { "r9", offsetof(struct pt_regs, uregs[9]) },
> > > +               { "r10", offsetof(struct pt_regs, uregs[10]) },
> > > +               { "fp", offsetof(struct pt_regs, uregs[11]) },
> > > +               { "ip", offsetof(struct pt_regs, uregs[12]) },
> > > +               { "sp", offsetof(struct pt_regs, uregs[13]) },
> > > +               { "lr", offsetof(struct pt_regs, uregs[14]) },
> > > +               { "pc", offsetof(struct pt_regs, uregs[15]) },
> > > +       };
> > > +       int i;
> > > +
> > > +       for (i = 0; i < ARRAY_SIZE(reg_map); i++) {
> > > +               if (strcmp(reg_name, reg_map[i].name) == 0)
> > > +                       return reg_map[i].pt_regs_off;
> > > +       }
> > > +
> > > +       pr_warn("usdt: unrecognized register '%s'\n", reg_name);
> > > +       return -ENOENT;
> > > +}
> > > +
> > > +static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
> > > +{
> > > +       char reg_name[16];
> > > +       int len, reg_off;
> > > +       long off;
> > > +
> > > +       if (sscanf(arg_str, " %d @ \[ %15[a-z0-9], #%ld ] %n",
> >
> > I've added space before , and applied to bpf-next.
> >
> > Thanks, it's a nice clean up and wider architecture support!
> >
> > BTW, I noticed that we don't support fp, ip, lr, and pc (only sp) for
> > __aarch64__, why such a difference between 32-bit and 64-bit arms?
>
> Actually, it is just a naming convention.
> in AARCH64 R29 is FP and R30 is LR, etc. so, they are decoded with
> that. Only SP is seperate.
> in ARM the register names are explicitly named.

ah, ok, makes sense, thanks for explaining!

>
> For ARM: https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst#machine-registers
> For AARCH64: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#machine-registers
>
> P.S.: For adding more BPF features for ARM, I feel the following
> things are remaining:
> 1. Adding CI for ARM:
> - Can you give me the steps needed to do this?

I'm CC'ing Manu and Daniel, who are working on BPF CI. We are (mostly,
with the exception for s390x) using AWS to get runners on native
architecture. I'm not sure if AWS provides arm32 instances, so to
enable ARM32 in CI we'd need to resort to cross-compilation, probably.
But let's see if Manu and Daniel have specific suggestions.


> 2. Implement BPF trampoline for ARM.
> - This should be a little complicated and might need other dependent
> features that might not be available in arm.

trampoline for ARM makes sense. Not sure if anyone else is working on
this or not, so feel free to create a separate email thread to discuss
plans and details.


> 3.???

Assuming we have CI, there probably will be a bunch of clean up work
to make existing test work on 32-bit host architectures properly.


Also please see how much work it is to start supporting kfuncs for
arm32, see bpf_jit_supports_kfunc_call() and related infrastructure.
It should be a smaller undertaking compared to BPF trampoline.

>
> >
> > > +                  arg_sz, reg_name, &off, &len) == 3) {
> > > +               /* Memory dereference case, e.g., -4@[fp, #96] */
> > > +               arg->arg_type = USDT_ARG_REG_DEREF;
> > > +               arg->val_off = off;
> > > +               reg_off = calc_pt_regs_off(reg_name);
> > > +               if (reg_off < 0)
> > > +                       return reg_off;
> > > +               arg->reg_off = reg_off;
> > > +       } else if (sscanf(arg_str, " %d @ \[ %15[a-z0-9] ] %n", arg_sz, reg_name, &len) == 2) {
> > > +               /* Memory dereference case, e.g., -4@[sp] */
> > > +               arg->arg_type = USDT_ARG_REG_DEREF;
> > > +               arg->val_off = 0;
> > > +               reg_off = calc_pt_regs_off(reg_name);
> > > +               if (reg_off < 0)
> > > +                       return reg_off;
> > > +               arg->reg_off = reg_off;
> > > +       } else if (sscanf(arg_str, " %d @ #%ld %n", arg_sz, &off, &len) == 2) {
> > > +               /* Constant value case, e.g., 4@#5 */
> > > +               arg->arg_type = USDT_ARG_CONST;
> > > +               arg->val_off = off;
> > > +               arg->reg_off = 0;
> > > +       } else if (sscanf(arg_str, " %d @ %15[a-z0-9] %n", arg_sz, reg_name, &len) == 2) {
> > > +               /* Register read case, e.g., -8@r4 */
> > > +               arg->arg_type = USDT_ARG_REG;
> > > +               arg->val_off = 0;
> > > +               reg_off = calc_pt_regs_off(reg_name);
> > > +               if (reg_off < 0)
> > > +                       return reg_off;
> > > +               arg->reg_off = reg_off;
> > > +       } else {
> > > +               pr_warn("usdt: unrecognized arg #%d spec '%s'\n", arg_num, arg_str);
> > > +               return -EINVAL;
> > > +       }
> > > +
> > > +       return len;
> > > +}
> > > +
> > >  #else
> > >
> > >  static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
> > > --
> > > 2.39.1
> > >
>
>
>
> --
> Thanks and Regards
>
> Yours Truly,
>
> Puranjay Mohan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH bpf-next v3 2/2] libbpf: usdt arm arg parsing support
  2023-03-08 17:15       ` Andrii Nakryiko
@ 2023-03-08 18:36         ` Puranjay Mohan
  0 siblings, 0 replies; 8+ messages in thread
From: Puranjay Mohan @ 2023-03-08 18:36 UTC (permalink / raw)
  To: Andrii Nakryiko
  Cc: Manu Bretelle, Daniel Müller, andrii, ast, daniel,
	martin.lau, song, yhs, bpf, memxor, yangjihong1

Hello,

On Wed, Mar 8, 2023 at 10:45 PM Andrii Nakryiko
<andrii.nakryiko@gmail.com> wrote:
>
> On Tue, Mar 7, 2023 at 9:02 PM Puranjay Mohan <puranjay12@gmail.com> wrote:
> >
> > Hi,
> > Thanks for applying the series.
> >
> > On Wed, Mar 8, 2023 at 12:41 AM Andrii Nakryiko
> > <andrii.nakryiko@gmail.com> wrote:
> > >
> > > On Tue, Mar 7, 2023 at 4:04 AM Puranjay Mohan <puranjay12@gmail.com> wrote:
> > > >
> > > > Parsing of USDT arguments is architecture-specific; on arm it is
> > > > relatively easy since registers used are r[0-10], fp, ip, sp, lr,
> > > > pc. Format is slightly different compared to aarch64; forms are
> > > >
> > > > - "size @ [ reg, #offset ]" for dereferences, for example
> > > >   "-8 @ [ sp, #76 ]" ; " -4 @ [ sp ]"
> > > > - "size @ reg" for register values; for example
> > > >   "-4@r0"
> > > > - "size @ #value" for raw values; for example
> > > >   "-8@#1"
> > > >
> > > > Add support for parsing USDT arguments for ARM architecture.
> > > >
> > > > To test the above changes QEMU's virt[1] board with cortex-a15
> > > > CPU was used. libbpf-bootstrap's usdt example[2] was modified to attach
> > > > to a test program with DTRACE_PROBE1/2/3/4... probes to test different
> > > > combinations.
> > > >
> > > > [1] https://www.qemu.org/docs/master/system/arm/virt.html
> > > > [2] https://github.com/libbpf/libbpf-bootstrap/blob/master/examples/c/usdt.bpf.c
> > > >
> > > > Signed-off-by: Puranjay Mohan <puranjay12@gmail.com>
> > > > ---
> > > >  tools/lib/bpf/usdt.c | 80 ++++++++++++++++++++++++++++++++++++++++++++
> > > >  1 file changed, 80 insertions(+)
> > > >
> > > > diff --git a/tools/lib/bpf/usdt.c b/tools/lib/bpf/usdt.c
> > > > index 293b7a37f8a1..27a4589eda1c 100644
> > > > --- a/tools/lib/bpf/usdt.c
> > > > +++ b/tools/lib/bpf/usdt.c
> > > > @@ -1466,6 +1466,86 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
> > > >         return len;
> > > >  }
> > > >
> > > > +#elif defined(__arm__)
> > > > +
> > > > +static int calc_pt_regs_off(const char *reg_name)
> > > > +{
> > > > +       static struct {
> > > > +               const char *name;
> > > > +               size_t pt_regs_off;
> > > > +       } reg_map[] = {
> > > > +               { "r0", offsetof(struct pt_regs, uregs[0]) },
> > > > +               { "r1", offsetof(struct pt_regs, uregs[1]) },
> > > > +               { "r2", offsetof(struct pt_regs, uregs[2]) },
> > > > +               { "r3", offsetof(struct pt_regs, uregs[3]) },
> > > > +               { "r4", offsetof(struct pt_regs, uregs[4]) },
> > > > +               { "r5", offsetof(struct pt_regs, uregs[5]) },
> > > > +               { "r6", offsetof(struct pt_regs, uregs[6]) },
> > > > +               { "r7", offsetof(struct pt_regs, uregs[7]) },
> > > > +               { "r8", offsetof(struct pt_regs, uregs[8]) },
> > > > +               { "r9", offsetof(struct pt_regs, uregs[9]) },
> > > > +               { "r10", offsetof(struct pt_regs, uregs[10]) },
> > > > +               { "fp", offsetof(struct pt_regs, uregs[11]) },
> > > > +               { "ip", offsetof(struct pt_regs, uregs[12]) },
> > > > +               { "sp", offsetof(struct pt_regs, uregs[13]) },
> > > > +               { "lr", offsetof(struct pt_regs, uregs[14]) },
> > > > +               { "pc", offsetof(struct pt_regs, uregs[15]) },
> > > > +       };
> > > > +       int i;
> > > > +
> > > > +       for (i = 0; i < ARRAY_SIZE(reg_map); i++) {
> > > > +               if (strcmp(reg_name, reg_map[i].name) == 0)
> > > > +                       return reg_map[i].pt_regs_off;
> > > > +       }
> > > > +
> > > > +       pr_warn("usdt: unrecognized register '%s'\n", reg_name);
> > > > +       return -ENOENT;
> > > > +}
> > > > +
> > > > +static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
> > > > +{
> > > > +       char reg_name[16];
> > > > +       int len, reg_off;
> > > > +       long off;
> > > > +
> > > > +       if (sscanf(arg_str, " %d @ \[ %15[a-z0-9], #%ld ] %n",
> > >
> > > I've added space before , and applied to bpf-next.
> > >
> > > Thanks, it's a nice clean up and wider architecture support!
> > >
> > > BTW, I noticed that we don't support fp, ip, lr, and pc (only sp) for
> > > __aarch64__, why such a difference between 32-bit and 64-bit arms?
> >
> > Actually, it is just a naming convention.
> > in AARCH64 R29 is FP and R30 is LR, etc. so, they are decoded with
> > that. Only SP is seperate.
> > in ARM the register names are explicitly named.
>
> ah, ok, makes sense, thanks for explaining!
>
> >
> > For ARM: https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst#machine-registers
> > For AARCH64: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#machine-registers
> >
> > P.S.: For adding more BPF features for ARM, I feel the following
> > things are remaining:
> > 1. Adding CI for ARM:
> > - Can you give me the steps needed to do this?
>
> I'm CC'ing Manu and Daniel, who are working on BPF CI. We are (mostly,
> with the exception for s390x) using AWS to get runners on native
> architecture. I'm not sure if AWS provides arm32 instances, so to
> enable ARM32 in CI we'd need to resort to cross-compilation, probably.
> But let's see if Manu and Daniel have specific suggestions.
>

Thanks for the details, this should be the first thing to do. If it is
possible to cross-compile and run on qemu in the CI.
AWS doesn't provide ARM32 instances. so we can't get runners on native
architectures.

>
> > 2. Implement BPF trampoline for ARM.
> > - This should be a little complicated and might need other dependent
> > features that might not be available in arm.
>
> trampoline for ARM makes sense. Not sure if anyone else is working on
> this or not, so feel free to create a separate email thread to discuss
> plans and details.

Sure, I will start a new thread to discuss this.

>
>
> > 3.???
>
> Assuming we have CI, there probably will be a bunch of clean up work
> to make existing test work on 32-bit host architectures properly.

Yes, the frequent problem here is tests using "long" variables in maps
and pointers which are 32-bit/64-bit in ARM/BPF.

>
>
> Also please see how much work it is to start supporting kfuncs for
> arm32, see bpf_jit_supports_kfunc_call() and related infrastructure.
> It should be a smaller undertaking compared to BPF trampoline.

I looked at the patch series for "bpf: Support kernel function call in
32-bit ARM"
https://lore.kernel.org/all/20221126094530.226629-1-yangjihong1@huawei.com/

I think Yang Jihong is planning to send more versions of this series.
CC'ing him on this thread.

>
> >
> > >
> > > > +                  arg_sz, reg_name, &off, &len) == 3) {
> > > > +               /* Memory dereference case, e.g., -4@[fp, #96] */
> > > > +               arg->arg_type = USDT_ARG_REG_DEREF;
> > > > +               arg->val_off = off;
> > > > +               reg_off = calc_pt_regs_off(reg_name);
> > > > +               if (reg_off < 0)
> > > > +                       return reg_off;
> > > > +               arg->reg_off = reg_off;
> > > > +       } else if (sscanf(arg_str, " %d @ \[ %15[a-z0-9] ] %n", arg_sz, reg_name, &len) == 2) {
> > > > +               /* Memory dereference case, e.g., -4@[sp] */
> > > > +               arg->arg_type = USDT_ARG_REG_DEREF;
> > > > +               arg->val_off = 0;
> > > > +               reg_off = calc_pt_regs_off(reg_name);
> > > > +               if (reg_off < 0)
> > > > +                       return reg_off;
> > > > +               arg->reg_off = reg_off;
> > > > +       } else if (sscanf(arg_str, " %d @ #%ld %n", arg_sz, &off, &len) == 2) {
> > > > +               /* Constant value case, e.g., 4@#5 */
> > > > +               arg->arg_type = USDT_ARG_CONST;
> > > > +               arg->val_off = off;
> > > > +               arg->reg_off = 0;
> > > > +       } else if (sscanf(arg_str, " %d @ %15[a-z0-9] %n", arg_sz, reg_name, &len) == 2) {
> > > > +               /* Register read case, e.g., -8@r4 */
> > > > +               arg->arg_type = USDT_ARG_REG;
> > > > +               arg->val_off = 0;
> > > > +               reg_off = calc_pt_regs_off(reg_name);
> > > > +               if (reg_off < 0)
> > > > +                       return reg_off;
> > > > +               arg->reg_off = reg_off;
> > > > +       } else {
> > > > +               pr_warn("usdt: unrecognized arg #%d spec '%s'\n", arg_num, arg_str);
> > > > +               return -EINVAL;
> > > > +       }
> > > > +
> > > > +       return len;
> > > > +}
> > > > +
> > > >  #else
> > > >
> > > >  static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg, int *arg_sz)
> > > > --
> > > > 2.39.1
> > > >
> >
> >
> >
> > --
> > Thanks and Regards
> >
> > Yours Truly,
> >
> > Puranjay Mohan



-- 
Thanks and Regards

Yours Truly,

Puranjay Mohan

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2023-03-08 18:37 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-07 12:04 [PATCH bpf-next v3 0/2] libbpf: usdt arm arg parsing support Puranjay Mohan
2023-03-07 12:04 ` [PATCH bpf-next v3 1/2] libbpf: refactor parse_usdt_arg() to re-use code Puranjay Mohan
2023-03-07 12:04 ` [PATCH bpf-next v3 2/2] libbpf: usdt arm arg parsing support Puranjay Mohan
2023-03-07 23:41   ` Andrii Nakryiko
2023-03-08  5:01     ` Puranjay Mohan
2023-03-08 17:15       ` Andrii Nakryiko
2023-03-08 18:36         ` Puranjay Mohan
2023-03-07 23:40 ` [PATCH bpf-next v3 0/2] " patchwork-bot+netdevbpf

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.