at v4.14 5.3 kB view raw
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 26int verbose; 27bool dump_trace = false, quiet = false; 28int debug_ordered_events; 29static int redirect_to_stderr; 30int debug_data_convert; 31 32int 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 46int 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 58static 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 73int 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 */ 91void 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 101int 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 115static 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 161void 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 172static 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 183int 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 222int 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) \ 237static 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 248DEBUG_WRAPPER(warning, 0); 249DEBUG_WRAPPER(debug, 1); 250 251void 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 258void 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 273void dump_stack(void) {} 274#endif 275 276void sighandler_dump_stack(int sig) 277{ 278 psignal(sig, "perf"); 279 dump_stack(); 280 signal(sig, SIG_DFL); 281 raise(sig); 282}