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 <sys/wait.h> 11 #include <api/debug.h> 12 #include <linux/time64.h> 13 #ifdef HAVE_BACKTRACE_SUPPORT 14 #include <execinfo.h> 15 #endif 16 #include "cache.h" 17 #include "color.h" 18 #include "event.h" 19 #include "debug.h" 20 #include "print_binary.h" 21 #include "util.h" 22 #include "target.h" 23 24 #include "sane_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 void trace_event_printer(enum binary_printer_ops op, 116 unsigned int val, void *extra) 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 122 switch (op) { 123 case BINARY_PRINT_DATA_BEGIN: 124 printf("."); 125 color_fprintf(stdout, color, "\n. ... raw event: size %d bytes\n", 126 event->header.size); 127 break; 128 case BINARY_PRINT_LINE_BEGIN: 129 printf("."); 130 break; 131 case BINARY_PRINT_ADDR: 132 color_fprintf(stdout, color, " %04x: ", val); 133 break; 134 case BINARY_PRINT_NUM_DATA: 135 color_fprintf(stdout, color, " %02x", val); 136 break; 137 case BINARY_PRINT_NUM_PAD: 138 color_fprintf(stdout, color, " "); 139 break; 140 case BINARY_PRINT_SEP: 141 color_fprintf(stdout, color, " "); 142 break; 143 case BINARY_PRINT_CHAR_DATA: 144 color_fprintf(stdout, color, "%c", 145 isprint(ch) ? ch : '.'); 146 break; 147 case BINARY_PRINT_CHAR_PAD: 148 color_fprintf(stdout, color, " "); 149 break; 150 case BINARY_PRINT_LINE_END: 151 color_fprintf(stdout, color, "\n"); 152 break; 153 case BINARY_PRINT_DATA_END: 154 printf("\n"); 155 break; 156 default: 157 break; 158 } 159 } 160 161 void trace_event(union perf_event *event) 162 { 163 unsigned char *raw_event = (void *)event; 164 165 if (!dump_trace) 166 return; 167 168 print_binary(raw_event, event->header.size, 16, 169 trace_event_printer, event); 170 } 171 172 static struct debug_variable { 173 const char *name; 174 int *ptr; 175 } debug_variables[] = { 176 { .name = "verbose", .ptr = &verbose }, 177 { .name = "ordered-events", .ptr = &debug_ordered_events}, 178 { .name = "stderr", .ptr = &redirect_to_stderr}, 179 { .name = "data-convert", .ptr = &debug_data_convert }, 180 { .name = NULL, } 181 }; 182 183 int perf_debug_option(const char *str) 184 { 185 struct debug_variable *var = &debug_variables[0]; 186 char *vstr, *s = strdup(str); 187 int v = 1; 188 189 vstr = strchr(s, '='); 190 if (vstr) 191 *vstr++ = 0; 192 193 while (var->name) { 194 if (!strcmp(s, var->name)) 195 break; 196 var++; 197 } 198 199 if (!var->name) { 200 pr_err("Unknown debug variable name '%s'\n", s); 201 free(s); 202 return -1; 203 } 204 205 if (vstr) { 206 v = atoi(vstr); 207 /* 208 * Allow only values in range (0, 10), 209 * otherwise set 0. 210 */ 211 v = (v < 0) || (v > 10) ? 0 : v; 212 } 213 214 if (quiet) 215 v = -1; 216 217 *var->ptr = v; 218 free(s); 219 return 0; 220 } 221 222 int perf_quiet_option(void) 223 { 224 struct debug_variable *var = &debug_variables[0]; 225 226 /* disable all debug messages */ 227 while (var->name) { 228 *var->ptr = -1; 229 var++; 230 } 231 232 quiet = true; 233 return 0; 234 } 235 236 #define DEBUG_WRAPPER(__n, __l) \ 237 static int pr_ ## __n ## _wrapper(const char *fmt, ...) \ 238 { \ 239 va_list args; \ 240 int ret; \ 241 \ 242 va_start(args, fmt); \ 243 ret = veprintf(__l, verbose, fmt, args); \ 244 va_end(args); \ 245 return ret; \ 246 } 247 248 DEBUG_WRAPPER(warning, 0); 249 DEBUG_WRAPPER(debug, 1); 250 251 void perf_debug_setup(void) 252 { 253 libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper); 254 } 255 256 /* Obtain a backtrace and print it to stdout. */ 257 #ifdef HAVE_BACKTRACE_SUPPORT 258 void dump_stack(void) 259 { 260 void *array[16]; 261 size_t size = backtrace(array, ARRAY_SIZE(array)); 262 char **strings = backtrace_symbols(array, size); 263 size_t i; 264 265 printf("Obtained %zd stack frames.\n", size); 266 267 for (i = 0; i < size; i++) 268 printf("%s\n", strings[i]); 269 270 free(strings); 271 } 272 #else 273 void dump_stack(void) {} 274 #endif 275 276 void sighandler_dump_stack(int sig) 277 { 278 psignal(sig, "perf"); 279 dump_stack(); 280 signal(sig, SIG_DFL); 281 raise(sig); 282 } 283