New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can't use argdist to trace args which type is double #3875
Comments
Very weird. Will investigate. BTW, you should trace #if defined(BPF_LICENSE)
#error BPF_LICENSE cannot be specified through cflags
#endif
#if !defined(CONFIG_CC_STACKPROTECTOR)
#if defined(CONFIG_CC_STACKPROTECTOR_AUTO) \
|| defined(CONFIG_CC_STACKPROTECTOR_REGULAR) \
|| defined(CONFIG_CC_STACKPROTECTOR_STRONG)
#define CONFIG_CC_STACKPROTECTOR
#endif
#endif
struct __string_t { char s[80]; };
#include <uapi/linux/ptrace.h>
struct sqrt_hash0_key_t {
long v0;
};
BPF_HASH(sqrt_hash0, struct sqrt_hash0_key_t, u64);
__attribute__((section(".bpf.fn.sqrt_probe0")))
int sqrt_probe0(struct pt_regs *ctx)
{
double x = ctx->di; <- This line causes the problem.
u64 __pid_tgid = bpf_get_current_pid_tgid();
u32 __pid = __pid_tgid; // lower 32 bits
u32 __tgid = __pid_tgid >> 32; // upper 32 bits
struct sqrt_hash0_key_t __key = {};
__key.v0 = x;
if (!(1)) return 0;
({ typeof(sqrt_hash0.key) _key = __key; typeof(sqrt_hash0.leaf) *_leaf = bpf_map_lookup_elem_(bpf_pseudo_fd(1, -1), &_key); if (_leaf) lock_xadd(_leaf, 1);else { typeof(sqrt_hash0.leaf) _zleaf; __builtin_memset(&_zleaf, 0, sizeof(_zleaf)); _zleaf += 1;bpf_map_update_elem_(bpf_pseudo_fd(1, -1), &_key, &_zleaf, BPF_NOEXIST); } });
return 0;
}
#include <bcc/footer.h> |
|
Did not realize this. :) So what is |
BTF_KIND_FLOAT is for vmlinux BTF (with arch x86_64, arm, etc.) |
can we use assembly code to trace double variables? As we know, gcc ABI defines call convention. For X86_64, gcc will use xmm register to store the floating parameters. |
How about using |
I do not think so. I think if double implicitly cast to long, value will be changed. |
Yeah, should be |
I tried, but failed. The |
Test program: static int foobar(int x, double y, int z) {
return x;
}
int main() {
int x = foobar(123, 456, 789);
return x;
} BPF program: SEC("kprobe/foobar")
int handle_foobar(struct pt_regs *ctx)
{
__u64 p1 = PT_REGS_PARM1_CORE(ctx);
bpf_printk("%ld %d %x", p1, p1, p1);
__u64 p2 = PT_REGS_PARM2_CORE(ctx);
bpf_printk("%ld %d %x", p2, p2, p2);
__u64 p3 = PT_REGS_PARM3_CORE(ctx);
bpf_printk("%ld %d %x", p3, p3, p3);
return 0;
} Output:
|
I think maybe we can fetch double parameter from registers. But I am not familiar with LLVM call convention. Does someone knows LLVM call convention? |
The x86_64 calling convention is to use xmm registers for floating point numbers. But unfortunately, xmm registers are not preserved in pt_regs, so we cannot really get them. Not sure debugfs uprobe_events can handle this or not. |
I am not meaning get double from pt_resg, I mean get double from registers directly. For example(in X86_64 architecture):
// compile : g++ test1.cpp -o test |
You can't do that in BPF. |
Yeah, just a thinking. Is assembly code avaliable in BPF code? I know it must be different from INTEL or ARM assembly code. |
bcc/libbpf-tools/cpufreq.bpf.c Lines 20 to 26 in 3a03901
|
Yes, bpf supports asm code. The assembly code has to be bpf insn similar to asm code generated with The best possible way is to use a bpf helper and inside the helper you can use x86 asm code to retrieve the value. The helper needs to be generic so it can apply to different architectures. |
@Hankin-Liu I noticed a similar issue in #3880. In that case, none of the arguments to my USDT were floats, but register pressure (presumably) resulted in the compiler choosing to use an After talking to @yonghong-song, unfortunately his 'use a bpf helper' suggestion:
is the best path forward. I'm working on a patch to expose such a helper, but we'll have to wait until it's included in a new kernel release to fix this problem permanently. In my case, I considered a potential workaround similar to what you did in this comment: reading the register from userspace since I wasn't using the value in the BPF program, just putting it in a perf buffer and sending it to userspace. Such a workaround would be very flakey at best since I decided not to validate this workaround, just throwing it out there. |
[root@fedora tools]# ./argdist -C 'p:c:sqrt(double x):double:x'
error: /virtual/main.c:24:13: in function sqrt_probe0 i32 (%struct.pt_regs*): A call to built-in function '__floatundidf' is not supported.
Does this tool support float or double parameter trace?
The text was updated successfully, but these errors were encountered: