Add ksnoop.8 describing options for tracing function entry/return with full argument/return value display. Include example use cases with output to demonstrate functionality. Signed-off-by: Alan Maguire <alan.maguire@xxxxxxxxxx> --- tools/bpf/ksnoop/Documentation/Makefile | 58 ++++++++++ tools/bpf/ksnoop/Documentation/ksnoop.rst | 173 ++++++++++++++++++++++++++++++ tools/bpf/ksnoop/Makefile | 17 ++- 3 files changed, 244 insertions(+), 4 deletions(-) create mode 100644 tools/bpf/ksnoop/Documentation/Makefile create mode 100644 tools/bpf/ksnoop/Documentation/ksnoop.rst diff --git a/tools/bpf/ksnoop/Documentation/Makefile b/tools/bpf/ksnoop/Documentation/Makefile new file mode 100644 index 0000000..7c2331b9 --- /dev/null +++ b/tools/bpf/ksnoop/Documentation/Makefile @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: GPL-2.0-only +include ../../../scripts/Makefile.include +include ../../../scripts/utilities.mak + +INSTALL ?= install +RM ?= rm -f +RMDIR ?= rmdir --ignore-fail-on-non-empty + +ifeq ($(V),1) + Q = +else + Q = @ +endif + +prefix ?= /usr/local +mandir ?= $(prefix)/man +man8dir = $(mandir)/man8 + +MAN8_RST = ksnoop.rst + +_DOC_MAN8 = $(patsubst %.rst,%.8,$(MAN8_RST)) +DOC_MAN8 = $(addprefix $(OUTPUT),$(_DOC_MAN8)) + +man: man8 +man8: $(DOC_MAN8) + +RST2MAN_DEP := $(shell command -v rst2man 2>/dev/null) +RST2MAN_OPTS += --verbose + +list_pages = $(sort $(basename $(filter-out $(1),$(MAN8_RST)))) +see_also = $(subst " ",, \ + "\n" \ + "SEE ALSO\n" \ + "========\n" \ + "\t**bpf**\ (2),\n") + +$(OUTPUT)%.8: %.rst +ifndef RST2MAN_DEP + $(error "rst2man not found, but required to generate man pages") +endif + $(QUIET_GEN)( cat $< ; printf "%b" $(call see_also,$<) ) | rst2man $(RST2MAN_OPTS) > $@ + +clean: + $(call QUIET_CLEAN, Documentation) + $(Q)$(RM) $(DOC_MAN8) + +install: man + $(call QUIET_INSTALL, Documentation-man) + $(Q)$(INSTALL) -d -m 755 $(DESTDIR)$(man8dir) + $(Q)$(INSTALL) -m 644 $(DOC_MAN8) $(DESTDIR)$(man8dir) + +uninstall: + $(call QUIET_UNINST, Documentation-man) + $(Q)$(RM) $(addprefix $(DESTDIR)$(man8dir)/,$(_DOC_MAN8)) + $(Q)$(RMDIR) $(DESTDIR)$(man8dir) + +.PHONY: man man8 clean install uninstall +.DEFAULT_GOAL := man diff --git a/tools/bpf/ksnoop/Documentation/ksnoop.rst b/tools/bpf/ksnoop/Documentation/ksnoop.rst new file mode 100644 index 0000000..31161c4 --- /dev/null +++ b/tools/bpf/ksnoop/Documentation/ksnoop.rst @@ -0,0 +1,173 @@ +================ +KSNOOP +================ +------------------------------------------------------------------------------- +tool for tracing kernel function entry/return showing arguments/return values +------------------------------------------------------------------------------- + +:Manual section: 8 + +SYNOPSIS +======== + + **ksnoop** [*OPTIONS*] { *COMMAND* *FUNC* | **help** } + + *OPTIONS* := { { **-V** | **--version** } | { **-h** | **--help** } + | { [**-P** | **--pages**] nr_pages} | { [**-p** | **--pid**] pid} | + [{ **-s** | **--stack** }] | [{ **-d** | **--debug** }] } + + *COMMAND* := { **trace** | **info** } + + *FUNC* := { **name** | **name**\(**arg**\[,**arg\]) } + +DESCRIPTION +=========== + *ksnoop* allows for inspection of arguments and return values + associated with function entry/return. + + **ksnoop info** *FUNC* + Show function description, arguments and return value types. + **ksnoop trace** *FUNC* [*FUNC*] + Trace function entry and return, showing arguments and + return values. A function name can simply be specified, + or a function name along with named arguments, return values. + **return** is used to specify the return value. + + *ksnoop* requires the kernel to provide BTF for itself, and if + tracing of module data is required, module BTF must be present also. + Check /sys/kernel/btf to see if BTF is present. + + **ksnoop** requires *CAP_BPF* and *CAP_TRACING* capabilities. + +OPTIONS +======= + -h, --help + Show help information + -V, --version + Show version. + -d, --debug + Show debug output. + -p, --pid + Filter events by pid. + -P, --pages + Specify number of pages used per-CPU for perf event + collection. Default is 8. + -s, --stack + Specified set of functions are traced if and only + if they are encountered in the order specified. + +EXAMPLES +======== +**# ksnoop info ip_send_skb** :: + + int ip_send_skb(struct net * net, struct sk_buff * skb); + +Show function description. + +**# ksnoop trace ip_send_skb** :: + + TIME CPU PID FUNCTION/ARGS + 78101668506811 1 2813 ip_send_skb( + net = *(0xffffffffb5959840) + (struct net){ + .passive = (refcount_t){ + .refs = (atomic_t){ + .counter = (int)0x2, + }, + }, + .dev_base_seq = (unsigned int)0x18, + .ifindex = (int)0xf, + .list = (struct list_head){ + .next = (struct list_head *)0xffff9895440dc120, + .prev = (struct list_head *)0xffffffffb595a8d0, + }, + ... + + 79561322965250 1 2813 ip_send_skb( + return = + (int)0x0 + ); + +Show entry/return for ip_send_skb() with arguments, return values. + +**# ksnoop trace "ip_send_skb(skb)"** :: + + + TIME CPU PID FUNCTION/ARGS + 78142420834537 1 2813 ip_send_skb( + skb = *(0xffff989750797c00) + (struct sk_buff){ + (union){ + .sk = (struct sock *)0xffff98966ce19200, + .ip_defrag_offset = (int)0x6ce19200, + }, + (union){ + (struct){ + ._skb_refdst = (long unsigned int)0xffff98981dde2d80, + .destructor = (void (*)(struct sk_buff *))0xffffffffb3e1beb0, + }, + ... + +Show entry argument **skb**. + +**# ksnoop trace "ip_send_skb(return)"** :: + + TIME CPU PID FUNCTION/ARGS + 78178228354796 1 2813 ip_send_skb( + return = + (int)0x0 + ); + +Show return value from ip_send_skb(). + +**# ksnoop trace "ip_send_skb(skb->sk)"** :: + + TIME CPU PID FUNCTION/ARGS + 78207649138829 2 2813 ip_send_skb( + skb->sk = *(0xffff98966ce19200) + (struct sock){ + .__sk_common = (struct sock_common){ + (union){ + .skc_addrpair = (__addrpair)0x1701a8c017d38f8d, + (struct){ + .skc_daddr = (__be32)0x17d38f8d, + .skc_rcv_saddr = (__be32)0x1701a8c0, + }, + }, + ... + +Trace meber information associated with argument. Only one level of +membership is supported. + +**# ksnoop -p 2813 "ip_rcv(dev)"** :: + + TIME CPU PID FUNCTION/ARGS + 78254803164920 1 2813 ip_rcv( + dev = *(0xffff9895414cb000) + (struct net_device){ + .name = (char[16])[ + 'l', + 'o', + ], + .name_node = (struct netdev_name_node *)0xffff989541515ec0, + .state = (long unsigned int)0x3, + ... + +Trace **dev** argument of **ip_rcv()**. Specify process id 2813 for events +for that process only. + +**# ksnoop -s tcp_sendmsg __tcp_transmit_skb ip_output** :: + + TIME CPU PID FUNCTION/ARGS + 71827770952903 1 4777 __tcp_transmit_skb( + sk = *(0xffff9852460a2300) + (struct sock){ + .__sk_common = (struct sock_common){ + (union){ + .skc_addrpair = (__addrpair)0x61b2af0a35cbfe0a, + +Trace entry/return of tcp_sendmsg, __tcp_transmit_skb and ip_output when +tcp_sendmsg leads to a call to __tcp_transmit_skb and that in turn +leads to a call to ip_output; i.e. with a call graph matching the order +specified. The order does not have to be direct calls, i.e. function A +can call another function that calls function B. diff --git a/tools/bpf/ksnoop/Makefile b/tools/bpf/ksnoop/Makefile index 0a1420e..149e4be 100644 --- a/tools/bpf/ksnoop/Makefile +++ b/tools/bpf/ksnoop/Makefile @@ -42,12 +42,12 @@ endif .DELETE_ON_ERROR: -.PHONY: all clean ksnoop +.PHONY: all clean ksnoop doc doc-clean doc-install all: ksnoop -ksnoop: $(OUTPUT)/ksnoop +ksnoop: $(OUTPUT)/ksnoop doc -clean: +clean: doc-clean $(call QUIET_CLEAN, ksnoop) $(Q)$(RM) -r $(BPFOBJ_OUTPUT) $(BPFTOOL_OUTPUT) $(Q)$(RM) $(OUTPUT)*.o $(OUTPUT)*.d @@ -55,11 +55,20 @@ clean: $(Q)$(RM) $(OUTPUT)ksnoop $(Q)$(RM) -r .output -install: ksnoop +install: ksnoop doc-install $(call QUIET_INSTALL, ksnoop) $(Q)$(INSTALL) -m 0755 -d $(DESTDIR)$(prefix)/sbin $(Q)$(INSTALL) $(OUTPUT)/ksnoop $(DESTDIR)$(prefix)/sbin/ksnoop +doc: + $(call descend,Documentation) + +doc-clean: + $(call descend,Documentation,clean) + +doc-install: + $(call descend,Documentation,install) + $(OUTPUT)/ksnoop: $(OUTPUT)/ksnoop.o $(BPFOBJ) $(QUIET_LINK)$(CC) $(CFLAGS) $^ -lelf -lz -o $@ -- 1.8.3.1