1 // SPDX-License-Identifier: LGPL-2.1
3 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
9 #include "event-parse.h"
10 #include "event-utils.h"
11 #include "trace-seq.h"
13 static struct func_stack
{
22 struct tep_plugin_option plugin_options
[] =
26 .plugin_alias
= "ftrace",
28 "Print parent of functions for function events",
32 .plugin_alias
= "ftrace",
34 "Try to show function call indents, based on parents",
39 .plugin_alias
= "ftrace",
41 "Show function names as well as their offsets",
49 static struct tep_plugin_option
*ftrace_parent
= &plugin_options
[0];
50 static struct tep_plugin_option
*ftrace_indent
= &plugin_options
[1];
51 static struct tep_plugin_option
*ftrace_offset
= &plugin_options
[2];
53 static void add_child(struct func_stack
*stack
, const char *child
, int pos
)
60 if (pos
< stack
->size
)
61 free(stack
->stack
[pos
]);
65 ptr
= realloc(stack
->stack
, sizeof(char *) *
66 (stack
->size
+ STK_BLK
));
68 warning("could not allocate plugin memory\n");
74 for (i
= stack
->size
; i
< stack
->size
+ STK_BLK
; i
++)
75 stack
->stack
[i
] = NULL
;
76 stack
->size
+= STK_BLK
;
79 stack
->stack
[pos
] = strdup(child
);
82 static int add_and_get_index(const char *parent
, const char *child
, int cpu
)
90 struct func_stack
*ptr
;
92 ptr
= realloc(fstack
, sizeof(*fstack
) * (cpu
+ 1));
94 warning("could not allocate plugin memory\n");
100 /* Account for holes in the cpu count */
101 for (i
= cpus
+ 1; i
<= cpu
; i
++)
102 memset(&fstack
[i
], 0, sizeof(fstack
[i
]));
106 for (i
= 0; i
< fstack
[cpu
].size
&& fstack
[cpu
].stack
[i
]; i
++) {
107 if (strcmp(parent
, fstack
[cpu
].stack
[i
]) == 0) {
108 add_child(&fstack
[cpu
], child
, i
+1);
114 add_child(&fstack
[cpu
], parent
, 0);
115 add_child(&fstack
[cpu
], child
, 1);
119 static void show_function(struct trace_seq
*s
, struct tep_handle
*tep
,
120 const char *func
, unsigned long long function
)
122 unsigned long long offset
;
124 trace_seq_printf(s
, "%s", func
);
125 if (ftrace_offset
->set
) {
126 offset
= tep_find_function_address(tep
, function
);
127 trace_seq_printf(s
, "+0x%x ", (int)(function
- offset
));
131 static int function_handler(struct trace_seq
*s
, struct tep_record
*record
,
132 struct tep_event
*event
, void *context
)
134 struct tep_handle
*tep
= event
->tep
;
135 unsigned long long function
;
136 unsigned long long pfunction
;
141 if (tep_get_field_val(s
, event
, "ip", record
, &function
, 1))
142 return trace_seq_putc(s
, '!');
144 func
= tep_find_function(tep
, function
);
146 if (tep_get_field_val(s
, event
, "parent_ip", record
, &pfunction
, 1))
147 return trace_seq_putc(s
, '!');
149 parent
= tep_find_function(tep
, pfunction
);
151 if (parent
&& ftrace_indent
->set
)
152 index
= add_and_get_index(parent
, func
, record
->cpu
);
154 trace_seq_printf(s
, "%*s", index
*3, "");
157 show_function(s
, tep
, func
, function
);
159 trace_seq_printf(s
, "0x%llx", function
);
161 if (ftrace_parent
->set
) {
162 trace_seq_printf(s
, " <-- ");
164 show_function(s
, tep
, parent
, pfunction
);
166 trace_seq_printf(s
, "0x%llx", pfunction
);
173 trace_stack_handler(struct trace_seq
*s
, struct tep_record
*record
,
174 struct tep_event
*event
, void *context
)
176 struct tep_format_field
*field
;
177 unsigned long long addr
;
180 void *data
= record
->data
;
182 field
= tep_find_any_field(event
, "caller");
184 trace_seq_printf(s
, "<CANT FIND FIELD %s>", "caller");
188 trace_seq_puts(s
, "<stack trace >\n");
190 long_size
= tep_get_long_size(event
->tep
);
192 for (data
+= field
->offset
; data
< record
->data
+ record
->size
;
194 addr
= tep_read_number(event
->tep
, data
, long_size
);
196 if ((long_size
== 8 && addr
== (unsigned long long)-1) ||
200 func
= tep_find_function(event
->tep
, addr
);
202 trace_seq_printf(s
, "=> %s (%llx)\n", func
, addr
);
204 trace_seq_printf(s
, "=> %llx\n", addr
);
211 trace_raw_data_handler(struct trace_seq
*s
, struct tep_record
*record
,
212 struct tep_event
*event
, void *context
)
214 struct tep_format_field
*field
;
215 unsigned long long id
;
217 void *data
= record
->data
;
219 if (tep_get_field_val(s
, event
, "id", record
, &id
, 1))
220 return trace_seq_putc(s
, '!');
222 trace_seq_printf(s
, "# %llx", id
);
224 field
= tep_find_any_field(event
, "buf");
226 trace_seq_printf(s
, "<CANT FIND FIELD %s>", "buf");
230 long_size
= tep_get_long_size(event
->tep
);
232 for (data
+= field
->offset
; data
< record
->data
+ record
->size
;
234 int size
= sizeof(long);
235 int left
= (record
->data
+ record
->size
) - data
;
241 for (i
= 0; i
< size
; i
++)
242 trace_seq_printf(s
, " %02x", *(unsigned char *)(data
+ i
));
248 int TEP_PLUGIN_LOADER(struct tep_handle
*tep
)
250 tep_register_event_handler(tep
, -1, "ftrace", "function",
251 function_handler
, NULL
);
253 tep_register_event_handler(tep
, -1, "ftrace", "kernel_stack",
254 trace_stack_handler
, NULL
);
256 tep_register_event_handler(tep
, -1, "ftrace", "raw_data",
257 trace_raw_data_handler
, NULL
);
259 tep_plugin_add_options("ftrace", plugin_options
);
264 void TEP_PLUGIN_UNLOADER(struct tep_handle
*tep
)
268 tep_unregister_event_handler(tep
, -1, "ftrace", "function",
269 function_handler
, NULL
);
271 for (i
= 0; i
<= cpus
; i
++) {
272 for (x
= 0; x
< fstack
[i
].size
&& fstack
[i
].stack
[x
]; x
++)
273 free(fstack
[i
].stack
[x
]);
274 free(fstack
[i
].stack
);
277 tep_plugin_remove_options(plugin_options
);