1cd84c2acSFrederic Weisbecker /* For general debugging purposes */ 2cd84c2acSFrederic Weisbecker 3cd84c2acSFrederic Weisbecker #include "../perf.h" 48f28827aSFrederic Weisbecker 5fd20e811SArnaldo Carvalho de Melo #include <inttypes.h> 6cd84c2acSFrederic Weisbecker #include <string.h> 7cd84c2acSFrederic Weisbecker #include <stdarg.h> 8cd84c2acSFrederic Weisbecker #include <stdio.h> 94208735dSArnaldo Carvalho de Melo #include <sys/wait.h> 10dd629cc0SJiri Olsa #include <api/debug.h> 11bd48c63eSArnaldo Carvalho de Melo #include <linux/time64.h> 128c2b7cacSArnaldo Carvalho de Melo #ifdef HAVE_BACKTRACE_SUPPORT 138c2b7cacSArnaldo Carvalho de Melo #include <execinfo.h> 148c2b7cacSArnaldo Carvalho de Melo #endif 15f9224c5cSArnaldo Carvalho de Melo #include "cache.h" 168f28827aSFrederic Weisbecker #include "color.h" 178f28827aSFrederic Weisbecker #include "event.h" 188f28827aSFrederic Weisbecker #include "debug.h" 19fea01392SArnaldo Carvalho de Melo #include "print_binary.h" 204a58e611SArnaldo Carvalho de Melo #include "util.h" 2116ad2ffbSNamhyung Kim #include "target.h" 228f28827aSFrederic Weisbecker 233d689ed6SArnaldo Carvalho de Melo #include "sane_ctype.h" 243d689ed6SArnaldo Carvalho de Melo 25b44308f5SArnaldo Carvalho de Melo int verbose; 26b44308f5SArnaldo Carvalho de Melo bool dump_trace = false, quiet = false; 27cee3ab9cSJiri Olsa int debug_ordered_events; 28f78eaef0SAndi Kleen static int redirect_to_stderr; 29edbe9817SJiri Olsa int debug_data_convert; 30cd84c2acSFrederic Weisbecker 31bedbdd42SArnaldo Carvalho de Melo int veprintf(int level, int var, const char *fmt, va_list args) 32cd84c2acSFrederic Weisbecker { 33cd84c2acSFrederic Weisbecker int ret = 0; 34cd84c2acSFrederic Weisbecker 35c95688aaSJiri Olsa if (var >= level) { 36f78eaef0SAndi Kleen if (use_browser >= 1 && !redirect_to_stderr) 37b56e5331SNamhyung Kim ui_helpline__vshow(fmt, args); 38f9224c5cSArnaldo Carvalho de Melo else 39cd84c2acSFrederic Weisbecker ret = vfprintf(stderr, fmt, args); 40cd84c2acSFrederic Weisbecker } 41cd84c2acSFrederic Weisbecker 42cd84c2acSFrederic Weisbecker return ret; 43cd84c2acSFrederic Weisbecker } 442cec19d9SFrederic Weisbecker 45c95688aaSJiri Olsa int eprintf(int level, int var, const char *fmt, ...) 46f772abc6SJiri Olsa { 47f772abc6SJiri Olsa va_list args; 48f772abc6SJiri Olsa int ret; 49f772abc6SJiri Olsa 50f772abc6SJiri Olsa va_start(args, fmt); 51bedbdd42SArnaldo Carvalho de Melo ret = veprintf(level, var, fmt, args); 52f772abc6SJiri Olsa va_end(args); 53f772abc6SJiri Olsa 54f772abc6SJiri Olsa return ret; 55f772abc6SJiri Olsa } 56f772abc6SJiri Olsa 57bedbdd42SArnaldo Carvalho de Melo static int veprintf_time(u64 t, const char *fmt, va_list args) 58cee3ab9cSJiri Olsa { 59cee3ab9cSJiri Olsa int ret = 0; 60cee3ab9cSJiri Olsa u64 secs, usecs, nsecs = t; 61cee3ab9cSJiri Olsa 62bd48c63eSArnaldo Carvalho de Melo secs = nsecs / NSEC_PER_SEC; 63bd48c63eSArnaldo Carvalho de Melo nsecs -= secs * NSEC_PER_SEC; 64bd48c63eSArnaldo Carvalho de Melo usecs = nsecs / NSEC_PER_USEC; 65cee3ab9cSJiri Olsa 66cee3ab9cSJiri Olsa ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ", 67cee3ab9cSJiri Olsa secs, usecs); 68cee3ab9cSJiri Olsa ret += vfprintf(stderr, fmt, args); 69cee3ab9cSJiri Olsa return ret; 70cee3ab9cSJiri Olsa } 71cee3ab9cSJiri Olsa 72cee3ab9cSJiri Olsa int eprintf_time(int level, int var, u64 t, const char *fmt, ...) 73cee3ab9cSJiri Olsa { 74cee3ab9cSJiri Olsa int ret = 0; 75cee3ab9cSJiri Olsa va_list args; 76cee3ab9cSJiri Olsa 77cee3ab9cSJiri Olsa if (var >= level) { 78cee3ab9cSJiri Olsa va_start(args, fmt); 79bedbdd42SArnaldo Carvalho de Melo ret = veprintf_time(t, fmt, args); 80cee3ab9cSJiri Olsa va_end(args); 81cee3ab9cSJiri Olsa } 82cee3ab9cSJiri Olsa 83cee3ab9cSJiri Olsa return ret; 84cee3ab9cSJiri Olsa } 85cee3ab9cSJiri Olsa 86f772abc6SJiri Olsa /* 87f772abc6SJiri Olsa * Overloading libtraceevent standard info print 88f772abc6SJiri Olsa * function, display with -v in perf. 89f772abc6SJiri Olsa */ 90f772abc6SJiri Olsa void pr_stat(const char *fmt, ...) 91f772abc6SJiri Olsa { 92f772abc6SJiri Olsa va_list args; 93f772abc6SJiri Olsa 94f772abc6SJiri Olsa va_start(args, fmt); 95bedbdd42SArnaldo Carvalho de Melo veprintf(1, verbose, fmt, args); 96f772abc6SJiri Olsa va_end(args); 97c95688aaSJiri Olsa eprintf(1, verbose, "\n"); 98f772abc6SJiri Olsa } 99f772abc6SJiri Olsa 1002cec19d9SFrederic Weisbecker int dump_printf(const char *fmt, ...) 1012cec19d9SFrederic Weisbecker { 1022cec19d9SFrederic Weisbecker va_list args; 1032cec19d9SFrederic Weisbecker int ret = 0; 1042cec19d9SFrederic Weisbecker 1052cec19d9SFrederic Weisbecker if (dump_trace) { 1062cec19d9SFrederic Weisbecker va_start(args, fmt); 1072cec19d9SFrederic Weisbecker ret = vprintf(fmt, args); 1082cec19d9SFrederic Weisbecker va_end(args); 1092cec19d9SFrederic Weisbecker } 1102cec19d9SFrederic Weisbecker 1112cec19d9SFrederic Weisbecker return ret; 1122cec19d9SFrederic Weisbecker } 1138f28827aSFrederic Weisbecker 114c339b1a9SWang Nan static void trace_event_printer(enum binary_printer_ops op, 115c339b1a9SWang Nan unsigned int val, void *extra) 116c339b1a9SWang Nan { 117c339b1a9SWang Nan const char *color = PERF_COLOR_BLUE; 118c339b1a9SWang Nan union perf_event *event = (union perf_event *)extra; 119c339b1a9SWang Nan unsigned char ch = (unsigned char)val; 120c339b1a9SWang Nan 121c339b1a9SWang Nan switch (op) { 122c339b1a9SWang Nan case BINARY_PRINT_DATA_BEGIN: 123c339b1a9SWang Nan printf("."); 124c339b1a9SWang Nan color_fprintf(stdout, color, "\n. ... raw event: size %d bytes\n", 125c339b1a9SWang Nan event->header.size); 126c339b1a9SWang Nan break; 127c339b1a9SWang Nan case BINARY_PRINT_LINE_BEGIN: 128c339b1a9SWang Nan printf("."); 129c339b1a9SWang Nan break; 130c339b1a9SWang Nan case BINARY_PRINT_ADDR: 131c339b1a9SWang Nan color_fprintf(stdout, color, " %04x: ", val); 132c339b1a9SWang Nan break; 133c339b1a9SWang Nan case BINARY_PRINT_NUM_DATA: 134c339b1a9SWang Nan color_fprintf(stdout, color, " %02x", val); 135c339b1a9SWang Nan break; 136c339b1a9SWang Nan case BINARY_PRINT_NUM_PAD: 137c339b1a9SWang Nan color_fprintf(stdout, color, " "); 138c339b1a9SWang Nan break; 139c339b1a9SWang Nan case BINARY_PRINT_SEP: 140c339b1a9SWang Nan color_fprintf(stdout, color, " "); 141c339b1a9SWang Nan break; 142c339b1a9SWang Nan case BINARY_PRINT_CHAR_DATA: 143c339b1a9SWang Nan color_fprintf(stdout, color, "%c", 144c339b1a9SWang Nan isprint(ch) ? ch : '.'); 145c339b1a9SWang Nan break; 146c339b1a9SWang Nan case BINARY_PRINT_CHAR_PAD: 147c339b1a9SWang Nan color_fprintf(stdout, color, " "); 148c339b1a9SWang Nan break; 149c339b1a9SWang Nan case BINARY_PRINT_LINE_END: 150c339b1a9SWang Nan color_fprintf(stdout, color, "\n"); 151c339b1a9SWang Nan break; 152c339b1a9SWang Nan case BINARY_PRINT_DATA_END: 153c339b1a9SWang Nan printf("\n"); 154c339b1a9SWang Nan break; 155c339b1a9SWang Nan default: 156c339b1a9SWang Nan break; 157c339b1a9SWang Nan } 158c339b1a9SWang Nan } 159c339b1a9SWang Nan 1608115d60cSArnaldo Carvalho de Melo void trace_event(union perf_event *event) 1618f28827aSFrederic Weisbecker { 1628f28827aSFrederic Weisbecker unsigned char *raw_event = (void *)event; 1638f28827aSFrederic Weisbecker 1648f28827aSFrederic Weisbecker if (!dump_trace) 1658f28827aSFrederic Weisbecker return; 1668f28827aSFrederic Weisbecker 167c339b1a9SWang Nan print_binary(raw_event, event->header.size, 16, 168c339b1a9SWang Nan trace_event_printer, event); 1698f28827aSFrederic Weisbecker } 170bbb2cea7SJiri Olsa 171bbb2cea7SJiri Olsa static struct debug_variable { 172bbb2cea7SJiri Olsa const char *name; 173bbb2cea7SJiri Olsa int *ptr; 174bbb2cea7SJiri Olsa } debug_variables[] = { 175bbb2cea7SJiri Olsa { .name = "verbose", .ptr = &verbose }, 176cee3ab9cSJiri Olsa { .name = "ordered-events", .ptr = &debug_ordered_events}, 177f78eaef0SAndi Kleen { .name = "stderr", .ptr = &redirect_to_stderr}, 178edbe9817SJiri Olsa { .name = "data-convert", .ptr = &debug_data_convert }, 179bbb2cea7SJiri Olsa { .name = NULL, } 180bbb2cea7SJiri Olsa }; 181bbb2cea7SJiri Olsa 182bbb2cea7SJiri Olsa int perf_debug_option(const char *str) 183bbb2cea7SJiri Olsa { 184bbb2cea7SJiri Olsa struct debug_variable *var = &debug_variables[0]; 185bbb2cea7SJiri Olsa char *vstr, *s = strdup(str); 186bbb2cea7SJiri Olsa int v = 1; 187bbb2cea7SJiri Olsa 188bbb2cea7SJiri Olsa vstr = strchr(s, '='); 189bbb2cea7SJiri Olsa if (vstr) 190bbb2cea7SJiri Olsa *vstr++ = 0; 191bbb2cea7SJiri Olsa 192bbb2cea7SJiri Olsa while (var->name) { 193bbb2cea7SJiri Olsa if (!strcmp(s, var->name)) 194bbb2cea7SJiri Olsa break; 195bbb2cea7SJiri Olsa var++; 196bbb2cea7SJiri Olsa } 197bbb2cea7SJiri Olsa 198bbb2cea7SJiri Olsa if (!var->name) { 199bbb2cea7SJiri Olsa pr_err("Unknown debug variable name '%s'\n", s); 200bbb2cea7SJiri Olsa free(s); 201bbb2cea7SJiri Olsa return -1; 202bbb2cea7SJiri Olsa } 203bbb2cea7SJiri Olsa 204bbb2cea7SJiri Olsa if (vstr) { 205bbb2cea7SJiri Olsa v = atoi(vstr); 206bbb2cea7SJiri Olsa /* 207bbb2cea7SJiri Olsa * Allow only values in range (0, 10), 208bbb2cea7SJiri Olsa * otherwise set 0. 209bbb2cea7SJiri Olsa */ 210bbb2cea7SJiri Olsa v = (v < 0) || (v > 10) ? 0 : v; 211bbb2cea7SJiri Olsa } 212bbb2cea7SJiri Olsa 21380df1988SNamhyung Kim if (quiet) 21480df1988SNamhyung Kim v = -1; 21580df1988SNamhyung Kim 216bbb2cea7SJiri Olsa *var->ptr = v; 217bbb2cea7SJiri Olsa free(s); 218bbb2cea7SJiri Olsa return 0; 219bbb2cea7SJiri Olsa } 220dd629cc0SJiri Olsa 22180df1988SNamhyung Kim int perf_quiet_option(void) 22280df1988SNamhyung Kim { 22380df1988SNamhyung Kim struct debug_variable *var = &debug_variables[0]; 22480df1988SNamhyung Kim 22580df1988SNamhyung Kim /* disable all debug messages */ 22680df1988SNamhyung Kim while (var->name) { 22780df1988SNamhyung Kim *var->ptr = -1; 22880df1988SNamhyung Kim var++; 22980df1988SNamhyung Kim } 23080df1988SNamhyung Kim 23180df1988SNamhyung Kim quiet = true; 23280df1988SNamhyung Kim return 0; 23380df1988SNamhyung Kim } 23480df1988SNamhyung Kim 235dd629cc0SJiri Olsa #define DEBUG_WRAPPER(__n, __l) \ 236dd629cc0SJiri Olsa static int pr_ ## __n ## _wrapper(const char *fmt, ...) \ 237dd629cc0SJiri Olsa { \ 238dd629cc0SJiri Olsa va_list args; \ 239dd629cc0SJiri Olsa int ret; \ 240dd629cc0SJiri Olsa \ 241dd629cc0SJiri Olsa va_start(args, fmt); \ 242dd629cc0SJiri Olsa ret = veprintf(__l, verbose, fmt, args); \ 243dd629cc0SJiri Olsa va_end(args); \ 244dd629cc0SJiri Olsa return ret; \ 245dd629cc0SJiri Olsa } 246dd629cc0SJiri Olsa 247dd629cc0SJiri Olsa DEBUG_WRAPPER(warning, 0); 248dd629cc0SJiri Olsa DEBUG_WRAPPER(debug, 1); 249dd629cc0SJiri Olsa 250dd629cc0SJiri Olsa void perf_debug_setup(void) 251dd629cc0SJiri Olsa { 252dd629cc0SJiri Olsa libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper); 253dd629cc0SJiri Olsa } 2548c2b7cacSArnaldo Carvalho de Melo 2558c2b7cacSArnaldo Carvalho de Melo /* Obtain a backtrace and print it to stdout. */ 2568c2b7cacSArnaldo Carvalho de Melo #ifdef HAVE_BACKTRACE_SUPPORT 2578c2b7cacSArnaldo Carvalho de Melo void dump_stack(void) 2588c2b7cacSArnaldo Carvalho de Melo { 2598c2b7cacSArnaldo Carvalho de Melo void *array[16]; 2608c2b7cacSArnaldo Carvalho de Melo size_t size = backtrace(array, ARRAY_SIZE(array)); 2618c2b7cacSArnaldo Carvalho de Melo char **strings = backtrace_symbols(array, size); 2628c2b7cacSArnaldo Carvalho de Melo size_t i; 2638c2b7cacSArnaldo Carvalho de Melo 2648c2b7cacSArnaldo Carvalho de Melo printf("Obtained %zd stack frames.\n", size); 2658c2b7cacSArnaldo Carvalho de Melo 2668c2b7cacSArnaldo Carvalho de Melo for (i = 0; i < size; i++) 2678c2b7cacSArnaldo Carvalho de Melo printf("%s\n", strings[i]); 2688c2b7cacSArnaldo Carvalho de Melo 2698c2b7cacSArnaldo Carvalho de Melo free(strings); 2708c2b7cacSArnaldo Carvalho de Melo } 2718c2b7cacSArnaldo Carvalho de Melo #else 2728c2b7cacSArnaldo Carvalho de Melo void dump_stack(void) {} 2738c2b7cacSArnaldo Carvalho de Melo #endif 2748c2b7cacSArnaldo Carvalho de Melo 2758c2b7cacSArnaldo Carvalho de Melo void sighandler_dump_stack(int sig) 2768c2b7cacSArnaldo Carvalho de Melo { 2778c2b7cacSArnaldo Carvalho de Melo psignal(sig, "perf"); 2788c2b7cacSArnaldo Carvalho de Melo dump_stack(); 2798c2b7cacSArnaldo Carvalho de Melo signal(sig, SIG_DFL); 2808c2b7cacSArnaldo Carvalho de Melo raise(sig); 2818c2b7cacSArnaldo Carvalho de Melo } 282