18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* For general debugging purposes */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <inttypes.h> 58c2ecf20Sopenharmony_ci#include <string.h> 68c2ecf20Sopenharmony_ci#include <stdarg.h> 78c2ecf20Sopenharmony_ci#include <stdio.h> 88c2ecf20Sopenharmony_ci#include <stdlib.h> 98c2ecf20Sopenharmony_ci#include <sys/wait.h> 108c2ecf20Sopenharmony_ci#include <api/debug.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/time64.h> 138c2ecf20Sopenharmony_ci#ifdef HAVE_BACKTRACE_SUPPORT 148c2ecf20Sopenharmony_ci#include <execinfo.h> 158c2ecf20Sopenharmony_ci#endif 168c2ecf20Sopenharmony_ci#include "color.h" 178c2ecf20Sopenharmony_ci#include "event.h" 188c2ecf20Sopenharmony_ci#include "debug.h" 198c2ecf20Sopenharmony_ci#include "print_binary.h" 208c2ecf20Sopenharmony_ci#include "target.h" 218c2ecf20Sopenharmony_ci#include "ui/helpline.h" 228c2ecf20Sopenharmony_ci#include "ui/ui.h" 238c2ecf20Sopenharmony_ci#include "util/parse-sublevel-options.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/ctype.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ciint verbose; 288c2ecf20Sopenharmony_ciint debug_peo_args; 298c2ecf20Sopenharmony_cibool dump_trace = false, quiet = false; 308c2ecf20Sopenharmony_ciint debug_ordered_events; 318c2ecf20Sopenharmony_cistatic int redirect_to_stderr; 328c2ecf20Sopenharmony_ciint debug_data_convert; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ciint veprintf(int level, int var, const char *fmt, va_list args) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci int ret = 0; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci if (var >= level) { 398c2ecf20Sopenharmony_ci if (use_browser >= 1 && !redirect_to_stderr) 408c2ecf20Sopenharmony_ci ui_helpline__vshow(fmt, args); 418c2ecf20Sopenharmony_ci else 428c2ecf20Sopenharmony_ci ret = vfprintf(stderr, fmt, args); 438c2ecf20Sopenharmony_ci } 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci return ret; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ciint eprintf(int level, int var, const char *fmt, ...) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci va_list args; 518c2ecf20Sopenharmony_ci int ret; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci va_start(args, fmt); 548c2ecf20Sopenharmony_ci ret = veprintf(level, var, fmt, args); 558c2ecf20Sopenharmony_ci va_end(args); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci return ret; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic int veprintf_time(u64 t, const char *fmt, va_list args) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci int ret = 0; 638c2ecf20Sopenharmony_ci u64 secs, usecs, nsecs = t; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci secs = nsecs / NSEC_PER_SEC; 668c2ecf20Sopenharmony_ci nsecs -= secs * NSEC_PER_SEC; 678c2ecf20Sopenharmony_ci usecs = nsecs / NSEC_PER_USEC; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ", 708c2ecf20Sopenharmony_ci secs, usecs); 718c2ecf20Sopenharmony_ci ret += vfprintf(stderr, fmt, args); 728c2ecf20Sopenharmony_ci return ret; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ciint eprintf_time(int level, int var, u64 t, const char *fmt, ...) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci int ret = 0; 788c2ecf20Sopenharmony_ci va_list args; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (var >= level) { 818c2ecf20Sopenharmony_ci va_start(args, fmt); 828c2ecf20Sopenharmony_ci ret = veprintf_time(t, fmt, args); 838c2ecf20Sopenharmony_ci va_end(args); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return ret; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* 908c2ecf20Sopenharmony_ci * Overloading libtraceevent standard info print 918c2ecf20Sopenharmony_ci * function, display with -v in perf. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_civoid pr_stat(const char *fmt, ...) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci va_list args; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci va_start(args, fmt); 988c2ecf20Sopenharmony_ci veprintf(1, verbose, fmt, args); 998c2ecf20Sopenharmony_ci va_end(args); 1008c2ecf20Sopenharmony_ci eprintf(1, verbose, "\n"); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ciint dump_printf(const char *fmt, ...) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci va_list args; 1068c2ecf20Sopenharmony_ci int ret = 0; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (dump_trace) { 1098c2ecf20Sopenharmony_ci va_start(args, fmt); 1108c2ecf20Sopenharmony_ci ret = vprintf(fmt, args); 1118c2ecf20Sopenharmony_ci va_end(args); 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return ret; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic int trace_event_printer(enum binary_printer_ops op, 1188c2ecf20Sopenharmony_ci unsigned int val, void *extra, FILE *fp) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci const char *color = PERF_COLOR_BLUE; 1218c2ecf20Sopenharmony_ci union perf_event *event = (union perf_event *)extra; 1228c2ecf20Sopenharmony_ci unsigned char ch = (unsigned char)val; 1238c2ecf20Sopenharmony_ci int printed = 0; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci switch (op) { 1268c2ecf20Sopenharmony_ci case BINARY_PRINT_DATA_BEGIN: 1278c2ecf20Sopenharmony_ci printed += fprintf(fp, "."); 1288c2ecf20Sopenharmony_ci printed += color_fprintf(fp, color, "\n. ... raw event: size %d bytes\n", 1298c2ecf20Sopenharmony_ci event->header.size); 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci case BINARY_PRINT_LINE_BEGIN: 1328c2ecf20Sopenharmony_ci printed += fprintf(fp, "."); 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci case BINARY_PRINT_ADDR: 1358c2ecf20Sopenharmony_ci printed += color_fprintf(fp, color, " %04x: ", val); 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci case BINARY_PRINT_NUM_DATA: 1388c2ecf20Sopenharmony_ci printed += color_fprintf(fp, color, " %02x", val); 1398c2ecf20Sopenharmony_ci break; 1408c2ecf20Sopenharmony_ci case BINARY_PRINT_NUM_PAD: 1418c2ecf20Sopenharmony_ci printed += color_fprintf(fp, color, " "); 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci case BINARY_PRINT_SEP: 1448c2ecf20Sopenharmony_ci printed += color_fprintf(fp, color, " "); 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci case BINARY_PRINT_CHAR_DATA: 1478c2ecf20Sopenharmony_ci printed += color_fprintf(fp, color, "%c", 1488c2ecf20Sopenharmony_ci isprint(ch) && isascii(ch) ? ch : '.'); 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci case BINARY_PRINT_CHAR_PAD: 1518c2ecf20Sopenharmony_ci printed += color_fprintf(fp, color, " "); 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci case BINARY_PRINT_LINE_END: 1548c2ecf20Sopenharmony_ci printed += color_fprintf(fp, color, "\n"); 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci case BINARY_PRINT_DATA_END: 1578c2ecf20Sopenharmony_ci printed += fprintf(fp, "\n"); 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci default: 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return printed; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_civoid trace_event(union perf_event *event) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci unsigned char *raw_event = (void *)event; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (!dump_trace) 1718c2ecf20Sopenharmony_ci return; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci print_binary(raw_event, event->header.size, 16, 1748c2ecf20Sopenharmony_ci trace_event_printer, event); 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic struct sublevel_option debug_opts[] = { 1788c2ecf20Sopenharmony_ci { .name = "verbose", .value_ptr = &verbose }, 1798c2ecf20Sopenharmony_ci { .name = "ordered-events", .value_ptr = &debug_ordered_events}, 1808c2ecf20Sopenharmony_ci { .name = "stderr", .value_ptr = &redirect_to_stderr}, 1818c2ecf20Sopenharmony_ci { .name = "data-convert", .value_ptr = &debug_data_convert }, 1828c2ecf20Sopenharmony_ci { .name = "perf-event-open", .value_ptr = &debug_peo_args }, 1838c2ecf20Sopenharmony_ci { .name = NULL, } 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ciint perf_debug_option(const char *str) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci int ret; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci ret = perf_parse_sublevel_options(str, debug_opts); 1918c2ecf20Sopenharmony_ci if (ret) 1928c2ecf20Sopenharmony_ci return ret; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* Allow only verbose value in range (0, 10), otherwise set 0. */ 1958c2ecf20Sopenharmony_ci verbose = (verbose < 0) || (verbose > 10) ? 0 : verbose; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return 0; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ciint perf_quiet_option(void) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct sublevel_option *opt = &debug_opts[0]; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* disable all debug messages */ 2058c2ecf20Sopenharmony_ci while (opt->name) { 2068c2ecf20Sopenharmony_ci *opt->value_ptr = -1; 2078c2ecf20Sopenharmony_ci opt++; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* For debug variables that are used as bool types, set to 0. */ 2118c2ecf20Sopenharmony_ci redirect_to_stderr = 0; 2128c2ecf20Sopenharmony_ci debug_peo_args = 0; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci return 0; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci#define DEBUG_WRAPPER(__n, __l) \ 2188c2ecf20Sopenharmony_cistatic int pr_ ## __n ## _wrapper(const char *fmt, ...) \ 2198c2ecf20Sopenharmony_ci{ \ 2208c2ecf20Sopenharmony_ci va_list args; \ 2218c2ecf20Sopenharmony_ci int ret; \ 2228c2ecf20Sopenharmony_ci \ 2238c2ecf20Sopenharmony_ci va_start(args, fmt); \ 2248c2ecf20Sopenharmony_ci ret = veprintf(__l, verbose, fmt, args); \ 2258c2ecf20Sopenharmony_ci va_end(args); \ 2268c2ecf20Sopenharmony_ci return ret; \ 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ciDEBUG_WRAPPER(warning, 0); 2308c2ecf20Sopenharmony_ciDEBUG_WRAPPER(debug, 1); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_civoid perf_debug_setup(void) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* Obtain a backtrace and print it to stdout. */ 2388c2ecf20Sopenharmony_ci#ifdef HAVE_BACKTRACE_SUPPORT 2398c2ecf20Sopenharmony_civoid dump_stack(void) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci void *array[16]; 2428c2ecf20Sopenharmony_ci size_t size = backtrace(array, ARRAY_SIZE(array)); 2438c2ecf20Sopenharmony_ci char **strings = backtrace_symbols(array, size); 2448c2ecf20Sopenharmony_ci size_t i; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci printf("Obtained %zd stack frames.\n", size); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) 2498c2ecf20Sopenharmony_ci printf("%s\n", strings[i]); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci free(strings); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci#else 2548c2ecf20Sopenharmony_civoid dump_stack(void) {} 2558c2ecf20Sopenharmony_ci#endif 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_civoid sighandler_dump_stack(int sig) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci psignal(sig, "perf"); 2608c2ecf20Sopenharmony_ci dump_stack(); 2618c2ecf20Sopenharmony_ci signal(sig, SIG_DFL); 2628c2ecf20Sopenharmony_ci raise(sig); 2638c2ecf20Sopenharmony_ci} 264