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 #include <sys/time.h> 14 #ifdef HAVE_BACKTRACE_SUPPORT 15 #include <execinfo.h> 16 #endif 17 #include "color.h" 18 #include "event.h" 19 #include "debug.h" 20 #include "print_binary.h" 21 #include "target.h" 22 #include "ui/helpline.h" 23 #include "ui/ui.h" 24 #include "util/parse-sublevel-options.h" 25 26 #include <linux/ctype.h> 27 #include <traceevent/event-parse.h> 28 29 #define MAKE_LIBTRACEEVENT_VERSION(a, b, c) ((a)*255*255+(b)*255+(c)) 30 #ifndef LIBTRACEEVENT_VERSION 31 /* 32 * If LIBTRACEEVENT_VERSION wasn't computed then set to version 1.1.0 that ships 33 * with the Linux kernel tools. 34 */ 35 #define LIBTRACEEVENT_VERSION MAKE_LIBTRACEEVENT_VERSION(1, 1, 0) 36 #endif 37 38 int verbose; 39 int debug_peo_args; 40 bool dump_trace = false, quiet = false; 41 int debug_ordered_events; 42 static int redirect_to_stderr; 43 int debug_data_convert; 44 static FILE *debug_file; 45 bool debug_display_time; 46 47 void debug_set_file(FILE *file) 48 { 49 debug_file = file; 50 } 51 52 void debug_set_display_time(bool set) 53 { 54 debug_display_time = set; 55 } 56 57 static int fprintf_time(FILE *file) 58 { 59 struct timeval tod; 60 struct tm ltime; 61 char date[64]; 62 63 if (!debug_display_time) 64 return 0; 65 66 if (gettimeofday(&tod, NULL) != 0) 67 return 0; 68 69 if (localtime_r(&tod.tv_sec, <ime) == NULL) 70 return 0; 71 72 strftime(date, sizeof(date), "%F %H:%M:%S", <ime); 73 return fprintf(file, "[%s.%06lu] ", date, (long)tod.tv_usec); 74 } 75 76 int veprintf(int level, int var, const char *fmt, va_list args) 77 { 78 int ret = 0; 79 80 if (var >= level) { 81 if (use_browser >= 1 && !redirect_to_stderr) { 82 ui_helpline__vshow(fmt, args); 83 } else { 84 ret = fprintf_time(debug_file); 85 ret += vfprintf(debug_file, fmt, args); 86 } 87 } 88 89 return ret; 90 } 91 92 int eprintf(int level, int var, const char *fmt, ...) 93 { 94 va_list args; 95 int ret; 96 97 va_start(args, fmt); 98 ret = veprintf(level, var, fmt, args); 99 va_end(args); 100 101 return ret; 102 } 103 104 static int veprintf_time(u64 t, const char *fmt, va_list args) 105 { 106 int ret = 0; 107 u64 secs, usecs, nsecs = t; 108 109 secs = nsecs / NSEC_PER_SEC; 110 nsecs -= secs * NSEC_PER_SEC; 111 usecs = nsecs / NSEC_PER_USEC; 112 113 ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ", 114 secs, usecs); 115 ret += vfprintf(stderr, fmt, args); 116 return ret; 117 } 118 119 int eprintf_time(int level, int var, u64 t, const char *fmt, ...) 120 { 121 int ret = 0; 122 va_list args; 123 124 if (var >= level) { 125 va_start(args, fmt); 126 ret = veprintf_time(t, fmt, args); 127 va_end(args); 128 } 129 130 return ret; 131 } 132 133 /* 134 * Overloading libtraceevent standard info print 135 * function, display with -v in perf. 136 */ 137 void pr_stat(const char *fmt, ...) 138 { 139 va_list args; 140 141 va_start(args, fmt); 142 veprintf(1, verbose, fmt, args); 143 va_end(args); 144 eprintf(1, verbose, "\n"); 145 } 146 147 int dump_printf(const char *fmt, ...) 148 { 149 va_list args; 150 int ret = 0; 151 152 if (dump_trace) { 153 va_start(args, fmt); 154 ret = vprintf(fmt, args); 155 va_end(args); 156 } 157 158 return ret; 159 } 160 161 static int trace_event_printer(enum binary_printer_ops op, 162 unsigned int val, void *extra, FILE *fp) 163 { 164 const char *color = PERF_COLOR_BLUE; 165 union perf_event *event = (union perf_event *)extra; 166 unsigned char ch = (unsigned char)val; 167 int printed = 0; 168 169 switch (op) { 170 case BINARY_PRINT_DATA_BEGIN: 171 printed += fprintf(fp, "."); 172 printed += color_fprintf(fp, color, "\n. ... raw event: size %d bytes\n", 173 event->header.size); 174 break; 175 case BINARY_PRINT_LINE_BEGIN: 176 printed += fprintf(fp, "."); 177 break; 178 case BINARY_PRINT_ADDR: 179 printed += color_fprintf(fp, color, " %04x: ", val); 180 break; 181 case BINARY_PRINT_NUM_DATA: 182 printed += color_fprintf(fp, color, " %02x", val); 183 break; 184 case BINARY_PRINT_NUM_PAD: 185 printed += color_fprintf(fp, color, " "); 186 break; 187 case BINARY_PRINT_SEP: 188 printed += color_fprintf(fp, color, " "); 189 break; 190 case BINARY_PRINT_CHAR_DATA: 191 printed += color_fprintf(fp, color, "%c", 192 isprint(ch) ? ch : '.'); 193 break; 194 case BINARY_PRINT_CHAR_PAD: 195 printed += color_fprintf(fp, color, " "); 196 break; 197 case BINARY_PRINT_LINE_END: 198 printed += color_fprintf(fp, color, "\n"); 199 break; 200 case BINARY_PRINT_DATA_END: 201 printed += fprintf(fp, "\n"); 202 break; 203 default: 204 break; 205 } 206 207 return printed; 208 } 209 210 void trace_event(union perf_event *event) 211 { 212 unsigned char *raw_event = (void *)event; 213 214 if (!dump_trace) 215 return; 216 217 print_binary(raw_event, event->header.size, 16, 218 trace_event_printer, event); 219 } 220 221 static struct sublevel_option debug_opts[] = { 222 { .name = "verbose", .value_ptr = &verbose }, 223 { .name = "ordered-events", .value_ptr = &debug_ordered_events}, 224 { .name = "stderr", .value_ptr = &redirect_to_stderr}, 225 { .name = "data-convert", .value_ptr = &debug_data_convert }, 226 { .name = "perf-event-open", .value_ptr = &debug_peo_args }, 227 { .name = NULL, } 228 }; 229 230 int perf_debug_option(const char *str) 231 { 232 int ret; 233 234 ret = perf_parse_sublevel_options(str, debug_opts); 235 if (ret) 236 return ret; 237 238 /* Allow only verbose value in range (0, 10), otherwise set 0. */ 239 verbose = (verbose < 0) || (verbose > 10) ? 0 : verbose; 240 241 #if MAKE_LIBTRACEEVENT_VERSION(1, 3, 0) <= LIBTRACEEVENT_VERSION 242 if (verbose == 1) 243 tep_set_loglevel(TEP_LOG_INFO); 244 else if (verbose == 2) 245 tep_set_loglevel(TEP_LOG_DEBUG); 246 else if (verbose >= 3) 247 tep_set_loglevel(TEP_LOG_ALL); 248 #endif 249 250 return 0; 251 } 252 253 int perf_quiet_option(void) 254 { 255 struct sublevel_option *opt = &debug_opts[0]; 256 257 /* disable all debug messages */ 258 while (opt->name) { 259 *opt->value_ptr = -1; 260 opt++; 261 } 262 263 return 0; 264 } 265 266 #define DEBUG_WRAPPER(__n, __l) \ 267 static int pr_ ## __n ## _wrapper(const char *fmt, ...) \ 268 { \ 269 va_list args; \ 270 int ret; \ 271 \ 272 va_start(args, fmt); \ 273 ret = veprintf(__l, verbose, fmt, args); \ 274 va_end(args); \ 275 return ret; \ 276 } 277 278 DEBUG_WRAPPER(warning, 0); 279 DEBUG_WRAPPER(debug, 1); 280 281 void perf_debug_setup(void) 282 { 283 debug_set_file(stderr); 284 libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper); 285 } 286 287 /* Obtain a backtrace and print it to stdout. */ 288 #ifdef HAVE_BACKTRACE_SUPPORT 289 void dump_stack(void) 290 { 291 void *array[16]; 292 size_t size = backtrace(array, ARRAY_SIZE(array)); 293 char **strings = backtrace_symbols(array, size); 294 size_t i; 295 296 printf("Obtained %zd stack frames.\n", size); 297 298 for (i = 0; i < size; i++) 299 printf("%s\n", strings[i]); 300 301 free(strings); 302 } 303 #else 304 void dump_stack(void) {} 305 #endif 306 307 void sighandler_dump_stack(int sig) 308 { 309 psignal(sig, "perf"); 310 dump_stack(); 311 signal(sig, SIG_DFL); 312 raise(sig); 313 } 314