1 /* 2 * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com> 3 * 4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; version 2 of the License (not later!) 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 20 */ 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <ctype.h> 25 #include <errno.h> 26 27 #include "../perf.h" 28 #include "util.h" 29 #include "trace-event.h" 30 31 bool latency_format; 32 33 struct pevent *read_trace_init(int file_bigendian, int host_bigendian) 34 { 35 struct pevent *pevent = pevent_alloc(); 36 37 if (pevent != NULL) { 38 pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); 39 pevent_set_file_bigendian(pevent, file_bigendian); 40 pevent_set_host_bigendian(pevent, host_bigendian); 41 } 42 43 return pevent; 44 } 45 46 static int get_common_field(struct scripting_context *context, 47 int *offset, int *size, const char *type) 48 { 49 struct pevent *pevent = context->pevent; 50 struct event_format *event; 51 struct format_field *field; 52 53 if (!*size) { 54 if (!pevent->events) 55 return 0; 56 57 event = pevent->events[0]; 58 field = pevent_find_common_field(event, type); 59 if (!field) 60 return 0; 61 *offset = field->offset; 62 *size = field->size; 63 } 64 65 return pevent_read_number(pevent, context->event_data + *offset, *size); 66 } 67 68 int common_lock_depth(struct scripting_context *context) 69 { 70 static int offset; 71 static int size; 72 int ret; 73 74 ret = get_common_field(context, &size, &offset, 75 "common_lock_depth"); 76 if (ret < 0) 77 return -1; 78 79 return ret; 80 } 81 82 int common_flags(struct scripting_context *context) 83 { 84 static int offset; 85 static int size; 86 int ret; 87 88 ret = get_common_field(context, &size, &offset, 89 "common_flags"); 90 if (ret < 0) 91 return -1; 92 93 return ret; 94 } 95 96 int common_pc(struct scripting_context *context) 97 { 98 static int offset; 99 static int size; 100 int ret; 101 102 ret = get_common_field(context, &size, &offset, 103 "common_preempt_count"); 104 if (ret < 0) 105 return -1; 106 107 return ret; 108 } 109 110 unsigned long long 111 raw_field_value(struct event_format *event, const char *name, void *data) 112 { 113 struct format_field *field; 114 unsigned long long val; 115 116 field = pevent_find_any_field(event, name); 117 if (!field) 118 return 0ULL; 119 120 pevent_read_number_field(field, data, &val); 121 122 return val; 123 } 124 125 void *raw_field_ptr(struct event_format *event, const char *name, void *data) 126 { 127 struct format_field *field; 128 129 field = pevent_find_any_field(event, name); 130 if (!field) 131 return NULL; 132 133 if (field->flags & FIELD_IS_DYNAMIC) { 134 int offset; 135 136 offset = *(int *)(data + field->offset); 137 offset &= 0xffff; 138 139 return data + offset; 140 } 141 142 return data + field->offset; 143 } 144 145 int trace_parse_common_type(struct pevent *pevent, void *data) 146 { 147 struct pevent_record record; 148 149 record.data = data; 150 return pevent_data_type(pevent, &record); 151 } 152 153 int trace_parse_common_pid(struct pevent *pevent, void *data) 154 { 155 struct pevent_record record; 156 157 record.data = data; 158 return pevent_data_pid(pevent, &record); 159 } 160 161 unsigned long long read_size(struct event_format *event, void *ptr, int size) 162 { 163 return pevent_read_number(event->pevent, ptr, size); 164 } 165 166 void event_format__print(struct event_format *event, 167 int cpu, void *data, int size) 168 { 169 struct pevent_record record; 170 struct trace_seq s; 171 172 memset(&record, 0, sizeof(record)); 173 record.cpu = cpu; 174 record.size = size; 175 record.data = data; 176 177 trace_seq_init(&s); 178 pevent_event_info(&s, event, &record); 179 trace_seq_do_printf(&s); 180 } 181 182 void parse_proc_kallsyms(struct pevent *pevent, 183 char *file, unsigned int size __maybe_unused) 184 { 185 unsigned long long addr; 186 char *func; 187 char *line; 188 char *next = NULL; 189 char *addr_str; 190 char *mod; 191 char *fmt; 192 193 line = strtok_r(file, "\n", &next); 194 while (line) { 195 mod = NULL; 196 addr_str = strtok_r(line, " ", &fmt); 197 addr = strtoull(addr_str, NULL, 16); 198 /* skip character */ 199 strtok_r(NULL, " ", &fmt); 200 func = strtok_r(NULL, "\t", &fmt); 201 mod = strtok_r(NULL, "]", &fmt); 202 /* truncate the extra '[' */ 203 if (mod) 204 mod = mod + 1; 205 206 pevent_register_function(pevent, func, addr, mod); 207 208 line = strtok_r(NULL, "\n", &next); 209 } 210 } 211 212 void parse_ftrace_printk(struct pevent *pevent, 213 char *file, unsigned int size __maybe_unused) 214 { 215 unsigned long long addr; 216 char *printk; 217 char *line; 218 char *next = NULL; 219 char *addr_str; 220 char *fmt; 221 222 line = strtok_r(file, "\n", &next); 223 while (line) { 224 addr_str = strtok_r(line, ":", &fmt); 225 if (!addr_str) { 226 warning("printk format with empty entry"); 227 break; 228 } 229 addr = strtoull(addr_str, NULL, 16); 230 /* fmt still has a space, skip it */ 231 printk = strdup(fmt+1); 232 line = strtok_r(NULL, "\n", &next); 233 pevent_register_print_string(pevent, printk, addr); 234 } 235 } 236 237 int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size) 238 { 239 return pevent_parse_event(pevent, buf, size, "ftrace"); 240 } 241 242 int parse_event_file(struct pevent *pevent, 243 char *buf, unsigned long size, char *sys) 244 { 245 return pevent_parse_event(pevent, buf, size, sys); 246 } 247 248 struct event_format *trace_find_next_event(struct pevent *pevent, 249 struct event_format *event) 250 { 251 static int idx; 252 253 if (!pevent || !pevent->events) 254 return NULL; 255 256 if (!event) { 257 idx = 0; 258 return pevent->events[0]; 259 } 260 261 if (idx < pevent->nr_events && event == pevent->events[idx]) { 262 idx++; 263 if (idx == pevent->nr_events) 264 return NULL; 265 return pevent->events[idx]; 266 } 267 268 for (idx = 1; idx < pevent->nr_events; idx++) { 269 if (event == pevent->events[idx - 1]) 270 return pevent->events[idx]; 271 } 272 return NULL; 273 } 274 275 struct flag { 276 const char *name; 277 unsigned long long value; 278 }; 279 280 static const struct flag flags[] = { 281 { "HI_SOFTIRQ", 0 }, 282 { "TIMER_SOFTIRQ", 1 }, 283 { "NET_TX_SOFTIRQ", 2 }, 284 { "NET_RX_SOFTIRQ", 3 }, 285 { "BLOCK_SOFTIRQ", 4 }, 286 { "BLOCK_IOPOLL_SOFTIRQ", 5 }, 287 { "TASKLET_SOFTIRQ", 6 }, 288 { "SCHED_SOFTIRQ", 7 }, 289 { "HRTIMER_SOFTIRQ", 8 }, 290 { "RCU_SOFTIRQ", 9 }, 291 292 { "HRTIMER_NORESTART", 0 }, 293 { "HRTIMER_RESTART", 1 }, 294 }; 295 296 unsigned long long eval_flag(const char *flag) 297 { 298 int i; 299 300 /* 301 * Some flags in the format files do not get converted. 302 * If the flag is not numeric, see if it is something that 303 * we already know about. 304 */ 305 if (isdigit(flag[0])) 306 return strtoull(flag, NULL, 0); 307 308 for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++) 309 if (strcmp(flags[i].name, flag) == 0) 310 return flags[i].value; 311 312 return 0; 313 } 314