public inbox for linux-trace-devel@vger.kernel.org
 help / color / mirror / Atom feed
From: CaoRuichuang <create0818@163.com>
To: linux-trace-devel@vger.kernel.org
Cc: rostedt@goodmis.org, tz.stoyanov@gmail.com, create0818@163.com
Subject: [PATCH v2] libtraceevent: parse %pB and %pa address specifiers
Date: Mon,  6 Apr 2026 14:20:09 +0800	[thread overview]
Message-ID: <20260406062009.57413-1-create0818@163.com> (raw)
In-Reply-To: <20260405221033.7036-1-create0818@163.com>

tep_parse_format() currently rejects events whose print fmt uses
%pB, %pa, %pap or %pad. The pointer format parser does not recognise
those suffixes, so libtraceevent fails before trace-cmd can report
the event at all.

Teach the pointer-format parser to accept %pB and %pa[p]/%pad,
print %pB with backtrace-style symbol lookup, and format %pa[p]/%pad
values from the referenced event fields.

Add unit tests that cover %pB, %pa, %pap and %pad.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=217337
Signed-off-by: CaoRuichuang <create0818@163.com>
---
 src/event-parse.c        |  90 +++++++++++++++++++++++++
 utest/traceevent-utest.c | 137 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 227 insertions(+)

diff --git a/src/event-parse.c b/src/event-parse.c
index fee0f91..4bd5c1b 100644
--- a/src/event-parse.c
+++ b/src/event-parse.c
@@ -6631,6 +6631,78 @@ static int print_function(struct trace_seq *s, const char *format,
 	return 0;
 }
 
+static int print_function_backtrace(struct trace_seq *s,
+				    void *data, int size,
+				    struct tep_event *event,
+				    struct tep_print_arg *arg, bool raw)
+{
+	struct func_map *func = NULL;
+	unsigned long long lookup;
+	unsigned long long val;
+
+	val = eval_num_arg(data, size, event, arg);
+	lookup = val ? val - 1 : 0;
+	func = val ? find_func(event->tep, lookup) : NULL;
+
+	if (func) {
+		trace_seq_puts(s, func->func);
+		trace_seq_printf(s, "+0x%llx", lookup - func->addr);
+	}
+
+	if (!func || raw) {
+		if (raw)
+			trace_seq_puts(s, " (");
+		if (event->tep->long_size == 4)
+			trace_seq_printf(s, "0x%lx", (long)val);
+		else
+			trace_seq_printf(s, "0x%llx", (long long)val);
+		if (raw)
+			trace_seq_puts(s, ")");
+	}
+
+	return 0;
+}
+
+static int print_addr_ref_arg(struct trace_seq *s, const char *format,
+			      void *data, int size,
+			      struct tep_event *event,
+			      struct tep_print_arg *arg)
+{
+	struct tep_format_field *field;
+	struct tep_handle *tep = event->tep;
+	unsigned long long val;
+	int width;
+	int ret = 0;
+
+	while (arg->type == TEP_PRINT_TYPE)
+		arg = arg->typecast.item;
+
+	if (arg->type != TEP_PRINT_FIELD) {
+		trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type);
+		return ret;
+	}
+
+	field = arg->field.field;
+	if (!field) {
+		field = tep_find_any_field(event, arg->field.name);
+		if (!field) {
+			do_warning_event(event, "%s: field %s not found",
+					 __func__, arg->field.name);
+			return ret;
+		}
+		arg->field.field = field;
+	}
+
+	val = tep_read_number(tep, data + field->offset, field->size);
+	width = field->size * 2;
+	trace_seq_printf(s, "0x%0*llx", width, val);
+
+	if (format[1] == 'p' || format[1] == 'd')
+		ret++;
+
+	return ret;
+}
+
 static int print_arg_pointer(struct trace_seq *s, const char *format, int plen,
 			     void *data, int size,
 			     struct tep_event *event, struct tep_print_arg *arg,
@@ -6652,12 +6724,18 @@ static int print_arg_pointer(struct trace_seq *s, const char *format, int plen,
 	}
 
 	switch (*format) {
+	case 'B':
+		ret += print_function_backtrace(s, data, size, event, arg, raw);
+		break;
 	case 'F':
 	case 'f':
 	case 'S':
 	case 's':
 		ret += print_function(s, format, data, size, event, arg, raw);
 		break;
+	case 'a':
+		ret += print_addr_ref_arg(s, format, data, size, event, arg);
+		break;
 	case 'M':
 	case 'm':
 		ret += print_mac_arg(s, format, data, size, event, arg);
@@ -6752,12 +6830,24 @@ static int parse_arg_format_pointer(const char *format)
 	int loop;
 
 	switch (*format) {
+	case 'B':
+		ret++;
+		break;
 	case 'F':
 	case 'S':
 	case 'f':
 	case 's':
 		ret++;
 		break;
+	case 'a':
+		switch (format[1]) {
+		case 'p':
+		case 'd':
+			ret++;
+			break;
+		}
+		ret++;
+		break;
 	case 'M':
 	case 'm':
 		/* [mM]R , [mM]F */
diff --git a/utest/traceevent-utest.c b/utest/traceevent-utest.c
index b62411c..e0b9686 100644
--- a/utest/traceevent-utest.c
+++ b/utest/traceevent-utest.c
@@ -16,6 +16,7 @@
 #include <ftw.h>
 
 #include <sys/mman.h>
+#include <stdint.h>
 
 #include <CUnit/CUnit.h>
 #include <CUnit/Basic.h>
@@ -182,6 +183,58 @@ static char sizeof_data[] = {
 };
 static void *sizeof_event_data = (void *)sizeof_data;
 
+static const char pointer_backtrace_event[] =
+	"name: pointer_backtrace_event\n"
+	"ID: 40\n"
+	"format:\n"
+	"\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n"
+	"\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n"
+	"\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;\n"
+	"\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n"
+	"\n"
+	"\tfield:unsigned long long ptr;\toffset:8;\tsize:8;\tsigned:0;\n"
+	"\n"
+	"print fmt: \"ptr=%pB\", REC->ptr\n";
+
+static const char phys_addr_event[] =
+	"name: phys_addr_event\n"
+	"ID: 41\n"
+	"format:\n"
+	"\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n"
+	"\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n"
+	"\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;\n"
+	"\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n"
+	"\n"
+	"\tfield:unsigned long long phys;\toffset:8;\tsize:8;\tsigned:0;\n"
+	"\n"
+	"print fmt: \"phys=%pap\", REC->phys\n";
+
+static const char phys_addr_plain_event[] =
+	"name: phys_addr_plain_event\n"
+	"ID: 43\n"
+	"format:\n"
+	"\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n"
+	"\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n"
+	"\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;\n"
+	"\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n"
+	"\n"
+	"\tfield:unsigned long long phys;\toffset:8;\tsize:8;\tsigned:0;\n"
+	"\n"
+	"print fmt: \"phys=%pa\", REC->phys\n";
+
+static const char dma_addr_event[] =
+	"name: dma_addr_event\n"
+	"ID: 42\n"
+	"format:\n"
+	"\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n"
+	"\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n"
+	"\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;\n"
+	"\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n"
+	"\n"
+	"\tfield:unsigned int dma;\toffset:8;\tsize:4;\tsigned:0;\n"
+	"\n"
+	"print fmt: \"dma=%pad\", REC->dma\n";
+
 DECL_CPUMASK_EVENT_DATA(full, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
 #define CPUMASK_FULL     "ARRAY[ff, ff, ff, ff, ff, ff, ff, ff]"
 #define CPUMASK_FULL_FMT "cpumask=0-63"
@@ -380,6 +433,78 @@ static void test_parse_sizeof_undef(void)
 	test_parse_sizeof(0, 5, "sizeof_undef", SIZEOF_LONG0_FMT);
 }
 
+static void parse_pointer_event(const char *format, const char *system,
+				void *data, int size, const char *expected)
+{
+	struct tep_event *event;
+	struct tep_record record;
+
+	record.data = data;
+	record.size = size;
+
+	CU_TEST(tep_parse_format(test_tep, &event, format, strlen(format),
+				 system) == TEP_ERRNO__SUCCESS);
+
+	trace_seq_reset(test_seq);
+	tep_print_event(test_tep, test_seq, &record, "%s", TEP_PRINT_INFO);
+	trace_seq_do_printf(test_seq);
+	CU_TEST(strcmp(test_seq->buffer, expected) == 0);
+}
+
+static void test_parse_pointer_backtrace(void)
+{
+	unsigned char data[16] = { 0 };
+	unsigned short type = 40;
+	uint64_t ptr = 0x1001ULL;
+
+	memcpy(data, &type, sizeof(type));
+	memcpy(data + 8, &ptr, sizeof(ptr));
+
+	parse_pointer_event(pointer_backtrace_event, "ptr_backtrace",
+			    data, sizeof(data), "ptr=test_func+0x0");
+}
+
+static void test_parse_phys_addr(void)
+{
+	unsigned char data[16] = { 0 };
+	unsigned short type = 41;
+	uint64_t phys = 0x123456789abcdef0ULL;
+
+	memcpy(data, &type, sizeof(type));
+	memcpy(data + 8, &phys, sizeof(phys));
+
+	parse_pointer_event(phys_addr_event, "ptr_phys",
+			    data, sizeof(data),
+			    "phys=0x123456789abcdef0");
+}
+
+static void test_parse_phys_addr_plain(void)
+{
+	unsigned char data[16] = { 0 };
+	unsigned short type = 43;
+	uint64_t phys = 0x123456789abcdef0ULL;
+
+	memcpy(data, &type, sizeof(type));
+	memcpy(data + 8, &phys, sizeof(phys));
+
+	parse_pointer_event(phys_addr_plain_event, "ptr_phys_plain",
+			    data, sizeof(data),
+			    "phys=0x123456789abcdef0");
+}
+
+static void test_parse_dma_addr(void)
+{
+	unsigned char data[12] = { 0 };
+	unsigned short type = 42;
+	uint32_t dma = 0x1234abcdU;
+
+	memcpy(data, &type, sizeof(type));
+	memcpy(data + 8, &dma, sizeof(dma));
+
+	parse_pointer_event(dma_addr_event, "ptr_dma",
+			    data, sizeof(data), "dma=0x1234abcd");
+}
+
 static void test_btf_read(void)
 {
 	unsigned long args[] = {0x7ffe7d33f3d0, 0, 0, 0, 0, 0};
@@ -429,6 +554,10 @@ static int test_suite_init(void)
 	test_tep = tep_alloc();
 	if (!test_tep)
 		return 1;
+	if (tep_register_function(test_tep, "test_func", 0x1000, NULL))
+		return 1;
+	if (tep_register_function(test_tep, "test_func_end", 0x2000, NULL))
+		return 1;
 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
 	tep_set_file_bigendian(test_tep, TEP_BIG_ENDIAN);
 #endif
@@ -466,6 +595,14 @@ void test_traceevent_lib(void)
 		    test_parse_sizeof4);
 	CU_add_test(suite, "parse sizeof() no long size defined",
 		    test_parse_sizeof_undef);
+	CU_add_test(suite, "parse %pB pointer format",
+		    test_parse_pointer_backtrace);
+	CU_add_test(suite, "parse %pap pointer format",
+		    test_parse_phys_addr);
+	CU_add_test(suite, "parse %pa pointer format",
+		    test_parse_phys_addr_plain);
+	CU_add_test(suite, "parse %pad pointer format",
+		    test_parse_dma_addr);
 	CU_add_test(suite, "read BTF",
 		    test_btf_read);
 }
-- 
2.39.5 (Apple Git-154)


      reply	other threads:[~2026-04-06  6:20 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-05 22:10 [PATCH] libtraceevent: parse %pB and %pa address specifiers CaoRuichuang
2026-04-06  6:20 ` CaoRuichuang [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260406062009.57413-1-create0818@163.com \
    --to=create0818@163.com \
    --cc=linux-trace-devel@vger.kernel.org \
    --cc=rostedt@goodmis.org \
    --cc=tz.stoyanov@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox