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