1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2cd84c2acSFrederic Weisbecker /* For general debugging purposes */ 3cd84c2acSFrederic Weisbecker 4fd20e811SArnaldo Carvalho de Melo #include <inttypes.h> 5cd84c2acSFrederic Weisbecker #include <string.h> 6cd84c2acSFrederic Weisbecker #include <stdarg.h> 7cd84c2acSFrederic Weisbecker #include <stdio.h> 8215a0d30SArnaldo Carvalho de Melo #include <stdlib.h> 94208735dSArnaldo Carvalho de Melo #include <sys/wait.h> 10dd629cc0SJiri Olsa #include <api/debug.h> 114cb3c6d5SArnaldo Carvalho de Melo #include <linux/kernel.h> 12bd48c63eSArnaldo Carvalho de Melo #include <linux/time64.h> 138c2b7cacSArnaldo Carvalho de Melo #ifdef HAVE_BACKTRACE_SUPPORT 148c2b7cacSArnaldo Carvalho de Melo #include <execinfo.h> 158c2b7cacSArnaldo Carvalho de Melo #endif 168f28827aSFrederic Weisbecker #include "color.h" 178f28827aSFrederic Weisbecker #include "event.h" 188f28827aSFrederic Weisbecker #include "debug.h" 19fea01392SArnaldo Carvalho de Melo #include "print_binary.h" 2016ad2ffbSNamhyung Kim #include "target.h" 218520a98dSArnaldo Carvalho de Melo #include "ui/helpline.h" 22fa0d9846SArnaldo Carvalho de Melo #include "ui/ui.h" 238f28827aSFrederic Weisbecker 243052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h> 253d689ed6SArnaldo Carvalho de Melo 26b44308f5SArnaldo Carvalho de Melo int verbose; 27ccd26741SRavi Bangoria int debug_peo_args; 28b44308f5SArnaldo Carvalho de Melo bool dump_trace = false, quiet = false; 29cee3ab9cSJiri Olsa int debug_ordered_events; 30f78eaef0SAndi Kleen static int redirect_to_stderr; 31edbe9817SJiri Olsa int debug_data_convert; 32cd84c2acSFrederic Weisbecker 33bedbdd42SArnaldo Carvalho de Melo int veprintf(int level, int var, const char *fmt, va_list args) 34cd84c2acSFrederic Weisbecker { 35cd84c2acSFrederic Weisbecker int ret = 0; 36cd84c2acSFrederic Weisbecker 37c95688aaSJiri Olsa if (var >= level) { 38f78eaef0SAndi Kleen if (use_browser >= 1 && !redirect_to_stderr) 39b56e5331SNamhyung Kim ui_helpline__vshow(fmt, args); 40f9224c5cSArnaldo Carvalho de Melo else 41cd84c2acSFrederic Weisbecker ret = vfprintf(stderr, fmt, args); 42cd84c2acSFrederic Weisbecker } 43cd84c2acSFrederic Weisbecker 44cd84c2acSFrederic Weisbecker return ret; 45cd84c2acSFrederic Weisbecker } 462cec19d9SFrederic Weisbecker 47c95688aaSJiri Olsa int eprintf(int level, int var, const char *fmt, ...) 48f772abc6SJiri Olsa { 49f772abc6SJiri Olsa va_list args; 50f772abc6SJiri Olsa int ret; 51f772abc6SJiri Olsa 52f772abc6SJiri Olsa va_start(args, fmt); 53bedbdd42SArnaldo Carvalho de Melo ret = veprintf(level, var, fmt, args); 54f772abc6SJiri Olsa va_end(args); 55f772abc6SJiri Olsa 56f772abc6SJiri Olsa return ret; 57f772abc6SJiri Olsa } 58f772abc6SJiri Olsa 59bedbdd42SArnaldo Carvalho de Melo static int veprintf_time(u64 t, const char *fmt, va_list args) 60cee3ab9cSJiri Olsa { 61cee3ab9cSJiri Olsa int ret = 0; 62cee3ab9cSJiri Olsa u64 secs, usecs, nsecs = t; 63cee3ab9cSJiri Olsa 64bd48c63eSArnaldo Carvalho de Melo secs = nsecs / NSEC_PER_SEC; 65bd48c63eSArnaldo Carvalho de Melo nsecs -= secs * NSEC_PER_SEC; 66bd48c63eSArnaldo Carvalho de Melo usecs = nsecs / NSEC_PER_USEC; 67cee3ab9cSJiri Olsa 68cee3ab9cSJiri Olsa ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ", 69cee3ab9cSJiri Olsa secs, usecs); 70cee3ab9cSJiri Olsa ret += vfprintf(stderr, fmt, args); 71cee3ab9cSJiri Olsa return ret; 72cee3ab9cSJiri Olsa } 73cee3ab9cSJiri Olsa 74cee3ab9cSJiri Olsa int eprintf_time(int level, int var, u64 t, const char *fmt, ...) 75cee3ab9cSJiri Olsa { 76cee3ab9cSJiri Olsa int ret = 0; 77cee3ab9cSJiri Olsa va_list args; 78cee3ab9cSJiri Olsa 79cee3ab9cSJiri Olsa if (var >= level) { 80cee3ab9cSJiri Olsa va_start(args, fmt); 81bedbdd42SArnaldo Carvalho de Melo ret = veprintf_time(t, fmt, args); 82cee3ab9cSJiri Olsa va_end(args); 83cee3ab9cSJiri Olsa } 84cee3ab9cSJiri Olsa 85cee3ab9cSJiri Olsa return ret; 86cee3ab9cSJiri Olsa } 87cee3ab9cSJiri Olsa 88f772abc6SJiri Olsa /* 89f772abc6SJiri Olsa * Overloading libtraceevent standard info print 90f772abc6SJiri Olsa * function, display with -v in perf. 91f772abc6SJiri Olsa */ 92f772abc6SJiri Olsa void pr_stat(const char *fmt, ...) 93f772abc6SJiri Olsa { 94f772abc6SJiri Olsa va_list args; 95f772abc6SJiri Olsa 96f772abc6SJiri Olsa va_start(args, fmt); 97bedbdd42SArnaldo Carvalho de Melo veprintf(1, verbose, fmt, args); 98f772abc6SJiri Olsa va_end(args); 99c95688aaSJiri Olsa eprintf(1, verbose, "\n"); 100f772abc6SJiri Olsa } 101f772abc6SJiri Olsa 1022cec19d9SFrederic Weisbecker int dump_printf(const char *fmt, ...) 1032cec19d9SFrederic Weisbecker { 1042cec19d9SFrederic Weisbecker va_list args; 1052cec19d9SFrederic Weisbecker int ret = 0; 1062cec19d9SFrederic Weisbecker 1072cec19d9SFrederic Weisbecker if (dump_trace) { 1082cec19d9SFrederic Weisbecker va_start(args, fmt); 1092cec19d9SFrederic Weisbecker ret = vprintf(fmt, args); 1102cec19d9SFrederic Weisbecker va_end(args); 1112cec19d9SFrederic Weisbecker } 1122cec19d9SFrederic Weisbecker 1132cec19d9SFrederic Weisbecker return ret; 1142cec19d9SFrederic Weisbecker } 1158f28827aSFrederic Weisbecker 116923d0c9aSArnaldo Carvalho de Melo static int trace_event_printer(enum binary_printer_ops op, 117923d0c9aSArnaldo Carvalho de Melo unsigned int val, void *extra, FILE *fp) 118c339b1a9SWang Nan { 119c339b1a9SWang Nan const char *color = PERF_COLOR_BLUE; 120c339b1a9SWang Nan union perf_event *event = (union perf_event *)extra; 121c339b1a9SWang Nan unsigned char ch = (unsigned char)val; 122923d0c9aSArnaldo Carvalho de Melo int printed = 0; 123c339b1a9SWang Nan 124c339b1a9SWang Nan switch (op) { 125c339b1a9SWang Nan case BINARY_PRINT_DATA_BEGIN: 126923d0c9aSArnaldo Carvalho de Melo printed += fprintf(fp, "."); 127923d0c9aSArnaldo Carvalho de Melo printed += color_fprintf(fp, color, "\n. ... raw event: size %d bytes\n", 128c339b1a9SWang Nan event->header.size); 129c339b1a9SWang Nan break; 130c339b1a9SWang Nan case BINARY_PRINT_LINE_BEGIN: 131923d0c9aSArnaldo Carvalho de Melo printed += fprintf(fp, "."); 132c339b1a9SWang Nan break; 133c339b1a9SWang Nan case BINARY_PRINT_ADDR: 134923d0c9aSArnaldo Carvalho de Melo printed += color_fprintf(fp, color, " %04x: ", val); 135c339b1a9SWang Nan break; 136c339b1a9SWang Nan case BINARY_PRINT_NUM_DATA: 137923d0c9aSArnaldo Carvalho de Melo printed += color_fprintf(fp, color, " %02x", val); 138c339b1a9SWang Nan break; 139c339b1a9SWang Nan case BINARY_PRINT_NUM_PAD: 140923d0c9aSArnaldo Carvalho de Melo printed += color_fprintf(fp, color, " "); 141c339b1a9SWang Nan break; 142c339b1a9SWang Nan case BINARY_PRINT_SEP: 143923d0c9aSArnaldo Carvalho de Melo printed += color_fprintf(fp, color, " "); 144c339b1a9SWang Nan break; 145c339b1a9SWang Nan case BINARY_PRINT_CHAR_DATA: 146923d0c9aSArnaldo Carvalho de Melo printed += color_fprintf(fp, color, "%c", 147c339b1a9SWang Nan isprint(ch) ? ch : '.'); 148c339b1a9SWang Nan break; 149c339b1a9SWang Nan case BINARY_PRINT_CHAR_PAD: 150923d0c9aSArnaldo Carvalho de Melo printed += color_fprintf(fp, color, " "); 151c339b1a9SWang Nan break; 152c339b1a9SWang Nan case BINARY_PRINT_LINE_END: 153923d0c9aSArnaldo Carvalho de Melo printed += color_fprintf(fp, color, "\n"); 154c339b1a9SWang Nan break; 155c339b1a9SWang Nan case BINARY_PRINT_DATA_END: 156923d0c9aSArnaldo Carvalho de Melo printed += fprintf(fp, "\n"); 157c339b1a9SWang Nan break; 158c339b1a9SWang Nan default: 159c339b1a9SWang Nan break; 160c339b1a9SWang Nan } 161923d0c9aSArnaldo Carvalho de Melo 162923d0c9aSArnaldo Carvalho de Melo return printed; 163c339b1a9SWang Nan } 164c339b1a9SWang Nan 1658115d60cSArnaldo Carvalho de Melo void trace_event(union perf_event *event) 1668f28827aSFrederic Weisbecker { 1678f28827aSFrederic Weisbecker unsigned char *raw_event = (void *)event; 1688f28827aSFrederic Weisbecker 1698f28827aSFrederic Weisbecker if (!dump_trace) 1708f28827aSFrederic Weisbecker return; 1718f28827aSFrederic Weisbecker 172c339b1a9SWang Nan print_binary(raw_event, event->header.size, 16, 173c339b1a9SWang Nan trace_event_printer, event); 1748f28827aSFrederic Weisbecker } 175bbb2cea7SJiri Olsa 176bbb2cea7SJiri Olsa static struct debug_variable { 177bbb2cea7SJiri Olsa const char *name; 178bbb2cea7SJiri Olsa int *ptr; 179bbb2cea7SJiri Olsa } debug_variables[] = { 180bbb2cea7SJiri Olsa { .name = "verbose", .ptr = &verbose }, 181cee3ab9cSJiri Olsa { .name = "ordered-events", .ptr = &debug_ordered_events}, 182f78eaef0SAndi Kleen { .name = "stderr", .ptr = &redirect_to_stderr}, 183edbe9817SJiri Olsa { .name = "data-convert", .ptr = &debug_data_convert }, 184ccd26741SRavi Bangoria { .name = "perf-event-open", .ptr = &debug_peo_args }, 185bbb2cea7SJiri Olsa { .name = NULL, } 186bbb2cea7SJiri Olsa }; 187bbb2cea7SJiri Olsa 188bbb2cea7SJiri Olsa int perf_debug_option(const char *str) 189bbb2cea7SJiri Olsa { 190bbb2cea7SJiri Olsa struct debug_variable *var = &debug_variables[0]; 191bbb2cea7SJiri Olsa char *vstr, *s = strdup(str); 192bbb2cea7SJiri Olsa int v = 1; 193bbb2cea7SJiri Olsa 194bbb2cea7SJiri Olsa vstr = strchr(s, '='); 195bbb2cea7SJiri Olsa if (vstr) 196bbb2cea7SJiri Olsa *vstr++ = 0; 197bbb2cea7SJiri Olsa 198bbb2cea7SJiri Olsa while (var->name) { 199bbb2cea7SJiri Olsa if (!strcmp(s, var->name)) 200bbb2cea7SJiri Olsa break; 201bbb2cea7SJiri Olsa var++; 202bbb2cea7SJiri Olsa } 203bbb2cea7SJiri Olsa 204bbb2cea7SJiri Olsa if (!var->name) { 205bbb2cea7SJiri Olsa pr_err("Unknown debug variable name '%s'\n", s); 206bbb2cea7SJiri Olsa free(s); 207bbb2cea7SJiri Olsa return -1; 208bbb2cea7SJiri Olsa } 209bbb2cea7SJiri Olsa 210bbb2cea7SJiri Olsa if (vstr) { 211bbb2cea7SJiri Olsa v = atoi(vstr); 212bbb2cea7SJiri Olsa /* 213bbb2cea7SJiri Olsa * Allow only values in range (0, 10), 214bbb2cea7SJiri Olsa * otherwise set 0. 215bbb2cea7SJiri Olsa */ 216bbb2cea7SJiri Olsa v = (v < 0) || (v > 10) ? 0 : v; 217bbb2cea7SJiri Olsa } 218bbb2cea7SJiri Olsa 21980df1988SNamhyung Kim if (quiet) 22080df1988SNamhyung Kim v = -1; 22180df1988SNamhyung Kim 222bbb2cea7SJiri Olsa *var->ptr = v; 223bbb2cea7SJiri Olsa free(s); 224bbb2cea7SJiri Olsa return 0; 225bbb2cea7SJiri Olsa } 226dd629cc0SJiri Olsa 22780df1988SNamhyung Kim int perf_quiet_option(void) 22880df1988SNamhyung Kim { 22980df1988SNamhyung Kim struct debug_variable *var = &debug_variables[0]; 23080df1988SNamhyung Kim 23180df1988SNamhyung Kim /* disable all debug messages */ 23280df1988SNamhyung Kim while (var->name) { 23380df1988SNamhyung Kim *var->ptr = -1; 23480df1988SNamhyung Kim var++; 23580df1988SNamhyung Kim } 23680df1988SNamhyung Kim 23780df1988SNamhyung Kim return 0; 23880df1988SNamhyung Kim } 23980df1988SNamhyung Kim 240dd629cc0SJiri Olsa #define DEBUG_WRAPPER(__n, __l) \ 241dd629cc0SJiri Olsa static int pr_ ## __n ## _wrapper(const char *fmt, ...) \ 242dd629cc0SJiri Olsa { \ 243dd629cc0SJiri Olsa va_list args; \ 244dd629cc0SJiri Olsa int ret; \ 245dd629cc0SJiri Olsa \ 246dd629cc0SJiri Olsa va_start(args, fmt); \ 247dd629cc0SJiri Olsa ret = veprintf(__l, verbose, fmt, args); \ 248dd629cc0SJiri Olsa va_end(args); \ 249dd629cc0SJiri Olsa return ret; \ 250dd629cc0SJiri Olsa } 251dd629cc0SJiri Olsa 252dd629cc0SJiri Olsa DEBUG_WRAPPER(warning, 0); 253dd629cc0SJiri Olsa DEBUG_WRAPPER(debug, 1); 254dd629cc0SJiri Olsa 255dd629cc0SJiri Olsa void perf_debug_setup(void) 256dd629cc0SJiri Olsa { 257dd629cc0SJiri Olsa libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper); 258dd629cc0SJiri Olsa } 2598c2b7cacSArnaldo Carvalho de Melo 2608c2b7cacSArnaldo Carvalho de Melo /* Obtain a backtrace and print it to stdout. */ 2618c2b7cacSArnaldo Carvalho de Melo #ifdef HAVE_BACKTRACE_SUPPORT 2628c2b7cacSArnaldo Carvalho de Melo void dump_stack(void) 2638c2b7cacSArnaldo Carvalho de Melo { 2648c2b7cacSArnaldo Carvalho de Melo void *array[16]; 2658c2b7cacSArnaldo Carvalho de Melo size_t size = backtrace(array, ARRAY_SIZE(array)); 2668c2b7cacSArnaldo Carvalho de Melo char **strings = backtrace_symbols(array, size); 2678c2b7cacSArnaldo Carvalho de Melo size_t i; 2688c2b7cacSArnaldo Carvalho de Melo 2698c2b7cacSArnaldo Carvalho de Melo printf("Obtained %zd stack frames.\n", size); 2708c2b7cacSArnaldo Carvalho de Melo 2718c2b7cacSArnaldo Carvalho de Melo for (i = 0; i < size; i++) 2728c2b7cacSArnaldo Carvalho de Melo printf("%s\n", strings[i]); 2738c2b7cacSArnaldo Carvalho de Melo 2748c2b7cacSArnaldo Carvalho de Melo free(strings); 2758c2b7cacSArnaldo Carvalho de Melo } 2768c2b7cacSArnaldo Carvalho de Melo #else 2778c2b7cacSArnaldo Carvalho de Melo void dump_stack(void) {} 2788c2b7cacSArnaldo Carvalho de Melo #endif 2798c2b7cacSArnaldo Carvalho de Melo 2808c2b7cacSArnaldo Carvalho de Melo void sighandler_dump_stack(int sig) 2818c2b7cacSArnaldo Carvalho de Melo { 2828c2b7cacSArnaldo Carvalho de Melo psignal(sig, "perf"); 2838c2b7cacSArnaldo Carvalho de Melo dump_stack(); 2848c2b7cacSArnaldo Carvalho de Melo signal(sig, SIG_DFL); 2858c2b7cacSArnaldo Carvalho de Melo raise(sig); 2868c2b7cacSArnaldo Carvalho de Melo } 287