1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com> 4 */ 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <errno.h> 9 10 #include "debug.h" 11 #include "trace-event.h" 12 13 #include <linux/ctype.h> 14 #include <linux/kernel.h> 15 #include <traceevent/event-parse.h> 16 17 static int get_common_field(struct scripting_context *context, 18 int *offset, int *size, const char *type) 19 { 20 struct tep_handle *pevent = context->pevent; 21 struct tep_event *event; 22 struct tep_format_field *field; 23 24 if (!*size) { 25 26 event = tep_get_first_event(pevent); 27 if (!event) 28 return 0; 29 30 field = tep_find_common_field(event, type); 31 if (!field) 32 return 0; 33 *offset = field->offset; 34 *size = field->size; 35 } 36 37 return tep_read_number(pevent, context->event_data + *offset, *size); 38 } 39 40 int common_lock_depth(struct scripting_context *context) 41 { 42 static int offset; 43 static int size; 44 int ret; 45 46 ret = get_common_field(context, &size, &offset, 47 "common_lock_depth"); 48 if (ret < 0) 49 return -1; 50 51 return ret; 52 } 53 54 int common_flags(struct scripting_context *context) 55 { 56 static int offset; 57 static int size; 58 int ret; 59 60 ret = get_common_field(context, &size, &offset, 61 "common_flags"); 62 if (ret < 0) 63 return -1; 64 65 return ret; 66 } 67 68 int common_pc(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_preempt_count"); 76 if (ret < 0) 77 return -1; 78 79 return ret; 80 } 81 82 unsigned long long 83 raw_field_value(struct tep_event *event, const char *name, void *data) 84 { 85 struct tep_format_field *field; 86 unsigned long long val; 87 88 field = tep_find_any_field(event, name); 89 if (!field) 90 return 0ULL; 91 92 tep_read_number_field(field, data, &val); 93 94 return val; 95 } 96 97 unsigned long long read_size(struct tep_event *event, void *ptr, int size) 98 { 99 return tep_read_number(event->tep, ptr, size); 100 } 101 102 void event_format__fprintf(struct tep_event *event, 103 int cpu, void *data, int size, FILE *fp) 104 { 105 struct tep_record record; 106 struct trace_seq s; 107 108 memset(&record, 0, sizeof(record)); 109 record.cpu = cpu; 110 record.size = size; 111 record.data = data; 112 113 trace_seq_init(&s); 114 tep_print_event(event->tep, &s, &record, "%s", TEP_PRINT_INFO); 115 trace_seq_do_fprintf(&s, fp); 116 trace_seq_destroy(&s); 117 } 118 119 void event_format__print(struct tep_event *event, 120 int cpu, void *data, int size) 121 { 122 return event_format__fprintf(event, cpu, data, size, stdout); 123 } 124 125 /* 126 * prev_state is of size long, which is 32 bits on 32 bit architectures. 127 * As it needs to have the same bits for both 32 bit and 64 bit architectures 128 * we can just assume that the flags we care about will all be within 129 * the 32 bits. 130 */ 131 #define MAX_STATE_BITS 32 132 133 static const char *convert_sym(struct tep_print_flag_sym *sym) 134 { 135 static char save_states[MAX_STATE_BITS + 1]; 136 137 memset(save_states, 0, sizeof(save_states)); 138 139 /* This is the flags for the prev_state_field, now make them into a string */ 140 for (; sym; sym = sym->next) { 141 long bitmask = strtoul(sym->value, NULL, 0); 142 int i; 143 144 for (i = 0; !(bitmask & 1); i++) 145 bitmask >>= 1; 146 147 if (i >= MAX_STATE_BITS) 148 continue; 149 150 save_states[i] = sym->str[0]; 151 } 152 153 return save_states; 154 } 155 156 static struct tep_print_arg_field * 157 find_arg_field(struct tep_format_field *prev_state_field, struct tep_print_arg *arg) 158 { 159 struct tep_print_arg_field *field; 160 161 if (!arg) 162 return NULL; 163 164 if (arg->type == TEP_PRINT_FIELD) 165 return &arg->field; 166 167 if (arg->type == TEP_PRINT_OP) { 168 field = find_arg_field(prev_state_field, arg->op.left); 169 if (field && field->field == prev_state_field) 170 return field; 171 field = find_arg_field(prev_state_field, arg->op.right); 172 if (field && field->field == prev_state_field) 173 return field; 174 } 175 return NULL; 176 } 177 178 static struct tep_print_flag_sym * 179 test_flags(struct tep_format_field *prev_state_field, struct tep_print_arg *arg) 180 { 181 struct tep_print_arg_field *field; 182 183 field = find_arg_field(prev_state_field, arg->flags.field); 184 if (!field) 185 return NULL; 186 187 return arg->flags.flags; 188 } 189 190 static struct tep_print_flag_sym * 191 search_op(struct tep_format_field *prev_state_field, struct tep_print_arg *arg) 192 { 193 struct tep_print_flag_sym *sym = NULL; 194 195 if (!arg) 196 return NULL; 197 198 if (arg->type == TEP_PRINT_OP) { 199 sym = search_op(prev_state_field, arg->op.left); 200 if (sym) 201 return sym; 202 203 sym = search_op(prev_state_field, arg->op.right); 204 if (sym) 205 return sym; 206 } else if (arg->type == TEP_PRINT_FLAGS) { 207 sym = test_flags(prev_state_field, arg); 208 } 209 210 return sym; 211 } 212 213 const char *parse_task_states(struct tep_format_field *state_field) 214 { 215 struct tep_print_flag_sym *sym; 216 struct tep_print_arg *arg; 217 struct tep_event *event; 218 219 event = state_field->event; 220 221 /* 222 * Look at the event format fields, and search for where 223 * the prev_state is parsed via the format flags. 224 */ 225 for (arg = event->print_fmt.args; arg; arg = arg->next) { 226 /* 227 * Currently, the __print_flags() for the prev_state 228 * is embedded in operations, so they too must be 229 * searched. 230 */ 231 sym = search_op(state_field, arg); 232 if (sym) 233 return convert_sym(sym); 234 } 235 return NULL; 236 } 237 238 void parse_ftrace_printk(struct tep_handle *pevent, 239 char *file, unsigned int size __maybe_unused) 240 { 241 unsigned long long addr; 242 char *printk; 243 char *line; 244 char *next = NULL; 245 char *addr_str; 246 char *fmt = NULL; 247 248 line = strtok_r(file, "\n", &next); 249 while (line) { 250 addr_str = strtok_r(line, ":", &fmt); 251 if (!addr_str) { 252 pr_warning("printk format with empty entry"); 253 break; 254 } 255 addr = strtoull(addr_str, NULL, 16); 256 /* fmt still has a space, skip it */ 257 printk = strdup(fmt+1); 258 line = strtok_r(NULL, "\n", &next); 259 tep_register_print_string(pevent, printk, addr); 260 free(printk); 261 } 262 } 263 264 void parse_saved_cmdline(struct tep_handle *pevent, 265 char *file, unsigned int size __maybe_unused) 266 { 267 char comm[17]; /* Max comm length in the kernel is 16. */ 268 char *line; 269 char *next = NULL; 270 int pid; 271 272 line = strtok_r(file, "\n", &next); 273 while (line) { 274 if (sscanf(line, "%d %16s", &pid, comm) == 2) 275 tep_register_comm(pevent, comm, pid); 276 line = strtok_r(NULL, "\n", &next); 277 } 278 } 279 280 int parse_ftrace_file(struct tep_handle *pevent, char *buf, unsigned long size) 281 { 282 return tep_parse_event(pevent, buf, size, "ftrace"); 283 } 284 285 int parse_event_file(struct tep_handle *pevent, 286 char *buf, unsigned long size, char *sys) 287 { 288 return tep_parse_event(pevent, buf, size, sys); 289 } 290 291 struct flag { 292 const char *name; 293 unsigned long long value; 294 }; 295 296 static const struct flag flags[] = { 297 { "HI_SOFTIRQ", 0 }, 298 { "TIMER_SOFTIRQ", 1 }, 299 { "NET_TX_SOFTIRQ", 2 }, 300 { "NET_RX_SOFTIRQ", 3 }, 301 { "BLOCK_SOFTIRQ", 4 }, 302 { "IRQ_POLL_SOFTIRQ", 5 }, 303 { "TASKLET_SOFTIRQ", 6 }, 304 { "SCHED_SOFTIRQ", 7 }, 305 { "HRTIMER_SOFTIRQ", 8 }, 306 { "RCU_SOFTIRQ", 9 }, 307 308 { "HRTIMER_NORESTART", 0 }, 309 { "HRTIMER_RESTART", 1 }, 310 }; 311 312 unsigned long long eval_flag(const char *flag) 313 { 314 int i; 315 316 /* 317 * Some flags in the format files do not get converted. 318 * If the flag is not numeric, see if it is something that 319 * we already know about. 320 */ 321 if (isdigit(flag[0])) 322 return strtoull(flag, NULL, 0); 323 324 for (i = 0; i < (int)(ARRAY_SIZE(flags)); i++) 325 if (strcmp(flags[i].name, flag) == 0) 326 return flags[i].value; 327 328 return 0; 329 } 330
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.