at v4.16 5.5 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 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 164void 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 175static 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 186int 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 225int 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 quiet = true; 236 return 0; 237} 238 239#define DEBUG_WRAPPER(__n, __l) \ 240static int pr_ ## __n ## _wrapper(const char *fmt, ...) \ 241{ \ 242 va_list args; \ 243 int ret; \ 244 \ 245 va_start(args, fmt); \ 246 ret = veprintf(__l, verbose, fmt, args); \ 247 va_end(args); \ 248 return ret; \ 249} 250 251DEBUG_WRAPPER(warning, 0); 252DEBUG_WRAPPER(debug, 1); 253 254void perf_debug_setup(void) 255{ 256 libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper); 257} 258 259/* Obtain a backtrace and print it to stdout. */ 260#ifdef HAVE_BACKTRACE_SUPPORT 261void dump_stack(void) 262{ 263 void *array[16]; 264 size_t size = backtrace(array, ARRAY_SIZE(array)); 265 char **strings = backtrace_symbols(array, size); 266 size_t i; 267 268 printf("Obtained %zd stack frames.\n", size); 269 270 for (i = 0; i < size; i++) 271 printf("%s\n", strings[i]); 272 273 free(strings); 274} 275#else 276void dump_stack(void) {} 277#endif 278 279void sighandler_dump_stack(int sig) 280{ 281 psignal(sig, "perf"); 282 dump_stack(); 283 signal(sig, SIG_DFL); 284 raise(sig); 285}