diff --git a/tools/lib/bpf/usdt.bpf.h b/tools/lib/bpf/usdt.bpf.h index 60237acf6b025..881a2422a8efb 100644 --- a/tools/lib/bpf/usdt.bpf.h +++ b/tools/lib/bpf/usdt.bpf.h @@ -166,7 +166,7 @@ int bpf_usdt_arg(struct pt_regs *ctx, __u64 arg_num, long *res) case BPF_USDT_ARG_REG_DEREF: /* Arg is in memory addressed by register, plus some offset * (e.g., "-4@-1204(%rbp)" in USDT arg spec). Register is - * identified lik with BPF_USDT_ARG_REG case, and the offset + * identified like with BPF_USDT_ARG_REG case, and the offset * is in arg_spec->val_off. We first fetch register contents * from pt_regs, then do another user-space probe read to * fetch argument value itself. @@ -177,6 +177,9 @@ int bpf_usdt_arg(struct pt_regs *ctx, __u64 arg_num, long *res) err = bpf_probe_read_user(&val, sizeof(val), (void *)val + arg_spec->val_off); if (err) return err; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + val >>= arg_spec->arg_bitshift; +#endif break; default: return -EINVAL; @@ -198,7 +201,7 @@ int bpf_usdt_arg(struct pt_regs *ctx, __u64 arg_num, long *res) /* Retrieve user-specified cookie value provided during attach as * bpf_usdt_opts.usdt_cookie. This serves the same purpose as BPF cookie * returned by bpf_get_attach_cookie(). Libbpf's support for USDT is itself - * utilizaing BPF cookies internally, so user can't use BPF cookie directly + * utilizing BPF cookies internally, so user can't use BPF cookie directly * for USDT programs and has to use bpf_usdt_cookie() API instead. */ static inline __noinline diff --git a/tools/lib/bpf/usdt.c b/tools/lib/bpf/usdt.c index b699e720136a9..cb9aa455c0dfb 100644 --- a/tools/lib/bpf/usdt.c +++ b/tools/lib/bpf/usdt.c @@ -108,7 +108,7 @@ * code through spec map. This allows BPF applications to quickly fetch the * actual value at runtime using a simple BPF-side code. * - * With basics out of the way, let's go over less immeditately obvious aspects + * With basics out of the way, let's go over less immediately obvious aspects * of supporting USDTs. * * First, there is no special USDT BPF program type. It is actually just @@ -189,14 +189,14 @@ #define USDT_NOTE_TYPE 3 #define USDT_NOTE_NAME "stapsdt" -/* should match exactly enum __bpf_usdt_arg_type from bpf_usdt.bpf.h */ +/* should match exactly enum __bpf_usdt_arg_type from usdt.bpf.h */ enum usdt_arg_type { USDT_ARG_CONST, USDT_ARG_REG, USDT_ARG_REG_DEREF, }; -/* should match exactly struct __bpf_usdt_arg_spec from bpf_usdt.bpf.h */ +/* should match exactly struct __bpf_usdt_arg_spec from usdt.bpf.h */ struct usdt_arg_spec { __u64 val_off; enum usdt_arg_type arg_type; @@ -328,9 +328,9 @@ static int sanity_check_usdt_elf(Elf *elf, const char *path) return -EBADF; } -#if __BYTE_ORDER == __LITTLE_ENDIAN +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ endianness = ELFDATA2LSB; -#elif __BYTE_ORDER == __BIG_ENDIAN +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ endianness = ELFDATA2MSB; #else # error "Unrecognized __BYTE_ORDER__" @@ -843,7 +843,7 @@ static int bpf_link_usdt_detach(struct bpf_link *link) sizeof(*new_free_ids)); /* If we couldn't resize free_spec_ids, we'll just leak * a bunch of free IDs; this is very unlikely to happen and if - * system is so exausted on memory, it's the least of user's + * system is so exhausted on memory, it's the least of user's * concerns, probably. * So just do our best here to return those IDs to usdt_manager. */ @@ -1269,6 +1269,63 @@ static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec return len; } +#elif defined(__s390x__) + +/* 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) +{ + unsigned int reg; + int sz, len; + long off; + + if (sscanf(arg_str, " %d @ %ld ( %%r%u ) %n", &sz, &off, ®, &len) == 3) { + /* Memory dereference case, e.g., -2@-28(%r15) */ + arg->arg_type = USDT_ARG_REG_DEREF; + arg->val_off = off; + if (reg > 15) { + pr_warn("usdt: unrecognized register '%%r%u'\n", reg); + return -EINVAL; + } + arg->reg_off = offsetof(user_pt_regs, gprs[reg]); + } else if (sscanf(arg_str, " %d @ %%r%u %n", &sz, ®, &len) == 2) { + /* Register read case, e.g., -8@%r0 */ + arg->arg_type = USDT_ARG_REG; + arg->val_off = 0; + if (reg > 15) { + pr_warn("usdt: unrecognized register '%%r%u'\n", reg); + return -EINVAL; + } + arg->reg_off = offsetof(user_pt_regs, gprs[reg]); + } else if (sscanf(arg_str, " %d @ %ld %n", &sz, &off, &len) == 2) { + /* Constant value case, e.g., 4@71 */ + arg->arg_type = USDT_ARG_CONST; + arg->val_off = off; + arg->reg_off = -1; + } else { + pr_warn("usdt: unrecognized arg #%d spec '%s'\n", arg_num, + arg_str); + return -EINVAL; + } + + arg->arg_signed = sz < 0; + if (sz < 0) + sz = -sz; + + switch (sz) { + case 1: case 2: case 4: case 8: + arg->arg_bitshift = 64 - sz * 8; + break; + default: + pr_warn("usdt: unsupported arg #%d (spec '%s') size: %d\n", + arg_num, arg_str, sz); + return -EINVAL; + } + + return len; +} + #else static int parse_usdt_arg(const char *arg_str, int arg_num, struct usdt_arg_spec *arg)