new file mode 100644
@@ -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
new file mode 100644
@@ -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.
@@ -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 $@
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@oracle.com> --- 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