1 // SPDX-License-Identifier: GPL-2.0 2 /* For general debugging purposes */ 3 4 #include <inttypes.h> 5 #include <string.h> 6 #include <stdarg.h> 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <sys/wait.h> 10 #include <api/debug.h> 11 #include <linux/kernel.h> 12 #include <linux/time64.h> 13 #ifdef HAVE_BACKTRACE_SUPPORT 14 #include <execinfo.h> 15 #endif 16 #include "color.h" 17 #include "event.h" 18 #include "debug.h" 19 #include "print_binary.h" 20 #include "target.h" 21 #include "ui/helpline.h" 22 #include "ui/ui.h" 23 24 #include <linux/ctype.h> 25 26 int verbose; 27 bool dump_trace = false, quiet = false; 28 int debug_ordered_events; 29 static int redirect_to_stderr; 30 int debug_data_convert; 31 32 int veprintf(int level, int var, const char *fmt, va_list args) 33 { 34 int ret = 0; 35 36 if (var >= level) { 37 if (use_browser >= 1 && !redirect_to_stderr) 38 ui_helpline__vshow(fmt, args); 39 else 40 ret = vfprintf(stderr, fmt, args); 41 } 42 43 return ret; 44 } 45 46 int eprintf(int level, int var, const char *fmt, ...) 47 { 48 va_list args; 49 int ret; 50 51 va_start(args, fmt); 52 ret = veprintf(level, var, fmt, args); 53 va_end(args); 54 55 return ret; 56 } 57 58 static int veprintf_time(u64 t, const char *fmt, va_list args) 59 { 60 int ret = 0; 61 u64 secs, usecs, nsecs = t; 62 63 secs = nsecs / NSEC_PER_SEC; 64 nsecs -= secs * NSEC_PER_SEC; 65 usecs = nsecs / NSEC_PER_USEC; 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); 80 ret = veprintf_time(t, fmt, args); 81 va_end(args); 82 } 83 84 return ret; 85 } 86 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); 96 veprintf(1, verbose, fmt, args); 97 va_end(args); 98 eprintf(1, verbose, "\n"); 99 } 100 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 } 114 115 static int trace_event_printer(enum binary_printer_ops op, 116 unsigned int val, void *extra, FILE *fp) 117 { 118 const char *color = PERF_COLOR_BLUE; 119 union perf_event *event = (union perf_event *)extra; 120 unsigned char ch = (unsigned char)val; 121 int printed = 0; 122 123 switch (op) { 124 case BINARY_PRINT_DATA_BEGIN: 125 printed += fprintf(fp, "."); 126 printed += color_fprintf(fp, color, "\n. ... raw event: size %d bytes\n", 127 event->header.size); 128 break; 129 case BINARY_PRINT_LINE_BEGIN: 130 printed += fprintf(fp, "."); 131 break; 132 case BINARY_PRINT_ADDR: 133 printed += color_fprintf(fp, color, " %04x: ", val); 134 break; 135 case BINARY_PRINT_NUM_DATA: 136 printed += color_fprintf(fp, color, " %02x", val); 137 break; 138 case BINARY_PRINT_NUM_PAD: 139 printed += color_fprintf(fp, color, " "); 140 break; 141 case BINARY_PRINT_SEP: 142 printed += color_fprintf(fp, color, " "); 143 break; 144 case BINARY_PRINT_CHAR_DATA: 145 printed += color_fprintf(fp, color, "%c", 146 isprint(ch) ? ch : '.'); 147 break; 148 case BINARY_PRINT_CHAR_PAD: 149 printed += color_fprintf(fp, color, " "); 150 break; 151 case BINARY_PRINT_LINE_END: 152 printed += color_fprintf(fp, color, "\n"); 153 break; 154 case BINARY_PRINT_DATA_END: 155 printed += fprintf(fp, "\n"); 156 break; 157 default: 158 break; 159 } 160 161 return printed; 162 } 163 164 void trace_event(union perf_event *event) 165 { 166 unsigned char *raw_event = (void *)event; 167 168 if (!dump_trace) 169 return; 170 171 print_binary(raw_event, event->header.size, 16, 172 trace_event_printer, event); 173 } 174 175 static struct debug_variable { 176 const char *name; 177 int *ptr; 178 } debug_variables[] = { 179 { .name = "verbose", .ptr = &verbose }, 180 { .name = "ordered-events", .ptr = &debug_ordered_events}, 181 { .name = "stderr", .ptr = &redirect_to_stderr}, 182 { .name = "data-convert", .ptr = &debug_data_convert }, 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 217 if (quiet) 218 v = -1; 219 220 *var->ptr = v; 221 free(s); 222 return 0; 223 } 224 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 235 return 0; 236 } 237 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 } 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 } 285