Skip to content

Commit 65a0018

Browse files
Pu LehuiKernel Patches Daemon
Pu Lehui
authored and
Kernel Patches Daemon
committed
libbpf: Support riscv USDT argument parsing logic
Add riscv-specific USDT argument specification parsing logic. riscv USDT argument format is shown below: - Memory dereference case: "size@off(reg)", e.g. "-8@-88(s0)" - Constant value case: "size@val", e.g. "4@5" - Register read case: "size@reg", e.g. "-8@a1" s8 will be marked as poison while it's a reg of riscv, we need to alias it in advance. Both RV32 and RV64 have been tested. Signed-off-by: Pu Lehui <[email protected]>
1 parent 579057d commit 65a0018

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed

tools/lib/bpf/usdt.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
#include <linux/ptrace.h>
1111
#include <linux/kernel.h>
1212

13+
/* s8 will be marked as poison while it's a reg of riscv */
14+
#if defined(__riscv)
15+
#define rv_s8 s8
16+
#endif
17+
1318
#include "bpf.h"
1419
#include "libbpf.h"
1520
#include "libbpf_common.h"
@@ -1400,6 +1405,108 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec
14001405
return len;
14011406
}
14021407

1408+
#elif defined(__riscv)
1409+
1410+
static int calc_pt_regs_off(const char *reg_name)
1411+
{
1412+
static struct {
1413+
const char *name;
1414+
size_t pt_regs_off;
1415+
} reg_map[] = {
1416+
{ "ra", offsetof(struct user_regs_struct, ra) },
1417+
{ "sp", offsetof(struct user_regs_struct, sp) },
1418+
{ "gp", offsetof(struct user_regs_struct, gp) },
1419+
{ "tp", offsetof(struct user_regs_struct, tp) },
1420+
{ "a0", offsetof(struct user_regs_struct, a0) },
1421+
{ "a1", offsetof(struct user_regs_struct, a1) },
1422+
{ "a2", offsetof(struct user_regs_struct, a2) },
1423+
{ "a3", offsetof(struct user_regs_struct, a3) },
1424+
{ "a4", offsetof(struct user_regs_struct, a4) },
1425+
{ "a5", offsetof(struct user_regs_struct, a5) },
1426+
{ "a6", offsetof(struct user_regs_struct, a6) },
1427+
{ "a7", offsetof(struct user_regs_struct, a7) },
1428+
{ "s0", offsetof(struct user_regs_struct, s0) },
1429+
{ "s1", offsetof(struct user_regs_struct, s1) },
1430+
{ "s2", offsetof(struct user_regs_struct, s2) },
1431+
{ "s3", offsetof(struct user_regs_struct, s3) },
1432+
{ "s4", offsetof(struct user_regs_struct, s4) },
1433+
{ "s5", offsetof(struct user_regs_struct, s5) },
1434+
{ "s6", offsetof(struct user_regs_struct, s6) },
1435+
{ "s7", offsetof(struct user_regs_struct, s7) },
1436+
{ "s8", offsetof(struct user_regs_struct, rv_s8) },
1437+
{ "s9", offsetof(struct user_regs_struct, s9) },
1438+
{ "s10", offsetof(struct user_regs_struct, s10) },
1439+
{ "s11", offsetof(struct user_regs_struct, s11) },
1440+
{ "t0", offsetof(struct user_regs_struct, t0) },
1441+
{ "t1", offsetof(struct user_regs_struct, t1) },
1442+
{ "t2", offsetof(struct user_regs_struct, t2) },
1443+
{ "t3", offsetof(struct user_regs_struct, t3) },
1444+
{ "t4", offsetof(struct user_regs_struct, t4) },
1445+
{ "t5", offsetof(struct user_regs_struct, t5) },
1446+
{ "t6", offsetof(struct user_regs_struct, t6) },
1447+
};
1448+
int i;
1449+
1450+
for (i = 0; i < ARRAY_SIZE(reg_map); i++) {
1451+
if (strcmp(reg_name, reg_map[i].name) == 0)
1452+
return reg_map[i].pt_regs_off;
1453+
}
1454+
1455+
pr_warn("usdt: unrecognized register '%s'\n", reg_name);
1456+
return -ENOENT;
1457+
}
1458+
1459+
static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg)
1460+
{
1461+
char *reg_name = NULL;
1462+
int arg_sz, len, reg_off;
1463+
long off;
1464+
1465+
if (sscanf(arg_str, " %d @ %ld ( %m[a-z0-9] ) %n", &arg_sz, &off, &reg_name, &len) == 3) {
1466+
/* Memory dereference case, e.g., -8@-88(s0) */
1467+
arg->arg_type = USDT_ARG_REG_DEREF;
1468+
arg->val_off = off;
1469+
reg_off = calc_pt_regs_off(reg_name);
1470+
free(reg_name);
1471+
if (reg_off < 0)
1472+
return reg_off;
1473+
arg->reg_off = reg_off;
1474+
} else if (sscanf(arg_str, " %d @ %ld %n", &arg_sz, &off, &len) == 2) {
1475+
/* Constant value case, e.g., 4@5 */
1476+
arg->arg_type = USDT_ARG_CONST;
1477+
arg->val_off = off;
1478+
arg->reg_off = 0;
1479+
} else if (sscanf(arg_str, " %d @ %m[a-z0-9] %n", &arg_sz, &reg_name, &len) == 2) {
1480+
/* Register read case, e.g., -8@a1 */
1481+
arg->arg_type = USDT_ARG_REG;
1482+
arg->val_off = 0;
1483+
reg_off = calc_pt_regs_off(reg_name);
1484+
free(reg_name);
1485+
if (reg_off < 0)
1486+
return reg_off;
1487+
arg->reg_off = reg_off;
1488+
} else {
1489+
pr_warn("usdt: unrecognized arg #%d spec '%s'\n", arg_num, arg_str);
1490+
return -EINVAL;
1491+
}
1492+
1493+
arg->arg_signed = arg_sz < 0;
1494+
if (arg_sz < 0)
1495+
arg_sz = -arg_sz;
1496+
1497+
switch (arg_sz) {
1498+
case 1: case 2: case 4: case 8:
1499+
arg->arg_bitshift = 64 - arg_sz * 8;
1500+
break;
1501+
default:
1502+
pr_warn("usdt: unsupported arg #%d (spec '%s') size: %d\n",
1503+
arg_num, arg_str, arg_sz);
1504+
return -EINVAL;
1505+
}
1506+
1507+
return len;
1508+
}
1509+
14031510
#else
14041511

14051512
static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg)

0 commit comments

Comments
 (0)