Use case:
we have function count bpf (libbpf based) profiler.
./profiler binary function_pattern
Counts number of times functions called and entry, exit time , time spent etc.
Attaches uprobes to functions matched the pattern in application.
We have use case of running multiple instances of profiler which will result in attaching
uprobe multiple times but from different instances of profiler.
issues :
application to long to complete or gets stuck.
are we not supposed to use uprobe like this.
example app-> has function “abc()”
terminal1 -> ./profiler app abc
terminal -> ./profiler app abc
profiler.c
{
uproble_attach("app", abc->offset);
}
actually we run profiler with mpi.
its works when rank is 1. more than rank one, app gets stuck.
mpi ./profiler app abc
This is example code.
kern_bpf.c
char LICENSE[] SEC("license") = "Dual BSD/GPL";
SEC("uprobe")
int handle_uprobe_ref_ctr(struct pt_regs *ctx)
{
__u64 addr = bpf_get_func_ip(ctx);
const char fmt_str[] = "function fp %lld ip %lldn";
bpf_trace_printk(fmt_str, sizeof(fmt_str), (void *)PT_REGS_FP(ctx), addr);
return 0;
}
SEC("uretprobe")
int handle_uretprobe_ref_ctr(struct pt_regs *ctx)
{
bpf_printk("handle_uretprobe_ref_ctr n");
return 0;
}
app.c
some executable operations
void op_add(int a, int b)
{
}
void op_sub(int a, int b)
{
}
int main()
{
printf("pid %dn",getpid());
for (int i = 0;; i++) {
/* trigger our BPF programs */
fprintf(stderr, ".");
op_add(i, i + 1);
op_sub(i * i, i);
sleep(1);
}
return 0;
}
user space bpf program
int main(int argc, char **argv)
{
size_t offset1;
size_t offset2;
int err, i;
char filename[256];
pid_t pid;
struct bpf_object *obj = NULL;
struct bpf_program *prog[2];
static struct bpf_link *bpflinks[2];
static struct bpf_link *ubpflinks[2];
if (argc < 2) {
printf("Error return n");
return 0;
}
pid = strtoul(argv[1], NULL, 10);
snprintf(filename, 256, "/proc/%d/exe", pid);
offset1 = get_elf_func_offset("/data/expr/operations", "op_add");
offset2 = get_elf_func_offset("/data/expr/operations", "op_sub");
snprintf(filename, sizeof(filename), "%s.bpf.o", argv[0]);
obj = bpf_object__open_file(filename, NULL);
if (libbpf_get_error(obj)) {
fprintf(stderr, "ERROR: opening BPF object file failedn");
obj = NULL;
goto cleanup;
}
/* load BPF program */
if (bpf_object__load(obj)) {
fprintf(stderr, "ERROR: loading BPF object file failedn");
goto cleanup;
}
prog[0] = bpf_object__find_program_by_name(obj, "handle_uprobe_ref_ctr");
// prog[1] = bpf_object__find_program_by_name(obj, "handle_uretprobe_ref_ctr");
ubpflinks[0] =
bpf_program__attach_uprobe(prog[0], false /* not uretprobe */,
pid, "/data/expr/operations" , offset1);
if (!ubpflinks[0])
printf("failed at link0n");
ubpflinks[1] =
bpf_program__attach_uprobe(prog[0], false /* not uretprobe */,
pid, "/data/expr/operations" , offset2);
if (!ubpflinks[1])
printf("failed at link1n");
// bpflinks[0] = bpf_program__attach(prog[0]); // do we need to attach program, already probes attached
getchar();
cleanup:
bpf_link__destroy(ubpflinks[0]);
bpf_link__destroy(ubpflinks[1]);
return -err;
}