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> 13bcbd79d1SJiri Olsa #include <sys/time.h> 148c2b7cacSArnaldo Carvalho de Melo #ifdef HAVE_BACKTRACE_SUPPORT 158c2b7cacSArnaldo Carvalho de Melo #include <execinfo.h> 168c2b7cacSArnaldo Carvalho de Melo #endif 178f28827aSFrederic Weisbecker #include "color.h" 188f28827aSFrederic Weisbecker #include "event.h" 198f28827aSFrederic Weisbecker #include "debug.h" 20fea01392SArnaldo Carvalho de Melo #include "print_binary.h" 2116ad2ffbSNamhyung Kim #include "target.h" 228520a98dSArnaldo Carvalho de Melo #include "ui/helpline.h" 23fa0d9846SArnaldo Carvalho de Melo #include "ui/ui.h" 24a80abe2aSChangbin Du #include "util/parse-sublevel-options.h" 258f28827aSFrederic Weisbecker 263052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h> 273d689ed6SArnaldo Carvalho de Melo 28b44308f5SArnaldo Carvalho de Melo int verbose; 29ccd26741SRavi Bangoria int debug_peo_args; 30b44308f5SArnaldo Carvalho de Melo bool dump_trace = false, quiet = false; 31cee3ab9cSJiri Olsa int debug_ordered_events; 32f78eaef0SAndi Kleen static int redirect_to_stderr; 33edbe9817SJiri Olsa int debug_data_convert; 348abceacfSJiri Olsa static FILE *debug_file; 35bcbd79d1SJiri Olsa bool debug_display_time; 368abceacfSJiri Olsa 378abceacfSJiri Olsa void debug_set_file(FILE *file) 388abceacfSJiri Olsa { 398abceacfSJiri Olsa debug_file = file; 408abceacfSJiri Olsa } 41cd84c2acSFrederic Weisbecker 42bcbd79d1SJiri Olsa void debug_set_display_time(bool set) 43bcbd79d1SJiri Olsa { 44bcbd79d1SJiri Olsa debug_display_time = set; 45bcbd79d1SJiri Olsa } 46bcbd79d1SJiri Olsa 47bcbd79d1SJiri Olsa static int fprintf_time(FILE *file) 48bcbd79d1SJiri Olsa { 49bcbd79d1SJiri Olsa struct timeval tod; 50bcbd79d1SJiri Olsa struct tm ltime; 51bcbd79d1SJiri Olsa char date[64]; 52bcbd79d1SJiri Olsa 53bcbd79d1SJiri Olsa if (!debug_display_time) 54bcbd79d1SJiri Olsa return 0; 55bcbd79d1SJiri Olsa 56bcbd79d1SJiri Olsa if (gettimeofday(&tod, NULL) != 0) 57bcbd79d1SJiri Olsa return 0; 58bcbd79d1SJiri Olsa 59bcbd79d1SJiri Olsa if (localtime_r(&tod.tv_sec, <ime) == NULL) 60bcbd79d1SJiri Olsa return 0; 61bcbd79d1SJiri Olsa 62bcbd79d1SJiri Olsa strftime(date, sizeof(date), "%F %H:%M:%S", <ime); 63bcbd79d1SJiri Olsa return fprintf(file, "[%s.%06lu] ", date, (long)tod.tv_usec); 64bcbd79d1SJiri Olsa } 65bcbd79d1SJiri Olsa 66bedbdd42SArnaldo Carvalho de Melo int veprintf(int level, int var, const char *fmt, va_list args) 67cd84c2acSFrederic Weisbecker { 68cd84c2acSFrederic Weisbecker int ret = 0; 69cd84c2acSFrederic Weisbecker 70c95688aaSJiri Olsa if (var >= level) { 71bcbd79d1SJiri Olsa if (use_browser >= 1 && !redirect_to_stderr) { 72b56e5331SNamhyung Kim ui_helpline__vshow(fmt, args); 73bcbd79d1SJiri Olsa } else { 74bcbd79d1SJiri Olsa ret = fprintf_time(debug_file); 75bcbd79d1SJiri Olsa ret += vfprintf(debug_file, fmt, args); 76bcbd79d1SJiri Olsa } 77cd84c2acSFrederic Weisbecker } 78cd84c2acSFrederic Weisbecker 79cd84c2acSFrederic Weisbecker return ret; 80cd84c2acSFrederic Weisbecker } 812cec19d9SFrederic Weisbecker 82c95688aaSJiri Olsa int eprintf(int level, int var, const char *fmt, ...) 83f772abc6SJiri Olsa { 84f772abc6SJiri Olsa va_list args; 85f772abc6SJiri Olsa int ret; 86f772abc6SJiri Olsa 87f772abc6SJiri Olsa va_start(args, fmt); 88bedbdd42SArnaldo Carvalho de Melo ret = veprintf(level, var, fmt, args); 89f772abc6SJiri Olsa va_end(args); 90f772abc6SJiri Olsa 91f772abc6SJiri Olsa return ret; 92f772abc6SJiri Olsa } 93f772abc6SJiri Olsa 94bedbdd42SArnaldo Carvalho de Melo static int veprintf_time(u64 t, const char *fmt, va_list args) 95cee3ab9cSJiri Olsa { 96cee3ab9cSJiri Olsa int ret = 0; 97cee3ab9cSJiri Olsa u64 secs, usecs, nsecs = t; 98cee3ab9cSJiri Olsa 99bd48c63eSArnaldo Carvalho de Melo secs = nsecs / NSEC_PER_SEC; 100bd48c63eSArnaldo Carvalho de Melo nsecs -= secs * NSEC_PER_SEC; 101bd48c63eSArnaldo Carvalho de Melo usecs = nsecs / NSEC_PER_USEC; 102cee3ab9cSJiri Olsa 103cee3ab9cSJiri Olsa ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ", 104cee3ab9cSJiri Olsa secs, usecs); 105cee3ab9cSJiri Olsa ret += vfprintf(stderr, fmt, args); 106cee3ab9cSJiri Olsa return ret; 107cee3ab9cSJiri Olsa } 108cee3ab9cSJiri Olsa 109cee3ab9cSJiri Olsa int eprintf_time(int level, int var, u64 t, const char *fmt, ...) 110cee3ab9cSJiri Olsa { 111cee3ab9cSJiri Olsa int ret = 0; 112cee3ab9cSJiri Olsa va_list args; 113cee3ab9cSJiri Olsa 114cee3ab9cSJiri Olsa if (var >= level) { 115cee3ab9cSJiri Olsa va_start(args, fmt); 116bedbdd42SArnaldo Carvalho de Melo ret = veprintf_time(t, fmt, args); 117cee3ab9cSJiri Olsa va_end(args); 118cee3ab9cSJiri Olsa } 119cee3ab9cSJiri Olsa 120cee3ab9cSJiri Olsa return ret; 121cee3ab9cSJiri Olsa } 122cee3ab9cSJiri Olsa 123f772abc6SJiri Olsa /* 124f772abc6SJiri Olsa * Overloading libtraceevent standard info print 125f772abc6SJiri Olsa * function, display with -v in perf. 126f772abc6SJiri Olsa */ 127f772abc6SJiri Olsa void pr_stat(const char *fmt, ...) 128f772abc6SJiri Olsa { 129f772abc6SJiri Olsa va_list args; 130f772abc6SJiri Olsa 131f772abc6SJiri Olsa va_start(args, fmt); 132bedbdd42SArnaldo Carvalho de Melo veprintf(1, verbose, fmt, args); 133f772abc6SJiri Olsa va_end(args); 134c95688aaSJiri Olsa eprintf(1, verbose, "\n"); 135f772abc6SJiri Olsa } 136f772abc6SJiri Olsa 1372cec19d9SFrederic Weisbecker int dump_printf(const char *fmt, ...) 1382cec19d9SFrederic Weisbecker { 1392cec19d9SFrederic Weisbecker va_list args; 1402cec19d9SFrederic Weisbecker int ret = 0; 1412cec19d9SFrederic Weisbecker 1422cec19d9SFrederic Weisbecker if (dump_trace) { 1432cec19d9SFrederic Weisbecker va_start(args, fmt); 1442cec19d9SFrederic Weisbecker ret = vprintf(fmt, args); 1452cec19d9SFrederic Weisbecker va_end(args); 1462cec19d9SFrederic Weisbecker } 1472cec19d9SFrederic Weisbecker 1482cec19d9SFrederic Weisbecker return ret; 1492cec19d9SFrederic Weisbecker } 1508f28827aSFrederic Weisbecker 151923d0c9aSArnaldo Carvalho de Melo static int trace_event_printer(enum binary_printer_ops op, 152923d0c9aSArnaldo Carvalho de Melo unsigned int val, void *extra, FILE *fp) 153c339b1a9SWang Nan { 154c339b1a9SWang Nan const char *color = PERF_COLOR_BLUE; 155c339b1a9SWang Nan union perf_event *event = (union perf_event *)extra; 156c339b1a9SWang Nan unsigned char ch = (unsigned char)val; 157923d0c9aSArnaldo Carvalho de Melo int printed = 0; 158c339b1a9SWang Nan 159c339b1a9SWang Nan switch (op) { 160c339b1a9SWang Nan case BINARY_PRINT_DATA_BEGIN: 161923d0c9aSArnaldo Carvalho de Melo printed += fprintf(fp, "."); 162923d0c9aSArnaldo Carvalho de Melo printed += color_fprintf(fp, color, "\n. ... raw event: size %d bytes\n", 163c339b1a9SWang Nan event->header.size); 164c339b1a9SWang Nan break; 165c339b1a9SWang Nan case BINARY_PRINT_LINE_BEGIN: 166923d0c9aSArnaldo Carvalho de Melo printed += fprintf(fp, "."); 167c339b1a9SWang Nan break; 168c339b1a9SWang Nan case BINARY_PRINT_ADDR: 169923d0c9aSArnaldo Carvalho de Melo printed += color_fprintf(fp, color, " %04x: ", val); 170c339b1a9SWang Nan break; 171c339b1a9SWang Nan case BINARY_PRINT_NUM_DATA: 172923d0c9aSArnaldo Carvalho de Melo printed += color_fprintf(fp, color, " %02x", val); 173c339b1a9SWang Nan break; 174c339b1a9SWang Nan case BINARY_PRINT_NUM_PAD: 175923d0c9aSArnaldo Carvalho de Melo printed += color_fprintf(fp, color, " "); 176c339b1a9SWang Nan break; 177c339b1a9SWang Nan case BINARY_PRINT_SEP: 178923d0c9aSArnaldo Carvalho de Melo printed += color_fprintf(fp, color, " "); 179c339b1a9SWang Nan break; 180c339b1a9SWang Nan case BINARY_PRINT_CHAR_DATA: 181923d0c9aSArnaldo Carvalho de Melo printed += color_fprintf(fp, color, "%c", 182*62942e9fSAdrian Hunter isprint(ch) && isascii(ch) ? ch : '.'); 183c339b1a9SWang Nan break; 184c339b1a9SWang Nan case BINARY_PRINT_CHAR_PAD: 185923d0c9aSArnaldo Carvalho de Melo printed += color_fprintf(fp, color, " "); 186c339b1a9SWang Nan break; 187c339b1a9SWang Nan case BINARY_PRINT_LINE_END: 188923d0c9aSArnaldo Carvalho de Melo printed += color_fprintf(fp, color, "\n"); 189c339b1a9SWang Nan break; 190c339b1a9SWang Nan case BINARY_PRINT_DATA_END: 191923d0c9aSArnaldo Carvalho de Melo printed += fprintf(fp, "\n"); 192c339b1a9SWang Nan break; 193c339b1a9SWang Nan default: 194c339b1a9SWang Nan break; 195c339b1a9SWang Nan } 196923d0c9aSArnaldo Carvalho de Melo 197923d0c9aSArnaldo Carvalho de Melo return printed; 198c339b1a9SWang Nan } 199c339b1a9SWang Nan 2008115d60cSArnaldo Carvalho de Melo void trace_event(union perf_event *event) 2018f28827aSFrederic Weisbecker { 2028f28827aSFrederic Weisbecker unsigned char *raw_event = (void *)event; 2038f28827aSFrederic Weisbecker 2048f28827aSFrederic Weisbecker if (!dump_trace) 2058f28827aSFrederic Weisbecker return; 2068f28827aSFrederic Weisbecker 207c339b1a9SWang Nan print_binary(raw_event, event->header.size, 16, 208c339b1a9SWang Nan trace_event_printer, event); 2098f28827aSFrederic Weisbecker } 210bbb2cea7SJiri Olsa 211a80abe2aSChangbin Du static struct sublevel_option debug_opts[] = { 212a80abe2aSChangbin Du { .name = "verbose", .value_ptr = &verbose }, 213a80abe2aSChangbin Du { .name = "ordered-events", .value_ptr = &debug_ordered_events}, 214a80abe2aSChangbin Du { .name = "stderr", .value_ptr = &redirect_to_stderr}, 215a80abe2aSChangbin Du { .name = "data-convert", .value_ptr = &debug_data_convert }, 216a80abe2aSChangbin Du { .name = "perf-event-open", .value_ptr = &debug_peo_args }, 217bbb2cea7SJiri Olsa { .name = NULL, } 218bbb2cea7SJiri Olsa }; 219bbb2cea7SJiri Olsa 220bbb2cea7SJiri Olsa int perf_debug_option(const char *str) 221bbb2cea7SJiri Olsa { 222a80abe2aSChangbin Du int ret; 223bbb2cea7SJiri Olsa 224a80abe2aSChangbin Du ret = perf_parse_sublevel_options(str, debug_opts); 225a80abe2aSChangbin Du if (ret) 226a80abe2aSChangbin Du return ret; 227bbb2cea7SJiri Olsa 228a80abe2aSChangbin Du /* Allow only verbose value in range (0, 10), otherwise set 0. */ 229a80abe2aSChangbin Du verbose = (verbose < 0) || (verbose > 10) ? 0 : verbose; 230bbb2cea7SJiri Olsa 231bbb2cea7SJiri Olsa return 0; 232bbb2cea7SJiri Olsa } 233dd629cc0SJiri Olsa 23480df1988SNamhyung Kim int perf_quiet_option(void) 23580df1988SNamhyung Kim { 236a80abe2aSChangbin Du struct sublevel_option *opt = &debug_opts[0]; 23780df1988SNamhyung Kim 23880df1988SNamhyung Kim /* disable all debug messages */ 239a80abe2aSChangbin Du while (opt->name) { 240a80abe2aSChangbin Du *opt->value_ptr = -1; 241a80abe2aSChangbin Du opt++; 24280df1988SNamhyung Kim } 24380df1988SNamhyung Kim 24480df1988SNamhyung Kim return 0; 24580df1988SNamhyung Kim } 24680df1988SNamhyung Kim 247dd629cc0SJiri Olsa #define DEBUG_WRAPPER(__n, __l) \ 248dd629cc0SJiri Olsa static int pr_ ## __n ## _wrapper(const char *fmt, ...) \ 249dd629cc0SJiri Olsa { \ 250dd629cc0SJiri Olsa va_list args; \ 251dd629cc0SJiri Olsa int ret; \ 252dd629cc0SJiri Olsa \ 253dd629cc0SJiri Olsa va_start(args, fmt); \ 254dd629cc0SJiri Olsa ret = veprintf(__l, verbose, fmt, args); \ 255dd629cc0SJiri Olsa va_end(args); \ 256dd629cc0SJiri Olsa return ret; \ 257dd629cc0SJiri Olsa } 258dd629cc0SJiri Olsa 259dd629cc0SJiri Olsa DEBUG_WRAPPER(warning, 0); 260dd629cc0SJiri Olsa DEBUG_WRAPPER(debug, 1); 261dd629cc0SJiri Olsa 262dd629cc0SJiri Olsa void perf_debug_setup(void) 263dd629cc0SJiri Olsa { 2648abceacfSJiri Olsa debug_set_file(stderr); 265dd629cc0SJiri Olsa libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper); 266dd629cc0SJiri Olsa } 2678c2b7cacSArnaldo Carvalho de Melo 2688c2b7cacSArnaldo Carvalho de Melo /* Obtain a backtrace and print it to stdout. */ 2698c2b7cacSArnaldo Carvalho de Melo #ifdef HAVE_BACKTRACE_SUPPORT 2708c2b7cacSArnaldo Carvalho de Melo void dump_stack(void) 2718c2b7cacSArnaldo Carvalho de Melo { 2728c2b7cacSArnaldo Carvalho de Melo void *array[16]; 2738c2b7cacSArnaldo Carvalho de Melo size_t size = backtrace(array, ARRAY_SIZE(array)); 2748c2b7cacSArnaldo Carvalho de Melo char **strings = backtrace_symbols(array, size); 2758c2b7cacSArnaldo Carvalho de Melo size_t i; 2768c2b7cacSArnaldo Carvalho de Melo 2778c2b7cacSArnaldo Carvalho de Melo printf("Obtained %zd stack frames.\n", size); 2788c2b7cacSArnaldo Carvalho de Melo 2798c2b7cacSArnaldo Carvalho de Melo for (i = 0; i < size; i++) 2808c2b7cacSArnaldo Carvalho de Melo printf("%s\n", strings[i]); 2818c2b7cacSArnaldo Carvalho de Melo 2828c2b7cacSArnaldo Carvalho de Melo free(strings); 2838c2b7cacSArnaldo Carvalho de Melo } 2848c2b7cacSArnaldo Carvalho de Melo #else 2858c2b7cacSArnaldo Carvalho de Melo void dump_stack(void) {} 2868c2b7cacSArnaldo Carvalho de Melo #endif 2878c2b7cacSArnaldo Carvalho de Melo 2888c2b7cacSArnaldo Carvalho de Melo void sighandler_dump_stack(int sig) 2898c2b7cacSArnaldo Carvalho de Melo { 2908c2b7cacSArnaldo Carvalho de Melo psignal(sig, "perf"); 2918c2b7cacSArnaldo Carvalho de Melo dump_stack(); 2928c2b7cacSArnaldo Carvalho de Melo signal(sig, SIG_DFL); 2938c2b7cacSArnaldo Carvalho de Melo raise(sig); 2948c2b7cacSArnaldo Carvalho de Melo } 295