0001
0002
0003
0004
0005 #include <stdio.h>
0006 #include <stdlib.h>
0007 #include <string.h>
0008
0009 #include "event-parse.h"
0010 #include "event-utils.h"
0011 #include "trace-seq.h"
0012
0013 static struct func_stack {
0014 int size;
0015 char **stack;
0016 } *fstack;
0017
0018 static int cpus = -1;
0019
0020 #define STK_BLK 10
0021
0022 struct tep_plugin_option plugin_options[] =
0023 {
0024 {
0025 .name = "parent",
0026 .plugin_alias = "ftrace",
0027 .description =
0028 "Print parent of functions for function events",
0029 },
0030 {
0031 .name = "indent",
0032 .plugin_alias = "ftrace",
0033 .description =
0034 "Try to show function call indents, based on parents",
0035 .set = 1,
0036 },
0037 {
0038 .name = "offset",
0039 .plugin_alias = "ftrace",
0040 .description =
0041 "Show function names as well as their offsets",
0042 .set = 0,
0043 },
0044 {
0045 .name = NULL,
0046 }
0047 };
0048
0049 static struct tep_plugin_option *ftrace_parent = &plugin_options[0];
0050 static struct tep_plugin_option *ftrace_indent = &plugin_options[1];
0051 static struct tep_plugin_option *ftrace_offset = &plugin_options[2];
0052
0053 static void add_child(struct func_stack *stack, const char *child, int pos)
0054 {
0055 int i;
0056
0057 if (!child)
0058 return;
0059
0060 if (pos < stack->size)
0061 free(stack->stack[pos]);
0062 else {
0063 char **ptr;
0064
0065 ptr = realloc(stack->stack, sizeof(char *) *
0066 (stack->size + STK_BLK));
0067 if (!ptr) {
0068 warning("could not allocate plugin memory\n");
0069 return;
0070 }
0071
0072 stack->stack = ptr;
0073
0074 for (i = stack->size; i < stack->size + STK_BLK; i++)
0075 stack->stack[i] = NULL;
0076 stack->size += STK_BLK;
0077 }
0078
0079 stack->stack[pos] = strdup(child);
0080 }
0081
0082 static int add_and_get_index(const char *parent, const char *child, int cpu)
0083 {
0084 int i;
0085
0086 if (cpu < 0)
0087 return 0;
0088
0089 if (cpu > cpus) {
0090 struct func_stack *ptr;
0091
0092 ptr = realloc(fstack, sizeof(*fstack) * (cpu + 1));
0093 if (!ptr) {
0094 warning("could not allocate plugin memory\n");
0095 return 0;
0096 }
0097
0098 fstack = ptr;
0099
0100
0101 for (i = cpus + 1; i <= cpu; i++)
0102 memset(&fstack[i], 0, sizeof(fstack[i]));
0103 cpus = cpu;
0104 }
0105
0106 for (i = 0; i < fstack[cpu].size && fstack[cpu].stack[i]; i++) {
0107 if (strcmp(parent, fstack[cpu].stack[i]) == 0) {
0108 add_child(&fstack[cpu], child, i+1);
0109 return i;
0110 }
0111 }
0112
0113
0114 add_child(&fstack[cpu], parent, 0);
0115 add_child(&fstack[cpu], child, 1);
0116 return 0;
0117 }
0118
0119 static void show_function(struct trace_seq *s, struct tep_handle *tep,
0120 const char *func, unsigned long long function)
0121 {
0122 unsigned long long offset;
0123
0124 trace_seq_printf(s, "%s", func);
0125 if (ftrace_offset->set) {
0126 offset = tep_find_function_address(tep, function);
0127 trace_seq_printf(s, "+0x%x ", (int)(function - offset));
0128 }
0129 }
0130
0131 static int function_handler(struct trace_seq *s, struct tep_record *record,
0132 struct tep_event *event, void *context)
0133 {
0134 struct tep_handle *tep = event->tep;
0135 unsigned long long function;
0136 unsigned long long pfunction;
0137 const char *func;
0138 const char *parent;
0139 int index = 0;
0140
0141 if (tep_get_field_val(s, event, "ip", record, &function, 1))
0142 return trace_seq_putc(s, '!');
0143
0144 func = tep_find_function(tep, function);
0145
0146 if (tep_get_field_val(s, event, "parent_ip", record, &pfunction, 1))
0147 return trace_seq_putc(s, '!');
0148
0149 parent = tep_find_function(tep, pfunction);
0150
0151 if (parent && ftrace_indent->set)
0152 index = add_and_get_index(parent, func, record->cpu);
0153
0154 trace_seq_printf(s, "%*s", index*3, "");
0155
0156 if (func)
0157 show_function(s, tep, func, function);
0158 else
0159 trace_seq_printf(s, "0x%llx", function);
0160
0161 if (ftrace_parent->set) {
0162 trace_seq_printf(s, " <-- ");
0163 if (parent)
0164 show_function(s, tep, parent, pfunction);
0165 else
0166 trace_seq_printf(s, "0x%llx", pfunction);
0167 }
0168
0169 return 0;
0170 }
0171
0172 static int
0173 trace_stack_handler(struct trace_seq *s, struct tep_record *record,
0174 struct tep_event *event, void *context)
0175 {
0176 struct tep_format_field *field;
0177 unsigned long long addr;
0178 const char *func;
0179 int long_size;
0180 void *data = record->data;
0181
0182 field = tep_find_any_field(event, "caller");
0183 if (!field) {
0184 trace_seq_printf(s, "<CANT FIND FIELD %s>", "caller");
0185 return 0;
0186 }
0187
0188 trace_seq_puts(s, "<stack trace >\n");
0189
0190 long_size = tep_get_long_size(event->tep);
0191
0192 for (data += field->offset; data < record->data + record->size;
0193 data += long_size) {
0194 addr = tep_read_number(event->tep, data, long_size);
0195
0196 if ((long_size == 8 && addr == (unsigned long long)-1) ||
0197 ((int)addr == -1))
0198 break;
0199
0200 func = tep_find_function(event->tep, addr);
0201 if (func)
0202 trace_seq_printf(s, "=> %s (%llx)\n", func, addr);
0203 else
0204 trace_seq_printf(s, "=> %llx\n", addr);
0205 }
0206
0207 return 0;
0208 }
0209
0210 static int
0211 trace_raw_data_handler(struct trace_seq *s, struct tep_record *record,
0212 struct tep_event *event, void *context)
0213 {
0214 struct tep_format_field *field;
0215 unsigned long long id;
0216 int long_size;
0217 void *data = record->data;
0218
0219 if (tep_get_field_val(s, event, "id", record, &id, 1))
0220 return trace_seq_putc(s, '!');
0221
0222 trace_seq_printf(s, "# %llx", id);
0223
0224 field = tep_find_any_field(event, "buf");
0225 if (!field) {
0226 trace_seq_printf(s, "<CANT FIND FIELD %s>", "buf");
0227 return 0;
0228 }
0229
0230 long_size = tep_get_long_size(event->tep);
0231
0232 for (data += field->offset; data < record->data + record->size;
0233 data += long_size) {
0234 int size = sizeof(long);
0235 int left = (record->data + record->size) - data;
0236 int i;
0237
0238 if (size > left)
0239 size = left;
0240
0241 for (i = 0; i < size; i++)
0242 trace_seq_printf(s, " %02x", *(unsigned char *)(data + i));
0243 }
0244
0245 return 0;
0246 }
0247
0248 int TEP_PLUGIN_LOADER(struct tep_handle *tep)
0249 {
0250 tep_register_event_handler(tep, -1, "ftrace", "function",
0251 function_handler, NULL);
0252
0253 tep_register_event_handler(tep, -1, "ftrace", "kernel_stack",
0254 trace_stack_handler, NULL);
0255
0256 tep_register_event_handler(tep, -1, "ftrace", "raw_data",
0257 trace_raw_data_handler, NULL);
0258
0259 tep_plugin_add_options("ftrace", plugin_options);
0260
0261 return 0;
0262 }
0263
0264 void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
0265 {
0266 int i, x;
0267
0268 tep_unregister_event_handler(tep, -1, "ftrace", "function",
0269 function_handler, NULL);
0270
0271 for (i = 0; i <= cpus; i++) {
0272 for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++)
0273 free(fstack[i].stack[x]);
0274 free(fstack[i].stack);
0275 }
0276
0277 tep_plugin_remove_options(plugin_options);
0278
0279 free(fstack);
0280 fstack = NULL;
0281 cpus = -1;
0282 }