Merge tag 'staging-5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[linux-2.6-microblaze.git] / tools / lib / traceevent / plugins / plugin_function.c
1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3  * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
4  */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include "event-parse.h"
10 #include "event-utils.h"
11 #include "trace-seq.h"
12
13 static struct func_stack {
14         int size;
15         char **stack;
16 } *fstack;
17
18 static int cpus = -1;
19
20 #define STK_BLK 10
21
22 struct tep_plugin_option plugin_options[] =
23 {
24         {
25                 .name = "parent",
26                 .plugin_alias = "ftrace",
27                 .description =
28                 "Print parent of functions for function events",
29         },
30         {
31                 .name = "indent",
32                 .plugin_alias = "ftrace",
33                 .description =
34                 "Try to show function call indents, based on parents",
35                 .set = 1,
36         },
37         {
38                 .name = "offset",
39                 .plugin_alias = "ftrace",
40                 .description =
41                 "Show function names as well as their offsets",
42                 .set = 0,
43         },
44         {
45                 .name = NULL,
46         }
47 };
48
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];
52
53 static void add_child(struct func_stack *stack, const char *child, int pos)
54 {
55         int i;
56
57         if (!child)
58                 return;
59
60         if (pos < stack->size)
61                 free(stack->stack[pos]);
62         else {
63                 char **ptr;
64
65                 ptr = realloc(stack->stack, sizeof(char *) *
66                               (stack->size + STK_BLK));
67                 if (!ptr) {
68                         warning("could not allocate plugin memory\n");
69                         return;
70                 }
71
72                 stack->stack = ptr;
73
74                 for (i = stack->size; i < stack->size + STK_BLK; i++)
75                         stack->stack[i] = NULL;
76                 stack->size += STK_BLK;
77         }
78
79         stack->stack[pos] = strdup(child);
80 }
81
82 static int add_and_get_index(const char *parent, const char *child, int cpu)
83 {
84         int i;
85
86         if (cpu < 0)
87                 return 0;
88
89         if (cpu > cpus) {
90                 struct func_stack *ptr;
91
92                 ptr = realloc(fstack, sizeof(*fstack) * (cpu + 1));
93                 if (!ptr) {
94                         warning("could not allocate plugin memory\n");
95                         return 0;
96                 }
97
98                 fstack = ptr;
99
100                 /* Account for holes in the cpu count */
101                 for (i = cpus + 1; i <= cpu; i++)
102                         memset(&fstack[i], 0, sizeof(fstack[i]));
103                 cpus = cpu;
104         }
105
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);
109                         return i;
110                 }
111         }
112
113         /* Not found */
114         add_child(&fstack[cpu], parent, 0);
115         add_child(&fstack[cpu], child, 1);
116         return 0;
117 }
118
119 static void show_function(struct trace_seq *s, struct tep_handle *tep,
120                           const char *func, unsigned long long function)
121 {
122         unsigned long long offset;
123
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));
128         }
129 }
130
131 static int function_handler(struct trace_seq *s, struct tep_record *record,
132                             struct tep_event *event, void *context)
133 {
134         struct tep_handle *tep = event->tep;
135         unsigned long long function;
136         unsigned long long pfunction;
137         const char *func;
138         const char *parent;
139         int index = 0;
140
141         if (tep_get_field_val(s, event, "ip", record, &function, 1))
142                 return trace_seq_putc(s, '!');
143
144         func = tep_find_function(tep, function);
145
146         if (tep_get_field_val(s, event, "parent_ip", record, &pfunction, 1))
147                 return trace_seq_putc(s, '!');
148
149         parent = tep_find_function(tep, pfunction);
150
151         if (parent && ftrace_indent->set)
152                 index = add_and_get_index(parent, func, record->cpu);
153
154         trace_seq_printf(s, "%*s", index*3, "");
155
156         if (func)
157                 show_function(s, tep, func, function);
158         else
159                 trace_seq_printf(s, "0x%llx", function);
160
161         if (ftrace_parent->set) {
162                 trace_seq_printf(s, " <-- ");
163                 if (parent)
164                         show_function(s, tep, parent, pfunction);
165                 else
166                         trace_seq_printf(s, "0x%llx", pfunction);
167         }
168
169         return 0;
170 }
171
172 static int
173 trace_stack_handler(struct trace_seq *s, struct tep_record *record,
174                     struct tep_event *event, void *context)
175 {
176         struct tep_format_field *field;
177         unsigned long long addr;
178         const char *func;
179         int long_size;
180         void *data = record->data;
181
182         field = tep_find_any_field(event, "caller");
183         if (!field) {
184                 trace_seq_printf(s, "<CANT FIND FIELD %s>", "caller");
185                 return 0;
186         }
187
188         trace_seq_puts(s, "<stack trace >\n");
189
190         long_size = tep_get_long_size(event->tep);
191
192         for (data += field->offset; data < record->data + record->size;
193              data += long_size) {
194                 addr = tep_read_number(event->tep, data, long_size);
195
196                 if ((long_size == 8 && addr == (unsigned long long)-1) ||
197                     ((int)addr == -1))
198                         break;
199
200                 func = tep_find_function(event->tep, addr);
201                 if (func)
202                         trace_seq_printf(s, "=> %s (%llx)\n", func, addr);
203                 else
204                         trace_seq_printf(s, "=> %llx\n", addr);
205         }
206
207         return 0;
208 }
209
210 static int
211 trace_raw_data_handler(struct trace_seq *s, struct tep_record *record,
212                     struct tep_event *event, void *context)
213 {
214         struct tep_format_field *field;
215         unsigned long long id;
216         int long_size;
217         void *data = record->data;
218
219         if (tep_get_field_val(s, event, "id", record, &id, 1))
220                 return trace_seq_putc(s, '!');
221
222         trace_seq_printf(s, "# %llx", id);
223
224         field = tep_find_any_field(event, "buf");
225         if (!field) {
226                 trace_seq_printf(s, "<CANT FIND FIELD %s>", "buf");
227                 return 0;
228         }
229
230         long_size = tep_get_long_size(event->tep);
231
232         for (data += field->offset; data < record->data + record->size;
233              data += long_size) {
234                 int size = sizeof(long);
235                 int left = (record->data + record->size) - data;
236                 int i;
237
238                 if (size > left)
239                         size = left;
240
241                 for (i = 0; i < size; i++)
242                         trace_seq_printf(s, " %02x", *(unsigned char *)(data + i));
243         }
244
245         return 0;
246 }
247
248 int TEP_PLUGIN_LOADER(struct tep_handle *tep)
249 {
250         tep_register_event_handler(tep, -1, "ftrace", "function",
251                                    function_handler, NULL);
252
253         tep_register_event_handler(tep, -1, "ftrace", "kernel_stack",
254                                       trace_stack_handler, NULL);
255
256         tep_register_event_handler(tep, -1, "ftrace", "raw_data",
257                                       trace_raw_data_handler, NULL);
258
259         tep_plugin_add_options("ftrace", plugin_options);
260
261         return 0;
262 }
263
264 void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
265 {
266         int i, x;
267
268         tep_unregister_event_handler(tep, -1, "ftrace", "function",
269                                      function_handler, NULL);
270
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);
275         }
276
277         tep_plugin_remove_options(plugin_options);
278
279         free(fstack);
280         fstack = NULL;
281         cpus = -1;
282 }