linux/tools/perf/util/debug.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* 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#ifdef HAVE_BACKTRACE_SUPPORT
  14#include <execinfo.h>
  15#endif
  16#include "color.h"
  17#include "event.h"
  18#include "debug.h"
  19#include "print_binary.h"
  20#include "target.h"
  21#include "ui/helpline.h"
  22#include "ui/ui.h"
  23#include "util/parse-sublevel-options.h"
  24
  25#include <linux/ctype.h>
  26
  27int verbose;
  28int debug_peo_args;
  29bool dump_trace = false, quiet = false;
  30int debug_ordered_events;
  31static int redirect_to_stderr;
  32int debug_data_convert;
  33
  34int veprintf(int level, int var, const char *fmt, va_list args)
  35{
  36        int ret = 0;
  37
  38        if (var >= level) {
  39                if (use_browser >= 1 && !redirect_to_stderr)
  40                        ui_helpline__vshow(fmt, args);
  41                else
  42                        ret = vfprintf(stderr, fmt, args);
  43        }
  44
  45        return ret;
  46}
  47
  48int eprintf(int level, int var, const char *fmt, ...)
  49{
  50        va_list args;
  51        int ret;
  52
  53        va_start(args, fmt);
  54        ret = veprintf(level, var, fmt, args);
  55        va_end(args);
  56
  57        return ret;
  58}
  59
  60static int veprintf_time(u64 t, const char *fmt, va_list args)
  61{
  62        int ret = 0;
  63        u64 secs, usecs, nsecs = t;
  64
  65        secs   = nsecs / NSEC_PER_SEC;
  66        nsecs -= secs  * NSEC_PER_SEC;
  67        usecs  = nsecs / NSEC_PER_USEC;
  68
  69        ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ",
  70                      secs, usecs);
  71        ret += vfprintf(stderr, fmt, args);
  72        return ret;
  73}
  74
  75int eprintf_time(int level, int var, u64 t, const char *fmt, ...)
  76{
  77        int ret = 0;
  78        va_list args;
  79
  80        if (var >= level) {
  81                va_start(args, fmt);
  82                ret = veprintf_time(t, fmt, args);
  83                va_end(args);
  84        }
  85
  86        return ret;
  87}
  88
  89/*
  90 * Overloading libtraceevent standard info print
  91 * function, display with -v in perf.
  92 */
  93void pr_stat(const char *fmt, ...)
  94{
  95        va_list args;
  96
  97        va_start(args, fmt);
  98        veprintf(1, verbose, fmt, args);
  99        va_end(args);
 100        eprintf(1, verbose, "\n");
 101}
 102
 103int dump_printf(const char *fmt, ...)
 104{
 105        va_list args;
 106        int ret = 0;
 107
 108        if (dump_trace) {
 109                va_start(args, fmt);
 110                ret = vprintf(fmt, args);
 111                va_end(args);
 112        }
 113
 114        return ret;
 115}
 116
 117static int trace_event_printer(enum binary_printer_ops op,
 118                               unsigned int val, void *extra, FILE *fp)
 119{
 120        const char *color = PERF_COLOR_BLUE;
 121        union perf_event *event = (union perf_event *)extra;
 122        unsigned char ch = (unsigned char)val;
 123        int printed = 0;
 124
 125        switch (op) {
 126        case BINARY_PRINT_DATA_BEGIN:
 127                printed += fprintf(fp, ".");
 128                printed += color_fprintf(fp, color, "\n. ... raw event: size %d bytes\n",
 129                                         event->header.size);
 130                break;
 131        case BINARY_PRINT_LINE_BEGIN:
 132                printed += fprintf(fp, ".");
 133                break;
 134        case BINARY_PRINT_ADDR:
 135                printed += color_fprintf(fp, color, "  %04x: ", val);
 136                break;
 137        case BINARY_PRINT_NUM_DATA:
 138                printed += color_fprintf(fp, color, " %02x", val);
 139                break;
 140        case BINARY_PRINT_NUM_PAD:
 141                printed += color_fprintf(fp, color, "   ");
 142                break;
 143        case BINARY_PRINT_SEP:
 144                printed += color_fprintf(fp, color, "  ");
 145                break;
 146        case BINARY_PRINT_CHAR_DATA:
 147                printed += color_fprintf(fp, color, "%c",
 148                              isprint(ch) ? ch : '.');
 149                break;
 150        case BINARY_PRINT_CHAR_PAD:
 151                printed += color_fprintf(fp, color, " ");
 152                break;
 153        case BINARY_PRINT_LINE_END:
 154                printed += color_fprintf(fp, color, "\n");
 155                break;
 156        case BINARY_PRINT_DATA_END:
 157                printed += fprintf(fp, "\n");
 158                break;
 159        default:
 160                break;
 161        }
 162
 163        return printed;
 164}
 165
 166void trace_event(union perf_event *event)
 167{
 168        unsigned char *raw_event = (void *)event;
 169
 170        if (!dump_trace)
 171                return;
 172
 173        print_binary(raw_event, event->header.size, 16,
 174                     trace_event_printer, event);
 175}
 176
 177static struct sublevel_option debug_opts[] = {
 178        { .name = "verbose",            .value_ptr = &verbose },
 179        { .name = "ordered-events",     .value_ptr = &debug_ordered_events},
 180        { .name = "stderr",             .value_ptr = &redirect_to_stderr},
 181        { .name = "data-convert",       .value_ptr = &debug_data_convert },
 182        { .name = "perf-event-open",    .value_ptr = &debug_peo_args },
 183        { .name = NULL, }
 184};
 185
 186int perf_debug_option(const char *str)
 187{
 188        int ret;
 189
 190        ret = perf_parse_sublevel_options(str, debug_opts);
 191        if (ret)
 192                return ret;
 193
 194        /* Allow only verbose value in range (0, 10), otherwise set 0. */
 195        verbose = (verbose < 0) || (verbose > 10) ? 0 : verbose;
 196
 197        return 0;
 198}
 199
 200int perf_quiet_option(void)
 201{
 202        struct sublevel_option *opt = &debug_opts[0];
 203
 204        /* disable all debug messages */
 205        while (opt->name) {
 206                *opt->value_ptr = -1;
 207                opt++;
 208        }
 209
 210        return 0;
 211}
 212
 213#define DEBUG_WRAPPER(__n, __l)                         \
 214static int pr_ ## __n ## _wrapper(const char *fmt, ...) \
 215{                                                       \
 216        va_list args;                                   \
 217        int ret;                                        \
 218                                                        \
 219        va_start(args, fmt);                            \
 220        ret = veprintf(__l, verbose, fmt, args);        \
 221        va_end(args);                                   \
 222        return ret;                                     \
 223}
 224
 225DEBUG_WRAPPER(warning, 0);
 226DEBUG_WRAPPER(debug, 1);
 227
 228void perf_debug_setup(void)
 229{
 230        libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper);
 231}
 232
 233/* Obtain a backtrace and print it to stdout. */
 234#ifdef HAVE_BACKTRACE_SUPPORT
 235void dump_stack(void)
 236{
 237        void *array[16];
 238        size_t size = backtrace(array, ARRAY_SIZE(array));
 239        char **strings = backtrace_symbols(array, size);
 240        size_t i;
 241
 242        printf("Obtained %zd stack frames.\n", size);
 243
 244        for (i = 0; i < size; i++)
 245                printf("%s\n", strings[i]);
 246
 247        free(strings);
 248}
 249#else
 250void dump_stack(void) {}
 251#endif
 252
 253void sighandler_dump_stack(int sig)
 254{
 255        psignal(sig, "perf");
 256        dump_stack();
 257        signal(sig, SIG_DFL);
 258        raise(sig);
 259}
 260