* [PATCH v2 0/2] Use BTF to trim return values
@ 2025-12-08 13:19 Donglin Peng
2025-12-08 13:19 ` [PATCH v2 1/2] fgraph: Use BTF to trim and filter " Donglin Peng
2025-12-08 13:19 ` [PATCH v2 2/2] tracing: Update funcgraph-retval documentation Donglin Peng
0 siblings, 2 replies; 6+ messages in thread
From: Donglin Peng @ 2025-12-08 13:19 UTC (permalink / raw)
To: rostedt; +Cc: linux-trace-kernel, linux-kernel, pengdonglin
From: pengdonglin <pengdonglin@xiaomi.com>
This patch series addresses two limitations of the funcgraph-retval feature:
1. Previously, return values were printed even for void functions.
2. For return types narrower than a register, high-bit corruption could
lead to incorrect values.
By leveraging BTF to obtain precise return type information, we now:
1. Suppress output for void functions (eliminating noise)
2. Properly truncate values to match the actual return type width (ensuring
correctness)
These improvements make funcgraph-retval more accurate and useful.
Before:
# perf ftrace -G vfs_read --graph-opts retval
...
1) | _raw_spin_unlock() {
1) 0.074 us | do_raw_spin_unlock(); /* ret=0x1 */
1) 0.072 us | preempt_count_sub(); /* ret=0x0 */
1) 0.373 us | } /* _raw_spin_unlock ret=0x80000000 */
1) | down_read() {
1) 0.070 us | __cond_resched(); /* ret=0x0 */
1) 0.069 us | preempt_count_add(); /* ret=0x0 */
1) 0.071 us | preempt_count_sub(); /* ret=0x0 */
1) 0.612 us | } /* down_read ret=0x80000000 */
1) | down_write() {
1) 0.070 us | __cond_resched(); /* ret=0x0 */
1) 0.071 us | preempt_count_add(); /* ret=0x0 */
1) 0.070 us | preempt_count_sub(); /* ret=0x0 */
1) 0.605 us | } /* down_write ret=0x80000000 */
After:
# perf ftrace -G vfs_read --graph-opts retval
...
0) | _raw_spin_unlock() {
0) 0.075 us | do_raw_spin_unlock();
0) 0.075 us | preempt_count_sub();
0) 0.380 us | } /* _raw_spin_unlock */
0) | down_read() {
0) 0.070 us | __cond_resched(); /* ret=0x0 */
0) 0.073 us | preempt_count_add();
0) 0.072 us | preempt_count_sub();
0) 0.586 us | } /* down_read */
0) | down_write() {
0) 0.070 us | __cond_resched(); /* ret=0x0 */
0) 0.072 us | preempt_count_add();
0) 0.072 us | preempt_count_sub();
0) 0.676 us | } /* down_write */
Changelog:
v2:
- Update the funcgraph-retval documentation
- Revise the cover letter
v1:
- Link: https://lore.kernel.org/all/20251207142742.229924-1-dolinux.peng@gmail.com/
pengdonglin (2):
fgraph: Use BTF to trim and filter return values
tracing: Update funcgraph-retval documentation
Documentation/trace/ftrace.rst | 76 ++++++++++++++++------------
kernel/trace/trace_functions_graph.c | 64 +++++++++++++++++++----
2 files changed, 97 insertions(+), 43 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v2 1/2] fgraph: Use BTF to trim and filter return values 2025-12-08 13:19 [PATCH v2 0/2] Use BTF to trim return values Donglin Peng @ 2025-12-08 13:19 ` Donglin Peng 2025-12-09 0:48 ` Masami Hiramatsu 2025-12-08 13:19 ` [PATCH v2 2/2] tracing: Update funcgraph-retval documentation Donglin Peng 1 sibling, 1 reply; 6+ messages in thread From: Donglin Peng @ 2025-12-08 13:19 UTC (permalink / raw) To: rostedt Cc: linux-trace-kernel, linux-kernel, pengdonglin, Masami Hiramatsu, Xiaoqin Zhang From: pengdonglin <pengdonglin@xiaomi.com> The current funcgraph-retval implementation has two limitations: 1. It prints a return value even when the traced function returns void. 2. When the return type is narrower than a register, the printed value may be incorrect because high bits can contain undefined data. Both issues are addressed by using BTF to obtain the precise return type of each traced function: - Return values are now printed only for functions whose return type is not void. - The value is truncated to the actual width of the return type, ensuring correct representation. These changes make the funcgraph-retval output more accurate and remove noise from void functions. Cc: Steven Rostedt (Google) <rostedt@goodmis.org> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Xiaoqin Zhang <zhangxiaoqin@xiaomi.com> Signed-off-by: pengdonglin <pengdonglin@xiaomi.com> --- kernel/trace/trace_functions_graph.c | 64 +++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 17c75cf2348e..9e63665c81e2 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -15,6 +15,7 @@ #include "trace.h" #include "trace_output.h" +#include "trace_btf.h" /* When set, irq functions might be ignored */ static int ftrace_graph_skip_irqs; @@ -865,6 +866,46 @@ static void print_graph_retaddr(struct trace_seq *s, struct fgraph_retaddr_ent_e #if defined(CONFIG_FUNCTION_GRAPH_RETVAL) || defined(CONFIG_FUNCTION_GRAPH_RETADDR) +static void trim_retval(unsigned long func, unsigned long *retval, bool *print_retval) +{ + const struct btf_type *t; + char name[KSYM_NAME_LEN]; + struct btf *btf; + u32 v, msb; + + if (!IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) + return; + + if (lookup_symbol_name(func, name)) + return; + + t = btf_find_func_proto(name, &btf); + if (IS_ERR_OR_NULL(t)) + return; + + t = btf_type_skip_modifiers(btf, t->type, NULL); + switch (t ? BTF_INFO_KIND(t->info) : BTF_KIND_UNKN) { + case BTF_KIND_UNKN: + *print_retval = false; + break; + case BTF_KIND_ENUM: + case BTF_KIND_ENUM64: + msb = BITS_PER_BYTE * t->size - 1; + *retval &= GENMASK(msb, 0); + break; + case BTF_KIND_INT: + v = *(u32 *)(t + 1); + if (BTF_INT_ENCODING(v) == BTF_INT_BOOL) + msb = 0; + else + msb = BTF_INT_BITS(v) - 1; + *retval &= GENMASK(msb, 0); + break; + default: + break; + } +} + static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entry *entry, struct ftrace_graph_ret *graph_ret, void *func, u32 opt_flags, u32 trace_flags, int args_size) @@ -884,17 +925,20 @@ static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entr print_retaddr = !!(opt_flags & TRACE_GRAPH_PRINT_RETADDR); #endif - if (print_retval && retval && !hex_format) { - /* Check if the return value matches the negative format */ - if (IS_ENABLED(CONFIG_64BIT) && (retval & BIT(31)) && - (((u64)retval) >> 32) == 0) { - err_code = sign_extend64(retval, 31); - } else { - err_code = retval; + if (print_retval) { + trim_retval((unsigned long)func, &retval, &print_retval); + if (print_retval && retval && !hex_format) { + /* Check if the return value matches the negative format */ + if (IS_ENABLED(CONFIG_64BIT) && (retval & BIT(31)) && + (((u64)retval) >> 32) == 0) { + err_code = sign_extend64(retval, 31); + } else { + err_code = retval; + } + + if (!IS_ERR_VALUE(err_code)) + err_code = 0; } - - if (!IS_ERR_VALUE(err_code)) - err_code = 0; } if (entry) { -- 2.34.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/2] fgraph: Use BTF to trim and filter return values 2025-12-08 13:19 ` [PATCH v2 1/2] fgraph: Use BTF to trim and filter " Donglin Peng @ 2025-12-09 0:48 ` Masami Hiramatsu 2025-12-09 1:42 ` Donglin Peng 0 siblings, 1 reply; 6+ messages in thread From: Masami Hiramatsu @ 2025-12-09 0:48 UTC (permalink / raw) To: Donglin Peng Cc: rostedt, linux-trace-kernel, linux-kernel, pengdonglin, Masami Hiramatsu, Xiaoqin Zhang On Mon, 8 Dec 2025 21:19:16 +0800 Donglin Peng <dolinux.peng@gmail.com> wrote: > From: pengdonglin <pengdonglin@xiaomi.com> > > The current funcgraph-retval implementation has two limitations: > > 1. It prints a return value even when the traced function returns void. > 2. When the return type is narrower than a register, the printed value may > be incorrect because high bits can contain undefined data. > > Both issues are addressed by using BTF to obtain the precise return type > of each traced function: > > - Return values are now printed only for functions whose return type is > not void. > - The value is truncated to the actual width of the return type, ensuring > correct representation. > > These changes make the funcgraph-retval output more accurate and remove > noise from void functions. > > Cc: Steven Rostedt (Google) <rostedt@goodmis.org> > Cc: Masami Hiramatsu <mhiramat@kernel.org> > Cc: Xiaoqin Zhang <zhangxiaoqin@xiaomi.com> > Signed-off-by: pengdonglin <pengdonglin@xiaomi.com> > --- > kernel/trace/trace_functions_graph.c | 64 +++++++++++++++++++++++----- > 1 file changed, 54 insertions(+), 10 deletions(-) > > diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c > index 17c75cf2348e..9e63665c81e2 100644 > --- a/kernel/trace/trace_functions_graph.c > +++ b/kernel/trace/trace_functions_graph.c > @@ -15,6 +15,7 @@ > > #include "trace.h" > #include "trace_output.h" > +#include "trace_btf.h" > > /* When set, irq functions might be ignored */ > static int ftrace_graph_skip_irqs; > @@ -865,6 +866,46 @@ static void print_graph_retaddr(struct trace_seq *s, struct fgraph_retaddr_ent_e > > #if defined(CONFIG_FUNCTION_GRAPH_RETVAL) || defined(CONFIG_FUNCTION_GRAPH_RETADDR) > > +static void trim_retval(unsigned long func, unsigned long *retval, bool *print_retval) > +{ > + const struct btf_type *t; > + char name[KSYM_NAME_LEN]; > + struct btf *btf; > + u32 v, msb; > + > + if (!IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) > + return; > + > + if (lookup_symbol_name(func, name)) > + return; > + > + t = btf_find_func_proto(name, &btf); > + if (IS_ERR_OR_NULL(t)) > + return; > + > + t = btf_type_skip_modifiers(btf, t->type, NULL); > + switch (t ? BTF_INFO_KIND(t->info) : BTF_KIND_UNKN) { > + case BTF_KIND_UNKN: > + *print_retval = false; > + break; > + case BTF_KIND_ENUM: > + case BTF_KIND_ENUM64: > + msb = BITS_PER_BYTE * t->size - 1; > + *retval &= GENMASK(msb, 0); > + break; > + case BTF_KIND_INT: > + v = *(u32 *)(t + 1); > + if (BTF_INT_ENCODING(v) == BTF_INT_BOOL) > + msb = 0; > + else > + msb = BTF_INT_BITS(v) - 1; > + *retval &= GENMASK(msb, 0); > + break; > + default: > + break; > + } > +} Hmm, I think we should have another flag which directly tells the print format of retval from BTF. > + > static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entry *entry, > struct ftrace_graph_ret *graph_ret, void *func, > u32 opt_flags, u32 trace_flags, int args_size) > @@ -884,17 +925,20 @@ static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entr > print_retaddr = !!(opt_flags & TRACE_GRAPH_PRINT_RETADDR); > #endif > > - if (print_retval && retval && !hex_format) { > - /* Check if the return value matches the negative format */ > - if (IS_ENABLED(CONFIG_64BIT) && (retval & BIT(31)) && > - (((u64)retval) >> 32) == 0) { > - err_code = sign_extend64(retval, 31); > - } else { > - err_code = retval; The original code just guesses the type (signed/unsigned) from the retval, but we don't need to do that with BTF. Thank you, > + if (print_retval) { > + trim_retval((unsigned long)func, &retval, &print_retval); > + if (print_retval && retval && !hex_format) { > + /* Check if the return value matches the negative format */ > + if (IS_ENABLED(CONFIG_64BIT) && (retval & BIT(31)) && > + (((u64)retval) >> 32) == 0) { > + err_code = sign_extend64(retval, 31); > + } else { > + err_code = retval; > + } > + > + if (!IS_ERR_VALUE(err_code)) > + err_code = 0; > } > - > - if (!IS_ERR_VALUE(err_code)) > - err_code = 0; > } > > if (entry) { > -- > 2.34.1 > -- Masami Hiramatsu (Google) <mhiramat@kernel.org> ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/2] fgraph: Use BTF to trim and filter return values 2025-12-09 0:48 ` Masami Hiramatsu @ 2025-12-09 1:42 ` Donglin Peng 2025-12-09 3:14 ` Donglin Peng 0 siblings, 1 reply; 6+ messages in thread From: Donglin Peng @ 2025-12-09 1:42 UTC (permalink / raw) To: Masami Hiramatsu Cc: rostedt, linux-trace-kernel, linux-kernel, pengdonglin, Xiaoqin Zhang On Tue, Dec 9, 2025 at 8:48 AM Masami Hiramatsu <mhiramat@kernel.org> wrote: > > On Mon, 8 Dec 2025 21:19:16 +0800 > Donglin Peng <dolinux.peng@gmail.com> wrote: > > > From: pengdonglin <pengdonglin@xiaomi.com> > > > > The current funcgraph-retval implementation has two limitations: > > > > 1. It prints a return value even when the traced function returns void. > > 2. When the return type is narrower than a register, the printed value may > > be incorrect because high bits can contain undefined data. > > > > Both issues are addressed by using BTF to obtain the precise return type > > of each traced function: > > > > - Return values are now printed only for functions whose return type is > > not void. > > - The value is truncated to the actual width of the return type, ensuring > > correct representation. > > > > These changes make the funcgraph-retval output more accurate and remove > > noise from void functions. > > > > Cc: Steven Rostedt (Google) <rostedt@goodmis.org> > > Cc: Masami Hiramatsu <mhiramat@kernel.org> > > Cc: Xiaoqin Zhang <zhangxiaoqin@xiaomi.com> > > Signed-off-by: pengdonglin <pengdonglin@xiaomi.com> > > --- > > kernel/trace/trace_functions_graph.c | 64 +++++++++++++++++++++++----- > > 1 file changed, 54 insertions(+), 10 deletions(-) > > > > diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c > > index 17c75cf2348e..9e63665c81e2 100644 > > --- a/kernel/trace/trace_functions_graph.c > > +++ b/kernel/trace/trace_functions_graph.c > > @@ -15,6 +15,7 @@ > > > > #include "trace.h" > > #include "trace_output.h" > > +#include "trace_btf.h" > > > > /* When set, irq functions might be ignored */ > > static int ftrace_graph_skip_irqs; > > @@ -865,6 +866,46 @@ static void print_graph_retaddr(struct trace_seq *s, struct fgraph_retaddr_ent_e > > > > #if defined(CONFIG_FUNCTION_GRAPH_RETVAL) || defined(CONFIG_FUNCTION_GRAPH_RETADDR) > > > > +static void trim_retval(unsigned long func, unsigned long *retval, bool *print_retval) > > +{ > > + const struct btf_type *t; > > + char name[KSYM_NAME_LEN]; > > + struct btf *btf; > > + u32 v, msb; > > + > > + if (!IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) > > + return; > > + > > + if (lookup_symbol_name(func, name)) > > + return; > > + > > + t = btf_find_func_proto(name, &btf); > > + if (IS_ERR_OR_NULL(t)) > > + return; > > + > > + t = btf_type_skip_modifiers(btf, t->type, NULL); > > + switch (t ? BTF_INFO_KIND(t->info) : BTF_KIND_UNKN) { > > + case BTF_KIND_UNKN: > > + *print_retval = false; > > + break; > > + case BTF_KIND_ENUM: > > + case BTF_KIND_ENUM64: > > + msb = BITS_PER_BYTE * t->size - 1; > > + *retval &= GENMASK(msb, 0); > > + break; > > + case BTF_KIND_INT: > > + v = *(u32 *)(t + 1); > > + if (BTF_INT_ENCODING(v) == BTF_INT_BOOL) > > + msb = 0; > > + else > > + msb = BTF_INT_BITS(v) - 1; > > + *retval &= GENMASK(msb, 0); > > + break; > > + default: > > + break; > > + } > > +} > > Hmm, I think we should have another flag which directly tells the print > format of retval from BTF. Thanks, I thought about it and the format flag could have the following values: 1. HEX - hexadecimal (%lx for pointers/unsigned) 2. DEC - decimal (%ld for signed/error_code) 3. BOOL - boolean strings ("true"/"false") WDYT? Thanks, Donglin > > > + > > static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entry *entry, > > struct ftrace_graph_ret *graph_ret, void *func, > > u32 opt_flags, u32 trace_flags, int args_size) > > @@ -884,17 +925,20 @@ static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entr > > print_retaddr = !!(opt_flags & TRACE_GRAPH_PRINT_RETADDR); > > #endif > > > > - if (print_retval && retval && !hex_format) { > > - /* Check if the return value matches the negative format */ > > - if (IS_ENABLED(CONFIG_64BIT) && (retval & BIT(31)) && > > - (((u64)retval) >> 32) == 0) { > > - err_code = sign_extend64(retval, 31); > > - } else { > > - err_code = retval; > > The original code just guesses the type (signed/unsigned) from > the retval, but we don't need to do that with BTF. Thanks. I will fix it in the next version. Thanks, Donglin > > Thank you, > > > + if (print_retval) { > > + trim_retval((unsigned long)func, &retval, &print_retval); > > + if (print_retval && retval && !hex_format) { > > + /* Check if the return value matches the negative format */ > > + if (IS_ENABLED(CONFIG_64BIT) && (retval & BIT(31)) && > > + (((u64)retval) >> 32) == 0) { > > + err_code = sign_extend64(retval, 31); > > + } else { > > + err_code = retval; > > + } > > + > > + if (!IS_ERR_VALUE(err_code)) > > + err_code = 0; > > } > > - > > - if (!IS_ERR_VALUE(err_code)) > > - err_code = 0; > > } > > > > if (entry) { > > -- > > 2.34.1 > > > > > -- > Masami Hiramatsu (Google) <mhiramat@kernel.org> ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/2] fgraph: Use BTF to trim and filter return values 2025-12-09 1:42 ` Donglin Peng @ 2025-12-09 3:14 ` Donglin Peng 0 siblings, 0 replies; 6+ messages in thread From: Donglin Peng @ 2025-12-09 3:14 UTC (permalink / raw) To: Masami Hiramatsu Cc: rostedt, linux-trace-kernel, linux-kernel, pengdonglin, Xiaoqin Zhang On Tue, Dec 9, 2025 at 9:42 AM Donglin Peng <dolinux.peng@gmail.com> wrote: > > On Tue, Dec 9, 2025 at 8:48 AM Masami Hiramatsu <mhiramat@kernel.org> wrote: > > > > On Mon, 8 Dec 2025 21:19:16 +0800 > > Donglin Peng <dolinux.peng@gmail.com> wrote: > > > > > From: pengdonglin <pengdonglin@xiaomi.com> > > > > > > The current funcgraph-retval implementation has two limitations: > > > > > > 1. It prints a return value even when the traced function returns void. > > > 2. When the return type is narrower than a register, the printed value may > > > be incorrect because high bits can contain undefined data. > > > > > > Both issues are addressed by using BTF to obtain the precise return type > > > of each traced function: > > > > > > - Return values are now printed only for functions whose return type is > > > not void. > > > - The value is truncated to the actual width of the return type, ensuring > > > correct representation. > > > > > > These changes make the funcgraph-retval output more accurate and remove > > > noise from void functions. > > > > > > Cc: Steven Rostedt (Google) <rostedt@goodmis.org> > > > Cc: Masami Hiramatsu <mhiramat@kernel.org> > > > Cc: Xiaoqin Zhang <zhangxiaoqin@xiaomi.com> > > > Signed-off-by: pengdonglin <pengdonglin@xiaomi.com> > > > --- > > > kernel/trace/trace_functions_graph.c | 64 +++++++++++++++++++++++----- > > > 1 file changed, 54 insertions(+), 10 deletions(-) > > > > > > diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c > > > index 17c75cf2348e..9e63665c81e2 100644 > > > --- a/kernel/trace/trace_functions_graph.c > > > +++ b/kernel/trace/trace_functions_graph.c > > > @@ -15,6 +15,7 @@ > > > > > > #include "trace.h" > > > #include "trace_output.h" > > > +#include "trace_btf.h" > > > > > > /* When set, irq functions might be ignored */ > > > static int ftrace_graph_skip_irqs; > > > @@ -865,6 +866,46 @@ static void print_graph_retaddr(struct trace_seq *s, struct fgraph_retaddr_ent_e > > > > > > #if defined(CONFIG_FUNCTION_GRAPH_RETVAL) || defined(CONFIG_FUNCTION_GRAPH_RETADDR) > > > > > > +static void trim_retval(unsigned long func, unsigned long *retval, bool *print_retval) > > > +{ > > > + const struct btf_type *t; > > > + char name[KSYM_NAME_LEN]; > > > + struct btf *btf; > > > + u32 v, msb; > > > + > > > + if (!IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) > > > + return; > > > + > > > + if (lookup_symbol_name(func, name)) > > > + return; > > > + > > > + t = btf_find_func_proto(name, &btf); > > > + if (IS_ERR_OR_NULL(t)) > > > + return; > > > + > > > + t = btf_type_skip_modifiers(btf, t->type, NULL); > > > + switch (t ? BTF_INFO_KIND(t->info) : BTF_KIND_UNKN) { > > > + case BTF_KIND_UNKN: > > > + *print_retval = false; > > > + break; > > > + case BTF_KIND_ENUM: > > > + case BTF_KIND_ENUM64: > > > + msb = BITS_PER_BYTE * t->size - 1; > > > + *retval &= GENMASK(msb, 0); > > > + break; > > > + case BTF_KIND_INT: > > > + v = *(u32 *)(t + 1); > > > + if (BTF_INT_ENCODING(v) == BTF_INT_BOOL) > > > + msb = 0; > > > + else > > > + msb = BTF_INT_BITS(v) - 1; > > > + *retval &= GENMASK(msb, 0); > > > + break; > > > + default: > > > + break; > > > + } > > > +} > > > > Hmm, I think we should have another flag which directly tells the print > > format of retval from BTF. > > Thanks, I thought about it and the format flag could have the following values: > > 1. HEX - hexadecimal (%lx for pointers/unsigned) > 2. DEC - decimal (%ld for signed/error_code) > 3. BOOL - boolean strings ("true"/"false") > > WDYT? > > Thanks, > Donglin > > > > > + > > > static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entry *entry, > > > struct ftrace_graph_ret *graph_ret, void *func, > > > u32 opt_flags, u32 trace_flags, int args_size) > > > @@ -884,17 +925,20 @@ static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entr > > > print_retaddr = !!(opt_flags & TRACE_GRAPH_PRINT_RETADDR); > > > #endif > > > > > > - if (print_retval && retval && !hex_format) { > > > - /* Check if the return value matches the negative format */ > > > - if (IS_ENABLED(CONFIG_64BIT) && (retval & BIT(31)) && > > > - (((u64)retval) >> 32) == 0) { > > > - err_code = sign_extend64(retval, 31); > > > - } else { > > > - err_code = retval; > > > > The original code just guesses the type (signed/unsigned) from > > the retval, but we don't need to do that with BTF. Sorry, I think the above guessing process is necessary to display an error code. In most cases, the return type is int, but retval is of size sizeof(unsigned long). We should perform sign extension to check whether it represents an error code. Thanks, Donglin > > Thanks. I will fix it in the next version. > > Thanks, > Donglin > > > > Thank you, > > > > > + if (print_retval) { > > > + trim_retval((unsigned long)func, &retval, &print_retval); > > > + if (print_retval && retval && !hex_format) { > > > + /* Check if the return value matches the negative format */ > > > + if (IS_ENABLED(CONFIG_64BIT) && (retval & BIT(31)) && > > > + (((u64)retval) >> 32) == 0) { > > > + err_code = sign_extend64(retval, 31); > > > + } else { > > > + err_code = retval; > > > + } > > > + > > > + if (!IS_ERR_VALUE(err_code)) > > > + err_code = 0; > > > } > > > - > > > - if (!IS_ERR_VALUE(err_code)) > > > - err_code = 0; > > > } > > > > > > if (entry) { > > > -- > > > 2.34.1 > > > > > > > > > -- > > Masami Hiramatsu (Google) <mhiramat@kernel.org> ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 2/2] tracing: Update funcgraph-retval documentation 2025-12-08 13:19 [PATCH v2 0/2] Use BTF to trim return values Donglin Peng 2025-12-08 13:19 ` [PATCH v2 1/2] fgraph: Use BTF to trim and filter " Donglin Peng @ 2025-12-08 13:19 ` Donglin Peng 1 sibling, 0 replies; 6+ messages in thread From: Donglin Peng @ 2025-12-08 13:19 UTC (permalink / raw) To: rostedt Cc: linux-trace-kernel, linux-kernel, pengdonglin, Masami Hiramatsu, Xiaoqin Zhang From: pengdonglin <pengdonglin@xiaomi.com> 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) <rostedt@goodmis.org> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Xiaoqin Zhang <zhangxiaoqin@xiaomi.com> Signed-off-by: pengdonglin <pengdonglin@xiaomi.com> --- Documentation/trace/ftrace.rst | 76 +++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst index d1f313a5f4ad..d2edd58f04c3 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,39 @@ 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 */ -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. -- 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 +2891,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 +2918,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 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-12-09 3:14 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-12-08 13:19 [PATCH v2 0/2] Use BTF to trim return values Donglin Peng 2025-12-08 13:19 ` [PATCH v2 1/2] fgraph: Use BTF to trim and filter " Donglin Peng 2025-12-09 0:48 ` Masami Hiramatsu 2025-12-09 1:42 ` Donglin Peng 2025-12-09 3:14 ` Donglin Peng 2025-12-08 13:19 ` [PATCH v2 2/2] tracing: Update funcgraph-retval documentation Donglin Peng
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox