Trace user-space function args

Is that possible to trace args of any user-space function by bpftrace?
Here I find a post Attach bpftrace probe to C++ function, which doesn’t work for me when i try on my host with command

sudo ./bpftrace  -e 'uprobe:/home/miaogen.123/tmp/main:_ZN6BigApp10methodNameEi { printf("1"); }' 

just nothing happened when i run main in another terminal.
Append ouput of additional -d option

AST
-------------------
Program
 uprobe:/home/miaogen.123/tmp/main:_ZN6BigApp10methodNameEv
  call: printf
   string: 1


AST after semantic analysis
-------------------
Program
 uprobe:/home/miaogen.123/tmp/main:_ZN6BigApp10methodNameEv
  call: printf :: type[none]
   string: 1 :: type[string[64]]

; ModuleID = 'bpftrace'
source_filename = "bpftrace"
target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128"
target triple = "bpf-pc-linux"

%printf_t = type { i64 }

; Function Attrs: nounwind
declare i64 @llvm.bpf.pseudo(i64, i64) #0

define i64 @"uprobe:/home/miaogen.123/tmp/main:_ZN6BigApp10methodNameEv"(i8*) local_unnamed_addr section "s_uprobe:/home/miaogen.123/tmp/main:_ZN6BigApp10methodNameEv_1" {
entry:
  %printf_args = alloca %printf_t, align 8
  %1 = bitcast %printf_t* %printf_args to i8*
  call void @llvm.lifetime.start.p0i8(i64 -1, i8* nonnull %1)
  %2 = getelementptr inbounds %printf_t, %printf_t* %printf_args, i64 0, i32 0
  store i64 0, i64* %2, align 8
  %pseudo = tail call i64 @llvm.bpf.pseudo(i64 1, i64 1)
  %get_cpu_id = tail call i64 inttoptr (i64 8 to i64 ()*)()
  %perf_event_output = call i64 inttoptr (i64 25 to i64 (i8*, i64, i64, %printf_t*, i64)*)(i8* %0, i64 %pseudo, i64 %get_cpu_id, %printf_t* nonnull %printf_args, i64 8)
  call void @llvm.lifetime.end.p0i8(i64 -1, i8* nonnull %1)
  ret i64 0
}

; Function Attrs: argmemonly nounwind
declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1

; Function Attrs: argmemonly nounwind
declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1

attributes #0 = { nounwind }
attributes #1 = { argmemonly nounwind }

Can you try doing printf("1\n")? Note the \n. bpftrace line buffers output by default.

1 Like

It works. funny and annoying…

And the first question:「Is that possible to trace args of any user-space function by bpftrace?」
it is hard to trace?

I found some fragments related to this:
From chapter 5 of BPF Performance Tools, written by Brendan Greg and discussion in the github, i get that you can simply cast one type to the type you need to get the value. But what if the args is an complicated class which is composed of many other classes(for instance, std::string), is there an example?
BPF-user-args

To access arguments, we need to know its data structure. I don’t know how to do it for C++ programs in general but as for std::string, apparently the beginning of the data is a pointer of data (though probably it’s implementation-specific). Therefore, for example, if the function is

void foo(std::string str) { ... }

then, its string data can be read by

bpftrace -e 'u:./a.out:foo { printf("%s\n", str(*(uint64*)arg0)); }'
1 Like

To expand on what @mmisono said, you can declare a struct ( https://github.com/iovisor/bpftrace/blob/master/docs/reference_guide.md#5-struct-struct-declaration ) and cast arg* to your struct. You may not be able to do some C++ specific things but everything in C should work.

1 Like