linux/tools/lib/traceevent/plugins/plugin_function.c
<<
>>
Prefs
   1// SPDX-License-Identifier: LGPL-2.1
   2/*
   3 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
   4 */
   5#include <stdio.h>
   6#include <stdlib.h>
   7#include <string.h>
   8
   9#include "event-parse.h"
  10#include "event-utils.h"
  11#include "trace-seq.h"
  12
  13static struct func_stack {
  14        int size;
  15        char **stack;
  16} *fstack;
  17
  18static int cpus = -1;
  19
  20#define STK_BLK 10
  21
  22struct tep_plugin_option plugin_options[] =
  23{
  24        {
  25                .name = "parent",
  26                .plugin_alias = "ftrace",
  27                .description =
  28                "Print parent of functions for function events",
  29        },
  30        {
  31                .name = "indent",
  32                .plugin_alias = "ftrace",
  33                .description =
  34                "Try to show function call indents, based on parents",
  35                .set = 1,
  36        },
  37        {
  38                .name = "offset",
  39                .plugin_alias = "ftrace",
  40                .description =
  41                "Show function names as well as their offsets",
  42                .set = 0,
  43        },
  44        {
  45                .name = NULL,
  46        }
  47};
  48
  49static struct tep_plugin_option *ftrace_parent = &plugin_options[0];
  50static struct tep_plugin_option *ftrace_indent = &plugin_options[1];
  51static struct tep_plugin_option *ftrace_offset = &plugin_options[2];
  52
  53static void add_child(struct func_stack *stack, const char *child, int pos)
  54{
  55        int i;
  56
  57        if (!child)
  58                return;
  59
  60        if (pos < stack->size)
  61                free(stack->stack[pos]);
  62        else {
  63                char **ptr;
  64
  65                ptr = realloc(stack->stack, sizeof(char *) *
  66                              (stack->size + STK_BLK));
  67                if (!ptr) {
  68                        warning("could not allocate plugin memory\n");
  69                        return;
  70                }
  71
  72                stack->stack = ptr;
  73
  74                for (i = stack->size; i < stack->size + STK_BLK; i++)
  75                        stack->stack[i] = NULL;
  76                stack->size += STK_BLK;
  77        }
  78
  79        stack->stack[pos] = strdup(child);
  80}
  81
  82static int add_and_get_index(const char *parent, const char *child, int cpu)
  83{
  84        int i;
  85
  86        if (cpu < 0)
  87                return 0;
  88
  89        if (cpu > cpus) {
  90                struct func_stack *ptr;
  91
  92                ptr = realloc(fstack, sizeof(*fstack) * (cpu + 1));
  93                if (!ptr) {
  94                        warning("could not allocate plugin memory\n");
  95                        return 0;
  96                }
  97
  98                fstack = ptr;
  99
 100                /* Account for holes in the cpu count */
 101                for (i = cpus + 1; i <= cpu; i++)
 102                        memset(&fstack[i], 0, sizeof(fstack[i]));
 103                cpus = cpu;
 104        }
 105
 106        for (i = 0; i < fstack[cpu].size && fstack[cpu].stack[i]; i++) {
 107                if (strcmp(parent, fstack[cpu].stack[i]) == 0) {
 108                        add_child(&fstack[cpu], child, i+1);
 109                        return i;
 110                }
 111        }
 112
 113        /* Not found */
 114        add_child(&fstack[cpu], parent, 0);
 115        add_child(&fstack[cpu], child, 1);
 116        return 0;
 117}
 118
 119static void show_function(struct trace_seq *s, struct tep_handle *tep,
 120                          const char *func, unsigned long long function)
 121{
 122        unsigned long long offset;
 123
 124        trace_seq_printf(s, "%s", func);
 125        if (ftrace_offset->set) {
 126                offset = tep_find_function_address(tep, function);
 127                trace_seq_printf(s, "+0x%x ", (int)(function - offset));
 128        }
 129}
 130
 131static int function_handler(struct trace_seq *s, struct tep_record *record,
 132                            struct tep_event *event, void *context)
 133{
 134        struct tep_handle *tep = event->tep;
 135        unsigned long long function;
 136        unsigned long long pfunction;
 137        const char *func;
 138        const char *parent;
 139        int index = 0;
 140
 141        if (tep_get_field_val(s, event, "ip", record, &function, 1))
 142                return trace_seq_putc(s, '!');
 143
 144        func = tep_find_function(tep, function);
 145
 146        if (tep_get_field_val(s, event, "parent_ip", record, &pfunction, 1))
 147                return trace_seq_putc(s, '!');
 148
 149        parent = tep_find_function(tep, pfunction);
 150
 151        if (parent && ftrace_indent->set)
 152                index = add_and_get_index(parent, func, record->cpu);
 153
 154        trace_seq_printf(s, "%*s", index*3, "");
 155
 156        if (func)
 157                show_function(s, tep, func, function);
 158        else
 159                trace_seq_printf(s, "0x%llx", function);
 160
 161        if (ftrace_parent->set) {
 162                trace_seq_printf(s, " <-- ");
 163                if (parent)
 164                        show_function(s, tep, parent, pfunction);
 165                else
 166                        trace_seq_printf(s, "0x%llx", pfunction);
 167        }
 168
 169        return 0;
 170}
 171
 172static int
 173trace_stack_handler(struct trace_seq *s, struct tep_record *record,
 174                    struct tep_event *event, void *context)
 175{
 176        struct tep_format_field *field;
 177        unsigned long long addr;
 178        const char *func;
 179        int long_size;
 180        void *data = record->data;
 181
 182        field = tep_find_any_field(event, "caller");
 183        if (!field) {
 184                trace_seq_printf(s, "<CANT FIND FIELD %s>", "caller");
 185                return 0;
 186        }
 187
 188        trace_seq_puts(s, "<stack trace >\n");
 189
 190        long_size = tep_get_long_size(event->tep);
 191
 192        for (data += field->offset; data < record->data + record->size;
 193             data += long_size) {
 194                addr = tep_read_number(event->tep, data, long_size);
 195
 196                if ((long_size == 8 && addr == (unsigned long long)-1) ||
 197                    ((int)addr == -1))
 198                        break;
 199
 200                func = tep_find_function(event->tep, addr);
 201                if (func)
 202                        trace_seq_printf(s, "=> %s (%llx)\n", func, addr);
 203                else
 204                        trace_seq_printf(s, "=> %llx\n", addr);
 205        }
 206
 207        return 0;
 208}
 209
 210static int
 211trace_raw_data_handler(struct trace_seq *s, struct tep_record *record,
 212                    struct tep_event *event, void *context)
 213{
 214        struct tep_format_field *field;
 215        unsigned long long id;
 216        int long_size;
 217        void *data = record->data;
 218
 219        if (tep_get_field_val(s, event, "id", record, &id, 1))
 220                return trace_seq_putc(s, '!');
 221
 222        trace_seq_printf(s, "# %llx", id);
 223
 224        field = tep_find_any_field(event, "buf");
 225        if (!field) {
 226                trace_seq_printf(s, "<CANT FIND FIELD %s>", "buf");
 227                return 0;
 228        }
 229
 230        long_size = tep_get_long_size(event->tep);
 231
 232        for (data += field->offset; data < record->data + record->size;
 233             data += long_size) {
 234                int size = sizeof(long);
 235                int left = (record->data + record->size) - data;
 236                int i;
 237
 238                if (size > left)
 239                        size = left;
 240
 241                for (i = 0; i < size; i++)
 242                        trace_seq_printf(s, " %02x", *(unsigned char *)(data + i));
 243        }
 244
 245        return 0;
 246}
 247
 248int TEP_PLUGIN_LOADER(struct tep_handle *tep)
 249{
 250        tep_register_event_handler(tep, -1, "ftrace", "function",
 251                                   function_handler, NULL);
 252
 253        tep_register_event_handler(tep, -1, "ftrace", "kernel_stack",
 254                                      trace_stack_handler, NULL);
 255
 256        tep_register_event_handler(tep, -1, "ftrace", "raw_data",
 257                                      trace_raw_data_handler, NULL);
 258
 259        tep_plugin_add_options("ftrace", plugin_options);
 260
 261        return 0;
 262}
 263
 264void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
 265{
 266        int i, x;
 267
 268        tep_unregister_event_handler(tep, -1, "ftrace", "function",
 269                                     function_handler, NULL);
 270
 271        for (i = 0; i <= cpus; i++) {
 272                for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++)
 273                        free(fstack[i].stack[x]);
 274                free(fstack[i].stack);
 275        }
 276
 277        tep_plugin_remove_options(plugin_options);
 278
 279        free(fstack);
 280        fstack = NULL;
 281        cpus = -1;
 282}
 283