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