Re: [PATCH 4/5] trace-cmd record / report: Record BTF file if function arguments are recorded

Douglas Raillard <[email protected]> Mon, 4 Aug 2025 13:37:06 +0100
Newsgroups org.kernel.vger.linux-trace-devel
Message-ID <[email protected]>
Don't forget to update the doc as well :)
Documentation/trace-cmd/trace-cmd.dat.v7.5.txt

On 31-07-2025 21:20, Steven Rostedt wrote:
> From: "Steven Rostedt (Google)" <[email protected]>
> 
> If function tracer is recorded with func-args option set, or the
> function_graph tracer is recorded with the funcgraph-args option set, then
> record the BTF file in a new BTF_FILE section in the trace.dat file.
> 
> This is compressed on disk, and when the trace.dat file is read, it is
> loaded into memory and sent to the libtraceevent tep_load_btf() function.
> 
> This will be used to show arguments of the function tracer:
> 
>               cat-33501 [005] ..... 136155.767937: function:             mutex_unlock(lock=0xffffffff831dbbe0)
>               cat-33501 [005] ..... 136155.767939: function:             __mutex_unlock_slowpath(lock=0xffffffff831dbbe0, ip=0xffffffff814a7154)
>               cat-33501 [005] ..... 136155.767940: function:             __f_unlock_pos(f=0xffff8881538de000)
>               cat-33501 [005] ..... 136155.767940: function:             mutex_unlock(lock=0xffff8881538de090)
>               cat-33501 [005] ..... 136155.767940: function:             __mutex_unlock_slowpath(lock=0xffff8881538de090, ip=0xffffffff816e8ed1)
>               cat-33501 [005] ..... 136155.767941: function:             mem_cgroup_handle_over_high(gfp_mask=0xcc0)
>               cat-33501 [005] ..... 136155.767941: function:             blkcg_maybe_throttle_current()
>               cat-33501 [005] ..... 136155.767942: function:             __rseq_handle_notify_resume(ksig=0x0, regs=0xffffc9000e3eff58)
>               cat-33501 [005] d.... 136155.767943: function:             fpregs_assert_state_consistent()
>               cat-33501 [005] d.... 136155.767943: function:             switch_fpu_return()
>               cat-33501 [005] ..... 136155.767950: function:             __x64_sys_execve(regs=0xffffc9000e3eff58)
>               cat-33501 [005] ..... 136155.767951: function:                getname_flags(filename=0x7ffe7d33f3d0, flags=0)
>               cat-33501 [005] ..... 136155.767951: function:                getname_flags.part.0(7ffe7d33f3d0, 0, 0, 0, 0, 0)
>               cat-33501 [005] ..... 136155.767951: function:                   kmem_cache_alloc_noprof(s=0xffff8881001d3800, gfpflags=0xcc0)
> 
> Signed-off-by: Steven Rostedt (Google) <[email protected]>
> ---
>   .../include/private/trace-cmd-private.h       |  3 +
>   lib/trace-cmd/trace-compress.c                | 26 ++++++++
>   lib/trace-cmd/trace-input.c                   | 15 +++++
>   lib/trace-cmd/trace-output.c                  | 64 +++++++++++++++++++
>   tracecmd/trace-record.c                       | 42 +++++++++++-
>   5 files changed, 149 insertions(+), 1 deletion(-)
> 
> diff --git a/lib/trace-cmd/include/private/trace-cmd-private.h b/lib/trace-cmd/include/private/trace-cmd-private.h
> index 809e244b2d1c..4743bbc62048 100644
> --- a/lib/trace-cmd/include/private/trace-cmd-private.h
> +++ b/lib/trace-cmd/include/private/trace-cmd-private.h
> @@ -159,6 +159,7 @@ enum {
>   	TRACECMD_OPTION_PRINTK,
>   	TRACECMD_OPTION_CMDLINES,
>   	TRACECMD_OPTION_BUFFER_TEXT,
> +	TRACECMD_OPTION_BTF_FILE,
>   	TRACECMD_OPTION_MAX,
>   };
>   
> @@ -340,6 +341,7 @@ int tracecmd_append_buffer_cpu_data(struct tracecmd_output *handle,
>   struct tracecmd_output *tracecmd_get_output_handle_fd(int fd);
>   unsigned long tracecmd_get_out_file_version(struct tracecmd_output *handle);
>   size_t tracecmd_get_out_file_offset(struct tracecmd_output *handle);
> +int tracecmd_append_btf_file(struct tracecmd_output *handle);
>   
>   /* --- Reading the Fly Recorder Trace --- */
>   
> @@ -568,6 +570,7 @@ int tracecmd_uncompress_chunk(struct tracecmd_compression *handle,
>   			      struct tracecmd_compress_chunk *chunk, char *data);
>   int tracecmd_load_chunks_info(struct tracecmd_compression *handle,
>   			      struct tracecmd_compress_chunk **chunks_info);
> +void *tracecmd_uncompress_buffer(struct tracecmd_compression *handle, size_t *size);
>   /* --- Plugin handling --- */
>   extern struct tep_plugin_option trace_ftrace_options[];
>   
> diff --git a/lib/trace-cmd/trace-compress.c b/lib/trace-cmd/trace-compress.c
> index 2a7a3e24a7ad..19457a1e0f41 100644
> --- a/lib/trace-cmd/trace-compress.c
> +++ b/lib/trace-cmd/trace-compress.c
> @@ -363,6 +363,32 @@ out:
>   	free(buf);
>   	return ret;
>   }
> +/**
> + * tracecmd_uncompress_buffer - Returned the current uncompressed buffer
> + * @handle: compression handle
> + * @size: A pointer to place the size of the uncompressed buffer in
> + *
> + * Returns the current uncompressed buffer and resets the compression
> + * @handle.
> + *
> + * Returns the buffer (must be freed with free()) or NULL.
> + *  @size (if not NULL) will contain the size of the uncompressed buffer.
> + */
> +void *tracecmd_uncompress_buffer(struct tracecmd_compression *handle, size_t *size)
> +{
> +	void *buffer;
> +
> +	if (!handle)
> +		return NULL;
> +
> +	if (size)
> +		*size = handle->capacity;
> +
> +	buffer = handle->buffer;
> +	handle->buffer = NULL;
> +	tracecmd_compress_reset(handle);
> +	return buffer;
> +}
>   
>   /**
>    * tracecmd_compress_buffer_write - write() to compression buffer
> diff --git a/lib/trace-cmd/trace-input.c b/lib/trace-cmd/trace-input.c
> index 6080a6f0cdfd..84afc346a86a 100644
> --- a/lib/trace-cmd/trace-input.c
> +++ b/lib/trace-cmd/trace-input.c
> @@ -1026,6 +1026,17 @@ static int read_ftrace_printk(struct tracecmd_input *handle)
>   	return 0;
>   }
>   
> +static int read_btf(struct tracecmd_input *handle)
> +{
> +	void *raw_data;
> +	size_t size;
> +
> +	raw_data = tracecmd_uncompress_buffer(handle->compress, &size);
> +
> +	tep_load_btf(handle->pevent, raw_data, size);
> +	return 0;
> +}
> +
>   static int read_and_parse_cmdlines(struct tracecmd_input *handle);
>   
>   /**
> @@ -1203,6 +1214,9 @@ static int handle_section(struct tracecmd_input *handle, struct file_section *se
>   	case TRACECMD_OPTION_CMDLINES:
>   		ret = read_and_parse_cmdlines(handle);
>   		break;
> +	case TRACECMD_OPTION_BTF_FILE:
> +		ret = read_btf(handle);
> +		break;
>   	default:
>   		ret = 0;
>   		break;
> @@ -4174,6 +4188,7 @@ static int handle_options(struct tracecmd_input *handle)
>   		case TRACECMD_OPTION_KALLSYMS:
>   		case TRACECMD_OPTION_PRINTK:
>   		case TRACECMD_OPTION_CMDLINES:
> +		case TRACECMD_OPTION_BTF_FILE:
>   			if (size < 8)
>   				break;
>   			section_add_or_update(handle, option, -1,
> diff --git a/lib/trace-cmd/trace-output.c b/lib/trace-cmd/trace-output.c
> index e775cdc03bfc..ac8f178b1a91 100644
> --- a/lib/trace-cmd/trace-output.c
> +++ b/lib/trace-cmd/trace-output.c
> @@ -2288,6 +2288,70 @@ int tracecmd_write_cmdlines(struct tracecmd_output *handle)
>   	return 0;
>   }
>   
> +#define BTF_FILE "/sys/kernel/btf/vmlinux"
> +
> +int tracecmd_append_btf_file(struct tracecmd_output *handle)
> +{
> +	tsize_t offset, size, check_size;
> +	struct tracecmd_option *option;
> +	struct iovec *vect;
> +	struct stat st;
> +	int ret;
> +
> +	if (!HAS_SECTIONS(handle))
> +		return -1;
> +
> +	offset = write_compress_section_header(handle, TRACECMD_OPTION_BTF_FILE, NULL, true);
> +	if (offset == (off_t)-1)
> +		return -1;
> +
> +	tcmd_out_compression_start(handle);
> +
> +	ret = stat(BTF_FILE, &st);
> +	if (ret < 0)
> +		return -1;
> +
> +	check_size = copy_file(handle, BTF_FILE);
> +	if (st.st_size != check_size) {
> +		errno = EINVAL;
> +		tracecmd_warning("error in size of file '%s'", BTF_FILE);
> +		return -1;
> +	}
> +
> +	if (tcmd_out_compression_end(handle))
> +		return -1;
> +
> +	if (tcmd_out_update_section_header(handle, offset))
> +		return -1;
> +
> +	return 0;
> +
> +	/*
> +	 * BTF file
> +	 *  - data offset in the file
> +	 *  - data size
> +	 */
> +
> +	vect = calloc(2, sizeof(struct iovec));
> +	if (!vect)
> +		return -1;
> +	vect[0].iov_base = &offset;
> +	vect[0].iov_len = 8;
> +	vect[1].iov_base = &size;
> +	vect[1].iov_len = 8;
> +
> +	option = tracecmd_add_option_v(handle, TRACECMD_OPTION_BTF_FILE, vect, 2);
> +	free(vect);
> +
> +	if (!option)
> +		return -1;
> +
> +	if (do_lseek(handle, 0, SEEK_END) == (off_t)-1)
> +		return -1;
> +
> +	return 0;
> +}
> +
>   static char *get_clock(struct tracecmd_output *handle)
>   {
>   	struct tracefs_instance *inst;
> diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c
> index 47486e9863df..f36ee6cd6cc6 100644
> --- a/tracecmd/trace-record.c
> +++ b/tracecmd/trace-record.c
> @@ -4632,12 +4632,46 @@ error:
>   	return NULL;
>   }
>   
> +static void check_need_btf(bool *need_btf, struct tracefs_instance *instance)
> +{
> +	bool func_graph_trace;
> +	bool func_trace;
> +	char *current;
> +
> +	/* Nothing to do if it's already set */
> +	if (*need_btf)
> +		return;
> +
> +	current = tracefs_instance_file_read(instance, "current_tracer", NULL);
> +	if (!current)
> +		return;
> +
> +	func_trace = strcmp(current, "function\n") == 0;
> +	func_graph_trace = strcmp(current, "function_graph\n") == 0;
> +
> +	free(current);
> +	if (!func_trace && !func_graph_trace)
> +		return;
> +
> +	if (func_trace)
> +		current = tracefs_instance_file_read(instance, "options/func-args", NULL);
> +	else
> +		current = tracefs_instance_file_read(instance, "options/funcgraph-args", NULL);
> +	if (!current)
> +		return;
> +
> +	*need_btf = strncmp(current, "1", 1) == 0;
> +
> +	free(current);
> +}
> +
>   static void record_data(struct common_record_context *ctx)
>   {
>   	struct tracecmd_output *handle;
>   	struct buffer_instance *instance;
>   	bool have_proxy = false;
>   	bool local = false;
> +	bool need_btf = false;
>   	int max_cpu_count = local_cpu_count;
>   	char **temp_files;
>   	int i;
> @@ -4733,11 +4767,17 @@ static void record_data(struct common_record_context *ctx)
>   							tracefs_instance_get_name(instance->tracefs),
>   							cpus);
>   				add_buffer_stat(handle, instance);
> +				check_need_btf(&need_btf, instance->tracefs);
>   			}
>   		}
>   
> -		if (!no_top_instance() && !top_instance.msg_handle)
> +		if (!no_top_instance() && !top_instance.msg_handle) {
>   			print_stat(&top_instance);
> +			check_need_btf(&need_btf, top_instance.tracefs);
> +		}
> +
> +		if (need_btf)
> +			tracecmd_append_btf_file(handle);
>   
>   		for_all_instances(instance) {
>   			add_pid_maps(handle, instance);