]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/perf/util/debug.c
Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
[karo-tx-linux.git] / tools / perf / util / debug.c
1 /* For general debugging purposes */
2
3 #include "../perf.h"
4
5 #include <inttypes.h>
6 #include <string.h>
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <sys/wait.h>
10 #include <api/debug.h>
11 #include <linux/time64.h>
12 #ifdef HAVE_BACKTRACE_SUPPORT
13 #include <execinfo.h>
14 #endif
15 #include "cache.h"
16 #include "color.h"
17 #include "event.h"
18 #include "debug.h"
19 #include "print_binary.h"
20 #include "util.h"
21 #include "target.h"
22
23 #include "sane_ctype.h"
24
25 int verbose;
26 bool dump_trace = false, quiet = false;
27 int debug_ordered_events;
28 static int redirect_to_stderr;
29 int debug_data_convert;
30
31 int veprintf(int level, int var, const char *fmt, va_list args)
32 {
33         int ret = 0;
34
35         if (var >= level) {
36                 if (use_browser >= 1 && !redirect_to_stderr)
37                         ui_helpline__vshow(fmt, args);
38                 else
39                         ret = vfprintf(stderr, fmt, args);
40         }
41
42         return ret;
43 }
44
45 int eprintf(int level, int var, const char *fmt, ...)
46 {
47         va_list args;
48         int ret;
49
50         va_start(args, fmt);
51         ret = veprintf(level, var, fmt, args);
52         va_end(args);
53
54         return ret;
55 }
56
57 static int veprintf_time(u64 t, const char *fmt, va_list args)
58 {
59         int ret = 0;
60         u64 secs, usecs, nsecs = t;
61
62         secs   = nsecs / NSEC_PER_SEC;
63         nsecs -= secs  * NSEC_PER_SEC;
64         usecs  = nsecs / NSEC_PER_USEC;
65
66         ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ",
67                       secs, usecs);
68         ret += vfprintf(stderr, fmt, args);
69         return ret;
70 }
71
72 int eprintf_time(int level, int var, u64 t, const char *fmt, ...)
73 {
74         int ret = 0;
75         va_list args;
76
77         if (var >= level) {
78                 va_start(args, fmt);
79                 ret = veprintf_time(t, fmt, args);
80                 va_end(args);
81         }
82
83         return ret;
84 }
85
86 /*
87  * Overloading libtraceevent standard info print
88  * function, display with -v in perf.
89  */
90 void pr_stat(const char *fmt, ...)
91 {
92         va_list args;
93
94         va_start(args, fmt);
95         veprintf(1, verbose, fmt, args);
96         va_end(args);
97         eprintf(1, verbose, "\n");
98 }
99
100 int dump_printf(const char *fmt, ...)
101 {
102         va_list args;
103         int ret = 0;
104
105         if (dump_trace) {
106                 va_start(args, fmt);
107                 ret = vprintf(fmt, args);
108                 va_end(args);
109         }
110
111         return ret;
112 }
113
114 static void trace_event_printer(enum binary_printer_ops op,
115                                 unsigned int val, void *extra)
116 {
117         const char *color = PERF_COLOR_BLUE;
118         union perf_event *event = (union perf_event *)extra;
119         unsigned char ch = (unsigned char)val;
120
121         switch (op) {
122         case BINARY_PRINT_DATA_BEGIN:
123                 printf(".");
124                 color_fprintf(stdout, color, "\n. ... raw event: size %d bytes\n",
125                                 event->header.size);
126                 break;
127         case BINARY_PRINT_LINE_BEGIN:
128                 printf(".");
129                 break;
130         case BINARY_PRINT_ADDR:
131                 color_fprintf(stdout, color, "  %04x: ", val);
132                 break;
133         case BINARY_PRINT_NUM_DATA:
134                 color_fprintf(stdout, color, " %02x", val);
135                 break;
136         case BINARY_PRINT_NUM_PAD:
137                 color_fprintf(stdout, color, "   ");
138                 break;
139         case BINARY_PRINT_SEP:
140                 color_fprintf(stdout, color, "  ");
141                 break;
142         case BINARY_PRINT_CHAR_DATA:
143                 color_fprintf(stdout, color, "%c",
144                               isprint(ch) ? ch : '.');
145                 break;
146         case BINARY_PRINT_CHAR_PAD:
147                 color_fprintf(stdout, color, " ");
148                 break;
149         case BINARY_PRINT_LINE_END:
150                 color_fprintf(stdout, color, "\n");
151                 break;
152         case BINARY_PRINT_DATA_END:
153                 printf("\n");
154                 break;
155         default:
156                 break;
157         }
158 }
159
160 void trace_event(union perf_event *event)
161 {
162         unsigned char *raw_event = (void *)event;
163
164         if (!dump_trace)
165                 return;
166
167         print_binary(raw_event, event->header.size, 16,
168                      trace_event_printer, event);
169 }
170
171 static struct debug_variable {
172         const char *name;
173         int *ptr;
174 } debug_variables[] = {
175         { .name = "verbose",            .ptr = &verbose },
176         { .name = "ordered-events",     .ptr = &debug_ordered_events},
177         { .name = "stderr",             .ptr = &redirect_to_stderr},
178         { .name = "data-convert",       .ptr = &debug_data_convert },
179         { .name = NULL, }
180 };
181
182 int perf_debug_option(const char *str)
183 {
184         struct debug_variable *var = &debug_variables[0];
185         char *vstr, *s = strdup(str);
186         int v = 1;
187
188         vstr = strchr(s, '=');
189         if (vstr)
190                 *vstr++ = 0;
191
192         while (var->name) {
193                 if (!strcmp(s, var->name))
194                         break;
195                 var++;
196         }
197
198         if (!var->name) {
199                 pr_err("Unknown debug variable name '%s'\n", s);
200                 free(s);
201                 return -1;
202         }
203
204         if (vstr) {
205                 v = atoi(vstr);
206                 /*
207                  * Allow only values in range (0, 10),
208                  * otherwise set 0.
209                  */
210                 v = (v < 0) || (v > 10) ? 0 : v;
211         }
212
213         if (quiet)
214                 v = -1;
215
216         *var->ptr = v;
217         free(s);
218         return 0;
219 }
220
221 int perf_quiet_option(void)
222 {
223         struct debug_variable *var = &debug_variables[0];
224
225         /* disable all debug messages */
226         while (var->name) {
227                 *var->ptr = -1;
228                 var++;
229         }
230
231         quiet = true;
232         return 0;
233 }
234
235 #define DEBUG_WRAPPER(__n, __l)                         \
236 static int pr_ ## __n ## _wrapper(const char *fmt, ...) \
237 {                                                       \
238         va_list args;                                   \
239         int ret;                                        \
240                                                         \
241         va_start(args, fmt);                            \
242         ret = veprintf(__l, verbose, fmt, args);        \
243         va_end(args);                                   \
244         return ret;                                     \
245 }
246
247 DEBUG_WRAPPER(warning, 0);
248 DEBUG_WRAPPER(debug, 1);
249
250 void perf_debug_setup(void)
251 {
252         libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper);
253 }
254
255 /* Obtain a backtrace and print it to stdout. */
256 #ifdef HAVE_BACKTRACE_SUPPORT
257 void dump_stack(void)
258 {
259         void *array[16];
260         size_t size = backtrace(array, ARRAY_SIZE(array));
261         char **strings = backtrace_symbols(array, size);
262         size_t i;
263
264         printf("Obtained %zd stack frames.\n", size);
265
266         for (i = 0; i < size; i++)
267                 printf("%s\n", strings[i]);
268
269         free(strings);
270 }
271 #else
272 void dump_stack(void) {}
273 #endif
274
275 void sighandler_dump_stack(int sig)
276 {
277         psignal(sig, "perf");
278         dump_stack();
279         signal(sig, SIG_DFL);
280         raise(sig);
281 }