[PATCH] libtraceevent: Handle __get_stacktrace()
Steven Rostedt <[email protected]> Mon, 29 Dec 2025 20:02:23 -0500
| Newsgroups | org.kernel.vger.linux-trace-devel |
|---|---|
| Message-ID | <[email protected]> |
From: "Steven Rostedt (Google)" <[email protected]> A synthetic event can add a stacktrace as one of its fields. The print fmt of getting to the stacktrace field is the __get_stacktrace() function helper. Add support for parsing the __get_stacktrace() so that it properly displays the stacktrace of synthetic events. Link: https://lore.kernel.org/all/aVG2VoBpFoEEE1gG@krava/ Signed-off-by: Steven Rostedt (Google) <[email protected]> --- include/traceevent/event-parse.h | 7 +++ src/event-parse.c | 76 ++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/include/traceevent/event-parse.h b/include/traceevent/event-parse.h index ebfc2c7abac2..9c1abfae28d9 100644 --- a/include/traceevent/event-parse.h +++ b/include/traceevent/event-parse.h @@ -138,6 +138,11 @@ struct tep_print_arg_bitmask { struct tep_format_field *field; }; +struct tep_print_arg_stacktrace { + char *stacktrace; + struct tep_format_field *field; +}; + struct tep_print_arg_field { char *name; struct tep_format_field *field; @@ -215,6 +220,7 @@ enum tep_print_arg_type { TEP_PRINT_DYNAMIC_ARRAY_LEN, TEP_PRINT_HEX_STR, TEP_PRINT_CPUMASK, + TEP_PRINT_STACKTRACE, }; struct tep_print_arg { @@ -231,6 +237,7 @@ struct tep_print_arg { struct tep_print_arg_func func; struct tep_print_arg_string string; struct tep_print_arg_bitmask bitmask; + struct tep_print_arg_stacktrace stacktrace; struct tep_print_arg_op op; struct tep_print_arg_dynarray dynarray; }; diff --git a/src/event-parse.c b/src/event-parse.c index 939b0a8fbdf2..09d9092d9d20 100644 --- a/src/event-parse.c +++ b/src/event-parse.c @@ -1129,6 +1129,9 @@ static void free_arg(struct tep_print_arg *arg) free_arg(arg->op.left); free_arg(arg->op.right); break; + case TEP_PRINT_STACKTRACE: + free(arg->stacktrace.stacktrace); + break; case TEP_PRINT_FUNC: while (arg->func.args) { farg = arg->func.args; @@ -2895,6 +2898,7 @@ static int arg_num_eval(struct tep_print_arg *arg, long long *val) case TEP_PRINT_BSTRING: case TEP_PRINT_BITMASK: case TEP_PRINT_CPUMASK: + case TEP_PRINT_STACKTRACE: default: do_warning("invalid eval type %d", arg->type); ret = 0; @@ -2925,6 +2929,7 @@ static char *arg_eval (struct tep_print_arg *arg) case TEP_PRINT_BSTRING: case TEP_PRINT_BITMASK: case TEP_PRINT_CPUMASK: + case TEP_PRINT_STACKTRACE: default: do_warning("invalid eval type %d", arg->type); break; @@ -3462,6 +3467,34 @@ process_cpumask(struct tep_event *event __maybe_unused, struct tep_print_arg *ar return type; } +static enum tep_event_type +process_stacktrace(struct tep_event *event, struct tep_print_arg *arg, char **tok) +{ + enum tep_event_type type; + char *token; + + if (read_expect_type(event->tep, TEP_EVENT_ITEM, &token) < 0) + goto out_free; + + arg->type = TEP_PRINT_STACKTRACE; + arg->stacktrace.stacktrace = token; + arg->stacktrace.field = NULL; + + if (read_expected(event->tep, TEP_EVENT_DELIM, ")") < 0) + goto out_err; + + type = read_token(event->tep, &token); + *tok = token; + + return type; + + out_free: + free_token(token); + out_err: + *tok = NULL; + return TEP_EVENT_ERROR; +} + static struct tep_function_handler * find_func_handler(struct tep_handle *tep, char *func_name) { @@ -3750,6 +3783,10 @@ process_function(struct tep_event *event, struct tep_print_arg *arg, free_token(token); return process_dynamic_array_len(event, arg, tok); } + if (strcmp(token, "__get_stacktrace") == 0) { + free_token(token); + return process_stacktrace(event, arg, tok); + } if (strcmp(token, "__builtin_expect") == 0) { free_token(token); return process_builtin_expect(event, arg, tok); @@ -4414,6 +4451,7 @@ eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg case TEP_PRINT_BSTRING: case TEP_PRINT_BITMASK: case TEP_PRINT_CPUMASK: + case TEP_PRINT_STACKTRACE: return 0; case TEP_PRINT_FUNC: { struct trace_seq s; @@ -4859,6 +4897,33 @@ more: free(str); } +static void print_stacktrace_to_seq(struct tep_handle *tep, + struct trace_seq *s, const char *format, + int len_arg, const void *data, int size) +{ + int nr_funcs = size / tep->long_size; + struct func_map *func; + unsigned long long val; + + trace_seq_putc(s, '\n'); + + /* The first entry is a counter, skip it */ + data += tep->long_size; + + for (int i = 1; i < nr_funcs; i++) { + trace_seq_puts(s, "=> "); + val = tep_read_number(tep, data, tep->long_size); + func = find_func(tep, val); + if (func) { + trace_seq_puts(s, func->func); + trace_seq_printf(s, "+0x%llx\n", val - func->addr); + } else { + trace_seq_printf(s, "%llx\n", val); + } + data += tep->long_size; + } +} + static void print_str_arg(struct trace_seq *s, void *data, int size, struct tep_event *event, const char *format, int len_arg, struct tep_print_arg *arg) @@ -5097,6 +5162,17 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, data + offset, len); break; } + case TEP_PRINT_STACKTRACE: { + if (!arg->stacktrace.field) { + arg->stacktrace.field = tep_find_any_field(event, arg->stacktrace.stacktrace); + if (!arg->stacktrace.field) + break; + } + dynamic_offset_field(tep, arg->stacktrace.field, data, size, &offset, &len); + print_stacktrace_to_seq(tep, s, format, len_arg, + data + offset, len); + break; + } case TEP_PRINT_OP: /* * The only op for string should be ? : -- 2.51.0