@@ -1359,6 +1359,19 @@ Options for function_graph tracer:
13591359 only a closing curly bracket "}" is displayed for
13601360 the return of a function.
13611361
1362+ funcgraph-retval
1363+ When set, the return value of each traced function
1364+ will be printed after an equal sign "=". By default
1365+ this is off.
1366+
1367+ funcgraph-retval-hex
1368+ When set, the return value will always be printed
1369+ in hexadecimal format. If the option is not set and
1370+ the return value is an error code, it will be printed
1371+ in signed decimal format; otherwise it will also be
1372+ printed in hexadecimal format. By default, this option
1373+ is off.
1374+
13621375 sleep-time
13631376 When running function graph tracer, to include
13641377 the time a task schedules out in its function.
@@ -2704,6 +2717,119 @@ It is default disabled.
27042717 0) 1.757 us | } /* kmem_cache_free() */
27052718 0) 2.861 us | } /* putname() */
27062719
2720+ The return value of each traced function can be displayed after
2721+ an equal sign "=". When encountering system call failures, it
2722+ can be verfy helpful to quickly locate the function that first
2723+ returns an error code.
2724+
2725+ - hide: echo nofuncgraph-retval > trace_options
2726+ - show: echo funcgraph-retval > trace_options
2727+
2728+ Example with funcgraph-retval::
2729+
2730+ 1) | cgroup_migrate() {
2731+ 1) 0.651 us | cgroup_migrate_add_task(); /* = 0xffff93fcfd346c00 */
2732+ 1) | cgroup_migrate_execute() {
2733+ 1) | cpu_cgroup_can_attach() {
2734+ 1) | cgroup_taskset_first() {
2735+ 1) 0.732 us | cgroup_taskset_next(); /* = 0xffff93fc8fb20000 */
2736+ 1) 1.232 us | } /* cgroup_taskset_first = 0xffff93fc8fb20000 */
2737+ 1) 0.380 us | sched_rt_can_attach(); /* = 0x0 */
2738+ 1) 2.335 us | } /* cpu_cgroup_can_attach = -22 */
2739+ 1) 4.369 us | } /* cgroup_migrate_execute = -22 */
2740+ 1) 7.143 us | } /* cgroup_migrate = -22 */
2741+
2742+ The above example shows that the function cpu_cgroup_can_attach
2743+ returned the error code -22 firstly, then we can read the code
2744+ of this function to get the root cause.
2745+
2746+ When the option funcgraph-retval-hex is not set, the return value can
2747+ be displayed in a smart way. Specifically, if it is an error code,
2748+ it will be printed in signed decimal format, otherwise it will
2749+ printed in hexadecimal format.
2750+
2751+ - smart: echo nofuncgraph-retval-hex > trace_options
2752+ - hexadecimal: echo funcgraph-retval-hex > trace_options
2753+
2754+ Example with funcgraph-retval-hex::
2755+
2756+ 1) | cgroup_migrate() {
2757+ 1) 0.651 us | cgroup_migrate_add_task(); /* = 0xffff93fcfd346c00 */
2758+ 1) | cgroup_migrate_execute() {
2759+ 1) | cpu_cgroup_can_attach() {
2760+ 1) | cgroup_taskset_first() {
2761+ 1) 0.732 us | cgroup_taskset_next(); /* = 0xffff93fc8fb20000 */
2762+ 1) 1.232 us | } /* cgroup_taskset_first = 0xffff93fc8fb20000 */
2763+ 1) 0.380 us | sched_rt_can_attach(); /* = 0x0 */
2764+ 1) 2.335 us | } /* cpu_cgroup_can_attach = 0xffffffea */
2765+ 1) 4.369 us | } /* cgroup_migrate_execute = 0xffffffea */
2766+ 1) 7.143 us | } /* cgroup_migrate = 0xffffffea */
2767+
2768+ At present, there are some limitations when using the funcgraph-retval
2769+ option, and these limitations will be eliminated in the future:
2770+
2771+ - Even if the function return type is void, a return value will still
2772+ be printed, and you can just ignore it.
2773+
2774+ - Even if return values are stored in multiple registers, only the
2775+ value contained in the first register will be recorded and printed.
2776+ To illustrate, in the x86 architecture, eax and edx are used to store
2777+ a 64-bit return value, with the lower 32 bits saved in eax and the
2778+ upper 32 bits saved in edx. However, only the value stored in eax
2779+ will be recorded and printed.
2780+
2781+ - In certain procedure call standards, such as arm64's AAPCS64, when a
2782+ type is smaller than a GPR, it is the responsibility of the consumer
2783+ to perform the narrowing, and the upper bits may contain UNKNOWN values.
2784+ Therefore, it is advisable to check the code for such cases. For instance,
2785+ when using a u8 in a 64-bit GPR, bits [63:8] may contain arbitrary values,
2786+ especially when larger types are truncated, whether explicitly or implicitly.
2787+ Here are some specific cases to illustrate this point:
2788+
2789+ **Case One **::
2790+
2791+ The function narrow_to_u8 is defined as follows::
2792+
2793+ u8 narrow_to_u8(u64 val)
2794+ {
2795+ // implicitly truncated
2796+ return val;
2797+ }
2798+
2799+ It may be compiled to::
2800+
2801+ narrow_to_u8:
2802+ < ... ftrace instrumentation ... >
2803+ RET
2804+
2805+ If you pass 0x123456789abcdef to this function and want to narrow it,
2806+ it may be recorded as 0x123456789abcdef instead of 0xef.
2807+
2808+ **Case Two **::
2809+
2810+ The function error_if_not_4g_aligned is defined as follows::
2811+
2812+ int error_if_not_4g_aligned(u64 val)
2813+ {
2814+ if (val & GENMASK(31, 0))
2815+ return -EINVAL;
2816+
2817+ return 0;
2818+ }
2819+
2820+ It could be compiled to::
2821+
2822+ error_if_not_4g_aligned:
2823+ CBNZ w0, .Lnot_aligned
2824+ RET // bits [31:0] are zero, bits
2825+ // [63:32] are UNKNOWN
2826+ .Lnot_aligned:
2827+ MOV x0, #-EINVAL
2828+ RET
2829+
2830+ When passing 0x2_0000_0000 to it, the return value may be recorded as
2831+ 0x2_0000_0000 instead of 0.
2832+
27072833You can put some comments on specific functions by using
27082834trace_printk() For example, if you want to put a comment inside
27092835the __might_sleep() function, you just have to include
0 commit comments