btf_loader: Add support for BTF_KIND_FUNC
...
Some changes to the fprintf routines were needed, as BTF has as the
function type just a BTF_KIND_FUNC_PROTO, while DWARF has as the type
for a function its return value type. With a function->btf flag this was
overcome and all the other goodies in pfunct are present, for instance:
$ pahole -JV examples/tcp.o | grep -w FUNC | head
[4068] FUNC tcp_init type_id=4067
[4070] FUNC tcp_abort type_id=4069
[4072] FUNC tcp_done type_id=4071
[4074] FUNC tcp_md5_hash_key type_id=4073
[4076] FUNC tcp_md5_hash_skb_data type_id=4075
[4078] FUNC tcp_get_md5sig_pool type_id=4077
[4080] FUNC tcp_alloc_md5sig_pool type_id=4079
[4082] FUNC compat_tcp_getsockopt type_id=4081
[4084] FUNC tcp_getsockopt type_id=4083
[4086] FUNC tcp_get_timestamping_opt_stats type_id=4085
$
$ pfunct -F btf examples/tcp.o | head
memset
memcpy
tcp_enter_memory_pressure
tcp_leave_memory_pressure
tcp_init_sock
tcp_init_transfer
tcp_poll
tcp_ioctl
tcp_splice_read
sk_stream_alloc_skb
$
$ pfunct --prototype -F btf examples/tcp.o | head
void * memset(void * p, int c, __kernel_size_t size);
void * memcpy(void * p, const void * q, __kernel_size_t size);
void tcp_enter_memory_pressure(struct sock * sk);
void tcp_leave_memory_pressure(struct sock * sk);
void tcp_init_sock(struct sock * sk);
void tcp_init_transfer(struct sock * sk, int bpf_op);
__poll_t tcp_poll(struct file * file, struct socket * sock, poll_table * wait);
int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg);
ssize_t tcp_splice_read(struct socket * sock, loff_t * ppos, struct pipe_inode_info * pipe, size_t len, unsigned int flags);
struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule);
$
Now to ask just for the 'struct sock' 'methods', i.e. functions that
have as one of its arguments a pointer to the given 'class' name:
$ pfunct --class sock -F btf examples/tcp.o | head
tcp_abort
tcp_done
compat_tcp_getsockopt
tcp_getsockopt
tcp_get_info
compat_tcp_setsockopt
tcp_setsockopt
tcp_disconnect
tcp_write_queue_purge
tcp_close
$
Then ask for the prototypes, which requires -V, should have that fixed:
$ pfunct -V --prototypes --class sock -F btf examples/tcp.o | head
int tcp_abort(struct sock * sk, int err);
void tcp_done(struct sock * sk);
int compat_tcp_getsockopt(struct sock * sk, int level, int optname, char * optval, int * optlen);
int tcp_getsockopt(struct sock * sk, int level, int optname, char * optval, int * optlen);
void tcp_get_info(struct sock * sk, struct tcp_info * info);
int compat_tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen);
int tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen);
int tcp_disconnect(struct sock * sk, int flags);
void tcp_write_queue_purge(struct sock * sk);
void tcp_close(struct sock * sk, long int timeout);
$
Don't like prototypes with parm names, got you covered:
$ pfunct --no_parm_names -V --prototypes --class sock -F btf examples/tcp.o | head
int tcp_abort(struct sock *, int);
void tcp_done(struct sock *);
int compat_tcp_getsockopt(struct sock *, int, int, char *, int *);
int tcp_getsockopt(struct sock *, int, int, char *, int *);
void tcp_get_info(struct sock *, struct tcp_info *);
int compat_tcp_setsockopt(struct sock *, int, int, char *, unsigned int);
int tcp_setsockopt(struct sock *, int, int, char *, unsigned int);
int tcp_disconnect(struct sock *, int);
void tcp_write_queue_purge(struct sock *);
void tcp_close(struct sock *, long int);
$
Don't like long options and want just one function?
$ pfunct -f tcp_setsockopt -F btf examples/tcp.o
int tcp_setsockopt(struct sock * sk, int level, int optname, char * optval, unsigned int optlen);
$
Want to generate compileable code for all of those functions, full with
the necessary types, etc?
$ pfunct -F btf --compile examples/tcp.o > a.c
$ gcc -c -o a.o a.c
$ pfunct -F dwarf --prototypes --class sock a.o | head
pfunct: a.o: No debugging information found
$ gcc -g -c -o a.o a.c
$ pfunct -V -F dwarf --prototypes --class sock a.o | head
void tcp_enter_memory_pressure(struct sock * sk);
void tcp_leave_memory_pressure(struct sock * sk);
void tcp_init_sock(struct sock * sk);
void tcp_init_transfer(struct sock * sk, int bpf_op);
int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg);
struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule);
ssize_t do_tcp_sendpages(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendpage_locked(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendpage(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendmsg_locked(struct sock * sk, struct msghdr * msg, size_t size);
$
Now lets go full circle and encode BTF for this a.o generated from
source code generated from the original BTF info in that examples/tcp.o
file:
$ pahole -JV a.o | tail
[465] FUNC_PROTO (anon) return=35 args=(392 hp, 393 skb, 5 header_len)
[466] FUNC tcp_md5_hash_skb_data type_id=465
[467] FUNC_PROTO (anon) return=35 args=(392 hp, 394 key)
[468] FUNC tcp_md5_hash_key type_id=467
[469] FUNC_PROTO (anon) return=0 args=(49 sk)
[470] FUNC tcp_done type_id=469
[471] FUNC_PROTO (anon) return=35 args=(49 sk, 35 err)
[472] FUNC tcp_abort type_id=471
[473] FUNC_PROTO (anon) return=0 args=(void)
[474] FUNC tcp_init type_id=473
$
$ pfunct -F btf -V --prototypes --class=sock a.o | head
void tcp_enter_memory_pressure(struct sock * sk);
void tcp_leave_memory_pressure(struct sock * sk);
void tcp_init_sock(struct sock * sk);
void tcp_init_transfer(struct sock * sk, int bpf_op);
int tcp_ioctl(struct sock * sk, int cmd, long unsigned int arg);
struct sk_buff * sk_stream_alloc_skb(struct sock * sk, int size, gfp_t gfp, bool force_schedule);
ssize_t do_tcp_sendpages(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendpage_locked(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendpage(struct sock * sk, struct page * page, int offset, size_t size, int flags);
int tcp_sendmsg_locked(struct sock * sk, struct msghdr * msg, size_t size);
$
Curious about the code generated by 'pfunct -F btf --compile examples/tcp.o?
http://vger.kernel.org/~acme/pahole/pfunct-F-BTF--compile-examples-tcp.o.txt
Cc: Alexei Starovoitov <ast@fb.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: Andrii Nakryiko <andriin@fb.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Yonghong Song <yhs@fb.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>