KSNOOP(8)
๐ KSNOOP(8) ๐ ksnoop: the kernel function snoop ๐ฆ
NAME โจ
KSNOOP is a tool for tracing kernel function entry and return. It shows the arguments and return values, bestie ๐
๐ 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 ๐
okay so ksnoop lets you inspect the arguments and return values that go along with function entry and return. it's giving detective energy ๐ต๏ธโโ๏ธโจ
๐ธ Commands ๐ธ
ksnoop info FUNCโ show the function description, its arguments, and the return value types. Very informative, very useful ๐งksnoop trace FUNC [FUNC]โ trace function entry and return, and show the arguments and return values. You can just give a function name, or a function name along with named arguments and return values.returnis the keyword you use to grab the return value ๐ฆ
๐ซถ Requirements ๐ซถ
ksnoop needs the kernel to provide BTF for itself. If you want to trace module data, module BTF has to be there too. Check /sys/kernel/btf to see if BTF is present ๐
ksnoop also needs the CAP_BPF and CAP_TRACING capabilities. no cap, you need these or it won't work ๐
๐ OPTIONS ๐
-h,--helpโ shows the help info ๐โโ๏ธ-V,--versionโ shows the version ๐-d,--debugโ shows debug output, for when you want to see behind the curtain ๐-p,--pidโ filters events by pid, so you only see the process you care about ๐ฏ-P,--pagesโ specifies the number of pages used per-CPU for perf event collection, as nr_pages. The default is8. โจ-s,--stackโ the set of functions you name gets traced if and only if they're hit in the order you listed them. the main character order ๐
๐ฆ EXAMPLES ๐ฆ
๐ง Show a function's description
# ksnoop info ip_send_skb
int ip_send_skb(struct net * net, struct sk_buff * skb);
Shows the function description for ip_send_skb. ๐
๐ Trace entry and return
# 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
);
Shows entry and return for ip_send_skb(), with the arguments and return values. the whole vibe ๐ธ
๐ซง Trace one argument
# 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,
},
...
Shows the entry argument skb. just the one you wanted ๐
๐ฎ Trace only the return value
# ksnoop trace "ip_send_skb(return)"
TIME CPU PID FUNCTION/ARGS
78178228354796 1 2813 ip_send_skb(
return =
(int)0x0
);
Shows the return value from ip_send_skb(). โจ
๐ฉท Trace a member of an argument
# 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,
},
},
...
Traces the member information tied to an argument. heads up, only one level of membership is supported, so no digging three layers deep ๐
๐ Filter by pid and trace an argument
# 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,
...
Traces the dev argument of ip_rcv(). Passing -p 2813 means you only get events from process id 2813. focused ๐ฏ
๐ Trace functions in call order
# 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,
Traces entry and return of tcp_sendmsg, __tcp_transmit_skb and ip_output, but only when tcp_sendmsg leads to a call to __tcp_transmit_skb, and that in turn leads to a call to ip_output. so the call graph has to match the order you gave. The order doesn't have to be direct calls, either: function A can call some other function that then calls function B. the chain just has to exist ๐
๐ท Filter with a condition
# ksnoop "ip_send_skb(skb->len > 100, skb)"
TIME CPU PID FUNCTION/ARGS
39267395709745 1 2955 ip_send_skb(
skb->len =
(unsigned int)0x89,
skb = *(0xffff89c8be81e500)
(struct sk_buff){
(union){
.sk = (struct sock *)0xffff89c6c59e5580,
.ip_defrag_offset = (int)0xc59e5580,
},
Traces ip_send_skb() for skbs where len is greater than 100. ๐ง
๐ SEE ALSO ๐
bpf(2)๐
Thanks for hanging with me through the whole KSNOOP(8) page, bestie ๐ซถ๐ Source and version details are all tucked in the footer, and that's a wrap! ๐ โจ
๐ฆ where this page comes from
- alpine 3.24: bcc-doc 0.36.1-r1 ยท Apache-2.0
- nixpkgs unstable: bcc 0.37.0
- opensuse-leap 16.0: bcc-tools 0.35.0-160000.2.2 ยท Apache-2.0
- opensuse-leap 16.0: bcc-tools 0.35.0-160000.2.2 ยท Apache-2.0
- opensuse-leap 16.0: bcc-tools 0.35.0-160000.2.2 ยท Apache-2.0
- opensuse-leap 16.0: bcc-tools 0.35.0-160000.2.2 ยท Apache-2.0
- ๐ girlified by anthropic/claude-haiku-5.5 on : a language model's rewrite of the original, under its terms