diff mbox series

[4/7] Add print_function_args()

Message ID 20240904065908.1009086-5-svens@linux.ibm.com (mailing list archive)
State Changes Requested
Headers show
Series None | expand

Commit Message

Sven Schnelle Sept. 4, 2024, 6:58 a.m. UTC
Add a function to decode argument types with the help of BTF. Will
be used to display arguments in the function and function graph
tracer.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
---
 kernel/trace/trace_output.c | 68 +++++++++++++++++++++++++++++++++++++
 kernel/trace/trace_output.h |  9 +++++
 2 files changed, 77 insertions(+)

Comments

Masami Hiramatsu (Google) Sept. 8, 2024, 3:17 p.m. UTC | #1
On Wed,  4 Sep 2024 08:58:58 +0200
Sven Schnelle <svens@linux.ibm.com> wrote:

> Add a function to decode argument types with the help of BTF. Will
> be used to display arguments in the function and function graph
> tracer.
> 
> Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
> ---
>  kernel/trace/trace_output.c | 68 +++++++++++++++++++++++++++++++++++++
>  kernel/trace/trace_output.h |  9 +++++
>  2 files changed, 77 insertions(+)
> 
> diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
> index d8b302d01083..70405c4cceb6 100644
> --- a/kernel/trace/trace_output.c
> +++ b/kernel/trace/trace_output.c
> @@ -12,8 +12,11 @@
>  #include <linux/sched/clock.h>
>  #include <linux/sched/mm.h>
>  #include <linux/idr.h>
> +#include <linux/btf.h>
> +#include <linux/bpf.h>
>  
>  #include "trace_output.h"
> +#include "trace_btf.h"
>  
>  /* must be a power of 2 */
>  #define EVENT_HASHSIZE	128
> @@ -669,6 +672,71 @@ int trace_print_lat_context(struct trace_iterator *iter)
>  	return !trace_seq_has_overflowed(s);
>  }
>  
> +#ifdef CONFIG_FUNCTION_TRACE_ARGS
> +void print_function_args(struct trace_seq *s, struct ftrace_regs *fregs,
> +			 unsigned long func)
> +{
> +	const struct btf_param *param;
> +	const struct btf_type *t;
> +	const char *param_name;
> +	char name[KSYM_NAME_LEN];
> +	unsigned long arg;
> +	struct btf *btf;
> +	s32 tid, nr = 0;
> +	int i;
> +
> +	trace_seq_printf(s, "(");
> +
> +	if (!ftrace_regs_has_args(fregs))
> +		goto out;
> +	if (lookup_symbol_name(func, name))
> +		goto out;
> +
> +	btf = bpf_get_btf_vmlinux();
> +	if (IS_ERR_OR_NULL(btf))
> +		goto out;
> +
> +	t = btf_find_func_proto(name, &btf);
> +	if (IS_ERR_OR_NULL(t))
> +		goto out;
> +
> +	param = btf_get_func_param(t, &nr);
> +	if (!param)
> +		goto out_put;
> +
> +	for (i = 0; i < nr; i++) {
> +		arg = ftrace_regs_get_argument(fregs, i);
> +
> +		param_name = btf_name_by_offset(btf, param[i].name_off);
> +		if (param_name)
> +			trace_seq_printf(s, "%s = ", param_name);
> +		t = btf_type_skip_modifiers(btf, param[i].type, &tid);
> +		if (!t)
> +			continue;
> +		switch (BTF_INFO_KIND(t->info)) {
> +		case BTF_KIND_PTR:
> +			trace_seq_printf(s, "0x%lx", arg);
> +			break;
> +		case BTF_KIND_INT:
> +			trace_seq_printf(s, "%ld", arg);

Don't we check the size and signed? :)

> +			break;
> +		case BTF_KIND_ENUM:
> +			trace_seq_printf(s, "%ld", arg);

nit: %d? (enum is equal to the int type)

BTW, this series splits the patches by coding, not functionality.
For the first review, it is OK. But eventually those should be merged.

Thank you,

> +			break;
> +		default:
> +			trace_seq_printf(s, "0x%lx (%d)", arg, BTF_INFO_KIND(param[i].type));
> +			break;
> +		}
> +		if (i < nr - 1)
> +			trace_seq_printf(s, ", ");
> +	}
> +out_put:
> +	btf_put(btf);
> +out:
> +	trace_seq_printf(s, ")");
> +}
> +#endif
> +
>  /**
>   * ftrace_find_event - find a registered event
>   * @type: the type of event to look for
> diff --git a/kernel/trace/trace_output.h b/kernel/trace/trace_output.h
> index dca40f1f1da4..a21d8ce606f7 100644
> --- a/kernel/trace/trace_output.h
> +++ b/kernel/trace/trace_output.h
> @@ -41,5 +41,14 @@ extern struct rw_semaphore trace_event_sem;
>  #define SEQ_PUT_HEX_FIELD(s, x)				\
>  	trace_seq_putmem_hex(s, &(x), sizeof(x))
>  
> +#ifdef CONFIG_FUNCTION_TRACE_ARGS
> +void print_function_args(struct trace_seq *s, struct ftrace_regs *fregs,
> +			 unsigned long func);
> +#else
> +static inline void print_function_args(struct trace_seq *s, struct ftrace_regs *fregs,
> +				       unsigned long func) {
> +	trace_seq_puts(s, "()");
> +}
> +#endif
>  #endif
>  
> -- 
> 2.43.0
>
Donglin Peng Sept. 9, 2024, 3:13 a.m. UTC | #2
On Wed, Sep 4, 2024 at 2:59 PM Sven Schnelle <svens@linux.ibm.com> wrote:
>
> Add a function to decode argument types with the help of BTF. Will
> be used to display arguments in the function and function graph
> tracer.
>
> Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
> ---
>  kernel/trace/trace_output.c | 68 +++++++++++++++++++++++++++++++++++++
>  kernel/trace/trace_output.h |  9 +++++
>  2 files changed, 77 insertions(+)
>
> diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
> index d8b302d01083..70405c4cceb6 100644
> --- a/kernel/trace/trace_output.c
> +++ b/kernel/trace/trace_output.c
> @@ -12,8 +12,11 @@
>  #include <linux/sched/clock.h>
>  #include <linux/sched/mm.h>
>  #include <linux/idr.h>
> +#include <linux/btf.h>
> +#include <linux/bpf.h>
>
>  #include "trace_output.h"
> +#include "trace_btf.h"
>
>  /* must be a power of 2 */
>  #define EVENT_HASHSIZE 128
> @@ -669,6 +672,71 @@ int trace_print_lat_context(struct trace_iterator *iter)
>         return !trace_seq_has_overflowed(s);
>  }
>
> +#ifdef CONFIG_FUNCTION_TRACE_ARGS
> +void print_function_args(struct trace_seq *s, struct ftrace_regs *fregs,
> +                        unsigned long func)
> +{
> +       const struct btf_param *param;
> +       const struct btf_type *t;
> +       const char *param_name;
> +       char name[KSYM_NAME_LEN];
> +       unsigned long arg;
> +       struct btf *btf;
> +       s32 tid, nr = 0;
> +       int i;
> +
> +       trace_seq_printf(s, "(");
> +
> +       if (!ftrace_regs_has_args(fregs))
> +               goto out;
> +       if (lookup_symbol_name(func, name))
> +               goto out;
> +
> +       btf = bpf_get_btf_vmlinux();
> +       if (IS_ERR_OR_NULL(btf))
> +               goto out;
> +
> +       t = btf_find_func_proto(name, &btf);

This is an excellent feature, and I am crafting a series of patches aimed
 at enhancing the search performance for locating the btf by its name.

> +       if (IS_ERR_OR_NULL(t))
> +               goto out;
> +
> +       param = btf_get_func_param(t, &nr);
> +       if (!param)
> +               goto out_put;
> +
> +       for (i = 0; i < nr; i++) {
> +               arg = ftrace_regs_get_argument(fregs, i);
> +
> +               param_name = btf_name_by_offset(btf, param[i].name_off);
> +               if (param_name)
> +                       trace_seq_printf(s, "%s = ", param_name);
> +               t = btf_type_skip_modifiers(btf, param[i].type, &tid);
> +               if (!t)
> +                       continue;
> +               switch (BTF_INFO_KIND(t->info)) {
> +               case BTF_KIND_PTR:
> +                       trace_seq_printf(s, "0x%lx", arg);
> +                       break;
> +               case BTF_KIND_INT:
> +                       trace_seq_printf(s, "%ld", arg);
> +                       break;
> +               case BTF_KIND_ENUM:
> +                       trace_seq_printf(s, "%ld", arg);
> +                       break;
> +               default:
> +                       trace_seq_printf(s, "0x%lx (%d)", arg, BTF_INFO_KIND(param[i].type));
> +                       break;
> +               }
> +               if (i < nr - 1)
> +                       trace_seq_printf(s, ", ");
> +       }
> +out_put:
> +       btf_put(btf);
> +out:
> +       trace_seq_printf(s, ")");
> +}
> +#endif
> +
>  /**
>   * ftrace_find_event - find a registered event
>   * @type: the type of event to look for
> diff --git a/kernel/trace/trace_output.h b/kernel/trace/trace_output.h
> index dca40f1f1da4..a21d8ce606f7 100644
> --- a/kernel/trace/trace_output.h
> +++ b/kernel/trace/trace_output.h
> @@ -41,5 +41,14 @@ extern struct rw_semaphore trace_event_sem;
>  #define SEQ_PUT_HEX_FIELD(s, x)                                \
>         trace_seq_putmem_hex(s, &(x), sizeof(x))
>
> +#ifdef CONFIG_FUNCTION_TRACE_ARGS
> +void print_function_args(struct trace_seq *s, struct ftrace_regs *fregs,
> +                        unsigned long func);
> +#else
> +static inline void print_function_args(struct trace_seq *s, struct ftrace_regs *fregs,
> +                                      unsigned long func) {
> +       trace_seq_puts(s, "()");
> +}
> +#endif
>  #endif
>
> --
> 2.43.0
>
>
diff mbox series

Patch

diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index d8b302d01083..70405c4cceb6 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -12,8 +12,11 @@ 
 #include <linux/sched/clock.h>
 #include <linux/sched/mm.h>
 #include <linux/idr.h>
+#include <linux/btf.h>
+#include <linux/bpf.h>
 
 #include "trace_output.h"
+#include "trace_btf.h"
 
 /* must be a power of 2 */
 #define EVENT_HASHSIZE	128
@@ -669,6 +672,71 @@  int trace_print_lat_context(struct trace_iterator *iter)
 	return !trace_seq_has_overflowed(s);
 }
 
+#ifdef CONFIG_FUNCTION_TRACE_ARGS
+void print_function_args(struct trace_seq *s, struct ftrace_regs *fregs,
+			 unsigned long func)
+{
+	const struct btf_param *param;
+	const struct btf_type *t;
+	const char *param_name;
+	char name[KSYM_NAME_LEN];
+	unsigned long arg;
+	struct btf *btf;
+	s32 tid, nr = 0;
+	int i;
+
+	trace_seq_printf(s, "(");
+
+	if (!ftrace_regs_has_args(fregs))
+		goto out;
+	if (lookup_symbol_name(func, name))
+		goto out;
+
+	btf = bpf_get_btf_vmlinux();
+	if (IS_ERR_OR_NULL(btf))
+		goto out;
+
+	t = btf_find_func_proto(name, &btf);
+	if (IS_ERR_OR_NULL(t))
+		goto out;
+
+	param = btf_get_func_param(t, &nr);
+	if (!param)
+		goto out_put;
+
+	for (i = 0; i < nr; i++) {
+		arg = ftrace_regs_get_argument(fregs, i);
+
+		param_name = btf_name_by_offset(btf, param[i].name_off);
+		if (param_name)
+			trace_seq_printf(s, "%s = ", param_name);
+		t = btf_type_skip_modifiers(btf, param[i].type, &tid);
+		if (!t)
+			continue;
+		switch (BTF_INFO_KIND(t->info)) {
+		case BTF_KIND_PTR:
+			trace_seq_printf(s, "0x%lx", arg);
+			break;
+		case BTF_KIND_INT:
+			trace_seq_printf(s, "%ld", arg);
+			break;
+		case BTF_KIND_ENUM:
+			trace_seq_printf(s, "%ld", arg);
+			break;
+		default:
+			trace_seq_printf(s, "0x%lx (%d)", arg, BTF_INFO_KIND(param[i].type));
+			break;
+		}
+		if (i < nr - 1)
+			trace_seq_printf(s, ", ");
+	}
+out_put:
+	btf_put(btf);
+out:
+	trace_seq_printf(s, ")");
+}
+#endif
+
 /**
  * ftrace_find_event - find a registered event
  * @type: the type of event to look for
diff --git a/kernel/trace/trace_output.h b/kernel/trace/trace_output.h
index dca40f1f1da4..a21d8ce606f7 100644
--- a/kernel/trace/trace_output.h
+++ b/kernel/trace/trace_output.h
@@ -41,5 +41,14 @@  extern struct rw_semaphore trace_event_sem;
 #define SEQ_PUT_HEX_FIELD(s, x)				\
 	trace_seq_putmem_hex(s, &(x), sizeof(x))
 
+#ifdef CONFIG_FUNCTION_TRACE_ARGS
+void print_function_args(struct trace_seq *s, struct ftrace_regs *fregs,
+			 unsigned long func);
+#else
+static inline void print_function_args(struct trace_seq *s, struct ftrace_regs *fregs,
+				       unsigned long func) {
+	trace_seq_puts(s, "()");
+}
+#endif
 #endif