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