Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* For general debugging purposes */
0003 
0004 #include <inttypes.h>
0005 #include <string.h>
0006 #include <stdarg.h>
0007 #include <stdio.h>
0008 #include <stdlib.h>
0009 #include <sys/wait.h>
0010 #include <api/debug.h>
0011 #include <linux/kernel.h>
0012 #include <linux/time64.h>
0013 #include <sys/time.h>
0014 #ifdef HAVE_BACKTRACE_SUPPORT
0015 #include <execinfo.h>
0016 #endif
0017 #include "color.h"
0018 #include "event.h"
0019 #include "debug.h"
0020 #include "print_binary.h"
0021 #include "target.h"
0022 #include "ui/helpline.h"
0023 #include "ui/ui.h"
0024 #include "util/parse-sublevel-options.h"
0025 
0026 #include <linux/ctype.h>
0027 
0028 int verbose;
0029 int debug_peo_args;
0030 bool dump_trace = false, quiet = false;
0031 int debug_ordered_events;
0032 static int redirect_to_stderr;
0033 int debug_data_convert;
0034 static FILE *debug_file;
0035 bool debug_display_time;
0036 
0037 void debug_set_file(FILE *file)
0038 {
0039     debug_file = file;
0040 }
0041 
0042 void debug_set_display_time(bool set)
0043 {
0044     debug_display_time = set;
0045 }
0046 
0047 static int fprintf_time(FILE *file)
0048 {
0049     struct timeval tod;
0050     struct tm ltime;
0051     char date[64];
0052 
0053     if (!debug_display_time)
0054         return 0;
0055 
0056     if (gettimeofday(&tod, NULL) != 0)
0057         return 0;
0058 
0059     if (localtime_r(&tod.tv_sec, &ltime) == NULL)
0060         return 0;
0061 
0062     strftime(date, sizeof(date),  "%F %H:%M:%S", &ltime);
0063     return fprintf(file, "[%s.%06lu] ", date, (long)tod.tv_usec);
0064 }
0065 
0066 int veprintf(int level, int var, const char *fmt, va_list args)
0067 {
0068     int ret = 0;
0069 
0070     if (var >= level) {
0071         if (use_browser >= 1 && !redirect_to_stderr) {
0072             ui_helpline__vshow(fmt, args);
0073         } else {
0074             ret = fprintf_time(debug_file);
0075             ret += vfprintf(debug_file, fmt, args);
0076         }
0077     }
0078 
0079     return ret;
0080 }
0081 
0082 int eprintf(int level, int var, const char *fmt, ...)
0083 {
0084     va_list args;
0085     int ret;
0086 
0087     va_start(args, fmt);
0088     ret = veprintf(level, var, fmt, args);
0089     va_end(args);
0090 
0091     return ret;
0092 }
0093 
0094 static int veprintf_time(u64 t, const char *fmt, va_list args)
0095 {
0096     int ret = 0;
0097     u64 secs, usecs, nsecs = t;
0098 
0099     secs   = nsecs / NSEC_PER_SEC;
0100     nsecs -= secs  * NSEC_PER_SEC;
0101     usecs  = nsecs / NSEC_PER_USEC;
0102 
0103     ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ",
0104               secs, usecs);
0105     ret += vfprintf(stderr, fmt, args);
0106     return ret;
0107 }
0108 
0109 int eprintf_time(int level, int var, u64 t, const char *fmt, ...)
0110 {
0111     int ret = 0;
0112     va_list args;
0113 
0114     if (var >= level) {
0115         va_start(args, fmt);
0116         ret = veprintf_time(t, fmt, args);
0117         va_end(args);
0118     }
0119 
0120     return ret;
0121 }
0122 
0123 /*
0124  * Overloading libtraceevent standard info print
0125  * function, display with -v in perf.
0126  */
0127 void pr_stat(const char *fmt, ...)
0128 {
0129     va_list args;
0130 
0131     va_start(args, fmt);
0132     veprintf(1, verbose, fmt, args);
0133     va_end(args);
0134     eprintf(1, verbose, "\n");
0135 }
0136 
0137 int dump_printf(const char *fmt, ...)
0138 {
0139     va_list args;
0140     int ret = 0;
0141 
0142     if (dump_trace) {
0143         va_start(args, fmt);
0144         ret = vprintf(fmt, args);
0145         va_end(args);
0146     }
0147 
0148     return ret;
0149 }
0150 
0151 static int trace_event_printer(enum binary_printer_ops op,
0152                    unsigned int val, void *extra, FILE *fp)
0153 {
0154     const char *color = PERF_COLOR_BLUE;
0155     union perf_event *event = (union perf_event *)extra;
0156     unsigned char ch = (unsigned char)val;
0157     int printed = 0;
0158 
0159     switch (op) {
0160     case BINARY_PRINT_DATA_BEGIN:
0161         printed += fprintf(fp, ".");
0162         printed += color_fprintf(fp, color, "\n. ... raw event: size %d bytes\n",
0163                      event->header.size);
0164         break;
0165     case BINARY_PRINT_LINE_BEGIN:
0166         printed += fprintf(fp, ".");
0167         break;
0168     case BINARY_PRINT_ADDR:
0169         printed += color_fprintf(fp, color, "  %04x: ", val);
0170         break;
0171     case BINARY_PRINT_NUM_DATA:
0172         printed += color_fprintf(fp, color, " %02x", val);
0173         break;
0174     case BINARY_PRINT_NUM_PAD:
0175         printed += color_fprintf(fp, color, "   ");
0176         break;
0177     case BINARY_PRINT_SEP:
0178         printed += color_fprintf(fp, color, "  ");
0179         break;
0180     case BINARY_PRINT_CHAR_DATA:
0181         printed += color_fprintf(fp, color, "%c",
0182                   isprint(ch) && isascii(ch) ? ch : '.');
0183         break;
0184     case BINARY_PRINT_CHAR_PAD:
0185         printed += color_fprintf(fp, color, " ");
0186         break;
0187     case BINARY_PRINT_LINE_END:
0188         printed += color_fprintf(fp, color, "\n");
0189         break;
0190     case BINARY_PRINT_DATA_END:
0191         printed += fprintf(fp, "\n");
0192         break;
0193     default:
0194         break;
0195     }
0196 
0197     return printed;
0198 }
0199 
0200 void trace_event(union perf_event *event)
0201 {
0202     unsigned char *raw_event = (void *)event;
0203 
0204     if (!dump_trace)
0205         return;
0206 
0207     print_binary(raw_event, event->header.size, 16,
0208              trace_event_printer, event);
0209 }
0210 
0211 static struct sublevel_option debug_opts[] = {
0212     { .name = "verbose",        .value_ptr = &verbose },
0213     { .name = "ordered-events", .value_ptr = &debug_ordered_events},
0214     { .name = "stderr",     .value_ptr = &redirect_to_stderr},
0215     { .name = "data-convert",   .value_ptr = &debug_data_convert },
0216     { .name = "perf-event-open",    .value_ptr = &debug_peo_args },
0217     { .name = NULL, }
0218 };
0219 
0220 int perf_debug_option(const char *str)
0221 {
0222     int ret;
0223 
0224     ret = perf_parse_sublevel_options(str, debug_opts);
0225     if (ret)
0226         return ret;
0227 
0228     /* Allow only verbose value in range (0, 10), otherwise set 0. */
0229     verbose = (verbose < 0) || (verbose > 10) ? 0 : verbose;
0230 
0231     return 0;
0232 }
0233 
0234 int perf_quiet_option(void)
0235 {
0236     struct sublevel_option *opt = &debug_opts[0];
0237 
0238     /* disable all debug messages */
0239     while (opt->name) {
0240         *opt->value_ptr = -1;
0241         opt++;
0242     }
0243 
0244     return 0;
0245 }
0246 
0247 #define DEBUG_WRAPPER(__n, __l)             \
0248 static int pr_ ## __n ## _wrapper(const char *fmt, ...) \
0249 {                           \
0250     va_list args;                   \
0251     int ret;                    \
0252                             \
0253     va_start(args, fmt);                \
0254     ret = veprintf(__l, verbose, fmt, args);    \
0255     va_end(args);                   \
0256     return ret;                 \
0257 }
0258 
0259 DEBUG_WRAPPER(warning, 0);
0260 DEBUG_WRAPPER(debug, 1);
0261 
0262 void perf_debug_setup(void)
0263 {
0264     debug_set_file(stderr);
0265     libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper);
0266 }
0267 
0268 /* Obtain a backtrace and print it to stdout. */
0269 #ifdef HAVE_BACKTRACE_SUPPORT
0270 void dump_stack(void)
0271 {
0272     void *array[16];
0273     size_t size = backtrace(array, ARRAY_SIZE(array));
0274     char **strings = backtrace_symbols(array, size);
0275     size_t i;
0276 
0277     printf("Obtained %zd stack frames.\n", size);
0278 
0279     for (i = 0; i < size; i++)
0280         printf("%s\n", strings[i]);
0281 
0282     free(strings);
0283 }
0284 #else
0285 void dump_stack(void) {}
0286 #endif
0287 
0288 void sighandler_dump_stack(int sig)
0289 {
0290     psignal(sig, "perf");
0291     dump_stack();
0292     signal(sig, SIG_DFL);
0293     raise(sig);
0294 }