On Tue, Dec 9, 2025 at 8:14 PM Donglin Peng <[email protected]> wrote: > > From: pengdonglin <[email protected]> > > The existing documentation for funcgraph-retval is outdated and partially > incorrect, as it describes limitations that have now been resolved. > > Recent changes (e.g., using BTF to obtain function return types) have > addressed key issues: > 1. Return values are now printed only for non-void functions. > 2. Values are trimmed to the correct width of the return type, avoiding > garbage data from high bits. > > Cc: Steven Rostedt (Google) <[email protected]> > Cc: Masami Hiramatsu <[email protected]> > Cc: Xiaoqin Zhang <[email protected]> > Signed-off-by: pengdonglin <[email protected]> > --- > Documentation/trace/ftrace.rst | 78 ++++++++++++++++++++-------------- > 1 file changed, 45 insertions(+), 33 deletions(-) > > diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst > index d1f313a5f4ad..03c8c433c803 100644 > --- a/Documentation/trace/ftrace.rst > +++ b/Documentation/trace/ftrace.rst > @@ -1454,6 +1454,10 @@ Options for function_graph tracer: > printed in hexadecimal format. By default, this option > is off. > > + funcgraph-retaddr > + When set, the return address will always be printed. > + By default, this option is off. > + > sleep-time > When running function graph tracer, to include > the time a task schedules out in its function. > @@ -2800,7 +2804,7 @@ It is default disabled. > 0) 2.861 us | } /* putname() */ > > The return value of each traced function can be displayed after > -an equal sign "=". When encountering system call failures, it > +an equal sign "ret =". When encountering system call failures, it > can be very helpful to quickly locate the function that first > returns an error code. > > @@ -2810,16 +2814,16 @@ returns an error code. > Example with funcgraph-retval:: > > 1) | cgroup_migrate() { > - 1) 0.651 us | cgroup_migrate_add_task(); /* = > 0xffff93fcfd346c00 */ > + 1) 0.651 us | cgroup_migrate_add_task(); /* > ret=0xffff93fcfd346c00 */ > 1) | cgroup_migrate_execute() { > 1) | cpu_cgroup_can_attach() { > 1) | cgroup_taskset_first() { > - 1) 0.732 us | cgroup_taskset_next(); /* = > 0xffff93fc8fb20000 */ > - 1) 1.232 us | } /* cgroup_taskset_first = > 0xffff93fc8fb20000 */ > - 1) 0.380 us | sched_rt_can_attach(); /* = 0x0 */ > - 1) 2.335 us | } /* cpu_cgroup_can_attach = -22 */ > - 1) 4.369 us | } /* cgroup_migrate_execute = -22 */ > - 1) 7.143 us | } /* cgroup_migrate = -22 */ > + 1) 0.732 us | cgroup_taskset_next(); /* > ret=0xffff93fc8fb20000 */ > + 1) 1.232 us | } /* cgroup_taskset_first > ret=0xffff93fc8fb20000 */ > + 1) 0.380 us | sched_rt_can_attach(); /* ret=0x0 */ > + 1) 2.335 us | } /* cpu_cgroup_can_attach ret=-22 */ > + 1) 4.369 us | } /* cgroup_migrate_execute ret=-22 */ > + 1) 7.143 us | } /* cgroup_migrate ret=-22 */ > > The above example shows that the function cpu_cgroup_can_attach > returned the error code -22 firstly, then we can read the code > @@ -2836,37 +2840,41 @@ printed in hexadecimal format. > Example with funcgraph-retval-hex:: > > 1) | cgroup_migrate() { > - 1) 0.651 us | cgroup_migrate_add_task(); /* = > 0xffff93fcfd346c00 */ > + 1) 0.651 us | cgroup_migrate_add_task(); /* > ret=0xffff93fcfd346c00 */ > 1) | cgroup_migrate_execute() { > 1) | cpu_cgroup_can_attach() { > 1) | cgroup_taskset_first() { > - 1) 0.732 us | cgroup_taskset_next(); /* = > 0xffff93fc8fb20000 */ > - 1) 1.232 us | } /* cgroup_taskset_first = > 0xffff93fc8fb20000 */ > - 1) 0.380 us | sched_rt_can_attach(); /* = 0x0 */ > - 1) 2.335 us | } /* cpu_cgroup_can_attach = 0xffffffea */ > - 1) 4.369 us | } /* cgroup_migrate_execute = 0xffffffea */ > + 1) 0.732 us | cgroup_taskset_next(); /* > ret=0xffff93fc8fb20000 */ > + 1) 1.232 us | } /* cgroup_taskset_first > ret=0xffff93fc8fb20000 */ > + 1) 0.380 us | sched_rt_can_attach(); /* ret=0x0 */ > + 1) 2.335 us | } /* cpu_cgroup_can_attach ret=0xffffffea */ > + 1) 4.369 us | } /* cgroup_migrate_execute ret=0xffffffea */ > 1) 7.143 us | } /* cgroup_migrate = 0xffffffea */
My bad for forgetting to update the above line and will fix it in the next version. > > -At present, there are some limitations when using the funcgraph-retval > -option, and these limitations will be eliminated in the future: > +Note that there are some limitations when using the funcgraph-retval > +option: > + > +- If CONFIG_DEBUG_INFO_BTF is disabled (n), a return value is printed even > for > + functions with a void return type. When CONFIG_DEBUG_INFO_BTF is enabled > (y), > + the return value is printed only for non-void functions. > > -- Even if the function return type is void, a return value will still > - be printed, and you can just ignore it. > +- If a return value occupies multiple registers, only the value in the first > + register is recorded and printed. For example, on the x86 architecture, a > + 64-bit return value is stored across eax (lower 32 bits) and edx (upper 32 > bits), > + but only the contents of eax are captured. If CONFIG_DEBUG_INFO_BTF is > enabled, > + the suffix "(trunc)" is appended to the printed value to indicate that the > + output may be truncated because high-order register contents are omitted. > > -- Even if return values are stored in multiple registers, only the > - value contained in the first register will be recorded and printed. > - To illustrate, in the x86 architecture, eax and edx are used to store > - a 64-bit return value, with the lower 32 bits saved in eax and the > - upper 32 bits saved in edx. However, only the value stored in eax > - will be recorded and printed. > +- Under certain procedure-call standards (e.g., arm64's AAPCS64), when the > return > + type is smaller than a general-purpose register (GPR), the caller is > responsible > + for narrowing the value; the upper bits of the register may contain > undefined data. > + For instance, when a u8 is returned in 64-bit GPR, bits [63:8] can hold > arbitrary > + values, especially when larger types are truncated (explicitly or > implicitly). It > + is therefore advisable to inspect the code in such cases. If > CONFIG_DEBUG_INFO_BTF > + is enabled (y), the return value is automatically trimmed to the width of > the return > + type. > > -- In certain procedure call standards, such as arm64's AAPCS64, when a > - type is smaller than a GPR, it is the responsibility of the consumer > - to perform the narrowing, and the upper bits may contain UNKNOWN values. > - Therefore, it is advisable to check the code for such cases. For instance, > - when using a u8 in a 64-bit GPR, bits [63:8] may contain arbitrary values, > - especially when larger types are truncated, whether explicitly or > implicitly. > - Here are some specific cases to illustrate this point: > + The following examples illustrate the behavior: > > **Case One**: > > @@ -2885,7 +2893,9 @@ option, and these limitations will be eliminated in the > future: > RET > > If you pass 0x123456789abcdef to this function and want to narrow it, > - it may be recorded as 0x123456789abcdef instead of 0xef. > + it may be recorded as 0x123456789abcdef instead of 0xef. When > + CONFIG_DEBUG_INFO_BTF is enabled, the value will be correctly truncated > + to 0xef based on the size constraints of the u8 type. > > **Case Two**: > > @@ -2910,7 +2920,9 @@ option, and these limitations will be eliminated in the > future: > RET > > When passing 0x2_0000_0000 to it, the return value may be recorded as > - 0x2_0000_0000 instead of 0. > + 0x2_0000_0000 instead of 0. When CONFIG_DEBUG_INFO_BTF is enabled, the > + value will be correctly truncated to 0 based on the size constraints of > + the int type. > > You can put some comments on specific functions by using > trace_printk() For example, if you want to put a comment inside > -- > 2.34.1 >
