.\" .\" SPDX-License-Identifier: BSD-2-Clause .\" .\" Copyright (c) 2025 Mateusz Piotrowski <0mp@FreeBSD.org> .\" .Dd July 16, 2025 .Dt DTRACE_FBT 4 .Os .Sh NAME .Nm dtrace_fbt .Nd a DTrace provider for dynamic kernel tracing based on function boundaries .Sh SYNOPSIS .Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:entry .Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:return .Sh DESCRIPTION The Function Boundary Tracing .Pq Nm fbt provider instruments the entry and return of almost every kernel function corresponding to an .Xr elf 5 symbol in the kernel and loaded kernel modules. .Pp .Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:entry fires whenever the .Ar function is called. .Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:return fires when the .Ar function returns. .Pp The .Ar module in the probe description is either the name of the loaded kernel module or .Ql kernel for functions compiled into the kernel. .Ss Function Boundary Instrumentation The .Nm fbt will always instrument a function's entry, but its return will be intsrumented so long as it can find a .Ql ret instruction. .Pp In some cases, .Nm fbt cannot instrument a function's entry and/or return. Refer to subsection .Sx Frame Pointer for more details. .Ss Probe Arguments The arguments of the entry probe .Pq Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:entry are the arguments of the traced function call. .Bl -column -offset indent "Entry Probe Argument" "Definition" .It Sy Entry Probe Argument Ta Sy Definition .It Fa args[0] Ta Function's first argument, typed .Pq e.g., Xr malloc 9 Ap s Ft size_t Fa size .It Fa args[1] Ta Function's second argument, typed .Pq e.g., Xr malloc 9 Ap s Ft struct malloc_type Fa *type .It Fa args[2] Ta Function's third argument, typed .Pq e.g., Xr malloc 9 Ap s Ft int Fa flags .It Fa ... Ta ... .El .Pp The arguments of the return probe .Pq Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:return are .Fa args[0] .Po the offset of the firing return instruction within the function; useful to tell apart two different return statements in a single function .Pc and .Fa args[1] .Pq the return value, if any . .Bl -column -offset indent "Return Probe Argument" "Definition" .It Sy Return Probe Argument Ta Sy Definition .It Fa args[0] Ta Offset of the traced return instruction .It Fa args[1] Ta Function's return value .Po e.g., a kernel virtual address if returning from a successful .Xr malloc 9 .Pc .El .Pp Subsection .Sx Example 2 : Getting Details About Probe's Arguments shows how to get probe's argument count and types directly with .Xr dtrace 1 without having to resort to the reading function's source code or documentation. .Sh EXAMPLES .Ss Example 1 : Listing Available FBT Probes The following example shows how to list all the available .Nm fbt probes. .Bd -literal -offset 2n # dtrace -l -P fbt ID PROVIDER MODULE FUNCTION NAME [...] 31868 fbt kernel hammer_time entry 31869 fbt kernel hammer_time return [...] .Ed .Pp Since .Fn hammer_time is a part of the kernel and not a separate loaded module, the .Ar module column displays .Ql kernel . .Ss Example 2 : Getting Details About Probe's Arguments The following example shows how to generate a program stability report of .Xr malloc 9 Ap s entry and return probes. Those reports are useful to view the probe's number of arguments and their types. .Bd -literal -offset 2n # dtrace -l -v -n fbt::malloc:entry [...] Argument Types args[0]: size_t args[1]: struct malloc_type * args[2]: int .Ed .Pp The count and types of .Nm fbt Ns Cm \&::malloc:entry arguments match the function signature of .Xr malloc 9 : .Va args[0] is .Ft size_t , .Va args[1] is .Ft "struct malloc_type *" , and .Va "args[2]" is .Ft int . .Bd -literal -offset 2n # dtrace -l -v -n fbt::malloc:return [...] Argument Types args[0]: int args[1]: void * .Ed .Pp The .Cm return probe reports two arguments and their types: the return instruction offset .Pq the usual Ft int and the function's return value, which in this case is .Ft void * , as .Xr malloc 9 returns a kernel virtual address. .Ss Example 3 : Counting Kernel Slab Memory Allocation by Function .Bd -literal -offset 2n # dtrace -n 'fbt::kmem*:entry { @[probefunc] = count(); }' dtrace: description 'fbt::kmem*:entry ' matched 47 probes ^C kmem_alloc_contig 1 kmem_alloc_contig_domainset 1 kmem_cache_reap_active 1 kmem_alloc_contig_pages 2 kmem_free 2 kmem_std_destructor 19 kmem_std_constructor 26 kmem_cache_free 151 kmem_cache_alloc 181 .Ed .Ss Example 4 : Counting Kernel Slab Memory Allocation by Calling Function .Bd -literal -offset 2n # dtrace -q -n 'fbt::kmem*:entry { @[caller] = count(); } END { printa("%40a %@16d\en", @); }' ^C kernel`contigmalloc+0x33 1 kernel`free+0xd3 1 kernel`kmem_alloc_contig+0x29 1 kernel`kmem_alloc_contig_domainset+0x19a 1 zfs.ko`arc_reap_cb_check+0x16 1 .Ed .Ss Example 5 : Counting Kernel malloc()'s by Calling Function .Bd -literal -offset 2n # dtrace -q -n 'fbt::malloc:entry { @[caller] = count(); } END { printa("%45a %@16d\en", @); }' ^C kernel`devclass_get_devices+0xa8 1 kernel`sys_ioctl+0xb7 1 dtrace.ko`dtrace_ioctl+0x15c1 1 dtrace.ko`dtrace_ioctl+0x972 2 dtrace.ko`dtrace_dof_create+0x35 2 kernel`kern_poll_kfds+0x2f0 4 kernel`kern_poll_kfds+0x28a 19 .Ed .Ss Example 6 : Counting Kernel malloc()'s by Kernel Stack Trace .Bd -literal -offset 2n # dtrace -q -n 'fbt::malloc:entry { @[stack()] = count(); }' ^C dtrace.ko`dtrace_dof_create+0x35 dtrace.ko`dtrace_ioctl+0x827 kernel`devfs_ioctl+0xd1 kernel`VOP_IOCTL_APV+0x2a kernel`vn_ioctl+0xb6 kernel`devfs_ioctl_f+0x1e kernel`kern_ioctl+0x286 kernel`sys_ioctl+0x12f kernel`amd64_syscall+0x169 kernel`0xffffffff81092b0b 2 .Ed .Ss Example 7 : Summarizing vmem_alloc()'s by Arena Name and Size Distribution .Bd -literal -offset 2n # dtrace -q -n 'fbt::vmem_alloc:entry { @[args[0]->vm_name] = quantize(arg1); }' ^C kernel arena dom value ------------- Distribution ------------- count 2048 | 0 4096 |@@@@@@@@@@@@@@@@@@@@@@@@@@@ 4 8192 |@@@@@@@@@@@@@ 2 16384 | 0 .Ed .Ss Example 8 : Measuring Total Time Spent Executing a Function This DTrace script measures the total time spent in .Fn vm_page* kernel functions. The .Fn quantize aggregation organizes the measurements into power-of-two buckets, providing a time distribution in nanoseconds for each function. .Bd -literal -offset 2n fbt::vm_page*:entry { self->start = timestamp; } fbt::vm_page*:return /self->start/ { @[probefunc] = quantize(timestamp - self->start); self->start = 0; } .Ed .Sh SEE ALSO .Xr dtrace 1 , .Xr dtrace_kinst 4 , .Xr tracing 7 .Rs .%A Brendan Gregg .%A Jim Mauro .%B DTrace: Dynamic Tracing in Oracle Solaris, Mac OS X and FreeBSD .%I Prentice Hall .%P pp. 898\(en903 .%D 2011 .%U https://www.brendangregg.com/dtracebook/ .Re .Rs .%B The illumos Dynamic Tracing Guide .%O Chapter fbt Provider .%D 2008 .%U https://illumos.org/books/dtrace/chp-fbt.html#chp-fbt .Re .Sh AUTHORS This manual page was written by .An Mateusz Piotrowski Aq Mt 0mp@FreeBSD.org . .Sh CAVEATS .Ss Stability and Portability .Nm fbt probes are by definition tightly coupled to kernel code; if the code underlying a script changes, the script may fail to run or may produce incorrect results. Scripts written for one version of .Fx might not work on others, and almost certainly will not work on other operating systems. .Pp Individual .Nm fbt probes often do not correspond nicely to logical system events. For example, consider a DTrace script which prints the destination address of every IP packet as the kernel hands them over to the network card driver (NIC). An .Nm fbt Ns -based implementation of such a script is a discouragingly difficult task: it involves instrumenting at least four different functions in different parts of the IPv4 and IPv6 code. At the same time, with the .Xr dtrace_ip 4 provider the script is a simple one-liner: .Dl dtrace -n 'ip:::send {printf("%s", args[2]->ip_daddr);}' .Pp Make sure to review available .Xr dtrace 1 providers first before implementing a custom script with the .Nm fbt provider. If none of the DTrace providers offer the desired probes, consider adding new statically-defined tracing probes .Pq Xr SDT 9 . .Ss Frame Pointer Inline functions are not instrumentable by .Nm fbt as they lack a frame pointer. A developer might explicitly disable inlining by adding the .Ql __noinline attribute to a function definition, but of course this requires a recompilation of the kernel. Building the kernel with .Fl fno-omit-frame-pointer is another way of preserving frame pointers. Note, that sometimes compilers will omit the frame pointer in leaf functions, even when configured with .Fl fno-omit-frame-pointer . .Pp Function returns via a tail call are also not instrumentable by .Nm fbt . As a result, a function might have an entry probe and a mix of instrumented and uninstrumentable returns. .Pp Use .Xr dtrace_kinst 4 to trace arbitrary instructions inside kernel functions and work around some of the limitations of .Nm fbt . .Ss Tracing DTrace The .Nm fbt provider cannot attach to functions inside DTrace provider kernel modules.