18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#include <stdio.h> 68c2ecf20Sopenharmony_ci#include <stdlib.h> 78c2ecf20Sopenharmony_ci#include <string.h> 88c2ecf20Sopenharmony_ci#include <errno.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "debug.h" 118c2ecf20Sopenharmony_ci#include "trace-event.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/ctype.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic int get_common_field(struct scripting_context *context, 168c2ecf20Sopenharmony_ci int *offset, int *size, const char *type) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci struct tep_handle *pevent = context->pevent; 198c2ecf20Sopenharmony_ci struct tep_event *event; 208c2ecf20Sopenharmony_ci struct tep_format_field *field; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci if (!*size) { 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci event = tep_get_first_event(pevent); 258c2ecf20Sopenharmony_ci if (!event) 268c2ecf20Sopenharmony_ci return 0; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci field = tep_find_common_field(event, type); 298c2ecf20Sopenharmony_ci if (!field) 308c2ecf20Sopenharmony_ci return 0; 318c2ecf20Sopenharmony_ci *offset = field->offset; 328c2ecf20Sopenharmony_ci *size = field->size; 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci return tep_read_number(pevent, context->event_data + *offset, *size); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ciint common_lock_depth(struct scripting_context *context) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci static int offset; 418c2ecf20Sopenharmony_ci static int size; 428c2ecf20Sopenharmony_ci int ret; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci ret = get_common_field(context, &size, &offset, 458c2ecf20Sopenharmony_ci "common_lock_depth"); 468c2ecf20Sopenharmony_ci if (ret < 0) 478c2ecf20Sopenharmony_ci return -1; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci return ret; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ciint common_flags(struct scripting_context *context) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci static int offset; 558c2ecf20Sopenharmony_ci static int size; 568c2ecf20Sopenharmony_ci int ret; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci ret = get_common_field(context, &size, &offset, 598c2ecf20Sopenharmony_ci "common_flags"); 608c2ecf20Sopenharmony_ci if (ret < 0) 618c2ecf20Sopenharmony_ci return -1; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return ret; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ciint common_pc(struct scripting_context *context) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci static int offset; 698c2ecf20Sopenharmony_ci static int size; 708c2ecf20Sopenharmony_ci int ret; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci ret = get_common_field(context, &size, &offset, 738c2ecf20Sopenharmony_ci "common_preempt_count"); 748c2ecf20Sopenharmony_ci if (ret < 0) 758c2ecf20Sopenharmony_ci return -1; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci return ret; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciunsigned long long 818c2ecf20Sopenharmony_ciraw_field_value(struct tep_event *event, const char *name, void *data) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct tep_format_field *field; 848c2ecf20Sopenharmony_ci unsigned long long val; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci field = tep_find_any_field(event, name); 878c2ecf20Sopenharmony_ci if (!field) 888c2ecf20Sopenharmony_ci return 0ULL; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci tep_read_number_field(field, data, &val); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci return val; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ciunsigned long long read_size(struct tep_event *event, void *ptr, int size) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci return tep_read_number(event->tep, ptr, size); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_civoid event_format__fprintf(struct tep_event *event, 1018c2ecf20Sopenharmony_ci int cpu, void *data, int size, FILE *fp) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct tep_record record; 1048c2ecf20Sopenharmony_ci struct trace_seq s; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci memset(&record, 0, sizeof(record)); 1078c2ecf20Sopenharmony_ci record.cpu = cpu; 1088c2ecf20Sopenharmony_ci record.size = size; 1098c2ecf20Sopenharmony_ci record.data = data; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci trace_seq_init(&s); 1128c2ecf20Sopenharmony_ci tep_print_event(event->tep, &s, &record, "%s", TEP_PRINT_INFO); 1138c2ecf20Sopenharmony_ci trace_seq_do_fprintf(&s, fp); 1148c2ecf20Sopenharmony_ci trace_seq_destroy(&s); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_civoid event_format__print(struct tep_event *event, 1188c2ecf20Sopenharmony_ci int cpu, void *data, int size) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci return event_format__fprintf(event, cpu, data, size, stdout); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_civoid parse_ftrace_printk(struct tep_handle *pevent, 1248c2ecf20Sopenharmony_ci char *file, unsigned int size __maybe_unused) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci unsigned long long addr; 1278c2ecf20Sopenharmony_ci char *printk; 1288c2ecf20Sopenharmony_ci char *line; 1298c2ecf20Sopenharmony_ci char *next = NULL; 1308c2ecf20Sopenharmony_ci char *addr_str; 1318c2ecf20Sopenharmony_ci char *fmt = NULL; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci line = strtok_r(file, "\n", &next); 1348c2ecf20Sopenharmony_ci while (line) { 1358c2ecf20Sopenharmony_ci addr_str = strtok_r(line, ":", &fmt); 1368c2ecf20Sopenharmony_ci if (!addr_str) { 1378c2ecf20Sopenharmony_ci pr_warning("printk format with empty entry"); 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci addr = strtoull(addr_str, NULL, 16); 1418c2ecf20Sopenharmony_ci /* fmt still has a space, skip it */ 1428c2ecf20Sopenharmony_ci printk = strdup(fmt+1); 1438c2ecf20Sopenharmony_ci line = strtok_r(NULL, "\n", &next); 1448c2ecf20Sopenharmony_ci tep_register_print_string(pevent, printk, addr); 1458c2ecf20Sopenharmony_ci free(printk); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_civoid parse_saved_cmdline(struct tep_handle *pevent, 1508c2ecf20Sopenharmony_ci char *file, unsigned int size __maybe_unused) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci char comm[17]; /* Max comm length in the kernel is 16. */ 1538c2ecf20Sopenharmony_ci char *line; 1548c2ecf20Sopenharmony_ci char *next = NULL; 1558c2ecf20Sopenharmony_ci int pid; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci line = strtok_r(file, "\n", &next); 1588c2ecf20Sopenharmony_ci while (line) { 1598c2ecf20Sopenharmony_ci if (sscanf(line, "%d %16s", &pid, comm) == 2) 1608c2ecf20Sopenharmony_ci tep_register_comm(pevent, comm, pid); 1618c2ecf20Sopenharmony_ci line = strtok_r(NULL, "\n", &next); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ciint parse_ftrace_file(struct tep_handle *pevent, char *buf, unsigned long size) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci return tep_parse_event(pevent, buf, size, "ftrace"); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ciint parse_event_file(struct tep_handle *pevent, 1718c2ecf20Sopenharmony_ci char *buf, unsigned long size, char *sys) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci return tep_parse_event(pevent, buf, size, sys); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistruct flag { 1778c2ecf20Sopenharmony_ci const char *name; 1788c2ecf20Sopenharmony_ci unsigned long long value; 1798c2ecf20Sopenharmony_ci}; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic const struct flag flags[] = { 1828c2ecf20Sopenharmony_ci { "HI_SOFTIRQ", 0 }, 1838c2ecf20Sopenharmony_ci { "TIMER_SOFTIRQ", 1 }, 1848c2ecf20Sopenharmony_ci { "NET_TX_SOFTIRQ", 2 }, 1858c2ecf20Sopenharmony_ci { "NET_RX_SOFTIRQ", 3 }, 1868c2ecf20Sopenharmony_ci { "BLOCK_SOFTIRQ", 4 }, 1878c2ecf20Sopenharmony_ci { "IRQ_POLL_SOFTIRQ", 5 }, 1888c2ecf20Sopenharmony_ci { "TASKLET_SOFTIRQ", 6 }, 1898c2ecf20Sopenharmony_ci { "SCHED_SOFTIRQ", 7 }, 1908c2ecf20Sopenharmony_ci { "HRTIMER_SOFTIRQ", 8 }, 1918c2ecf20Sopenharmony_ci { "RCU_SOFTIRQ", 9 }, 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci { "HRTIMER_NORESTART", 0 }, 1948c2ecf20Sopenharmony_ci { "HRTIMER_RESTART", 1 }, 1958c2ecf20Sopenharmony_ci}; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ciunsigned long long eval_flag(const char *flag) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci int i; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* 2028c2ecf20Sopenharmony_ci * Some flags in the format files do not get converted. 2038c2ecf20Sopenharmony_ci * If the flag is not numeric, see if it is something that 2048c2ecf20Sopenharmony_ci * we already know about. 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ci if (isdigit(flag[0])) 2078c2ecf20Sopenharmony_ci return strtoull(flag, NULL, 0); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++) 2108c2ecf20Sopenharmony_ci if (strcmp(flags[i].name, flag) == 0) 2118c2ecf20Sopenharmony_ci return flags[i].value; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return 0; 2148c2ecf20Sopenharmony_ci} 215