[PATCH] libtraceevent: Add support for __print_dynamic_array() macro

Steven Rostedt <[email protected]> Mon, 14 Apr 2025 15:30:17 -0400
Newsgroups org.kernel.vger.linux-trace-devel
Message-ID <[email protected]>
From: "Steven Rostedt (Google)" <[email protected]>

The Linux version v6.13 added a __print_dynamic_array() helper macro that is
basically:

 #define __print_dynamic_array(array, el_size)                          \
        ({                                                              \
                __print_array(__get_dynamic_array(array),               \
                              __get_dynamic_array_len(array) / (el_size), \
                              (el_size));                               \
        })

Add support for in.

Signed-off-by: Steven Rostedt (Google) <[email protected]>
---
 src/event-parse.c | 65 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 63 insertions(+), 2 deletions(-)

diff --git a/src/event-parse.c b/src/event-parse.c
index 6317ff6..ba6e42b 100644
--- a/src/event-parse.c
+++ b/src/event-parse.c
@@ -3160,6 +3160,54 @@ out:
 	return TEP_EVENT_ERROR;
 }
 
+static enum tep_event_type
+process_int_dynamic_array(struct tep_event *event, struct tep_print_arg *arg, char **tok)
+{
+	struct tep_format_field *field;
+	enum tep_event_type type;
+	char *token;
+
+	memset(arg, 0, sizeof(*arg));
+	arg->type = TEP_PRINT_INT_ARRAY;
+
+	/*
+	 * The first item within the parenthesis is another field that holds
+	 * the index into where the array starts.
+	 */
+	type = tep_read_token(event->tep, &token);
+	if (type != TEP_EVENT_ITEM)
+		return TEP_EVENT_ERROR;
+
+	/* Find the field */
+	field = tep_find_field(event, token);
+	if (!field)
+		goto out;
+
+	if (read_expected(event->tep, TEP_EVENT_DELIM, ",") < 0)
+		goto out;
+
+	arg->int_array.count = NULL;
+
+	if (alloc_and_process_delim(event, ")", &arg->int_array.el_size))
+		goto out;
+
+	arg->int_array.field = alloc_arg();
+	if (!arg) {
+		do_warning_event(event, "%s: not enough memory!", __func__);
+		goto out;
+	}
+
+	arg->int_array.field->type = TEP_PRINT_DYNAMIC_ARRAY;
+	arg->int_array.field->dynarray.field = field;
+	arg->int_array.field->dynarray.index = 0;
+
+	return read_token_item(event->tep, tok);
+out:
+	tep_free_token(token);
+	*tok = NULL;
+	return TEP_EVENT_ERROR;
+}
+
 static enum tep_event_type
 process_dynamic_array(struct tep_event *event, struct tep_print_arg *arg, char **tok)
 {
@@ -3661,6 +3709,10 @@ process_function(struct tep_event *event, struct tep_print_arg *arg,
 		tep_free_token(token);
 		return process_int_array(event, arg, tok);
 	}
+	if (strcmp(token, "__print_dynamic_array") == 0) {
+		tep_free_token(token);
+		return process_int_dynamic_array(event, arg, tok);
+	}
 	if (strcmp(token, "__get_str") == 0 ||
 	    strcmp(token, "__get_rel_str") == 0) {
 		tep_free_token(token);
@@ -4941,9 +4993,11 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
 		void *num;
 		int el_size;
 
+		len = 0;
+
 		if (arg->int_array.field->type == TEP_PRINT_DYNAMIC_ARRAY) {
 			dynamic_offset_field(tep, arg->int_array.field->dynarray.field, data,
-					     size, &offset, NULL);
+					     size, &offset, &len);
 			num = data + offset;
 		} else {
 			field = arg->int_array.field->field.field;
@@ -4956,9 +5010,16 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
 			}
 			num = data + field->offset;
 		}
-		len = eval_num_arg(data, size, event, arg->int_array.count);
 		el_size = eval_num_arg(data, size, event,
 				       arg->int_array.el_size);
+
+		if (arg->int_array.count) {
+			len = eval_num_arg(data, size, event, arg->int_array.count);
+		} else {
+			/* __print_dynamic_array() has a dynamic count */
+			if (el_size)
+				len /= el_size;
+		}
 		trace_seq_putc(s, '{');
 		for (i = 0; i < len; i++) {
 			if (i)
-- 
2.47.2