mirror of
https://github.com/brendangregg/perf-tools.git
synced 2025-11-30 23:16:03 +07:00
380 lines
21 KiB
Plaintext
380 lines
21 KiB
Plaintext
Demonstrations of kprobe, the Linux ftrace version.
|
|
|
|
|
|
This traces the kernel do_sys_open() function, when it is called:
|
|
|
|
# ./kprobe p:do_sys_open
|
|
Tracing kprobe do_sys_open. Ctrl-C to end.
|
|
kprobe-26042 [001] d... 6910441.001452: do_sys_open: (do_sys_open+0x0/0x220)
|
|
kprobe-26042 [001] d... 6910441.001475: do_sys_open: (do_sys_open+0x0/0x220)
|
|
kprobe-26042 [001] d... 6910441.001866: do_sys_open: (do_sys_open+0x0/0x220)
|
|
kprobe-26042 [001] d... 6910441.001966: do_sys_open: (do_sys_open+0x0/0x220)
|
|
supervise-1689 [000] d... 6910441.083302: do_sys_open: (do_sys_open+0x0/0x220)
|
|
supervise-1693 [001] d... 6910441.083530: do_sys_open: (do_sys_open+0x0/0x220)
|
|
supervise-1689 [000] d... 6910441.083759: do_sys_open: (do_sys_open+0x0/0x220)
|
|
supervise-1693 [001] d... 6910441.083877: do_sys_open: (do_sys_open+0x0/0x220)
|
|
[...]
|
|
|
|
The "p:" is for creating a probe. Use "r:" to probe the return of the function:
|
|
|
|
# ./kprobe r:do_sys_open
|
|
Tracing kprobe do_sys_open. Ctrl-C to end.
|
|
kprobe-29475 [001] d... 6910688.229777: do_sys_open: (SyS_open+0x1e/0x20 <- do_sys_open)
|
|
<...>-29476 [001] d... 6910688.231101: do_sys_open: (SyS_open+0x1e/0x20 <- do_sys_open)
|
|
<...>-29476 [001] d... 6910688.231123: do_sys_open: (SyS_open+0x1e/0x20 <- do_sys_open)
|
|
<...>-29476 [001] d... 6910688.231530: do_sys_open: (SyS_open+0x1e/0x20 <- do_sys_open)
|
|
<...>-29476 [001] d... 6910688.231624: do_sys_open: (SyS_open+0x1e/0x20 <- do_sys_open)
|
|
supervise-1685 [001] d... 6910688.328776: do_sys_open: (SyS_open+0x1e/0x20 <- do_sys_open)
|
|
supervise-1689 [000] d... 6910688.328780: do_sys_open: (SyS_open+0x1e/0x20 <- do_sys_open)
|
|
[...]
|
|
|
|
This output includes the function that the traced function is returning to.
|
|
|
|
|
|
The trace output can be a little different between kernel versions. Use -H to
|
|
print the header:
|
|
|
|
# ./kprobe -H p:do_sys_open
|
|
Tracing kprobe do_sys_open. Ctrl-C to end.
|
|
# tracer: nop
|
|
#
|
|
# entries-in-buffer/entries-written: 4/4 #P:2
|
|
#
|
|
# _-----=> irqs-off
|
|
# / _----=> need-resched
|
|
# | / _---=> hardirq/softirq
|
|
# || / _--=> preempt-depth
|
|
# ||| / delay
|
|
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
|
|
# | | | |||| | |
|
|
kprobe-27952 [001] d... 6910580.008086: do_sys_open: (do_sys_open+0x0/0x220)
|
|
kprobe-27952 [001] d... 6910580.008109: do_sys_open: (do_sys_open+0x0/0x220)
|
|
kprobe-27952 [001] d... 6910580.008483: do_sys_open: (do_sys_open+0x0/0x220)
|
|
[...]
|
|
|
|
These columns are explained in the kernel source under Documentation/trace/ftrace.txt.
|
|
|
|
|
|
This traces do_sys_open() returns, using a probe alias "myopen", and showing
|
|
the return value ($retval):
|
|
|
|
# ./kprobe 'r:myopen do_sys_open $retval'
|
|
Tracing kprobe myopen. Ctrl-C to end.
|
|
kprobe-26386 [001] d... 6593278.858754: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x3
|
|
<...>-26387 [001] d... 6593278.860043: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x3
|
|
<...>-26387 [001] d... 6593278.860064: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x3
|
|
<...>-26387 [001] d... 6593278.860433: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x3
|
|
<...>-26387 [001] d... 6593278.860521: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x3
|
|
supervise-1685 [001] d... 6593279.178806: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x9
|
|
supervise-1689 [001] d... 6593279.228756: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x9
|
|
supervise-1689 [001] d... 6593279.229106: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x9
|
|
supervise-1688 [000] d... 6593279.229501: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x9
|
|
supervise-1695 [000] d... 6593279.229944: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x9
|
|
supervise-1685 [001] d... 6593279.230104: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x9
|
|
supervise-1687 [001] d... 6593279.230293: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x9
|
|
supervise-1699 [000] d... 6593279.230381: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x9
|
|
supervise-1692 [000] d... 6593279.230825: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x9
|
|
supervise-1698 [000] d... 6593279.230915: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x9
|
|
supervise-1698 [000] d... 6593279.231277: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x9
|
|
supervise-1690 [000] d... 6593279.231703: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) arg1=0x9
|
|
^C
|
|
Ending tracing...
|
|
|
|
The string specified, 'r:myopen do_sys_open $retval', is a kprobe definition,
|
|
and is the same as those documented in the Linux kernel source under
|
|
Documentation/trace/kprobetrace.txt, which can be written to the
|
|
/sys/kernel/debug/tracing/kprobe_events file.
|
|
|
|
Apart from probe name aliases, you can also provide arbitrary names for
|
|
arguments. Eg, instead of the "arg1" default, calling it "rval":
|
|
|
|
# ./kprobe 'r:myopen do_sys_open rval=$retval'
|
|
Tracing kprobe myopen. Ctrl-C to end.
|
|
kprobe-27454 [001] d... 6593356.250019: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) rval=0x3
|
|
<...>-27455 [001] d... 6593356.251280: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) rval=0x3
|
|
<...>-27455 [001] d... 6593356.251301: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) rval=0x3
|
|
<...>-27455 [001] d... 6593356.251672: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) rval=0x3
|
|
<...>-27455 [001] d... 6593356.251769: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) rval=0x3
|
|
supervise-1689 [000] d... 6593356.859758: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) rval=0x9
|
|
supervise-1689 [000] d... 6593356.860143: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) rval=0x9
|
|
supervise-1696 [000] d... 6593356.862682: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) rval=0x9
|
|
supervise-1685 [001] d... 6593356.862684: myopen: (SyS_open+0x1e/0x20 <- do_sys_open) rval=0x9
|
|
[...]
|
|
|
|
That's a bit better.
|
|
|
|
|
|
Tracing the open() mode:
|
|
|
|
# ./kprobe 'p:myopen do_sys_open mode=%cx:u16'
|
|
Tracing kprobe myopen. Ctrl-C to end.
|
|
kprobe-29572 [001] d... 6593503.353923: myopen: (do_sys_open+0x0/0x220) mode=0x1
|
|
kprobe-29572 [001] d... 6593503.353945: myopen: (do_sys_open+0x0/0x220) mode=0x0
|
|
kprobe-29572 [001] d... 6593503.354307: myopen: (do_sys_open+0x0/0x220) mode=0x5c00
|
|
kprobe-29572 [001] d... 6593503.354401: myopen: (do_sys_open+0x0/0x220) mode=0x0
|
|
supervise-1689 [000] d... 6593503.944125: myopen: (do_sys_open+0x0/0x220) mode=0x1a4
|
|
supervise-1688 [001] d... 6593503.944125: myopen: (do_sys_open+0x0/0x220) mode=0x1a4
|
|
supervise-1688 [001] d... 6593503.944606: myopen: (do_sys_open+0x0/0x220) mode=0x1a4
|
|
supervise-1689 [000] d... 6593503.944606: myopen: (do_sys_open+0x0/0x220) mode=0x1a4
|
|
supervise-1698 [000] d... 6593503.944728: myopen: (do_sys_open+0x0/0x220) mode=0x1a4
|
|
supervise-1698 [000] d... 6593503.945077: myopen: (do_sys_open+0x0/0x220) mode=0x1a4
|
|
[...]
|
|
|
|
Here I guessed that the mode was in register %cx, and cast it as a 16-bit
|
|
unsigned integer (":u16"). Your platform and kernel may be different, and the
|
|
mode may be in a different register. If fiddling with such registers becomes too
|
|
painful or unreliable for you, consider installing kernel debuginfo and using
|
|
the named variables with perf_events "perf probe".
|
|
|
|
|
|
Tracing the open() filename:
|
|
|
|
# ./kprobe 'p:myopen do_sys_open filename=+0(%si):string'
|
|
Tracing kprobe myopen. Ctrl-C to end.
|
|
kprobe-32369 [001] d... 6593706.999728: myopen: (do_sys_open+0x0/0x220) filename="/etc/ld.so.cache"
|
|
kprobe-32369 [001] d... 6593706.999748: myopen: (do_sys_open+0x0/0x220) filename="/lib/x86_64-linux-gnu/libc.so.6"
|
|
kprobe-32369 [001] d... 6593707.000092: myopen: (do_sys_open+0x0/0x220) filename="/usr/lib/locale/locale-archive"
|
|
kprobe-32369 [001] d... 6593707.000176: myopen: (do_sys_open+0x0/0x220) filename="trace_pipe"
|
|
supervise-1699 [000] d... 6593707.254970: myopen: (do_sys_open+0x0/0x220) filename="supervise/status.new"
|
|
supervise-1689 [001] d... 6593707.254970: myopen: (do_sys_open+0x0/0x220) filename="supervise/status.new"
|
|
supervise-1689 [001] d... 6593707.255432: myopen: (do_sys_open+0x0/0x220) filename="supervise/status.new"
|
|
supervise-1699 [000] d... 6593707.255432: myopen: (do_sys_open+0x0/0x220) filename="supervise/status.new"
|
|
supervise-1695 [001] d... 6593707.258805: myopen: (do_sys_open+0x0/0x220) filename="supervise/status.new"
|
|
[...]
|
|
|
|
As mentioned previously, the %si register may be different on your platform.
|
|
In this example, I cast it as a string.
|
|
|
|
|
|
Specifying a duration will buffer in-kernel (reducing overhead), and write at
|
|
the end. Here's tracing for 10 seconds, and writing to the "out" file:
|
|
|
|
# ./kprobe -d 10 'p:myopen do_sys_open filename=+0(%si):string' > out
|
|
|
|
|
|
You can match on a single PID only:
|
|
|
|
# ./kprobe -p 1696 'p:myopen do_sys_open filename=+0(%si):string'
|
|
Tracing kprobe myopen. Ctrl-C to end.
|
|
supervise-1696 [001] d... 6593773.677033: myopen: (do_sys_open+0x0/0x220) filename="supervise/status.new"
|
|
supervise-1696 [001] d... 6593773.677332: myopen: (do_sys_open+0x0/0x220) filename="supervise/status.new"
|
|
supervise-1696 [001] d... 6593774.697144: myopen: (do_sys_open+0x0/0x220) filename="supervise/status.new"
|
|
supervise-1696 [001] d... 6593774.697675: myopen: (do_sys_open+0x0/0x220) filename="supervise/status.new"
|
|
supervise-1696 [001] d... 6593775.717986: myopen: (do_sys_open+0x0/0x220) filename="supervise/status.new"
|
|
supervise-1696 [001] d... 6593775.718499: myopen: (do_sys_open+0x0/0x220) filename="supervise/status.new"
|
|
^C
|
|
Ending tracing...
|
|
|
|
This will only show events when that PID is on-CPU.
|
|
|
|
|
|
The -v option will show you the available variables you can use in custom
|
|
filters:
|
|
|
|
# ./kprobe -v 'p:myopen do_sys_open filename=+0(%si):string'
|
|
name: myopen
|
|
ID: 1443
|
|
format:
|
|
field:unsigned short common_type; offset:0; size:2; signed:0;
|
|
field:unsigned char common_flags; offset:2; size:1; signed:0;
|
|
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
|
|
field:int common_pid; offset:4; size:4; signed:1;
|
|
|
|
field:unsigned long __probe_ip; offset:8; size:8; signed:0;
|
|
field:__data_loc char[] filename; offset:16; size:4; signed:1;
|
|
|
|
print fmt: "(%lx) filename=\"%s\"", REC->__probe_ip, __get_str(filename)
|
|
|
|
|
|
Tracing filenames that end in "stat", by adding a filter:
|
|
|
|
# ./kprobe 'p:myopen do_sys_open filename=+0(%si):string' 'filename ~ "*stat"'
|
|
Tracing kprobe myopen. Ctrl-C to end.
|
|
postgres-1172 [000] d... 6594028.787166: myopen: (do_sys_open+0x0/0x220) filename="pg_stat_tmp/pgstat.stat"
|
|
postgres-1172 [001] d... 6594028.797410: myopen: (do_sys_open+0x0/0x220) filename="pg_stat_tmp/pgstat.stat"
|
|
postgres-1172 [001] d... 6594028.797467: myopen: (do_sys_open+0x0/0x220) filename="pg_stat_tmp/pgstat.stat"
|
|
postgres-4443 [001] d... 6594028.800908: myopen: (do_sys_open+0x0/0x220) filename="pg_stat_tmp/pgstat.stat"
|
|
postgres-4443 [000] d... 6594028.811237: myopen: (do_sys_open+0x0/0x220) filename="pg_stat_tmp/pgstat.stat"
|
|
postgres-4443 [000] d... 6594028.811290: myopen: (do_sys_open+0x0/0x220) filename="pg_stat_tmp/pgstat.stat"
|
|
^C
|
|
Ending tracing...
|
|
|
|
This filtering is done in-kernel context.
|
|
|
|
|
|
As an example of tracing a deeper kernel function, lets trace bio_alloc() and
|
|
entry registers:
|
|
|
|
# ./kprobe 'p:myprobe bio_alloc %ax %bx %cx %dx'
|
|
Tracing kprobe myprobe. Ctrl-C to end.
|
|
supervise-3055 [000] 2172148.728250: myprobe: (bio_alloc+0x0/0x30) arg1=ffff880064acc8d0 arg2=ffff8800e56a7990 arg3=0 arg4=ffff880064acc910
|
|
supervise-3055 [000] 2172148.728527: myprobe: (bio_alloc+0x0/0x30) arg1=ffff880064acf948 arg2=ffff8800e56a7990 arg3=0 arg4=ffff880064acf988
|
|
jbd2/xvda1-8-212 [000] 2172149.749474: myprobe: (bio_alloc+0x0/0x30) arg1=ffffffff arg2=ffff8800ad1f87b8 arg3=ffff8800ba22c06c arg4=8
|
|
jbd2/xvda1-8-212 [000] 2172149.749485: myprobe: (bio_alloc+0x0/0x30) arg1=0 arg2=ffff880089d053a8 arg3=10f16c5bb arg4=0
|
|
jbd2/xvda1-8-212 [000] 2172149.749487: myprobe: (bio_alloc+0x0/0x30) arg1=0 arg2=ffff880089d05958 arg3=5 arg4=0
|
|
jbd2/xvda1-8-212 [000] 2172149.749488: myprobe: (bio_alloc+0x0/0x30) arg1=0 arg2=ffff880089d05b60 arg3=5 arg4=0
|
|
jbd2/xvda1-8-212 [000] 2172149.749489: myprobe: (bio_alloc+0x0/0x30) arg1=0 arg2=ffff880089d05820 arg3=5 arg4=0
|
|
jbd2/xvda1-8-212 [000] 2172149.749489: myprobe: (bio_alloc+0x0/0x30) arg1=0 arg2=ffff880089d055b0 arg3=5 arg4=0
|
|
jbd2/xvda1-8-212 [000] 2172149.749490: myprobe: (bio_alloc+0x0/0x30) arg1=0 arg2=ffff88006ff22ea0 arg3=5 arg4=0
|
|
jbd2/xvda1-8-212 [000] 2172149.749491: myprobe: (bio_alloc+0x0/0x30) arg1=0 arg2=ffff880089d1f000 arg3=5 arg4=0
|
|
jbd2/xvda1-8-212 [000] 2172149.749492: myprobe: (bio_alloc+0x0/0x30) arg1=0 arg2=ffff880089d1f138 arg3=5 arg4=0
|
|
jbd2/xvda1-8-212 [000] 2172149.749493: myprobe: (bio_alloc+0x0/0x30) arg1=0 arg2=ffff88005d267138 arg3=5 arg4=0
|
|
jbd2/xvda1-8-212 [000] 2172149.749494: myprobe: (bio_alloc+0x0/0x30) arg1=0 arg2=ffff88005d267680 arg3=5 arg4=0
|
|
jbd2/xvda1-8-212 [000] 2172149.749495: myprobe: (bio_alloc+0x0/0x30) arg1=0 arg2=ffff88005d2675b0 arg3=5 arg4=0
|
|
jbd2/xvda1-8-212 [000] 2172149.751044: myprobe: (bio_alloc+0x0/0x30) arg1=ffffffff arg2=ffff8800cc241ea0 arg3=445f0300 arg4=ffff8800effba000
|
|
supervise-3055 [000] 2172149.751095: myprobe: (bio_alloc+0x0/0x30) arg1=ffff880064acf948 arg2=ffff8800e56a7990 arg3=0 arg4=ffff880064acf988
|
|
supervise-3055 [000] 2172149.751341: myprobe: (bio_alloc+0x0/0x30) arg1=ffff880064acc8d0 arg2=ffff8800e56a7990 arg3=0 arg4=ffff880064acc910
|
|
supervise-3055 [000] 2172150.772033: myprobe: (bio_alloc+0x0/0x30) arg1=ffff880064acc8d0 arg2=ffff8800e56a7990 arg3=0 arg4=ffff880064acc910
|
|
supervise-3055 [000] 2172150.772305: myprobe: (bio_alloc+0x0/0x30) arg1=ffff880064acf948 arg2=ffff8800e56a7990 arg3=0 arg4=ffff880064acf988
|
|
flush-202:1-409 [000] 2172151.087815: myprobe: (bio_alloc+0x0/0x30) arg1=ffffffff arg2=ffff8800da51d6e8 arg3=16afd arg4=1
|
|
flush-202:1-409 [000] 2172151.087829: myprobe: (bio_alloc+0x0/0x30) arg1=ffffffff arg2=ffff8800e7537f08 arg3=16afd arg4=2
|
|
flush-202:1-409 [000] 2172151.087844: myprobe: (bio_alloc+0x0/0x30) arg1=ffffffff arg2=ffff8800e7519af8 arg3=16afd arg4=3
|
|
flush-202:1-409 [000] 2172151.087846: myprobe: (bio_alloc+0x0/0x30) arg1=ffffffff arg2=ffff8800e7511478 arg3=16afd arg4=4
|
|
flush-202:1-409 [000] 2172151.087849: myprobe: (bio_alloc+0x0/0x30) arg1=ffffffff arg2=ffff8800e75e6a90 arg3=16afd arg4=5
|
|
flush-202:1-409 [000] 2172151.087851: myprobe: (bio_alloc+0x0/0x30) arg1=ffffffff arg2=ffff8800e7512bc8 arg3=16afd arg4=6
|
|
flush-202:1-409 [000] 2172151.087853: myprobe: (bio_alloc+0x0/0x30) arg1=ffffffff arg2=ffff8800eb3bf410 arg3=16afd arg4=7
|
|
^C
|
|
|
|
The output includes who is on-CPU, high resolution timestamps, and the arguments
|
|
we requested (registers %ax to %dx). These registers are platform dependent,
|
|
and are mapped by the compiler to the entry arguments of the function.
|
|
|
|
How are these useful? If you are debugging this kernel function, you'll know. :)
|
|
|
|
|
|
Note that you can add qualifiers, eg, if I knew %ax was a uint32:
|
|
|
|
# ./kprobe 'p:myprobe bio_alloc %ax:u32'
|
|
Tracing kprobe myprobe. Ctrl-C to end.
|
|
supervise-3055 [000] 2172389.734606: myprobe: (bio_alloc+0x0/0x30) arg1=64acf948
|
|
supervise-3055 [000] 2172389.734865: myprobe: (bio_alloc+0x0/0x30) arg1=64acc8d0
|
|
supervise-3055 [000] 2172390.772391: myprobe: (bio_alloc+0x0/0x30) arg1=64acf948
|
|
supervise-3055 [000] 2172390.772676: myprobe: (bio_alloc+0x0/0x30) arg1=64acc8d0
|
|
^C
|
|
Ending tracing...
|
|
|
|
You can give them aliases too, instead of the default arg1..N:
|
|
|
|
# ./kprobe 'p:myprobe bio_alloc ax=%ax'
|
|
Tracing kprobe myprobe. Ctrl-C to end.
|
|
supervise-3055 [000] 2172420.451663: myprobe: (bio_alloc+0x0/0x30) ax=ffff880064acc8d0
|
|
supervise-3055 [000] 2172420.451938: myprobe: (bio_alloc+0x0/0x30) ax=ffff880064acf948
|
|
flush-202:1-409 [000] 2172421.163462: myprobe: (bio_alloc+0x0/0x30) ax=ffff880064acc8d0
|
|
supervise-3055 [000] 2172421.500994: myprobe: (bio_alloc+0x0/0x30) ax=ffff880064acc8d0
|
|
supervise-3055 [000] 2172421.501307: myprobe: (bio_alloc+0x0/0x30) ax=ffff880064acf948
|
|
^C
|
|
Ending tracing...
|
|
|
|
|
|
Now for the return of bio_alloc():
|
|
|
|
# ./kprobe 'r:myprobe bio_alloc $retval'
|
|
Tracing kprobe myprobe. Ctrl-C to end.
|
|
supervise-3055 [000] 2172164.145533: myprobe: (io_submit_init.isra.6+0x74/0x100 <- bio_alloc) arg1=ffff8800e55843c0
|
|
supervise-3055 [000] 2172164.145829: myprobe: (io_submit_init.isra.6+0x74/0x100 <- bio_alloc) arg1=ffff8800e5584840
|
|
jbd2/xvda1-8-212 [000] 2172165.166453: myprobe: (submit_bh+0x76/0x120 <- bio_alloc) arg1=ffff8800e57596c0
|
|
jbd2/xvda1-8-212 [000] 2172165.166493: myprobe: (submit_bh+0x76/0x120 <- bio_alloc) arg1=ffff8800e5759c00
|
|
jbd2/xvda1-8-212 [000] 2172165.166496: myprobe: (submit_bh+0x76/0x120 <- bio_alloc) arg1=ffff8800e5759600
|
|
jbd2/xvda1-8-212 [000] 2172165.166497: myprobe: (submit_bh+0x76/0x120 <- bio_alloc) arg1=ffff8800e5759e40
|
|
jbd2/xvda1-8-212 [000] 2172165.166498: myprobe: (submit_bh+0x76/0x120 <- bio_alloc) arg1=ffff8800e57590c0
|
|
jbd2/xvda1-8-212 [000] 2172165.166500: myprobe: (submit_bh+0x76/0x120 <- bio_alloc) arg1=ffff8800e57599c0
|
|
jbd2/xvda1-8-212 [000] 2172165.166500: myprobe: (submit_bh+0x76/0x120 <- bio_alloc) arg1=ffff8800e5759a80
|
|
jbd2/xvda1-8-212 [000] 2172165.166502: myprobe: (submit_bh+0x76/0x120 <- bio_alloc) arg1=ffff8800e5759f00
|
|
jbd2/xvda1-8-212 [000] 2172165.166503: myprobe: (submit_bh+0x76/0x120 <- bio_alloc) arg1=ffff8800e5759540
|
|
jbd2/xvda1-8-212 [000] 2172165.166504: myprobe: (submit_bh+0x76/0x120 <- bio_alloc) arg1=ffff8800e5759180
|
|
jbd2/xvda1-8-212 [000] 2172165.166504: myprobe: (submit_bh+0x76/0x120 <- bio_alloc) arg1=ffff8800e5759900
|
|
jbd2/xvda1-8-212 [000] 2172165.166505: myprobe: (submit_bh+0x76/0x120 <- bio_alloc) arg1=ffff8800e5759000
|
|
jbd2/xvda1-8-212 [000] 2172165.166506: myprobe: (submit_bh+0x76/0x120 <- bio_alloc) arg1=ffff8800e5759480
|
|
<...>-212 [000] 2172165.176261: myprobe: (submit_bh+0x76/0x120 <- bio_alloc) arg1=ffff8800e5759480
|
|
supervise-3055 [000] 2172165.176317: myprobe: (io_submit_init.isra.6+0x74/0x100 <- bio_alloc) arg1=ffff8800e57596c0
|
|
supervise-3055 [000] 2172165.176586: myprobe: (io_submit_init.isra.6+0x74/0x100 <- bio_alloc) arg1=ffff8800e5759900
|
|
^C
|
|
Ending tracing...
|
|
|
|
Great. This output includes the function we are returning to, in most cases,
|
|
submit_bh().
|
|
|
|
Note that this mode (without a duration) prints events as they happen,
|
|
so the overheads can be high for frequent events. You could try the -d mode,
|
|
which buffers in-kernel.
|
|
|
|
|
|
The -s option will print the kernel stack trace after the event:
|
|
|
|
# ./kprobe -s 'p:mytcp tcp_init_cwnd'
|
|
Tracing kprobe mytcp. Ctrl-C to end.
|
|
sshd-5121 [000] d... 6897275.911301: mytcp: (tcp_init_cwnd+0x0/0x40)
|
|
sshd-5121 [000] d... 6897275.911309: <stack trace>
|
|
=> tcp_write_xmit
|
|
=> __tcp_push_pending_frames
|
|
=> tcp_push
|
|
=> tcp_sendmsg
|
|
=> inet_sendmsg
|
|
=> sock_aio_write
|
|
=> do_sync_write
|
|
=> vfs_write
|
|
=> SyS_write
|
|
=> system_call_fastpath
|
|
sshd-32219 [000] d... 6897275.911467: mytcp: (tcp_init_cwnd+0x0/0x40)
|
|
sshd-32219 [000] d... 6897275.911471: <stack trace>
|
|
=> tcp_write_xmit
|
|
=> __tcp_push_pending_frames
|
|
=> tcp_push
|
|
=> tcp_sendmsg
|
|
=> inet_sendmsg
|
|
=> sock_aio_write
|
|
=> do_sync_write
|
|
=> vfs_write
|
|
=> SyS_write
|
|
=> system_call_fastpath
|
|
sshd-5121 [000] d... 6897277.878794: mytcp: (tcp_init_cwnd+0x0/0x40)
|
|
sshd-5121 [000] d... 6897277.878801: <stack trace>
|
|
=> tcp_write_xmit
|
|
=> __tcp_push_pending_frames
|
|
=> tcp_push
|
|
=> tcp_sendmsg
|
|
=> inet_sendmsg
|
|
=> sock_aio_write
|
|
=> do_sync_write
|
|
=> vfs_write
|
|
=> SyS_write
|
|
=> system_call_fastpath
|
|
|
|
This makes use of the kernel options/stacktrace feature.
|
|
|
|
|
|
Use -h to print the USAGE message:
|
|
|
|
# ./kprobe -h
|
|
USAGE: kprobe [-FhHsv] [-d secs] [-p PID] [-L TID] kprobe_definition [filter]
|
|
-F # force. trace despite warnings.
|
|
-d seconds # trace duration, and use buffers
|
|
-p PID # PID to match on events
|
|
-L TID # thread id to match on events
|
|
-v # view format file (don't trace)
|
|
-H # include column headers
|
|
-s # show kernel stack traces
|
|
-h # this usage message
|
|
|
|
Note that these examples may need modification to match your kernel
|
|
version's function names and platform's register usage.
|
|
eg,
|
|
kprobe p:do_sys_open
|
|
# trace open() entry
|
|
kprobe r:do_sys_open
|
|
# trace open() return
|
|
kprobe 'r:do_sys_open $retval'
|
|
# trace open() return value
|
|
kprobe 'r:myopen do_sys_open $retval'
|
|
# use a custom probe name
|
|
kprobe 'p:myopen do_sys_open mode=%cx:u16'
|
|
# trace open() file mode
|
|
kprobe 'p:myopen do_sys_open filename=+0(%si):string'
|
|
# trace open() with filename
|
|
kprobe -s 'p:myprobe tcp_retransmit_skb'
|
|
# show kernel stacks
|
|
kprobe 'p:do_sys_open file=+0(%si):string' 'file ~ "*stat"'
|
|
# opened files ending in "stat"
|
|
|
|
See the man page and example file for more info.
|