328 lines · c
1// SPDX-License-Identifier: GPL-2.02/* For general debugging purposes */3 4#include <inttypes.h>5#include <string.h>6#include <stdarg.h>7#include <stdio.h>8#include <stdlib.h>9#include <sys/wait.h>10#include <api/debug.h>11#include <linux/kernel.h>12#include <linux/time64.h>13#include <sys/time.h>14#ifdef HAVE_BACKTRACE_SUPPORT15#include <execinfo.h>16#endif17#include "color.h"18#include "event.h"19#include "debug.h"20#include "print_binary.h"21#include "target.h"22#include "trace-event.h"23#include "ui/helpline.h"24#include "ui/ui.h"25#include "util/parse-sublevel-options.h"26 27#include <linux/ctype.h>28 29#ifdef HAVE_LIBTRACEEVENT30#include <traceevent/event-parse.h>31#else32#define LIBTRACEEVENT_VERSION 033#endif34 35int verbose;36int debug_kmaps;37int debug_peo_args;38bool dump_trace = false, quiet = false;39int debug_ordered_events;40static int redirect_to_stderr;41int debug_data_convert;42static FILE *_debug_file;43bool debug_display_time;44int debug_type_profile;45 46FILE *debug_file(void)47{48 if (!_debug_file) {49 pr_warning_once("debug_file not set");50 debug_set_file(stderr);51 }52 return _debug_file;53}54 55void debug_set_file(FILE *file)56{57 _debug_file = file;58}59 60void debug_set_display_time(bool set)61{62 debug_display_time = set;63}64 65static int fprintf_time(FILE *file)66{67 struct timeval tod;68 struct tm ltime;69 char date[64];70 71 if (!debug_display_time)72 return 0;73 74 if (gettimeofday(&tod, NULL) != 0)75 return 0;76 77 if (localtime_r(&tod.tv_sec, <ime) == NULL)78 return 0;79 80 strftime(date, sizeof(date), "%F %H:%M:%S", <ime);81 return fprintf(file, "[%s.%06lu] ", date, (long)tod.tv_usec);82}83 84int veprintf(int level, int var, const char *fmt, va_list args)85{86 int ret = 0;87 88 if (var >= level) {89 if (use_browser >= 1 && !redirect_to_stderr) {90 ui_helpline__vshow(fmt, args);91 } else {92 ret = fprintf_time(debug_file());93 ret += vfprintf(debug_file(), fmt, args);94 }95 }96 97 return ret;98}99 100int eprintf(int level, int var, const char *fmt, ...)101{102 va_list args;103 int ret;104 105 va_start(args, fmt);106 ret = veprintf(level, var, fmt, args);107 va_end(args);108 109 return ret;110}111 112static int veprintf_time(u64 t, const char *fmt, va_list args)113{114 int ret = 0;115 u64 secs, usecs, nsecs = t;116 117 secs = nsecs / NSEC_PER_SEC;118 nsecs -= secs * NSEC_PER_SEC;119 usecs = nsecs / NSEC_PER_USEC;120 121 ret = fprintf(debug_file(), "[%13" PRIu64 ".%06" PRIu64 "] ", secs, usecs);122 ret += vfprintf(debug_file(), fmt, args);123 return ret;124}125 126int eprintf_time(int level, int var, u64 t, const char *fmt, ...)127{128 int ret = 0;129 va_list args;130 131 if (var >= level) {132 va_start(args, fmt);133 ret = veprintf_time(t, fmt, args);134 va_end(args);135 }136 137 return ret;138}139 140/*141 * Overloading libtraceevent standard info print142 * function, display with -v in perf.143 */144void pr_stat(const char *fmt, ...)145{146 va_list args;147 148 va_start(args, fmt);149 veprintf(1, verbose, fmt, args);150 va_end(args);151 eprintf(1, verbose, "\n");152}153 154int dump_printf(const char *fmt, ...)155{156 va_list args;157 int ret = 0;158 159 if (dump_trace) {160 va_start(args, fmt);161 ret = vprintf(fmt, args);162 va_end(args);163 }164 165 return ret;166}167 168static int trace_event_printer(enum binary_printer_ops op,169 unsigned int val, void *extra, FILE *fp)170{171 const char *color = PERF_COLOR_BLUE;172 union perf_event *event = (union perf_event *)extra;173 unsigned char ch = (unsigned char)val;174 int printed = 0;175 176 switch (op) {177 case BINARY_PRINT_DATA_BEGIN:178 printed += fprintf(fp, ".");179 printed += color_fprintf(fp, color, "\n. ... raw event: size %d bytes\n",180 event->header.size);181 break;182 case BINARY_PRINT_LINE_BEGIN:183 printed += fprintf(fp, ".");184 break;185 case BINARY_PRINT_ADDR:186 printed += color_fprintf(fp, color, " %04x: ", val);187 break;188 case BINARY_PRINT_NUM_DATA:189 printed += color_fprintf(fp, color, " %02x", val);190 break;191 case BINARY_PRINT_NUM_PAD:192 printed += color_fprintf(fp, color, " ");193 break;194 case BINARY_PRINT_SEP:195 printed += color_fprintf(fp, color, " ");196 break;197 case BINARY_PRINT_CHAR_DATA:198 printed += color_fprintf(fp, color, "%c",199 isprint(ch) && isascii(ch) ? ch : '.');200 break;201 case BINARY_PRINT_CHAR_PAD:202 printed += color_fprintf(fp, color, " ");203 break;204 case BINARY_PRINT_LINE_END:205 printed += color_fprintf(fp, color, "\n");206 break;207 case BINARY_PRINT_DATA_END:208 printed += fprintf(fp, "\n");209 break;210 default:211 break;212 }213 214 return printed;215}216 217void trace_event(union perf_event *event)218{219 unsigned char *raw_event = (void *)event;220 221 if (!dump_trace)222 return;223 224 print_binary(raw_event, event->header.size, 16,225 trace_event_printer, event);226}227 228static struct sublevel_option debug_opts[] = {229 { .name = "verbose", .value_ptr = &verbose },230 { .name = "ordered-events", .value_ptr = &debug_ordered_events},231 { .name = "stderr", .value_ptr = &redirect_to_stderr},232 { .name = "data-convert", .value_ptr = &debug_data_convert },233 { .name = "perf-event-open", .value_ptr = &debug_peo_args },234 { .name = "kmaps", .value_ptr = &debug_kmaps },235 { .name = "type-profile", .value_ptr = &debug_type_profile },236 { .name = NULL, }237};238 239int perf_debug_option(const char *str)240{241 int ret;242 243 ret = perf_parse_sublevel_options(str, debug_opts);244 if (ret)245 return ret;246 247 /* Allow only verbose value in range (0, 10), otherwise set 0. */248 verbose = (verbose < 0) || (verbose > 10) ? 0 : verbose;249 250#if LIBTRACEEVENT_VERSION >= MAKE_LIBTRACEEVENT_VERSION(1, 3, 0)251 if (verbose == 1)252 tep_set_loglevel(TEP_LOG_INFO);253 else if (verbose == 2)254 tep_set_loglevel(TEP_LOG_DEBUG);255 else if (verbose >= 3)256 tep_set_loglevel(TEP_LOG_ALL);257#endif258 return 0;259}260 261int perf_quiet_option(void)262{263 struct sublevel_option *opt = &debug_opts[0];264 265 /* disable all debug messages */266 while (opt->name) {267 *opt->value_ptr = -1;268 opt++;269 }270 271 /* For debug variables that are used as bool types, set to 0. */272 redirect_to_stderr = 0;273 debug_peo_args = 0;274 debug_kmaps = 0;275 debug_type_profile = 0;276 277 return 0;278}279 280#define DEBUG_WRAPPER(__n, __l) \281static int pr_ ## __n ## _wrapper(const char *fmt, ...) \282{ \283 va_list args; \284 int ret; \285 \286 va_start(args, fmt); \287 ret = veprintf(__l, verbose, fmt, args); \288 va_end(args); \289 return ret; \290}291 292DEBUG_WRAPPER(warning, 0);293DEBUG_WRAPPER(debug, 1);294 295void perf_debug_setup(void)296{297 debug_set_file(stderr);298 libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper);299}300 301/* Obtain a backtrace and print it to stdout. */302#ifdef HAVE_BACKTRACE_SUPPORT303void dump_stack(void)304{305 void *array[16];306 size_t size = backtrace(array, ARRAY_SIZE(array));307 char **strings = backtrace_symbols(array, size);308 size_t i;309 310 printf("Obtained %zd stack frames.\n", size);311 312 for (i = 0; i < size; i++)313 printf("%s\n", strings[i]);314 315 free(strings);316}317#else318void dump_stack(void) {}319#endif320 321void sighandler_dump_stack(int sig)322{323 psignal(sig, "perf");324 dump_stack();325 signal(sig, SIG_DFL);326 raise(sig);327}328