18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * The parts for function graph printing was taken and modified from the 78c2ecf20Sopenharmony_ci * Linux Kernel that were written by 88c2ecf20Sopenharmony_ci * - Copyright (C) 2009 Frederic Weisbecker, 98c2ecf20Sopenharmony_ci * Frederic Weisbecker gave his permission to relicense the code to 108c2ecf20Sopenharmony_ci * the Lesser General Public License. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci#include <inttypes.h> 138c2ecf20Sopenharmony_ci#include <stdio.h> 148c2ecf20Sopenharmony_ci#include <stdlib.h> 158c2ecf20Sopenharmony_ci#include <string.h> 168c2ecf20Sopenharmony_ci#include <stdarg.h> 178c2ecf20Sopenharmony_ci#include <ctype.h> 188c2ecf20Sopenharmony_ci#include <errno.h> 198c2ecf20Sopenharmony_ci#include <stdint.h> 208c2ecf20Sopenharmony_ci#include <limits.h> 218c2ecf20Sopenharmony_ci#include <linux/time64.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <netinet/in.h> 248c2ecf20Sopenharmony_ci#include "event-parse.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "event-parse-local.h" 278c2ecf20Sopenharmony_ci#include "event-utils.h" 288c2ecf20Sopenharmony_ci#include "trace-seq.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic const char *input_buf; 318c2ecf20Sopenharmony_cistatic unsigned long long input_buf_ptr; 328c2ecf20Sopenharmony_cistatic unsigned long long input_buf_siz; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int is_flag_field; 358c2ecf20Sopenharmony_cistatic int is_symbolic_field; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int show_warning = 1; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define do_warning(fmt, ...) \ 408c2ecf20Sopenharmony_ci do { \ 418c2ecf20Sopenharmony_ci if (show_warning) \ 428c2ecf20Sopenharmony_ci warning(fmt, ##__VA_ARGS__); \ 438c2ecf20Sopenharmony_ci } while (0) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define do_warning_event(event, fmt, ...) \ 468c2ecf20Sopenharmony_ci do { \ 478c2ecf20Sopenharmony_ci if (!show_warning) \ 488c2ecf20Sopenharmony_ci continue; \ 498c2ecf20Sopenharmony_ci \ 508c2ecf20Sopenharmony_ci if (event) \ 518c2ecf20Sopenharmony_ci warning("[%s:%s] " fmt, event->system, \ 528c2ecf20Sopenharmony_ci event->name, ##__VA_ARGS__); \ 538c2ecf20Sopenharmony_ci else \ 548c2ecf20Sopenharmony_ci warning(fmt, ##__VA_ARGS__); \ 558c2ecf20Sopenharmony_ci } while (0) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/** 588c2ecf20Sopenharmony_ci * init_input_buf - init buffer for parsing 598c2ecf20Sopenharmony_ci * @buf: buffer to parse 608c2ecf20Sopenharmony_ci * @size: the size of the buffer 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * Initializes the internal buffer that tep_read_token() will parse. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci__hidden void init_input_buf(const char *buf, unsigned long long size) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci input_buf = buf; 678c2ecf20Sopenharmony_ci input_buf_siz = size; 688c2ecf20Sopenharmony_ci input_buf_ptr = 0; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci__hidden const char *get_input_buf(void) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci return input_buf; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci__hidden unsigned long long get_input_buf_ptr(void) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci return input_buf_ptr; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistruct event_handler { 828c2ecf20Sopenharmony_ci struct event_handler *next; 838c2ecf20Sopenharmony_ci int id; 848c2ecf20Sopenharmony_ci const char *sys_name; 858c2ecf20Sopenharmony_ci const char *event_name; 868c2ecf20Sopenharmony_ci tep_event_handler_func func; 878c2ecf20Sopenharmony_ci void *context; 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistruct func_params { 918c2ecf20Sopenharmony_ci struct func_params *next; 928c2ecf20Sopenharmony_ci enum tep_func_arg_type type; 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistruct tep_function_handler { 968c2ecf20Sopenharmony_ci struct tep_function_handler *next; 978c2ecf20Sopenharmony_ci enum tep_func_arg_type ret_type; 988c2ecf20Sopenharmony_ci char *name; 998c2ecf20Sopenharmony_ci tep_func_handler func; 1008c2ecf20Sopenharmony_ci struct func_params *params; 1018c2ecf20Sopenharmony_ci int nr_args; 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic unsigned long long 1058c2ecf20Sopenharmony_ciprocess_defined_func(struct trace_seq *s, void *data, int size, 1068c2ecf20Sopenharmony_ci struct tep_event *event, struct tep_print_arg *arg); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic void free_func_handle(struct tep_function_handler *func); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_civoid breakpoint(void) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci static int x; 1138c2ecf20Sopenharmony_ci x++; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic struct tep_print_arg *alloc_arg(void) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci return calloc(1, sizeof(struct tep_print_arg)); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistruct tep_cmdline { 1228c2ecf20Sopenharmony_ci char *comm; 1238c2ecf20Sopenharmony_ci int pid; 1248c2ecf20Sopenharmony_ci}; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int cmdline_cmp(const void *a, const void *b) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci const struct tep_cmdline *ca = a; 1298c2ecf20Sopenharmony_ci const struct tep_cmdline *cb = b; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (ca->pid < cb->pid) 1328c2ecf20Sopenharmony_ci return -1; 1338c2ecf20Sopenharmony_ci if (ca->pid > cb->pid) 1348c2ecf20Sopenharmony_ci return 1; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* Looking for where to place the key */ 1408c2ecf20Sopenharmony_cistatic int cmdline_slot_cmp(const void *a, const void *b) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci const struct tep_cmdline *ca = a; 1438c2ecf20Sopenharmony_ci const struct tep_cmdline *cb = b; 1448c2ecf20Sopenharmony_ci const struct tep_cmdline *cb1 = cb + 1; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (ca->pid < cb->pid) 1478c2ecf20Sopenharmony_ci return -1; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (ca->pid > cb->pid) { 1508c2ecf20Sopenharmony_ci if (ca->pid <= cb1->pid) 1518c2ecf20Sopenharmony_ci return 0; 1528c2ecf20Sopenharmony_ci return 1; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return 0; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistruct cmdline_list { 1598c2ecf20Sopenharmony_ci struct cmdline_list *next; 1608c2ecf20Sopenharmony_ci char *comm; 1618c2ecf20Sopenharmony_ci int pid; 1628c2ecf20Sopenharmony_ci}; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int cmdline_init(struct tep_handle *tep) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct cmdline_list *cmdlist = tep->cmdlist; 1678c2ecf20Sopenharmony_ci struct cmdline_list *item; 1688c2ecf20Sopenharmony_ci struct tep_cmdline *cmdlines; 1698c2ecf20Sopenharmony_ci int i; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci cmdlines = malloc(sizeof(*cmdlines) * tep->cmdline_count); 1728c2ecf20Sopenharmony_ci if (!cmdlines) 1738c2ecf20Sopenharmony_ci return -1; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci i = 0; 1768c2ecf20Sopenharmony_ci while (cmdlist) { 1778c2ecf20Sopenharmony_ci cmdlines[i].pid = cmdlist->pid; 1788c2ecf20Sopenharmony_ci cmdlines[i].comm = cmdlist->comm; 1798c2ecf20Sopenharmony_ci i++; 1808c2ecf20Sopenharmony_ci item = cmdlist; 1818c2ecf20Sopenharmony_ci cmdlist = cmdlist->next; 1828c2ecf20Sopenharmony_ci free(item); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci qsort(cmdlines, tep->cmdline_count, sizeof(*cmdlines), cmdline_cmp); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci tep->cmdlines = cmdlines; 1888c2ecf20Sopenharmony_ci tep->cmdlist = NULL; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return 0; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic const char *find_cmdline(struct tep_handle *tep, int pid) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci const struct tep_cmdline *comm; 1968c2ecf20Sopenharmony_ci struct tep_cmdline key; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (!pid) 1998c2ecf20Sopenharmony_ci return "<idle>"; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (!tep->cmdlines && cmdline_init(tep)) 2028c2ecf20Sopenharmony_ci return "<not enough memory for cmdlines!>"; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci key.pid = pid; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci comm = bsearch(&key, tep->cmdlines, tep->cmdline_count, 2078c2ecf20Sopenharmony_ci sizeof(*tep->cmdlines), cmdline_cmp); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (comm) 2108c2ecf20Sopenharmony_ci return comm->comm; 2118c2ecf20Sopenharmony_ci return "<...>"; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/** 2158c2ecf20Sopenharmony_ci * tep_is_pid_registered - return if a pid has a cmdline registered 2168c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 2178c2ecf20Sopenharmony_ci * @pid: The pid to check if it has a cmdline registered with. 2188c2ecf20Sopenharmony_ci * 2198c2ecf20Sopenharmony_ci * Returns true if the pid has a cmdline mapped to it 2208c2ecf20Sopenharmony_ci * false otherwise. 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_cibool tep_is_pid_registered(struct tep_handle *tep, int pid) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci const struct tep_cmdline *comm; 2258c2ecf20Sopenharmony_ci struct tep_cmdline key; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (!pid) 2288c2ecf20Sopenharmony_ci return true; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (!tep->cmdlines && cmdline_init(tep)) 2318c2ecf20Sopenharmony_ci return false; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci key.pid = pid; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci comm = bsearch(&key, tep->cmdlines, tep->cmdline_count, 2368c2ecf20Sopenharmony_ci sizeof(*tep->cmdlines), cmdline_cmp); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (comm) 2398c2ecf20Sopenharmony_ci return true; 2408c2ecf20Sopenharmony_ci return false; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci/* 2448c2ecf20Sopenharmony_ci * If the command lines have been converted to an array, then 2458c2ecf20Sopenharmony_ci * we must add this pid. This is much slower than when cmdlines 2468c2ecf20Sopenharmony_ci * are added before the array is initialized. 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_cistatic int add_new_comm(struct tep_handle *tep, 2498c2ecf20Sopenharmony_ci const char *comm, int pid, bool override) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct tep_cmdline *cmdlines = tep->cmdlines; 2528c2ecf20Sopenharmony_ci struct tep_cmdline *cmdline; 2538c2ecf20Sopenharmony_ci struct tep_cmdline key; 2548c2ecf20Sopenharmony_ci char *new_comm; 2558c2ecf20Sopenharmony_ci int cnt; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (!pid) 2588c2ecf20Sopenharmony_ci return 0; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* avoid duplicates */ 2618c2ecf20Sopenharmony_ci key.pid = pid; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci cmdline = bsearch(&key, tep->cmdlines, tep->cmdline_count, 2648c2ecf20Sopenharmony_ci sizeof(*tep->cmdlines), cmdline_cmp); 2658c2ecf20Sopenharmony_ci if (cmdline) { 2668c2ecf20Sopenharmony_ci if (!override) { 2678c2ecf20Sopenharmony_ci errno = EEXIST; 2688c2ecf20Sopenharmony_ci return -1; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci new_comm = strdup(comm); 2718c2ecf20Sopenharmony_ci if (!new_comm) { 2728c2ecf20Sopenharmony_ci errno = ENOMEM; 2738c2ecf20Sopenharmony_ci return -1; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci free(cmdline->comm); 2768c2ecf20Sopenharmony_ci cmdline->comm = new_comm; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return 0; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci cmdlines = realloc(cmdlines, sizeof(*cmdlines) * (tep->cmdline_count + 1)); 2828c2ecf20Sopenharmony_ci if (!cmdlines) { 2838c2ecf20Sopenharmony_ci errno = ENOMEM; 2848c2ecf20Sopenharmony_ci return -1; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci tep->cmdlines = cmdlines; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci key.comm = strdup(comm); 2898c2ecf20Sopenharmony_ci if (!key.comm) { 2908c2ecf20Sopenharmony_ci errno = ENOMEM; 2918c2ecf20Sopenharmony_ci return -1; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (!tep->cmdline_count) { 2958c2ecf20Sopenharmony_ci /* no entries yet */ 2968c2ecf20Sopenharmony_ci tep->cmdlines[0] = key; 2978c2ecf20Sopenharmony_ci tep->cmdline_count++; 2988c2ecf20Sopenharmony_ci return 0; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* Now find where we want to store the new cmdline */ 3028c2ecf20Sopenharmony_ci cmdline = bsearch(&key, tep->cmdlines, tep->cmdline_count - 1, 3038c2ecf20Sopenharmony_ci sizeof(*tep->cmdlines), cmdline_slot_cmp); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci cnt = tep->cmdline_count; 3068c2ecf20Sopenharmony_ci if (cmdline) { 3078c2ecf20Sopenharmony_ci /* cmdline points to the one before the spot we want */ 3088c2ecf20Sopenharmony_ci cmdline++; 3098c2ecf20Sopenharmony_ci cnt -= cmdline - tep->cmdlines; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci } else { 3128c2ecf20Sopenharmony_ci /* The new entry is either before or after the list */ 3138c2ecf20Sopenharmony_ci if (key.pid > tep->cmdlines[tep->cmdline_count - 1].pid) { 3148c2ecf20Sopenharmony_ci tep->cmdlines[tep->cmdline_count++] = key; 3158c2ecf20Sopenharmony_ci return 0; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci cmdline = &tep->cmdlines[0]; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci memmove(cmdline + 1, cmdline, (cnt * sizeof(*cmdline))); 3208c2ecf20Sopenharmony_ci *cmdline = key; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci tep->cmdline_count++; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic int _tep_register_comm(struct tep_handle *tep, 3288c2ecf20Sopenharmony_ci const char *comm, int pid, bool override) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci struct cmdline_list *item; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (tep->cmdlines) 3338c2ecf20Sopenharmony_ci return add_new_comm(tep, comm, pid, override); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci item = malloc(sizeof(*item)); 3368c2ecf20Sopenharmony_ci if (!item) 3378c2ecf20Sopenharmony_ci return -1; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (comm) 3408c2ecf20Sopenharmony_ci item->comm = strdup(comm); 3418c2ecf20Sopenharmony_ci else 3428c2ecf20Sopenharmony_ci item->comm = strdup("<...>"); 3438c2ecf20Sopenharmony_ci if (!item->comm) { 3448c2ecf20Sopenharmony_ci free(item); 3458c2ecf20Sopenharmony_ci return -1; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci item->pid = pid; 3488c2ecf20Sopenharmony_ci item->next = tep->cmdlist; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci tep->cmdlist = item; 3518c2ecf20Sopenharmony_ci tep->cmdline_count++; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return 0; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci/** 3578c2ecf20Sopenharmony_ci * tep_register_comm - register a pid / comm mapping 3588c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 3598c2ecf20Sopenharmony_ci * @comm: the command line to register 3608c2ecf20Sopenharmony_ci * @pid: the pid to map the command line to 3618c2ecf20Sopenharmony_ci * 3628c2ecf20Sopenharmony_ci * This adds a mapping to search for command line names with 3638c2ecf20Sopenharmony_ci * a given pid. The comm is duplicated. If a command with the same pid 3648c2ecf20Sopenharmony_ci * already exist, -1 is returned and errno is set to EEXIST 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_ciint tep_register_comm(struct tep_handle *tep, const char *comm, int pid) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci return _tep_register_comm(tep, comm, pid, false); 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci/** 3728c2ecf20Sopenharmony_ci * tep_override_comm - register a pid / comm mapping 3738c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 3748c2ecf20Sopenharmony_ci * @comm: the command line to register 3758c2ecf20Sopenharmony_ci * @pid: the pid to map the command line to 3768c2ecf20Sopenharmony_ci * 3778c2ecf20Sopenharmony_ci * This adds a mapping to search for command line names with 3788c2ecf20Sopenharmony_ci * a given pid. The comm is duplicated. If a command with the same pid 3798c2ecf20Sopenharmony_ci * already exist, the command string is udapted with the new one 3808c2ecf20Sopenharmony_ci */ 3818c2ecf20Sopenharmony_ciint tep_override_comm(struct tep_handle *tep, const char *comm, int pid) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci if (!tep->cmdlines && cmdline_init(tep)) { 3848c2ecf20Sopenharmony_ci errno = ENOMEM; 3858c2ecf20Sopenharmony_ci return -1; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci return _tep_register_comm(tep, comm, pid, true); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistruct func_map { 3918c2ecf20Sopenharmony_ci unsigned long long addr; 3928c2ecf20Sopenharmony_ci char *func; 3938c2ecf20Sopenharmony_ci char *mod; 3948c2ecf20Sopenharmony_ci}; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistruct func_list { 3978c2ecf20Sopenharmony_ci struct func_list *next; 3988c2ecf20Sopenharmony_ci unsigned long long addr; 3998c2ecf20Sopenharmony_ci char *func; 4008c2ecf20Sopenharmony_ci char *mod; 4018c2ecf20Sopenharmony_ci}; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic int func_cmp(const void *a, const void *b) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci const struct func_map *fa = a; 4068c2ecf20Sopenharmony_ci const struct func_map *fb = b; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (fa->addr < fb->addr) 4098c2ecf20Sopenharmony_ci return -1; 4108c2ecf20Sopenharmony_ci if (fa->addr > fb->addr) 4118c2ecf20Sopenharmony_ci return 1; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return 0; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci/* 4178c2ecf20Sopenharmony_ci * We are searching for a record in between, not an exact 4188c2ecf20Sopenharmony_ci * match. 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_cistatic int func_bcmp(const void *a, const void *b) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci const struct func_map *fa = a; 4238c2ecf20Sopenharmony_ci const struct func_map *fb = b; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if ((fa->addr == fb->addr) || 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci (fa->addr > fb->addr && 4288c2ecf20Sopenharmony_ci fa->addr < (fb+1)->addr)) 4298c2ecf20Sopenharmony_ci return 0; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (fa->addr < fb->addr) 4328c2ecf20Sopenharmony_ci return -1; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci return 1; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic int func_map_init(struct tep_handle *tep) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct func_list *funclist; 4408c2ecf20Sopenharmony_ci struct func_list *item; 4418c2ecf20Sopenharmony_ci struct func_map *func_map; 4428c2ecf20Sopenharmony_ci int i; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci func_map = malloc(sizeof(*func_map) * (tep->func_count + 1)); 4458c2ecf20Sopenharmony_ci if (!func_map) 4468c2ecf20Sopenharmony_ci return -1; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci funclist = tep->funclist; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci i = 0; 4518c2ecf20Sopenharmony_ci while (funclist) { 4528c2ecf20Sopenharmony_ci func_map[i].func = funclist->func; 4538c2ecf20Sopenharmony_ci func_map[i].addr = funclist->addr; 4548c2ecf20Sopenharmony_ci func_map[i].mod = funclist->mod; 4558c2ecf20Sopenharmony_ci i++; 4568c2ecf20Sopenharmony_ci item = funclist; 4578c2ecf20Sopenharmony_ci funclist = funclist->next; 4588c2ecf20Sopenharmony_ci free(item); 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci qsort(func_map, tep->func_count, sizeof(*func_map), func_cmp); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* 4648c2ecf20Sopenharmony_ci * Add a special record at the end. 4658c2ecf20Sopenharmony_ci */ 4668c2ecf20Sopenharmony_ci func_map[tep->func_count].func = NULL; 4678c2ecf20Sopenharmony_ci func_map[tep->func_count].addr = 0; 4688c2ecf20Sopenharmony_ci func_map[tep->func_count].mod = NULL; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci tep->func_map = func_map; 4718c2ecf20Sopenharmony_ci tep->funclist = NULL; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci return 0; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic struct func_map * 4778c2ecf20Sopenharmony_ci__find_func(struct tep_handle *tep, unsigned long long addr) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct func_map *func; 4808c2ecf20Sopenharmony_ci struct func_map key; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (!tep->func_map) 4838c2ecf20Sopenharmony_ci func_map_init(tep); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci key.addr = addr; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci func = bsearch(&key, tep->func_map, tep->func_count, 4888c2ecf20Sopenharmony_ci sizeof(*tep->func_map), func_bcmp); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci return func; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistruct func_resolver { 4948c2ecf20Sopenharmony_ci tep_func_resolver_t *func; 4958c2ecf20Sopenharmony_ci void *priv; 4968c2ecf20Sopenharmony_ci struct func_map map; 4978c2ecf20Sopenharmony_ci}; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci/** 5008c2ecf20Sopenharmony_ci * tep_set_function_resolver - set an alternative function resolver 5018c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 5028c2ecf20Sopenharmony_ci * @resolver: function to be used 5038c2ecf20Sopenharmony_ci * @priv: resolver function private state. 5048c2ecf20Sopenharmony_ci * 5058c2ecf20Sopenharmony_ci * Some tools may have already a way to resolve kernel functions, allow them to 5068c2ecf20Sopenharmony_ci * keep using it instead of duplicating all the entries inside tep->funclist. 5078c2ecf20Sopenharmony_ci */ 5088c2ecf20Sopenharmony_ciint tep_set_function_resolver(struct tep_handle *tep, 5098c2ecf20Sopenharmony_ci tep_func_resolver_t *func, void *priv) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci struct func_resolver *resolver = malloc(sizeof(*resolver)); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (resolver == NULL) 5148c2ecf20Sopenharmony_ci return -1; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci resolver->func = func; 5178c2ecf20Sopenharmony_ci resolver->priv = priv; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci free(tep->func_resolver); 5208c2ecf20Sopenharmony_ci tep->func_resolver = resolver; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci return 0; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci/** 5268c2ecf20Sopenharmony_ci * tep_reset_function_resolver - reset alternative function resolver 5278c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 5288c2ecf20Sopenharmony_ci * 5298c2ecf20Sopenharmony_ci * Stop using whatever alternative resolver was set, use the default 5308c2ecf20Sopenharmony_ci * one instead. 5318c2ecf20Sopenharmony_ci */ 5328c2ecf20Sopenharmony_civoid tep_reset_function_resolver(struct tep_handle *tep) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci free(tep->func_resolver); 5358c2ecf20Sopenharmony_ci tep->func_resolver = NULL; 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic struct func_map * 5398c2ecf20Sopenharmony_cifind_func(struct tep_handle *tep, unsigned long long addr) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci struct func_map *map; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (!tep->func_resolver) 5448c2ecf20Sopenharmony_ci return __find_func(tep, addr); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci map = &tep->func_resolver->map; 5478c2ecf20Sopenharmony_ci map->mod = NULL; 5488c2ecf20Sopenharmony_ci map->addr = addr; 5498c2ecf20Sopenharmony_ci map->func = tep->func_resolver->func(tep->func_resolver->priv, 5508c2ecf20Sopenharmony_ci &map->addr, &map->mod); 5518c2ecf20Sopenharmony_ci if (map->func == NULL) 5528c2ecf20Sopenharmony_ci return NULL; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci return map; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci/** 5588c2ecf20Sopenharmony_ci * tep_find_function - find a function by a given address 5598c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 5608c2ecf20Sopenharmony_ci * @addr: the address to find the function with 5618c2ecf20Sopenharmony_ci * 5628c2ecf20Sopenharmony_ci * Returns a pointer to the function stored that has the given 5638c2ecf20Sopenharmony_ci * address. Note, the address does not have to be exact, it 5648c2ecf20Sopenharmony_ci * will select the function that would contain the address. 5658c2ecf20Sopenharmony_ci */ 5668c2ecf20Sopenharmony_ciconst char *tep_find_function(struct tep_handle *tep, unsigned long long addr) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct func_map *map; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci map = find_func(tep, addr); 5718c2ecf20Sopenharmony_ci if (!map) 5728c2ecf20Sopenharmony_ci return NULL; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci return map->func; 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci/** 5788c2ecf20Sopenharmony_ci * tep_find_function_address - find a function address by a given address 5798c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 5808c2ecf20Sopenharmony_ci * @addr: the address to find the function with 5818c2ecf20Sopenharmony_ci * 5828c2ecf20Sopenharmony_ci * Returns the address the function starts at. This can be used in 5838c2ecf20Sopenharmony_ci * conjunction with tep_find_function to print both the function 5848c2ecf20Sopenharmony_ci * name and the function offset. 5858c2ecf20Sopenharmony_ci */ 5868c2ecf20Sopenharmony_ciunsigned long long 5878c2ecf20Sopenharmony_citep_find_function_address(struct tep_handle *tep, unsigned long long addr) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci struct func_map *map; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci map = find_func(tep, addr); 5928c2ecf20Sopenharmony_ci if (!map) 5938c2ecf20Sopenharmony_ci return 0; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci return map->addr; 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci/** 5998c2ecf20Sopenharmony_ci * tep_register_function - register a function with a given address 6008c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 6018c2ecf20Sopenharmony_ci * @function: the function name to register 6028c2ecf20Sopenharmony_ci * @addr: the address the function starts at 6038c2ecf20Sopenharmony_ci * @mod: the kernel module the function may be in (NULL for none) 6048c2ecf20Sopenharmony_ci * 6058c2ecf20Sopenharmony_ci * This registers a function name with an address and module. 6068c2ecf20Sopenharmony_ci * The @func passed in is duplicated. 6078c2ecf20Sopenharmony_ci */ 6088c2ecf20Sopenharmony_ciint tep_register_function(struct tep_handle *tep, char *func, 6098c2ecf20Sopenharmony_ci unsigned long long addr, char *mod) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci struct func_list *item = malloc(sizeof(*item)); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci if (!item) 6148c2ecf20Sopenharmony_ci return -1; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci item->next = tep->funclist; 6178c2ecf20Sopenharmony_ci item->func = strdup(func); 6188c2ecf20Sopenharmony_ci if (!item->func) 6198c2ecf20Sopenharmony_ci goto out_free; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (mod) { 6228c2ecf20Sopenharmony_ci item->mod = strdup(mod); 6238c2ecf20Sopenharmony_ci if (!item->mod) 6248c2ecf20Sopenharmony_ci goto out_free_func; 6258c2ecf20Sopenharmony_ci } else 6268c2ecf20Sopenharmony_ci item->mod = NULL; 6278c2ecf20Sopenharmony_ci item->addr = addr; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci tep->funclist = item; 6308c2ecf20Sopenharmony_ci tep->func_count++; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci return 0; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ciout_free_func: 6358c2ecf20Sopenharmony_ci free(item->func); 6368c2ecf20Sopenharmony_ci item->func = NULL; 6378c2ecf20Sopenharmony_ciout_free: 6388c2ecf20Sopenharmony_ci free(item); 6398c2ecf20Sopenharmony_ci errno = ENOMEM; 6408c2ecf20Sopenharmony_ci return -1; 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci/** 6448c2ecf20Sopenharmony_ci * tep_print_funcs - print out the stored functions 6458c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 6468c2ecf20Sopenharmony_ci * 6478c2ecf20Sopenharmony_ci * This prints out the stored functions. 6488c2ecf20Sopenharmony_ci */ 6498c2ecf20Sopenharmony_civoid tep_print_funcs(struct tep_handle *tep) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci int i; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (!tep->func_map) 6548c2ecf20Sopenharmony_ci func_map_init(tep); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci for (i = 0; i < (int)tep->func_count; i++) { 6578c2ecf20Sopenharmony_ci printf("%016llx %s", 6588c2ecf20Sopenharmony_ci tep->func_map[i].addr, 6598c2ecf20Sopenharmony_ci tep->func_map[i].func); 6608c2ecf20Sopenharmony_ci if (tep->func_map[i].mod) 6618c2ecf20Sopenharmony_ci printf(" [%s]\n", tep->func_map[i].mod); 6628c2ecf20Sopenharmony_ci else 6638c2ecf20Sopenharmony_ci printf("\n"); 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistruct printk_map { 6688c2ecf20Sopenharmony_ci unsigned long long addr; 6698c2ecf20Sopenharmony_ci char *printk; 6708c2ecf20Sopenharmony_ci}; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistruct printk_list { 6738c2ecf20Sopenharmony_ci struct printk_list *next; 6748c2ecf20Sopenharmony_ci unsigned long long addr; 6758c2ecf20Sopenharmony_ci char *printk; 6768c2ecf20Sopenharmony_ci}; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic int printk_cmp(const void *a, const void *b) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci const struct printk_map *pa = a; 6818c2ecf20Sopenharmony_ci const struct printk_map *pb = b; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (pa->addr < pb->addr) 6848c2ecf20Sopenharmony_ci return -1; 6858c2ecf20Sopenharmony_ci if (pa->addr > pb->addr) 6868c2ecf20Sopenharmony_ci return 1; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci return 0; 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic int printk_map_init(struct tep_handle *tep) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct printk_list *printklist; 6948c2ecf20Sopenharmony_ci struct printk_list *item; 6958c2ecf20Sopenharmony_ci struct printk_map *printk_map; 6968c2ecf20Sopenharmony_ci int i; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci printk_map = malloc(sizeof(*printk_map) * (tep->printk_count + 1)); 6998c2ecf20Sopenharmony_ci if (!printk_map) 7008c2ecf20Sopenharmony_ci return -1; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci printklist = tep->printklist; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci i = 0; 7058c2ecf20Sopenharmony_ci while (printklist) { 7068c2ecf20Sopenharmony_ci printk_map[i].printk = printklist->printk; 7078c2ecf20Sopenharmony_ci printk_map[i].addr = printklist->addr; 7088c2ecf20Sopenharmony_ci i++; 7098c2ecf20Sopenharmony_ci item = printklist; 7108c2ecf20Sopenharmony_ci printklist = printklist->next; 7118c2ecf20Sopenharmony_ci free(item); 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci qsort(printk_map, tep->printk_count, sizeof(*printk_map), printk_cmp); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci tep->printk_map = printk_map; 7178c2ecf20Sopenharmony_ci tep->printklist = NULL; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci return 0; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic struct printk_map * 7238c2ecf20Sopenharmony_cifind_printk(struct tep_handle *tep, unsigned long long addr) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct printk_map *printk; 7268c2ecf20Sopenharmony_ci struct printk_map key; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if (!tep->printk_map && printk_map_init(tep)) 7298c2ecf20Sopenharmony_ci return NULL; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci key.addr = addr; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci printk = bsearch(&key, tep->printk_map, tep->printk_count, 7348c2ecf20Sopenharmony_ci sizeof(*tep->printk_map), printk_cmp); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci return printk; 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci/** 7408c2ecf20Sopenharmony_ci * tep_register_print_string - register a string by its address 7418c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 7428c2ecf20Sopenharmony_ci * @fmt: the string format to register 7438c2ecf20Sopenharmony_ci * @addr: the address the string was located at 7448c2ecf20Sopenharmony_ci * 7458c2ecf20Sopenharmony_ci * This registers a string by the address it was stored in the kernel. 7468c2ecf20Sopenharmony_ci * The @fmt passed in is duplicated. 7478c2ecf20Sopenharmony_ci */ 7488c2ecf20Sopenharmony_ciint tep_register_print_string(struct tep_handle *tep, const char *fmt, 7498c2ecf20Sopenharmony_ci unsigned long long addr) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci struct printk_list *item = malloc(sizeof(*item)); 7528c2ecf20Sopenharmony_ci char *p; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (!item) 7558c2ecf20Sopenharmony_ci return -1; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci item->next = tep->printklist; 7588c2ecf20Sopenharmony_ci item->addr = addr; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci /* Strip off quotes and '\n' from the end */ 7618c2ecf20Sopenharmony_ci if (fmt[0] == '"') 7628c2ecf20Sopenharmony_ci fmt++; 7638c2ecf20Sopenharmony_ci item->printk = strdup(fmt); 7648c2ecf20Sopenharmony_ci if (!item->printk) 7658c2ecf20Sopenharmony_ci goto out_free; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci p = item->printk + strlen(item->printk) - 1; 7688c2ecf20Sopenharmony_ci if (*p == '"') 7698c2ecf20Sopenharmony_ci *p = 0; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci p -= 2; 7728c2ecf20Sopenharmony_ci if (strcmp(p, "\\n") == 0) 7738c2ecf20Sopenharmony_ci *p = 0; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci tep->printklist = item; 7768c2ecf20Sopenharmony_ci tep->printk_count++; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci return 0; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ciout_free: 7818c2ecf20Sopenharmony_ci free(item); 7828c2ecf20Sopenharmony_ci errno = ENOMEM; 7838c2ecf20Sopenharmony_ci return -1; 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci/** 7878c2ecf20Sopenharmony_ci * tep_print_printk - print out the stored strings 7888c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 7898c2ecf20Sopenharmony_ci * 7908c2ecf20Sopenharmony_ci * This prints the string formats that were stored. 7918c2ecf20Sopenharmony_ci */ 7928c2ecf20Sopenharmony_civoid tep_print_printk(struct tep_handle *tep) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci int i; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci if (!tep->printk_map) 7978c2ecf20Sopenharmony_ci printk_map_init(tep); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci for (i = 0; i < (int)tep->printk_count; i++) { 8008c2ecf20Sopenharmony_ci printf("%016llx %s\n", 8018c2ecf20Sopenharmony_ci tep->printk_map[i].addr, 8028c2ecf20Sopenharmony_ci tep->printk_map[i].printk); 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_cistatic struct tep_event *alloc_event(void) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci return calloc(1, sizeof(struct tep_event)); 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cistatic int add_event(struct tep_handle *tep, struct tep_event *event) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci int i; 8148c2ecf20Sopenharmony_ci struct tep_event **events = realloc(tep->events, sizeof(event) * 8158c2ecf20Sopenharmony_ci (tep->nr_events + 1)); 8168c2ecf20Sopenharmony_ci if (!events) 8178c2ecf20Sopenharmony_ci return -1; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci tep->events = events; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci for (i = 0; i < tep->nr_events; i++) { 8228c2ecf20Sopenharmony_ci if (tep->events[i]->id > event->id) 8238c2ecf20Sopenharmony_ci break; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci if (i < tep->nr_events) 8268c2ecf20Sopenharmony_ci memmove(&tep->events[i + 1], 8278c2ecf20Sopenharmony_ci &tep->events[i], 8288c2ecf20Sopenharmony_ci sizeof(event) * (tep->nr_events - i)); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci tep->events[i] = event; 8318c2ecf20Sopenharmony_ci tep->nr_events++; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci event->tep = tep; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci return 0; 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cistatic int event_item_type(enum tep_event_type type) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci switch (type) { 8418c2ecf20Sopenharmony_ci case TEP_EVENT_ITEM ... TEP_EVENT_SQUOTE: 8428c2ecf20Sopenharmony_ci return 1; 8438c2ecf20Sopenharmony_ci case TEP_EVENT_ERROR ... TEP_EVENT_DELIM: 8448c2ecf20Sopenharmony_ci default: 8458c2ecf20Sopenharmony_ci return 0; 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic void free_flag_sym(struct tep_print_flag_sym *fsym) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci struct tep_print_flag_sym *next; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci while (fsym) { 8548c2ecf20Sopenharmony_ci next = fsym->next; 8558c2ecf20Sopenharmony_ci free(fsym->value); 8568c2ecf20Sopenharmony_ci free(fsym->str); 8578c2ecf20Sopenharmony_ci free(fsym); 8588c2ecf20Sopenharmony_ci fsym = next; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_cistatic void free_arg(struct tep_print_arg *arg) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci struct tep_print_arg *farg; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (!arg) 8678c2ecf20Sopenharmony_ci return; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci switch (arg->type) { 8708c2ecf20Sopenharmony_ci case TEP_PRINT_ATOM: 8718c2ecf20Sopenharmony_ci free(arg->atom.atom); 8728c2ecf20Sopenharmony_ci break; 8738c2ecf20Sopenharmony_ci case TEP_PRINT_FIELD: 8748c2ecf20Sopenharmony_ci free(arg->field.name); 8758c2ecf20Sopenharmony_ci break; 8768c2ecf20Sopenharmony_ci case TEP_PRINT_FLAGS: 8778c2ecf20Sopenharmony_ci free_arg(arg->flags.field); 8788c2ecf20Sopenharmony_ci free(arg->flags.delim); 8798c2ecf20Sopenharmony_ci free_flag_sym(arg->flags.flags); 8808c2ecf20Sopenharmony_ci break; 8818c2ecf20Sopenharmony_ci case TEP_PRINT_SYMBOL: 8828c2ecf20Sopenharmony_ci free_arg(arg->symbol.field); 8838c2ecf20Sopenharmony_ci free_flag_sym(arg->symbol.symbols); 8848c2ecf20Sopenharmony_ci break; 8858c2ecf20Sopenharmony_ci case TEP_PRINT_HEX: 8868c2ecf20Sopenharmony_ci case TEP_PRINT_HEX_STR: 8878c2ecf20Sopenharmony_ci free_arg(arg->hex.field); 8888c2ecf20Sopenharmony_ci free_arg(arg->hex.size); 8898c2ecf20Sopenharmony_ci break; 8908c2ecf20Sopenharmony_ci case TEP_PRINT_INT_ARRAY: 8918c2ecf20Sopenharmony_ci free_arg(arg->int_array.field); 8928c2ecf20Sopenharmony_ci free_arg(arg->int_array.count); 8938c2ecf20Sopenharmony_ci free_arg(arg->int_array.el_size); 8948c2ecf20Sopenharmony_ci break; 8958c2ecf20Sopenharmony_ci case TEP_PRINT_TYPE: 8968c2ecf20Sopenharmony_ci free(arg->typecast.type); 8978c2ecf20Sopenharmony_ci free_arg(arg->typecast.item); 8988c2ecf20Sopenharmony_ci break; 8998c2ecf20Sopenharmony_ci case TEP_PRINT_STRING: 9008c2ecf20Sopenharmony_ci case TEP_PRINT_BSTRING: 9018c2ecf20Sopenharmony_ci free(arg->string.string); 9028c2ecf20Sopenharmony_ci break; 9038c2ecf20Sopenharmony_ci case TEP_PRINT_BITMASK: 9048c2ecf20Sopenharmony_ci free(arg->bitmask.bitmask); 9058c2ecf20Sopenharmony_ci break; 9068c2ecf20Sopenharmony_ci case TEP_PRINT_DYNAMIC_ARRAY: 9078c2ecf20Sopenharmony_ci case TEP_PRINT_DYNAMIC_ARRAY_LEN: 9088c2ecf20Sopenharmony_ci free(arg->dynarray.index); 9098c2ecf20Sopenharmony_ci break; 9108c2ecf20Sopenharmony_ci case TEP_PRINT_OP: 9118c2ecf20Sopenharmony_ci free(arg->op.op); 9128c2ecf20Sopenharmony_ci free_arg(arg->op.left); 9138c2ecf20Sopenharmony_ci free_arg(arg->op.right); 9148c2ecf20Sopenharmony_ci break; 9158c2ecf20Sopenharmony_ci case TEP_PRINT_FUNC: 9168c2ecf20Sopenharmony_ci while (arg->func.args) { 9178c2ecf20Sopenharmony_ci farg = arg->func.args; 9188c2ecf20Sopenharmony_ci arg->func.args = farg->next; 9198c2ecf20Sopenharmony_ci free_arg(farg); 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci break; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci case TEP_PRINT_NULL: 9248c2ecf20Sopenharmony_ci default: 9258c2ecf20Sopenharmony_ci break; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci free(arg); 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_cistatic enum tep_event_type get_type(int ch) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci if (ch == '\n') 9348c2ecf20Sopenharmony_ci return TEP_EVENT_NEWLINE; 9358c2ecf20Sopenharmony_ci if (isspace(ch)) 9368c2ecf20Sopenharmony_ci return TEP_EVENT_SPACE; 9378c2ecf20Sopenharmony_ci if (isalnum(ch) || ch == '_') 9388c2ecf20Sopenharmony_ci return TEP_EVENT_ITEM; 9398c2ecf20Sopenharmony_ci if (ch == '\'') 9408c2ecf20Sopenharmony_ci return TEP_EVENT_SQUOTE; 9418c2ecf20Sopenharmony_ci if (ch == '"') 9428c2ecf20Sopenharmony_ci return TEP_EVENT_DQUOTE; 9438c2ecf20Sopenharmony_ci if (!isprint(ch)) 9448c2ecf20Sopenharmony_ci return TEP_EVENT_NONE; 9458c2ecf20Sopenharmony_ci if (ch == '(' || ch == ')' || ch == ',') 9468c2ecf20Sopenharmony_ci return TEP_EVENT_DELIM; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci return TEP_EVENT_OP; 9498c2ecf20Sopenharmony_ci} 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_cistatic int __read_char(void) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci if (input_buf_ptr >= input_buf_siz) 9548c2ecf20Sopenharmony_ci return -1; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci return input_buf[input_buf_ptr++]; 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci/** 9608c2ecf20Sopenharmony_ci * peek_char - peek at the next character that will be read 9618c2ecf20Sopenharmony_ci * 9628c2ecf20Sopenharmony_ci * Returns the next character read, or -1 if end of buffer. 9638c2ecf20Sopenharmony_ci */ 9648c2ecf20Sopenharmony_ci__hidden int peek_char(void) 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci if (input_buf_ptr >= input_buf_siz) 9678c2ecf20Sopenharmony_ci return -1; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci return input_buf[input_buf_ptr]; 9708c2ecf20Sopenharmony_ci} 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_cistatic int extend_token(char **tok, char *buf, int size) 9738c2ecf20Sopenharmony_ci{ 9748c2ecf20Sopenharmony_ci char *newtok = realloc(*tok, size); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (!newtok) { 9778c2ecf20Sopenharmony_ci free(*tok); 9788c2ecf20Sopenharmony_ci *tok = NULL; 9798c2ecf20Sopenharmony_ci return -1; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci if (!*tok) 9838c2ecf20Sopenharmony_ci strcpy(newtok, buf); 9848c2ecf20Sopenharmony_ci else 9858c2ecf20Sopenharmony_ci strcat(newtok, buf); 9868c2ecf20Sopenharmony_ci *tok = newtok; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci return 0; 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic enum tep_event_type force_token(const char *str, char **tok); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_cistatic enum tep_event_type __read_token(char **tok) 9948c2ecf20Sopenharmony_ci{ 9958c2ecf20Sopenharmony_ci char buf[BUFSIZ]; 9968c2ecf20Sopenharmony_ci int ch, last_ch, quote_ch, next_ch; 9978c2ecf20Sopenharmony_ci int i = 0; 9988c2ecf20Sopenharmony_ci int tok_size = 0; 9998c2ecf20Sopenharmony_ci enum tep_event_type type; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci *tok = NULL; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci ch = __read_char(); 10058c2ecf20Sopenharmony_ci if (ch < 0) 10068c2ecf20Sopenharmony_ci return TEP_EVENT_NONE; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci type = get_type(ch); 10098c2ecf20Sopenharmony_ci if (type == TEP_EVENT_NONE) 10108c2ecf20Sopenharmony_ci return type; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci buf[i++] = ch; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci switch (type) { 10158c2ecf20Sopenharmony_ci case TEP_EVENT_NEWLINE: 10168c2ecf20Sopenharmony_ci case TEP_EVENT_DELIM: 10178c2ecf20Sopenharmony_ci if (asprintf(tok, "%c", ch) < 0) 10188c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci return type; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci case TEP_EVENT_OP: 10238c2ecf20Sopenharmony_ci switch (ch) { 10248c2ecf20Sopenharmony_ci case '-': 10258c2ecf20Sopenharmony_ci next_ch = peek_char(); 10268c2ecf20Sopenharmony_ci if (next_ch == '>') { 10278c2ecf20Sopenharmony_ci buf[i++] = __read_char(); 10288c2ecf20Sopenharmony_ci break; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci /* fall through */ 10318c2ecf20Sopenharmony_ci case '+': 10328c2ecf20Sopenharmony_ci case '|': 10338c2ecf20Sopenharmony_ci case '&': 10348c2ecf20Sopenharmony_ci case '>': 10358c2ecf20Sopenharmony_ci case '<': 10368c2ecf20Sopenharmony_ci last_ch = ch; 10378c2ecf20Sopenharmony_ci ch = peek_char(); 10388c2ecf20Sopenharmony_ci if (ch != last_ch) 10398c2ecf20Sopenharmony_ci goto test_equal; 10408c2ecf20Sopenharmony_ci buf[i++] = __read_char(); 10418c2ecf20Sopenharmony_ci switch (last_ch) { 10428c2ecf20Sopenharmony_ci case '>': 10438c2ecf20Sopenharmony_ci case '<': 10448c2ecf20Sopenharmony_ci goto test_equal; 10458c2ecf20Sopenharmony_ci default: 10468c2ecf20Sopenharmony_ci break; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci break; 10498c2ecf20Sopenharmony_ci case '!': 10508c2ecf20Sopenharmony_ci case '=': 10518c2ecf20Sopenharmony_ci goto test_equal; 10528c2ecf20Sopenharmony_ci default: /* what should we do instead? */ 10538c2ecf20Sopenharmony_ci break; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci buf[i] = 0; 10568c2ecf20Sopenharmony_ci *tok = strdup(buf); 10578c2ecf20Sopenharmony_ci return type; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci test_equal: 10608c2ecf20Sopenharmony_ci ch = peek_char(); 10618c2ecf20Sopenharmony_ci if (ch == '=') 10628c2ecf20Sopenharmony_ci buf[i++] = __read_char(); 10638c2ecf20Sopenharmony_ci goto out; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci case TEP_EVENT_DQUOTE: 10668c2ecf20Sopenharmony_ci case TEP_EVENT_SQUOTE: 10678c2ecf20Sopenharmony_ci /* don't keep quotes */ 10688c2ecf20Sopenharmony_ci i--; 10698c2ecf20Sopenharmony_ci quote_ch = ch; 10708c2ecf20Sopenharmony_ci last_ch = 0; 10718c2ecf20Sopenharmony_ci concat: 10728c2ecf20Sopenharmony_ci do { 10738c2ecf20Sopenharmony_ci if (i == (BUFSIZ - 1)) { 10748c2ecf20Sopenharmony_ci buf[i] = 0; 10758c2ecf20Sopenharmony_ci tok_size += BUFSIZ; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci if (extend_token(tok, buf, tok_size) < 0) 10788c2ecf20Sopenharmony_ci return TEP_EVENT_NONE; 10798c2ecf20Sopenharmony_ci i = 0; 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci last_ch = ch; 10828c2ecf20Sopenharmony_ci ch = __read_char(); 10838c2ecf20Sopenharmony_ci buf[i++] = ch; 10848c2ecf20Sopenharmony_ci /* the '\' '\' will cancel itself */ 10858c2ecf20Sopenharmony_ci if (ch == '\\' && last_ch == '\\') 10868c2ecf20Sopenharmony_ci last_ch = 0; 10878c2ecf20Sopenharmony_ci } while (ch != quote_ch || last_ch == '\\'); 10888c2ecf20Sopenharmony_ci /* remove the last quote */ 10898c2ecf20Sopenharmony_ci i--; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci /* 10928c2ecf20Sopenharmony_ci * For strings (double quotes) check the next token. 10938c2ecf20Sopenharmony_ci * If it is another string, concatinate the two. 10948c2ecf20Sopenharmony_ci */ 10958c2ecf20Sopenharmony_ci if (type == TEP_EVENT_DQUOTE) { 10968c2ecf20Sopenharmony_ci unsigned long long save_input_buf_ptr = input_buf_ptr; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci do { 10998c2ecf20Sopenharmony_ci ch = __read_char(); 11008c2ecf20Sopenharmony_ci } while (isspace(ch)); 11018c2ecf20Sopenharmony_ci if (ch == '"') 11028c2ecf20Sopenharmony_ci goto concat; 11038c2ecf20Sopenharmony_ci input_buf_ptr = save_input_buf_ptr; 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci goto out; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci case TEP_EVENT_ERROR ... TEP_EVENT_SPACE: 11098c2ecf20Sopenharmony_ci case TEP_EVENT_ITEM: 11108c2ecf20Sopenharmony_ci default: 11118c2ecf20Sopenharmony_ci break; 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci while (get_type(peek_char()) == type) { 11158c2ecf20Sopenharmony_ci if (i == (BUFSIZ - 1)) { 11168c2ecf20Sopenharmony_ci buf[i] = 0; 11178c2ecf20Sopenharmony_ci tok_size += BUFSIZ; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (extend_token(tok, buf, tok_size) < 0) 11208c2ecf20Sopenharmony_ci return TEP_EVENT_NONE; 11218c2ecf20Sopenharmony_ci i = 0; 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci ch = __read_char(); 11248c2ecf20Sopenharmony_ci buf[i++] = ch; 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci out: 11288c2ecf20Sopenharmony_ci buf[i] = 0; 11298c2ecf20Sopenharmony_ci if (extend_token(tok, buf, tok_size + i + 1) < 0) 11308c2ecf20Sopenharmony_ci return TEP_EVENT_NONE; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci if (type == TEP_EVENT_ITEM) { 11338c2ecf20Sopenharmony_ci /* 11348c2ecf20Sopenharmony_ci * Older versions of the kernel has a bug that 11358c2ecf20Sopenharmony_ci * creates invalid symbols and will break the mac80211 11368c2ecf20Sopenharmony_ci * parsing. This is a work around to that bug. 11378c2ecf20Sopenharmony_ci * 11388c2ecf20Sopenharmony_ci * See Linux kernel commit: 11398c2ecf20Sopenharmony_ci * 811cb50baf63461ce0bdb234927046131fc7fa8b 11408c2ecf20Sopenharmony_ci */ 11418c2ecf20Sopenharmony_ci if (strcmp(*tok, "LOCAL_PR_FMT") == 0) { 11428c2ecf20Sopenharmony_ci free(*tok); 11438c2ecf20Sopenharmony_ci *tok = NULL; 11448c2ecf20Sopenharmony_ci return force_token("\"%s\" ", tok); 11458c2ecf20Sopenharmony_ci } else if (strcmp(*tok, "STA_PR_FMT") == 0) { 11468c2ecf20Sopenharmony_ci free(*tok); 11478c2ecf20Sopenharmony_ci *tok = NULL; 11488c2ecf20Sopenharmony_ci return force_token("\" sta:%pM\" ", tok); 11498c2ecf20Sopenharmony_ci } else if (strcmp(*tok, "VIF_PR_FMT") == 0) { 11508c2ecf20Sopenharmony_ci free(*tok); 11518c2ecf20Sopenharmony_ci *tok = NULL; 11528c2ecf20Sopenharmony_ci return force_token("\" vif:%p(%d)\" ", tok); 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci return type; 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_cistatic enum tep_event_type force_token(const char *str, char **tok) 11608c2ecf20Sopenharmony_ci{ 11618c2ecf20Sopenharmony_ci const char *save_input_buf; 11628c2ecf20Sopenharmony_ci unsigned long long save_input_buf_ptr; 11638c2ecf20Sopenharmony_ci unsigned long long save_input_buf_siz; 11648c2ecf20Sopenharmony_ci enum tep_event_type type; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci /* save off the current input pointers */ 11678c2ecf20Sopenharmony_ci save_input_buf = input_buf; 11688c2ecf20Sopenharmony_ci save_input_buf_ptr = input_buf_ptr; 11698c2ecf20Sopenharmony_ci save_input_buf_siz = input_buf_siz; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci init_input_buf(str, strlen(str)); 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci type = __read_token(tok); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci /* reset back to original token */ 11768c2ecf20Sopenharmony_ci input_buf = save_input_buf; 11778c2ecf20Sopenharmony_ci input_buf_ptr = save_input_buf_ptr; 11788c2ecf20Sopenharmony_ci input_buf_siz = save_input_buf_siz; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci return type; 11818c2ecf20Sopenharmony_ci} 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci/** 11848c2ecf20Sopenharmony_ci * free_token - free a token returned by tep_read_token 11858c2ecf20Sopenharmony_ci * @token: the token to free 11868c2ecf20Sopenharmony_ci */ 11878c2ecf20Sopenharmony_ci__hidden void free_token(char *tok) 11888c2ecf20Sopenharmony_ci{ 11898c2ecf20Sopenharmony_ci if (tok) 11908c2ecf20Sopenharmony_ci free(tok); 11918c2ecf20Sopenharmony_ci} 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci/** 11948c2ecf20Sopenharmony_ci * read_token - access to utilities to use the tep parser 11958c2ecf20Sopenharmony_ci * @tok: The token to return 11968c2ecf20Sopenharmony_ci * 11978c2ecf20Sopenharmony_ci * This will parse tokens from the string given by 11988c2ecf20Sopenharmony_ci * tep_init_data(). 11998c2ecf20Sopenharmony_ci * 12008c2ecf20Sopenharmony_ci * Returns the token type. 12018c2ecf20Sopenharmony_ci */ 12028c2ecf20Sopenharmony_ci__hidden enum tep_event_type read_token(char **tok) 12038c2ecf20Sopenharmony_ci{ 12048c2ecf20Sopenharmony_ci enum tep_event_type type; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci for (;;) { 12078c2ecf20Sopenharmony_ci type = __read_token(tok); 12088c2ecf20Sopenharmony_ci if (type != TEP_EVENT_SPACE) 12098c2ecf20Sopenharmony_ci return type; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci free_token(*tok); 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci /* not reached */ 12158c2ecf20Sopenharmony_ci *tok = NULL; 12168c2ecf20Sopenharmony_ci return TEP_EVENT_NONE; 12178c2ecf20Sopenharmony_ci} 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci/* no newline */ 12208c2ecf20Sopenharmony_cistatic enum tep_event_type read_token_item(char **tok) 12218c2ecf20Sopenharmony_ci{ 12228c2ecf20Sopenharmony_ci enum tep_event_type type; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci for (;;) { 12258c2ecf20Sopenharmony_ci type = __read_token(tok); 12268c2ecf20Sopenharmony_ci if (type != TEP_EVENT_SPACE && type != TEP_EVENT_NEWLINE) 12278c2ecf20Sopenharmony_ci return type; 12288c2ecf20Sopenharmony_ci free_token(*tok); 12298c2ecf20Sopenharmony_ci *tok = NULL; 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci /* not reached */ 12338c2ecf20Sopenharmony_ci *tok = NULL; 12348c2ecf20Sopenharmony_ci return TEP_EVENT_NONE; 12358c2ecf20Sopenharmony_ci} 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_cistatic int test_type(enum tep_event_type type, enum tep_event_type expect) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci if (type != expect) { 12408c2ecf20Sopenharmony_ci do_warning("Error: expected type %d but read %d", 12418c2ecf20Sopenharmony_ci expect, type); 12428c2ecf20Sopenharmony_ci return -1; 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci return 0; 12458c2ecf20Sopenharmony_ci} 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_cistatic int test_type_token(enum tep_event_type type, const char *token, 12488c2ecf20Sopenharmony_ci enum tep_event_type expect, const char *expect_tok) 12498c2ecf20Sopenharmony_ci{ 12508c2ecf20Sopenharmony_ci if (type != expect) { 12518c2ecf20Sopenharmony_ci do_warning("Error: expected type %d but read %d", 12528c2ecf20Sopenharmony_ci expect, type); 12538c2ecf20Sopenharmony_ci return -1; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci if (strcmp(token, expect_tok) != 0) { 12578c2ecf20Sopenharmony_ci do_warning("Error: expected '%s' but read '%s'", 12588c2ecf20Sopenharmony_ci expect_tok, token); 12598c2ecf20Sopenharmony_ci return -1; 12608c2ecf20Sopenharmony_ci } 12618c2ecf20Sopenharmony_ci return 0; 12628c2ecf20Sopenharmony_ci} 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_cistatic int __read_expect_type(enum tep_event_type expect, char **tok, int newline_ok) 12658c2ecf20Sopenharmony_ci{ 12668c2ecf20Sopenharmony_ci enum tep_event_type type; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci if (newline_ok) 12698c2ecf20Sopenharmony_ci type = read_token(tok); 12708c2ecf20Sopenharmony_ci else 12718c2ecf20Sopenharmony_ci type = read_token_item(tok); 12728c2ecf20Sopenharmony_ci return test_type(type, expect); 12738c2ecf20Sopenharmony_ci} 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_cistatic int read_expect_type(enum tep_event_type expect, char **tok) 12768c2ecf20Sopenharmony_ci{ 12778c2ecf20Sopenharmony_ci return __read_expect_type(expect, tok, 1); 12788c2ecf20Sopenharmony_ci} 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cistatic int __read_expected(enum tep_event_type expect, const char *str, 12818c2ecf20Sopenharmony_ci int newline_ok) 12828c2ecf20Sopenharmony_ci{ 12838c2ecf20Sopenharmony_ci enum tep_event_type type; 12848c2ecf20Sopenharmony_ci char *token; 12858c2ecf20Sopenharmony_ci int ret; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci if (newline_ok) 12888c2ecf20Sopenharmony_ci type = read_token(&token); 12898c2ecf20Sopenharmony_ci else 12908c2ecf20Sopenharmony_ci type = read_token_item(&token); 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci ret = test_type_token(type, token, expect, str); 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci free_token(token); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci return ret; 12978c2ecf20Sopenharmony_ci} 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_cistatic int read_expected(enum tep_event_type expect, const char *str) 13008c2ecf20Sopenharmony_ci{ 13018c2ecf20Sopenharmony_ci return __read_expected(expect, str, 1); 13028c2ecf20Sopenharmony_ci} 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_cistatic int read_expected_item(enum tep_event_type expect, const char *str) 13058c2ecf20Sopenharmony_ci{ 13068c2ecf20Sopenharmony_ci return __read_expected(expect, str, 0); 13078c2ecf20Sopenharmony_ci} 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_cistatic char *event_read_name(void) 13108c2ecf20Sopenharmony_ci{ 13118c2ecf20Sopenharmony_ci char *token; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_ITEM, "name") < 0) 13148c2ecf20Sopenharmony_ci return NULL; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ":") < 0) 13178c2ecf20Sopenharmony_ci return NULL; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) 13208c2ecf20Sopenharmony_ci goto fail; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci return token; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci fail: 13258c2ecf20Sopenharmony_ci free_token(token); 13268c2ecf20Sopenharmony_ci return NULL; 13278c2ecf20Sopenharmony_ci} 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_cistatic int event_read_id(void) 13308c2ecf20Sopenharmony_ci{ 13318c2ecf20Sopenharmony_ci char *token; 13328c2ecf20Sopenharmony_ci int id; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci if (read_expected_item(TEP_EVENT_ITEM, "ID") < 0) 13358c2ecf20Sopenharmony_ci return -1; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ":") < 0) 13388c2ecf20Sopenharmony_ci return -1; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) 13418c2ecf20Sopenharmony_ci goto fail; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci id = strtoul(token, NULL, 0); 13448c2ecf20Sopenharmony_ci free_token(token); 13458c2ecf20Sopenharmony_ci return id; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci fail: 13488c2ecf20Sopenharmony_ci free_token(token); 13498c2ecf20Sopenharmony_ci return -1; 13508c2ecf20Sopenharmony_ci} 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_cistatic int field_is_string(struct tep_format_field *field) 13538c2ecf20Sopenharmony_ci{ 13548c2ecf20Sopenharmony_ci if ((field->flags & TEP_FIELD_IS_ARRAY) && 13558c2ecf20Sopenharmony_ci (strstr(field->type, "char") || strstr(field->type, "u8") || 13568c2ecf20Sopenharmony_ci strstr(field->type, "s8"))) 13578c2ecf20Sopenharmony_ci return 1; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci return 0; 13608c2ecf20Sopenharmony_ci} 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_cistatic int field_is_dynamic(struct tep_format_field *field) 13638c2ecf20Sopenharmony_ci{ 13648c2ecf20Sopenharmony_ci if (strncmp(field->type, "__data_loc", 10) == 0) 13658c2ecf20Sopenharmony_ci return 1; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci return 0; 13688c2ecf20Sopenharmony_ci} 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_cistatic int field_is_long(struct tep_format_field *field) 13718c2ecf20Sopenharmony_ci{ 13728c2ecf20Sopenharmony_ci /* includes long long */ 13738c2ecf20Sopenharmony_ci if (strstr(field->type, "long")) 13748c2ecf20Sopenharmony_ci return 1; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci return 0; 13778c2ecf20Sopenharmony_ci} 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_cistatic unsigned int type_size(const char *name) 13808c2ecf20Sopenharmony_ci{ 13818c2ecf20Sopenharmony_ci /* This covers all TEP_FIELD_IS_STRING types. */ 13828c2ecf20Sopenharmony_ci static struct { 13838c2ecf20Sopenharmony_ci const char *type; 13848c2ecf20Sopenharmony_ci unsigned int size; 13858c2ecf20Sopenharmony_ci } table[] = { 13868c2ecf20Sopenharmony_ci { "u8", 1 }, 13878c2ecf20Sopenharmony_ci { "u16", 2 }, 13888c2ecf20Sopenharmony_ci { "u32", 4 }, 13898c2ecf20Sopenharmony_ci { "u64", 8 }, 13908c2ecf20Sopenharmony_ci { "s8", 1 }, 13918c2ecf20Sopenharmony_ci { "s16", 2 }, 13928c2ecf20Sopenharmony_ci { "s32", 4 }, 13938c2ecf20Sopenharmony_ci { "s64", 8 }, 13948c2ecf20Sopenharmony_ci { "char", 1 }, 13958c2ecf20Sopenharmony_ci { }, 13968c2ecf20Sopenharmony_ci }; 13978c2ecf20Sopenharmony_ci int i; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci for (i = 0; table[i].type; i++) { 14008c2ecf20Sopenharmony_ci if (!strcmp(table[i].type, name)) 14018c2ecf20Sopenharmony_ci return table[i].size; 14028c2ecf20Sopenharmony_ci } 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci return 0; 14058c2ecf20Sopenharmony_ci} 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_cistatic int append(char **buf, const char *delim, const char *str) 14088c2ecf20Sopenharmony_ci{ 14098c2ecf20Sopenharmony_ci char *new_buf; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci new_buf = realloc(*buf, strlen(*buf) + strlen(delim) + strlen(str) + 1); 14128c2ecf20Sopenharmony_ci if (!new_buf) 14138c2ecf20Sopenharmony_ci return -1; 14148c2ecf20Sopenharmony_ci strcat(new_buf, delim); 14158c2ecf20Sopenharmony_ci strcat(new_buf, str); 14168c2ecf20Sopenharmony_ci *buf = new_buf; 14178c2ecf20Sopenharmony_ci return 0; 14188c2ecf20Sopenharmony_ci} 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_cistatic int event_read_fields(struct tep_event *event, struct tep_format_field **fields) 14218c2ecf20Sopenharmony_ci{ 14228c2ecf20Sopenharmony_ci struct tep_format_field *field = NULL; 14238c2ecf20Sopenharmony_ci enum tep_event_type type; 14248c2ecf20Sopenharmony_ci char *token; 14258c2ecf20Sopenharmony_ci char *last_token; 14268c2ecf20Sopenharmony_ci char *delim = " "; 14278c2ecf20Sopenharmony_ci int count = 0; 14288c2ecf20Sopenharmony_ci int ret; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci do { 14318c2ecf20Sopenharmony_ci unsigned int size_dynamic = 0; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci type = read_token(&token); 14348c2ecf20Sopenharmony_ci if (type == TEP_EVENT_NEWLINE) { 14358c2ecf20Sopenharmony_ci free_token(token); 14368c2ecf20Sopenharmony_ci return count; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci count++; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_ITEM, "field")) 14428c2ecf20Sopenharmony_ci goto fail; 14438c2ecf20Sopenharmony_ci free_token(token); 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci type = read_token(&token); 14468c2ecf20Sopenharmony_ci /* 14478c2ecf20Sopenharmony_ci * The ftrace fields may still use the "special" name. 14488c2ecf20Sopenharmony_ci * Just ignore it. 14498c2ecf20Sopenharmony_ci */ 14508c2ecf20Sopenharmony_ci if (event->flags & TEP_EVENT_FL_ISFTRACE && 14518c2ecf20Sopenharmony_ci type == TEP_EVENT_ITEM && strcmp(token, "special") == 0) { 14528c2ecf20Sopenharmony_ci free_token(token); 14538c2ecf20Sopenharmony_ci type = read_token(&token); 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_OP, ":") < 0) 14578c2ecf20Sopenharmony_ci goto fail; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci free_token(token); 14608c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) 14618c2ecf20Sopenharmony_ci goto fail; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci last_token = token; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci field = calloc(1, sizeof(*field)); 14668c2ecf20Sopenharmony_ci if (!field) 14678c2ecf20Sopenharmony_ci goto fail; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci field->event = event; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci /* read the rest of the type */ 14728c2ecf20Sopenharmony_ci for (;;) { 14738c2ecf20Sopenharmony_ci type = read_token(&token); 14748c2ecf20Sopenharmony_ci if (type == TEP_EVENT_ITEM || 14758c2ecf20Sopenharmony_ci (type == TEP_EVENT_OP && strcmp(token, "*") == 0) || 14768c2ecf20Sopenharmony_ci /* 14778c2ecf20Sopenharmony_ci * Some of the ftrace fields are broken and have 14788c2ecf20Sopenharmony_ci * an illegal "." in them. 14798c2ecf20Sopenharmony_ci */ 14808c2ecf20Sopenharmony_ci (event->flags & TEP_EVENT_FL_ISFTRACE && 14818c2ecf20Sopenharmony_ci type == TEP_EVENT_OP && strcmp(token, ".") == 0)) { 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci if (strcmp(token, "*") == 0) 14848c2ecf20Sopenharmony_ci field->flags |= TEP_FIELD_IS_POINTER; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci if (field->type) { 14878c2ecf20Sopenharmony_ci ret = append(&field->type, delim, last_token); 14888c2ecf20Sopenharmony_ci free(last_token); 14898c2ecf20Sopenharmony_ci if (ret < 0) 14908c2ecf20Sopenharmony_ci goto fail; 14918c2ecf20Sopenharmony_ci } else 14928c2ecf20Sopenharmony_ci field->type = last_token; 14938c2ecf20Sopenharmony_ci last_token = token; 14948c2ecf20Sopenharmony_ci delim = " "; 14958c2ecf20Sopenharmony_ci continue; 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci /* Handle __attribute__((user)) */ 14998c2ecf20Sopenharmony_ci if ((type == TEP_EVENT_DELIM) && 15008c2ecf20Sopenharmony_ci strcmp("__attribute__", last_token) == 0 && 15018c2ecf20Sopenharmony_ci token[0] == '(') { 15028c2ecf20Sopenharmony_ci int depth = 1; 15038c2ecf20Sopenharmony_ci int ret; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci ret = append(&field->type, " ", last_token); 15068c2ecf20Sopenharmony_ci ret |= append(&field->type, "", "("); 15078c2ecf20Sopenharmony_ci if (ret < 0) 15088c2ecf20Sopenharmony_ci goto fail; 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci delim = " "; 15118c2ecf20Sopenharmony_ci while ((type = read_token(&token)) != TEP_EVENT_NONE) { 15128c2ecf20Sopenharmony_ci if (type == TEP_EVENT_DELIM) { 15138c2ecf20Sopenharmony_ci if (token[0] == '(') 15148c2ecf20Sopenharmony_ci depth++; 15158c2ecf20Sopenharmony_ci else if (token[0] == ')') 15168c2ecf20Sopenharmony_ci depth--; 15178c2ecf20Sopenharmony_ci if (!depth) 15188c2ecf20Sopenharmony_ci break; 15198c2ecf20Sopenharmony_ci ret = append(&field->type, "", token); 15208c2ecf20Sopenharmony_ci delim = ""; 15218c2ecf20Sopenharmony_ci } else { 15228c2ecf20Sopenharmony_ci ret = append(&field->type, delim, token); 15238c2ecf20Sopenharmony_ci delim = " "; 15248c2ecf20Sopenharmony_ci } 15258c2ecf20Sopenharmony_ci if (ret < 0) 15268c2ecf20Sopenharmony_ci goto fail; 15278c2ecf20Sopenharmony_ci free(last_token); 15288c2ecf20Sopenharmony_ci last_token = token; 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci continue; 15318c2ecf20Sopenharmony_ci } 15328c2ecf20Sopenharmony_ci break; 15338c2ecf20Sopenharmony_ci } 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci if (!field->type) { 15368c2ecf20Sopenharmony_ci do_warning_event(event, "%s: no type found", __func__); 15378c2ecf20Sopenharmony_ci goto fail; 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci field->name = field->alias = last_token; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci if (test_type(type, TEP_EVENT_OP)) 15428c2ecf20Sopenharmony_ci goto fail; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci if (strcmp(token, "[") == 0) { 15458c2ecf20Sopenharmony_ci enum tep_event_type last_type = type; 15468c2ecf20Sopenharmony_ci char *brackets = token; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci field->flags |= TEP_FIELD_IS_ARRAY; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci type = read_token(&token); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci if (type == TEP_EVENT_ITEM) 15538c2ecf20Sopenharmony_ci field->arraylen = strtoul(token, NULL, 0); 15548c2ecf20Sopenharmony_ci else 15558c2ecf20Sopenharmony_ci field->arraylen = 0; 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci while (strcmp(token, "]") != 0) { 15588c2ecf20Sopenharmony_ci const char *delim; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci if (last_type == TEP_EVENT_ITEM && 15618c2ecf20Sopenharmony_ci type == TEP_EVENT_ITEM) 15628c2ecf20Sopenharmony_ci delim = " "; 15638c2ecf20Sopenharmony_ci else 15648c2ecf20Sopenharmony_ci delim = ""; 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci last_type = type; 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci ret = append(&brackets, delim, token); 15698c2ecf20Sopenharmony_ci if (ret < 0) { 15708c2ecf20Sopenharmony_ci free(brackets); 15718c2ecf20Sopenharmony_ci goto fail; 15728c2ecf20Sopenharmony_ci } 15738c2ecf20Sopenharmony_ci /* We only care about the last token */ 15748c2ecf20Sopenharmony_ci field->arraylen = strtoul(token, NULL, 0); 15758c2ecf20Sopenharmony_ci free_token(token); 15768c2ecf20Sopenharmony_ci type = read_token(&token); 15778c2ecf20Sopenharmony_ci if (type == TEP_EVENT_NONE) { 15788c2ecf20Sopenharmony_ci free(brackets); 15798c2ecf20Sopenharmony_ci do_warning_event(event, "failed to find token"); 15808c2ecf20Sopenharmony_ci goto fail; 15818c2ecf20Sopenharmony_ci } 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci free_token(token); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci ret = append(&brackets, "", "]"); 15878c2ecf20Sopenharmony_ci if (ret < 0) { 15888c2ecf20Sopenharmony_ci free(brackets); 15898c2ecf20Sopenharmony_ci goto fail; 15908c2ecf20Sopenharmony_ci } 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci /* add brackets to type */ 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci type = read_token(&token); 15958c2ecf20Sopenharmony_ci /* 15968c2ecf20Sopenharmony_ci * If the next token is not an OP, then it is of 15978c2ecf20Sopenharmony_ci * the format: type [] item; 15988c2ecf20Sopenharmony_ci */ 15998c2ecf20Sopenharmony_ci if (type == TEP_EVENT_ITEM) { 16008c2ecf20Sopenharmony_ci ret = append(&field->type, " ", field->name); 16018c2ecf20Sopenharmony_ci if (ret < 0) { 16028c2ecf20Sopenharmony_ci free(brackets); 16038c2ecf20Sopenharmony_ci goto fail; 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci ret = append(&field->type, "", brackets); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci size_dynamic = type_size(field->name); 16088c2ecf20Sopenharmony_ci free_token(field->name); 16098c2ecf20Sopenharmony_ci field->name = field->alias = token; 16108c2ecf20Sopenharmony_ci type = read_token(&token); 16118c2ecf20Sopenharmony_ci } else { 16128c2ecf20Sopenharmony_ci ret = append(&field->type, "", brackets); 16138c2ecf20Sopenharmony_ci if (ret < 0) { 16148c2ecf20Sopenharmony_ci free(brackets); 16158c2ecf20Sopenharmony_ci goto fail; 16168c2ecf20Sopenharmony_ci } 16178c2ecf20Sopenharmony_ci } 16188c2ecf20Sopenharmony_ci free(brackets); 16198c2ecf20Sopenharmony_ci } 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci if (field_is_string(field)) 16228c2ecf20Sopenharmony_ci field->flags |= TEP_FIELD_IS_STRING; 16238c2ecf20Sopenharmony_ci if (field_is_dynamic(field)) 16248c2ecf20Sopenharmony_ci field->flags |= TEP_FIELD_IS_DYNAMIC; 16258c2ecf20Sopenharmony_ci if (field_is_long(field)) 16268c2ecf20Sopenharmony_ci field->flags |= TEP_FIELD_IS_LONG; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_OP, ";")) 16298c2ecf20Sopenharmony_ci goto fail; 16308c2ecf20Sopenharmony_ci free_token(token); 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_ITEM, "offset") < 0) 16338c2ecf20Sopenharmony_ci goto fail_expect; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ":") < 0) 16368c2ecf20Sopenharmony_ci goto fail_expect; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_ITEM, &token)) 16398c2ecf20Sopenharmony_ci goto fail; 16408c2ecf20Sopenharmony_ci field->offset = strtoul(token, NULL, 0); 16418c2ecf20Sopenharmony_ci free_token(token); 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ";") < 0) 16448c2ecf20Sopenharmony_ci goto fail_expect; 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_ITEM, "size") < 0) 16478c2ecf20Sopenharmony_ci goto fail_expect; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ":") < 0) 16508c2ecf20Sopenharmony_ci goto fail_expect; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_ITEM, &token)) 16538c2ecf20Sopenharmony_ci goto fail; 16548c2ecf20Sopenharmony_ci field->size = strtoul(token, NULL, 0); 16558c2ecf20Sopenharmony_ci free_token(token); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ";") < 0) 16588c2ecf20Sopenharmony_ci goto fail_expect; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci type = read_token(&token); 16618c2ecf20Sopenharmony_ci if (type != TEP_EVENT_NEWLINE) { 16628c2ecf20Sopenharmony_ci /* newer versions of the kernel have a "signed" type */ 16638c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_ITEM, "signed")) 16648c2ecf20Sopenharmony_ci goto fail; 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci free_token(token); 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ":") < 0) 16698c2ecf20Sopenharmony_ci goto fail_expect; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_ITEM, &token)) 16728c2ecf20Sopenharmony_ci goto fail; 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci if (strtoul(token, NULL, 0)) 16758c2ecf20Sopenharmony_ci field->flags |= TEP_FIELD_IS_SIGNED; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci free_token(token); 16788c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ";") < 0) 16798c2ecf20Sopenharmony_ci goto fail_expect; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_NEWLINE, &token)) 16828c2ecf20Sopenharmony_ci goto fail; 16838c2ecf20Sopenharmony_ci } 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci free_token(token); 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci if (field->flags & TEP_FIELD_IS_ARRAY) { 16888c2ecf20Sopenharmony_ci if (field->arraylen) 16898c2ecf20Sopenharmony_ci field->elementsize = field->size / field->arraylen; 16908c2ecf20Sopenharmony_ci else if (field->flags & TEP_FIELD_IS_DYNAMIC) 16918c2ecf20Sopenharmony_ci field->elementsize = size_dynamic; 16928c2ecf20Sopenharmony_ci else if (field->flags & TEP_FIELD_IS_STRING) 16938c2ecf20Sopenharmony_ci field->elementsize = 1; 16948c2ecf20Sopenharmony_ci else if (field->flags & TEP_FIELD_IS_LONG) 16958c2ecf20Sopenharmony_ci field->elementsize = event->tep ? 16968c2ecf20Sopenharmony_ci event->tep->long_size : 16978c2ecf20Sopenharmony_ci sizeof(long); 16988c2ecf20Sopenharmony_ci } else 16998c2ecf20Sopenharmony_ci field->elementsize = field->size; 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci *fields = field; 17028c2ecf20Sopenharmony_ci fields = &field->next; 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci } while (1); 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci return 0; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_cifail: 17098c2ecf20Sopenharmony_ci free_token(token); 17108c2ecf20Sopenharmony_cifail_expect: 17118c2ecf20Sopenharmony_ci if (field) { 17128c2ecf20Sopenharmony_ci free(field->type); 17138c2ecf20Sopenharmony_ci free(field->name); 17148c2ecf20Sopenharmony_ci free(field); 17158c2ecf20Sopenharmony_ci } 17168c2ecf20Sopenharmony_ci return -1; 17178c2ecf20Sopenharmony_ci} 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_cistatic int event_read_format(struct tep_event *event) 17208c2ecf20Sopenharmony_ci{ 17218c2ecf20Sopenharmony_ci char *token; 17228c2ecf20Sopenharmony_ci int ret; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci if (read_expected_item(TEP_EVENT_ITEM, "format") < 0) 17258c2ecf20Sopenharmony_ci return -1; 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ":") < 0) 17288c2ecf20Sopenharmony_ci return -1; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_NEWLINE, &token)) 17318c2ecf20Sopenharmony_ci goto fail; 17328c2ecf20Sopenharmony_ci free_token(token); 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci ret = event_read_fields(event, &event->format.common_fields); 17358c2ecf20Sopenharmony_ci if (ret < 0) 17368c2ecf20Sopenharmony_ci return ret; 17378c2ecf20Sopenharmony_ci event->format.nr_common = ret; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci ret = event_read_fields(event, &event->format.fields); 17408c2ecf20Sopenharmony_ci if (ret < 0) 17418c2ecf20Sopenharmony_ci return ret; 17428c2ecf20Sopenharmony_ci event->format.nr_fields = ret; 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci return 0; 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci fail: 17478c2ecf20Sopenharmony_ci free_token(token); 17488c2ecf20Sopenharmony_ci return -1; 17498c2ecf20Sopenharmony_ci} 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_cistatic enum tep_event_type 17528c2ecf20Sopenharmony_ciprocess_arg_token(struct tep_event *event, struct tep_print_arg *arg, 17538c2ecf20Sopenharmony_ci char **tok, enum tep_event_type type); 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_cistatic enum tep_event_type 17568c2ecf20Sopenharmony_ciprocess_arg(struct tep_event *event, struct tep_print_arg *arg, char **tok) 17578c2ecf20Sopenharmony_ci{ 17588c2ecf20Sopenharmony_ci enum tep_event_type type; 17598c2ecf20Sopenharmony_ci char *token; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci type = read_token(&token); 17628c2ecf20Sopenharmony_ci *tok = token; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci return process_arg_token(event, arg, tok, type); 17658c2ecf20Sopenharmony_ci} 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_cistatic enum tep_event_type 17688c2ecf20Sopenharmony_ciprocess_op(struct tep_event *event, struct tep_print_arg *arg, char **tok); 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci/* 17718c2ecf20Sopenharmony_ci * For __print_symbolic() and __print_flags, we need to completely 17728c2ecf20Sopenharmony_ci * evaluate the first argument, which defines what to print next. 17738c2ecf20Sopenharmony_ci */ 17748c2ecf20Sopenharmony_cistatic enum tep_event_type 17758c2ecf20Sopenharmony_ciprocess_field_arg(struct tep_event *event, struct tep_print_arg *arg, char **tok) 17768c2ecf20Sopenharmony_ci{ 17778c2ecf20Sopenharmony_ci enum tep_event_type type; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci type = process_arg(event, arg, tok); 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci while (type == TEP_EVENT_OP) { 17828c2ecf20Sopenharmony_ci type = process_op(event, arg, tok); 17838c2ecf20Sopenharmony_ci } 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci return type; 17868c2ecf20Sopenharmony_ci} 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_cistatic enum tep_event_type 17898c2ecf20Sopenharmony_ciprocess_cond(struct tep_event *event, struct tep_print_arg *top, char **tok) 17908c2ecf20Sopenharmony_ci{ 17918c2ecf20Sopenharmony_ci struct tep_print_arg *arg, *left, *right; 17928c2ecf20Sopenharmony_ci enum tep_event_type type; 17938c2ecf20Sopenharmony_ci char *token = NULL; 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci arg = alloc_arg(); 17968c2ecf20Sopenharmony_ci left = alloc_arg(); 17978c2ecf20Sopenharmony_ci right = alloc_arg(); 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci if (!arg || !left || !right) { 18008c2ecf20Sopenharmony_ci do_warning_event(event, "%s: not enough memory!", __func__); 18018c2ecf20Sopenharmony_ci /* arg will be freed at out_free */ 18028c2ecf20Sopenharmony_ci free_arg(left); 18038c2ecf20Sopenharmony_ci free_arg(right); 18048c2ecf20Sopenharmony_ci goto out_free; 18058c2ecf20Sopenharmony_ci } 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_OP; 18088c2ecf20Sopenharmony_ci arg->op.left = left; 18098c2ecf20Sopenharmony_ci arg->op.right = right; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci *tok = NULL; 18128c2ecf20Sopenharmony_ci type = process_arg(event, left, &token); 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci again: 18158c2ecf20Sopenharmony_ci if (type == TEP_EVENT_ERROR) 18168c2ecf20Sopenharmony_ci goto out_free; 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci /* Handle other operations in the arguments */ 18198c2ecf20Sopenharmony_ci if (type == TEP_EVENT_OP && strcmp(token, ":") != 0) { 18208c2ecf20Sopenharmony_ci type = process_op(event, left, &token); 18218c2ecf20Sopenharmony_ci goto again; 18228c2ecf20Sopenharmony_ci } 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_OP, ":")) 18258c2ecf20Sopenharmony_ci goto out_free; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci arg->op.op = token; 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci type = process_arg(event, right, &token); 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci top->op.right = arg; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci *tok = token; 18348c2ecf20Sopenharmony_ci return type; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ciout_free: 18378c2ecf20Sopenharmony_ci /* Top may point to itself */ 18388c2ecf20Sopenharmony_ci top->op.right = NULL; 18398c2ecf20Sopenharmony_ci free_token(token); 18408c2ecf20Sopenharmony_ci free_arg(arg); 18418c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 18428c2ecf20Sopenharmony_ci} 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_cistatic enum tep_event_type 18458c2ecf20Sopenharmony_ciprocess_array(struct tep_event *event, struct tep_print_arg *top, char **tok) 18468c2ecf20Sopenharmony_ci{ 18478c2ecf20Sopenharmony_ci struct tep_print_arg *arg; 18488c2ecf20Sopenharmony_ci enum tep_event_type type; 18498c2ecf20Sopenharmony_ci char *token = NULL; 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci arg = alloc_arg(); 18528c2ecf20Sopenharmony_ci if (!arg) { 18538c2ecf20Sopenharmony_ci do_warning_event(event, "%s: not enough memory!", __func__); 18548c2ecf20Sopenharmony_ci /* '*tok' is set to top->op.op. No need to free. */ 18558c2ecf20Sopenharmony_ci *tok = NULL; 18568c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 18578c2ecf20Sopenharmony_ci } 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci *tok = NULL; 18608c2ecf20Sopenharmony_ci type = process_arg(event, arg, &token); 18618c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_OP, "]")) 18628c2ecf20Sopenharmony_ci goto out_free; 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci top->op.right = arg; 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci free_token(token); 18678c2ecf20Sopenharmony_ci type = read_token_item(&token); 18688c2ecf20Sopenharmony_ci *tok = token; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci return type; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ciout_free: 18738c2ecf20Sopenharmony_ci free_token(token); 18748c2ecf20Sopenharmony_ci free_arg(arg); 18758c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 18768c2ecf20Sopenharmony_ci} 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_cistatic int get_op_prio(char *op) 18798c2ecf20Sopenharmony_ci{ 18808c2ecf20Sopenharmony_ci if (!op[1]) { 18818c2ecf20Sopenharmony_ci switch (op[0]) { 18828c2ecf20Sopenharmony_ci case '~': 18838c2ecf20Sopenharmony_ci case '!': 18848c2ecf20Sopenharmony_ci return 4; 18858c2ecf20Sopenharmony_ci case '*': 18868c2ecf20Sopenharmony_ci case '/': 18878c2ecf20Sopenharmony_ci case '%': 18888c2ecf20Sopenharmony_ci return 6; 18898c2ecf20Sopenharmony_ci case '+': 18908c2ecf20Sopenharmony_ci case '-': 18918c2ecf20Sopenharmony_ci return 7; 18928c2ecf20Sopenharmony_ci /* '>>' and '<<' are 8 */ 18938c2ecf20Sopenharmony_ci case '<': 18948c2ecf20Sopenharmony_ci case '>': 18958c2ecf20Sopenharmony_ci return 9; 18968c2ecf20Sopenharmony_ci /* '==' and '!=' are 10 */ 18978c2ecf20Sopenharmony_ci case '&': 18988c2ecf20Sopenharmony_ci return 11; 18998c2ecf20Sopenharmony_ci case '^': 19008c2ecf20Sopenharmony_ci return 12; 19018c2ecf20Sopenharmony_ci case '|': 19028c2ecf20Sopenharmony_ci return 13; 19038c2ecf20Sopenharmony_ci case '?': 19048c2ecf20Sopenharmony_ci return 16; 19058c2ecf20Sopenharmony_ci default: 19068c2ecf20Sopenharmony_ci do_warning("unknown op '%c'", op[0]); 19078c2ecf20Sopenharmony_ci return -1; 19088c2ecf20Sopenharmony_ci } 19098c2ecf20Sopenharmony_ci } else { 19108c2ecf20Sopenharmony_ci if (strcmp(op, "++") == 0 || 19118c2ecf20Sopenharmony_ci strcmp(op, "--") == 0) { 19128c2ecf20Sopenharmony_ci return 3; 19138c2ecf20Sopenharmony_ci } else if (strcmp(op, ">>") == 0 || 19148c2ecf20Sopenharmony_ci strcmp(op, "<<") == 0) { 19158c2ecf20Sopenharmony_ci return 8; 19168c2ecf20Sopenharmony_ci } else if (strcmp(op, ">=") == 0 || 19178c2ecf20Sopenharmony_ci strcmp(op, "<=") == 0) { 19188c2ecf20Sopenharmony_ci return 9; 19198c2ecf20Sopenharmony_ci } else if (strcmp(op, "==") == 0 || 19208c2ecf20Sopenharmony_ci strcmp(op, "!=") == 0) { 19218c2ecf20Sopenharmony_ci return 10; 19228c2ecf20Sopenharmony_ci } else if (strcmp(op, "&&") == 0) { 19238c2ecf20Sopenharmony_ci return 14; 19248c2ecf20Sopenharmony_ci } else if (strcmp(op, "||") == 0) { 19258c2ecf20Sopenharmony_ci return 15; 19268c2ecf20Sopenharmony_ci } else { 19278c2ecf20Sopenharmony_ci do_warning("unknown op '%s'", op); 19288c2ecf20Sopenharmony_ci return -1; 19298c2ecf20Sopenharmony_ci } 19308c2ecf20Sopenharmony_ci } 19318c2ecf20Sopenharmony_ci} 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_cistatic int set_op_prio(struct tep_print_arg *arg) 19348c2ecf20Sopenharmony_ci{ 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci /* single ops are the greatest */ 19378c2ecf20Sopenharmony_ci if (!arg->op.left || arg->op.left->type == TEP_PRINT_NULL) 19388c2ecf20Sopenharmony_ci arg->op.prio = 0; 19398c2ecf20Sopenharmony_ci else 19408c2ecf20Sopenharmony_ci arg->op.prio = get_op_prio(arg->op.op); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci return arg->op.prio; 19438c2ecf20Sopenharmony_ci} 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci/* Note, *tok does not get freed, but will most likely be saved */ 19468c2ecf20Sopenharmony_cistatic enum tep_event_type 19478c2ecf20Sopenharmony_ciprocess_op(struct tep_event *event, struct tep_print_arg *arg, char **tok) 19488c2ecf20Sopenharmony_ci{ 19498c2ecf20Sopenharmony_ci struct tep_print_arg *left, *right = NULL; 19508c2ecf20Sopenharmony_ci enum tep_event_type type; 19518c2ecf20Sopenharmony_ci char *token; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci /* the op is passed in via tok */ 19548c2ecf20Sopenharmony_ci token = *tok; 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci if (arg->type == TEP_PRINT_OP && !arg->op.left) { 19578c2ecf20Sopenharmony_ci /* handle single op */ 19588c2ecf20Sopenharmony_ci if (token[1]) { 19598c2ecf20Sopenharmony_ci do_warning_event(event, "bad op token %s", token); 19608c2ecf20Sopenharmony_ci goto out_free; 19618c2ecf20Sopenharmony_ci } 19628c2ecf20Sopenharmony_ci switch (token[0]) { 19638c2ecf20Sopenharmony_ci case '~': 19648c2ecf20Sopenharmony_ci case '!': 19658c2ecf20Sopenharmony_ci case '+': 19668c2ecf20Sopenharmony_ci case '-': 19678c2ecf20Sopenharmony_ci break; 19688c2ecf20Sopenharmony_ci default: 19698c2ecf20Sopenharmony_ci do_warning_event(event, "bad op token %s", token); 19708c2ecf20Sopenharmony_ci goto out_free; 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci } 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci /* make an empty left */ 19758c2ecf20Sopenharmony_ci left = alloc_arg(); 19768c2ecf20Sopenharmony_ci if (!left) 19778c2ecf20Sopenharmony_ci goto out_warn_free; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci left->type = TEP_PRINT_NULL; 19808c2ecf20Sopenharmony_ci arg->op.left = left; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci right = alloc_arg(); 19838c2ecf20Sopenharmony_ci if (!right) 19848c2ecf20Sopenharmony_ci goto out_warn_free; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci arg->op.right = right; 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci /* do not free the token, it belongs to an op */ 19898c2ecf20Sopenharmony_ci *tok = NULL; 19908c2ecf20Sopenharmony_ci type = process_arg(event, right, tok); 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci } else if (strcmp(token, "?") == 0) { 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci left = alloc_arg(); 19958c2ecf20Sopenharmony_ci if (!left) 19968c2ecf20Sopenharmony_ci goto out_warn_free; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci /* copy the top arg to the left */ 19998c2ecf20Sopenharmony_ci *left = *arg; 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_OP; 20028c2ecf20Sopenharmony_ci arg->op.op = token; 20038c2ecf20Sopenharmony_ci arg->op.left = left; 20048c2ecf20Sopenharmony_ci arg->op.prio = 0; 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci /* it will set arg->op.right */ 20078c2ecf20Sopenharmony_ci type = process_cond(event, arg, tok); 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci } else if (strcmp(token, ">>") == 0 || 20108c2ecf20Sopenharmony_ci strcmp(token, "<<") == 0 || 20118c2ecf20Sopenharmony_ci strcmp(token, "&") == 0 || 20128c2ecf20Sopenharmony_ci strcmp(token, "|") == 0 || 20138c2ecf20Sopenharmony_ci strcmp(token, "&&") == 0 || 20148c2ecf20Sopenharmony_ci strcmp(token, "||") == 0 || 20158c2ecf20Sopenharmony_ci strcmp(token, "-") == 0 || 20168c2ecf20Sopenharmony_ci strcmp(token, "+") == 0 || 20178c2ecf20Sopenharmony_ci strcmp(token, "*") == 0 || 20188c2ecf20Sopenharmony_ci strcmp(token, "^") == 0 || 20198c2ecf20Sopenharmony_ci strcmp(token, "/") == 0 || 20208c2ecf20Sopenharmony_ci strcmp(token, "%") == 0 || 20218c2ecf20Sopenharmony_ci strcmp(token, "<") == 0 || 20228c2ecf20Sopenharmony_ci strcmp(token, ">") == 0 || 20238c2ecf20Sopenharmony_ci strcmp(token, "<=") == 0 || 20248c2ecf20Sopenharmony_ci strcmp(token, ">=") == 0 || 20258c2ecf20Sopenharmony_ci strcmp(token, "==") == 0 || 20268c2ecf20Sopenharmony_ci strcmp(token, "!=") == 0) { 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci left = alloc_arg(); 20298c2ecf20Sopenharmony_ci if (!left) 20308c2ecf20Sopenharmony_ci goto out_warn_free; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci /* copy the top arg to the left */ 20338c2ecf20Sopenharmony_ci *left = *arg; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_OP; 20368c2ecf20Sopenharmony_ci arg->op.op = token; 20378c2ecf20Sopenharmony_ci arg->op.left = left; 20388c2ecf20Sopenharmony_ci arg->op.right = NULL; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci if (set_op_prio(arg) == -1) { 20418c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_FAILED; 20428c2ecf20Sopenharmony_ci /* arg->op.op (= token) will be freed at out_free */ 20438c2ecf20Sopenharmony_ci arg->op.op = NULL; 20448c2ecf20Sopenharmony_ci goto out_free; 20458c2ecf20Sopenharmony_ci } 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci type = read_token_item(&token); 20488c2ecf20Sopenharmony_ci *tok = token; 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci /* could just be a type pointer */ 20518c2ecf20Sopenharmony_ci if ((strcmp(arg->op.op, "*") == 0) && 20528c2ecf20Sopenharmony_ci type == TEP_EVENT_DELIM && (strcmp(token, ")") == 0)) { 20538c2ecf20Sopenharmony_ci int ret; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci if (left->type != TEP_PRINT_ATOM) { 20568c2ecf20Sopenharmony_ci do_warning_event(event, "bad pointer type"); 20578c2ecf20Sopenharmony_ci goto out_free; 20588c2ecf20Sopenharmony_ci } 20598c2ecf20Sopenharmony_ci ret = append(&left->atom.atom, " ", "*"); 20608c2ecf20Sopenharmony_ci if (ret < 0) 20618c2ecf20Sopenharmony_ci goto out_warn_free; 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci free(arg->op.op); 20648c2ecf20Sopenharmony_ci *arg = *left; 20658c2ecf20Sopenharmony_ci free(left); 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci return type; 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci right = alloc_arg(); 20718c2ecf20Sopenharmony_ci if (!right) 20728c2ecf20Sopenharmony_ci goto out_warn_free; 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci type = process_arg_token(event, right, tok, type); 20758c2ecf20Sopenharmony_ci if (type == TEP_EVENT_ERROR) { 20768c2ecf20Sopenharmony_ci free_arg(right); 20778c2ecf20Sopenharmony_ci /* token was freed in process_arg_token() via *tok */ 20788c2ecf20Sopenharmony_ci token = NULL; 20798c2ecf20Sopenharmony_ci goto out_free; 20808c2ecf20Sopenharmony_ci } 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci if (right->type == TEP_PRINT_OP && 20838c2ecf20Sopenharmony_ci get_op_prio(arg->op.op) < get_op_prio(right->op.op)) { 20848c2ecf20Sopenharmony_ci struct tep_print_arg tmp; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci /* rotate ops according to the priority */ 20878c2ecf20Sopenharmony_ci arg->op.right = right->op.left; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci tmp = *arg; 20908c2ecf20Sopenharmony_ci *arg = *right; 20918c2ecf20Sopenharmony_ci *right = tmp; 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci arg->op.left = right; 20948c2ecf20Sopenharmony_ci } else { 20958c2ecf20Sopenharmony_ci arg->op.right = right; 20968c2ecf20Sopenharmony_ci } 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci } else if (strcmp(token, "[") == 0) { 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci left = alloc_arg(); 21018c2ecf20Sopenharmony_ci if (!left) 21028c2ecf20Sopenharmony_ci goto out_warn_free; 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci *left = *arg; 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_OP; 21078c2ecf20Sopenharmony_ci arg->op.op = token; 21088c2ecf20Sopenharmony_ci arg->op.left = left; 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci arg->op.prio = 0; 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci /* it will set arg->op.right */ 21138c2ecf20Sopenharmony_ci type = process_array(event, arg, tok); 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci } else { 21168c2ecf20Sopenharmony_ci do_warning_event(event, "unknown op '%s'", token); 21178c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_FAILED; 21188c2ecf20Sopenharmony_ci /* the arg is now the left side */ 21198c2ecf20Sopenharmony_ci goto out_free; 21208c2ecf20Sopenharmony_ci } 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci if (type == TEP_EVENT_OP && strcmp(*tok, ":") != 0) { 21238c2ecf20Sopenharmony_ci int prio; 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci /* higher prios need to be closer to the root */ 21268c2ecf20Sopenharmony_ci prio = get_op_prio(*tok); 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci if (prio > arg->op.prio) 21298c2ecf20Sopenharmony_ci return process_op(event, arg, tok); 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci return process_op(event, right, tok); 21328c2ecf20Sopenharmony_ci } 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci return type; 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ciout_warn_free: 21378c2ecf20Sopenharmony_ci do_warning_event(event, "%s: not enough memory!", __func__); 21388c2ecf20Sopenharmony_ciout_free: 21398c2ecf20Sopenharmony_ci free_token(token); 21408c2ecf20Sopenharmony_ci *tok = NULL; 21418c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 21428c2ecf20Sopenharmony_ci} 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_cistatic enum tep_event_type 21458c2ecf20Sopenharmony_ciprocess_entry(struct tep_event *event __maybe_unused, struct tep_print_arg *arg, 21468c2ecf20Sopenharmony_ci char **tok) 21478c2ecf20Sopenharmony_ci{ 21488c2ecf20Sopenharmony_ci enum tep_event_type type; 21498c2ecf20Sopenharmony_ci char *field; 21508c2ecf20Sopenharmony_ci char *token; 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, "->") < 0) 21538c2ecf20Sopenharmony_ci goto out_err; 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) 21568c2ecf20Sopenharmony_ci goto out_free; 21578c2ecf20Sopenharmony_ci field = token; 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_FIELD; 21608c2ecf20Sopenharmony_ci arg->field.name = field; 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci if (is_flag_field) { 21638c2ecf20Sopenharmony_ci arg->field.field = tep_find_any_field(event, arg->field.name); 21648c2ecf20Sopenharmony_ci arg->field.field->flags |= TEP_FIELD_IS_FLAG; 21658c2ecf20Sopenharmony_ci is_flag_field = 0; 21668c2ecf20Sopenharmony_ci } else if (is_symbolic_field) { 21678c2ecf20Sopenharmony_ci arg->field.field = tep_find_any_field(event, arg->field.name); 21688c2ecf20Sopenharmony_ci arg->field.field->flags |= TEP_FIELD_IS_SYMBOLIC; 21698c2ecf20Sopenharmony_ci is_symbolic_field = 0; 21708c2ecf20Sopenharmony_ci } 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci type = read_token(&token); 21738c2ecf20Sopenharmony_ci *tok = token; 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci return type; 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci out_free: 21788c2ecf20Sopenharmony_ci free_token(token); 21798c2ecf20Sopenharmony_ci out_err: 21808c2ecf20Sopenharmony_ci *tok = NULL; 21818c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 21828c2ecf20Sopenharmony_ci} 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_cistatic int alloc_and_process_delim(struct tep_event *event, char *next_token, 21858c2ecf20Sopenharmony_ci struct tep_print_arg **print_arg) 21868c2ecf20Sopenharmony_ci{ 21878c2ecf20Sopenharmony_ci struct tep_print_arg *field; 21888c2ecf20Sopenharmony_ci enum tep_event_type type; 21898c2ecf20Sopenharmony_ci char *token; 21908c2ecf20Sopenharmony_ci int ret = 0; 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci field = alloc_arg(); 21938c2ecf20Sopenharmony_ci if (!field) { 21948c2ecf20Sopenharmony_ci do_warning_event(event, "%s: not enough memory!", __func__); 21958c2ecf20Sopenharmony_ci errno = ENOMEM; 21968c2ecf20Sopenharmony_ci return -1; 21978c2ecf20Sopenharmony_ci } 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci type = process_arg(event, field, &token); 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_DELIM, next_token)) { 22028c2ecf20Sopenharmony_ci errno = EINVAL; 22038c2ecf20Sopenharmony_ci ret = -1; 22048c2ecf20Sopenharmony_ci free_arg(field); 22058c2ecf20Sopenharmony_ci goto out_free_token; 22068c2ecf20Sopenharmony_ci } 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci *print_arg = field; 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ciout_free_token: 22118c2ecf20Sopenharmony_ci free_token(token); 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci return ret; 22148c2ecf20Sopenharmony_ci} 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_cistatic char *arg_eval (struct tep_print_arg *arg); 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_cistatic unsigned long long 22198c2ecf20Sopenharmony_cieval_type_str(unsigned long long val, const char *type, int pointer) 22208c2ecf20Sopenharmony_ci{ 22218c2ecf20Sopenharmony_ci int sign = 0; 22228c2ecf20Sopenharmony_ci char *ref; 22238c2ecf20Sopenharmony_ci int len; 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci len = strlen(type); 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci if (pointer) { 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci if (type[len-1] != '*') { 22308c2ecf20Sopenharmony_ci do_warning("pointer expected with non pointer type"); 22318c2ecf20Sopenharmony_ci return val; 22328c2ecf20Sopenharmony_ci } 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci ref = malloc(len); 22358c2ecf20Sopenharmony_ci if (!ref) { 22368c2ecf20Sopenharmony_ci do_warning("%s: not enough memory!", __func__); 22378c2ecf20Sopenharmony_ci return val; 22388c2ecf20Sopenharmony_ci } 22398c2ecf20Sopenharmony_ci memcpy(ref, type, len); 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci /* chop off the " *" */ 22428c2ecf20Sopenharmony_ci ref[len - 2] = 0; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci val = eval_type_str(val, ref, 0); 22458c2ecf20Sopenharmony_ci free(ref); 22468c2ecf20Sopenharmony_ci return val; 22478c2ecf20Sopenharmony_ci } 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci /* check if this is a pointer */ 22508c2ecf20Sopenharmony_ci if (type[len - 1] == '*') 22518c2ecf20Sopenharmony_ci return val; 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ci /* Try to figure out the arg size*/ 22548c2ecf20Sopenharmony_ci if (strncmp(type, "struct", 6) == 0) 22558c2ecf20Sopenharmony_ci /* all bets off */ 22568c2ecf20Sopenharmony_ci return val; 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci if (strcmp(type, "u8") == 0) 22598c2ecf20Sopenharmony_ci return val & 0xff; 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci if (strcmp(type, "u16") == 0) 22628c2ecf20Sopenharmony_ci return val & 0xffff; 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci if (strcmp(type, "u32") == 0) 22658c2ecf20Sopenharmony_ci return val & 0xffffffff; 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci if (strcmp(type, "u64") == 0 || 22688c2ecf20Sopenharmony_ci strcmp(type, "s64") == 0) 22698c2ecf20Sopenharmony_ci return val; 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci if (strcmp(type, "s8") == 0) 22728c2ecf20Sopenharmony_ci return (unsigned long long)(char)val & 0xff; 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_ci if (strcmp(type, "s16") == 0) 22758c2ecf20Sopenharmony_ci return (unsigned long long)(short)val & 0xffff; 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci if (strcmp(type, "s32") == 0) 22788c2ecf20Sopenharmony_ci return (unsigned long long)(int)val & 0xffffffff; 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci if (strncmp(type, "unsigned ", 9) == 0) { 22818c2ecf20Sopenharmony_ci sign = 0; 22828c2ecf20Sopenharmony_ci type += 9; 22838c2ecf20Sopenharmony_ci } 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci if (strcmp(type, "char") == 0) { 22868c2ecf20Sopenharmony_ci if (sign) 22878c2ecf20Sopenharmony_ci return (unsigned long long)(char)val & 0xff; 22888c2ecf20Sopenharmony_ci else 22898c2ecf20Sopenharmony_ci return val & 0xff; 22908c2ecf20Sopenharmony_ci } 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci if (strcmp(type, "short") == 0) { 22938c2ecf20Sopenharmony_ci if (sign) 22948c2ecf20Sopenharmony_ci return (unsigned long long)(short)val & 0xffff; 22958c2ecf20Sopenharmony_ci else 22968c2ecf20Sopenharmony_ci return val & 0xffff; 22978c2ecf20Sopenharmony_ci } 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci if (strcmp(type, "int") == 0) { 23008c2ecf20Sopenharmony_ci if (sign) 23018c2ecf20Sopenharmony_ci return (unsigned long long)(int)val & 0xffffffff; 23028c2ecf20Sopenharmony_ci else 23038c2ecf20Sopenharmony_ci return val & 0xffffffff; 23048c2ecf20Sopenharmony_ci } 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci return val; 23078c2ecf20Sopenharmony_ci} 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci/* 23108c2ecf20Sopenharmony_ci * Try to figure out the type. 23118c2ecf20Sopenharmony_ci */ 23128c2ecf20Sopenharmony_cistatic unsigned long long 23138c2ecf20Sopenharmony_cieval_type(unsigned long long val, struct tep_print_arg *arg, int pointer) 23148c2ecf20Sopenharmony_ci{ 23158c2ecf20Sopenharmony_ci if (arg->type != TEP_PRINT_TYPE) { 23168c2ecf20Sopenharmony_ci do_warning("expected type argument"); 23178c2ecf20Sopenharmony_ci return 0; 23188c2ecf20Sopenharmony_ci } 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci return eval_type_str(val, arg->typecast.type, pointer); 23218c2ecf20Sopenharmony_ci} 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_cistatic int arg_num_eval(struct tep_print_arg *arg, long long *val) 23248c2ecf20Sopenharmony_ci{ 23258c2ecf20Sopenharmony_ci long long left, right; 23268c2ecf20Sopenharmony_ci int ret = 1; 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci switch (arg->type) { 23298c2ecf20Sopenharmony_ci case TEP_PRINT_ATOM: 23308c2ecf20Sopenharmony_ci *val = strtoll(arg->atom.atom, NULL, 0); 23318c2ecf20Sopenharmony_ci break; 23328c2ecf20Sopenharmony_ci case TEP_PRINT_TYPE: 23338c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->typecast.item, val); 23348c2ecf20Sopenharmony_ci if (!ret) 23358c2ecf20Sopenharmony_ci break; 23368c2ecf20Sopenharmony_ci *val = eval_type(*val, arg, 0); 23378c2ecf20Sopenharmony_ci break; 23388c2ecf20Sopenharmony_ci case TEP_PRINT_OP: 23398c2ecf20Sopenharmony_ci switch (arg->op.op[0]) { 23408c2ecf20Sopenharmony_ci case '|': 23418c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.left, &left); 23428c2ecf20Sopenharmony_ci if (!ret) 23438c2ecf20Sopenharmony_ci break; 23448c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.right, &right); 23458c2ecf20Sopenharmony_ci if (!ret) 23468c2ecf20Sopenharmony_ci break; 23478c2ecf20Sopenharmony_ci if (arg->op.op[1]) 23488c2ecf20Sopenharmony_ci *val = left || right; 23498c2ecf20Sopenharmony_ci else 23508c2ecf20Sopenharmony_ci *val = left | right; 23518c2ecf20Sopenharmony_ci break; 23528c2ecf20Sopenharmony_ci case '&': 23538c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.left, &left); 23548c2ecf20Sopenharmony_ci if (!ret) 23558c2ecf20Sopenharmony_ci break; 23568c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.right, &right); 23578c2ecf20Sopenharmony_ci if (!ret) 23588c2ecf20Sopenharmony_ci break; 23598c2ecf20Sopenharmony_ci if (arg->op.op[1]) 23608c2ecf20Sopenharmony_ci *val = left && right; 23618c2ecf20Sopenharmony_ci else 23628c2ecf20Sopenharmony_ci *val = left & right; 23638c2ecf20Sopenharmony_ci break; 23648c2ecf20Sopenharmony_ci case '<': 23658c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.left, &left); 23668c2ecf20Sopenharmony_ci if (!ret) 23678c2ecf20Sopenharmony_ci break; 23688c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.right, &right); 23698c2ecf20Sopenharmony_ci if (!ret) 23708c2ecf20Sopenharmony_ci break; 23718c2ecf20Sopenharmony_ci switch (arg->op.op[1]) { 23728c2ecf20Sopenharmony_ci case 0: 23738c2ecf20Sopenharmony_ci *val = left < right; 23748c2ecf20Sopenharmony_ci break; 23758c2ecf20Sopenharmony_ci case '<': 23768c2ecf20Sopenharmony_ci *val = left << right; 23778c2ecf20Sopenharmony_ci break; 23788c2ecf20Sopenharmony_ci case '=': 23798c2ecf20Sopenharmony_ci *val = left <= right; 23808c2ecf20Sopenharmony_ci break; 23818c2ecf20Sopenharmony_ci default: 23828c2ecf20Sopenharmony_ci do_warning("unknown op '%s'", arg->op.op); 23838c2ecf20Sopenharmony_ci ret = 0; 23848c2ecf20Sopenharmony_ci } 23858c2ecf20Sopenharmony_ci break; 23868c2ecf20Sopenharmony_ci case '>': 23878c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.left, &left); 23888c2ecf20Sopenharmony_ci if (!ret) 23898c2ecf20Sopenharmony_ci break; 23908c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.right, &right); 23918c2ecf20Sopenharmony_ci if (!ret) 23928c2ecf20Sopenharmony_ci break; 23938c2ecf20Sopenharmony_ci switch (arg->op.op[1]) { 23948c2ecf20Sopenharmony_ci case 0: 23958c2ecf20Sopenharmony_ci *val = left > right; 23968c2ecf20Sopenharmony_ci break; 23978c2ecf20Sopenharmony_ci case '>': 23988c2ecf20Sopenharmony_ci *val = left >> right; 23998c2ecf20Sopenharmony_ci break; 24008c2ecf20Sopenharmony_ci case '=': 24018c2ecf20Sopenharmony_ci *val = left >= right; 24028c2ecf20Sopenharmony_ci break; 24038c2ecf20Sopenharmony_ci default: 24048c2ecf20Sopenharmony_ci do_warning("unknown op '%s'", arg->op.op); 24058c2ecf20Sopenharmony_ci ret = 0; 24068c2ecf20Sopenharmony_ci } 24078c2ecf20Sopenharmony_ci break; 24088c2ecf20Sopenharmony_ci case '=': 24098c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.left, &left); 24108c2ecf20Sopenharmony_ci if (!ret) 24118c2ecf20Sopenharmony_ci break; 24128c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.right, &right); 24138c2ecf20Sopenharmony_ci if (!ret) 24148c2ecf20Sopenharmony_ci break; 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci if (arg->op.op[1] != '=') { 24178c2ecf20Sopenharmony_ci do_warning("unknown op '%s'", arg->op.op); 24188c2ecf20Sopenharmony_ci ret = 0; 24198c2ecf20Sopenharmony_ci } else 24208c2ecf20Sopenharmony_ci *val = left == right; 24218c2ecf20Sopenharmony_ci break; 24228c2ecf20Sopenharmony_ci case '!': 24238c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.left, &left); 24248c2ecf20Sopenharmony_ci if (!ret) 24258c2ecf20Sopenharmony_ci break; 24268c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.right, &right); 24278c2ecf20Sopenharmony_ci if (!ret) 24288c2ecf20Sopenharmony_ci break; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci switch (arg->op.op[1]) { 24318c2ecf20Sopenharmony_ci case '=': 24328c2ecf20Sopenharmony_ci *val = left != right; 24338c2ecf20Sopenharmony_ci break; 24348c2ecf20Sopenharmony_ci default: 24358c2ecf20Sopenharmony_ci do_warning("unknown op '%s'", arg->op.op); 24368c2ecf20Sopenharmony_ci ret = 0; 24378c2ecf20Sopenharmony_ci } 24388c2ecf20Sopenharmony_ci break; 24398c2ecf20Sopenharmony_ci case '-': 24408c2ecf20Sopenharmony_ci /* check for negative */ 24418c2ecf20Sopenharmony_ci if (arg->op.left->type == TEP_PRINT_NULL) 24428c2ecf20Sopenharmony_ci left = 0; 24438c2ecf20Sopenharmony_ci else 24448c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.left, &left); 24458c2ecf20Sopenharmony_ci if (!ret) 24468c2ecf20Sopenharmony_ci break; 24478c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.right, &right); 24488c2ecf20Sopenharmony_ci if (!ret) 24498c2ecf20Sopenharmony_ci break; 24508c2ecf20Sopenharmony_ci *val = left - right; 24518c2ecf20Sopenharmony_ci break; 24528c2ecf20Sopenharmony_ci case '+': 24538c2ecf20Sopenharmony_ci if (arg->op.left->type == TEP_PRINT_NULL) 24548c2ecf20Sopenharmony_ci left = 0; 24558c2ecf20Sopenharmony_ci else 24568c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.left, &left); 24578c2ecf20Sopenharmony_ci if (!ret) 24588c2ecf20Sopenharmony_ci break; 24598c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.right, &right); 24608c2ecf20Sopenharmony_ci if (!ret) 24618c2ecf20Sopenharmony_ci break; 24628c2ecf20Sopenharmony_ci *val = left + right; 24638c2ecf20Sopenharmony_ci break; 24648c2ecf20Sopenharmony_ci case '~': 24658c2ecf20Sopenharmony_ci ret = arg_num_eval(arg->op.right, &right); 24668c2ecf20Sopenharmony_ci if (!ret) 24678c2ecf20Sopenharmony_ci break; 24688c2ecf20Sopenharmony_ci *val = ~right; 24698c2ecf20Sopenharmony_ci break; 24708c2ecf20Sopenharmony_ci default: 24718c2ecf20Sopenharmony_ci do_warning("unknown op '%s'", arg->op.op); 24728c2ecf20Sopenharmony_ci ret = 0; 24738c2ecf20Sopenharmony_ci } 24748c2ecf20Sopenharmony_ci break; 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci case TEP_PRINT_NULL: 24778c2ecf20Sopenharmony_ci case TEP_PRINT_FIELD ... TEP_PRINT_SYMBOL: 24788c2ecf20Sopenharmony_ci case TEP_PRINT_STRING: 24798c2ecf20Sopenharmony_ci case TEP_PRINT_BSTRING: 24808c2ecf20Sopenharmony_ci case TEP_PRINT_BITMASK: 24818c2ecf20Sopenharmony_ci default: 24828c2ecf20Sopenharmony_ci do_warning("invalid eval type %d", arg->type); 24838c2ecf20Sopenharmony_ci ret = 0; 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci } 24868c2ecf20Sopenharmony_ci return ret; 24878c2ecf20Sopenharmony_ci} 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_cistatic char *arg_eval (struct tep_print_arg *arg) 24908c2ecf20Sopenharmony_ci{ 24918c2ecf20Sopenharmony_ci long long val; 24928c2ecf20Sopenharmony_ci static char buf[24]; 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci switch (arg->type) { 24958c2ecf20Sopenharmony_ci case TEP_PRINT_ATOM: 24968c2ecf20Sopenharmony_ci return arg->atom.atom; 24978c2ecf20Sopenharmony_ci case TEP_PRINT_TYPE: 24988c2ecf20Sopenharmony_ci return arg_eval(arg->typecast.item); 24998c2ecf20Sopenharmony_ci case TEP_PRINT_OP: 25008c2ecf20Sopenharmony_ci if (!arg_num_eval(arg, &val)) 25018c2ecf20Sopenharmony_ci break; 25028c2ecf20Sopenharmony_ci sprintf(buf, "%lld", val); 25038c2ecf20Sopenharmony_ci return buf; 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci case TEP_PRINT_NULL: 25068c2ecf20Sopenharmony_ci case TEP_PRINT_FIELD ... TEP_PRINT_SYMBOL: 25078c2ecf20Sopenharmony_ci case TEP_PRINT_STRING: 25088c2ecf20Sopenharmony_ci case TEP_PRINT_BSTRING: 25098c2ecf20Sopenharmony_ci case TEP_PRINT_BITMASK: 25108c2ecf20Sopenharmony_ci default: 25118c2ecf20Sopenharmony_ci do_warning("invalid eval type %d", arg->type); 25128c2ecf20Sopenharmony_ci break; 25138c2ecf20Sopenharmony_ci } 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci return NULL; 25168c2ecf20Sopenharmony_ci} 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_cistatic enum tep_event_type 25198c2ecf20Sopenharmony_ciprocess_fields(struct tep_event *event, struct tep_print_flag_sym **list, char **tok) 25208c2ecf20Sopenharmony_ci{ 25218c2ecf20Sopenharmony_ci enum tep_event_type type; 25228c2ecf20Sopenharmony_ci struct tep_print_arg *arg = NULL; 25238c2ecf20Sopenharmony_ci struct tep_print_flag_sym *field; 25248c2ecf20Sopenharmony_ci char *token = *tok; 25258c2ecf20Sopenharmony_ci char *value; 25268c2ecf20Sopenharmony_ci 25278c2ecf20Sopenharmony_ci do { 25288c2ecf20Sopenharmony_ci free_token(token); 25298c2ecf20Sopenharmony_ci type = read_token_item(&token); 25308c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_OP, "{")) 25318c2ecf20Sopenharmony_ci break; 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci arg = alloc_arg(); 25348c2ecf20Sopenharmony_ci if (!arg) 25358c2ecf20Sopenharmony_ci goto out_free; 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci free_token(token); 25388c2ecf20Sopenharmony_ci type = process_arg(event, arg, &token); 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci if (type == TEP_EVENT_OP) 25418c2ecf20Sopenharmony_ci type = process_op(event, arg, &token); 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci if (type == TEP_EVENT_ERROR) 25448c2ecf20Sopenharmony_ci goto out_free; 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_DELIM, ",")) 25478c2ecf20Sopenharmony_ci goto out_free; 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci field = calloc(1, sizeof(*field)); 25508c2ecf20Sopenharmony_ci if (!field) 25518c2ecf20Sopenharmony_ci goto out_free; 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci value = arg_eval(arg); 25548c2ecf20Sopenharmony_ci if (value == NULL) 25558c2ecf20Sopenharmony_ci goto out_free_field; 25568c2ecf20Sopenharmony_ci field->value = strdup(value); 25578c2ecf20Sopenharmony_ci if (field->value == NULL) 25588c2ecf20Sopenharmony_ci goto out_free_field; 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci free_arg(arg); 25618c2ecf20Sopenharmony_ci arg = alloc_arg(); 25628c2ecf20Sopenharmony_ci if (!arg) 25638c2ecf20Sopenharmony_ci goto out_free; 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci free_token(token); 25668c2ecf20Sopenharmony_ci type = process_arg(event, arg, &token); 25678c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_OP, "}")) 25688c2ecf20Sopenharmony_ci goto out_free_field; 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci value = arg_eval(arg); 25718c2ecf20Sopenharmony_ci if (value == NULL) 25728c2ecf20Sopenharmony_ci goto out_free_field; 25738c2ecf20Sopenharmony_ci field->str = strdup(value); 25748c2ecf20Sopenharmony_ci if (field->str == NULL) 25758c2ecf20Sopenharmony_ci goto out_free_field; 25768c2ecf20Sopenharmony_ci free_arg(arg); 25778c2ecf20Sopenharmony_ci arg = NULL; 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci *list = field; 25808c2ecf20Sopenharmony_ci list = &field->next; 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_ci free_token(token); 25838c2ecf20Sopenharmony_ci type = read_token_item(&token); 25848c2ecf20Sopenharmony_ci } while (type == TEP_EVENT_DELIM && strcmp(token, ",") == 0); 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_ci *tok = token; 25878c2ecf20Sopenharmony_ci return type; 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ciout_free_field: 25908c2ecf20Sopenharmony_ci free_flag_sym(field); 25918c2ecf20Sopenharmony_ciout_free: 25928c2ecf20Sopenharmony_ci free_arg(arg); 25938c2ecf20Sopenharmony_ci free_token(token); 25948c2ecf20Sopenharmony_ci *tok = NULL; 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 25978c2ecf20Sopenharmony_ci} 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_cistatic enum tep_event_type 26008c2ecf20Sopenharmony_ciprocess_flags(struct tep_event *event, struct tep_print_arg *arg, char **tok) 26018c2ecf20Sopenharmony_ci{ 26028c2ecf20Sopenharmony_ci struct tep_print_arg *field; 26038c2ecf20Sopenharmony_ci enum tep_event_type type; 26048c2ecf20Sopenharmony_ci char *token = NULL; 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci memset(arg, 0, sizeof(*arg)); 26078c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_FLAGS; 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci field = alloc_arg(); 26108c2ecf20Sopenharmony_ci if (!field) { 26118c2ecf20Sopenharmony_ci do_warning_event(event, "%s: not enough memory!", __func__); 26128c2ecf20Sopenharmony_ci goto out_free; 26138c2ecf20Sopenharmony_ci } 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci type = process_field_arg(event, field, &token); 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci /* Handle operations in the first argument */ 26188c2ecf20Sopenharmony_ci while (type == TEP_EVENT_OP) 26198c2ecf20Sopenharmony_ci type = process_op(event, field, &token); 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_DELIM, ",")) 26228c2ecf20Sopenharmony_ci goto out_free_field; 26238c2ecf20Sopenharmony_ci free_token(token); 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci arg->flags.field = field; 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci type = read_token_item(&token); 26288c2ecf20Sopenharmony_ci if (event_item_type(type)) { 26298c2ecf20Sopenharmony_ci arg->flags.delim = token; 26308c2ecf20Sopenharmony_ci type = read_token_item(&token); 26318c2ecf20Sopenharmony_ci } 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_DELIM, ",")) 26348c2ecf20Sopenharmony_ci goto out_free; 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci type = process_fields(event, &arg->flags.flags, &token); 26378c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_DELIM, ")")) 26388c2ecf20Sopenharmony_ci goto out_free; 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci free_token(token); 26418c2ecf20Sopenharmony_ci type = read_token_item(tok); 26428c2ecf20Sopenharmony_ci return type; 26438c2ecf20Sopenharmony_ci 26448c2ecf20Sopenharmony_ciout_free_field: 26458c2ecf20Sopenharmony_ci free_arg(field); 26468c2ecf20Sopenharmony_ciout_free: 26478c2ecf20Sopenharmony_ci free_token(token); 26488c2ecf20Sopenharmony_ci *tok = NULL; 26498c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 26508c2ecf20Sopenharmony_ci} 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_cistatic enum tep_event_type 26538c2ecf20Sopenharmony_ciprocess_symbols(struct tep_event *event, struct tep_print_arg *arg, char **tok) 26548c2ecf20Sopenharmony_ci{ 26558c2ecf20Sopenharmony_ci struct tep_print_arg *field; 26568c2ecf20Sopenharmony_ci enum tep_event_type type; 26578c2ecf20Sopenharmony_ci char *token = NULL; 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_ci memset(arg, 0, sizeof(*arg)); 26608c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_SYMBOL; 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci field = alloc_arg(); 26638c2ecf20Sopenharmony_ci if (!field) { 26648c2ecf20Sopenharmony_ci do_warning_event(event, "%s: not enough memory!", __func__); 26658c2ecf20Sopenharmony_ci goto out_free; 26668c2ecf20Sopenharmony_ci } 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci type = process_field_arg(event, field, &token); 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_DELIM, ",")) 26718c2ecf20Sopenharmony_ci goto out_free_field; 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci arg->symbol.field = field; 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_ci type = process_fields(event, &arg->symbol.symbols, &token); 26768c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_DELIM, ")")) 26778c2ecf20Sopenharmony_ci goto out_free; 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci free_token(token); 26808c2ecf20Sopenharmony_ci type = read_token_item(tok); 26818c2ecf20Sopenharmony_ci return type; 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ciout_free_field: 26848c2ecf20Sopenharmony_ci free_arg(field); 26858c2ecf20Sopenharmony_ciout_free: 26868c2ecf20Sopenharmony_ci free_token(token); 26878c2ecf20Sopenharmony_ci *tok = NULL; 26888c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 26898c2ecf20Sopenharmony_ci} 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_cistatic enum tep_event_type 26928c2ecf20Sopenharmony_ciprocess_hex_common(struct tep_event *event, struct tep_print_arg *arg, 26938c2ecf20Sopenharmony_ci char **tok, enum tep_print_arg_type type) 26948c2ecf20Sopenharmony_ci{ 26958c2ecf20Sopenharmony_ci memset(arg, 0, sizeof(*arg)); 26968c2ecf20Sopenharmony_ci arg->type = type; 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci if (alloc_and_process_delim(event, ",", &arg->hex.field)) 26998c2ecf20Sopenharmony_ci goto out; 27008c2ecf20Sopenharmony_ci 27018c2ecf20Sopenharmony_ci if (alloc_and_process_delim(event, ")", &arg->hex.size)) 27028c2ecf20Sopenharmony_ci goto free_field; 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_ci return read_token_item(tok); 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_cifree_field: 27078c2ecf20Sopenharmony_ci free_arg(arg->hex.field); 27088c2ecf20Sopenharmony_ci arg->hex.field = NULL; 27098c2ecf20Sopenharmony_ciout: 27108c2ecf20Sopenharmony_ci *tok = NULL; 27118c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 27128c2ecf20Sopenharmony_ci} 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_cistatic enum tep_event_type 27158c2ecf20Sopenharmony_ciprocess_hex(struct tep_event *event, struct tep_print_arg *arg, char **tok) 27168c2ecf20Sopenharmony_ci{ 27178c2ecf20Sopenharmony_ci return process_hex_common(event, arg, tok, TEP_PRINT_HEX); 27188c2ecf20Sopenharmony_ci} 27198c2ecf20Sopenharmony_ci 27208c2ecf20Sopenharmony_cistatic enum tep_event_type 27218c2ecf20Sopenharmony_ciprocess_hex_str(struct tep_event *event, struct tep_print_arg *arg, 27228c2ecf20Sopenharmony_ci char **tok) 27238c2ecf20Sopenharmony_ci{ 27248c2ecf20Sopenharmony_ci return process_hex_common(event, arg, tok, TEP_PRINT_HEX_STR); 27258c2ecf20Sopenharmony_ci} 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_cistatic enum tep_event_type 27288c2ecf20Sopenharmony_ciprocess_int_array(struct tep_event *event, struct tep_print_arg *arg, char **tok) 27298c2ecf20Sopenharmony_ci{ 27308c2ecf20Sopenharmony_ci memset(arg, 0, sizeof(*arg)); 27318c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_INT_ARRAY; 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci if (alloc_and_process_delim(event, ",", &arg->int_array.field)) 27348c2ecf20Sopenharmony_ci goto out; 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci if (alloc_and_process_delim(event, ",", &arg->int_array.count)) 27378c2ecf20Sopenharmony_ci goto free_field; 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci if (alloc_and_process_delim(event, ")", &arg->int_array.el_size)) 27408c2ecf20Sopenharmony_ci goto free_size; 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci return read_token_item(tok); 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_cifree_size: 27458c2ecf20Sopenharmony_ci free_arg(arg->int_array.count); 27468c2ecf20Sopenharmony_ci arg->int_array.count = NULL; 27478c2ecf20Sopenharmony_cifree_field: 27488c2ecf20Sopenharmony_ci free_arg(arg->int_array.field); 27498c2ecf20Sopenharmony_ci arg->int_array.field = NULL; 27508c2ecf20Sopenharmony_ciout: 27518c2ecf20Sopenharmony_ci *tok = NULL; 27528c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 27538c2ecf20Sopenharmony_ci} 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_cistatic enum tep_event_type 27568c2ecf20Sopenharmony_ciprocess_dynamic_array(struct tep_event *event, struct tep_print_arg *arg, char **tok) 27578c2ecf20Sopenharmony_ci{ 27588c2ecf20Sopenharmony_ci struct tep_format_field *field; 27598c2ecf20Sopenharmony_ci enum tep_event_type type; 27608c2ecf20Sopenharmony_ci char *token; 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci memset(arg, 0, sizeof(*arg)); 27638c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_DYNAMIC_ARRAY; 27648c2ecf20Sopenharmony_ci 27658c2ecf20Sopenharmony_ci /* 27668c2ecf20Sopenharmony_ci * The item within the parenthesis is another field that holds 27678c2ecf20Sopenharmony_ci * the index into where the array starts. 27688c2ecf20Sopenharmony_ci */ 27698c2ecf20Sopenharmony_ci type = read_token(&token); 27708c2ecf20Sopenharmony_ci *tok = token; 27718c2ecf20Sopenharmony_ci if (type != TEP_EVENT_ITEM) 27728c2ecf20Sopenharmony_ci goto out_free; 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci /* Find the field */ 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci field = tep_find_field(event, token); 27778c2ecf20Sopenharmony_ci if (!field) 27788c2ecf20Sopenharmony_ci goto out_free; 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_ci arg->dynarray.field = field; 27818c2ecf20Sopenharmony_ci arg->dynarray.index = 0; 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_DELIM, ")") < 0) 27848c2ecf20Sopenharmony_ci goto out_free; 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci free_token(token); 27878c2ecf20Sopenharmony_ci type = read_token_item(&token); 27888c2ecf20Sopenharmony_ci *tok = token; 27898c2ecf20Sopenharmony_ci if (type != TEP_EVENT_OP || strcmp(token, "[") != 0) 27908c2ecf20Sopenharmony_ci return type; 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci free_token(token); 27938c2ecf20Sopenharmony_ci arg = alloc_arg(); 27948c2ecf20Sopenharmony_ci if (!arg) { 27958c2ecf20Sopenharmony_ci do_warning_event(event, "%s: not enough memory!", __func__); 27968c2ecf20Sopenharmony_ci *tok = NULL; 27978c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 27988c2ecf20Sopenharmony_ci } 27998c2ecf20Sopenharmony_ci 28008c2ecf20Sopenharmony_ci type = process_arg(event, arg, &token); 28018c2ecf20Sopenharmony_ci if (type == TEP_EVENT_ERROR) 28028c2ecf20Sopenharmony_ci goto out_free_arg; 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci if (!test_type_token(type, token, TEP_EVENT_OP, "]")) 28058c2ecf20Sopenharmony_ci goto out_free_arg; 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci free_token(token); 28088c2ecf20Sopenharmony_ci type = read_token_item(tok); 28098c2ecf20Sopenharmony_ci return type; 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci out_free_arg: 28128c2ecf20Sopenharmony_ci free_arg(arg); 28138c2ecf20Sopenharmony_ci out_free: 28148c2ecf20Sopenharmony_ci free_token(token); 28158c2ecf20Sopenharmony_ci *tok = NULL; 28168c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 28178c2ecf20Sopenharmony_ci} 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_cistatic enum tep_event_type 28208c2ecf20Sopenharmony_ciprocess_dynamic_array_len(struct tep_event *event, struct tep_print_arg *arg, 28218c2ecf20Sopenharmony_ci char **tok) 28228c2ecf20Sopenharmony_ci{ 28238c2ecf20Sopenharmony_ci struct tep_format_field *field; 28248c2ecf20Sopenharmony_ci enum tep_event_type type; 28258c2ecf20Sopenharmony_ci char *token; 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) 28288c2ecf20Sopenharmony_ci goto out_free; 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_DYNAMIC_ARRAY_LEN; 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci /* Find the field */ 28338c2ecf20Sopenharmony_ci field = tep_find_field(event, token); 28348c2ecf20Sopenharmony_ci if (!field) 28358c2ecf20Sopenharmony_ci goto out_free; 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ci arg->dynarray.field = field; 28388c2ecf20Sopenharmony_ci arg->dynarray.index = 0; 28398c2ecf20Sopenharmony_ci 28408c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_DELIM, ")") < 0) 28418c2ecf20Sopenharmony_ci goto out_err; 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_ci free_token(token); 28448c2ecf20Sopenharmony_ci type = read_token(&token); 28458c2ecf20Sopenharmony_ci *tok = token; 28468c2ecf20Sopenharmony_ci 28478c2ecf20Sopenharmony_ci return type; 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci out_free: 28508c2ecf20Sopenharmony_ci free_token(token); 28518c2ecf20Sopenharmony_ci out_err: 28528c2ecf20Sopenharmony_ci *tok = NULL; 28538c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 28548c2ecf20Sopenharmony_ci} 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_cistatic enum tep_event_type 28578c2ecf20Sopenharmony_ciprocess_paren(struct tep_event *event, struct tep_print_arg *arg, char **tok) 28588c2ecf20Sopenharmony_ci{ 28598c2ecf20Sopenharmony_ci struct tep_print_arg *item_arg; 28608c2ecf20Sopenharmony_ci enum tep_event_type type; 28618c2ecf20Sopenharmony_ci char *token; 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ci type = process_arg(event, arg, &token); 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci if (type == TEP_EVENT_ERROR) 28668c2ecf20Sopenharmony_ci goto out_free; 28678c2ecf20Sopenharmony_ci 28688c2ecf20Sopenharmony_ci if (type == TEP_EVENT_OP) 28698c2ecf20Sopenharmony_ci type = process_op(event, arg, &token); 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_ci if (type == TEP_EVENT_ERROR) 28728c2ecf20Sopenharmony_ci goto out_free; 28738c2ecf20Sopenharmony_ci 28748c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_DELIM, ")")) 28758c2ecf20Sopenharmony_ci goto out_free; 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_ci free_token(token); 28788c2ecf20Sopenharmony_ci type = read_token_item(&token); 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_ci /* 28818c2ecf20Sopenharmony_ci * If the next token is an item or another open paren, then 28828c2ecf20Sopenharmony_ci * this was a typecast. 28838c2ecf20Sopenharmony_ci */ 28848c2ecf20Sopenharmony_ci if (event_item_type(type) || 28858c2ecf20Sopenharmony_ci (type == TEP_EVENT_DELIM && strcmp(token, "(") == 0)) { 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_ci /* make this a typecast and contine */ 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci /* prevous must be an atom */ 28908c2ecf20Sopenharmony_ci if (arg->type != TEP_PRINT_ATOM) { 28918c2ecf20Sopenharmony_ci do_warning_event(event, "previous needed to be TEP_PRINT_ATOM"); 28928c2ecf20Sopenharmony_ci goto out_free; 28938c2ecf20Sopenharmony_ci } 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_ci item_arg = alloc_arg(); 28968c2ecf20Sopenharmony_ci if (!item_arg) { 28978c2ecf20Sopenharmony_ci do_warning_event(event, "%s: not enough memory!", 28988c2ecf20Sopenharmony_ci __func__); 28998c2ecf20Sopenharmony_ci goto out_free; 29008c2ecf20Sopenharmony_ci } 29018c2ecf20Sopenharmony_ci 29028c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_TYPE; 29038c2ecf20Sopenharmony_ci arg->typecast.type = arg->atom.atom; 29048c2ecf20Sopenharmony_ci arg->typecast.item = item_arg; 29058c2ecf20Sopenharmony_ci type = process_arg_token(event, item_arg, &token, type); 29068c2ecf20Sopenharmony_ci 29078c2ecf20Sopenharmony_ci } 29088c2ecf20Sopenharmony_ci 29098c2ecf20Sopenharmony_ci *tok = token; 29108c2ecf20Sopenharmony_ci return type; 29118c2ecf20Sopenharmony_ci 29128c2ecf20Sopenharmony_ci out_free: 29138c2ecf20Sopenharmony_ci free_token(token); 29148c2ecf20Sopenharmony_ci *tok = NULL; 29158c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 29168c2ecf20Sopenharmony_ci} 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_cistatic enum tep_event_type 29208c2ecf20Sopenharmony_ciprocess_str(struct tep_event *event __maybe_unused, struct tep_print_arg *arg, 29218c2ecf20Sopenharmony_ci char **tok) 29228c2ecf20Sopenharmony_ci{ 29238c2ecf20Sopenharmony_ci enum tep_event_type type; 29248c2ecf20Sopenharmony_ci char *token; 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) 29278c2ecf20Sopenharmony_ci goto out_free; 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_STRING; 29308c2ecf20Sopenharmony_ci arg->string.string = token; 29318c2ecf20Sopenharmony_ci arg->string.offset = -1; 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_DELIM, ")") < 0) 29348c2ecf20Sopenharmony_ci goto out_err; 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci type = read_token(&token); 29378c2ecf20Sopenharmony_ci *tok = token; 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_ci return type; 29408c2ecf20Sopenharmony_ci 29418c2ecf20Sopenharmony_ci out_free: 29428c2ecf20Sopenharmony_ci free_token(token); 29438c2ecf20Sopenharmony_ci out_err: 29448c2ecf20Sopenharmony_ci *tok = NULL; 29458c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 29468c2ecf20Sopenharmony_ci} 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_cistatic enum tep_event_type 29498c2ecf20Sopenharmony_ciprocess_bitmask(struct tep_event *event __maybe_unused, struct tep_print_arg *arg, 29508c2ecf20Sopenharmony_ci char **tok) 29518c2ecf20Sopenharmony_ci{ 29528c2ecf20Sopenharmony_ci enum tep_event_type type; 29538c2ecf20Sopenharmony_ci char *token; 29548c2ecf20Sopenharmony_ci 29558c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) 29568c2ecf20Sopenharmony_ci goto out_free; 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_BITMASK; 29598c2ecf20Sopenharmony_ci arg->bitmask.bitmask = token; 29608c2ecf20Sopenharmony_ci arg->bitmask.offset = -1; 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_DELIM, ")") < 0) 29638c2ecf20Sopenharmony_ci goto out_err; 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci type = read_token(&token); 29668c2ecf20Sopenharmony_ci *tok = token; 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ci return type; 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci out_free: 29718c2ecf20Sopenharmony_ci free_token(token); 29728c2ecf20Sopenharmony_ci out_err: 29738c2ecf20Sopenharmony_ci *tok = NULL; 29748c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 29758c2ecf20Sopenharmony_ci} 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_cistatic struct tep_function_handler * 29788c2ecf20Sopenharmony_cifind_func_handler(struct tep_handle *tep, char *func_name) 29798c2ecf20Sopenharmony_ci{ 29808c2ecf20Sopenharmony_ci struct tep_function_handler *func; 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci if (!tep) 29838c2ecf20Sopenharmony_ci return NULL; 29848c2ecf20Sopenharmony_ci 29858c2ecf20Sopenharmony_ci for (func = tep->func_handlers; func; func = func->next) { 29868c2ecf20Sopenharmony_ci if (strcmp(func->name, func_name) == 0) 29878c2ecf20Sopenharmony_ci break; 29888c2ecf20Sopenharmony_ci } 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ci return func; 29918c2ecf20Sopenharmony_ci} 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_cistatic void remove_func_handler(struct tep_handle *tep, char *func_name) 29948c2ecf20Sopenharmony_ci{ 29958c2ecf20Sopenharmony_ci struct tep_function_handler *func; 29968c2ecf20Sopenharmony_ci struct tep_function_handler **next; 29978c2ecf20Sopenharmony_ci 29988c2ecf20Sopenharmony_ci next = &tep->func_handlers; 29998c2ecf20Sopenharmony_ci while ((func = *next)) { 30008c2ecf20Sopenharmony_ci if (strcmp(func->name, func_name) == 0) { 30018c2ecf20Sopenharmony_ci *next = func->next; 30028c2ecf20Sopenharmony_ci free_func_handle(func); 30038c2ecf20Sopenharmony_ci break; 30048c2ecf20Sopenharmony_ci } 30058c2ecf20Sopenharmony_ci next = &func->next; 30068c2ecf20Sopenharmony_ci } 30078c2ecf20Sopenharmony_ci} 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_cistatic enum tep_event_type 30108c2ecf20Sopenharmony_ciprocess_func_handler(struct tep_event *event, struct tep_function_handler *func, 30118c2ecf20Sopenharmony_ci struct tep_print_arg *arg, char **tok) 30128c2ecf20Sopenharmony_ci{ 30138c2ecf20Sopenharmony_ci struct tep_print_arg **next_arg; 30148c2ecf20Sopenharmony_ci struct tep_print_arg *farg; 30158c2ecf20Sopenharmony_ci enum tep_event_type type; 30168c2ecf20Sopenharmony_ci char *token; 30178c2ecf20Sopenharmony_ci int i; 30188c2ecf20Sopenharmony_ci 30198c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_FUNC; 30208c2ecf20Sopenharmony_ci arg->func.func = func; 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci *tok = NULL; 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ci next_arg = &(arg->func.args); 30258c2ecf20Sopenharmony_ci for (i = 0; i < func->nr_args; i++) { 30268c2ecf20Sopenharmony_ci farg = alloc_arg(); 30278c2ecf20Sopenharmony_ci if (!farg) { 30288c2ecf20Sopenharmony_ci do_warning_event(event, "%s: not enough memory!", 30298c2ecf20Sopenharmony_ci __func__); 30308c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 30318c2ecf20Sopenharmony_ci } 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci type = process_arg(event, farg, &token); 30348c2ecf20Sopenharmony_ci if (i < (func->nr_args - 1)) { 30358c2ecf20Sopenharmony_ci if (type != TEP_EVENT_DELIM || strcmp(token, ",") != 0) { 30368c2ecf20Sopenharmony_ci do_warning_event(event, 30378c2ecf20Sopenharmony_ci "Error: function '%s()' expects %d arguments but event %s only uses %d", 30388c2ecf20Sopenharmony_ci func->name, func->nr_args, 30398c2ecf20Sopenharmony_ci event->name, i + 1); 30408c2ecf20Sopenharmony_ci goto err; 30418c2ecf20Sopenharmony_ci } 30428c2ecf20Sopenharmony_ci } else { 30438c2ecf20Sopenharmony_ci if (type != TEP_EVENT_DELIM || strcmp(token, ")") != 0) { 30448c2ecf20Sopenharmony_ci do_warning_event(event, 30458c2ecf20Sopenharmony_ci "Error: function '%s()' only expects %d arguments but event %s has more", 30468c2ecf20Sopenharmony_ci func->name, func->nr_args, event->name); 30478c2ecf20Sopenharmony_ci goto err; 30488c2ecf20Sopenharmony_ci } 30498c2ecf20Sopenharmony_ci } 30508c2ecf20Sopenharmony_ci 30518c2ecf20Sopenharmony_ci *next_arg = farg; 30528c2ecf20Sopenharmony_ci next_arg = &(farg->next); 30538c2ecf20Sopenharmony_ci free_token(token); 30548c2ecf20Sopenharmony_ci } 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci type = read_token(&token); 30578c2ecf20Sopenharmony_ci *tok = token; 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_ci return type; 30608c2ecf20Sopenharmony_ci 30618c2ecf20Sopenharmony_cierr: 30628c2ecf20Sopenharmony_ci free_arg(farg); 30638c2ecf20Sopenharmony_ci free_token(token); 30648c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 30658c2ecf20Sopenharmony_ci} 30668c2ecf20Sopenharmony_ci 30678c2ecf20Sopenharmony_cistatic enum tep_event_type 30688c2ecf20Sopenharmony_ciprocess_builtin_expect(struct tep_event *event, struct tep_print_arg *arg, char **tok) 30698c2ecf20Sopenharmony_ci{ 30708c2ecf20Sopenharmony_ci enum tep_event_type type; 30718c2ecf20Sopenharmony_ci char *token = NULL; 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci /* Handle __builtin_expect( cond, #) */ 30748c2ecf20Sopenharmony_ci type = process_arg(event, arg, &token); 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_ci if (type != TEP_EVENT_DELIM || token[0] != ',') 30778c2ecf20Sopenharmony_ci goto out_free; 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_ci free_token(token); 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ci /* We don't care what the second parameter is of the __builtin_expect() */ 30828c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) 30838c2ecf20Sopenharmony_ci goto out_free; 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_DELIM, ")") < 0) 30868c2ecf20Sopenharmony_ci goto out_free; 30878c2ecf20Sopenharmony_ci 30888c2ecf20Sopenharmony_ci free_token(token); 30898c2ecf20Sopenharmony_ci type = read_token_item(tok); 30908c2ecf20Sopenharmony_ci return type; 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_ciout_free: 30938c2ecf20Sopenharmony_ci free_token(token); 30948c2ecf20Sopenharmony_ci *tok = NULL; 30958c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 30968c2ecf20Sopenharmony_ci} 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_cistatic enum tep_event_type 30998c2ecf20Sopenharmony_ciprocess_function(struct tep_event *event, struct tep_print_arg *arg, 31008c2ecf20Sopenharmony_ci char *token, char **tok) 31018c2ecf20Sopenharmony_ci{ 31028c2ecf20Sopenharmony_ci struct tep_function_handler *func; 31038c2ecf20Sopenharmony_ci 31048c2ecf20Sopenharmony_ci if (strcmp(token, "__print_flags") == 0) { 31058c2ecf20Sopenharmony_ci free_token(token); 31068c2ecf20Sopenharmony_ci is_flag_field = 1; 31078c2ecf20Sopenharmony_ci return process_flags(event, arg, tok); 31088c2ecf20Sopenharmony_ci } 31098c2ecf20Sopenharmony_ci if (strcmp(token, "__print_symbolic") == 0) { 31108c2ecf20Sopenharmony_ci free_token(token); 31118c2ecf20Sopenharmony_ci is_symbolic_field = 1; 31128c2ecf20Sopenharmony_ci return process_symbols(event, arg, tok); 31138c2ecf20Sopenharmony_ci } 31148c2ecf20Sopenharmony_ci if (strcmp(token, "__print_hex") == 0) { 31158c2ecf20Sopenharmony_ci free_token(token); 31168c2ecf20Sopenharmony_ci return process_hex(event, arg, tok); 31178c2ecf20Sopenharmony_ci } 31188c2ecf20Sopenharmony_ci if (strcmp(token, "__print_hex_str") == 0) { 31198c2ecf20Sopenharmony_ci free_token(token); 31208c2ecf20Sopenharmony_ci return process_hex_str(event, arg, tok); 31218c2ecf20Sopenharmony_ci } 31228c2ecf20Sopenharmony_ci if (strcmp(token, "__print_array") == 0) { 31238c2ecf20Sopenharmony_ci free_token(token); 31248c2ecf20Sopenharmony_ci return process_int_array(event, arg, tok); 31258c2ecf20Sopenharmony_ci } 31268c2ecf20Sopenharmony_ci if (strcmp(token, "__get_str") == 0) { 31278c2ecf20Sopenharmony_ci free_token(token); 31288c2ecf20Sopenharmony_ci return process_str(event, arg, tok); 31298c2ecf20Sopenharmony_ci } 31308c2ecf20Sopenharmony_ci if (strcmp(token, "__get_bitmask") == 0) { 31318c2ecf20Sopenharmony_ci free_token(token); 31328c2ecf20Sopenharmony_ci return process_bitmask(event, arg, tok); 31338c2ecf20Sopenharmony_ci } 31348c2ecf20Sopenharmony_ci if (strcmp(token, "__get_dynamic_array") == 0) { 31358c2ecf20Sopenharmony_ci free_token(token); 31368c2ecf20Sopenharmony_ci return process_dynamic_array(event, arg, tok); 31378c2ecf20Sopenharmony_ci } 31388c2ecf20Sopenharmony_ci if (strcmp(token, "__get_dynamic_array_len") == 0) { 31398c2ecf20Sopenharmony_ci free_token(token); 31408c2ecf20Sopenharmony_ci return process_dynamic_array_len(event, arg, tok); 31418c2ecf20Sopenharmony_ci } 31428c2ecf20Sopenharmony_ci if (strcmp(token, "__builtin_expect") == 0) { 31438c2ecf20Sopenharmony_ci free_token(token); 31448c2ecf20Sopenharmony_ci return process_builtin_expect(event, arg, tok); 31458c2ecf20Sopenharmony_ci } 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_ci func = find_func_handler(event->tep, token); 31488c2ecf20Sopenharmony_ci if (func) { 31498c2ecf20Sopenharmony_ci free_token(token); 31508c2ecf20Sopenharmony_ci return process_func_handler(event, func, arg, tok); 31518c2ecf20Sopenharmony_ci } 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci do_warning_event(event, "function %s not defined", token); 31548c2ecf20Sopenharmony_ci free_token(token); 31558c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 31568c2ecf20Sopenharmony_ci} 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_cistatic enum tep_event_type 31598c2ecf20Sopenharmony_ciprocess_arg_token(struct tep_event *event, struct tep_print_arg *arg, 31608c2ecf20Sopenharmony_ci char **tok, enum tep_event_type type) 31618c2ecf20Sopenharmony_ci{ 31628c2ecf20Sopenharmony_ci char *token; 31638c2ecf20Sopenharmony_ci char *atom; 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci token = *tok; 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_ci switch (type) { 31688c2ecf20Sopenharmony_ci case TEP_EVENT_ITEM: 31698c2ecf20Sopenharmony_ci if (strcmp(token, "REC") == 0) { 31708c2ecf20Sopenharmony_ci free_token(token); 31718c2ecf20Sopenharmony_ci type = process_entry(event, arg, &token); 31728c2ecf20Sopenharmony_ci break; 31738c2ecf20Sopenharmony_ci } 31748c2ecf20Sopenharmony_ci atom = token; 31758c2ecf20Sopenharmony_ci /* test the next token */ 31768c2ecf20Sopenharmony_ci type = read_token_item(&token); 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci /* 31798c2ecf20Sopenharmony_ci * If the next token is a parenthesis, then this 31808c2ecf20Sopenharmony_ci * is a function. 31818c2ecf20Sopenharmony_ci */ 31828c2ecf20Sopenharmony_ci if (type == TEP_EVENT_DELIM && strcmp(token, "(") == 0) { 31838c2ecf20Sopenharmony_ci free_token(token); 31848c2ecf20Sopenharmony_ci token = NULL; 31858c2ecf20Sopenharmony_ci /* this will free atom. */ 31868c2ecf20Sopenharmony_ci type = process_function(event, arg, atom, &token); 31878c2ecf20Sopenharmony_ci break; 31888c2ecf20Sopenharmony_ci } 31898c2ecf20Sopenharmony_ci /* atoms can be more than one token long */ 31908c2ecf20Sopenharmony_ci while (type == TEP_EVENT_ITEM) { 31918c2ecf20Sopenharmony_ci int ret; 31928c2ecf20Sopenharmony_ci 31938c2ecf20Sopenharmony_ci ret = append(&atom, " ", token); 31948c2ecf20Sopenharmony_ci if (ret < 0) { 31958c2ecf20Sopenharmony_ci free(atom); 31968c2ecf20Sopenharmony_ci *tok = NULL; 31978c2ecf20Sopenharmony_ci free_token(token); 31988c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 31998c2ecf20Sopenharmony_ci } 32008c2ecf20Sopenharmony_ci free_token(token); 32018c2ecf20Sopenharmony_ci type = read_token_item(&token); 32028c2ecf20Sopenharmony_ci } 32038c2ecf20Sopenharmony_ci 32048c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_ATOM; 32058c2ecf20Sopenharmony_ci arg->atom.atom = atom; 32068c2ecf20Sopenharmony_ci break; 32078c2ecf20Sopenharmony_ci 32088c2ecf20Sopenharmony_ci case TEP_EVENT_DQUOTE: 32098c2ecf20Sopenharmony_ci case TEP_EVENT_SQUOTE: 32108c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_ATOM; 32118c2ecf20Sopenharmony_ci arg->atom.atom = token; 32128c2ecf20Sopenharmony_ci type = read_token_item(&token); 32138c2ecf20Sopenharmony_ci break; 32148c2ecf20Sopenharmony_ci case TEP_EVENT_DELIM: 32158c2ecf20Sopenharmony_ci if (strcmp(token, "(") == 0) { 32168c2ecf20Sopenharmony_ci free_token(token); 32178c2ecf20Sopenharmony_ci type = process_paren(event, arg, &token); 32188c2ecf20Sopenharmony_ci break; 32198c2ecf20Sopenharmony_ci } 32208c2ecf20Sopenharmony_ci case TEP_EVENT_OP: 32218c2ecf20Sopenharmony_ci /* handle single ops */ 32228c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_OP; 32238c2ecf20Sopenharmony_ci arg->op.op = token; 32248c2ecf20Sopenharmony_ci arg->op.left = NULL; 32258c2ecf20Sopenharmony_ci type = process_op(event, arg, &token); 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci /* On error, the op is freed */ 32288c2ecf20Sopenharmony_ci if (type == TEP_EVENT_ERROR) 32298c2ecf20Sopenharmony_ci arg->op.op = NULL; 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ci /* return error type if errored */ 32328c2ecf20Sopenharmony_ci break; 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci case TEP_EVENT_ERROR ... TEP_EVENT_NEWLINE: 32358c2ecf20Sopenharmony_ci default: 32368c2ecf20Sopenharmony_ci do_warning_event(event, "unexpected type %d", type); 32378c2ecf20Sopenharmony_ci return TEP_EVENT_ERROR; 32388c2ecf20Sopenharmony_ci } 32398c2ecf20Sopenharmony_ci *tok = token; 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci return type; 32428c2ecf20Sopenharmony_ci} 32438c2ecf20Sopenharmony_ci 32448c2ecf20Sopenharmony_cistatic int event_read_print_args(struct tep_event *event, struct tep_print_arg **list) 32458c2ecf20Sopenharmony_ci{ 32468c2ecf20Sopenharmony_ci enum tep_event_type type = TEP_EVENT_ERROR; 32478c2ecf20Sopenharmony_ci struct tep_print_arg *arg; 32488c2ecf20Sopenharmony_ci char *token; 32498c2ecf20Sopenharmony_ci int args = 0; 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci do { 32528c2ecf20Sopenharmony_ci if (type == TEP_EVENT_NEWLINE) { 32538c2ecf20Sopenharmony_ci type = read_token_item(&token); 32548c2ecf20Sopenharmony_ci continue; 32558c2ecf20Sopenharmony_ci } 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci arg = alloc_arg(); 32588c2ecf20Sopenharmony_ci if (!arg) { 32598c2ecf20Sopenharmony_ci do_warning_event(event, "%s: not enough memory!", 32608c2ecf20Sopenharmony_ci __func__); 32618c2ecf20Sopenharmony_ci return -1; 32628c2ecf20Sopenharmony_ci } 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci type = process_arg(event, arg, &token); 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_ci if (type == TEP_EVENT_ERROR) { 32678c2ecf20Sopenharmony_ci free_token(token); 32688c2ecf20Sopenharmony_ci free_arg(arg); 32698c2ecf20Sopenharmony_ci return -1; 32708c2ecf20Sopenharmony_ci } 32718c2ecf20Sopenharmony_ci 32728c2ecf20Sopenharmony_ci *list = arg; 32738c2ecf20Sopenharmony_ci args++; 32748c2ecf20Sopenharmony_ci 32758c2ecf20Sopenharmony_ci if (type == TEP_EVENT_OP) { 32768c2ecf20Sopenharmony_ci type = process_op(event, arg, &token); 32778c2ecf20Sopenharmony_ci free_token(token); 32788c2ecf20Sopenharmony_ci if (type == TEP_EVENT_ERROR) { 32798c2ecf20Sopenharmony_ci *list = NULL; 32808c2ecf20Sopenharmony_ci free_arg(arg); 32818c2ecf20Sopenharmony_ci return -1; 32828c2ecf20Sopenharmony_ci } 32838c2ecf20Sopenharmony_ci list = &arg->next; 32848c2ecf20Sopenharmony_ci continue; 32858c2ecf20Sopenharmony_ci } 32868c2ecf20Sopenharmony_ci 32878c2ecf20Sopenharmony_ci if (type == TEP_EVENT_DELIM && strcmp(token, ",") == 0) { 32888c2ecf20Sopenharmony_ci free_token(token); 32898c2ecf20Sopenharmony_ci *list = arg; 32908c2ecf20Sopenharmony_ci list = &arg->next; 32918c2ecf20Sopenharmony_ci continue; 32928c2ecf20Sopenharmony_ci } 32938c2ecf20Sopenharmony_ci break; 32948c2ecf20Sopenharmony_ci } while (type != TEP_EVENT_NONE); 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_ci if (type != TEP_EVENT_NONE && type != TEP_EVENT_ERROR) 32978c2ecf20Sopenharmony_ci free_token(token); 32988c2ecf20Sopenharmony_ci 32998c2ecf20Sopenharmony_ci return args; 33008c2ecf20Sopenharmony_ci} 33018c2ecf20Sopenharmony_ci 33028c2ecf20Sopenharmony_cistatic int event_read_print(struct tep_event *event) 33038c2ecf20Sopenharmony_ci{ 33048c2ecf20Sopenharmony_ci enum tep_event_type type; 33058c2ecf20Sopenharmony_ci char *token; 33068c2ecf20Sopenharmony_ci int ret; 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_ci if (read_expected_item(TEP_EVENT_ITEM, "print") < 0) 33098c2ecf20Sopenharmony_ci return -1; 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_ITEM, "fmt") < 0) 33128c2ecf20Sopenharmony_ci return -1; 33138c2ecf20Sopenharmony_ci 33148c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ":") < 0) 33158c2ecf20Sopenharmony_ci return -1; 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_DQUOTE, &token) < 0) 33188c2ecf20Sopenharmony_ci goto fail; 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_ci concat: 33218c2ecf20Sopenharmony_ci event->print_fmt.format = token; 33228c2ecf20Sopenharmony_ci event->print_fmt.args = NULL; 33238c2ecf20Sopenharmony_ci 33248c2ecf20Sopenharmony_ci /* ok to have no arg */ 33258c2ecf20Sopenharmony_ci type = read_token_item(&token); 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_ci if (type == TEP_EVENT_NONE) 33288c2ecf20Sopenharmony_ci return 0; 33298c2ecf20Sopenharmony_ci 33308c2ecf20Sopenharmony_ci /* Handle concatenation of print lines */ 33318c2ecf20Sopenharmony_ci if (type == TEP_EVENT_DQUOTE) { 33328c2ecf20Sopenharmony_ci char *cat; 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci if (asprintf(&cat, "%s%s", event->print_fmt.format, token) < 0) 33358c2ecf20Sopenharmony_ci goto fail; 33368c2ecf20Sopenharmony_ci free_token(token); 33378c2ecf20Sopenharmony_ci free_token(event->print_fmt.format); 33388c2ecf20Sopenharmony_ci event->print_fmt.format = NULL; 33398c2ecf20Sopenharmony_ci token = cat; 33408c2ecf20Sopenharmony_ci goto concat; 33418c2ecf20Sopenharmony_ci } 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_ci if (test_type_token(type, token, TEP_EVENT_DELIM, ",")) 33448c2ecf20Sopenharmony_ci goto fail; 33458c2ecf20Sopenharmony_ci 33468c2ecf20Sopenharmony_ci free_token(token); 33478c2ecf20Sopenharmony_ci 33488c2ecf20Sopenharmony_ci ret = event_read_print_args(event, &event->print_fmt.args); 33498c2ecf20Sopenharmony_ci if (ret < 0) 33508c2ecf20Sopenharmony_ci return -1; 33518c2ecf20Sopenharmony_ci 33528c2ecf20Sopenharmony_ci return ret; 33538c2ecf20Sopenharmony_ci 33548c2ecf20Sopenharmony_ci fail: 33558c2ecf20Sopenharmony_ci free_token(token); 33568c2ecf20Sopenharmony_ci return -1; 33578c2ecf20Sopenharmony_ci} 33588c2ecf20Sopenharmony_ci 33598c2ecf20Sopenharmony_ci/** 33608c2ecf20Sopenharmony_ci * tep_find_common_field - return a common field by event 33618c2ecf20Sopenharmony_ci * @event: handle for the event 33628c2ecf20Sopenharmony_ci * @name: the name of the common field to return 33638c2ecf20Sopenharmony_ci * 33648c2ecf20Sopenharmony_ci * Returns a common field from the event by the given @name. 33658c2ecf20Sopenharmony_ci * This only searches the common fields and not all field. 33668c2ecf20Sopenharmony_ci */ 33678c2ecf20Sopenharmony_cistruct tep_format_field * 33688c2ecf20Sopenharmony_citep_find_common_field(struct tep_event *event, const char *name) 33698c2ecf20Sopenharmony_ci{ 33708c2ecf20Sopenharmony_ci struct tep_format_field *format; 33718c2ecf20Sopenharmony_ci 33728c2ecf20Sopenharmony_ci for (format = event->format.common_fields; 33738c2ecf20Sopenharmony_ci format; format = format->next) { 33748c2ecf20Sopenharmony_ci if (strcmp(format->name, name) == 0) 33758c2ecf20Sopenharmony_ci break; 33768c2ecf20Sopenharmony_ci } 33778c2ecf20Sopenharmony_ci 33788c2ecf20Sopenharmony_ci return format; 33798c2ecf20Sopenharmony_ci} 33808c2ecf20Sopenharmony_ci 33818c2ecf20Sopenharmony_ci/** 33828c2ecf20Sopenharmony_ci * tep_find_field - find a non-common field 33838c2ecf20Sopenharmony_ci * @event: handle for the event 33848c2ecf20Sopenharmony_ci * @name: the name of the non-common field 33858c2ecf20Sopenharmony_ci * 33868c2ecf20Sopenharmony_ci * Returns a non-common field by the given @name. 33878c2ecf20Sopenharmony_ci * This does not search common fields. 33888c2ecf20Sopenharmony_ci */ 33898c2ecf20Sopenharmony_cistruct tep_format_field * 33908c2ecf20Sopenharmony_citep_find_field(struct tep_event *event, const char *name) 33918c2ecf20Sopenharmony_ci{ 33928c2ecf20Sopenharmony_ci struct tep_format_field *format; 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_ci for (format = event->format.fields; 33958c2ecf20Sopenharmony_ci format; format = format->next) { 33968c2ecf20Sopenharmony_ci if (strcmp(format->name, name) == 0) 33978c2ecf20Sopenharmony_ci break; 33988c2ecf20Sopenharmony_ci } 33998c2ecf20Sopenharmony_ci 34008c2ecf20Sopenharmony_ci return format; 34018c2ecf20Sopenharmony_ci} 34028c2ecf20Sopenharmony_ci 34038c2ecf20Sopenharmony_ci/** 34048c2ecf20Sopenharmony_ci * tep_find_any_field - find any field by name 34058c2ecf20Sopenharmony_ci * @event: handle for the event 34068c2ecf20Sopenharmony_ci * @name: the name of the field 34078c2ecf20Sopenharmony_ci * 34088c2ecf20Sopenharmony_ci * Returns a field by the given @name. 34098c2ecf20Sopenharmony_ci * This searches the common field names first, then 34108c2ecf20Sopenharmony_ci * the non-common ones if a common one was not found. 34118c2ecf20Sopenharmony_ci */ 34128c2ecf20Sopenharmony_cistruct tep_format_field * 34138c2ecf20Sopenharmony_citep_find_any_field(struct tep_event *event, const char *name) 34148c2ecf20Sopenharmony_ci{ 34158c2ecf20Sopenharmony_ci struct tep_format_field *format; 34168c2ecf20Sopenharmony_ci 34178c2ecf20Sopenharmony_ci format = tep_find_common_field(event, name); 34188c2ecf20Sopenharmony_ci if (format) 34198c2ecf20Sopenharmony_ci return format; 34208c2ecf20Sopenharmony_ci return tep_find_field(event, name); 34218c2ecf20Sopenharmony_ci} 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci/** 34248c2ecf20Sopenharmony_ci * tep_read_number - read a number from data 34258c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 34268c2ecf20Sopenharmony_ci * @ptr: the raw data 34278c2ecf20Sopenharmony_ci * @size: the size of the data that holds the number 34288c2ecf20Sopenharmony_ci * 34298c2ecf20Sopenharmony_ci * Returns the number (converted to host) from the 34308c2ecf20Sopenharmony_ci * raw data. 34318c2ecf20Sopenharmony_ci */ 34328c2ecf20Sopenharmony_ciunsigned long long tep_read_number(struct tep_handle *tep, 34338c2ecf20Sopenharmony_ci const void *ptr, int size) 34348c2ecf20Sopenharmony_ci{ 34358c2ecf20Sopenharmony_ci unsigned long long val; 34368c2ecf20Sopenharmony_ci 34378c2ecf20Sopenharmony_ci switch (size) { 34388c2ecf20Sopenharmony_ci case 1: 34398c2ecf20Sopenharmony_ci return *(unsigned char *)ptr; 34408c2ecf20Sopenharmony_ci case 2: 34418c2ecf20Sopenharmony_ci return data2host2(tep, *(unsigned short *)ptr); 34428c2ecf20Sopenharmony_ci case 4: 34438c2ecf20Sopenharmony_ci return data2host4(tep, *(unsigned int *)ptr); 34448c2ecf20Sopenharmony_ci case 8: 34458c2ecf20Sopenharmony_ci memcpy(&val, (ptr), sizeof(unsigned long long)); 34468c2ecf20Sopenharmony_ci return data2host8(tep, val); 34478c2ecf20Sopenharmony_ci default: 34488c2ecf20Sopenharmony_ci /* BUG! */ 34498c2ecf20Sopenharmony_ci return 0; 34508c2ecf20Sopenharmony_ci } 34518c2ecf20Sopenharmony_ci} 34528c2ecf20Sopenharmony_ci 34538c2ecf20Sopenharmony_ci/** 34548c2ecf20Sopenharmony_ci * tep_read_number_field - read a number from data 34558c2ecf20Sopenharmony_ci * @field: a handle to the field 34568c2ecf20Sopenharmony_ci * @data: the raw data to read 34578c2ecf20Sopenharmony_ci * @value: the value to place the number in 34588c2ecf20Sopenharmony_ci * 34598c2ecf20Sopenharmony_ci * Reads raw data according to a field offset and size, 34608c2ecf20Sopenharmony_ci * and translates it into @value. 34618c2ecf20Sopenharmony_ci * 34628c2ecf20Sopenharmony_ci * Returns 0 on success, -1 otherwise. 34638c2ecf20Sopenharmony_ci */ 34648c2ecf20Sopenharmony_ciint tep_read_number_field(struct tep_format_field *field, const void *data, 34658c2ecf20Sopenharmony_ci unsigned long long *value) 34668c2ecf20Sopenharmony_ci{ 34678c2ecf20Sopenharmony_ci if (!field) 34688c2ecf20Sopenharmony_ci return -1; 34698c2ecf20Sopenharmony_ci switch (field->size) { 34708c2ecf20Sopenharmony_ci case 1: 34718c2ecf20Sopenharmony_ci case 2: 34728c2ecf20Sopenharmony_ci case 4: 34738c2ecf20Sopenharmony_ci case 8: 34748c2ecf20Sopenharmony_ci *value = tep_read_number(field->event->tep, 34758c2ecf20Sopenharmony_ci data + field->offset, field->size); 34768c2ecf20Sopenharmony_ci return 0; 34778c2ecf20Sopenharmony_ci default: 34788c2ecf20Sopenharmony_ci return -1; 34798c2ecf20Sopenharmony_ci } 34808c2ecf20Sopenharmony_ci} 34818c2ecf20Sopenharmony_ci 34828c2ecf20Sopenharmony_cistatic int get_common_info(struct tep_handle *tep, 34838c2ecf20Sopenharmony_ci const char *type, int *offset, int *size) 34848c2ecf20Sopenharmony_ci{ 34858c2ecf20Sopenharmony_ci struct tep_event *event; 34868c2ecf20Sopenharmony_ci struct tep_format_field *field; 34878c2ecf20Sopenharmony_ci 34888c2ecf20Sopenharmony_ci /* 34898c2ecf20Sopenharmony_ci * All events should have the same common elements. 34908c2ecf20Sopenharmony_ci * Pick any event to find where the type is; 34918c2ecf20Sopenharmony_ci */ 34928c2ecf20Sopenharmony_ci if (!tep->events) { 34938c2ecf20Sopenharmony_ci do_warning("no event_list!"); 34948c2ecf20Sopenharmony_ci return -1; 34958c2ecf20Sopenharmony_ci } 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_ci event = tep->events[0]; 34988c2ecf20Sopenharmony_ci field = tep_find_common_field(event, type); 34998c2ecf20Sopenharmony_ci if (!field) 35008c2ecf20Sopenharmony_ci return -1; 35018c2ecf20Sopenharmony_ci 35028c2ecf20Sopenharmony_ci *offset = field->offset; 35038c2ecf20Sopenharmony_ci *size = field->size; 35048c2ecf20Sopenharmony_ci 35058c2ecf20Sopenharmony_ci return 0; 35068c2ecf20Sopenharmony_ci} 35078c2ecf20Sopenharmony_ci 35088c2ecf20Sopenharmony_cistatic int __parse_common(struct tep_handle *tep, void *data, 35098c2ecf20Sopenharmony_ci int *size, int *offset, const char *name) 35108c2ecf20Sopenharmony_ci{ 35118c2ecf20Sopenharmony_ci int ret; 35128c2ecf20Sopenharmony_ci 35138c2ecf20Sopenharmony_ci if (!*size) { 35148c2ecf20Sopenharmony_ci ret = get_common_info(tep, name, offset, size); 35158c2ecf20Sopenharmony_ci if (ret < 0) 35168c2ecf20Sopenharmony_ci return ret; 35178c2ecf20Sopenharmony_ci } 35188c2ecf20Sopenharmony_ci return tep_read_number(tep, data + *offset, *size); 35198c2ecf20Sopenharmony_ci} 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_cistatic int trace_parse_common_type(struct tep_handle *tep, void *data) 35228c2ecf20Sopenharmony_ci{ 35238c2ecf20Sopenharmony_ci return __parse_common(tep, data, 35248c2ecf20Sopenharmony_ci &tep->type_size, &tep->type_offset, 35258c2ecf20Sopenharmony_ci "common_type"); 35268c2ecf20Sopenharmony_ci} 35278c2ecf20Sopenharmony_ci 35288c2ecf20Sopenharmony_cistatic int parse_common_pid(struct tep_handle *tep, void *data) 35298c2ecf20Sopenharmony_ci{ 35308c2ecf20Sopenharmony_ci return __parse_common(tep, data, 35318c2ecf20Sopenharmony_ci &tep->pid_size, &tep->pid_offset, 35328c2ecf20Sopenharmony_ci "common_pid"); 35338c2ecf20Sopenharmony_ci} 35348c2ecf20Sopenharmony_ci 35358c2ecf20Sopenharmony_cistatic int parse_common_pc(struct tep_handle *tep, void *data) 35368c2ecf20Sopenharmony_ci{ 35378c2ecf20Sopenharmony_ci return __parse_common(tep, data, 35388c2ecf20Sopenharmony_ci &tep->pc_size, &tep->pc_offset, 35398c2ecf20Sopenharmony_ci "common_preempt_count"); 35408c2ecf20Sopenharmony_ci} 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_cistatic int parse_common_flags(struct tep_handle *tep, void *data) 35438c2ecf20Sopenharmony_ci{ 35448c2ecf20Sopenharmony_ci return __parse_common(tep, data, 35458c2ecf20Sopenharmony_ci &tep->flags_size, &tep->flags_offset, 35468c2ecf20Sopenharmony_ci "common_flags"); 35478c2ecf20Sopenharmony_ci} 35488c2ecf20Sopenharmony_ci 35498c2ecf20Sopenharmony_cistatic int parse_common_lock_depth(struct tep_handle *tep, void *data) 35508c2ecf20Sopenharmony_ci{ 35518c2ecf20Sopenharmony_ci return __parse_common(tep, data, 35528c2ecf20Sopenharmony_ci &tep->ld_size, &tep->ld_offset, 35538c2ecf20Sopenharmony_ci "common_lock_depth"); 35548c2ecf20Sopenharmony_ci} 35558c2ecf20Sopenharmony_ci 35568c2ecf20Sopenharmony_cistatic int parse_common_migrate_disable(struct tep_handle *tep, void *data) 35578c2ecf20Sopenharmony_ci{ 35588c2ecf20Sopenharmony_ci return __parse_common(tep, data, 35598c2ecf20Sopenharmony_ci &tep->ld_size, &tep->ld_offset, 35608c2ecf20Sopenharmony_ci "common_migrate_disable"); 35618c2ecf20Sopenharmony_ci} 35628c2ecf20Sopenharmony_ci 35638c2ecf20Sopenharmony_cistatic int events_id_cmp(const void *a, const void *b); 35648c2ecf20Sopenharmony_ci 35658c2ecf20Sopenharmony_ci/** 35668c2ecf20Sopenharmony_ci * tep_find_event - find an event by given id 35678c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 35688c2ecf20Sopenharmony_ci * @id: the id of the event 35698c2ecf20Sopenharmony_ci * 35708c2ecf20Sopenharmony_ci * Returns an event that has a given @id. 35718c2ecf20Sopenharmony_ci */ 35728c2ecf20Sopenharmony_cistruct tep_event *tep_find_event(struct tep_handle *tep, int id) 35738c2ecf20Sopenharmony_ci{ 35748c2ecf20Sopenharmony_ci struct tep_event **eventptr; 35758c2ecf20Sopenharmony_ci struct tep_event key; 35768c2ecf20Sopenharmony_ci struct tep_event *pkey = &key; 35778c2ecf20Sopenharmony_ci 35788c2ecf20Sopenharmony_ci /* Check cache first */ 35798c2ecf20Sopenharmony_ci if (tep->last_event && tep->last_event->id == id) 35808c2ecf20Sopenharmony_ci return tep->last_event; 35818c2ecf20Sopenharmony_ci 35828c2ecf20Sopenharmony_ci key.id = id; 35838c2ecf20Sopenharmony_ci 35848c2ecf20Sopenharmony_ci eventptr = bsearch(&pkey, tep->events, tep->nr_events, 35858c2ecf20Sopenharmony_ci sizeof(*tep->events), events_id_cmp); 35868c2ecf20Sopenharmony_ci 35878c2ecf20Sopenharmony_ci if (eventptr) { 35888c2ecf20Sopenharmony_ci tep->last_event = *eventptr; 35898c2ecf20Sopenharmony_ci return *eventptr; 35908c2ecf20Sopenharmony_ci } 35918c2ecf20Sopenharmony_ci 35928c2ecf20Sopenharmony_ci return NULL; 35938c2ecf20Sopenharmony_ci} 35948c2ecf20Sopenharmony_ci 35958c2ecf20Sopenharmony_ci/** 35968c2ecf20Sopenharmony_ci * tep_find_event_by_name - find an event by given name 35978c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 35988c2ecf20Sopenharmony_ci * @sys: the system name to search for 35998c2ecf20Sopenharmony_ci * @name: the name of the event to search for 36008c2ecf20Sopenharmony_ci * 36018c2ecf20Sopenharmony_ci * This returns an event with a given @name and under the system 36028c2ecf20Sopenharmony_ci * @sys. If @sys is NULL the first event with @name is returned. 36038c2ecf20Sopenharmony_ci */ 36048c2ecf20Sopenharmony_cistruct tep_event * 36058c2ecf20Sopenharmony_citep_find_event_by_name(struct tep_handle *tep, 36068c2ecf20Sopenharmony_ci const char *sys, const char *name) 36078c2ecf20Sopenharmony_ci{ 36088c2ecf20Sopenharmony_ci struct tep_event *event = NULL; 36098c2ecf20Sopenharmony_ci int i; 36108c2ecf20Sopenharmony_ci 36118c2ecf20Sopenharmony_ci if (tep->last_event && 36128c2ecf20Sopenharmony_ci strcmp(tep->last_event->name, name) == 0 && 36138c2ecf20Sopenharmony_ci (!sys || strcmp(tep->last_event->system, sys) == 0)) 36148c2ecf20Sopenharmony_ci return tep->last_event; 36158c2ecf20Sopenharmony_ci 36168c2ecf20Sopenharmony_ci for (i = 0; i < tep->nr_events; i++) { 36178c2ecf20Sopenharmony_ci event = tep->events[i]; 36188c2ecf20Sopenharmony_ci if (strcmp(event->name, name) == 0) { 36198c2ecf20Sopenharmony_ci if (!sys) 36208c2ecf20Sopenharmony_ci break; 36218c2ecf20Sopenharmony_ci if (strcmp(event->system, sys) == 0) 36228c2ecf20Sopenharmony_ci break; 36238c2ecf20Sopenharmony_ci } 36248c2ecf20Sopenharmony_ci } 36258c2ecf20Sopenharmony_ci if (i == tep->nr_events) 36268c2ecf20Sopenharmony_ci event = NULL; 36278c2ecf20Sopenharmony_ci 36288c2ecf20Sopenharmony_ci tep->last_event = event; 36298c2ecf20Sopenharmony_ci return event; 36308c2ecf20Sopenharmony_ci} 36318c2ecf20Sopenharmony_ci 36328c2ecf20Sopenharmony_cistatic unsigned long long 36338c2ecf20Sopenharmony_cieval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg *arg) 36348c2ecf20Sopenharmony_ci{ 36358c2ecf20Sopenharmony_ci struct tep_handle *tep = event->tep; 36368c2ecf20Sopenharmony_ci unsigned long long val = 0; 36378c2ecf20Sopenharmony_ci unsigned long long left, right; 36388c2ecf20Sopenharmony_ci struct tep_print_arg *typearg = NULL; 36398c2ecf20Sopenharmony_ci struct tep_print_arg *larg; 36408c2ecf20Sopenharmony_ci unsigned long offset; 36418c2ecf20Sopenharmony_ci unsigned int field_size; 36428c2ecf20Sopenharmony_ci 36438c2ecf20Sopenharmony_ci switch (arg->type) { 36448c2ecf20Sopenharmony_ci case TEP_PRINT_NULL: 36458c2ecf20Sopenharmony_ci /* ?? */ 36468c2ecf20Sopenharmony_ci return 0; 36478c2ecf20Sopenharmony_ci case TEP_PRINT_ATOM: 36488c2ecf20Sopenharmony_ci return strtoull(arg->atom.atom, NULL, 0); 36498c2ecf20Sopenharmony_ci case TEP_PRINT_FIELD: 36508c2ecf20Sopenharmony_ci if (!arg->field.field) { 36518c2ecf20Sopenharmony_ci arg->field.field = tep_find_any_field(event, arg->field.name); 36528c2ecf20Sopenharmony_ci if (!arg->field.field) 36538c2ecf20Sopenharmony_ci goto out_warning_field; 36548c2ecf20Sopenharmony_ci 36558c2ecf20Sopenharmony_ci } 36568c2ecf20Sopenharmony_ci /* must be a number */ 36578c2ecf20Sopenharmony_ci val = tep_read_number(tep, data + arg->field.field->offset, 36588c2ecf20Sopenharmony_ci arg->field.field->size); 36598c2ecf20Sopenharmony_ci break; 36608c2ecf20Sopenharmony_ci case TEP_PRINT_FLAGS: 36618c2ecf20Sopenharmony_ci case TEP_PRINT_SYMBOL: 36628c2ecf20Sopenharmony_ci case TEP_PRINT_INT_ARRAY: 36638c2ecf20Sopenharmony_ci case TEP_PRINT_HEX: 36648c2ecf20Sopenharmony_ci case TEP_PRINT_HEX_STR: 36658c2ecf20Sopenharmony_ci break; 36668c2ecf20Sopenharmony_ci case TEP_PRINT_TYPE: 36678c2ecf20Sopenharmony_ci val = eval_num_arg(data, size, event, arg->typecast.item); 36688c2ecf20Sopenharmony_ci return eval_type(val, arg, 0); 36698c2ecf20Sopenharmony_ci case TEP_PRINT_STRING: 36708c2ecf20Sopenharmony_ci case TEP_PRINT_BSTRING: 36718c2ecf20Sopenharmony_ci case TEP_PRINT_BITMASK: 36728c2ecf20Sopenharmony_ci return 0; 36738c2ecf20Sopenharmony_ci case TEP_PRINT_FUNC: { 36748c2ecf20Sopenharmony_ci struct trace_seq s; 36758c2ecf20Sopenharmony_ci trace_seq_init(&s); 36768c2ecf20Sopenharmony_ci val = process_defined_func(&s, data, size, event, arg); 36778c2ecf20Sopenharmony_ci trace_seq_destroy(&s); 36788c2ecf20Sopenharmony_ci return val; 36798c2ecf20Sopenharmony_ci } 36808c2ecf20Sopenharmony_ci case TEP_PRINT_OP: 36818c2ecf20Sopenharmony_ci if (strcmp(arg->op.op, "[") == 0) { 36828c2ecf20Sopenharmony_ci /* 36838c2ecf20Sopenharmony_ci * Arrays are special, since we don't want 36848c2ecf20Sopenharmony_ci * to read the arg as is. 36858c2ecf20Sopenharmony_ci */ 36868c2ecf20Sopenharmony_ci right = eval_num_arg(data, size, event, arg->op.right); 36878c2ecf20Sopenharmony_ci 36888c2ecf20Sopenharmony_ci /* handle typecasts */ 36898c2ecf20Sopenharmony_ci larg = arg->op.left; 36908c2ecf20Sopenharmony_ci while (larg->type == TEP_PRINT_TYPE) { 36918c2ecf20Sopenharmony_ci if (!typearg) 36928c2ecf20Sopenharmony_ci typearg = larg; 36938c2ecf20Sopenharmony_ci larg = larg->typecast.item; 36948c2ecf20Sopenharmony_ci } 36958c2ecf20Sopenharmony_ci 36968c2ecf20Sopenharmony_ci /* Default to long size */ 36978c2ecf20Sopenharmony_ci field_size = tep->long_size; 36988c2ecf20Sopenharmony_ci 36998c2ecf20Sopenharmony_ci switch (larg->type) { 37008c2ecf20Sopenharmony_ci case TEP_PRINT_DYNAMIC_ARRAY: 37018c2ecf20Sopenharmony_ci offset = tep_read_number(tep, 37028c2ecf20Sopenharmony_ci data + larg->dynarray.field->offset, 37038c2ecf20Sopenharmony_ci larg->dynarray.field->size); 37048c2ecf20Sopenharmony_ci if (larg->dynarray.field->elementsize) 37058c2ecf20Sopenharmony_ci field_size = larg->dynarray.field->elementsize; 37068c2ecf20Sopenharmony_ci /* 37078c2ecf20Sopenharmony_ci * The actual length of the dynamic array is stored 37088c2ecf20Sopenharmony_ci * in the top half of the field, and the offset 37098c2ecf20Sopenharmony_ci * is in the bottom half of the 32 bit field. 37108c2ecf20Sopenharmony_ci */ 37118c2ecf20Sopenharmony_ci offset &= 0xffff; 37128c2ecf20Sopenharmony_ci offset += right; 37138c2ecf20Sopenharmony_ci break; 37148c2ecf20Sopenharmony_ci case TEP_PRINT_FIELD: 37158c2ecf20Sopenharmony_ci if (!larg->field.field) { 37168c2ecf20Sopenharmony_ci larg->field.field = 37178c2ecf20Sopenharmony_ci tep_find_any_field(event, larg->field.name); 37188c2ecf20Sopenharmony_ci if (!larg->field.field) { 37198c2ecf20Sopenharmony_ci arg = larg; 37208c2ecf20Sopenharmony_ci goto out_warning_field; 37218c2ecf20Sopenharmony_ci } 37228c2ecf20Sopenharmony_ci } 37238c2ecf20Sopenharmony_ci field_size = larg->field.field->elementsize; 37248c2ecf20Sopenharmony_ci offset = larg->field.field->offset + 37258c2ecf20Sopenharmony_ci right * larg->field.field->elementsize; 37268c2ecf20Sopenharmony_ci break; 37278c2ecf20Sopenharmony_ci default: 37288c2ecf20Sopenharmony_ci goto default_op; /* oops, all bets off */ 37298c2ecf20Sopenharmony_ci } 37308c2ecf20Sopenharmony_ci val = tep_read_number(tep, 37318c2ecf20Sopenharmony_ci data + offset, field_size); 37328c2ecf20Sopenharmony_ci if (typearg) 37338c2ecf20Sopenharmony_ci val = eval_type(val, typearg, 1); 37348c2ecf20Sopenharmony_ci break; 37358c2ecf20Sopenharmony_ci } else if (strcmp(arg->op.op, "?") == 0) { 37368c2ecf20Sopenharmony_ci left = eval_num_arg(data, size, event, arg->op.left); 37378c2ecf20Sopenharmony_ci arg = arg->op.right; 37388c2ecf20Sopenharmony_ci if (left) 37398c2ecf20Sopenharmony_ci val = eval_num_arg(data, size, event, arg->op.left); 37408c2ecf20Sopenharmony_ci else 37418c2ecf20Sopenharmony_ci val = eval_num_arg(data, size, event, arg->op.right); 37428c2ecf20Sopenharmony_ci break; 37438c2ecf20Sopenharmony_ci } 37448c2ecf20Sopenharmony_ci default_op: 37458c2ecf20Sopenharmony_ci left = eval_num_arg(data, size, event, arg->op.left); 37468c2ecf20Sopenharmony_ci right = eval_num_arg(data, size, event, arg->op.right); 37478c2ecf20Sopenharmony_ci switch (arg->op.op[0]) { 37488c2ecf20Sopenharmony_ci case '!': 37498c2ecf20Sopenharmony_ci switch (arg->op.op[1]) { 37508c2ecf20Sopenharmony_ci case 0: 37518c2ecf20Sopenharmony_ci val = !right; 37528c2ecf20Sopenharmony_ci break; 37538c2ecf20Sopenharmony_ci case '=': 37548c2ecf20Sopenharmony_ci val = left != right; 37558c2ecf20Sopenharmony_ci break; 37568c2ecf20Sopenharmony_ci default: 37578c2ecf20Sopenharmony_ci goto out_warning_op; 37588c2ecf20Sopenharmony_ci } 37598c2ecf20Sopenharmony_ci break; 37608c2ecf20Sopenharmony_ci case '~': 37618c2ecf20Sopenharmony_ci val = ~right; 37628c2ecf20Sopenharmony_ci break; 37638c2ecf20Sopenharmony_ci case '|': 37648c2ecf20Sopenharmony_ci if (arg->op.op[1]) 37658c2ecf20Sopenharmony_ci val = left || right; 37668c2ecf20Sopenharmony_ci else 37678c2ecf20Sopenharmony_ci val = left | right; 37688c2ecf20Sopenharmony_ci break; 37698c2ecf20Sopenharmony_ci case '&': 37708c2ecf20Sopenharmony_ci if (arg->op.op[1]) 37718c2ecf20Sopenharmony_ci val = left && right; 37728c2ecf20Sopenharmony_ci else 37738c2ecf20Sopenharmony_ci val = left & right; 37748c2ecf20Sopenharmony_ci break; 37758c2ecf20Sopenharmony_ci case '<': 37768c2ecf20Sopenharmony_ci switch (arg->op.op[1]) { 37778c2ecf20Sopenharmony_ci case 0: 37788c2ecf20Sopenharmony_ci val = left < right; 37798c2ecf20Sopenharmony_ci break; 37808c2ecf20Sopenharmony_ci case '<': 37818c2ecf20Sopenharmony_ci val = left << right; 37828c2ecf20Sopenharmony_ci break; 37838c2ecf20Sopenharmony_ci case '=': 37848c2ecf20Sopenharmony_ci val = left <= right; 37858c2ecf20Sopenharmony_ci break; 37868c2ecf20Sopenharmony_ci default: 37878c2ecf20Sopenharmony_ci goto out_warning_op; 37888c2ecf20Sopenharmony_ci } 37898c2ecf20Sopenharmony_ci break; 37908c2ecf20Sopenharmony_ci case '>': 37918c2ecf20Sopenharmony_ci switch (arg->op.op[1]) { 37928c2ecf20Sopenharmony_ci case 0: 37938c2ecf20Sopenharmony_ci val = left > right; 37948c2ecf20Sopenharmony_ci break; 37958c2ecf20Sopenharmony_ci case '>': 37968c2ecf20Sopenharmony_ci val = left >> right; 37978c2ecf20Sopenharmony_ci break; 37988c2ecf20Sopenharmony_ci case '=': 37998c2ecf20Sopenharmony_ci val = left >= right; 38008c2ecf20Sopenharmony_ci break; 38018c2ecf20Sopenharmony_ci default: 38028c2ecf20Sopenharmony_ci goto out_warning_op; 38038c2ecf20Sopenharmony_ci } 38048c2ecf20Sopenharmony_ci break; 38058c2ecf20Sopenharmony_ci case '=': 38068c2ecf20Sopenharmony_ci if (arg->op.op[1] != '=') 38078c2ecf20Sopenharmony_ci goto out_warning_op; 38088c2ecf20Sopenharmony_ci 38098c2ecf20Sopenharmony_ci val = left == right; 38108c2ecf20Sopenharmony_ci break; 38118c2ecf20Sopenharmony_ci case '-': 38128c2ecf20Sopenharmony_ci val = left - right; 38138c2ecf20Sopenharmony_ci break; 38148c2ecf20Sopenharmony_ci case '+': 38158c2ecf20Sopenharmony_ci val = left + right; 38168c2ecf20Sopenharmony_ci break; 38178c2ecf20Sopenharmony_ci case '/': 38188c2ecf20Sopenharmony_ci val = left / right; 38198c2ecf20Sopenharmony_ci break; 38208c2ecf20Sopenharmony_ci case '%': 38218c2ecf20Sopenharmony_ci val = left % right; 38228c2ecf20Sopenharmony_ci break; 38238c2ecf20Sopenharmony_ci case '*': 38248c2ecf20Sopenharmony_ci val = left * right; 38258c2ecf20Sopenharmony_ci break; 38268c2ecf20Sopenharmony_ci default: 38278c2ecf20Sopenharmony_ci goto out_warning_op; 38288c2ecf20Sopenharmony_ci } 38298c2ecf20Sopenharmony_ci break; 38308c2ecf20Sopenharmony_ci case TEP_PRINT_DYNAMIC_ARRAY_LEN: 38318c2ecf20Sopenharmony_ci offset = tep_read_number(tep, 38328c2ecf20Sopenharmony_ci data + arg->dynarray.field->offset, 38338c2ecf20Sopenharmony_ci arg->dynarray.field->size); 38348c2ecf20Sopenharmony_ci /* 38358c2ecf20Sopenharmony_ci * The total allocated length of the dynamic array is 38368c2ecf20Sopenharmony_ci * stored in the top half of the field, and the offset 38378c2ecf20Sopenharmony_ci * is in the bottom half of the 32 bit field. 38388c2ecf20Sopenharmony_ci */ 38398c2ecf20Sopenharmony_ci val = (unsigned long long)(offset >> 16); 38408c2ecf20Sopenharmony_ci break; 38418c2ecf20Sopenharmony_ci case TEP_PRINT_DYNAMIC_ARRAY: 38428c2ecf20Sopenharmony_ci /* Without [], we pass the address to the dynamic data */ 38438c2ecf20Sopenharmony_ci offset = tep_read_number(tep, 38448c2ecf20Sopenharmony_ci data + arg->dynarray.field->offset, 38458c2ecf20Sopenharmony_ci arg->dynarray.field->size); 38468c2ecf20Sopenharmony_ci /* 38478c2ecf20Sopenharmony_ci * The total allocated length of the dynamic array is 38488c2ecf20Sopenharmony_ci * stored in the top half of the field, and the offset 38498c2ecf20Sopenharmony_ci * is in the bottom half of the 32 bit field. 38508c2ecf20Sopenharmony_ci */ 38518c2ecf20Sopenharmony_ci offset &= 0xffff; 38528c2ecf20Sopenharmony_ci val = (unsigned long long)((unsigned long)data + offset); 38538c2ecf20Sopenharmony_ci break; 38548c2ecf20Sopenharmony_ci default: /* not sure what to do there */ 38558c2ecf20Sopenharmony_ci return 0; 38568c2ecf20Sopenharmony_ci } 38578c2ecf20Sopenharmony_ci return val; 38588c2ecf20Sopenharmony_ci 38598c2ecf20Sopenharmony_ciout_warning_op: 38608c2ecf20Sopenharmony_ci do_warning_event(event, "%s: unknown op '%s'", __func__, arg->op.op); 38618c2ecf20Sopenharmony_ci return 0; 38628c2ecf20Sopenharmony_ci 38638c2ecf20Sopenharmony_ciout_warning_field: 38648c2ecf20Sopenharmony_ci do_warning_event(event, "%s: field %s not found", 38658c2ecf20Sopenharmony_ci __func__, arg->field.name); 38668c2ecf20Sopenharmony_ci return 0; 38678c2ecf20Sopenharmony_ci} 38688c2ecf20Sopenharmony_ci 38698c2ecf20Sopenharmony_cistruct flag { 38708c2ecf20Sopenharmony_ci const char *name; 38718c2ecf20Sopenharmony_ci unsigned long long value; 38728c2ecf20Sopenharmony_ci}; 38738c2ecf20Sopenharmony_ci 38748c2ecf20Sopenharmony_cistatic const struct flag flags[] = { 38758c2ecf20Sopenharmony_ci { "HI_SOFTIRQ", 0 }, 38768c2ecf20Sopenharmony_ci { "TIMER_SOFTIRQ", 1 }, 38778c2ecf20Sopenharmony_ci { "NET_TX_SOFTIRQ", 2 }, 38788c2ecf20Sopenharmony_ci { "NET_RX_SOFTIRQ", 3 }, 38798c2ecf20Sopenharmony_ci { "BLOCK_SOFTIRQ", 4 }, 38808c2ecf20Sopenharmony_ci { "IRQ_POLL_SOFTIRQ", 5 }, 38818c2ecf20Sopenharmony_ci { "TASKLET_SOFTIRQ", 6 }, 38828c2ecf20Sopenharmony_ci { "SCHED_SOFTIRQ", 7 }, 38838c2ecf20Sopenharmony_ci { "HRTIMER_SOFTIRQ", 8 }, 38848c2ecf20Sopenharmony_ci { "RCU_SOFTIRQ", 9 }, 38858c2ecf20Sopenharmony_ci 38868c2ecf20Sopenharmony_ci { "HRTIMER_NORESTART", 0 }, 38878c2ecf20Sopenharmony_ci { "HRTIMER_RESTART", 1 }, 38888c2ecf20Sopenharmony_ci}; 38898c2ecf20Sopenharmony_ci 38908c2ecf20Sopenharmony_cistatic long long eval_flag(const char *flag) 38918c2ecf20Sopenharmony_ci{ 38928c2ecf20Sopenharmony_ci int i; 38938c2ecf20Sopenharmony_ci 38948c2ecf20Sopenharmony_ci /* 38958c2ecf20Sopenharmony_ci * Some flags in the format files do not get converted. 38968c2ecf20Sopenharmony_ci * If the flag is not numeric, see if it is something that 38978c2ecf20Sopenharmony_ci * we already know about. 38988c2ecf20Sopenharmony_ci */ 38998c2ecf20Sopenharmony_ci if (isdigit(flag[0])) 39008c2ecf20Sopenharmony_ci return strtoull(flag, NULL, 0); 39018c2ecf20Sopenharmony_ci 39028c2ecf20Sopenharmony_ci for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++) 39038c2ecf20Sopenharmony_ci if (strcmp(flags[i].name, flag) == 0) 39048c2ecf20Sopenharmony_ci return flags[i].value; 39058c2ecf20Sopenharmony_ci 39068c2ecf20Sopenharmony_ci return -1LL; 39078c2ecf20Sopenharmony_ci} 39088c2ecf20Sopenharmony_ci 39098c2ecf20Sopenharmony_cistatic void print_str_to_seq(struct trace_seq *s, const char *format, 39108c2ecf20Sopenharmony_ci int len_arg, const char *str) 39118c2ecf20Sopenharmony_ci{ 39128c2ecf20Sopenharmony_ci if (len_arg >= 0) 39138c2ecf20Sopenharmony_ci trace_seq_printf(s, format, len_arg, str); 39148c2ecf20Sopenharmony_ci else 39158c2ecf20Sopenharmony_ci trace_seq_printf(s, format, str); 39168c2ecf20Sopenharmony_ci} 39178c2ecf20Sopenharmony_ci 39188c2ecf20Sopenharmony_cistatic void print_bitmask_to_seq(struct tep_handle *tep, 39198c2ecf20Sopenharmony_ci struct trace_seq *s, const char *format, 39208c2ecf20Sopenharmony_ci int len_arg, const void *data, int size) 39218c2ecf20Sopenharmony_ci{ 39228c2ecf20Sopenharmony_ci int nr_bits = size * 8; 39238c2ecf20Sopenharmony_ci int str_size = (nr_bits + 3) / 4; 39248c2ecf20Sopenharmony_ci int len = 0; 39258c2ecf20Sopenharmony_ci char buf[3]; 39268c2ecf20Sopenharmony_ci char *str; 39278c2ecf20Sopenharmony_ci int index; 39288c2ecf20Sopenharmony_ci int i; 39298c2ecf20Sopenharmony_ci 39308c2ecf20Sopenharmony_ci /* 39318c2ecf20Sopenharmony_ci * The kernel likes to put in commas every 32 bits, we 39328c2ecf20Sopenharmony_ci * can do the same. 39338c2ecf20Sopenharmony_ci */ 39348c2ecf20Sopenharmony_ci str_size += (nr_bits - 1) / 32; 39358c2ecf20Sopenharmony_ci 39368c2ecf20Sopenharmony_ci str = malloc(str_size + 1); 39378c2ecf20Sopenharmony_ci if (!str) { 39388c2ecf20Sopenharmony_ci do_warning("%s: not enough memory!", __func__); 39398c2ecf20Sopenharmony_ci return; 39408c2ecf20Sopenharmony_ci } 39418c2ecf20Sopenharmony_ci str[str_size] = 0; 39428c2ecf20Sopenharmony_ci 39438c2ecf20Sopenharmony_ci /* Start out with -2 for the two chars per byte */ 39448c2ecf20Sopenharmony_ci for (i = str_size - 2; i >= 0; i -= 2) { 39458c2ecf20Sopenharmony_ci /* 39468c2ecf20Sopenharmony_ci * data points to a bit mask of size bytes. 39478c2ecf20Sopenharmony_ci * In the kernel, this is an array of long words, thus 39488c2ecf20Sopenharmony_ci * endianness is very important. 39498c2ecf20Sopenharmony_ci */ 39508c2ecf20Sopenharmony_ci if (tep->file_bigendian) 39518c2ecf20Sopenharmony_ci index = size - (len + 1); 39528c2ecf20Sopenharmony_ci else 39538c2ecf20Sopenharmony_ci index = len; 39548c2ecf20Sopenharmony_ci 39558c2ecf20Sopenharmony_ci snprintf(buf, 3, "%02x", *((unsigned char *)data + index)); 39568c2ecf20Sopenharmony_ci memcpy(str + i, buf, 2); 39578c2ecf20Sopenharmony_ci len++; 39588c2ecf20Sopenharmony_ci if (!(len & 3) && i > 0) { 39598c2ecf20Sopenharmony_ci i--; 39608c2ecf20Sopenharmony_ci str[i] = ','; 39618c2ecf20Sopenharmony_ci } 39628c2ecf20Sopenharmony_ci } 39638c2ecf20Sopenharmony_ci 39648c2ecf20Sopenharmony_ci if (len_arg >= 0) 39658c2ecf20Sopenharmony_ci trace_seq_printf(s, format, len_arg, str); 39668c2ecf20Sopenharmony_ci else 39678c2ecf20Sopenharmony_ci trace_seq_printf(s, format, str); 39688c2ecf20Sopenharmony_ci 39698c2ecf20Sopenharmony_ci free(str); 39708c2ecf20Sopenharmony_ci} 39718c2ecf20Sopenharmony_ci 39728c2ecf20Sopenharmony_cistatic void print_str_arg(struct trace_seq *s, void *data, int size, 39738c2ecf20Sopenharmony_ci struct tep_event *event, const char *format, 39748c2ecf20Sopenharmony_ci int len_arg, struct tep_print_arg *arg) 39758c2ecf20Sopenharmony_ci{ 39768c2ecf20Sopenharmony_ci struct tep_handle *tep = event->tep; 39778c2ecf20Sopenharmony_ci struct tep_print_flag_sym *flag; 39788c2ecf20Sopenharmony_ci struct tep_format_field *field; 39798c2ecf20Sopenharmony_ci struct printk_map *printk; 39808c2ecf20Sopenharmony_ci long long val, fval; 39818c2ecf20Sopenharmony_ci unsigned long long addr; 39828c2ecf20Sopenharmony_ci char *str; 39838c2ecf20Sopenharmony_ci unsigned char *hex; 39848c2ecf20Sopenharmony_ci int print; 39858c2ecf20Sopenharmony_ci int i, len; 39868c2ecf20Sopenharmony_ci 39878c2ecf20Sopenharmony_ci switch (arg->type) { 39888c2ecf20Sopenharmony_ci case TEP_PRINT_NULL: 39898c2ecf20Sopenharmony_ci /* ?? */ 39908c2ecf20Sopenharmony_ci return; 39918c2ecf20Sopenharmony_ci case TEP_PRINT_ATOM: 39928c2ecf20Sopenharmony_ci print_str_to_seq(s, format, len_arg, arg->atom.atom); 39938c2ecf20Sopenharmony_ci return; 39948c2ecf20Sopenharmony_ci case TEP_PRINT_FIELD: 39958c2ecf20Sopenharmony_ci field = arg->field.field; 39968c2ecf20Sopenharmony_ci if (!field) { 39978c2ecf20Sopenharmony_ci field = tep_find_any_field(event, arg->field.name); 39988c2ecf20Sopenharmony_ci if (!field) { 39998c2ecf20Sopenharmony_ci str = arg->field.name; 40008c2ecf20Sopenharmony_ci goto out_warning_field; 40018c2ecf20Sopenharmony_ci } 40028c2ecf20Sopenharmony_ci arg->field.field = field; 40038c2ecf20Sopenharmony_ci } 40048c2ecf20Sopenharmony_ci /* Zero sized fields, mean the rest of the data */ 40058c2ecf20Sopenharmony_ci len = field->size ? : size - field->offset; 40068c2ecf20Sopenharmony_ci 40078c2ecf20Sopenharmony_ci /* 40088c2ecf20Sopenharmony_ci * Some events pass in pointers. If this is not an array 40098c2ecf20Sopenharmony_ci * and the size is the same as long_size, assume that it 40108c2ecf20Sopenharmony_ci * is a pointer. 40118c2ecf20Sopenharmony_ci */ 40128c2ecf20Sopenharmony_ci if (!(field->flags & TEP_FIELD_IS_ARRAY) && 40138c2ecf20Sopenharmony_ci field->size == tep->long_size) { 40148c2ecf20Sopenharmony_ci 40158c2ecf20Sopenharmony_ci /* Handle heterogeneous recording and processing 40168c2ecf20Sopenharmony_ci * architectures 40178c2ecf20Sopenharmony_ci * 40188c2ecf20Sopenharmony_ci * CASE I: 40198c2ecf20Sopenharmony_ci * Traces recorded on 32-bit devices (32-bit 40208c2ecf20Sopenharmony_ci * addressing) and processed on 64-bit devices: 40218c2ecf20Sopenharmony_ci * In this case, only 32 bits should be read. 40228c2ecf20Sopenharmony_ci * 40238c2ecf20Sopenharmony_ci * CASE II: 40248c2ecf20Sopenharmony_ci * Traces recorded on 64 bit devices and processed 40258c2ecf20Sopenharmony_ci * on 32-bit devices: 40268c2ecf20Sopenharmony_ci * In this case, 64 bits must be read. 40278c2ecf20Sopenharmony_ci */ 40288c2ecf20Sopenharmony_ci addr = (tep->long_size == 8) ? 40298c2ecf20Sopenharmony_ci *(unsigned long long *)(data + field->offset) : 40308c2ecf20Sopenharmony_ci (unsigned long long)*(unsigned int *)(data + field->offset); 40318c2ecf20Sopenharmony_ci 40328c2ecf20Sopenharmony_ci /* Check if it matches a print format */ 40338c2ecf20Sopenharmony_ci printk = find_printk(tep, addr); 40348c2ecf20Sopenharmony_ci if (printk) 40358c2ecf20Sopenharmony_ci trace_seq_puts(s, printk->printk); 40368c2ecf20Sopenharmony_ci else 40378c2ecf20Sopenharmony_ci trace_seq_printf(s, "%llx", addr); 40388c2ecf20Sopenharmony_ci break; 40398c2ecf20Sopenharmony_ci } 40408c2ecf20Sopenharmony_ci str = malloc(len + 1); 40418c2ecf20Sopenharmony_ci if (!str) { 40428c2ecf20Sopenharmony_ci do_warning_event(event, "%s: not enough memory!", 40438c2ecf20Sopenharmony_ci __func__); 40448c2ecf20Sopenharmony_ci return; 40458c2ecf20Sopenharmony_ci } 40468c2ecf20Sopenharmony_ci memcpy(str, data + field->offset, len); 40478c2ecf20Sopenharmony_ci str[len] = 0; 40488c2ecf20Sopenharmony_ci print_str_to_seq(s, format, len_arg, str); 40498c2ecf20Sopenharmony_ci free(str); 40508c2ecf20Sopenharmony_ci break; 40518c2ecf20Sopenharmony_ci case TEP_PRINT_FLAGS: 40528c2ecf20Sopenharmony_ci val = eval_num_arg(data, size, event, arg->flags.field); 40538c2ecf20Sopenharmony_ci print = 0; 40548c2ecf20Sopenharmony_ci for (flag = arg->flags.flags; flag; flag = flag->next) { 40558c2ecf20Sopenharmony_ci fval = eval_flag(flag->value); 40568c2ecf20Sopenharmony_ci if (!val && fval < 0) { 40578c2ecf20Sopenharmony_ci print_str_to_seq(s, format, len_arg, flag->str); 40588c2ecf20Sopenharmony_ci break; 40598c2ecf20Sopenharmony_ci } 40608c2ecf20Sopenharmony_ci if (fval > 0 && (val & fval) == fval) { 40618c2ecf20Sopenharmony_ci if (print && arg->flags.delim) 40628c2ecf20Sopenharmony_ci trace_seq_puts(s, arg->flags.delim); 40638c2ecf20Sopenharmony_ci print_str_to_seq(s, format, len_arg, flag->str); 40648c2ecf20Sopenharmony_ci print = 1; 40658c2ecf20Sopenharmony_ci val &= ~fval; 40668c2ecf20Sopenharmony_ci } 40678c2ecf20Sopenharmony_ci } 40688c2ecf20Sopenharmony_ci if (val) { 40698c2ecf20Sopenharmony_ci if (print && arg->flags.delim) 40708c2ecf20Sopenharmony_ci trace_seq_puts(s, arg->flags.delim); 40718c2ecf20Sopenharmony_ci trace_seq_printf(s, "0x%llx", val); 40728c2ecf20Sopenharmony_ci } 40738c2ecf20Sopenharmony_ci break; 40748c2ecf20Sopenharmony_ci case TEP_PRINT_SYMBOL: 40758c2ecf20Sopenharmony_ci val = eval_num_arg(data, size, event, arg->symbol.field); 40768c2ecf20Sopenharmony_ci for (flag = arg->symbol.symbols; flag; flag = flag->next) { 40778c2ecf20Sopenharmony_ci fval = eval_flag(flag->value); 40788c2ecf20Sopenharmony_ci if (val == fval) { 40798c2ecf20Sopenharmony_ci print_str_to_seq(s, format, len_arg, flag->str); 40808c2ecf20Sopenharmony_ci break; 40818c2ecf20Sopenharmony_ci } 40828c2ecf20Sopenharmony_ci } 40838c2ecf20Sopenharmony_ci if (!flag) 40848c2ecf20Sopenharmony_ci trace_seq_printf(s, "0x%llx", val); 40858c2ecf20Sopenharmony_ci break; 40868c2ecf20Sopenharmony_ci case TEP_PRINT_HEX: 40878c2ecf20Sopenharmony_ci case TEP_PRINT_HEX_STR: 40888c2ecf20Sopenharmony_ci if (arg->hex.field->type == TEP_PRINT_DYNAMIC_ARRAY) { 40898c2ecf20Sopenharmony_ci unsigned long offset; 40908c2ecf20Sopenharmony_ci offset = tep_read_number(tep, 40918c2ecf20Sopenharmony_ci data + arg->hex.field->dynarray.field->offset, 40928c2ecf20Sopenharmony_ci arg->hex.field->dynarray.field->size); 40938c2ecf20Sopenharmony_ci hex = data + (offset & 0xffff); 40948c2ecf20Sopenharmony_ci } else { 40958c2ecf20Sopenharmony_ci field = arg->hex.field->field.field; 40968c2ecf20Sopenharmony_ci if (!field) { 40978c2ecf20Sopenharmony_ci str = arg->hex.field->field.name; 40988c2ecf20Sopenharmony_ci field = tep_find_any_field(event, str); 40998c2ecf20Sopenharmony_ci if (!field) 41008c2ecf20Sopenharmony_ci goto out_warning_field; 41018c2ecf20Sopenharmony_ci arg->hex.field->field.field = field; 41028c2ecf20Sopenharmony_ci } 41038c2ecf20Sopenharmony_ci hex = data + field->offset; 41048c2ecf20Sopenharmony_ci } 41058c2ecf20Sopenharmony_ci len = eval_num_arg(data, size, event, arg->hex.size); 41068c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 41078c2ecf20Sopenharmony_ci if (i && arg->type == TEP_PRINT_HEX) 41088c2ecf20Sopenharmony_ci trace_seq_putc(s, ' '); 41098c2ecf20Sopenharmony_ci trace_seq_printf(s, "%02x", hex[i]); 41108c2ecf20Sopenharmony_ci } 41118c2ecf20Sopenharmony_ci break; 41128c2ecf20Sopenharmony_ci 41138c2ecf20Sopenharmony_ci case TEP_PRINT_INT_ARRAY: { 41148c2ecf20Sopenharmony_ci void *num; 41158c2ecf20Sopenharmony_ci int el_size; 41168c2ecf20Sopenharmony_ci 41178c2ecf20Sopenharmony_ci if (arg->int_array.field->type == TEP_PRINT_DYNAMIC_ARRAY) { 41188c2ecf20Sopenharmony_ci unsigned long offset; 41198c2ecf20Sopenharmony_ci struct tep_format_field *field = 41208c2ecf20Sopenharmony_ci arg->int_array.field->dynarray.field; 41218c2ecf20Sopenharmony_ci offset = tep_read_number(tep, 41228c2ecf20Sopenharmony_ci data + field->offset, 41238c2ecf20Sopenharmony_ci field->size); 41248c2ecf20Sopenharmony_ci num = data + (offset & 0xffff); 41258c2ecf20Sopenharmony_ci } else { 41268c2ecf20Sopenharmony_ci field = arg->int_array.field->field.field; 41278c2ecf20Sopenharmony_ci if (!field) { 41288c2ecf20Sopenharmony_ci str = arg->int_array.field->field.name; 41298c2ecf20Sopenharmony_ci field = tep_find_any_field(event, str); 41308c2ecf20Sopenharmony_ci if (!field) 41318c2ecf20Sopenharmony_ci goto out_warning_field; 41328c2ecf20Sopenharmony_ci arg->int_array.field->field.field = field; 41338c2ecf20Sopenharmony_ci } 41348c2ecf20Sopenharmony_ci num = data + field->offset; 41358c2ecf20Sopenharmony_ci } 41368c2ecf20Sopenharmony_ci len = eval_num_arg(data, size, event, arg->int_array.count); 41378c2ecf20Sopenharmony_ci el_size = eval_num_arg(data, size, event, 41388c2ecf20Sopenharmony_ci arg->int_array.el_size); 41398c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 41408c2ecf20Sopenharmony_ci if (i) 41418c2ecf20Sopenharmony_ci trace_seq_putc(s, ' '); 41428c2ecf20Sopenharmony_ci 41438c2ecf20Sopenharmony_ci if (el_size == 1) { 41448c2ecf20Sopenharmony_ci trace_seq_printf(s, "%u", *(uint8_t *)num); 41458c2ecf20Sopenharmony_ci } else if (el_size == 2) { 41468c2ecf20Sopenharmony_ci trace_seq_printf(s, "%u", *(uint16_t *)num); 41478c2ecf20Sopenharmony_ci } else if (el_size == 4) { 41488c2ecf20Sopenharmony_ci trace_seq_printf(s, "%u", *(uint32_t *)num); 41498c2ecf20Sopenharmony_ci } else if (el_size == 8) { 41508c2ecf20Sopenharmony_ci trace_seq_printf(s, "%"PRIu64, *(uint64_t *)num); 41518c2ecf20Sopenharmony_ci } else { 41528c2ecf20Sopenharmony_ci trace_seq_printf(s, "BAD SIZE:%d 0x%x", 41538c2ecf20Sopenharmony_ci el_size, *(uint8_t *)num); 41548c2ecf20Sopenharmony_ci el_size = 1; 41558c2ecf20Sopenharmony_ci } 41568c2ecf20Sopenharmony_ci 41578c2ecf20Sopenharmony_ci num += el_size; 41588c2ecf20Sopenharmony_ci } 41598c2ecf20Sopenharmony_ci break; 41608c2ecf20Sopenharmony_ci } 41618c2ecf20Sopenharmony_ci case TEP_PRINT_TYPE: 41628c2ecf20Sopenharmony_ci break; 41638c2ecf20Sopenharmony_ci case TEP_PRINT_STRING: { 41648c2ecf20Sopenharmony_ci int str_offset; 41658c2ecf20Sopenharmony_ci 41668c2ecf20Sopenharmony_ci if (arg->string.offset == -1) { 41678c2ecf20Sopenharmony_ci struct tep_format_field *f; 41688c2ecf20Sopenharmony_ci 41698c2ecf20Sopenharmony_ci f = tep_find_any_field(event, arg->string.string); 41708c2ecf20Sopenharmony_ci arg->string.offset = f->offset; 41718c2ecf20Sopenharmony_ci } 41728c2ecf20Sopenharmony_ci str_offset = data2host4(tep, *(unsigned int *)(data + arg->string.offset)); 41738c2ecf20Sopenharmony_ci str_offset &= 0xffff; 41748c2ecf20Sopenharmony_ci print_str_to_seq(s, format, len_arg, ((char *)data) + str_offset); 41758c2ecf20Sopenharmony_ci break; 41768c2ecf20Sopenharmony_ci } 41778c2ecf20Sopenharmony_ci case TEP_PRINT_BSTRING: 41788c2ecf20Sopenharmony_ci print_str_to_seq(s, format, len_arg, arg->string.string); 41798c2ecf20Sopenharmony_ci break; 41808c2ecf20Sopenharmony_ci case TEP_PRINT_BITMASK: { 41818c2ecf20Sopenharmony_ci int bitmask_offset; 41828c2ecf20Sopenharmony_ci int bitmask_size; 41838c2ecf20Sopenharmony_ci 41848c2ecf20Sopenharmony_ci if (arg->bitmask.offset == -1) { 41858c2ecf20Sopenharmony_ci struct tep_format_field *f; 41868c2ecf20Sopenharmony_ci 41878c2ecf20Sopenharmony_ci f = tep_find_any_field(event, arg->bitmask.bitmask); 41888c2ecf20Sopenharmony_ci arg->bitmask.offset = f->offset; 41898c2ecf20Sopenharmony_ci } 41908c2ecf20Sopenharmony_ci bitmask_offset = data2host4(tep, *(unsigned int *)(data + arg->bitmask.offset)); 41918c2ecf20Sopenharmony_ci bitmask_size = bitmask_offset >> 16; 41928c2ecf20Sopenharmony_ci bitmask_offset &= 0xffff; 41938c2ecf20Sopenharmony_ci print_bitmask_to_seq(tep, s, format, len_arg, 41948c2ecf20Sopenharmony_ci data + bitmask_offset, bitmask_size); 41958c2ecf20Sopenharmony_ci break; 41968c2ecf20Sopenharmony_ci } 41978c2ecf20Sopenharmony_ci case TEP_PRINT_OP: 41988c2ecf20Sopenharmony_ci /* 41998c2ecf20Sopenharmony_ci * The only op for string should be ? : 42008c2ecf20Sopenharmony_ci */ 42018c2ecf20Sopenharmony_ci if (arg->op.op[0] != '?') 42028c2ecf20Sopenharmony_ci return; 42038c2ecf20Sopenharmony_ci val = eval_num_arg(data, size, event, arg->op.left); 42048c2ecf20Sopenharmony_ci if (val) 42058c2ecf20Sopenharmony_ci print_str_arg(s, data, size, event, 42068c2ecf20Sopenharmony_ci format, len_arg, arg->op.right->op.left); 42078c2ecf20Sopenharmony_ci else 42088c2ecf20Sopenharmony_ci print_str_arg(s, data, size, event, 42098c2ecf20Sopenharmony_ci format, len_arg, arg->op.right->op.right); 42108c2ecf20Sopenharmony_ci break; 42118c2ecf20Sopenharmony_ci case TEP_PRINT_FUNC: 42128c2ecf20Sopenharmony_ci process_defined_func(s, data, size, event, arg); 42138c2ecf20Sopenharmony_ci break; 42148c2ecf20Sopenharmony_ci default: 42158c2ecf20Sopenharmony_ci /* well... */ 42168c2ecf20Sopenharmony_ci break; 42178c2ecf20Sopenharmony_ci } 42188c2ecf20Sopenharmony_ci 42198c2ecf20Sopenharmony_ci return; 42208c2ecf20Sopenharmony_ci 42218c2ecf20Sopenharmony_ciout_warning_field: 42228c2ecf20Sopenharmony_ci do_warning_event(event, "%s: field %s not found", 42238c2ecf20Sopenharmony_ci __func__, arg->field.name); 42248c2ecf20Sopenharmony_ci} 42258c2ecf20Sopenharmony_ci 42268c2ecf20Sopenharmony_cistatic unsigned long long 42278c2ecf20Sopenharmony_ciprocess_defined_func(struct trace_seq *s, void *data, int size, 42288c2ecf20Sopenharmony_ci struct tep_event *event, struct tep_print_arg *arg) 42298c2ecf20Sopenharmony_ci{ 42308c2ecf20Sopenharmony_ci struct tep_function_handler *func_handle = arg->func.func; 42318c2ecf20Sopenharmony_ci struct func_params *param; 42328c2ecf20Sopenharmony_ci unsigned long long *args; 42338c2ecf20Sopenharmony_ci unsigned long long ret; 42348c2ecf20Sopenharmony_ci struct tep_print_arg *farg; 42358c2ecf20Sopenharmony_ci struct trace_seq str; 42368c2ecf20Sopenharmony_ci struct save_str { 42378c2ecf20Sopenharmony_ci struct save_str *next; 42388c2ecf20Sopenharmony_ci char *str; 42398c2ecf20Sopenharmony_ci } *strings = NULL, *string; 42408c2ecf20Sopenharmony_ci int i; 42418c2ecf20Sopenharmony_ci 42428c2ecf20Sopenharmony_ci if (!func_handle->nr_args) { 42438c2ecf20Sopenharmony_ci ret = (*func_handle->func)(s, NULL); 42448c2ecf20Sopenharmony_ci goto out; 42458c2ecf20Sopenharmony_ci } 42468c2ecf20Sopenharmony_ci 42478c2ecf20Sopenharmony_ci farg = arg->func.args; 42488c2ecf20Sopenharmony_ci param = func_handle->params; 42498c2ecf20Sopenharmony_ci 42508c2ecf20Sopenharmony_ci ret = ULLONG_MAX; 42518c2ecf20Sopenharmony_ci args = malloc(sizeof(*args) * func_handle->nr_args); 42528c2ecf20Sopenharmony_ci if (!args) 42538c2ecf20Sopenharmony_ci goto out; 42548c2ecf20Sopenharmony_ci 42558c2ecf20Sopenharmony_ci for (i = 0; i < func_handle->nr_args; i++) { 42568c2ecf20Sopenharmony_ci switch (param->type) { 42578c2ecf20Sopenharmony_ci case TEP_FUNC_ARG_INT: 42588c2ecf20Sopenharmony_ci case TEP_FUNC_ARG_LONG: 42598c2ecf20Sopenharmony_ci case TEP_FUNC_ARG_PTR: 42608c2ecf20Sopenharmony_ci args[i] = eval_num_arg(data, size, event, farg); 42618c2ecf20Sopenharmony_ci break; 42628c2ecf20Sopenharmony_ci case TEP_FUNC_ARG_STRING: 42638c2ecf20Sopenharmony_ci trace_seq_init(&str); 42648c2ecf20Sopenharmony_ci print_str_arg(&str, data, size, event, "%s", -1, farg); 42658c2ecf20Sopenharmony_ci trace_seq_terminate(&str); 42668c2ecf20Sopenharmony_ci string = malloc(sizeof(*string)); 42678c2ecf20Sopenharmony_ci if (!string) { 42688c2ecf20Sopenharmony_ci do_warning_event(event, "%s(%d): malloc str", 42698c2ecf20Sopenharmony_ci __func__, __LINE__); 42708c2ecf20Sopenharmony_ci goto out_free; 42718c2ecf20Sopenharmony_ci } 42728c2ecf20Sopenharmony_ci string->next = strings; 42738c2ecf20Sopenharmony_ci string->str = strdup(str.buffer); 42748c2ecf20Sopenharmony_ci if (!string->str) { 42758c2ecf20Sopenharmony_ci free(string); 42768c2ecf20Sopenharmony_ci do_warning_event(event, "%s(%d): malloc str", 42778c2ecf20Sopenharmony_ci __func__, __LINE__); 42788c2ecf20Sopenharmony_ci goto out_free; 42798c2ecf20Sopenharmony_ci } 42808c2ecf20Sopenharmony_ci args[i] = (uintptr_t)string->str; 42818c2ecf20Sopenharmony_ci strings = string; 42828c2ecf20Sopenharmony_ci trace_seq_destroy(&str); 42838c2ecf20Sopenharmony_ci break; 42848c2ecf20Sopenharmony_ci default: 42858c2ecf20Sopenharmony_ci /* 42868c2ecf20Sopenharmony_ci * Something went totally wrong, this is not 42878c2ecf20Sopenharmony_ci * an input error, something in this code broke. 42888c2ecf20Sopenharmony_ci */ 42898c2ecf20Sopenharmony_ci do_warning_event(event, "Unexpected end of arguments\n"); 42908c2ecf20Sopenharmony_ci goto out_free; 42918c2ecf20Sopenharmony_ci } 42928c2ecf20Sopenharmony_ci farg = farg->next; 42938c2ecf20Sopenharmony_ci param = param->next; 42948c2ecf20Sopenharmony_ci } 42958c2ecf20Sopenharmony_ci 42968c2ecf20Sopenharmony_ci ret = (*func_handle->func)(s, args); 42978c2ecf20Sopenharmony_ciout_free: 42988c2ecf20Sopenharmony_ci free(args); 42998c2ecf20Sopenharmony_ci while (strings) { 43008c2ecf20Sopenharmony_ci string = strings; 43018c2ecf20Sopenharmony_ci strings = string->next; 43028c2ecf20Sopenharmony_ci free(string->str); 43038c2ecf20Sopenharmony_ci free(string); 43048c2ecf20Sopenharmony_ci } 43058c2ecf20Sopenharmony_ci 43068c2ecf20Sopenharmony_ci out: 43078c2ecf20Sopenharmony_ci /* TBD : handle return type here */ 43088c2ecf20Sopenharmony_ci return ret; 43098c2ecf20Sopenharmony_ci} 43108c2ecf20Sopenharmony_ci 43118c2ecf20Sopenharmony_cistatic void free_args(struct tep_print_arg *args) 43128c2ecf20Sopenharmony_ci{ 43138c2ecf20Sopenharmony_ci struct tep_print_arg *next; 43148c2ecf20Sopenharmony_ci 43158c2ecf20Sopenharmony_ci while (args) { 43168c2ecf20Sopenharmony_ci next = args->next; 43178c2ecf20Sopenharmony_ci 43188c2ecf20Sopenharmony_ci free_arg(args); 43198c2ecf20Sopenharmony_ci args = next; 43208c2ecf20Sopenharmony_ci } 43218c2ecf20Sopenharmony_ci} 43228c2ecf20Sopenharmony_ci 43238c2ecf20Sopenharmony_cistatic struct tep_print_arg *make_bprint_args(char *fmt, void *data, int size, struct tep_event *event) 43248c2ecf20Sopenharmony_ci{ 43258c2ecf20Sopenharmony_ci struct tep_handle *tep = event->tep; 43268c2ecf20Sopenharmony_ci struct tep_format_field *field, *ip_field; 43278c2ecf20Sopenharmony_ci struct tep_print_arg *args, *arg, **next; 43288c2ecf20Sopenharmony_ci unsigned long long ip, val; 43298c2ecf20Sopenharmony_ci char *ptr; 43308c2ecf20Sopenharmony_ci void *bptr; 43318c2ecf20Sopenharmony_ci int vsize = 0; 43328c2ecf20Sopenharmony_ci 43338c2ecf20Sopenharmony_ci field = tep->bprint_buf_field; 43348c2ecf20Sopenharmony_ci ip_field = tep->bprint_ip_field; 43358c2ecf20Sopenharmony_ci 43368c2ecf20Sopenharmony_ci if (!field) { 43378c2ecf20Sopenharmony_ci field = tep_find_field(event, "buf"); 43388c2ecf20Sopenharmony_ci if (!field) { 43398c2ecf20Sopenharmony_ci do_warning_event(event, "can't find buffer field for binary printk"); 43408c2ecf20Sopenharmony_ci return NULL; 43418c2ecf20Sopenharmony_ci } 43428c2ecf20Sopenharmony_ci ip_field = tep_find_field(event, "ip"); 43438c2ecf20Sopenharmony_ci if (!ip_field) { 43448c2ecf20Sopenharmony_ci do_warning_event(event, "can't find ip field for binary printk"); 43458c2ecf20Sopenharmony_ci return NULL; 43468c2ecf20Sopenharmony_ci } 43478c2ecf20Sopenharmony_ci tep->bprint_buf_field = field; 43488c2ecf20Sopenharmony_ci tep->bprint_ip_field = ip_field; 43498c2ecf20Sopenharmony_ci } 43508c2ecf20Sopenharmony_ci 43518c2ecf20Sopenharmony_ci ip = tep_read_number(tep, data + ip_field->offset, ip_field->size); 43528c2ecf20Sopenharmony_ci 43538c2ecf20Sopenharmony_ci /* 43548c2ecf20Sopenharmony_ci * The first arg is the IP pointer. 43558c2ecf20Sopenharmony_ci */ 43568c2ecf20Sopenharmony_ci args = alloc_arg(); 43578c2ecf20Sopenharmony_ci if (!args) { 43588c2ecf20Sopenharmony_ci do_warning_event(event, "%s(%d): not enough memory!", 43598c2ecf20Sopenharmony_ci __func__, __LINE__); 43608c2ecf20Sopenharmony_ci return NULL; 43618c2ecf20Sopenharmony_ci } 43628c2ecf20Sopenharmony_ci arg = args; 43638c2ecf20Sopenharmony_ci arg->next = NULL; 43648c2ecf20Sopenharmony_ci next = &arg->next; 43658c2ecf20Sopenharmony_ci 43668c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_ATOM; 43678c2ecf20Sopenharmony_ci 43688c2ecf20Sopenharmony_ci if (asprintf(&arg->atom.atom, "%lld", ip) < 0) 43698c2ecf20Sopenharmony_ci goto out_free; 43708c2ecf20Sopenharmony_ci 43718c2ecf20Sopenharmony_ci /* skip the first "%ps: " */ 43728c2ecf20Sopenharmony_ci for (ptr = fmt + 5, bptr = data + field->offset; 43738c2ecf20Sopenharmony_ci bptr < data + size && *ptr; ptr++) { 43748c2ecf20Sopenharmony_ci int ls = 0; 43758c2ecf20Sopenharmony_ci 43768c2ecf20Sopenharmony_ci if (*ptr == '%') { 43778c2ecf20Sopenharmony_ci process_again: 43788c2ecf20Sopenharmony_ci ptr++; 43798c2ecf20Sopenharmony_ci switch (*ptr) { 43808c2ecf20Sopenharmony_ci case '%': 43818c2ecf20Sopenharmony_ci break; 43828c2ecf20Sopenharmony_ci case 'l': 43838c2ecf20Sopenharmony_ci ls++; 43848c2ecf20Sopenharmony_ci goto process_again; 43858c2ecf20Sopenharmony_ci case 'L': 43868c2ecf20Sopenharmony_ci ls = 2; 43878c2ecf20Sopenharmony_ci goto process_again; 43888c2ecf20Sopenharmony_ci case '0' ... '9': 43898c2ecf20Sopenharmony_ci goto process_again; 43908c2ecf20Sopenharmony_ci case '.': 43918c2ecf20Sopenharmony_ci goto process_again; 43928c2ecf20Sopenharmony_ci case 'z': 43938c2ecf20Sopenharmony_ci case 'Z': 43948c2ecf20Sopenharmony_ci ls = 1; 43958c2ecf20Sopenharmony_ci goto process_again; 43968c2ecf20Sopenharmony_ci case 'p': 43978c2ecf20Sopenharmony_ci ls = 1; 43988c2ecf20Sopenharmony_ci if (isalnum(ptr[1])) { 43998c2ecf20Sopenharmony_ci ptr++; 44008c2ecf20Sopenharmony_ci /* Check for special pointers */ 44018c2ecf20Sopenharmony_ci switch (*ptr) { 44028c2ecf20Sopenharmony_ci case 's': 44038c2ecf20Sopenharmony_ci case 'S': 44048c2ecf20Sopenharmony_ci case 'x': 44058c2ecf20Sopenharmony_ci break; 44068c2ecf20Sopenharmony_ci case 'f': 44078c2ecf20Sopenharmony_ci case 'F': 44088c2ecf20Sopenharmony_ci /* 44098c2ecf20Sopenharmony_ci * Pre-5.5 kernels use %pf and 44108c2ecf20Sopenharmony_ci * %pF for printing symbols 44118c2ecf20Sopenharmony_ci * while kernels since 5.5 use 44128c2ecf20Sopenharmony_ci * %pfw for fwnodes. So check 44138c2ecf20Sopenharmony_ci * %p[fF] isn't followed by 'w'. 44148c2ecf20Sopenharmony_ci */ 44158c2ecf20Sopenharmony_ci if (ptr[1] != 'w') 44168c2ecf20Sopenharmony_ci break; 44178c2ecf20Sopenharmony_ci /* fall through */ 44188c2ecf20Sopenharmony_ci default: 44198c2ecf20Sopenharmony_ci /* 44208c2ecf20Sopenharmony_ci * Older kernels do not process 44218c2ecf20Sopenharmony_ci * dereferenced pointers. 44228c2ecf20Sopenharmony_ci * Only process if the pointer 44238c2ecf20Sopenharmony_ci * value is a printable. 44248c2ecf20Sopenharmony_ci */ 44258c2ecf20Sopenharmony_ci if (isprint(*(char *)bptr)) 44268c2ecf20Sopenharmony_ci goto process_string; 44278c2ecf20Sopenharmony_ci } 44288c2ecf20Sopenharmony_ci } 44298c2ecf20Sopenharmony_ci /* fall through */ 44308c2ecf20Sopenharmony_ci case 'd': 44318c2ecf20Sopenharmony_ci case 'u': 44328c2ecf20Sopenharmony_ci case 'i': 44338c2ecf20Sopenharmony_ci case 'x': 44348c2ecf20Sopenharmony_ci case 'X': 44358c2ecf20Sopenharmony_ci case 'o': 44368c2ecf20Sopenharmony_ci switch (ls) { 44378c2ecf20Sopenharmony_ci case 0: 44388c2ecf20Sopenharmony_ci vsize = 4; 44398c2ecf20Sopenharmony_ci break; 44408c2ecf20Sopenharmony_ci case 1: 44418c2ecf20Sopenharmony_ci vsize = tep->long_size; 44428c2ecf20Sopenharmony_ci break; 44438c2ecf20Sopenharmony_ci case 2: 44448c2ecf20Sopenharmony_ci vsize = 8; 44458c2ecf20Sopenharmony_ci break; 44468c2ecf20Sopenharmony_ci default: 44478c2ecf20Sopenharmony_ci vsize = ls; /* ? */ 44488c2ecf20Sopenharmony_ci break; 44498c2ecf20Sopenharmony_ci } 44508c2ecf20Sopenharmony_ci /* fall through */ 44518c2ecf20Sopenharmony_ci case '*': 44528c2ecf20Sopenharmony_ci if (*ptr == '*') 44538c2ecf20Sopenharmony_ci vsize = 4; 44548c2ecf20Sopenharmony_ci 44558c2ecf20Sopenharmony_ci /* the pointers are always 4 bytes aligned */ 44568c2ecf20Sopenharmony_ci bptr = (void *)(((unsigned long)bptr + 3) & 44578c2ecf20Sopenharmony_ci ~3); 44588c2ecf20Sopenharmony_ci val = tep_read_number(tep, bptr, vsize); 44598c2ecf20Sopenharmony_ci bptr += vsize; 44608c2ecf20Sopenharmony_ci arg = alloc_arg(); 44618c2ecf20Sopenharmony_ci if (!arg) { 44628c2ecf20Sopenharmony_ci do_warning_event(event, "%s(%d): not enough memory!", 44638c2ecf20Sopenharmony_ci __func__, __LINE__); 44648c2ecf20Sopenharmony_ci goto out_free; 44658c2ecf20Sopenharmony_ci } 44668c2ecf20Sopenharmony_ci arg->next = NULL; 44678c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_ATOM; 44688c2ecf20Sopenharmony_ci if (asprintf(&arg->atom.atom, "%lld", val) < 0) { 44698c2ecf20Sopenharmony_ci free(arg); 44708c2ecf20Sopenharmony_ci goto out_free; 44718c2ecf20Sopenharmony_ci } 44728c2ecf20Sopenharmony_ci *next = arg; 44738c2ecf20Sopenharmony_ci next = &arg->next; 44748c2ecf20Sopenharmony_ci /* 44758c2ecf20Sopenharmony_ci * The '*' case means that an arg is used as the length. 44768c2ecf20Sopenharmony_ci * We need to continue to figure out for what. 44778c2ecf20Sopenharmony_ci */ 44788c2ecf20Sopenharmony_ci if (*ptr == '*') 44798c2ecf20Sopenharmony_ci goto process_again; 44808c2ecf20Sopenharmony_ci 44818c2ecf20Sopenharmony_ci break; 44828c2ecf20Sopenharmony_ci case 's': 44838c2ecf20Sopenharmony_ci process_string: 44848c2ecf20Sopenharmony_ci arg = alloc_arg(); 44858c2ecf20Sopenharmony_ci if (!arg) { 44868c2ecf20Sopenharmony_ci do_warning_event(event, "%s(%d): not enough memory!", 44878c2ecf20Sopenharmony_ci __func__, __LINE__); 44888c2ecf20Sopenharmony_ci goto out_free; 44898c2ecf20Sopenharmony_ci } 44908c2ecf20Sopenharmony_ci arg->next = NULL; 44918c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_BSTRING; 44928c2ecf20Sopenharmony_ci arg->string.string = strdup(bptr); 44938c2ecf20Sopenharmony_ci if (!arg->string.string) 44948c2ecf20Sopenharmony_ci goto out_free; 44958c2ecf20Sopenharmony_ci bptr += strlen(bptr) + 1; 44968c2ecf20Sopenharmony_ci *next = arg; 44978c2ecf20Sopenharmony_ci next = &arg->next; 44988c2ecf20Sopenharmony_ci default: 44998c2ecf20Sopenharmony_ci break; 45008c2ecf20Sopenharmony_ci } 45018c2ecf20Sopenharmony_ci } 45028c2ecf20Sopenharmony_ci } 45038c2ecf20Sopenharmony_ci 45048c2ecf20Sopenharmony_ci return args; 45058c2ecf20Sopenharmony_ci 45068c2ecf20Sopenharmony_ciout_free: 45078c2ecf20Sopenharmony_ci free_args(args); 45088c2ecf20Sopenharmony_ci return NULL; 45098c2ecf20Sopenharmony_ci} 45108c2ecf20Sopenharmony_ci 45118c2ecf20Sopenharmony_cistatic char * 45128c2ecf20Sopenharmony_ciget_bprint_format(void *data, int size __maybe_unused, 45138c2ecf20Sopenharmony_ci struct tep_event *event) 45148c2ecf20Sopenharmony_ci{ 45158c2ecf20Sopenharmony_ci struct tep_handle *tep = event->tep; 45168c2ecf20Sopenharmony_ci unsigned long long addr; 45178c2ecf20Sopenharmony_ci struct tep_format_field *field; 45188c2ecf20Sopenharmony_ci struct printk_map *printk; 45198c2ecf20Sopenharmony_ci char *format; 45208c2ecf20Sopenharmony_ci 45218c2ecf20Sopenharmony_ci field = tep->bprint_fmt_field; 45228c2ecf20Sopenharmony_ci 45238c2ecf20Sopenharmony_ci if (!field) { 45248c2ecf20Sopenharmony_ci field = tep_find_field(event, "fmt"); 45258c2ecf20Sopenharmony_ci if (!field) { 45268c2ecf20Sopenharmony_ci do_warning_event(event, "can't find format field for binary printk"); 45278c2ecf20Sopenharmony_ci return NULL; 45288c2ecf20Sopenharmony_ci } 45298c2ecf20Sopenharmony_ci tep->bprint_fmt_field = field; 45308c2ecf20Sopenharmony_ci } 45318c2ecf20Sopenharmony_ci 45328c2ecf20Sopenharmony_ci addr = tep_read_number(tep, data + field->offset, field->size); 45338c2ecf20Sopenharmony_ci 45348c2ecf20Sopenharmony_ci printk = find_printk(tep, addr); 45358c2ecf20Sopenharmony_ci if (!printk) { 45368c2ecf20Sopenharmony_ci if (asprintf(&format, "%%ps: (NO FORMAT FOUND at %llx)\n", addr) < 0) 45378c2ecf20Sopenharmony_ci return NULL; 45388c2ecf20Sopenharmony_ci return format; 45398c2ecf20Sopenharmony_ci } 45408c2ecf20Sopenharmony_ci 45418c2ecf20Sopenharmony_ci if (asprintf(&format, "%s: %s", "%ps", printk->printk) < 0) 45428c2ecf20Sopenharmony_ci return NULL; 45438c2ecf20Sopenharmony_ci 45448c2ecf20Sopenharmony_ci return format; 45458c2ecf20Sopenharmony_ci} 45468c2ecf20Sopenharmony_ci 45478c2ecf20Sopenharmony_cistatic int print_mac_arg(struct trace_seq *s, const char *format, 45488c2ecf20Sopenharmony_ci void *data, int size, struct tep_event *event, 45498c2ecf20Sopenharmony_ci struct tep_print_arg *arg) 45508c2ecf20Sopenharmony_ci{ 45518c2ecf20Sopenharmony_ci const char *fmt = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"; 45528c2ecf20Sopenharmony_ci bool reverse = false; 45538c2ecf20Sopenharmony_ci unsigned char *buf; 45548c2ecf20Sopenharmony_ci int ret = 0; 45558c2ecf20Sopenharmony_ci 45568c2ecf20Sopenharmony_ci if (arg->type == TEP_PRINT_FUNC) { 45578c2ecf20Sopenharmony_ci process_defined_func(s, data, size, event, arg); 45588c2ecf20Sopenharmony_ci return 0; 45598c2ecf20Sopenharmony_ci } 45608c2ecf20Sopenharmony_ci 45618c2ecf20Sopenharmony_ci if (arg->type != TEP_PRINT_FIELD) { 45628c2ecf20Sopenharmony_ci trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", 45638c2ecf20Sopenharmony_ci arg->type); 45648c2ecf20Sopenharmony_ci return 0; 45658c2ecf20Sopenharmony_ci } 45668c2ecf20Sopenharmony_ci 45678c2ecf20Sopenharmony_ci if (format[0] == 'm') { 45688c2ecf20Sopenharmony_ci fmt = "%.2x%.2x%.2x%.2x%.2x%.2x"; 45698c2ecf20Sopenharmony_ci } else if (format[0] == 'M' && format[1] == 'F') { 45708c2ecf20Sopenharmony_ci fmt = "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x"; 45718c2ecf20Sopenharmony_ci ret++; 45728c2ecf20Sopenharmony_ci } 45738c2ecf20Sopenharmony_ci if (format[1] == 'R') { 45748c2ecf20Sopenharmony_ci reverse = true; 45758c2ecf20Sopenharmony_ci ret++; 45768c2ecf20Sopenharmony_ci } 45778c2ecf20Sopenharmony_ci 45788c2ecf20Sopenharmony_ci if (!arg->field.field) { 45798c2ecf20Sopenharmony_ci arg->field.field = 45808c2ecf20Sopenharmony_ci tep_find_any_field(event, arg->field.name); 45818c2ecf20Sopenharmony_ci if (!arg->field.field) { 45828c2ecf20Sopenharmony_ci do_warning_event(event, "%s: field %s not found", 45838c2ecf20Sopenharmony_ci __func__, arg->field.name); 45848c2ecf20Sopenharmony_ci return ret; 45858c2ecf20Sopenharmony_ci } 45868c2ecf20Sopenharmony_ci } 45878c2ecf20Sopenharmony_ci if (arg->field.field->size != 6) { 45888c2ecf20Sopenharmony_ci trace_seq_printf(s, "INVALIDMAC"); 45898c2ecf20Sopenharmony_ci return ret; 45908c2ecf20Sopenharmony_ci } 45918c2ecf20Sopenharmony_ci 45928c2ecf20Sopenharmony_ci buf = data + arg->field.field->offset; 45938c2ecf20Sopenharmony_ci if (reverse) 45948c2ecf20Sopenharmony_ci trace_seq_printf(s, fmt, buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]); 45958c2ecf20Sopenharmony_ci else 45968c2ecf20Sopenharmony_ci trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); 45978c2ecf20Sopenharmony_ci 45988c2ecf20Sopenharmony_ci return ret; 45998c2ecf20Sopenharmony_ci} 46008c2ecf20Sopenharmony_ci 46018c2ecf20Sopenharmony_cistatic int parse_ip4_print_args(struct tep_handle *tep, 46028c2ecf20Sopenharmony_ci const char *ptr, bool *reverse) 46038c2ecf20Sopenharmony_ci{ 46048c2ecf20Sopenharmony_ci int ret = 0; 46058c2ecf20Sopenharmony_ci 46068c2ecf20Sopenharmony_ci *reverse = false; 46078c2ecf20Sopenharmony_ci 46088c2ecf20Sopenharmony_ci /* hnbl */ 46098c2ecf20Sopenharmony_ci switch (*ptr) { 46108c2ecf20Sopenharmony_ci case 'h': 46118c2ecf20Sopenharmony_ci if (tep->file_bigendian) 46128c2ecf20Sopenharmony_ci *reverse = false; 46138c2ecf20Sopenharmony_ci else 46148c2ecf20Sopenharmony_ci *reverse = true; 46158c2ecf20Sopenharmony_ci ret++; 46168c2ecf20Sopenharmony_ci break; 46178c2ecf20Sopenharmony_ci case 'l': 46188c2ecf20Sopenharmony_ci *reverse = true; 46198c2ecf20Sopenharmony_ci ret++; 46208c2ecf20Sopenharmony_ci break; 46218c2ecf20Sopenharmony_ci case 'n': 46228c2ecf20Sopenharmony_ci case 'b': 46238c2ecf20Sopenharmony_ci ret++; 46248c2ecf20Sopenharmony_ci /* fall through */ 46258c2ecf20Sopenharmony_ci default: 46268c2ecf20Sopenharmony_ci *reverse = false; 46278c2ecf20Sopenharmony_ci break; 46288c2ecf20Sopenharmony_ci } 46298c2ecf20Sopenharmony_ci 46308c2ecf20Sopenharmony_ci return ret; 46318c2ecf20Sopenharmony_ci} 46328c2ecf20Sopenharmony_ci 46338c2ecf20Sopenharmony_cistatic void print_ip4_addr(struct trace_seq *s, char i, bool reverse, unsigned char *buf) 46348c2ecf20Sopenharmony_ci{ 46358c2ecf20Sopenharmony_ci const char *fmt; 46368c2ecf20Sopenharmony_ci 46378c2ecf20Sopenharmony_ci if (i == 'i') 46388c2ecf20Sopenharmony_ci fmt = "%03d.%03d.%03d.%03d"; 46398c2ecf20Sopenharmony_ci else 46408c2ecf20Sopenharmony_ci fmt = "%d.%d.%d.%d"; 46418c2ecf20Sopenharmony_ci 46428c2ecf20Sopenharmony_ci if (reverse) 46438c2ecf20Sopenharmony_ci trace_seq_printf(s, fmt, buf[3], buf[2], buf[1], buf[0]); 46448c2ecf20Sopenharmony_ci else 46458c2ecf20Sopenharmony_ci trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3]); 46468c2ecf20Sopenharmony_ci 46478c2ecf20Sopenharmony_ci} 46488c2ecf20Sopenharmony_ci 46498c2ecf20Sopenharmony_cistatic inline bool ipv6_addr_v4mapped(const struct in6_addr *a) 46508c2ecf20Sopenharmony_ci{ 46518c2ecf20Sopenharmony_ci return ((unsigned long)(a->s6_addr32[0] | a->s6_addr32[1]) | 46528c2ecf20Sopenharmony_ci (unsigned long)(a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0UL; 46538c2ecf20Sopenharmony_ci} 46548c2ecf20Sopenharmony_ci 46558c2ecf20Sopenharmony_cistatic inline bool ipv6_addr_is_isatap(const struct in6_addr *addr) 46568c2ecf20Sopenharmony_ci{ 46578c2ecf20Sopenharmony_ci return (addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE); 46588c2ecf20Sopenharmony_ci} 46598c2ecf20Sopenharmony_ci 46608c2ecf20Sopenharmony_cistatic void print_ip6c_addr(struct trace_seq *s, unsigned char *addr) 46618c2ecf20Sopenharmony_ci{ 46628c2ecf20Sopenharmony_ci int i, j, range; 46638c2ecf20Sopenharmony_ci unsigned char zerolength[8]; 46648c2ecf20Sopenharmony_ci int longest = 1; 46658c2ecf20Sopenharmony_ci int colonpos = -1; 46668c2ecf20Sopenharmony_ci uint16_t word; 46678c2ecf20Sopenharmony_ci uint8_t hi, lo; 46688c2ecf20Sopenharmony_ci bool needcolon = false; 46698c2ecf20Sopenharmony_ci bool useIPv4; 46708c2ecf20Sopenharmony_ci struct in6_addr in6; 46718c2ecf20Sopenharmony_ci 46728c2ecf20Sopenharmony_ci memcpy(&in6, addr, sizeof(struct in6_addr)); 46738c2ecf20Sopenharmony_ci 46748c2ecf20Sopenharmony_ci useIPv4 = ipv6_addr_v4mapped(&in6) || ipv6_addr_is_isatap(&in6); 46758c2ecf20Sopenharmony_ci 46768c2ecf20Sopenharmony_ci memset(zerolength, 0, sizeof(zerolength)); 46778c2ecf20Sopenharmony_ci 46788c2ecf20Sopenharmony_ci if (useIPv4) 46798c2ecf20Sopenharmony_ci range = 6; 46808c2ecf20Sopenharmony_ci else 46818c2ecf20Sopenharmony_ci range = 8; 46828c2ecf20Sopenharmony_ci 46838c2ecf20Sopenharmony_ci /* find position of longest 0 run */ 46848c2ecf20Sopenharmony_ci for (i = 0; i < range; i++) { 46858c2ecf20Sopenharmony_ci for (j = i; j < range; j++) { 46868c2ecf20Sopenharmony_ci if (in6.s6_addr16[j] != 0) 46878c2ecf20Sopenharmony_ci break; 46888c2ecf20Sopenharmony_ci zerolength[i]++; 46898c2ecf20Sopenharmony_ci } 46908c2ecf20Sopenharmony_ci } 46918c2ecf20Sopenharmony_ci for (i = 0; i < range; i++) { 46928c2ecf20Sopenharmony_ci if (zerolength[i] > longest) { 46938c2ecf20Sopenharmony_ci longest = zerolength[i]; 46948c2ecf20Sopenharmony_ci colonpos = i; 46958c2ecf20Sopenharmony_ci } 46968c2ecf20Sopenharmony_ci } 46978c2ecf20Sopenharmony_ci if (longest == 1) /* don't compress a single 0 */ 46988c2ecf20Sopenharmony_ci colonpos = -1; 46998c2ecf20Sopenharmony_ci 47008c2ecf20Sopenharmony_ci /* emit address */ 47018c2ecf20Sopenharmony_ci for (i = 0; i < range; i++) { 47028c2ecf20Sopenharmony_ci if (i == colonpos) { 47038c2ecf20Sopenharmony_ci if (needcolon || i == 0) 47048c2ecf20Sopenharmony_ci trace_seq_printf(s, ":"); 47058c2ecf20Sopenharmony_ci trace_seq_printf(s, ":"); 47068c2ecf20Sopenharmony_ci needcolon = false; 47078c2ecf20Sopenharmony_ci i += longest - 1; 47088c2ecf20Sopenharmony_ci continue; 47098c2ecf20Sopenharmony_ci } 47108c2ecf20Sopenharmony_ci if (needcolon) { 47118c2ecf20Sopenharmony_ci trace_seq_printf(s, ":"); 47128c2ecf20Sopenharmony_ci needcolon = false; 47138c2ecf20Sopenharmony_ci } 47148c2ecf20Sopenharmony_ci /* hex u16 without leading 0s */ 47158c2ecf20Sopenharmony_ci word = ntohs(in6.s6_addr16[i]); 47168c2ecf20Sopenharmony_ci hi = word >> 8; 47178c2ecf20Sopenharmony_ci lo = word & 0xff; 47188c2ecf20Sopenharmony_ci if (hi) 47198c2ecf20Sopenharmony_ci trace_seq_printf(s, "%x%02x", hi, lo); 47208c2ecf20Sopenharmony_ci else 47218c2ecf20Sopenharmony_ci trace_seq_printf(s, "%x", lo); 47228c2ecf20Sopenharmony_ci 47238c2ecf20Sopenharmony_ci needcolon = true; 47248c2ecf20Sopenharmony_ci } 47258c2ecf20Sopenharmony_ci 47268c2ecf20Sopenharmony_ci if (useIPv4) { 47278c2ecf20Sopenharmony_ci if (needcolon) 47288c2ecf20Sopenharmony_ci trace_seq_printf(s, ":"); 47298c2ecf20Sopenharmony_ci print_ip4_addr(s, 'I', false, &in6.s6_addr[12]); 47308c2ecf20Sopenharmony_ci } 47318c2ecf20Sopenharmony_ci 47328c2ecf20Sopenharmony_ci return; 47338c2ecf20Sopenharmony_ci} 47348c2ecf20Sopenharmony_ci 47358c2ecf20Sopenharmony_cistatic void print_ip6_addr(struct trace_seq *s, char i, unsigned char *buf) 47368c2ecf20Sopenharmony_ci{ 47378c2ecf20Sopenharmony_ci int j; 47388c2ecf20Sopenharmony_ci 47398c2ecf20Sopenharmony_ci for (j = 0; j < 16; j += 2) { 47408c2ecf20Sopenharmony_ci trace_seq_printf(s, "%02x%02x", buf[j], buf[j+1]); 47418c2ecf20Sopenharmony_ci if (i == 'I' && j < 14) 47428c2ecf20Sopenharmony_ci trace_seq_printf(s, ":"); 47438c2ecf20Sopenharmony_ci } 47448c2ecf20Sopenharmony_ci} 47458c2ecf20Sopenharmony_ci 47468c2ecf20Sopenharmony_ci/* 47478c2ecf20Sopenharmony_ci * %pi4 print an IPv4 address with leading zeros 47488c2ecf20Sopenharmony_ci * %pI4 print an IPv4 address without leading zeros 47498c2ecf20Sopenharmony_ci * %pi6 print an IPv6 address without colons 47508c2ecf20Sopenharmony_ci * %pI6 print an IPv6 address with colons 47518c2ecf20Sopenharmony_ci * %pI6c print an IPv6 address in compressed form with colons 47528c2ecf20Sopenharmony_ci * %pISpc print an IP address based on sockaddr; p adds port. 47538c2ecf20Sopenharmony_ci */ 47548c2ecf20Sopenharmony_cistatic int print_ipv4_arg(struct trace_seq *s, const char *ptr, char i, 47558c2ecf20Sopenharmony_ci void *data, int size, struct tep_event *event, 47568c2ecf20Sopenharmony_ci struct tep_print_arg *arg) 47578c2ecf20Sopenharmony_ci{ 47588c2ecf20Sopenharmony_ci bool reverse = false; 47598c2ecf20Sopenharmony_ci unsigned char *buf; 47608c2ecf20Sopenharmony_ci int ret; 47618c2ecf20Sopenharmony_ci 47628c2ecf20Sopenharmony_ci ret = parse_ip4_print_args(event->tep, ptr, &reverse); 47638c2ecf20Sopenharmony_ci 47648c2ecf20Sopenharmony_ci if (arg->type == TEP_PRINT_FUNC) { 47658c2ecf20Sopenharmony_ci process_defined_func(s, data, size, event, arg); 47668c2ecf20Sopenharmony_ci return ret; 47678c2ecf20Sopenharmony_ci } 47688c2ecf20Sopenharmony_ci 47698c2ecf20Sopenharmony_ci if (arg->type != TEP_PRINT_FIELD) { 47708c2ecf20Sopenharmony_ci trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type); 47718c2ecf20Sopenharmony_ci return ret; 47728c2ecf20Sopenharmony_ci } 47738c2ecf20Sopenharmony_ci 47748c2ecf20Sopenharmony_ci if (!arg->field.field) { 47758c2ecf20Sopenharmony_ci arg->field.field = 47768c2ecf20Sopenharmony_ci tep_find_any_field(event, arg->field.name); 47778c2ecf20Sopenharmony_ci if (!arg->field.field) { 47788c2ecf20Sopenharmony_ci do_warning("%s: field %s not found", 47798c2ecf20Sopenharmony_ci __func__, arg->field.name); 47808c2ecf20Sopenharmony_ci return ret; 47818c2ecf20Sopenharmony_ci } 47828c2ecf20Sopenharmony_ci } 47838c2ecf20Sopenharmony_ci 47848c2ecf20Sopenharmony_ci buf = data + arg->field.field->offset; 47858c2ecf20Sopenharmony_ci 47868c2ecf20Sopenharmony_ci if (arg->field.field->size != 4) { 47878c2ecf20Sopenharmony_ci trace_seq_printf(s, "INVALIDIPv4"); 47888c2ecf20Sopenharmony_ci return ret; 47898c2ecf20Sopenharmony_ci } 47908c2ecf20Sopenharmony_ci 47918c2ecf20Sopenharmony_ci print_ip4_addr(s, i, reverse, buf); 47928c2ecf20Sopenharmony_ci return ret; 47938c2ecf20Sopenharmony_ci 47948c2ecf20Sopenharmony_ci} 47958c2ecf20Sopenharmony_ci 47968c2ecf20Sopenharmony_cistatic int print_ipv6_arg(struct trace_seq *s, const char *ptr, char i, 47978c2ecf20Sopenharmony_ci void *data, int size, struct tep_event *event, 47988c2ecf20Sopenharmony_ci struct tep_print_arg *arg) 47998c2ecf20Sopenharmony_ci{ 48008c2ecf20Sopenharmony_ci char have_c = 0; 48018c2ecf20Sopenharmony_ci unsigned char *buf; 48028c2ecf20Sopenharmony_ci int rc = 0; 48038c2ecf20Sopenharmony_ci 48048c2ecf20Sopenharmony_ci /* pI6c */ 48058c2ecf20Sopenharmony_ci if (i == 'I' && *ptr == 'c') { 48068c2ecf20Sopenharmony_ci have_c = 1; 48078c2ecf20Sopenharmony_ci ptr++; 48088c2ecf20Sopenharmony_ci rc++; 48098c2ecf20Sopenharmony_ci } 48108c2ecf20Sopenharmony_ci 48118c2ecf20Sopenharmony_ci if (arg->type == TEP_PRINT_FUNC) { 48128c2ecf20Sopenharmony_ci process_defined_func(s, data, size, event, arg); 48138c2ecf20Sopenharmony_ci return rc; 48148c2ecf20Sopenharmony_ci } 48158c2ecf20Sopenharmony_ci 48168c2ecf20Sopenharmony_ci if (arg->type != TEP_PRINT_FIELD) { 48178c2ecf20Sopenharmony_ci trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type); 48188c2ecf20Sopenharmony_ci return rc; 48198c2ecf20Sopenharmony_ci } 48208c2ecf20Sopenharmony_ci 48218c2ecf20Sopenharmony_ci if (!arg->field.field) { 48228c2ecf20Sopenharmony_ci arg->field.field = 48238c2ecf20Sopenharmony_ci tep_find_any_field(event, arg->field.name); 48248c2ecf20Sopenharmony_ci if (!arg->field.field) { 48258c2ecf20Sopenharmony_ci do_warning("%s: field %s not found", 48268c2ecf20Sopenharmony_ci __func__, arg->field.name); 48278c2ecf20Sopenharmony_ci return rc; 48288c2ecf20Sopenharmony_ci } 48298c2ecf20Sopenharmony_ci } 48308c2ecf20Sopenharmony_ci 48318c2ecf20Sopenharmony_ci buf = data + arg->field.field->offset; 48328c2ecf20Sopenharmony_ci 48338c2ecf20Sopenharmony_ci if (arg->field.field->size != 16) { 48348c2ecf20Sopenharmony_ci trace_seq_printf(s, "INVALIDIPv6"); 48358c2ecf20Sopenharmony_ci return rc; 48368c2ecf20Sopenharmony_ci } 48378c2ecf20Sopenharmony_ci 48388c2ecf20Sopenharmony_ci if (have_c) 48398c2ecf20Sopenharmony_ci print_ip6c_addr(s, buf); 48408c2ecf20Sopenharmony_ci else 48418c2ecf20Sopenharmony_ci print_ip6_addr(s, i, buf); 48428c2ecf20Sopenharmony_ci 48438c2ecf20Sopenharmony_ci return rc; 48448c2ecf20Sopenharmony_ci} 48458c2ecf20Sopenharmony_ci 48468c2ecf20Sopenharmony_cistatic int print_ipsa_arg(struct trace_seq *s, const char *ptr, char i, 48478c2ecf20Sopenharmony_ci void *data, int size, struct tep_event *event, 48488c2ecf20Sopenharmony_ci struct tep_print_arg *arg) 48498c2ecf20Sopenharmony_ci{ 48508c2ecf20Sopenharmony_ci char have_c = 0, have_p = 0; 48518c2ecf20Sopenharmony_ci unsigned char *buf; 48528c2ecf20Sopenharmony_ci struct sockaddr_storage *sa; 48538c2ecf20Sopenharmony_ci bool reverse = false; 48548c2ecf20Sopenharmony_ci int rc = 0; 48558c2ecf20Sopenharmony_ci int ret; 48568c2ecf20Sopenharmony_ci 48578c2ecf20Sopenharmony_ci /* pISpc */ 48588c2ecf20Sopenharmony_ci if (i == 'I') { 48598c2ecf20Sopenharmony_ci if (*ptr == 'p') { 48608c2ecf20Sopenharmony_ci have_p = 1; 48618c2ecf20Sopenharmony_ci ptr++; 48628c2ecf20Sopenharmony_ci rc++; 48638c2ecf20Sopenharmony_ci } 48648c2ecf20Sopenharmony_ci if (*ptr == 'c') { 48658c2ecf20Sopenharmony_ci have_c = 1; 48668c2ecf20Sopenharmony_ci ptr++; 48678c2ecf20Sopenharmony_ci rc++; 48688c2ecf20Sopenharmony_ci } 48698c2ecf20Sopenharmony_ci } 48708c2ecf20Sopenharmony_ci ret = parse_ip4_print_args(event->tep, ptr, &reverse); 48718c2ecf20Sopenharmony_ci ptr += ret; 48728c2ecf20Sopenharmony_ci rc += ret; 48738c2ecf20Sopenharmony_ci 48748c2ecf20Sopenharmony_ci if (arg->type == TEP_PRINT_FUNC) { 48758c2ecf20Sopenharmony_ci process_defined_func(s, data, size, event, arg); 48768c2ecf20Sopenharmony_ci return rc; 48778c2ecf20Sopenharmony_ci } 48788c2ecf20Sopenharmony_ci 48798c2ecf20Sopenharmony_ci if (arg->type != TEP_PRINT_FIELD) { 48808c2ecf20Sopenharmony_ci trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type); 48818c2ecf20Sopenharmony_ci return rc; 48828c2ecf20Sopenharmony_ci } 48838c2ecf20Sopenharmony_ci 48848c2ecf20Sopenharmony_ci if (!arg->field.field) { 48858c2ecf20Sopenharmony_ci arg->field.field = 48868c2ecf20Sopenharmony_ci tep_find_any_field(event, arg->field.name); 48878c2ecf20Sopenharmony_ci if (!arg->field.field) { 48888c2ecf20Sopenharmony_ci do_warning("%s: field %s not found", 48898c2ecf20Sopenharmony_ci __func__, arg->field.name); 48908c2ecf20Sopenharmony_ci return rc; 48918c2ecf20Sopenharmony_ci } 48928c2ecf20Sopenharmony_ci } 48938c2ecf20Sopenharmony_ci 48948c2ecf20Sopenharmony_ci sa = (struct sockaddr_storage *) (data + arg->field.field->offset); 48958c2ecf20Sopenharmony_ci 48968c2ecf20Sopenharmony_ci if (sa->ss_family == AF_INET) { 48978c2ecf20Sopenharmony_ci struct sockaddr_in *sa4 = (struct sockaddr_in *) sa; 48988c2ecf20Sopenharmony_ci 48998c2ecf20Sopenharmony_ci if (arg->field.field->size < sizeof(struct sockaddr_in)) { 49008c2ecf20Sopenharmony_ci trace_seq_printf(s, "INVALIDIPv4"); 49018c2ecf20Sopenharmony_ci return rc; 49028c2ecf20Sopenharmony_ci } 49038c2ecf20Sopenharmony_ci 49048c2ecf20Sopenharmony_ci print_ip4_addr(s, i, reverse, (unsigned char *) &sa4->sin_addr); 49058c2ecf20Sopenharmony_ci if (have_p) 49068c2ecf20Sopenharmony_ci trace_seq_printf(s, ":%d", ntohs(sa4->sin_port)); 49078c2ecf20Sopenharmony_ci 49088c2ecf20Sopenharmony_ci 49098c2ecf20Sopenharmony_ci } else if (sa->ss_family == AF_INET6) { 49108c2ecf20Sopenharmony_ci struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa; 49118c2ecf20Sopenharmony_ci 49128c2ecf20Sopenharmony_ci if (arg->field.field->size < sizeof(struct sockaddr_in6)) { 49138c2ecf20Sopenharmony_ci trace_seq_printf(s, "INVALIDIPv6"); 49148c2ecf20Sopenharmony_ci return rc; 49158c2ecf20Sopenharmony_ci } 49168c2ecf20Sopenharmony_ci 49178c2ecf20Sopenharmony_ci if (have_p) 49188c2ecf20Sopenharmony_ci trace_seq_printf(s, "["); 49198c2ecf20Sopenharmony_ci 49208c2ecf20Sopenharmony_ci buf = (unsigned char *) &sa6->sin6_addr; 49218c2ecf20Sopenharmony_ci if (have_c) 49228c2ecf20Sopenharmony_ci print_ip6c_addr(s, buf); 49238c2ecf20Sopenharmony_ci else 49248c2ecf20Sopenharmony_ci print_ip6_addr(s, i, buf); 49258c2ecf20Sopenharmony_ci 49268c2ecf20Sopenharmony_ci if (have_p) 49278c2ecf20Sopenharmony_ci trace_seq_printf(s, "]:%d", ntohs(sa6->sin6_port)); 49288c2ecf20Sopenharmony_ci } 49298c2ecf20Sopenharmony_ci 49308c2ecf20Sopenharmony_ci return rc; 49318c2ecf20Sopenharmony_ci} 49328c2ecf20Sopenharmony_ci 49338c2ecf20Sopenharmony_cistatic int print_ip_arg(struct trace_seq *s, const char *ptr, 49348c2ecf20Sopenharmony_ci void *data, int size, struct tep_event *event, 49358c2ecf20Sopenharmony_ci struct tep_print_arg *arg) 49368c2ecf20Sopenharmony_ci{ 49378c2ecf20Sopenharmony_ci char i = *ptr; /* 'i' or 'I' */ 49388c2ecf20Sopenharmony_ci int rc = 1; 49398c2ecf20Sopenharmony_ci 49408c2ecf20Sopenharmony_ci /* IP version */ 49418c2ecf20Sopenharmony_ci ptr++; 49428c2ecf20Sopenharmony_ci 49438c2ecf20Sopenharmony_ci switch (*ptr) { 49448c2ecf20Sopenharmony_ci case '4': 49458c2ecf20Sopenharmony_ci rc += print_ipv4_arg(s, ptr + 1, i, data, size, event, arg); 49468c2ecf20Sopenharmony_ci break; 49478c2ecf20Sopenharmony_ci case '6': 49488c2ecf20Sopenharmony_ci rc += print_ipv6_arg(s, ptr + 1, i, data, size, event, arg); 49498c2ecf20Sopenharmony_ci break; 49508c2ecf20Sopenharmony_ci case 'S': 49518c2ecf20Sopenharmony_ci rc += print_ipsa_arg(s, ptr + 1, i, data, size, event, arg); 49528c2ecf20Sopenharmony_ci break; 49538c2ecf20Sopenharmony_ci default: 49548c2ecf20Sopenharmony_ci return 0; 49558c2ecf20Sopenharmony_ci } 49568c2ecf20Sopenharmony_ci 49578c2ecf20Sopenharmony_ci return rc; 49588c2ecf20Sopenharmony_ci} 49598c2ecf20Sopenharmony_ci 49608c2ecf20Sopenharmony_cistatic const int guid_index[16] = {3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15}; 49618c2ecf20Sopenharmony_cistatic const int uuid_index[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; 49628c2ecf20Sopenharmony_ci 49638c2ecf20Sopenharmony_cistatic int print_uuid_arg(struct trace_seq *s, const char *ptr, 49648c2ecf20Sopenharmony_ci void *data, int size, struct tep_event *event, 49658c2ecf20Sopenharmony_ci struct tep_print_arg *arg) 49668c2ecf20Sopenharmony_ci{ 49678c2ecf20Sopenharmony_ci const int *index = uuid_index; 49688c2ecf20Sopenharmony_ci char *format = "%02x"; 49698c2ecf20Sopenharmony_ci int ret = 0; 49708c2ecf20Sopenharmony_ci char *buf; 49718c2ecf20Sopenharmony_ci int i; 49728c2ecf20Sopenharmony_ci 49738c2ecf20Sopenharmony_ci switch (*(ptr + 1)) { 49748c2ecf20Sopenharmony_ci case 'L': 49758c2ecf20Sopenharmony_ci format = "%02X"; 49768c2ecf20Sopenharmony_ci /* fall through */ 49778c2ecf20Sopenharmony_ci case 'l': 49788c2ecf20Sopenharmony_ci index = guid_index; 49798c2ecf20Sopenharmony_ci ret++; 49808c2ecf20Sopenharmony_ci break; 49818c2ecf20Sopenharmony_ci case 'B': 49828c2ecf20Sopenharmony_ci format = "%02X"; 49838c2ecf20Sopenharmony_ci /* fall through */ 49848c2ecf20Sopenharmony_ci case 'b': 49858c2ecf20Sopenharmony_ci ret++; 49868c2ecf20Sopenharmony_ci break; 49878c2ecf20Sopenharmony_ci } 49888c2ecf20Sopenharmony_ci 49898c2ecf20Sopenharmony_ci if (arg->type == TEP_PRINT_FUNC) { 49908c2ecf20Sopenharmony_ci process_defined_func(s, data, size, event, arg); 49918c2ecf20Sopenharmony_ci return ret; 49928c2ecf20Sopenharmony_ci } 49938c2ecf20Sopenharmony_ci 49948c2ecf20Sopenharmony_ci if (arg->type != TEP_PRINT_FIELD) { 49958c2ecf20Sopenharmony_ci trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type); 49968c2ecf20Sopenharmony_ci return ret; 49978c2ecf20Sopenharmony_ci } 49988c2ecf20Sopenharmony_ci 49998c2ecf20Sopenharmony_ci if (!arg->field.field) { 50008c2ecf20Sopenharmony_ci arg->field.field = 50018c2ecf20Sopenharmony_ci tep_find_any_field(event, arg->field.name); 50028c2ecf20Sopenharmony_ci if (!arg->field.field) { 50038c2ecf20Sopenharmony_ci do_warning("%s: field %s not found", 50048c2ecf20Sopenharmony_ci __func__, arg->field.name); 50058c2ecf20Sopenharmony_ci return ret; 50068c2ecf20Sopenharmony_ci } 50078c2ecf20Sopenharmony_ci } 50088c2ecf20Sopenharmony_ci 50098c2ecf20Sopenharmony_ci if (arg->field.field->size != 16) { 50108c2ecf20Sopenharmony_ci trace_seq_printf(s, "INVALIDUUID"); 50118c2ecf20Sopenharmony_ci return ret; 50128c2ecf20Sopenharmony_ci } 50138c2ecf20Sopenharmony_ci 50148c2ecf20Sopenharmony_ci buf = data + arg->field.field->offset; 50158c2ecf20Sopenharmony_ci 50168c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 50178c2ecf20Sopenharmony_ci trace_seq_printf(s, format, buf[index[i]] & 0xff); 50188c2ecf20Sopenharmony_ci switch (i) { 50198c2ecf20Sopenharmony_ci case 3: 50208c2ecf20Sopenharmony_ci case 5: 50218c2ecf20Sopenharmony_ci case 7: 50228c2ecf20Sopenharmony_ci case 9: 50238c2ecf20Sopenharmony_ci trace_seq_printf(s, "-"); 50248c2ecf20Sopenharmony_ci break; 50258c2ecf20Sopenharmony_ci } 50268c2ecf20Sopenharmony_ci } 50278c2ecf20Sopenharmony_ci 50288c2ecf20Sopenharmony_ci return ret; 50298c2ecf20Sopenharmony_ci} 50308c2ecf20Sopenharmony_ci 50318c2ecf20Sopenharmony_cistatic int print_raw_buff_arg(struct trace_seq *s, const char *ptr, 50328c2ecf20Sopenharmony_ci void *data, int size, struct tep_event *event, 50338c2ecf20Sopenharmony_ci struct tep_print_arg *arg, int print_len) 50348c2ecf20Sopenharmony_ci{ 50358c2ecf20Sopenharmony_ci int plen = print_len; 50368c2ecf20Sopenharmony_ci char *delim = " "; 50378c2ecf20Sopenharmony_ci int ret = 0; 50388c2ecf20Sopenharmony_ci char *buf; 50398c2ecf20Sopenharmony_ci int i; 50408c2ecf20Sopenharmony_ci unsigned long offset; 50418c2ecf20Sopenharmony_ci int arr_len; 50428c2ecf20Sopenharmony_ci 50438c2ecf20Sopenharmony_ci switch (*(ptr + 1)) { 50448c2ecf20Sopenharmony_ci case 'C': 50458c2ecf20Sopenharmony_ci delim = ":"; 50468c2ecf20Sopenharmony_ci ret++; 50478c2ecf20Sopenharmony_ci break; 50488c2ecf20Sopenharmony_ci case 'D': 50498c2ecf20Sopenharmony_ci delim = "-"; 50508c2ecf20Sopenharmony_ci ret++; 50518c2ecf20Sopenharmony_ci break; 50528c2ecf20Sopenharmony_ci case 'N': 50538c2ecf20Sopenharmony_ci delim = ""; 50548c2ecf20Sopenharmony_ci ret++; 50558c2ecf20Sopenharmony_ci break; 50568c2ecf20Sopenharmony_ci } 50578c2ecf20Sopenharmony_ci 50588c2ecf20Sopenharmony_ci if (arg->type == TEP_PRINT_FUNC) { 50598c2ecf20Sopenharmony_ci process_defined_func(s, data, size, event, arg); 50608c2ecf20Sopenharmony_ci return ret; 50618c2ecf20Sopenharmony_ci } 50628c2ecf20Sopenharmony_ci 50638c2ecf20Sopenharmony_ci if (arg->type != TEP_PRINT_DYNAMIC_ARRAY) { 50648c2ecf20Sopenharmony_ci trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", arg->type); 50658c2ecf20Sopenharmony_ci return ret; 50668c2ecf20Sopenharmony_ci } 50678c2ecf20Sopenharmony_ci 50688c2ecf20Sopenharmony_ci offset = tep_read_number(event->tep, 50698c2ecf20Sopenharmony_ci data + arg->dynarray.field->offset, 50708c2ecf20Sopenharmony_ci arg->dynarray.field->size); 50718c2ecf20Sopenharmony_ci arr_len = (unsigned long long)(offset >> 16); 50728c2ecf20Sopenharmony_ci buf = data + (offset & 0xffff); 50738c2ecf20Sopenharmony_ci 50748c2ecf20Sopenharmony_ci if (arr_len < plen) 50758c2ecf20Sopenharmony_ci plen = arr_len; 50768c2ecf20Sopenharmony_ci 50778c2ecf20Sopenharmony_ci if (plen < 1) 50788c2ecf20Sopenharmony_ci return ret; 50798c2ecf20Sopenharmony_ci 50808c2ecf20Sopenharmony_ci trace_seq_printf(s, "%02x", buf[0] & 0xff); 50818c2ecf20Sopenharmony_ci for (i = 1; i < plen; i++) 50828c2ecf20Sopenharmony_ci trace_seq_printf(s, "%s%02x", delim, buf[i] & 0xff); 50838c2ecf20Sopenharmony_ci 50848c2ecf20Sopenharmony_ci return ret; 50858c2ecf20Sopenharmony_ci} 50868c2ecf20Sopenharmony_ci 50878c2ecf20Sopenharmony_cistatic int is_printable_array(char *p, unsigned int len) 50888c2ecf20Sopenharmony_ci{ 50898c2ecf20Sopenharmony_ci unsigned int i; 50908c2ecf20Sopenharmony_ci 50918c2ecf20Sopenharmony_ci for (i = 0; i < len && p[i]; i++) 50928c2ecf20Sopenharmony_ci if (!isprint(p[i]) && !isspace(p[i])) 50938c2ecf20Sopenharmony_ci return 0; 50948c2ecf20Sopenharmony_ci return 1; 50958c2ecf20Sopenharmony_ci} 50968c2ecf20Sopenharmony_ci 50978c2ecf20Sopenharmony_civoid tep_print_field(struct trace_seq *s, void *data, 50988c2ecf20Sopenharmony_ci struct tep_format_field *field) 50998c2ecf20Sopenharmony_ci{ 51008c2ecf20Sopenharmony_ci unsigned long long val; 51018c2ecf20Sopenharmony_ci unsigned int offset, len, i; 51028c2ecf20Sopenharmony_ci struct tep_handle *tep = field->event->tep; 51038c2ecf20Sopenharmony_ci 51048c2ecf20Sopenharmony_ci if (field->flags & TEP_FIELD_IS_ARRAY) { 51058c2ecf20Sopenharmony_ci offset = field->offset; 51068c2ecf20Sopenharmony_ci len = field->size; 51078c2ecf20Sopenharmony_ci if (field->flags & TEP_FIELD_IS_DYNAMIC) { 51088c2ecf20Sopenharmony_ci val = tep_read_number(tep, data + offset, len); 51098c2ecf20Sopenharmony_ci offset = val; 51108c2ecf20Sopenharmony_ci len = offset >> 16; 51118c2ecf20Sopenharmony_ci offset &= 0xffff; 51128c2ecf20Sopenharmony_ci } 51138c2ecf20Sopenharmony_ci if (field->flags & TEP_FIELD_IS_STRING && 51148c2ecf20Sopenharmony_ci is_printable_array(data + offset, len)) { 51158c2ecf20Sopenharmony_ci trace_seq_printf(s, "%s", (char *)data + offset); 51168c2ecf20Sopenharmony_ci } else { 51178c2ecf20Sopenharmony_ci trace_seq_puts(s, "ARRAY["); 51188c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 51198c2ecf20Sopenharmony_ci if (i) 51208c2ecf20Sopenharmony_ci trace_seq_puts(s, ", "); 51218c2ecf20Sopenharmony_ci trace_seq_printf(s, "%02x", 51228c2ecf20Sopenharmony_ci *((unsigned char *)data + offset + i)); 51238c2ecf20Sopenharmony_ci } 51248c2ecf20Sopenharmony_ci trace_seq_putc(s, ']'); 51258c2ecf20Sopenharmony_ci field->flags &= ~TEP_FIELD_IS_STRING; 51268c2ecf20Sopenharmony_ci } 51278c2ecf20Sopenharmony_ci } else { 51288c2ecf20Sopenharmony_ci val = tep_read_number(tep, data + field->offset, 51298c2ecf20Sopenharmony_ci field->size); 51308c2ecf20Sopenharmony_ci if (field->flags & TEP_FIELD_IS_POINTER) { 51318c2ecf20Sopenharmony_ci trace_seq_printf(s, "0x%llx", val); 51328c2ecf20Sopenharmony_ci } else if (field->flags & TEP_FIELD_IS_SIGNED) { 51338c2ecf20Sopenharmony_ci switch (field->size) { 51348c2ecf20Sopenharmony_ci case 4: 51358c2ecf20Sopenharmony_ci /* 51368c2ecf20Sopenharmony_ci * If field is long then print it in hex. 51378c2ecf20Sopenharmony_ci * A long usually stores pointers. 51388c2ecf20Sopenharmony_ci */ 51398c2ecf20Sopenharmony_ci if (field->flags & TEP_FIELD_IS_LONG) 51408c2ecf20Sopenharmony_ci trace_seq_printf(s, "0x%x", (int)val); 51418c2ecf20Sopenharmony_ci else 51428c2ecf20Sopenharmony_ci trace_seq_printf(s, "%d", (int)val); 51438c2ecf20Sopenharmony_ci break; 51448c2ecf20Sopenharmony_ci case 2: 51458c2ecf20Sopenharmony_ci trace_seq_printf(s, "%2d", (short)val); 51468c2ecf20Sopenharmony_ci break; 51478c2ecf20Sopenharmony_ci case 1: 51488c2ecf20Sopenharmony_ci trace_seq_printf(s, "%1d", (char)val); 51498c2ecf20Sopenharmony_ci break; 51508c2ecf20Sopenharmony_ci default: 51518c2ecf20Sopenharmony_ci trace_seq_printf(s, "%lld", val); 51528c2ecf20Sopenharmony_ci } 51538c2ecf20Sopenharmony_ci } else { 51548c2ecf20Sopenharmony_ci if (field->flags & TEP_FIELD_IS_LONG) 51558c2ecf20Sopenharmony_ci trace_seq_printf(s, "0x%llx", val); 51568c2ecf20Sopenharmony_ci else 51578c2ecf20Sopenharmony_ci trace_seq_printf(s, "%llu", val); 51588c2ecf20Sopenharmony_ci } 51598c2ecf20Sopenharmony_ci } 51608c2ecf20Sopenharmony_ci} 51618c2ecf20Sopenharmony_ci 51628c2ecf20Sopenharmony_civoid tep_print_fields(struct trace_seq *s, void *data, 51638c2ecf20Sopenharmony_ci int size __maybe_unused, struct tep_event *event) 51648c2ecf20Sopenharmony_ci{ 51658c2ecf20Sopenharmony_ci struct tep_format_field *field; 51668c2ecf20Sopenharmony_ci 51678c2ecf20Sopenharmony_ci field = event->format.fields; 51688c2ecf20Sopenharmony_ci while (field) { 51698c2ecf20Sopenharmony_ci trace_seq_printf(s, " %s=", field->name); 51708c2ecf20Sopenharmony_ci tep_print_field(s, data, field); 51718c2ecf20Sopenharmony_ci field = field->next; 51728c2ecf20Sopenharmony_ci } 51738c2ecf20Sopenharmony_ci} 51748c2ecf20Sopenharmony_ci 51758c2ecf20Sopenharmony_cistatic int print_function(struct trace_seq *s, const char *format, 51768c2ecf20Sopenharmony_ci void *data, int size, struct tep_event *event, 51778c2ecf20Sopenharmony_ci struct tep_print_arg *arg) 51788c2ecf20Sopenharmony_ci{ 51798c2ecf20Sopenharmony_ci struct func_map *func; 51808c2ecf20Sopenharmony_ci unsigned long long val; 51818c2ecf20Sopenharmony_ci 51828c2ecf20Sopenharmony_ci val = eval_num_arg(data, size, event, arg); 51838c2ecf20Sopenharmony_ci func = find_func(event->tep, val); 51848c2ecf20Sopenharmony_ci if (func) { 51858c2ecf20Sopenharmony_ci trace_seq_puts(s, func->func); 51868c2ecf20Sopenharmony_ci if (*format == 'F' || *format == 'S') 51878c2ecf20Sopenharmony_ci trace_seq_printf(s, "+0x%llx", val - func->addr); 51888c2ecf20Sopenharmony_ci } else { 51898c2ecf20Sopenharmony_ci if (event->tep->long_size == 4) 51908c2ecf20Sopenharmony_ci trace_seq_printf(s, "0x%lx", (long)val); 51918c2ecf20Sopenharmony_ci else 51928c2ecf20Sopenharmony_ci trace_seq_printf(s, "0x%llx", (long long)val); 51938c2ecf20Sopenharmony_ci } 51948c2ecf20Sopenharmony_ci 51958c2ecf20Sopenharmony_ci return 0; 51968c2ecf20Sopenharmony_ci} 51978c2ecf20Sopenharmony_ci 51988c2ecf20Sopenharmony_cistatic int print_arg_pointer(struct trace_seq *s, const char *format, int plen, 51998c2ecf20Sopenharmony_ci void *data, int size, 52008c2ecf20Sopenharmony_ci struct tep_event *event, struct tep_print_arg *arg) 52018c2ecf20Sopenharmony_ci{ 52028c2ecf20Sopenharmony_ci unsigned long long val; 52038c2ecf20Sopenharmony_ci int ret = 1; 52048c2ecf20Sopenharmony_ci 52058c2ecf20Sopenharmony_ci if (arg->type == TEP_PRINT_BSTRING) { 52068c2ecf20Sopenharmony_ci trace_seq_puts(s, arg->string.string); 52078c2ecf20Sopenharmony_ci return 0; 52088c2ecf20Sopenharmony_ci } 52098c2ecf20Sopenharmony_ci while (*format) { 52108c2ecf20Sopenharmony_ci if (*format == 'p') { 52118c2ecf20Sopenharmony_ci format++; 52128c2ecf20Sopenharmony_ci break; 52138c2ecf20Sopenharmony_ci } 52148c2ecf20Sopenharmony_ci format++; 52158c2ecf20Sopenharmony_ci } 52168c2ecf20Sopenharmony_ci 52178c2ecf20Sopenharmony_ci switch (*format) { 52188c2ecf20Sopenharmony_ci case 'F': 52198c2ecf20Sopenharmony_ci case 'f': 52208c2ecf20Sopenharmony_ci case 'S': 52218c2ecf20Sopenharmony_ci case 's': 52228c2ecf20Sopenharmony_ci ret += print_function(s, format, data, size, event, arg); 52238c2ecf20Sopenharmony_ci break; 52248c2ecf20Sopenharmony_ci case 'M': 52258c2ecf20Sopenharmony_ci case 'm': 52268c2ecf20Sopenharmony_ci ret += print_mac_arg(s, format, data, size, event, arg); 52278c2ecf20Sopenharmony_ci break; 52288c2ecf20Sopenharmony_ci case 'I': 52298c2ecf20Sopenharmony_ci case 'i': 52308c2ecf20Sopenharmony_ci ret += print_ip_arg(s, format, data, size, event, arg); 52318c2ecf20Sopenharmony_ci break; 52328c2ecf20Sopenharmony_ci case 'U': 52338c2ecf20Sopenharmony_ci ret += print_uuid_arg(s, format, data, size, event, arg); 52348c2ecf20Sopenharmony_ci break; 52358c2ecf20Sopenharmony_ci case 'h': 52368c2ecf20Sopenharmony_ci ret += print_raw_buff_arg(s, format, data, size, event, arg, plen); 52378c2ecf20Sopenharmony_ci break; 52388c2ecf20Sopenharmony_ci default: 52398c2ecf20Sopenharmony_ci ret = 0; 52408c2ecf20Sopenharmony_ci val = eval_num_arg(data, size, event, arg); 52418c2ecf20Sopenharmony_ci trace_seq_printf(s, "%p", (void *)(intptr_t)val); 52428c2ecf20Sopenharmony_ci break; 52438c2ecf20Sopenharmony_ci } 52448c2ecf20Sopenharmony_ci 52458c2ecf20Sopenharmony_ci return ret; 52468c2ecf20Sopenharmony_ci 52478c2ecf20Sopenharmony_ci} 52488c2ecf20Sopenharmony_ci 52498c2ecf20Sopenharmony_cistatic int print_arg_number(struct trace_seq *s, const char *format, int plen, 52508c2ecf20Sopenharmony_ci void *data, int size, int ls, 52518c2ecf20Sopenharmony_ci struct tep_event *event, struct tep_print_arg *arg) 52528c2ecf20Sopenharmony_ci{ 52538c2ecf20Sopenharmony_ci unsigned long long val; 52548c2ecf20Sopenharmony_ci 52558c2ecf20Sopenharmony_ci val = eval_num_arg(data, size, event, arg); 52568c2ecf20Sopenharmony_ci 52578c2ecf20Sopenharmony_ci switch (ls) { 52588c2ecf20Sopenharmony_ci case -2: 52598c2ecf20Sopenharmony_ci if (plen >= 0) 52608c2ecf20Sopenharmony_ci trace_seq_printf(s, format, plen, (char)val); 52618c2ecf20Sopenharmony_ci else 52628c2ecf20Sopenharmony_ci trace_seq_printf(s, format, (char)val); 52638c2ecf20Sopenharmony_ci break; 52648c2ecf20Sopenharmony_ci case -1: 52658c2ecf20Sopenharmony_ci if (plen >= 0) 52668c2ecf20Sopenharmony_ci trace_seq_printf(s, format, plen, (short)val); 52678c2ecf20Sopenharmony_ci else 52688c2ecf20Sopenharmony_ci trace_seq_printf(s, format, (short)val); 52698c2ecf20Sopenharmony_ci break; 52708c2ecf20Sopenharmony_ci case 0: 52718c2ecf20Sopenharmony_ci if (plen >= 0) 52728c2ecf20Sopenharmony_ci trace_seq_printf(s, format, plen, (int)val); 52738c2ecf20Sopenharmony_ci else 52748c2ecf20Sopenharmony_ci trace_seq_printf(s, format, (int)val); 52758c2ecf20Sopenharmony_ci break; 52768c2ecf20Sopenharmony_ci case 1: 52778c2ecf20Sopenharmony_ci if (plen >= 0) 52788c2ecf20Sopenharmony_ci trace_seq_printf(s, format, plen, (long)val); 52798c2ecf20Sopenharmony_ci else 52808c2ecf20Sopenharmony_ci trace_seq_printf(s, format, (long)val); 52818c2ecf20Sopenharmony_ci break; 52828c2ecf20Sopenharmony_ci case 2: 52838c2ecf20Sopenharmony_ci if (plen >= 0) 52848c2ecf20Sopenharmony_ci trace_seq_printf(s, format, plen, (long long)val); 52858c2ecf20Sopenharmony_ci else 52868c2ecf20Sopenharmony_ci trace_seq_printf(s, format, (long long)val); 52878c2ecf20Sopenharmony_ci break; 52888c2ecf20Sopenharmony_ci default: 52898c2ecf20Sopenharmony_ci do_warning_event(event, "bad count (%d)", ls); 52908c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_FAILED; 52918c2ecf20Sopenharmony_ci } 52928c2ecf20Sopenharmony_ci return 0; 52938c2ecf20Sopenharmony_ci} 52948c2ecf20Sopenharmony_ci 52958c2ecf20Sopenharmony_ci 52968c2ecf20Sopenharmony_cistatic void print_arg_string(struct trace_seq *s, const char *format, int plen, 52978c2ecf20Sopenharmony_ci void *data, int size, 52988c2ecf20Sopenharmony_ci struct tep_event *event, struct tep_print_arg *arg) 52998c2ecf20Sopenharmony_ci{ 53008c2ecf20Sopenharmony_ci struct trace_seq p; 53018c2ecf20Sopenharmony_ci 53028c2ecf20Sopenharmony_ci /* Use helper trace_seq */ 53038c2ecf20Sopenharmony_ci trace_seq_init(&p); 53048c2ecf20Sopenharmony_ci print_str_arg(&p, data, size, event, 53058c2ecf20Sopenharmony_ci format, plen, arg); 53068c2ecf20Sopenharmony_ci trace_seq_terminate(&p); 53078c2ecf20Sopenharmony_ci trace_seq_puts(s, p.buffer); 53088c2ecf20Sopenharmony_ci trace_seq_destroy(&p); 53098c2ecf20Sopenharmony_ci} 53108c2ecf20Sopenharmony_ci 53118c2ecf20Sopenharmony_cistatic int parse_arg_format_pointer(const char *format) 53128c2ecf20Sopenharmony_ci{ 53138c2ecf20Sopenharmony_ci int ret = 0; 53148c2ecf20Sopenharmony_ci int index; 53158c2ecf20Sopenharmony_ci int loop; 53168c2ecf20Sopenharmony_ci 53178c2ecf20Sopenharmony_ci switch (*format) { 53188c2ecf20Sopenharmony_ci case 'F': 53198c2ecf20Sopenharmony_ci case 'S': 53208c2ecf20Sopenharmony_ci case 'f': 53218c2ecf20Sopenharmony_ci case 's': 53228c2ecf20Sopenharmony_ci ret++; 53238c2ecf20Sopenharmony_ci break; 53248c2ecf20Sopenharmony_ci case 'M': 53258c2ecf20Sopenharmony_ci case 'm': 53268c2ecf20Sopenharmony_ci /* [mM]R , [mM]F */ 53278c2ecf20Sopenharmony_ci switch (format[1]) { 53288c2ecf20Sopenharmony_ci case 'R': 53298c2ecf20Sopenharmony_ci case 'F': 53308c2ecf20Sopenharmony_ci ret++; 53318c2ecf20Sopenharmony_ci break; 53328c2ecf20Sopenharmony_ci } 53338c2ecf20Sopenharmony_ci ret++; 53348c2ecf20Sopenharmony_ci break; 53358c2ecf20Sopenharmony_ci case 'I': 53368c2ecf20Sopenharmony_ci case 'i': 53378c2ecf20Sopenharmony_ci index = 2; 53388c2ecf20Sopenharmony_ci loop = 1; 53398c2ecf20Sopenharmony_ci switch (format[1]) { 53408c2ecf20Sopenharmony_ci case 'S': 53418c2ecf20Sopenharmony_ci /*[S][pfs]*/ 53428c2ecf20Sopenharmony_ci while (loop) { 53438c2ecf20Sopenharmony_ci switch (format[index]) { 53448c2ecf20Sopenharmony_ci case 'p': 53458c2ecf20Sopenharmony_ci case 'f': 53468c2ecf20Sopenharmony_ci case 's': 53478c2ecf20Sopenharmony_ci ret++; 53488c2ecf20Sopenharmony_ci index++; 53498c2ecf20Sopenharmony_ci break; 53508c2ecf20Sopenharmony_ci default: 53518c2ecf20Sopenharmony_ci loop = 0; 53528c2ecf20Sopenharmony_ci break; 53538c2ecf20Sopenharmony_ci } 53548c2ecf20Sopenharmony_ci } 53558c2ecf20Sopenharmony_ci /* fall through */ 53568c2ecf20Sopenharmony_ci case '4': 53578c2ecf20Sopenharmony_ci /* [4S][hnbl] */ 53588c2ecf20Sopenharmony_ci switch (format[index]) { 53598c2ecf20Sopenharmony_ci case 'h': 53608c2ecf20Sopenharmony_ci case 'n': 53618c2ecf20Sopenharmony_ci case 'l': 53628c2ecf20Sopenharmony_ci case 'b': 53638c2ecf20Sopenharmony_ci ret++; 53648c2ecf20Sopenharmony_ci index++; 53658c2ecf20Sopenharmony_ci break; 53668c2ecf20Sopenharmony_ci } 53678c2ecf20Sopenharmony_ci if (format[1] == '4') { 53688c2ecf20Sopenharmony_ci ret++; 53698c2ecf20Sopenharmony_ci break; 53708c2ecf20Sopenharmony_ci } 53718c2ecf20Sopenharmony_ci /* fall through */ 53728c2ecf20Sopenharmony_ci case '6': 53738c2ecf20Sopenharmony_ci /* [6S]c */ 53748c2ecf20Sopenharmony_ci if (format[index] == 'c') 53758c2ecf20Sopenharmony_ci ret++; 53768c2ecf20Sopenharmony_ci ret++; 53778c2ecf20Sopenharmony_ci break; 53788c2ecf20Sopenharmony_ci } 53798c2ecf20Sopenharmony_ci ret++; 53808c2ecf20Sopenharmony_ci break; 53818c2ecf20Sopenharmony_ci case 'U': 53828c2ecf20Sopenharmony_ci switch (format[1]) { 53838c2ecf20Sopenharmony_ci case 'L': 53848c2ecf20Sopenharmony_ci case 'l': 53858c2ecf20Sopenharmony_ci case 'B': 53868c2ecf20Sopenharmony_ci case 'b': 53878c2ecf20Sopenharmony_ci ret++; 53888c2ecf20Sopenharmony_ci break; 53898c2ecf20Sopenharmony_ci } 53908c2ecf20Sopenharmony_ci ret++; 53918c2ecf20Sopenharmony_ci break; 53928c2ecf20Sopenharmony_ci case 'h': 53938c2ecf20Sopenharmony_ci switch (format[1]) { 53948c2ecf20Sopenharmony_ci case 'C': 53958c2ecf20Sopenharmony_ci case 'D': 53968c2ecf20Sopenharmony_ci case 'N': 53978c2ecf20Sopenharmony_ci ret++; 53988c2ecf20Sopenharmony_ci break; 53998c2ecf20Sopenharmony_ci } 54008c2ecf20Sopenharmony_ci ret++; 54018c2ecf20Sopenharmony_ci break; 54028c2ecf20Sopenharmony_ci default: 54038c2ecf20Sopenharmony_ci break; 54048c2ecf20Sopenharmony_ci } 54058c2ecf20Sopenharmony_ci 54068c2ecf20Sopenharmony_ci return ret; 54078c2ecf20Sopenharmony_ci} 54088c2ecf20Sopenharmony_ci 54098c2ecf20Sopenharmony_cistatic void free_parse_args(struct tep_print_parse *arg) 54108c2ecf20Sopenharmony_ci{ 54118c2ecf20Sopenharmony_ci struct tep_print_parse *del; 54128c2ecf20Sopenharmony_ci 54138c2ecf20Sopenharmony_ci while (arg) { 54148c2ecf20Sopenharmony_ci del = arg; 54158c2ecf20Sopenharmony_ci arg = del->next; 54168c2ecf20Sopenharmony_ci free(del->format); 54178c2ecf20Sopenharmony_ci free(del); 54188c2ecf20Sopenharmony_ci } 54198c2ecf20Sopenharmony_ci} 54208c2ecf20Sopenharmony_ci 54218c2ecf20Sopenharmony_cistatic int parse_arg_add(struct tep_print_parse **parse, char *format, 54228c2ecf20Sopenharmony_ci enum tep_print_parse_type type, 54238c2ecf20Sopenharmony_ci struct tep_print_arg *arg, 54248c2ecf20Sopenharmony_ci struct tep_print_arg *len_as_arg, 54258c2ecf20Sopenharmony_ci int ls) 54268c2ecf20Sopenharmony_ci{ 54278c2ecf20Sopenharmony_ci struct tep_print_parse *parg = NULL; 54288c2ecf20Sopenharmony_ci 54298c2ecf20Sopenharmony_ci parg = calloc(1, sizeof(*parg)); 54308c2ecf20Sopenharmony_ci if (!parg) 54318c2ecf20Sopenharmony_ci goto error; 54328c2ecf20Sopenharmony_ci parg->format = strdup(format); 54338c2ecf20Sopenharmony_ci if (!parg->format) 54348c2ecf20Sopenharmony_ci goto error; 54358c2ecf20Sopenharmony_ci parg->type = type; 54368c2ecf20Sopenharmony_ci parg->arg = arg; 54378c2ecf20Sopenharmony_ci parg->len_as_arg = len_as_arg; 54388c2ecf20Sopenharmony_ci parg->ls = ls; 54398c2ecf20Sopenharmony_ci *parse = parg; 54408c2ecf20Sopenharmony_ci return 0; 54418c2ecf20Sopenharmony_cierror: 54428c2ecf20Sopenharmony_ci if (parg) { 54438c2ecf20Sopenharmony_ci free(parg->format); 54448c2ecf20Sopenharmony_ci free(parg); 54458c2ecf20Sopenharmony_ci } 54468c2ecf20Sopenharmony_ci return -1; 54478c2ecf20Sopenharmony_ci} 54488c2ecf20Sopenharmony_ci 54498c2ecf20Sopenharmony_cistatic int parse_arg_format(struct tep_print_parse **parse, 54508c2ecf20Sopenharmony_ci struct tep_event *event, 54518c2ecf20Sopenharmony_ci const char *format, struct tep_print_arg **arg) 54528c2ecf20Sopenharmony_ci{ 54538c2ecf20Sopenharmony_ci struct tep_print_arg *len_arg = NULL; 54548c2ecf20Sopenharmony_ci char print_format[32]; 54558c2ecf20Sopenharmony_ci const char *start = format; 54568c2ecf20Sopenharmony_ci int ret = 0; 54578c2ecf20Sopenharmony_ci int ls = 0; 54588c2ecf20Sopenharmony_ci int res; 54598c2ecf20Sopenharmony_ci int len; 54608c2ecf20Sopenharmony_ci 54618c2ecf20Sopenharmony_ci format++; 54628c2ecf20Sopenharmony_ci ret++; 54638c2ecf20Sopenharmony_ci for (; *format; format++) { 54648c2ecf20Sopenharmony_ci switch (*format) { 54658c2ecf20Sopenharmony_ci case '#': 54668c2ecf20Sopenharmony_ci /* FIXME: need to handle properly */ 54678c2ecf20Sopenharmony_ci break; 54688c2ecf20Sopenharmony_ci case 'h': 54698c2ecf20Sopenharmony_ci ls--; 54708c2ecf20Sopenharmony_ci break; 54718c2ecf20Sopenharmony_ci case 'l': 54728c2ecf20Sopenharmony_ci ls++; 54738c2ecf20Sopenharmony_ci break; 54748c2ecf20Sopenharmony_ci case 'L': 54758c2ecf20Sopenharmony_ci ls = 2; 54768c2ecf20Sopenharmony_ci break; 54778c2ecf20Sopenharmony_ci case '.': 54788c2ecf20Sopenharmony_ci case 'z': 54798c2ecf20Sopenharmony_ci case 'Z': 54808c2ecf20Sopenharmony_ci case '0' ... '9': 54818c2ecf20Sopenharmony_ci case '-': 54828c2ecf20Sopenharmony_ci break; 54838c2ecf20Sopenharmony_ci case '*': 54848c2ecf20Sopenharmony_ci /* The argument is the length. */ 54858c2ecf20Sopenharmony_ci if (!*arg) { 54868c2ecf20Sopenharmony_ci do_warning_event(event, "no argument match"); 54878c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_FAILED; 54888c2ecf20Sopenharmony_ci goto out_failed; 54898c2ecf20Sopenharmony_ci } 54908c2ecf20Sopenharmony_ci if (len_arg) { 54918c2ecf20Sopenharmony_ci do_warning_event(event, "argument already matched"); 54928c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_FAILED; 54938c2ecf20Sopenharmony_ci goto out_failed; 54948c2ecf20Sopenharmony_ci } 54958c2ecf20Sopenharmony_ci len_arg = *arg; 54968c2ecf20Sopenharmony_ci *arg = (*arg)->next; 54978c2ecf20Sopenharmony_ci break; 54988c2ecf20Sopenharmony_ci case 'p': 54998c2ecf20Sopenharmony_ci if (!*arg) { 55008c2ecf20Sopenharmony_ci do_warning_event(event, "no argument match"); 55018c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_FAILED; 55028c2ecf20Sopenharmony_ci goto out_failed; 55038c2ecf20Sopenharmony_ci } 55048c2ecf20Sopenharmony_ci res = parse_arg_format_pointer(format + 1); 55058c2ecf20Sopenharmony_ci if (res > 0) { 55068c2ecf20Sopenharmony_ci format += res; 55078c2ecf20Sopenharmony_ci ret += res; 55088c2ecf20Sopenharmony_ci } 55098c2ecf20Sopenharmony_ci len = ((unsigned long)format + 1) - 55108c2ecf20Sopenharmony_ci (unsigned long)start; 55118c2ecf20Sopenharmony_ci /* should never happen */ 55128c2ecf20Sopenharmony_ci if (len > 31) { 55138c2ecf20Sopenharmony_ci do_warning_event(event, "bad format!"); 55148c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_FAILED; 55158c2ecf20Sopenharmony_ci len = 31; 55168c2ecf20Sopenharmony_ci } 55178c2ecf20Sopenharmony_ci memcpy(print_format, start, len); 55188c2ecf20Sopenharmony_ci print_format[len] = 0; 55198c2ecf20Sopenharmony_ci 55208c2ecf20Sopenharmony_ci parse_arg_add(parse, print_format, 55218c2ecf20Sopenharmony_ci PRINT_FMT_ARG_POINTER, *arg, len_arg, ls); 55228c2ecf20Sopenharmony_ci *arg = (*arg)->next; 55238c2ecf20Sopenharmony_ci ret++; 55248c2ecf20Sopenharmony_ci return ret; 55258c2ecf20Sopenharmony_ci case 'd': 55268c2ecf20Sopenharmony_ci case 'u': 55278c2ecf20Sopenharmony_ci case 'i': 55288c2ecf20Sopenharmony_ci case 'x': 55298c2ecf20Sopenharmony_ci case 'X': 55308c2ecf20Sopenharmony_ci case 'o': 55318c2ecf20Sopenharmony_ci if (!*arg) { 55328c2ecf20Sopenharmony_ci do_warning_event(event, "no argument match"); 55338c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_FAILED; 55348c2ecf20Sopenharmony_ci goto out_failed; 55358c2ecf20Sopenharmony_ci } 55368c2ecf20Sopenharmony_ci 55378c2ecf20Sopenharmony_ci len = ((unsigned long)format + 1) - 55388c2ecf20Sopenharmony_ci (unsigned long)start; 55398c2ecf20Sopenharmony_ci 55408c2ecf20Sopenharmony_ci /* should never happen */ 55418c2ecf20Sopenharmony_ci if (len > 30) { 55428c2ecf20Sopenharmony_ci do_warning_event(event, "bad format!"); 55438c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_FAILED; 55448c2ecf20Sopenharmony_ci len = 31; 55458c2ecf20Sopenharmony_ci } 55468c2ecf20Sopenharmony_ci memcpy(print_format, start, len); 55478c2ecf20Sopenharmony_ci print_format[len] = 0; 55488c2ecf20Sopenharmony_ci 55498c2ecf20Sopenharmony_ci if (event->tep->long_size == 8 && ls == 1 && 55508c2ecf20Sopenharmony_ci sizeof(long) != 8) { 55518c2ecf20Sopenharmony_ci char *p; 55528c2ecf20Sopenharmony_ci 55538c2ecf20Sopenharmony_ci /* make %l into %ll */ 55548c2ecf20Sopenharmony_ci if (ls == 1 && (p = strchr(print_format, 'l'))) 55558c2ecf20Sopenharmony_ci memmove(p+1, p, strlen(p)+1); 55568c2ecf20Sopenharmony_ci ls = 2; 55578c2ecf20Sopenharmony_ci } 55588c2ecf20Sopenharmony_ci if (ls < -2 || ls > 2) { 55598c2ecf20Sopenharmony_ci do_warning_event(event, "bad count (%d)", ls); 55608c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_FAILED; 55618c2ecf20Sopenharmony_ci } 55628c2ecf20Sopenharmony_ci parse_arg_add(parse, print_format, 55638c2ecf20Sopenharmony_ci PRINT_FMT_ARG_DIGIT, *arg, len_arg, ls); 55648c2ecf20Sopenharmony_ci *arg = (*arg)->next; 55658c2ecf20Sopenharmony_ci ret++; 55668c2ecf20Sopenharmony_ci return ret; 55678c2ecf20Sopenharmony_ci case 's': 55688c2ecf20Sopenharmony_ci if (!*arg) { 55698c2ecf20Sopenharmony_ci do_warning_event(event, "no matching argument"); 55708c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_FAILED; 55718c2ecf20Sopenharmony_ci goto out_failed; 55728c2ecf20Sopenharmony_ci } 55738c2ecf20Sopenharmony_ci 55748c2ecf20Sopenharmony_ci len = ((unsigned long)format + 1) - 55758c2ecf20Sopenharmony_ci (unsigned long)start; 55768c2ecf20Sopenharmony_ci 55778c2ecf20Sopenharmony_ci /* should never happen */ 55788c2ecf20Sopenharmony_ci if (len > 31) { 55798c2ecf20Sopenharmony_ci do_warning_event(event, "bad format!"); 55808c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_FAILED; 55818c2ecf20Sopenharmony_ci len = 31; 55828c2ecf20Sopenharmony_ci } 55838c2ecf20Sopenharmony_ci 55848c2ecf20Sopenharmony_ci memcpy(print_format, start, len); 55858c2ecf20Sopenharmony_ci print_format[len] = 0; 55868c2ecf20Sopenharmony_ci 55878c2ecf20Sopenharmony_ci parse_arg_add(parse, print_format, 55888c2ecf20Sopenharmony_ci PRINT_FMT_ARG_STRING, *arg, len_arg, 0); 55898c2ecf20Sopenharmony_ci *arg = (*arg)->next; 55908c2ecf20Sopenharmony_ci ret++; 55918c2ecf20Sopenharmony_ci return ret; 55928c2ecf20Sopenharmony_ci default: 55938c2ecf20Sopenharmony_ci snprintf(print_format, 32, ">%c<", *format); 55948c2ecf20Sopenharmony_ci parse_arg_add(parse, print_format, 55958c2ecf20Sopenharmony_ci PRINT_FMT_STRING, NULL, NULL, 0); 55968c2ecf20Sopenharmony_ci ret++; 55978c2ecf20Sopenharmony_ci return ret; 55988c2ecf20Sopenharmony_ci } 55998c2ecf20Sopenharmony_ci ret++; 56008c2ecf20Sopenharmony_ci } 56018c2ecf20Sopenharmony_ci 56028c2ecf20Sopenharmony_ciout_failed: 56038c2ecf20Sopenharmony_ci return ret; 56048c2ecf20Sopenharmony_ci 56058c2ecf20Sopenharmony_ci} 56068c2ecf20Sopenharmony_ci 56078c2ecf20Sopenharmony_cistatic int parse_arg_string(struct tep_print_parse **parse, const char *format) 56088c2ecf20Sopenharmony_ci{ 56098c2ecf20Sopenharmony_ci struct trace_seq s; 56108c2ecf20Sopenharmony_ci int ret = 0; 56118c2ecf20Sopenharmony_ci 56128c2ecf20Sopenharmony_ci trace_seq_init(&s); 56138c2ecf20Sopenharmony_ci for (; *format; format++) { 56148c2ecf20Sopenharmony_ci if (*format == '\\') { 56158c2ecf20Sopenharmony_ci format++; 56168c2ecf20Sopenharmony_ci ret++; 56178c2ecf20Sopenharmony_ci switch (*format) { 56188c2ecf20Sopenharmony_ci case 'n': 56198c2ecf20Sopenharmony_ci trace_seq_putc(&s, '\n'); 56208c2ecf20Sopenharmony_ci break; 56218c2ecf20Sopenharmony_ci case 't': 56228c2ecf20Sopenharmony_ci trace_seq_putc(&s, '\t'); 56238c2ecf20Sopenharmony_ci break; 56248c2ecf20Sopenharmony_ci case 'r': 56258c2ecf20Sopenharmony_ci trace_seq_putc(&s, '\r'); 56268c2ecf20Sopenharmony_ci break; 56278c2ecf20Sopenharmony_ci case '\\': 56288c2ecf20Sopenharmony_ci trace_seq_putc(&s, '\\'); 56298c2ecf20Sopenharmony_ci break; 56308c2ecf20Sopenharmony_ci default: 56318c2ecf20Sopenharmony_ci trace_seq_putc(&s, *format); 56328c2ecf20Sopenharmony_ci break; 56338c2ecf20Sopenharmony_ci } 56348c2ecf20Sopenharmony_ci } else if (*format == '%') { 56358c2ecf20Sopenharmony_ci if (*(format + 1) == '%') { 56368c2ecf20Sopenharmony_ci trace_seq_putc(&s, '%'); 56378c2ecf20Sopenharmony_ci format++; 56388c2ecf20Sopenharmony_ci ret++; 56398c2ecf20Sopenharmony_ci } else 56408c2ecf20Sopenharmony_ci break; 56418c2ecf20Sopenharmony_ci } else 56428c2ecf20Sopenharmony_ci trace_seq_putc(&s, *format); 56438c2ecf20Sopenharmony_ci 56448c2ecf20Sopenharmony_ci ret++; 56458c2ecf20Sopenharmony_ci } 56468c2ecf20Sopenharmony_ci trace_seq_terminate(&s); 56478c2ecf20Sopenharmony_ci parse_arg_add(parse, s.buffer, PRINT_FMT_STRING, NULL, NULL, 0); 56488c2ecf20Sopenharmony_ci trace_seq_destroy(&s); 56498c2ecf20Sopenharmony_ci 56508c2ecf20Sopenharmony_ci return ret; 56518c2ecf20Sopenharmony_ci} 56528c2ecf20Sopenharmony_ci 56538c2ecf20Sopenharmony_cistatic struct tep_print_parse * 56548c2ecf20Sopenharmony_ciparse_args(struct tep_event *event, const char *format, struct tep_print_arg *arg) 56558c2ecf20Sopenharmony_ci{ 56568c2ecf20Sopenharmony_ci struct tep_print_parse *parse_ret = NULL; 56578c2ecf20Sopenharmony_ci struct tep_print_parse **parse = NULL; 56588c2ecf20Sopenharmony_ci int ret; 56598c2ecf20Sopenharmony_ci int len; 56608c2ecf20Sopenharmony_ci 56618c2ecf20Sopenharmony_ci len = strlen(format); 56628c2ecf20Sopenharmony_ci while (*format) { 56638c2ecf20Sopenharmony_ci if (!parse_ret) 56648c2ecf20Sopenharmony_ci parse = &parse_ret; 56658c2ecf20Sopenharmony_ci if (*format == '%' && *(format + 1) != '%') 56668c2ecf20Sopenharmony_ci ret = parse_arg_format(parse, event, format, &arg); 56678c2ecf20Sopenharmony_ci else 56688c2ecf20Sopenharmony_ci ret = parse_arg_string(parse, format); 56698c2ecf20Sopenharmony_ci if (*parse) 56708c2ecf20Sopenharmony_ci parse = &((*parse)->next); 56718c2ecf20Sopenharmony_ci 56728c2ecf20Sopenharmony_ci len -= ret; 56738c2ecf20Sopenharmony_ci if (len > 0) 56748c2ecf20Sopenharmony_ci format += ret; 56758c2ecf20Sopenharmony_ci else 56768c2ecf20Sopenharmony_ci break; 56778c2ecf20Sopenharmony_ci } 56788c2ecf20Sopenharmony_ci return parse_ret; 56798c2ecf20Sopenharmony_ci} 56808c2ecf20Sopenharmony_ci 56818c2ecf20Sopenharmony_cistatic void print_event_cache(struct tep_print_parse *parse, struct trace_seq *s, 56828c2ecf20Sopenharmony_ci void *data, int size, struct tep_event *event) 56838c2ecf20Sopenharmony_ci{ 56848c2ecf20Sopenharmony_ci int len_arg; 56858c2ecf20Sopenharmony_ci 56868c2ecf20Sopenharmony_ci while (parse) { 56878c2ecf20Sopenharmony_ci if (parse->len_as_arg) 56888c2ecf20Sopenharmony_ci len_arg = eval_num_arg(data, size, event, parse->len_as_arg); 56898c2ecf20Sopenharmony_ci switch (parse->type) { 56908c2ecf20Sopenharmony_ci case PRINT_FMT_ARG_DIGIT: 56918c2ecf20Sopenharmony_ci print_arg_number(s, parse->format, 56928c2ecf20Sopenharmony_ci parse->len_as_arg ? len_arg : -1, data, 56938c2ecf20Sopenharmony_ci size, parse->ls, event, parse->arg); 56948c2ecf20Sopenharmony_ci break; 56958c2ecf20Sopenharmony_ci case PRINT_FMT_ARG_POINTER: 56968c2ecf20Sopenharmony_ci print_arg_pointer(s, parse->format, 56978c2ecf20Sopenharmony_ci parse->len_as_arg ? len_arg : 1, 56988c2ecf20Sopenharmony_ci data, size, event, parse->arg); 56998c2ecf20Sopenharmony_ci break; 57008c2ecf20Sopenharmony_ci case PRINT_FMT_ARG_STRING: 57018c2ecf20Sopenharmony_ci print_arg_string(s, parse->format, 57028c2ecf20Sopenharmony_ci parse->len_as_arg ? len_arg : -1, 57038c2ecf20Sopenharmony_ci data, size, event, parse->arg); 57048c2ecf20Sopenharmony_ci break; 57058c2ecf20Sopenharmony_ci case PRINT_FMT_STRING: 57068c2ecf20Sopenharmony_ci default: 57078c2ecf20Sopenharmony_ci trace_seq_printf(s, "%s", parse->format); 57088c2ecf20Sopenharmony_ci break; 57098c2ecf20Sopenharmony_ci } 57108c2ecf20Sopenharmony_ci parse = parse->next; 57118c2ecf20Sopenharmony_ci } 57128c2ecf20Sopenharmony_ci} 57138c2ecf20Sopenharmony_ci 57148c2ecf20Sopenharmony_cistatic void pretty_print(struct trace_seq *s, void *data, int size, struct tep_event *event) 57158c2ecf20Sopenharmony_ci{ 57168c2ecf20Sopenharmony_ci struct tep_print_parse *parse = event->print_fmt.print_cache; 57178c2ecf20Sopenharmony_ci struct tep_print_arg *args = NULL; 57188c2ecf20Sopenharmony_ci char *bprint_fmt = NULL; 57198c2ecf20Sopenharmony_ci 57208c2ecf20Sopenharmony_ci if (event->flags & TEP_EVENT_FL_FAILED) { 57218c2ecf20Sopenharmony_ci trace_seq_printf(s, "[FAILED TO PARSE]"); 57228c2ecf20Sopenharmony_ci tep_print_fields(s, data, size, event); 57238c2ecf20Sopenharmony_ci return; 57248c2ecf20Sopenharmony_ci } 57258c2ecf20Sopenharmony_ci 57268c2ecf20Sopenharmony_ci if (event->flags & TEP_EVENT_FL_ISBPRINT) { 57278c2ecf20Sopenharmony_ci bprint_fmt = get_bprint_format(data, size, event); 57288c2ecf20Sopenharmony_ci args = make_bprint_args(bprint_fmt, data, size, event); 57298c2ecf20Sopenharmony_ci parse = parse_args(event, bprint_fmt, args); 57308c2ecf20Sopenharmony_ci } 57318c2ecf20Sopenharmony_ci 57328c2ecf20Sopenharmony_ci print_event_cache(parse, s, data, size, event); 57338c2ecf20Sopenharmony_ci 57348c2ecf20Sopenharmony_ci if (event->flags & TEP_EVENT_FL_ISBPRINT) { 57358c2ecf20Sopenharmony_ci free_parse_args(parse); 57368c2ecf20Sopenharmony_ci free_args(args); 57378c2ecf20Sopenharmony_ci free(bprint_fmt); 57388c2ecf20Sopenharmony_ci } 57398c2ecf20Sopenharmony_ci} 57408c2ecf20Sopenharmony_ci 57418c2ecf20Sopenharmony_ci/* 57428c2ecf20Sopenharmony_ci * This parses out the Latency format (interrupts disabled, 57438c2ecf20Sopenharmony_ci * need rescheduling, in hard/soft interrupt, preempt count 57448c2ecf20Sopenharmony_ci * and lock depth) and places it into the trace_seq. 57458c2ecf20Sopenharmony_ci */ 57468c2ecf20Sopenharmony_cistatic void data_latency_format(struct tep_handle *tep, struct trace_seq *s, 57478c2ecf20Sopenharmony_ci char *format, struct tep_record *record) 57488c2ecf20Sopenharmony_ci{ 57498c2ecf20Sopenharmony_ci static int check_lock_depth = 1; 57508c2ecf20Sopenharmony_ci static int check_migrate_disable = 1; 57518c2ecf20Sopenharmony_ci static int lock_depth_exists; 57528c2ecf20Sopenharmony_ci static int migrate_disable_exists; 57538c2ecf20Sopenharmony_ci unsigned int lat_flags; 57548c2ecf20Sopenharmony_ci struct trace_seq sq; 57558c2ecf20Sopenharmony_ci unsigned int pc; 57568c2ecf20Sopenharmony_ci int lock_depth = 0; 57578c2ecf20Sopenharmony_ci int migrate_disable = 0; 57588c2ecf20Sopenharmony_ci int hardirq; 57598c2ecf20Sopenharmony_ci int softirq; 57608c2ecf20Sopenharmony_ci void *data = record->data; 57618c2ecf20Sopenharmony_ci 57628c2ecf20Sopenharmony_ci trace_seq_init(&sq); 57638c2ecf20Sopenharmony_ci lat_flags = parse_common_flags(tep, data); 57648c2ecf20Sopenharmony_ci pc = parse_common_pc(tep, data); 57658c2ecf20Sopenharmony_ci /* lock_depth may not always exist */ 57668c2ecf20Sopenharmony_ci if (lock_depth_exists) 57678c2ecf20Sopenharmony_ci lock_depth = parse_common_lock_depth(tep, data); 57688c2ecf20Sopenharmony_ci else if (check_lock_depth) { 57698c2ecf20Sopenharmony_ci lock_depth = parse_common_lock_depth(tep, data); 57708c2ecf20Sopenharmony_ci if (lock_depth < 0) 57718c2ecf20Sopenharmony_ci check_lock_depth = 0; 57728c2ecf20Sopenharmony_ci else 57738c2ecf20Sopenharmony_ci lock_depth_exists = 1; 57748c2ecf20Sopenharmony_ci } 57758c2ecf20Sopenharmony_ci 57768c2ecf20Sopenharmony_ci /* migrate_disable may not always exist */ 57778c2ecf20Sopenharmony_ci if (migrate_disable_exists) 57788c2ecf20Sopenharmony_ci migrate_disable = parse_common_migrate_disable(tep, data); 57798c2ecf20Sopenharmony_ci else if (check_migrate_disable) { 57808c2ecf20Sopenharmony_ci migrate_disable = parse_common_migrate_disable(tep, data); 57818c2ecf20Sopenharmony_ci if (migrate_disable < 0) 57828c2ecf20Sopenharmony_ci check_migrate_disable = 0; 57838c2ecf20Sopenharmony_ci else 57848c2ecf20Sopenharmony_ci migrate_disable_exists = 1; 57858c2ecf20Sopenharmony_ci } 57868c2ecf20Sopenharmony_ci 57878c2ecf20Sopenharmony_ci hardirq = lat_flags & TRACE_FLAG_HARDIRQ; 57888c2ecf20Sopenharmony_ci softirq = lat_flags & TRACE_FLAG_SOFTIRQ; 57898c2ecf20Sopenharmony_ci 57908c2ecf20Sopenharmony_ci trace_seq_printf(&sq, "%c%c%c", 57918c2ecf20Sopenharmony_ci (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' : 57928c2ecf20Sopenharmony_ci (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ? 57938c2ecf20Sopenharmony_ci 'X' : '.', 57948c2ecf20Sopenharmony_ci (lat_flags & TRACE_FLAG_NEED_RESCHED) ? 57958c2ecf20Sopenharmony_ci 'N' : '.', 57968c2ecf20Sopenharmony_ci (hardirq && softirq) ? 'H' : 57978c2ecf20Sopenharmony_ci hardirq ? 'h' : softirq ? 's' : '.'); 57988c2ecf20Sopenharmony_ci 57998c2ecf20Sopenharmony_ci if (pc) 58008c2ecf20Sopenharmony_ci trace_seq_printf(&sq, "%x", pc); 58018c2ecf20Sopenharmony_ci else 58028c2ecf20Sopenharmony_ci trace_seq_printf(&sq, "."); 58038c2ecf20Sopenharmony_ci 58048c2ecf20Sopenharmony_ci if (migrate_disable_exists) { 58058c2ecf20Sopenharmony_ci if (migrate_disable < 0) 58068c2ecf20Sopenharmony_ci trace_seq_printf(&sq, "."); 58078c2ecf20Sopenharmony_ci else 58088c2ecf20Sopenharmony_ci trace_seq_printf(&sq, "%d", migrate_disable); 58098c2ecf20Sopenharmony_ci } 58108c2ecf20Sopenharmony_ci 58118c2ecf20Sopenharmony_ci if (lock_depth_exists) { 58128c2ecf20Sopenharmony_ci if (lock_depth < 0) 58138c2ecf20Sopenharmony_ci trace_seq_printf(&sq, "."); 58148c2ecf20Sopenharmony_ci else 58158c2ecf20Sopenharmony_ci trace_seq_printf(&sq, "%d", lock_depth); 58168c2ecf20Sopenharmony_ci } 58178c2ecf20Sopenharmony_ci 58188c2ecf20Sopenharmony_ci if (sq.state == TRACE_SEQ__MEM_ALLOC_FAILED) { 58198c2ecf20Sopenharmony_ci s->state = TRACE_SEQ__MEM_ALLOC_FAILED; 58208c2ecf20Sopenharmony_ci return; 58218c2ecf20Sopenharmony_ci } 58228c2ecf20Sopenharmony_ci 58238c2ecf20Sopenharmony_ci trace_seq_terminate(&sq); 58248c2ecf20Sopenharmony_ci trace_seq_puts(s, sq.buffer); 58258c2ecf20Sopenharmony_ci trace_seq_destroy(&sq); 58268c2ecf20Sopenharmony_ci trace_seq_terminate(s); 58278c2ecf20Sopenharmony_ci} 58288c2ecf20Sopenharmony_ci 58298c2ecf20Sopenharmony_ci/** 58308c2ecf20Sopenharmony_ci * tep_data_type - parse out the given event type 58318c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 58328c2ecf20Sopenharmony_ci * @rec: the record to read from 58338c2ecf20Sopenharmony_ci * 58348c2ecf20Sopenharmony_ci * This returns the event id from the @rec. 58358c2ecf20Sopenharmony_ci */ 58368c2ecf20Sopenharmony_ciint tep_data_type(struct tep_handle *tep, struct tep_record *rec) 58378c2ecf20Sopenharmony_ci{ 58388c2ecf20Sopenharmony_ci return trace_parse_common_type(tep, rec->data); 58398c2ecf20Sopenharmony_ci} 58408c2ecf20Sopenharmony_ci 58418c2ecf20Sopenharmony_ci/** 58428c2ecf20Sopenharmony_ci * tep_data_pid - parse the PID from record 58438c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 58448c2ecf20Sopenharmony_ci * @rec: the record to parse 58458c2ecf20Sopenharmony_ci * 58468c2ecf20Sopenharmony_ci * This returns the PID from a record. 58478c2ecf20Sopenharmony_ci */ 58488c2ecf20Sopenharmony_ciint tep_data_pid(struct tep_handle *tep, struct tep_record *rec) 58498c2ecf20Sopenharmony_ci{ 58508c2ecf20Sopenharmony_ci return parse_common_pid(tep, rec->data); 58518c2ecf20Sopenharmony_ci} 58528c2ecf20Sopenharmony_ci 58538c2ecf20Sopenharmony_ci/** 58548c2ecf20Sopenharmony_ci * tep_data_preempt_count - parse the preempt count from the record 58558c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 58568c2ecf20Sopenharmony_ci * @rec: the record to parse 58578c2ecf20Sopenharmony_ci * 58588c2ecf20Sopenharmony_ci * This returns the preempt count from a record. 58598c2ecf20Sopenharmony_ci */ 58608c2ecf20Sopenharmony_ciint tep_data_preempt_count(struct tep_handle *tep, struct tep_record *rec) 58618c2ecf20Sopenharmony_ci{ 58628c2ecf20Sopenharmony_ci return parse_common_pc(tep, rec->data); 58638c2ecf20Sopenharmony_ci} 58648c2ecf20Sopenharmony_ci 58658c2ecf20Sopenharmony_ci/** 58668c2ecf20Sopenharmony_ci * tep_data_flags - parse the latency flags from the record 58678c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 58688c2ecf20Sopenharmony_ci * @rec: the record to parse 58698c2ecf20Sopenharmony_ci * 58708c2ecf20Sopenharmony_ci * This returns the latency flags from a record. 58718c2ecf20Sopenharmony_ci * 58728c2ecf20Sopenharmony_ci * Use trace_flag_type enum for the flags (see event-parse.h). 58738c2ecf20Sopenharmony_ci */ 58748c2ecf20Sopenharmony_ciint tep_data_flags(struct tep_handle *tep, struct tep_record *rec) 58758c2ecf20Sopenharmony_ci{ 58768c2ecf20Sopenharmony_ci return parse_common_flags(tep, rec->data); 58778c2ecf20Sopenharmony_ci} 58788c2ecf20Sopenharmony_ci 58798c2ecf20Sopenharmony_ci/** 58808c2ecf20Sopenharmony_ci * tep_data_comm_from_pid - return the command line from PID 58818c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 58828c2ecf20Sopenharmony_ci * @pid: the PID of the task to search for 58838c2ecf20Sopenharmony_ci * 58848c2ecf20Sopenharmony_ci * This returns a pointer to the command line that has the given 58858c2ecf20Sopenharmony_ci * @pid. 58868c2ecf20Sopenharmony_ci */ 58878c2ecf20Sopenharmony_ciconst char *tep_data_comm_from_pid(struct tep_handle *tep, int pid) 58888c2ecf20Sopenharmony_ci{ 58898c2ecf20Sopenharmony_ci const char *comm; 58908c2ecf20Sopenharmony_ci 58918c2ecf20Sopenharmony_ci comm = find_cmdline(tep, pid); 58928c2ecf20Sopenharmony_ci return comm; 58938c2ecf20Sopenharmony_ci} 58948c2ecf20Sopenharmony_ci 58958c2ecf20Sopenharmony_cistatic struct tep_cmdline * 58968c2ecf20Sopenharmony_cipid_from_cmdlist(struct tep_handle *tep, const char *comm, struct tep_cmdline *next) 58978c2ecf20Sopenharmony_ci{ 58988c2ecf20Sopenharmony_ci struct cmdline_list *cmdlist = (struct cmdline_list *)next; 58998c2ecf20Sopenharmony_ci 59008c2ecf20Sopenharmony_ci if (cmdlist) 59018c2ecf20Sopenharmony_ci cmdlist = cmdlist->next; 59028c2ecf20Sopenharmony_ci else 59038c2ecf20Sopenharmony_ci cmdlist = tep->cmdlist; 59048c2ecf20Sopenharmony_ci 59058c2ecf20Sopenharmony_ci while (cmdlist && strcmp(cmdlist->comm, comm) != 0) 59068c2ecf20Sopenharmony_ci cmdlist = cmdlist->next; 59078c2ecf20Sopenharmony_ci 59088c2ecf20Sopenharmony_ci return (struct tep_cmdline *)cmdlist; 59098c2ecf20Sopenharmony_ci} 59108c2ecf20Sopenharmony_ci 59118c2ecf20Sopenharmony_ci/** 59128c2ecf20Sopenharmony_ci * tep_data_pid_from_comm - return the pid from a given comm 59138c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 59148c2ecf20Sopenharmony_ci * @comm: the cmdline to find the pid from 59158c2ecf20Sopenharmony_ci * @next: the cmdline structure to find the next comm 59168c2ecf20Sopenharmony_ci * 59178c2ecf20Sopenharmony_ci * This returns the cmdline structure that holds a pid for a given 59188c2ecf20Sopenharmony_ci * comm, or NULL if none found. As there may be more than one pid for 59198c2ecf20Sopenharmony_ci * a given comm, the result of this call can be passed back into 59208c2ecf20Sopenharmony_ci * a recurring call in the @next parameter, and then it will find the 59218c2ecf20Sopenharmony_ci * next pid. 59228c2ecf20Sopenharmony_ci * Also, it does a linear search, so it may be slow. 59238c2ecf20Sopenharmony_ci */ 59248c2ecf20Sopenharmony_cistruct tep_cmdline *tep_data_pid_from_comm(struct tep_handle *tep, const char *comm, 59258c2ecf20Sopenharmony_ci struct tep_cmdline *next) 59268c2ecf20Sopenharmony_ci{ 59278c2ecf20Sopenharmony_ci struct tep_cmdline *cmdline; 59288c2ecf20Sopenharmony_ci 59298c2ecf20Sopenharmony_ci /* 59308c2ecf20Sopenharmony_ci * If the cmdlines have not been converted yet, then use 59318c2ecf20Sopenharmony_ci * the list. 59328c2ecf20Sopenharmony_ci */ 59338c2ecf20Sopenharmony_ci if (!tep->cmdlines) 59348c2ecf20Sopenharmony_ci return pid_from_cmdlist(tep, comm, next); 59358c2ecf20Sopenharmony_ci 59368c2ecf20Sopenharmony_ci if (next) { 59378c2ecf20Sopenharmony_ci /* 59388c2ecf20Sopenharmony_ci * The next pointer could have been still from 59398c2ecf20Sopenharmony_ci * a previous call before cmdlines were created 59408c2ecf20Sopenharmony_ci */ 59418c2ecf20Sopenharmony_ci if (next < tep->cmdlines || 59428c2ecf20Sopenharmony_ci next >= tep->cmdlines + tep->cmdline_count) 59438c2ecf20Sopenharmony_ci next = NULL; 59448c2ecf20Sopenharmony_ci else 59458c2ecf20Sopenharmony_ci cmdline = next++; 59468c2ecf20Sopenharmony_ci } 59478c2ecf20Sopenharmony_ci 59488c2ecf20Sopenharmony_ci if (!next) 59498c2ecf20Sopenharmony_ci cmdline = tep->cmdlines; 59508c2ecf20Sopenharmony_ci 59518c2ecf20Sopenharmony_ci while (cmdline < tep->cmdlines + tep->cmdline_count) { 59528c2ecf20Sopenharmony_ci if (strcmp(cmdline->comm, comm) == 0) 59538c2ecf20Sopenharmony_ci return cmdline; 59548c2ecf20Sopenharmony_ci cmdline++; 59558c2ecf20Sopenharmony_ci } 59568c2ecf20Sopenharmony_ci return NULL; 59578c2ecf20Sopenharmony_ci} 59588c2ecf20Sopenharmony_ci 59598c2ecf20Sopenharmony_ci/** 59608c2ecf20Sopenharmony_ci * tep_cmdline_pid - return the pid associated to a given cmdline 59618c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 59628c2ecf20Sopenharmony_ci * @cmdline: The cmdline structure to get the pid from 59638c2ecf20Sopenharmony_ci * 59648c2ecf20Sopenharmony_ci * Returns the pid for a give cmdline. If @cmdline is NULL, then 59658c2ecf20Sopenharmony_ci * -1 is returned. 59668c2ecf20Sopenharmony_ci */ 59678c2ecf20Sopenharmony_ciint tep_cmdline_pid(struct tep_handle *tep, struct tep_cmdline *cmdline) 59688c2ecf20Sopenharmony_ci{ 59698c2ecf20Sopenharmony_ci struct cmdline_list *cmdlist = (struct cmdline_list *)cmdline; 59708c2ecf20Sopenharmony_ci 59718c2ecf20Sopenharmony_ci if (!cmdline) 59728c2ecf20Sopenharmony_ci return -1; 59738c2ecf20Sopenharmony_ci 59748c2ecf20Sopenharmony_ci /* 59758c2ecf20Sopenharmony_ci * If cmdlines have not been created yet, or cmdline is 59768c2ecf20Sopenharmony_ci * not part of the array, then treat it as a cmdlist instead. 59778c2ecf20Sopenharmony_ci */ 59788c2ecf20Sopenharmony_ci if (!tep->cmdlines || 59798c2ecf20Sopenharmony_ci cmdline < tep->cmdlines || 59808c2ecf20Sopenharmony_ci cmdline >= tep->cmdlines + tep->cmdline_count) 59818c2ecf20Sopenharmony_ci return cmdlist->pid; 59828c2ecf20Sopenharmony_ci 59838c2ecf20Sopenharmony_ci return cmdline->pid; 59848c2ecf20Sopenharmony_ci} 59858c2ecf20Sopenharmony_ci 59868c2ecf20Sopenharmony_ci/* 59878c2ecf20Sopenharmony_ci * This parses the raw @data using the given @event information and 59888c2ecf20Sopenharmony_ci * writes the print format into the trace_seq. 59898c2ecf20Sopenharmony_ci */ 59908c2ecf20Sopenharmony_cistatic void print_event_info(struct trace_seq *s, char *format, bool raw, 59918c2ecf20Sopenharmony_ci struct tep_event *event, struct tep_record *record) 59928c2ecf20Sopenharmony_ci{ 59938c2ecf20Sopenharmony_ci int print_pretty = 1; 59948c2ecf20Sopenharmony_ci 59958c2ecf20Sopenharmony_ci if (raw || (event->flags & TEP_EVENT_FL_PRINTRAW)) 59968c2ecf20Sopenharmony_ci tep_print_fields(s, record->data, record->size, event); 59978c2ecf20Sopenharmony_ci else { 59988c2ecf20Sopenharmony_ci 59998c2ecf20Sopenharmony_ci if (event->handler && !(event->flags & TEP_EVENT_FL_NOHANDLE)) 60008c2ecf20Sopenharmony_ci print_pretty = event->handler(s, record, event, 60018c2ecf20Sopenharmony_ci event->context); 60028c2ecf20Sopenharmony_ci 60038c2ecf20Sopenharmony_ci if (print_pretty) 60048c2ecf20Sopenharmony_ci pretty_print(s, record->data, record->size, event); 60058c2ecf20Sopenharmony_ci } 60068c2ecf20Sopenharmony_ci 60078c2ecf20Sopenharmony_ci trace_seq_terminate(s); 60088c2ecf20Sopenharmony_ci} 60098c2ecf20Sopenharmony_ci 60108c2ecf20Sopenharmony_ci/** 60118c2ecf20Sopenharmony_ci * tep_find_event_by_record - return the event from a given record 60128c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 60138c2ecf20Sopenharmony_ci * @record: The record to get the event from 60148c2ecf20Sopenharmony_ci * 60158c2ecf20Sopenharmony_ci * Returns the associated event for a given record, or NULL if non is 60168c2ecf20Sopenharmony_ci * is found. 60178c2ecf20Sopenharmony_ci */ 60188c2ecf20Sopenharmony_cistruct tep_event * 60198c2ecf20Sopenharmony_citep_find_event_by_record(struct tep_handle *tep, struct tep_record *record) 60208c2ecf20Sopenharmony_ci{ 60218c2ecf20Sopenharmony_ci int type; 60228c2ecf20Sopenharmony_ci 60238c2ecf20Sopenharmony_ci if (record->size < 0) { 60248c2ecf20Sopenharmony_ci do_warning("ug! negative record size %d", record->size); 60258c2ecf20Sopenharmony_ci return NULL; 60268c2ecf20Sopenharmony_ci } 60278c2ecf20Sopenharmony_ci 60288c2ecf20Sopenharmony_ci type = trace_parse_common_type(tep, record->data); 60298c2ecf20Sopenharmony_ci 60308c2ecf20Sopenharmony_ci return tep_find_event(tep, type); 60318c2ecf20Sopenharmony_ci} 60328c2ecf20Sopenharmony_ci 60338c2ecf20Sopenharmony_ci/* 60348c2ecf20Sopenharmony_ci * Writes the timestamp of the record into @s. Time divisor and precision can be 60358c2ecf20Sopenharmony_ci * specified as part of printf @format string. Example: 60368c2ecf20Sopenharmony_ci * "%3.1000d" - divide the time by 1000 and print the first 3 digits 60378c2ecf20Sopenharmony_ci * before the dot. Thus, the timestamp "123456000" will be printed as 60388c2ecf20Sopenharmony_ci * "123.456" 60398c2ecf20Sopenharmony_ci */ 60408c2ecf20Sopenharmony_cistatic void print_event_time(struct tep_handle *tep, struct trace_seq *s, 60418c2ecf20Sopenharmony_ci char *format, struct tep_event *event, 60428c2ecf20Sopenharmony_ci struct tep_record *record) 60438c2ecf20Sopenharmony_ci{ 60448c2ecf20Sopenharmony_ci unsigned long long time; 60458c2ecf20Sopenharmony_ci char *divstr; 60468c2ecf20Sopenharmony_ci int prec = 0, pr; 60478c2ecf20Sopenharmony_ci int div = 0; 60488c2ecf20Sopenharmony_ci int p10 = 1; 60498c2ecf20Sopenharmony_ci 60508c2ecf20Sopenharmony_ci if (isdigit(*(format + 1))) 60518c2ecf20Sopenharmony_ci prec = atoi(format + 1); 60528c2ecf20Sopenharmony_ci divstr = strchr(format, '.'); 60538c2ecf20Sopenharmony_ci if (divstr && isdigit(*(divstr + 1))) 60548c2ecf20Sopenharmony_ci div = atoi(divstr + 1); 60558c2ecf20Sopenharmony_ci time = record->ts; 60568c2ecf20Sopenharmony_ci if (div) { 60578c2ecf20Sopenharmony_ci time += div / 2; 60588c2ecf20Sopenharmony_ci time /= div; 60598c2ecf20Sopenharmony_ci } 60608c2ecf20Sopenharmony_ci pr = prec; 60618c2ecf20Sopenharmony_ci while (pr--) 60628c2ecf20Sopenharmony_ci p10 *= 10; 60638c2ecf20Sopenharmony_ci 60648c2ecf20Sopenharmony_ci if (p10 > 1 && p10 < time) 60658c2ecf20Sopenharmony_ci trace_seq_printf(s, "%5llu.%0*llu", time / p10, prec, time % p10); 60668c2ecf20Sopenharmony_ci else 60678c2ecf20Sopenharmony_ci trace_seq_printf(s, "%12llu", time); 60688c2ecf20Sopenharmony_ci} 60698c2ecf20Sopenharmony_ci 60708c2ecf20Sopenharmony_cistruct print_event_type { 60718c2ecf20Sopenharmony_ci enum { 60728c2ecf20Sopenharmony_ci EVENT_TYPE_INT = 1, 60738c2ecf20Sopenharmony_ci EVENT_TYPE_STRING, 60748c2ecf20Sopenharmony_ci EVENT_TYPE_UNKNOWN, 60758c2ecf20Sopenharmony_ci } type; 60768c2ecf20Sopenharmony_ci char format[32]; 60778c2ecf20Sopenharmony_ci}; 60788c2ecf20Sopenharmony_ci 60798c2ecf20Sopenharmony_cistatic void print_string(struct tep_handle *tep, struct trace_seq *s, 60808c2ecf20Sopenharmony_ci struct tep_record *record, struct tep_event *event, 60818c2ecf20Sopenharmony_ci const char *arg, struct print_event_type *type) 60828c2ecf20Sopenharmony_ci{ 60838c2ecf20Sopenharmony_ci const char *comm; 60848c2ecf20Sopenharmony_ci int pid; 60858c2ecf20Sopenharmony_ci 60868c2ecf20Sopenharmony_ci if (strncmp(arg, TEP_PRINT_LATENCY, strlen(TEP_PRINT_LATENCY)) == 0) { 60878c2ecf20Sopenharmony_ci data_latency_format(tep, s, type->format, record); 60888c2ecf20Sopenharmony_ci } else if (strncmp(arg, TEP_PRINT_COMM, strlen(TEP_PRINT_COMM)) == 0) { 60898c2ecf20Sopenharmony_ci pid = parse_common_pid(tep, record->data); 60908c2ecf20Sopenharmony_ci comm = find_cmdline(tep, pid); 60918c2ecf20Sopenharmony_ci trace_seq_printf(s, type->format, comm); 60928c2ecf20Sopenharmony_ci } else if (strncmp(arg, TEP_PRINT_INFO_RAW, strlen(TEP_PRINT_INFO_RAW)) == 0) { 60938c2ecf20Sopenharmony_ci print_event_info(s, type->format, true, event, record); 60948c2ecf20Sopenharmony_ci } else if (strncmp(arg, TEP_PRINT_INFO, strlen(TEP_PRINT_INFO)) == 0) { 60958c2ecf20Sopenharmony_ci print_event_info(s, type->format, false, event, record); 60968c2ecf20Sopenharmony_ci } else if (strncmp(arg, TEP_PRINT_NAME, strlen(TEP_PRINT_NAME)) == 0) { 60978c2ecf20Sopenharmony_ci trace_seq_printf(s, type->format, event->name); 60988c2ecf20Sopenharmony_ci } else { 60998c2ecf20Sopenharmony_ci trace_seq_printf(s, "[UNKNOWN TEP TYPE %s]", arg); 61008c2ecf20Sopenharmony_ci } 61018c2ecf20Sopenharmony_ci 61028c2ecf20Sopenharmony_ci} 61038c2ecf20Sopenharmony_ci 61048c2ecf20Sopenharmony_cistatic void print_int(struct tep_handle *tep, struct trace_seq *s, 61058c2ecf20Sopenharmony_ci struct tep_record *record, struct tep_event *event, 61068c2ecf20Sopenharmony_ci int arg, struct print_event_type *type) 61078c2ecf20Sopenharmony_ci{ 61088c2ecf20Sopenharmony_ci int param; 61098c2ecf20Sopenharmony_ci 61108c2ecf20Sopenharmony_ci switch (arg) { 61118c2ecf20Sopenharmony_ci case TEP_PRINT_CPU: 61128c2ecf20Sopenharmony_ci param = record->cpu; 61138c2ecf20Sopenharmony_ci break; 61148c2ecf20Sopenharmony_ci case TEP_PRINT_PID: 61158c2ecf20Sopenharmony_ci param = parse_common_pid(tep, record->data); 61168c2ecf20Sopenharmony_ci break; 61178c2ecf20Sopenharmony_ci case TEP_PRINT_TIME: 61188c2ecf20Sopenharmony_ci return print_event_time(tep, s, type->format, event, record); 61198c2ecf20Sopenharmony_ci default: 61208c2ecf20Sopenharmony_ci return; 61218c2ecf20Sopenharmony_ci } 61228c2ecf20Sopenharmony_ci trace_seq_printf(s, type->format, param); 61238c2ecf20Sopenharmony_ci} 61248c2ecf20Sopenharmony_ci 61258c2ecf20Sopenharmony_cistatic int tep_print_event_param_type(char *format, 61268c2ecf20Sopenharmony_ci struct print_event_type *type) 61278c2ecf20Sopenharmony_ci{ 61288c2ecf20Sopenharmony_ci char *str = format + 1; 61298c2ecf20Sopenharmony_ci int i = 1; 61308c2ecf20Sopenharmony_ci 61318c2ecf20Sopenharmony_ci type->type = EVENT_TYPE_UNKNOWN; 61328c2ecf20Sopenharmony_ci while (*str) { 61338c2ecf20Sopenharmony_ci switch (*str) { 61348c2ecf20Sopenharmony_ci case 'd': 61358c2ecf20Sopenharmony_ci case 'u': 61368c2ecf20Sopenharmony_ci case 'i': 61378c2ecf20Sopenharmony_ci case 'x': 61388c2ecf20Sopenharmony_ci case 'X': 61398c2ecf20Sopenharmony_ci case 'o': 61408c2ecf20Sopenharmony_ci type->type = EVENT_TYPE_INT; 61418c2ecf20Sopenharmony_ci break; 61428c2ecf20Sopenharmony_ci case 's': 61438c2ecf20Sopenharmony_ci type->type = EVENT_TYPE_STRING; 61448c2ecf20Sopenharmony_ci break; 61458c2ecf20Sopenharmony_ci } 61468c2ecf20Sopenharmony_ci str++; 61478c2ecf20Sopenharmony_ci i++; 61488c2ecf20Sopenharmony_ci if (type->type != EVENT_TYPE_UNKNOWN) 61498c2ecf20Sopenharmony_ci break; 61508c2ecf20Sopenharmony_ci } 61518c2ecf20Sopenharmony_ci memset(type->format, 0, 32); 61528c2ecf20Sopenharmony_ci memcpy(type->format, format, i < 32 ? i : 31); 61538c2ecf20Sopenharmony_ci return i; 61548c2ecf20Sopenharmony_ci} 61558c2ecf20Sopenharmony_ci 61568c2ecf20Sopenharmony_ci/** 61578c2ecf20Sopenharmony_ci * tep_print_event - Write various event information 61588c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 61598c2ecf20Sopenharmony_ci * @s: the trace_seq to write to 61608c2ecf20Sopenharmony_ci * @record: The record to get the event from 61618c2ecf20Sopenharmony_ci * @format: a printf format string. Supported event fileds: 61628c2ecf20Sopenharmony_ci * TEP_PRINT_PID, "%d" - event PID 61638c2ecf20Sopenharmony_ci * TEP_PRINT_CPU, "%d" - event CPU 61648c2ecf20Sopenharmony_ci * TEP_PRINT_COMM, "%s" - event command string 61658c2ecf20Sopenharmony_ci * TEP_PRINT_NAME, "%s" - event name 61668c2ecf20Sopenharmony_ci * TEP_PRINT_LATENCY, "%s" - event latency 61678c2ecf20Sopenharmony_ci * TEP_PRINT_TIME, %d - event time stamp. A divisor and precision 61688c2ecf20Sopenharmony_ci * can be specified as part of this format string: 61698c2ecf20Sopenharmony_ci * "%precision.divisord". Example: 61708c2ecf20Sopenharmony_ci * "%3.1000d" - divide the time by 1000 and print the first 61718c2ecf20Sopenharmony_ci * 3 digits before the dot. Thus, the time stamp 61728c2ecf20Sopenharmony_ci * "123456000" will be printed as "123.456" 61738c2ecf20Sopenharmony_ci * TEP_PRINT_INFO, "%s" - event information. If any width is specified in 61748c2ecf20Sopenharmony_ci * the format string, the event information will be printed 61758c2ecf20Sopenharmony_ci * in raw format. 61768c2ecf20Sopenharmony_ci * Writes the specified event information into @s. 61778c2ecf20Sopenharmony_ci */ 61788c2ecf20Sopenharmony_civoid tep_print_event(struct tep_handle *tep, struct trace_seq *s, 61798c2ecf20Sopenharmony_ci struct tep_record *record, const char *fmt, ...) 61808c2ecf20Sopenharmony_ci{ 61818c2ecf20Sopenharmony_ci struct print_event_type type; 61828c2ecf20Sopenharmony_ci char *format = strdup(fmt); 61838c2ecf20Sopenharmony_ci char *current = format; 61848c2ecf20Sopenharmony_ci char *str = format; 61858c2ecf20Sopenharmony_ci int offset; 61868c2ecf20Sopenharmony_ci va_list args; 61878c2ecf20Sopenharmony_ci struct tep_event *event; 61888c2ecf20Sopenharmony_ci 61898c2ecf20Sopenharmony_ci if (!format) 61908c2ecf20Sopenharmony_ci return; 61918c2ecf20Sopenharmony_ci 61928c2ecf20Sopenharmony_ci event = tep_find_event_by_record(tep, record); 61938c2ecf20Sopenharmony_ci va_start(args, fmt); 61948c2ecf20Sopenharmony_ci while (*current) { 61958c2ecf20Sopenharmony_ci current = strchr(str, '%'); 61968c2ecf20Sopenharmony_ci if (!current) { 61978c2ecf20Sopenharmony_ci trace_seq_puts(s, str); 61988c2ecf20Sopenharmony_ci break; 61998c2ecf20Sopenharmony_ci } 62008c2ecf20Sopenharmony_ci memset(&type, 0, sizeof(type)); 62018c2ecf20Sopenharmony_ci offset = tep_print_event_param_type(current, &type); 62028c2ecf20Sopenharmony_ci *current = '\0'; 62038c2ecf20Sopenharmony_ci trace_seq_puts(s, str); 62048c2ecf20Sopenharmony_ci current += offset; 62058c2ecf20Sopenharmony_ci switch (type.type) { 62068c2ecf20Sopenharmony_ci case EVENT_TYPE_STRING: 62078c2ecf20Sopenharmony_ci print_string(tep, s, record, event, 62088c2ecf20Sopenharmony_ci va_arg(args, char*), &type); 62098c2ecf20Sopenharmony_ci break; 62108c2ecf20Sopenharmony_ci case EVENT_TYPE_INT: 62118c2ecf20Sopenharmony_ci print_int(tep, s, record, event, 62128c2ecf20Sopenharmony_ci va_arg(args, int), &type); 62138c2ecf20Sopenharmony_ci break; 62148c2ecf20Sopenharmony_ci case EVENT_TYPE_UNKNOWN: 62158c2ecf20Sopenharmony_ci default: 62168c2ecf20Sopenharmony_ci trace_seq_printf(s, "[UNKNOWN TYPE]"); 62178c2ecf20Sopenharmony_ci break; 62188c2ecf20Sopenharmony_ci } 62198c2ecf20Sopenharmony_ci str = current; 62208c2ecf20Sopenharmony_ci 62218c2ecf20Sopenharmony_ci } 62228c2ecf20Sopenharmony_ci va_end(args); 62238c2ecf20Sopenharmony_ci free(format); 62248c2ecf20Sopenharmony_ci} 62258c2ecf20Sopenharmony_ci 62268c2ecf20Sopenharmony_cistatic int events_id_cmp(const void *a, const void *b) 62278c2ecf20Sopenharmony_ci{ 62288c2ecf20Sopenharmony_ci struct tep_event * const * ea = a; 62298c2ecf20Sopenharmony_ci struct tep_event * const * eb = b; 62308c2ecf20Sopenharmony_ci 62318c2ecf20Sopenharmony_ci if ((*ea)->id < (*eb)->id) 62328c2ecf20Sopenharmony_ci return -1; 62338c2ecf20Sopenharmony_ci 62348c2ecf20Sopenharmony_ci if ((*ea)->id > (*eb)->id) 62358c2ecf20Sopenharmony_ci return 1; 62368c2ecf20Sopenharmony_ci 62378c2ecf20Sopenharmony_ci return 0; 62388c2ecf20Sopenharmony_ci} 62398c2ecf20Sopenharmony_ci 62408c2ecf20Sopenharmony_cistatic int events_name_cmp(const void *a, const void *b) 62418c2ecf20Sopenharmony_ci{ 62428c2ecf20Sopenharmony_ci struct tep_event * const * ea = a; 62438c2ecf20Sopenharmony_ci struct tep_event * const * eb = b; 62448c2ecf20Sopenharmony_ci int res; 62458c2ecf20Sopenharmony_ci 62468c2ecf20Sopenharmony_ci res = strcmp((*ea)->name, (*eb)->name); 62478c2ecf20Sopenharmony_ci if (res) 62488c2ecf20Sopenharmony_ci return res; 62498c2ecf20Sopenharmony_ci 62508c2ecf20Sopenharmony_ci res = strcmp((*ea)->system, (*eb)->system); 62518c2ecf20Sopenharmony_ci if (res) 62528c2ecf20Sopenharmony_ci return res; 62538c2ecf20Sopenharmony_ci 62548c2ecf20Sopenharmony_ci return events_id_cmp(a, b); 62558c2ecf20Sopenharmony_ci} 62568c2ecf20Sopenharmony_ci 62578c2ecf20Sopenharmony_cistatic int events_system_cmp(const void *a, const void *b) 62588c2ecf20Sopenharmony_ci{ 62598c2ecf20Sopenharmony_ci struct tep_event * const * ea = a; 62608c2ecf20Sopenharmony_ci struct tep_event * const * eb = b; 62618c2ecf20Sopenharmony_ci int res; 62628c2ecf20Sopenharmony_ci 62638c2ecf20Sopenharmony_ci res = strcmp((*ea)->system, (*eb)->system); 62648c2ecf20Sopenharmony_ci if (res) 62658c2ecf20Sopenharmony_ci return res; 62668c2ecf20Sopenharmony_ci 62678c2ecf20Sopenharmony_ci res = strcmp((*ea)->name, (*eb)->name); 62688c2ecf20Sopenharmony_ci if (res) 62698c2ecf20Sopenharmony_ci return res; 62708c2ecf20Sopenharmony_ci 62718c2ecf20Sopenharmony_ci return events_id_cmp(a, b); 62728c2ecf20Sopenharmony_ci} 62738c2ecf20Sopenharmony_ci 62748c2ecf20Sopenharmony_cistatic struct tep_event **list_events_copy(struct tep_handle *tep) 62758c2ecf20Sopenharmony_ci{ 62768c2ecf20Sopenharmony_ci struct tep_event **events; 62778c2ecf20Sopenharmony_ci 62788c2ecf20Sopenharmony_ci if (!tep) 62798c2ecf20Sopenharmony_ci return NULL; 62808c2ecf20Sopenharmony_ci 62818c2ecf20Sopenharmony_ci events = malloc(sizeof(*events) * (tep->nr_events + 1)); 62828c2ecf20Sopenharmony_ci if (!events) 62838c2ecf20Sopenharmony_ci return NULL; 62848c2ecf20Sopenharmony_ci 62858c2ecf20Sopenharmony_ci memcpy(events, tep->events, sizeof(*events) * tep->nr_events); 62868c2ecf20Sopenharmony_ci events[tep->nr_events] = NULL; 62878c2ecf20Sopenharmony_ci return events; 62888c2ecf20Sopenharmony_ci} 62898c2ecf20Sopenharmony_ci 62908c2ecf20Sopenharmony_cistatic void list_events_sort(struct tep_event **events, int nr_events, 62918c2ecf20Sopenharmony_ci enum tep_event_sort_type sort_type) 62928c2ecf20Sopenharmony_ci{ 62938c2ecf20Sopenharmony_ci int (*sort)(const void *a, const void *b); 62948c2ecf20Sopenharmony_ci 62958c2ecf20Sopenharmony_ci switch (sort_type) { 62968c2ecf20Sopenharmony_ci case TEP_EVENT_SORT_ID: 62978c2ecf20Sopenharmony_ci sort = events_id_cmp; 62988c2ecf20Sopenharmony_ci break; 62998c2ecf20Sopenharmony_ci case TEP_EVENT_SORT_NAME: 63008c2ecf20Sopenharmony_ci sort = events_name_cmp; 63018c2ecf20Sopenharmony_ci break; 63028c2ecf20Sopenharmony_ci case TEP_EVENT_SORT_SYSTEM: 63038c2ecf20Sopenharmony_ci sort = events_system_cmp; 63048c2ecf20Sopenharmony_ci break; 63058c2ecf20Sopenharmony_ci default: 63068c2ecf20Sopenharmony_ci sort = NULL; 63078c2ecf20Sopenharmony_ci } 63088c2ecf20Sopenharmony_ci 63098c2ecf20Sopenharmony_ci if (sort) 63108c2ecf20Sopenharmony_ci qsort(events, nr_events, sizeof(*events), sort); 63118c2ecf20Sopenharmony_ci} 63128c2ecf20Sopenharmony_ci 63138c2ecf20Sopenharmony_ci/** 63148c2ecf20Sopenharmony_ci * tep_list_events - Get events, sorted by given criteria. 63158c2ecf20Sopenharmony_ci * @tep: a handle to the tep context 63168c2ecf20Sopenharmony_ci * @sort_type: desired sort order of the events in the array 63178c2ecf20Sopenharmony_ci * 63188c2ecf20Sopenharmony_ci * Returns an array of pointers to all events, sorted by the given 63198c2ecf20Sopenharmony_ci * @sort_type criteria. The last element of the array is NULL. The returned 63208c2ecf20Sopenharmony_ci * memory must not be freed, it is managed by the library. 63218c2ecf20Sopenharmony_ci * The function is not thread safe. 63228c2ecf20Sopenharmony_ci */ 63238c2ecf20Sopenharmony_cistruct tep_event **tep_list_events(struct tep_handle *tep, 63248c2ecf20Sopenharmony_ci enum tep_event_sort_type sort_type) 63258c2ecf20Sopenharmony_ci{ 63268c2ecf20Sopenharmony_ci struct tep_event **events; 63278c2ecf20Sopenharmony_ci 63288c2ecf20Sopenharmony_ci if (!tep) 63298c2ecf20Sopenharmony_ci return NULL; 63308c2ecf20Sopenharmony_ci 63318c2ecf20Sopenharmony_ci events = tep->sort_events; 63328c2ecf20Sopenharmony_ci if (events && tep->last_type == sort_type) 63338c2ecf20Sopenharmony_ci return events; 63348c2ecf20Sopenharmony_ci 63358c2ecf20Sopenharmony_ci if (!events) { 63368c2ecf20Sopenharmony_ci events = list_events_copy(tep); 63378c2ecf20Sopenharmony_ci if (!events) 63388c2ecf20Sopenharmony_ci return NULL; 63398c2ecf20Sopenharmony_ci 63408c2ecf20Sopenharmony_ci tep->sort_events = events; 63418c2ecf20Sopenharmony_ci 63428c2ecf20Sopenharmony_ci /* the internal events are sorted by id */ 63438c2ecf20Sopenharmony_ci if (sort_type == TEP_EVENT_SORT_ID) { 63448c2ecf20Sopenharmony_ci tep->last_type = sort_type; 63458c2ecf20Sopenharmony_ci return events; 63468c2ecf20Sopenharmony_ci } 63478c2ecf20Sopenharmony_ci } 63488c2ecf20Sopenharmony_ci 63498c2ecf20Sopenharmony_ci list_events_sort(events, tep->nr_events, sort_type); 63508c2ecf20Sopenharmony_ci tep->last_type = sort_type; 63518c2ecf20Sopenharmony_ci 63528c2ecf20Sopenharmony_ci return events; 63538c2ecf20Sopenharmony_ci} 63548c2ecf20Sopenharmony_ci 63558c2ecf20Sopenharmony_ci 63568c2ecf20Sopenharmony_ci/** 63578c2ecf20Sopenharmony_ci * tep_list_events_copy - Thread safe version of tep_list_events() 63588c2ecf20Sopenharmony_ci * @tep: a handle to the tep context 63598c2ecf20Sopenharmony_ci * @sort_type: desired sort order of the events in the array 63608c2ecf20Sopenharmony_ci * 63618c2ecf20Sopenharmony_ci * Returns an array of pointers to all events, sorted by the given 63628c2ecf20Sopenharmony_ci * @sort_type criteria. The last element of the array is NULL. The returned 63638c2ecf20Sopenharmony_ci * array is newly allocated inside the function and must be freed by the caller 63648c2ecf20Sopenharmony_ci */ 63658c2ecf20Sopenharmony_cistruct tep_event **tep_list_events_copy(struct tep_handle *tep, 63668c2ecf20Sopenharmony_ci enum tep_event_sort_type sort_type) 63678c2ecf20Sopenharmony_ci{ 63688c2ecf20Sopenharmony_ci struct tep_event **events; 63698c2ecf20Sopenharmony_ci 63708c2ecf20Sopenharmony_ci if (!tep) 63718c2ecf20Sopenharmony_ci return NULL; 63728c2ecf20Sopenharmony_ci 63738c2ecf20Sopenharmony_ci events = list_events_copy(tep); 63748c2ecf20Sopenharmony_ci if (!events) 63758c2ecf20Sopenharmony_ci return NULL; 63768c2ecf20Sopenharmony_ci 63778c2ecf20Sopenharmony_ci /* the internal events are sorted by id */ 63788c2ecf20Sopenharmony_ci if (sort_type == TEP_EVENT_SORT_ID) 63798c2ecf20Sopenharmony_ci return events; 63808c2ecf20Sopenharmony_ci 63818c2ecf20Sopenharmony_ci list_events_sort(events, tep->nr_events, sort_type); 63828c2ecf20Sopenharmony_ci 63838c2ecf20Sopenharmony_ci return events; 63848c2ecf20Sopenharmony_ci} 63858c2ecf20Sopenharmony_ci 63868c2ecf20Sopenharmony_cistatic struct tep_format_field ** 63878c2ecf20Sopenharmony_ciget_event_fields(const char *type, const char *name, 63888c2ecf20Sopenharmony_ci int count, struct tep_format_field *list) 63898c2ecf20Sopenharmony_ci{ 63908c2ecf20Sopenharmony_ci struct tep_format_field **fields; 63918c2ecf20Sopenharmony_ci struct tep_format_field *field; 63928c2ecf20Sopenharmony_ci int i = 0; 63938c2ecf20Sopenharmony_ci 63948c2ecf20Sopenharmony_ci fields = malloc(sizeof(*fields) * (count + 1)); 63958c2ecf20Sopenharmony_ci if (!fields) 63968c2ecf20Sopenharmony_ci return NULL; 63978c2ecf20Sopenharmony_ci 63988c2ecf20Sopenharmony_ci for (field = list; field; field = field->next) { 63998c2ecf20Sopenharmony_ci fields[i++] = field; 64008c2ecf20Sopenharmony_ci if (i == count + 1) { 64018c2ecf20Sopenharmony_ci do_warning("event %s has more %s fields than specified", 64028c2ecf20Sopenharmony_ci name, type); 64038c2ecf20Sopenharmony_ci i--; 64048c2ecf20Sopenharmony_ci break; 64058c2ecf20Sopenharmony_ci } 64068c2ecf20Sopenharmony_ci } 64078c2ecf20Sopenharmony_ci 64088c2ecf20Sopenharmony_ci if (i != count) 64098c2ecf20Sopenharmony_ci do_warning("event %s has less %s fields than specified", 64108c2ecf20Sopenharmony_ci name, type); 64118c2ecf20Sopenharmony_ci 64128c2ecf20Sopenharmony_ci fields[i] = NULL; 64138c2ecf20Sopenharmony_ci 64148c2ecf20Sopenharmony_ci return fields; 64158c2ecf20Sopenharmony_ci} 64168c2ecf20Sopenharmony_ci 64178c2ecf20Sopenharmony_ci/** 64188c2ecf20Sopenharmony_ci * tep_event_common_fields - return a list of common fields for an event 64198c2ecf20Sopenharmony_ci * @event: the event to return the common fields of. 64208c2ecf20Sopenharmony_ci * 64218c2ecf20Sopenharmony_ci * Returns an allocated array of fields. The last item in the array is NULL. 64228c2ecf20Sopenharmony_ci * The array must be freed with free(). 64238c2ecf20Sopenharmony_ci */ 64248c2ecf20Sopenharmony_cistruct tep_format_field **tep_event_common_fields(struct tep_event *event) 64258c2ecf20Sopenharmony_ci{ 64268c2ecf20Sopenharmony_ci return get_event_fields("common", event->name, 64278c2ecf20Sopenharmony_ci event->format.nr_common, 64288c2ecf20Sopenharmony_ci event->format.common_fields); 64298c2ecf20Sopenharmony_ci} 64308c2ecf20Sopenharmony_ci 64318c2ecf20Sopenharmony_ci/** 64328c2ecf20Sopenharmony_ci * tep_event_fields - return a list of event specific fields for an event 64338c2ecf20Sopenharmony_ci * @event: the event to return the fields of. 64348c2ecf20Sopenharmony_ci * 64358c2ecf20Sopenharmony_ci * Returns an allocated array of fields. The last item in the array is NULL. 64368c2ecf20Sopenharmony_ci * The array must be freed with free(). 64378c2ecf20Sopenharmony_ci */ 64388c2ecf20Sopenharmony_cistruct tep_format_field **tep_event_fields(struct tep_event *event) 64398c2ecf20Sopenharmony_ci{ 64408c2ecf20Sopenharmony_ci return get_event_fields("event", event->name, 64418c2ecf20Sopenharmony_ci event->format.nr_fields, 64428c2ecf20Sopenharmony_ci event->format.fields); 64438c2ecf20Sopenharmony_ci} 64448c2ecf20Sopenharmony_ci 64458c2ecf20Sopenharmony_cistatic void print_fields(struct trace_seq *s, struct tep_print_flag_sym *field) 64468c2ecf20Sopenharmony_ci{ 64478c2ecf20Sopenharmony_ci trace_seq_printf(s, "{ %s, %s }", field->value, field->str); 64488c2ecf20Sopenharmony_ci if (field->next) { 64498c2ecf20Sopenharmony_ci trace_seq_puts(s, ", "); 64508c2ecf20Sopenharmony_ci print_fields(s, field->next); 64518c2ecf20Sopenharmony_ci } 64528c2ecf20Sopenharmony_ci} 64538c2ecf20Sopenharmony_ci 64548c2ecf20Sopenharmony_ci/* for debugging */ 64558c2ecf20Sopenharmony_cistatic void print_args(struct tep_print_arg *args) 64568c2ecf20Sopenharmony_ci{ 64578c2ecf20Sopenharmony_ci int print_paren = 1; 64588c2ecf20Sopenharmony_ci struct trace_seq s; 64598c2ecf20Sopenharmony_ci 64608c2ecf20Sopenharmony_ci switch (args->type) { 64618c2ecf20Sopenharmony_ci case TEP_PRINT_NULL: 64628c2ecf20Sopenharmony_ci printf("null"); 64638c2ecf20Sopenharmony_ci break; 64648c2ecf20Sopenharmony_ci case TEP_PRINT_ATOM: 64658c2ecf20Sopenharmony_ci printf("%s", args->atom.atom); 64668c2ecf20Sopenharmony_ci break; 64678c2ecf20Sopenharmony_ci case TEP_PRINT_FIELD: 64688c2ecf20Sopenharmony_ci printf("REC->%s", args->field.name); 64698c2ecf20Sopenharmony_ci break; 64708c2ecf20Sopenharmony_ci case TEP_PRINT_FLAGS: 64718c2ecf20Sopenharmony_ci printf("__print_flags("); 64728c2ecf20Sopenharmony_ci print_args(args->flags.field); 64738c2ecf20Sopenharmony_ci printf(", %s, ", args->flags.delim); 64748c2ecf20Sopenharmony_ci trace_seq_init(&s); 64758c2ecf20Sopenharmony_ci print_fields(&s, args->flags.flags); 64768c2ecf20Sopenharmony_ci trace_seq_do_printf(&s); 64778c2ecf20Sopenharmony_ci trace_seq_destroy(&s); 64788c2ecf20Sopenharmony_ci printf(")"); 64798c2ecf20Sopenharmony_ci break; 64808c2ecf20Sopenharmony_ci case TEP_PRINT_SYMBOL: 64818c2ecf20Sopenharmony_ci printf("__print_symbolic("); 64828c2ecf20Sopenharmony_ci print_args(args->symbol.field); 64838c2ecf20Sopenharmony_ci printf(", "); 64848c2ecf20Sopenharmony_ci trace_seq_init(&s); 64858c2ecf20Sopenharmony_ci print_fields(&s, args->symbol.symbols); 64868c2ecf20Sopenharmony_ci trace_seq_do_printf(&s); 64878c2ecf20Sopenharmony_ci trace_seq_destroy(&s); 64888c2ecf20Sopenharmony_ci printf(")"); 64898c2ecf20Sopenharmony_ci break; 64908c2ecf20Sopenharmony_ci case TEP_PRINT_HEX: 64918c2ecf20Sopenharmony_ci printf("__print_hex("); 64928c2ecf20Sopenharmony_ci print_args(args->hex.field); 64938c2ecf20Sopenharmony_ci printf(", "); 64948c2ecf20Sopenharmony_ci print_args(args->hex.size); 64958c2ecf20Sopenharmony_ci printf(")"); 64968c2ecf20Sopenharmony_ci break; 64978c2ecf20Sopenharmony_ci case TEP_PRINT_HEX_STR: 64988c2ecf20Sopenharmony_ci printf("__print_hex_str("); 64998c2ecf20Sopenharmony_ci print_args(args->hex.field); 65008c2ecf20Sopenharmony_ci printf(", "); 65018c2ecf20Sopenharmony_ci print_args(args->hex.size); 65028c2ecf20Sopenharmony_ci printf(")"); 65038c2ecf20Sopenharmony_ci break; 65048c2ecf20Sopenharmony_ci case TEP_PRINT_INT_ARRAY: 65058c2ecf20Sopenharmony_ci printf("__print_array("); 65068c2ecf20Sopenharmony_ci print_args(args->int_array.field); 65078c2ecf20Sopenharmony_ci printf(", "); 65088c2ecf20Sopenharmony_ci print_args(args->int_array.count); 65098c2ecf20Sopenharmony_ci printf(", "); 65108c2ecf20Sopenharmony_ci print_args(args->int_array.el_size); 65118c2ecf20Sopenharmony_ci printf(")"); 65128c2ecf20Sopenharmony_ci break; 65138c2ecf20Sopenharmony_ci case TEP_PRINT_STRING: 65148c2ecf20Sopenharmony_ci case TEP_PRINT_BSTRING: 65158c2ecf20Sopenharmony_ci printf("__get_str(%s)", args->string.string); 65168c2ecf20Sopenharmony_ci break; 65178c2ecf20Sopenharmony_ci case TEP_PRINT_BITMASK: 65188c2ecf20Sopenharmony_ci printf("__get_bitmask(%s)", args->bitmask.bitmask); 65198c2ecf20Sopenharmony_ci break; 65208c2ecf20Sopenharmony_ci case TEP_PRINT_TYPE: 65218c2ecf20Sopenharmony_ci printf("(%s)", args->typecast.type); 65228c2ecf20Sopenharmony_ci print_args(args->typecast.item); 65238c2ecf20Sopenharmony_ci break; 65248c2ecf20Sopenharmony_ci case TEP_PRINT_OP: 65258c2ecf20Sopenharmony_ci if (strcmp(args->op.op, ":") == 0) 65268c2ecf20Sopenharmony_ci print_paren = 0; 65278c2ecf20Sopenharmony_ci if (print_paren) 65288c2ecf20Sopenharmony_ci printf("("); 65298c2ecf20Sopenharmony_ci print_args(args->op.left); 65308c2ecf20Sopenharmony_ci printf(" %s ", args->op.op); 65318c2ecf20Sopenharmony_ci print_args(args->op.right); 65328c2ecf20Sopenharmony_ci if (print_paren) 65338c2ecf20Sopenharmony_ci printf(")"); 65348c2ecf20Sopenharmony_ci break; 65358c2ecf20Sopenharmony_ci default: 65368c2ecf20Sopenharmony_ci /* we should warn... */ 65378c2ecf20Sopenharmony_ci return; 65388c2ecf20Sopenharmony_ci } 65398c2ecf20Sopenharmony_ci if (args->next) { 65408c2ecf20Sopenharmony_ci printf("\n"); 65418c2ecf20Sopenharmony_ci print_args(args->next); 65428c2ecf20Sopenharmony_ci } 65438c2ecf20Sopenharmony_ci} 65448c2ecf20Sopenharmony_ci 65458c2ecf20Sopenharmony_cistatic void parse_header_field(const char *field, 65468c2ecf20Sopenharmony_ci int *offset, int *size, int mandatory) 65478c2ecf20Sopenharmony_ci{ 65488c2ecf20Sopenharmony_ci unsigned long long save_input_buf_ptr; 65498c2ecf20Sopenharmony_ci unsigned long long save_input_buf_siz; 65508c2ecf20Sopenharmony_ci char *token; 65518c2ecf20Sopenharmony_ci int type; 65528c2ecf20Sopenharmony_ci 65538c2ecf20Sopenharmony_ci save_input_buf_ptr = input_buf_ptr; 65548c2ecf20Sopenharmony_ci save_input_buf_siz = input_buf_siz; 65558c2ecf20Sopenharmony_ci 65568c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_ITEM, "field") < 0) 65578c2ecf20Sopenharmony_ci return; 65588c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ":") < 0) 65598c2ecf20Sopenharmony_ci return; 65608c2ecf20Sopenharmony_ci 65618c2ecf20Sopenharmony_ci /* type */ 65628c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) 65638c2ecf20Sopenharmony_ci goto fail; 65648c2ecf20Sopenharmony_ci free_token(token); 65658c2ecf20Sopenharmony_ci 65668c2ecf20Sopenharmony_ci /* 65678c2ecf20Sopenharmony_ci * If this is not a mandatory field, then test it first. 65688c2ecf20Sopenharmony_ci */ 65698c2ecf20Sopenharmony_ci if (mandatory) { 65708c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_ITEM, field) < 0) 65718c2ecf20Sopenharmony_ci return; 65728c2ecf20Sopenharmony_ci } else { 65738c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) 65748c2ecf20Sopenharmony_ci goto fail; 65758c2ecf20Sopenharmony_ci if (strcmp(token, field) != 0) 65768c2ecf20Sopenharmony_ci goto discard; 65778c2ecf20Sopenharmony_ci free_token(token); 65788c2ecf20Sopenharmony_ci } 65798c2ecf20Sopenharmony_ci 65808c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ";") < 0) 65818c2ecf20Sopenharmony_ci return; 65828c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_ITEM, "offset") < 0) 65838c2ecf20Sopenharmony_ci return; 65848c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ":") < 0) 65858c2ecf20Sopenharmony_ci return; 65868c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) 65878c2ecf20Sopenharmony_ci goto fail; 65888c2ecf20Sopenharmony_ci *offset = atoi(token); 65898c2ecf20Sopenharmony_ci free_token(token); 65908c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ";") < 0) 65918c2ecf20Sopenharmony_ci return; 65928c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_ITEM, "size") < 0) 65938c2ecf20Sopenharmony_ci return; 65948c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ":") < 0) 65958c2ecf20Sopenharmony_ci return; 65968c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) 65978c2ecf20Sopenharmony_ci goto fail; 65988c2ecf20Sopenharmony_ci *size = atoi(token); 65998c2ecf20Sopenharmony_ci free_token(token); 66008c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ";") < 0) 66018c2ecf20Sopenharmony_ci return; 66028c2ecf20Sopenharmony_ci type = read_token(&token); 66038c2ecf20Sopenharmony_ci if (type != TEP_EVENT_NEWLINE) { 66048c2ecf20Sopenharmony_ci /* newer versions of the kernel have a "signed" type */ 66058c2ecf20Sopenharmony_ci if (type != TEP_EVENT_ITEM) 66068c2ecf20Sopenharmony_ci goto fail; 66078c2ecf20Sopenharmony_ci 66088c2ecf20Sopenharmony_ci if (strcmp(token, "signed") != 0) 66098c2ecf20Sopenharmony_ci goto fail; 66108c2ecf20Sopenharmony_ci 66118c2ecf20Sopenharmony_ci free_token(token); 66128c2ecf20Sopenharmony_ci 66138c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ":") < 0) 66148c2ecf20Sopenharmony_ci return; 66158c2ecf20Sopenharmony_ci 66168c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_ITEM, &token)) 66178c2ecf20Sopenharmony_ci goto fail; 66188c2ecf20Sopenharmony_ci 66198c2ecf20Sopenharmony_ci free_token(token); 66208c2ecf20Sopenharmony_ci if (read_expected(TEP_EVENT_OP, ";") < 0) 66218c2ecf20Sopenharmony_ci return; 66228c2ecf20Sopenharmony_ci 66238c2ecf20Sopenharmony_ci if (read_expect_type(TEP_EVENT_NEWLINE, &token)) 66248c2ecf20Sopenharmony_ci goto fail; 66258c2ecf20Sopenharmony_ci } 66268c2ecf20Sopenharmony_ci fail: 66278c2ecf20Sopenharmony_ci free_token(token); 66288c2ecf20Sopenharmony_ci return; 66298c2ecf20Sopenharmony_ci 66308c2ecf20Sopenharmony_ci discard: 66318c2ecf20Sopenharmony_ci input_buf_ptr = save_input_buf_ptr; 66328c2ecf20Sopenharmony_ci input_buf_siz = save_input_buf_siz; 66338c2ecf20Sopenharmony_ci *offset = 0; 66348c2ecf20Sopenharmony_ci *size = 0; 66358c2ecf20Sopenharmony_ci free_token(token); 66368c2ecf20Sopenharmony_ci} 66378c2ecf20Sopenharmony_ci 66388c2ecf20Sopenharmony_ci/** 66398c2ecf20Sopenharmony_ci * tep_parse_header_page - parse the data stored in the header page 66408c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 66418c2ecf20Sopenharmony_ci * @buf: the buffer storing the header page format string 66428c2ecf20Sopenharmony_ci * @size: the size of @buf 66438c2ecf20Sopenharmony_ci * @long_size: the long size to use if there is no header 66448c2ecf20Sopenharmony_ci * 66458c2ecf20Sopenharmony_ci * This parses the header page format for information on the 66468c2ecf20Sopenharmony_ci * ring buffer used. The @buf should be copied from 66478c2ecf20Sopenharmony_ci * 66488c2ecf20Sopenharmony_ci * /sys/kernel/debug/tracing/events/header_page 66498c2ecf20Sopenharmony_ci */ 66508c2ecf20Sopenharmony_ciint tep_parse_header_page(struct tep_handle *tep, char *buf, unsigned long size, 66518c2ecf20Sopenharmony_ci int long_size) 66528c2ecf20Sopenharmony_ci{ 66538c2ecf20Sopenharmony_ci int ignore; 66548c2ecf20Sopenharmony_ci 66558c2ecf20Sopenharmony_ci if (!size) { 66568c2ecf20Sopenharmony_ci /* 66578c2ecf20Sopenharmony_ci * Old kernels did not have header page info. 66588c2ecf20Sopenharmony_ci * Sorry but we just use what we find here in user space. 66598c2ecf20Sopenharmony_ci */ 66608c2ecf20Sopenharmony_ci tep->header_page_ts_size = sizeof(long long); 66618c2ecf20Sopenharmony_ci tep->header_page_size_size = long_size; 66628c2ecf20Sopenharmony_ci tep->header_page_data_offset = sizeof(long long) + long_size; 66638c2ecf20Sopenharmony_ci tep->old_format = 1; 66648c2ecf20Sopenharmony_ci return -1; 66658c2ecf20Sopenharmony_ci } 66668c2ecf20Sopenharmony_ci init_input_buf(buf, size); 66678c2ecf20Sopenharmony_ci 66688c2ecf20Sopenharmony_ci parse_header_field("timestamp", &tep->header_page_ts_offset, 66698c2ecf20Sopenharmony_ci &tep->header_page_ts_size, 1); 66708c2ecf20Sopenharmony_ci parse_header_field("commit", &tep->header_page_size_offset, 66718c2ecf20Sopenharmony_ci &tep->header_page_size_size, 1); 66728c2ecf20Sopenharmony_ci parse_header_field("overwrite", &tep->header_page_overwrite, 66738c2ecf20Sopenharmony_ci &ignore, 0); 66748c2ecf20Sopenharmony_ci parse_header_field("data", &tep->header_page_data_offset, 66758c2ecf20Sopenharmony_ci &tep->header_page_data_size, 1); 66768c2ecf20Sopenharmony_ci 66778c2ecf20Sopenharmony_ci return 0; 66788c2ecf20Sopenharmony_ci} 66798c2ecf20Sopenharmony_ci 66808c2ecf20Sopenharmony_cistatic int event_matches(struct tep_event *event, 66818c2ecf20Sopenharmony_ci int id, const char *sys_name, 66828c2ecf20Sopenharmony_ci const char *event_name) 66838c2ecf20Sopenharmony_ci{ 66848c2ecf20Sopenharmony_ci if (id >= 0 && id != event->id) 66858c2ecf20Sopenharmony_ci return 0; 66868c2ecf20Sopenharmony_ci 66878c2ecf20Sopenharmony_ci if (event_name && (strcmp(event_name, event->name) != 0)) 66888c2ecf20Sopenharmony_ci return 0; 66898c2ecf20Sopenharmony_ci 66908c2ecf20Sopenharmony_ci if (sys_name && (strcmp(sys_name, event->system) != 0)) 66918c2ecf20Sopenharmony_ci return 0; 66928c2ecf20Sopenharmony_ci 66938c2ecf20Sopenharmony_ci return 1; 66948c2ecf20Sopenharmony_ci} 66958c2ecf20Sopenharmony_ci 66968c2ecf20Sopenharmony_cistatic void free_handler(struct event_handler *handle) 66978c2ecf20Sopenharmony_ci{ 66988c2ecf20Sopenharmony_ci free((void *)handle->sys_name); 66998c2ecf20Sopenharmony_ci free((void *)handle->event_name); 67008c2ecf20Sopenharmony_ci free(handle); 67018c2ecf20Sopenharmony_ci} 67028c2ecf20Sopenharmony_ci 67038c2ecf20Sopenharmony_cistatic int find_event_handle(struct tep_handle *tep, struct tep_event *event) 67048c2ecf20Sopenharmony_ci{ 67058c2ecf20Sopenharmony_ci struct event_handler *handle, **next; 67068c2ecf20Sopenharmony_ci 67078c2ecf20Sopenharmony_ci for (next = &tep->handlers; *next; 67088c2ecf20Sopenharmony_ci next = &(*next)->next) { 67098c2ecf20Sopenharmony_ci handle = *next; 67108c2ecf20Sopenharmony_ci if (event_matches(event, handle->id, 67118c2ecf20Sopenharmony_ci handle->sys_name, 67128c2ecf20Sopenharmony_ci handle->event_name)) 67138c2ecf20Sopenharmony_ci break; 67148c2ecf20Sopenharmony_ci } 67158c2ecf20Sopenharmony_ci 67168c2ecf20Sopenharmony_ci if (!(*next)) 67178c2ecf20Sopenharmony_ci return 0; 67188c2ecf20Sopenharmony_ci 67198c2ecf20Sopenharmony_ci pr_stat("overriding event (%d) %s:%s with new print handler", 67208c2ecf20Sopenharmony_ci event->id, event->system, event->name); 67218c2ecf20Sopenharmony_ci 67228c2ecf20Sopenharmony_ci event->handler = handle->func; 67238c2ecf20Sopenharmony_ci event->context = handle->context; 67248c2ecf20Sopenharmony_ci 67258c2ecf20Sopenharmony_ci *next = handle->next; 67268c2ecf20Sopenharmony_ci free_handler(handle); 67278c2ecf20Sopenharmony_ci 67288c2ecf20Sopenharmony_ci return 1; 67298c2ecf20Sopenharmony_ci} 67308c2ecf20Sopenharmony_ci 67318c2ecf20Sopenharmony_ci/** 67328c2ecf20Sopenharmony_ci * parse_format - parse the event format 67338c2ecf20Sopenharmony_ci * @buf: the buffer storing the event format string 67348c2ecf20Sopenharmony_ci * @size: the size of @buf 67358c2ecf20Sopenharmony_ci * @sys: the system the event belongs to 67368c2ecf20Sopenharmony_ci * 67378c2ecf20Sopenharmony_ci * This parses the event format and creates an event structure 67388c2ecf20Sopenharmony_ci * to quickly parse raw data for a given event. 67398c2ecf20Sopenharmony_ci * 67408c2ecf20Sopenharmony_ci * These files currently come from: 67418c2ecf20Sopenharmony_ci * 67428c2ecf20Sopenharmony_ci * /sys/kernel/debug/tracing/events/.../.../format 67438c2ecf20Sopenharmony_ci */ 67448c2ecf20Sopenharmony_cistatic enum tep_errno parse_format(struct tep_event **eventp, 67458c2ecf20Sopenharmony_ci struct tep_handle *tep, const char *buf, 67468c2ecf20Sopenharmony_ci unsigned long size, const char *sys) 67478c2ecf20Sopenharmony_ci{ 67488c2ecf20Sopenharmony_ci struct tep_event *event; 67498c2ecf20Sopenharmony_ci int ret; 67508c2ecf20Sopenharmony_ci 67518c2ecf20Sopenharmony_ci init_input_buf(buf, size); 67528c2ecf20Sopenharmony_ci 67538c2ecf20Sopenharmony_ci *eventp = event = alloc_event(); 67548c2ecf20Sopenharmony_ci if (!event) 67558c2ecf20Sopenharmony_ci return TEP_ERRNO__MEM_ALLOC_FAILED; 67568c2ecf20Sopenharmony_ci 67578c2ecf20Sopenharmony_ci event->name = event_read_name(); 67588c2ecf20Sopenharmony_ci if (!event->name) { 67598c2ecf20Sopenharmony_ci /* Bad event? */ 67608c2ecf20Sopenharmony_ci ret = TEP_ERRNO__MEM_ALLOC_FAILED; 67618c2ecf20Sopenharmony_ci goto event_alloc_failed; 67628c2ecf20Sopenharmony_ci } 67638c2ecf20Sopenharmony_ci 67648c2ecf20Sopenharmony_ci if (strcmp(sys, "ftrace") == 0) { 67658c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_ISFTRACE; 67668c2ecf20Sopenharmony_ci 67678c2ecf20Sopenharmony_ci if (strcmp(event->name, "bprint") == 0) 67688c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_ISBPRINT; 67698c2ecf20Sopenharmony_ci } 67708c2ecf20Sopenharmony_ci 67718c2ecf20Sopenharmony_ci event->id = event_read_id(); 67728c2ecf20Sopenharmony_ci if (event->id < 0) { 67738c2ecf20Sopenharmony_ci ret = TEP_ERRNO__READ_ID_FAILED; 67748c2ecf20Sopenharmony_ci /* 67758c2ecf20Sopenharmony_ci * This isn't an allocation error actually. 67768c2ecf20Sopenharmony_ci * But as the ID is critical, just bail out. 67778c2ecf20Sopenharmony_ci */ 67788c2ecf20Sopenharmony_ci goto event_alloc_failed; 67798c2ecf20Sopenharmony_ci } 67808c2ecf20Sopenharmony_ci 67818c2ecf20Sopenharmony_ci event->system = strdup(sys); 67828c2ecf20Sopenharmony_ci if (!event->system) { 67838c2ecf20Sopenharmony_ci ret = TEP_ERRNO__MEM_ALLOC_FAILED; 67848c2ecf20Sopenharmony_ci goto event_alloc_failed; 67858c2ecf20Sopenharmony_ci } 67868c2ecf20Sopenharmony_ci 67878c2ecf20Sopenharmony_ci /* Add tep to event so that it can be referenced */ 67888c2ecf20Sopenharmony_ci event->tep = tep; 67898c2ecf20Sopenharmony_ci 67908c2ecf20Sopenharmony_ci ret = event_read_format(event); 67918c2ecf20Sopenharmony_ci if (ret < 0) { 67928c2ecf20Sopenharmony_ci ret = TEP_ERRNO__READ_FORMAT_FAILED; 67938c2ecf20Sopenharmony_ci goto event_parse_failed; 67948c2ecf20Sopenharmony_ci } 67958c2ecf20Sopenharmony_ci 67968c2ecf20Sopenharmony_ci /* 67978c2ecf20Sopenharmony_ci * If the event has an override, don't print warnings if the event 67988c2ecf20Sopenharmony_ci * print format fails to parse. 67998c2ecf20Sopenharmony_ci */ 68008c2ecf20Sopenharmony_ci if (tep && find_event_handle(tep, event)) 68018c2ecf20Sopenharmony_ci show_warning = 0; 68028c2ecf20Sopenharmony_ci 68038c2ecf20Sopenharmony_ci ret = event_read_print(event); 68048c2ecf20Sopenharmony_ci show_warning = 1; 68058c2ecf20Sopenharmony_ci 68068c2ecf20Sopenharmony_ci if (ret < 0) { 68078c2ecf20Sopenharmony_ci ret = TEP_ERRNO__READ_PRINT_FAILED; 68088c2ecf20Sopenharmony_ci goto event_parse_failed; 68098c2ecf20Sopenharmony_ci } 68108c2ecf20Sopenharmony_ci 68118c2ecf20Sopenharmony_ci if (!ret && (event->flags & TEP_EVENT_FL_ISFTRACE)) { 68128c2ecf20Sopenharmony_ci struct tep_format_field *field; 68138c2ecf20Sopenharmony_ci struct tep_print_arg *arg, **list; 68148c2ecf20Sopenharmony_ci 68158c2ecf20Sopenharmony_ci /* old ftrace had no args */ 68168c2ecf20Sopenharmony_ci list = &event->print_fmt.args; 68178c2ecf20Sopenharmony_ci for (field = event->format.fields; field; field = field->next) { 68188c2ecf20Sopenharmony_ci arg = alloc_arg(); 68198c2ecf20Sopenharmony_ci if (!arg) { 68208c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_FAILED; 68218c2ecf20Sopenharmony_ci return TEP_ERRNO__OLD_FTRACE_ARG_FAILED; 68228c2ecf20Sopenharmony_ci } 68238c2ecf20Sopenharmony_ci arg->type = TEP_PRINT_FIELD; 68248c2ecf20Sopenharmony_ci arg->field.name = strdup(field->name); 68258c2ecf20Sopenharmony_ci if (!arg->field.name) { 68268c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_FAILED; 68278c2ecf20Sopenharmony_ci free_arg(arg); 68288c2ecf20Sopenharmony_ci return TEP_ERRNO__OLD_FTRACE_ARG_FAILED; 68298c2ecf20Sopenharmony_ci } 68308c2ecf20Sopenharmony_ci arg->field.field = field; 68318c2ecf20Sopenharmony_ci *list = arg; 68328c2ecf20Sopenharmony_ci list = &arg->next; 68338c2ecf20Sopenharmony_ci } 68348c2ecf20Sopenharmony_ci } 68358c2ecf20Sopenharmony_ci 68368c2ecf20Sopenharmony_ci if (!(event->flags & TEP_EVENT_FL_ISBPRINT)) 68378c2ecf20Sopenharmony_ci event->print_fmt.print_cache = parse_args(event, 68388c2ecf20Sopenharmony_ci event->print_fmt.format, 68398c2ecf20Sopenharmony_ci event->print_fmt.args); 68408c2ecf20Sopenharmony_ci 68418c2ecf20Sopenharmony_ci return 0; 68428c2ecf20Sopenharmony_ci 68438c2ecf20Sopenharmony_ci event_parse_failed: 68448c2ecf20Sopenharmony_ci event->flags |= TEP_EVENT_FL_FAILED; 68458c2ecf20Sopenharmony_ci return ret; 68468c2ecf20Sopenharmony_ci 68478c2ecf20Sopenharmony_ci event_alloc_failed: 68488c2ecf20Sopenharmony_ci free(event->system); 68498c2ecf20Sopenharmony_ci free(event->name); 68508c2ecf20Sopenharmony_ci free(event); 68518c2ecf20Sopenharmony_ci *eventp = NULL; 68528c2ecf20Sopenharmony_ci return ret; 68538c2ecf20Sopenharmony_ci} 68548c2ecf20Sopenharmony_ci 68558c2ecf20Sopenharmony_cistatic enum tep_errno 68568c2ecf20Sopenharmony_ci__parse_event(struct tep_handle *tep, 68578c2ecf20Sopenharmony_ci struct tep_event **eventp, 68588c2ecf20Sopenharmony_ci const char *buf, unsigned long size, 68598c2ecf20Sopenharmony_ci const char *sys) 68608c2ecf20Sopenharmony_ci{ 68618c2ecf20Sopenharmony_ci int ret = parse_format(eventp, tep, buf, size, sys); 68628c2ecf20Sopenharmony_ci struct tep_event *event = *eventp; 68638c2ecf20Sopenharmony_ci 68648c2ecf20Sopenharmony_ci if (event == NULL) 68658c2ecf20Sopenharmony_ci return ret; 68668c2ecf20Sopenharmony_ci 68678c2ecf20Sopenharmony_ci if (tep && add_event(tep, event)) { 68688c2ecf20Sopenharmony_ci ret = TEP_ERRNO__MEM_ALLOC_FAILED; 68698c2ecf20Sopenharmony_ci goto event_add_failed; 68708c2ecf20Sopenharmony_ci } 68718c2ecf20Sopenharmony_ci 68728c2ecf20Sopenharmony_ci#define PRINT_ARGS 0 68738c2ecf20Sopenharmony_ci if (PRINT_ARGS && event->print_fmt.args) 68748c2ecf20Sopenharmony_ci print_args(event->print_fmt.args); 68758c2ecf20Sopenharmony_ci 68768c2ecf20Sopenharmony_ci return 0; 68778c2ecf20Sopenharmony_ci 68788c2ecf20Sopenharmony_cievent_add_failed: 68798c2ecf20Sopenharmony_ci free_tep_event(event); 68808c2ecf20Sopenharmony_ci return ret; 68818c2ecf20Sopenharmony_ci} 68828c2ecf20Sopenharmony_ci 68838c2ecf20Sopenharmony_ci/** 68848c2ecf20Sopenharmony_ci * tep_parse_format - parse the event format 68858c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 68868c2ecf20Sopenharmony_ci * @eventp: returned format 68878c2ecf20Sopenharmony_ci * @buf: the buffer storing the event format string 68888c2ecf20Sopenharmony_ci * @size: the size of @buf 68898c2ecf20Sopenharmony_ci * @sys: the system the event belongs to 68908c2ecf20Sopenharmony_ci * 68918c2ecf20Sopenharmony_ci * This parses the event format and creates an event structure 68928c2ecf20Sopenharmony_ci * to quickly parse raw data for a given event. 68938c2ecf20Sopenharmony_ci * 68948c2ecf20Sopenharmony_ci * These files currently come from: 68958c2ecf20Sopenharmony_ci * 68968c2ecf20Sopenharmony_ci * /sys/kernel/debug/tracing/events/.../.../format 68978c2ecf20Sopenharmony_ci */ 68988c2ecf20Sopenharmony_cienum tep_errno tep_parse_format(struct tep_handle *tep, 68998c2ecf20Sopenharmony_ci struct tep_event **eventp, 69008c2ecf20Sopenharmony_ci const char *buf, 69018c2ecf20Sopenharmony_ci unsigned long size, const char *sys) 69028c2ecf20Sopenharmony_ci{ 69038c2ecf20Sopenharmony_ci return __parse_event(tep, eventp, buf, size, sys); 69048c2ecf20Sopenharmony_ci} 69058c2ecf20Sopenharmony_ci 69068c2ecf20Sopenharmony_ci/** 69078c2ecf20Sopenharmony_ci * tep_parse_event - parse the event format 69088c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 69098c2ecf20Sopenharmony_ci * @buf: the buffer storing the event format string 69108c2ecf20Sopenharmony_ci * @size: the size of @buf 69118c2ecf20Sopenharmony_ci * @sys: the system the event belongs to 69128c2ecf20Sopenharmony_ci * 69138c2ecf20Sopenharmony_ci * This parses the event format and creates an event structure 69148c2ecf20Sopenharmony_ci * to quickly parse raw data for a given event. 69158c2ecf20Sopenharmony_ci * 69168c2ecf20Sopenharmony_ci * These files currently come from: 69178c2ecf20Sopenharmony_ci * 69188c2ecf20Sopenharmony_ci * /sys/kernel/debug/tracing/events/.../.../format 69198c2ecf20Sopenharmony_ci */ 69208c2ecf20Sopenharmony_cienum tep_errno tep_parse_event(struct tep_handle *tep, const char *buf, 69218c2ecf20Sopenharmony_ci unsigned long size, const char *sys) 69228c2ecf20Sopenharmony_ci{ 69238c2ecf20Sopenharmony_ci struct tep_event *event = NULL; 69248c2ecf20Sopenharmony_ci return __parse_event(tep, &event, buf, size, sys); 69258c2ecf20Sopenharmony_ci} 69268c2ecf20Sopenharmony_ci 69278c2ecf20Sopenharmony_ciint get_field_val(struct trace_seq *s, struct tep_format_field *field, 69288c2ecf20Sopenharmony_ci const char *name, struct tep_record *record, 69298c2ecf20Sopenharmony_ci unsigned long long *val, int err) 69308c2ecf20Sopenharmony_ci{ 69318c2ecf20Sopenharmony_ci if (!field) { 69328c2ecf20Sopenharmony_ci if (err) 69338c2ecf20Sopenharmony_ci trace_seq_printf(s, "<CANT FIND FIELD %s>", name); 69348c2ecf20Sopenharmony_ci return -1; 69358c2ecf20Sopenharmony_ci } 69368c2ecf20Sopenharmony_ci 69378c2ecf20Sopenharmony_ci if (tep_read_number_field(field, record->data, val)) { 69388c2ecf20Sopenharmony_ci if (err) 69398c2ecf20Sopenharmony_ci trace_seq_printf(s, " %s=INVALID", name); 69408c2ecf20Sopenharmony_ci return -1; 69418c2ecf20Sopenharmony_ci } 69428c2ecf20Sopenharmony_ci 69438c2ecf20Sopenharmony_ci return 0; 69448c2ecf20Sopenharmony_ci} 69458c2ecf20Sopenharmony_ci 69468c2ecf20Sopenharmony_ci/** 69478c2ecf20Sopenharmony_ci * tep_get_field_raw - return the raw pointer into the data field 69488c2ecf20Sopenharmony_ci * @s: The seq to print to on error 69498c2ecf20Sopenharmony_ci * @event: the event that the field is for 69508c2ecf20Sopenharmony_ci * @name: The name of the field 69518c2ecf20Sopenharmony_ci * @record: The record with the field name. 69528c2ecf20Sopenharmony_ci * @len: place to store the field length. 69538c2ecf20Sopenharmony_ci * @err: print default error if failed. 69548c2ecf20Sopenharmony_ci * 69558c2ecf20Sopenharmony_ci * Returns a pointer into record->data of the field and places 69568c2ecf20Sopenharmony_ci * the length of the field in @len. 69578c2ecf20Sopenharmony_ci * 69588c2ecf20Sopenharmony_ci * On failure, it returns NULL. 69598c2ecf20Sopenharmony_ci */ 69608c2ecf20Sopenharmony_civoid *tep_get_field_raw(struct trace_seq *s, struct tep_event *event, 69618c2ecf20Sopenharmony_ci const char *name, struct tep_record *record, 69628c2ecf20Sopenharmony_ci int *len, int err) 69638c2ecf20Sopenharmony_ci{ 69648c2ecf20Sopenharmony_ci struct tep_format_field *field; 69658c2ecf20Sopenharmony_ci void *data = record->data; 69668c2ecf20Sopenharmony_ci unsigned offset; 69678c2ecf20Sopenharmony_ci int dummy; 69688c2ecf20Sopenharmony_ci 69698c2ecf20Sopenharmony_ci if (!event) 69708c2ecf20Sopenharmony_ci return NULL; 69718c2ecf20Sopenharmony_ci 69728c2ecf20Sopenharmony_ci field = tep_find_field(event, name); 69738c2ecf20Sopenharmony_ci 69748c2ecf20Sopenharmony_ci if (!field) { 69758c2ecf20Sopenharmony_ci if (err) 69768c2ecf20Sopenharmony_ci trace_seq_printf(s, "<CANT FIND FIELD %s>", name); 69778c2ecf20Sopenharmony_ci return NULL; 69788c2ecf20Sopenharmony_ci } 69798c2ecf20Sopenharmony_ci 69808c2ecf20Sopenharmony_ci /* Allow @len to be NULL */ 69818c2ecf20Sopenharmony_ci if (!len) 69828c2ecf20Sopenharmony_ci len = &dummy; 69838c2ecf20Sopenharmony_ci 69848c2ecf20Sopenharmony_ci offset = field->offset; 69858c2ecf20Sopenharmony_ci if (field->flags & TEP_FIELD_IS_DYNAMIC) { 69868c2ecf20Sopenharmony_ci offset = tep_read_number(event->tep, 69878c2ecf20Sopenharmony_ci data + offset, field->size); 69888c2ecf20Sopenharmony_ci *len = offset >> 16; 69898c2ecf20Sopenharmony_ci offset &= 0xffff; 69908c2ecf20Sopenharmony_ci } else 69918c2ecf20Sopenharmony_ci *len = field->size; 69928c2ecf20Sopenharmony_ci 69938c2ecf20Sopenharmony_ci return data + offset; 69948c2ecf20Sopenharmony_ci} 69958c2ecf20Sopenharmony_ci 69968c2ecf20Sopenharmony_ci/** 69978c2ecf20Sopenharmony_ci * tep_get_field_val - find a field and return its value 69988c2ecf20Sopenharmony_ci * @s: The seq to print to on error 69998c2ecf20Sopenharmony_ci * @event: the event that the field is for 70008c2ecf20Sopenharmony_ci * @name: The name of the field 70018c2ecf20Sopenharmony_ci * @record: The record with the field name. 70028c2ecf20Sopenharmony_ci * @val: place to store the value of the field. 70038c2ecf20Sopenharmony_ci * @err: print default error if failed. 70048c2ecf20Sopenharmony_ci * 70058c2ecf20Sopenharmony_ci * Returns 0 on success -1 on field not found. 70068c2ecf20Sopenharmony_ci */ 70078c2ecf20Sopenharmony_ciint tep_get_field_val(struct trace_seq *s, struct tep_event *event, 70088c2ecf20Sopenharmony_ci const char *name, struct tep_record *record, 70098c2ecf20Sopenharmony_ci unsigned long long *val, int err) 70108c2ecf20Sopenharmony_ci{ 70118c2ecf20Sopenharmony_ci struct tep_format_field *field; 70128c2ecf20Sopenharmony_ci 70138c2ecf20Sopenharmony_ci if (!event) 70148c2ecf20Sopenharmony_ci return -1; 70158c2ecf20Sopenharmony_ci 70168c2ecf20Sopenharmony_ci field = tep_find_field(event, name); 70178c2ecf20Sopenharmony_ci 70188c2ecf20Sopenharmony_ci return get_field_val(s, field, name, record, val, err); 70198c2ecf20Sopenharmony_ci} 70208c2ecf20Sopenharmony_ci 70218c2ecf20Sopenharmony_ci/** 70228c2ecf20Sopenharmony_ci * tep_get_common_field_val - find a common field and return its value 70238c2ecf20Sopenharmony_ci * @s: The seq to print to on error 70248c2ecf20Sopenharmony_ci * @event: the event that the field is for 70258c2ecf20Sopenharmony_ci * @name: The name of the field 70268c2ecf20Sopenharmony_ci * @record: The record with the field name. 70278c2ecf20Sopenharmony_ci * @val: place to store the value of the field. 70288c2ecf20Sopenharmony_ci * @err: print default error if failed. 70298c2ecf20Sopenharmony_ci * 70308c2ecf20Sopenharmony_ci * Returns 0 on success -1 on field not found. 70318c2ecf20Sopenharmony_ci */ 70328c2ecf20Sopenharmony_ciint tep_get_common_field_val(struct trace_seq *s, struct tep_event *event, 70338c2ecf20Sopenharmony_ci const char *name, struct tep_record *record, 70348c2ecf20Sopenharmony_ci unsigned long long *val, int err) 70358c2ecf20Sopenharmony_ci{ 70368c2ecf20Sopenharmony_ci struct tep_format_field *field; 70378c2ecf20Sopenharmony_ci 70388c2ecf20Sopenharmony_ci if (!event) 70398c2ecf20Sopenharmony_ci return -1; 70408c2ecf20Sopenharmony_ci 70418c2ecf20Sopenharmony_ci field = tep_find_common_field(event, name); 70428c2ecf20Sopenharmony_ci 70438c2ecf20Sopenharmony_ci return get_field_val(s, field, name, record, val, err); 70448c2ecf20Sopenharmony_ci} 70458c2ecf20Sopenharmony_ci 70468c2ecf20Sopenharmony_ci/** 70478c2ecf20Sopenharmony_ci * tep_get_any_field_val - find a any field and return its value 70488c2ecf20Sopenharmony_ci * @s: The seq to print to on error 70498c2ecf20Sopenharmony_ci * @event: the event that the field is for 70508c2ecf20Sopenharmony_ci * @name: The name of the field 70518c2ecf20Sopenharmony_ci * @record: The record with the field name. 70528c2ecf20Sopenharmony_ci * @val: place to store the value of the field. 70538c2ecf20Sopenharmony_ci * @err: print default error if failed. 70548c2ecf20Sopenharmony_ci * 70558c2ecf20Sopenharmony_ci * Returns 0 on success -1 on field not found. 70568c2ecf20Sopenharmony_ci */ 70578c2ecf20Sopenharmony_ciint tep_get_any_field_val(struct trace_seq *s, struct tep_event *event, 70588c2ecf20Sopenharmony_ci const char *name, struct tep_record *record, 70598c2ecf20Sopenharmony_ci unsigned long long *val, int err) 70608c2ecf20Sopenharmony_ci{ 70618c2ecf20Sopenharmony_ci struct tep_format_field *field; 70628c2ecf20Sopenharmony_ci 70638c2ecf20Sopenharmony_ci if (!event) 70648c2ecf20Sopenharmony_ci return -1; 70658c2ecf20Sopenharmony_ci 70668c2ecf20Sopenharmony_ci field = tep_find_any_field(event, name); 70678c2ecf20Sopenharmony_ci 70688c2ecf20Sopenharmony_ci return get_field_val(s, field, name, record, val, err); 70698c2ecf20Sopenharmony_ci} 70708c2ecf20Sopenharmony_ci 70718c2ecf20Sopenharmony_ci/** 70728c2ecf20Sopenharmony_ci * tep_print_num_field - print a field and a format 70738c2ecf20Sopenharmony_ci * @s: The seq to print to 70748c2ecf20Sopenharmony_ci * @fmt: The printf format to print the field with. 70758c2ecf20Sopenharmony_ci * @event: the event that the field is for 70768c2ecf20Sopenharmony_ci * @name: The name of the field 70778c2ecf20Sopenharmony_ci * @record: The record with the field name. 70788c2ecf20Sopenharmony_ci * @err: print default error if failed. 70798c2ecf20Sopenharmony_ci * 70808c2ecf20Sopenharmony_ci * Returns positive value on success, negative in case of an error, 70818c2ecf20Sopenharmony_ci * or 0 if buffer is full. 70828c2ecf20Sopenharmony_ci */ 70838c2ecf20Sopenharmony_ciint tep_print_num_field(struct trace_seq *s, const char *fmt, 70848c2ecf20Sopenharmony_ci struct tep_event *event, const char *name, 70858c2ecf20Sopenharmony_ci struct tep_record *record, int err) 70868c2ecf20Sopenharmony_ci{ 70878c2ecf20Sopenharmony_ci struct tep_format_field *field = tep_find_field(event, name); 70888c2ecf20Sopenharmony_ci unsigned long long val; 70898c2ecf20Sopenharmony_ci 70908c2ecf20Sopenharmony_ci if (!field) 70918c2ecf20Sopenharmony_ci goto failed; 70928c2ecf20Sopenharmony_ci 70938c2ecf20Sopenharmony_ci if (tep_read_number_field(field, record->data, &val)) 70948c2ecf20Sopenharmony_ci goto failed; 70958c2ecf20Sopenharmony_ci 70968c2ecf20Sopenharmony_ci return trace_seq_printf(s, fmt, val); 70978c2ecf20Sopenharmony_ci 70988c2ecf20Sopenharmony_ci failed: 70998c2ecf20Sopenharmony_ci if (err) 71008c2ecf20Sopenharmony_ci trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name); 71018c2ecf20Sopenharmony_ci return -1; 71028c2ecf20Sopenharmony_ci} 71038c2ecf20Sopenharmony_ci 71048c2ecf20Sopenharmony_ci/** 71058c2ecf20Sopenharmony_ci * tep_print_func_field - print a field and a format for function pointers 71068c2ecf20Sopenharmony_ci * @s: The seq to print to 71078c2ecf20Sopenharmony_ci * @fmt: The printf format to print the field with. 71088c2ecf20Sopenharmony_ci * @event: the event that the field is for 71098c2ecf20Sopenharmony_ci * @name: The name of the field 71108c2ecf20Sopenharmony_ci * @record: The record with the field name. 71118c2ecf20Sopenharmony_ci * @err: print default error if failed. 71128c2ecf20Sopenharmony_ci * 71138c2ecf20Sopenharmony_ci * Returns positive value on success, negative in case of an error, 71148c2ecf20Sopenharmony_ci * or 0 if buffer is full. 71158c2ecf20Sopenharmony_ci */ 71168c2ecf20Sopenharmony_ciint tep_print_func_field(struct trace_seq *s, const char *fmt, 71178c2ecf20Sopenharmony_ci struct tep_event *event, const char *name, 71188c2ecf20Sopenharmony_ci struct tep_record *record, int err) 71198c2ecf20Sopenharmony_ci{ 71208c2ecf20Sopenharmony_ci struct tep_format_field *field = tep_find_field(event, name); 71218c2ecf20Sopenharmony_ci struct tep_handle *tep = event->tep; 71228c2ecf20Sopenharmony_ci unsigned long long val; 71238c2ecf20Sopenharmony_ci struct func_map *func; 71248c2ecf20Sopenharmony_ci char tmp[128]; 71258c2ecf20Sopenharmony_ci 71268c2ecf20Sopenharmony_ci if (!field) 71278c2ecf20Sopenharmony_ci goto failed; 71288c2ecf20Sopenharmony_ci 71298c2ecf20Sopenharmony_ci if (tep_read_number_field(field, record->data, &val)) 71308c2ecf20Sopenharmony_ci goto failed; 71318c2ecf20Sopenharmony_ci 71328c2ecf20Sopenharmony_ci func = find_func(tep, val); 71338c2ecf20Sopenharmony_ci 71348c2ecf20Sopenharmony_ci if (func) 71358c2ecf20Sopenharmony_ci snprintf(tmp, 128, "%s/0x%llx", func->func, func->addr - val); 71368c2ecf20Sopenharmony_ci else 71378c2ecf20Sopenharmony_ci sprintf(tmp, "0x%08llx", val); 71388c2ecf20Sopenharmony_ci 71398c2ecf20Sopenharmony_ci return trace_seq_printf(s, fmt, tmp); 71408c2ecf20Sopenharmony_ci 71418c2ecf20Sopenharmony_ci failed: 71428c2ecf20Sopenharmony_ci if (err) 71438c2ecf20Sopenharmony_ci trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name); 71448c2ecf20Sopenharmony_ci return -1; 71458c2ecf20Sopenharmony_ci} 71468c2ecf20Sopenharmony_ci 71478c2ecf20Sopenharmony_cistatic void free_func_handle(struct tep_function_handler *func) 71488c2ecf20Sopenharmony_ci{ 71498c2ecf20Sopenharmony_ci struct func_params *params; 71508c2ecf20Sopenharmony_ci 71518c2ecf20Sopenharmony_ci free(func->name); 71528c2ecf20Sopenharmony_ci 71538c2ecf20Sopenharmony_ci while (func->params) { 71548c2ecf20Sopenharmony_ci params = func->params; 71558c2ecf20Sopenharmony_ci func->params = params->next; 71568c2ecf20Sopenharmony_ci free(params); 71578c2ecf20Sopenharmony_ci } 71588c2ecf20Sopenharmony_ci 71598c2ecf20Sopenharmony_ci free(func); 71608c2ecf20Sopenharmony_ci} 71618c2ecf20Sopenharmony_ci 71628c2ecf20Sopenharmony_ci/** 71638c2ecf20Sopenharmony_ci * tep_register_print_function - register a helper function 71648c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 71658c2ecf20Sopenharmony_ci * @func: the function to process the helper function 71668c2ecf20Sopenharmony_ci * @ret_type: the return type of the helper function 71678c2ecf20Sopenharmony_ci * @name: the name of the helper function 71688c2ecf20Sopenharmony_ci * @parameters: A list of enum tep_func_arg_type 71698c2ecf20Sopenharmony_ci * 71708c2ecf20Sopenharmony_ci * Some events may have helper functions in the print format arguments. 71718c2ecf20Sopenharmony_ci * This allows a plugin to dynamically create a way to process one 71728c2ecf20Sopenharmony_ci * of these functions. 71738c2ecf20Sopenharmony_ci * 71748c2ecf20Sopenharmony_ci * The @parameters is a variable list of tep_func_arg_type enums that 71758c2ecf20Sopenharmony_ci * must end with TEP_FUNC_ARG_VOID. 71768c2ecf20Sopenharmony_ci */ 71778c2ecf20Sopenharmony_ciint tep_register_print_function(struct tep_handle *tep, 71788c2ecf20Sopenharmony_ci tep_func_handler func, 71798c2ecf20Sopenharmony_ci enum tep_func_arg_type ret_type, 71808c2ecf20Sopenharmony_ci char *name, ...) 71818c2ecf20Sopenharmony_ci{ 71828c2ecf20Sopenharmony_ci struct tep_function_handler *func_handle; 71838c2ecf20Sopenharmony_ci struct func_params **next_param; 71848c2ecf20Sopenharmony_ci struct func_params *param; 71858c2ecf20Sopenharmony_ci enum tep_func_arg_type type; 71868c2ecf20Sopenharmony_ci va_list ap; 71878c2ecf20Sopenharmony_ci int ret; 71888c2ecf20Sopenharmony_ci 71898c2ecf20Sopenharmony_ci func_handle = find_func_handler(tep, name); 71908c2ecf20Sopenharmony_ci if (func_handle) { 71918c2ecf20Sopenharmony_ci /* 71928c2ecf20Sopenharmony_ci * This is most like caused by the users own 71938c2ecf20Sopenharmony_ci * plugins updating the function. This overrides the 71948c2ecf20Sopenharmony_ci * system defaults. 71958c2ecf20Sopenharmony_ci */ 71968c2ecf20Sopenharmony_ci pr_stat("override of function helper '%s'", name); 71978c2ecf20Sopenharmony_ci remove_func_handler(tep, name); 71988c2ecf20Sopenharmony_ci } 71998c2ecf20Sopenharmony_ci 72008c2ecf20Sopenharmony_ci func_handle = calloc(1, sizeof(*func_handle)); 72018c2ecf20Sopenharmony_ci if (!func_handle) { 72028c2ecf20Sopenharmony_ci do_warning("Failed to allocate function handler"); 72038c2ecf20Sopenharmony_ci return TEP_ERRNO__MEM_ALLOC_FAILED; 72048c2ecf20Sopenharmony_ci } 72058c2ecf20Sopenharmony_ci 72068c2ecf20Sopenharmony_ci func_handle->ret_type = ret_type; 72078c2ecf20Sopenharmony_ci func_handle->name = strdup(name); 72088c2ecf20Sopenharmony_ci func_handle->func = func; 72098c2ecf20Sopenharmony_ci if (!func_handle->name) { 72108c2ecf20Sopenharmony_ci do_warning("Failed to allocate function name"); 72118c2ecf20Sopenharmony_ci free(func_handle); 72128c2ecf20Sopenharmony_ci return TEP_ERRNO__MEM_ALLOC_FAILED; 72138c2ecf20Sopenharmony_ci } 72148c2ecf20Sopenharmony_ci 72158c2ecf20Sopenharmony_ci next_param = &(func_handle->params); 72168c2ecf20Sopenharmony_ci va_start(ap, name); 72178c2ecf20Sopenharmony_ci for (;;) { 72188c2ecf20Sopenharmony_ci type = va_arg(ap, enum tep_func_arg_type); 72198c2ecf20Sopenharmony_ci if (type == TEP_FUNC_ARG_VOID) 72208c2ecf20Sopenharmony_ci break; 72218c2ecf20Sopenharmony_ci 72228c2ecf20Sopenharmony_ci if (type >= TEP_FUNC_ARG_MAX_TYPES) { 72238c2ecf20Sopenharmony_ci do_warning("Invalid argument type %d", type); 72248c2ecf20Sopenharmony_ci ret = TEP_ERRNO__INVALID_ARG_TYPE; 72258c2ecf20Sopenharmony_ci goto out_free; 72268c2ecf20Sopenharmony_ci } 72278c2ecf20Sopenharmony_ci 72288c2ecf20Sopenharmony_ci param = malloc(sizeof(*param)); 72298c2ecf20Sopenharmony_ci if (!param) { 72308c2ecf20Sopenharmony_ci do_warning("Failed to allocate function param"); 72318c2ecf20Sopenharmony_ci ret = TEP_ERRNO__MEM_ALLOC_FAILED; 72328c2ecf20Sopenharmony_ci goto out_free; 72338c2ecf20Sopenharmony_ci } 72348c2ecf20Sopenharmony_ci param->type = type; 72358c2ecf20Sopenharmony_ci param->next = NULL; 72368c2ecf20Sopenharmony_ci 72378c2ecf20Sopenharmony_ci *next_param = param; 72388c2ecf20Sopenharmony_ci next_param = &(param->next); 72398c2ecf20Sopenharmony_ci 72408c2ecf20Sopenharmony_ci func_handle->nr_args++; 72418c2ecf20Sopenharmony_ci } 72428c2ecf20Sopenharmony_ci va_end(ap); 72438c2ecf20Sopenharmony_ci 72448c2ecf20Sopenharmony_ci func_handle->next = tep->func_handlers; 72458c2ecf20Sopenharmony_ci tep->func_handlers = func_handle; 72468c2ecf20Sopenharmony_ci 72478c2ecf20Sopenharmony_ci return 0; 72488c2ecf20Sopenharmony_ci out_free: 72498c2ecf20Sopenharmony_ci va_end(ap); 72508c2ecf20Sopenharmony_ci free_func_handle(func_handle); 72518c2ecf20Sopenharmony_ci return ret; 72528c2ecf20Sopenharmony_ci} 72538c2ecf20Sopenharmony_ci 72548c2ecf20Sopenharmony_ci/** 72558c2ecf20Sopenharmony_ci * tep_unregister_print_function - unregister a helper function 72568c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 72578c2ecf20Sopenharmony_ci * @func: the function to process the helper function 72588c2ecf20Sopenharmony_ci * @name: the name of the helper function 72598c2ecf20Sopenharmony_ci * 72608c2ecf20Sopenharmony_ci * This function removes existing print handler for function @name. 72618c2ecf20Sopenharmony_ci * 72628c2ecf20Sopenharmony_ci * Returns 0 if the handler was removed successully, -1 otherwise. 72638c2ecf20Sopenharmony_ci */ 72648c2ecf20Sopenharmony_ciint tep_unregister_print_function(struct tep_handle *tep, 72658c2ecf20Sopenharmony_ci tep_func_handler func, char *name) 72668c2ecf20Sopenharmony_ci{ 72678c2ecf20Sopenharmony_ci struct tep_function_handler *func_handle; 72688c2ecf20Sopenharmony_ci 72698c2ecf20Sopenharmony_ci func_handle = find_func_handler(tep, name); 72708c2ecf20Sopenharmony_ci if (func_handle && func_handle->func == func) { 72718c2ecf20Sopenharmony_ci remove_func_handler(tep, name); 72728c2ecf20Sopenharmony_ci return 0; 72738c2ecf20Sopenharmony_ci } 72748c2ecf20Sopenharmony_ci return -1; 72758c2ecf20Sopenharmony_ci} 72768c2ecf20Sopenharmony_ci 72778c2ecf20Sopenharmony_cistatic struct tep_event *search_event(struct tep_handle *tep, int id, 72788c2ecf20Sopenharmony_ci const char *sys_name, 72798c2ecf20Sopenharmony_ci const char *event_name) 72808c2ecf20Sopenharmony_ci{ 72818c2ecf20Sopenharmony_ci struct tep_event *event; 72828c2ecf20Sopenharmony_ci 72838c2ecf20Sopenharmony_ci if (id >= 0) { 72848c2ecf20Sopenharmony_ci /* search by id */ 72858c2ecf20Sopenharmony_ci event = tep_find_event(tep, id); 72868c2ecf20Sopenharmony_ci if (!event) 72878c2ecf20Sopenharmony_ci return NULL; 72888c2ecf20Sopenharmony_ci if (event_name && (strcmp(event_name, event->name) != 0)) 72898c2ecf20Sopenharmony_ci return NULL; 72908c2ecf20Sopenharmony_ci if (sys_name && (strcmp(sys_name, event->system) != 0)) 72918c2ecf20Sopenharmony_ci return NULL; 72928c2ecf20Sopenharmony_ci } else { 72938c2ecf20Sopenharmony_ci event = tep_find_event_by_name(tep, sys_name, event_name); 72948c2ecf20Sopenharmony_ci if (!event) 72958c2ecf20Sopenharmony_ci return NULL; 72968c2ecf20Sopenharmony_ci } 72978c2ecf20Sopenharmony_ci return event; 72988c2ecf20Sopenharmony_ci} 72998c2ecf20Sopenharmony_ci 73008c2ecf20Sopenharmony_ci/** 73018c2ecf20Sopenharmony_ci * tep_register_event_handler - register a way to parse an event 73028c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 73038c2ecf20Sopenharmony_ci * @id: the id of the event to register 73048c2ecf20Sopenharmony_ci * @sys_name: the system name the event belongs to 73058c2ecf20Sopenharmony_ci * @event_name: the name of the event 73068c2ecf20Sopenharmony_ci * @func: the function to call to parse the event information 73078c2ecf20Sopenharmony_ci * @context: the data to be passed to @func 73088c2ecf20Sopenharmony_ci * 73098c2ecf20Sopenharmony_ci * This function allows a developer to override the parsing of 73108c2ecf20Sopenharmony_ci * a given event. If for some reason the default print format 73118c2ecf20Sopenharmony_ci * is not sufficient, this function will register a function 73128c2ecf20Sopenharmony_ci * for an event to be used to parse the data instead. 73138c2ecf20Sopenharmony_ci * 73148c2ecf20Sopenharmony_ci * If @id is >= 0, then it is used to find the event. 73158c2ecf20Sopenharmony_ci * else @sys_name and @event_name are used. 73168c2ecf20Sopenharmony_ci * 73178c2ecf20Sopenharmony_ci * Returns: 73188c2ecf20Sopenharmony_ci * TEP_REGISTER_SUCCESS_OVERWRITE if an existing handler is overwritten 73198c2ecf20Sopenharmony_ci * TEP_REGISTER_SUCCESS if a new handler is registered successfully 73208c2ecf20Sopenharmony_ci * negative TEP_ERRNO_... in case of an error 73218c2ecf20Sopenharmony_ci * 73228c2ecf20Sopenharmony_ci */ 73238c2ecf20Sopenharmony_ciint tep_register_event_handler(struct tep_handle *tep, int id, 73248c2ecf20Sopenharmony_ci const char *sys_name, const char *event_name, 73258c2ecf20Sopenharmony_ci tep_event_handler_func func, void *context) 73268c2ecf20Sopenharmony_ci{ 73278c2ecf20Sopenharmony_ci struct tep_event *event; 73288c2ecf20Sopenharmony_ci struct event_handler *handle; 73298c2ecf20Sopenharmony_ci 73308c2ecf20Sopenharmony_ci event = search_event(tep, id, sys_name, event_name); 73318c2ecf20Sopenharmony_ci if (event == NULL) 73328c2ecf20Sopenharmony_ci goto not_found; 73338c2ecf20Sopenharmony_ci 73348c2ecf20Sopenharmony_ci pr_stat("overriding event (%d) %s:%s with new print handler", 73358c2ecf20Sopenharmony_ci event->id, event->system, event->name); 73368c2ecf20Sopenharmony_ci 73378c2ecf20Sopenharmony_ci event->handler = func; 73388c2ecf20Sopenharmony_ci event->context = context; 73398c2ecf20Sopenharmony_ci return TEP_REGISTER_SUCCESS_OVERWRITE; 73408c2ecf20Sopenharmony_ci 73418c2ecf20Sopenharmony_ci not_found: 73428c2ecf20Sopenharmony_ci /* Save for later use. */ 73438c2ecf20Sopenharmony_ci handle = calloc(1, sizeof(*handle)); 73448c2ecf20Sopenharmony_ci if (!handle) { 73458c2ecf20Sopenharmony_ci do_warning("Failed to allocate event handler"); 73468c2ecf20Sopenharmony_ci return TEP_ERRNO__MEM_ALLOC_FAILED; 73478c2ecf20Sopenharmony_ci } 73488c2ecf20Sopenharmony_ci 73498c2ecf20Sopenharmony_ci handle->id = id; 73508c2ecf20Sopenharmony_ci if (event_name) 73518c2ecf20Sopenharmony_ci handle->event_name = strdup(event_name); 73528c2ecf20Sopenharmony_ci if (sys_name) 73538c2ecf20Sopenharmony_ci handle->sys_name = strdup(sys_name); 73548c2ecf20Sopenharmony_ci 73558c2ecf20Sopenharmony_ci if ((event_name && !handle->event_name) || 73568c2ecf20Sopenharmony_ci (sys_name && !handle->sys_name)) { 73578c2ecf20Sopenharmony_ci do_warning("Failed to allocate event/sys name"); 73588c2ecf20Sopenharmony_ci free((void *)handle->event_name); 73598c2ecf20Sopenharmony_ci free((void *)handle->sys_name); 73608c2ecf20Sopenharmony_ci free(handle); 73618c2ecf20Sopenharmony_ci return TEP_ERRNO__MEM_ALLOC_FAILED; 73628c2ecf20Sopenharmony_ci } 73638c2ecf20Sopenharmony_ci 73648c2ecf20Sopenharmony_ci handle->func = func; 73658c2ecf20Sopenharmony_ci handle->next = tep->handlers; 73668c2ecf20Sopenharmony_ci tep->handlers = handle; 73678c2ecf20Sopenharmony_ci handle->context = context; 73688c2ecf20Sopenharmony_ci 73698c2ecf20Sopenharmony_ci return TEP_REGISTER_SUCCESS; 73708c2ecf20Sopenharmony_ci} 73718c2ecf20Sopenharmony_ci 73728c2ecf20Sopenharmony_cistatic int handle_matches(struct event_handler *handler, int id, 73738c2ecf20Sopenharmony_ci const char *sys_name, const char *event_name, 73748c2ecf20Sopenharmony_ci tep_event_handler_func func, void *context) 73758c2ecf20Sopenharmony_ci{ 73768c2ecf20Sopenharmony_ci if (id >= 0 && id != handler->id) 73778c2ecf20Sopenharmony_ci return 0; 73788c2ecf20Sopenharmony_ci 73798c2ecf20Sopenharmony_ci if (event_name && (strcmp(event_name, handler->event_name) != 0)) 73808c2ecf20Sopenharmony_ci return 0; 73818c2ecf20Sopenharmony_ci 73828c2ecf20Sopenharmony_ci if (sys_name && (strcmp(sys_name, handler->sys_name) != 0)) 73838c2ecf20Sopenharmony_ci return 0; 73848c2ecf20Sopenharmony_ci 73858c2ecf20Sopenharmony_ci if (func != handler->func || context != handler->context) 73868c2ecf20Sopenharmony_ci return 0; 73878c2ecf20Sopenharmony_ci 73888c2ecf20Sopenharmony_ci return 1; 73898c2ecf20Sopenharmony_ci} 73908c2ecf20Sopenharmony_ci 73918c2ecf20Sopenharmony_ci/** 73928c2ecf20Sopenharmony_ci * tep_unregister_event_handler - unregister an existing event handler 73938c2ecf20Sopenharmony_ci * @tep: a handle to the trace event parser context 73948c2ecf20Sopenharmony_ci * @id: the id of the event to unregister 73958c2ecf20Sopenharmony_ci * @sys_name: the system name the handler belongs to 73968c2ecf20Sopenharmony_ci * @event_name: the name of the event handler 73978c2ecf20Sopenharmony_ci * @func: the function to call to parse the event information 73988c2ecf20Sopenharmony_ci * @context: the data to be passed to @func 73998c2ecf20Sopenharmony_ci * 74008c2ecf20Sopenharmony_ci * This function removes existing event handler (parser). 74018c2ecf20Sopenharmony_ci * 74028c2ecf20Sopenharmony_ci * If @id is >= 0, then it is used to find the event. 74038c2ecf20Sopenharmony_ci * else @sys_name and @event_name are used. 74048c2ecf20Sopenharmony_ci * 74058c2ecf20Sopenharmony_ci * Returns 0 if handler was removed successfully, -1 if event was not found. 74068c2ecf20Sopenharmony_ci */ 74078c2ecf20Sopenharmony_ciint tep_unregister_event_handler(struct tep_handle *tep, int id, 74088c2ecf20Sopenharmony_ci const char *sys_name, const char *event_name, 74098c2ecf20Sopenharmony_ci tep_event_handler_func func, void *context) 74108c2ecf20Sopenharmony_ci{ 74118c2ecf20Sopenharmony_ci struct tep_event *event; 74128c2ecf20Sopenharmony_ci struct event_handler *handle; 74138c2ecf20Sopenharmony_ci struct event_handler **next; 74148c2ecf20Sopenharmony_ci 74158c2ecf20Sopenharmony_ci event = search_event(tep, id, sys_name, event_name); 74168c2ecf20Sopenharmony_ci if (event == NULL) 74178c2ecf20Sopenharmony_ci goto not_found; 74188c2ecf20Sopenharmony_ci 74198c2ecf20Sopenharmony_ci if (event->handler == func && event->context == context) { 74208c2ecf20Sopenharmony_ci pr_stat("removing override handler for event (%d) %s:%s. Going back to default handler.", 74218c2ecf20Sopenharmony_ci event->id, event->system, event->name); 74228c2ecf20Sopenharmony_ci 74238c2ecf20Sopenharmony_ci event->handler = NULL; 74248c2ecf20Sopenharmony_ci event->context = NULL; 74258c2ecf20Sopenharmony_ci return 0; 74268c2ecf20Sopenharmony_ci } 74278c2ecf20Sopenharmony_ci 74288c2ecf20Sopenharmony_cinot_found: 74298c2ecf20Sopenharmony_ci for (next = &tep->handlers; *next; next = &(*next)->next) { 74308c2ecf20Sopenharmony_ci handle = *next; 74318c2ecf20Sopenharmony_ci if (handle_matches(handle, id, sys_name, event_name, 74328c2ecf20Sopenharmony_ci func, context)) 74338c2ecf20Sopenharmony_ci break; 74348c2ecf20Sopenharmony_ci } 74358c2ecf20Sopenharmony_ci 74368c2ecf20Sopenharmony_ci if (!(*next)) 74378c2ecf20Sopenharmony_ci return -1; 74388c2ecf20Sopenharmony_ci 74398c2ecf20Sopenharmony_ci *next = handle->next; 74408c2ecf20Sopenharmony_ci free_handler(handle); 74418c2ecf20Sopenharmony_ci 74428c2ecf20Sopenharmony_ci return 0; 74438c2ecf20Sopenharmony_ci} 74448c2ecf20Sopenharmony_ci 74458c2ecf20Sopenharmony_ci/** 74468c2ecf20Sopenharmony_ci * tep_alloc - create a tep handle 74478c2ecf20Sopenharmony_ci */ 74488c2ecf20Sopenharmony_cistruct tep_handle *tep_alloc(void) 74498c2ecf20Sopenharmony_ci{ 74508c2ecf20Sopenharmony_ci struct tep_handle *tep = calloc(1, sizeof(*tep)); 74518c2ecf20Sopenharmony_ci 74528c2ecf20Sopenharmony_ci if (tep) { 74538c2ecf20Sopenharmony_ci tep->ref_count = 1; 74548c2ecf20Sopenharmony_ci tep->host_bigendian = tep_is_bigendian(); 74558c2ecf20Sopenharmony_ci } 74568c2ecf20Sopenharmony_ci 74578c2ecf20Sopenharmony_ci return tep; 74588c2ecf20Sopenharmony_ci} 74598c2ecf20Sopenharmony_ci 74608c2ecf20Sopenharmony_civoid tep_ref(struct tep_handle *tep) 74618c2ecf20Sopenharmony_ci{ 74628c2ecf20Sopenharmony_ci tep->ref_count++; 74638c2ecf20Sopenharmony_ci} 74648c2ecf20Sopenharmony_ci 74658c2ecf20Sopenharmony_ciint tep_get_ref(struct tep_handle *tep) 74668c2ecf20Sopenharmony_ci{ 74678c2ecf20Sopenharmony_ci if (tep) 74688c2ecf20Sopenharmony_ci return tep->ref_count; 74698c2ecf20Sopenharmony_ci return 0; 74708c2ecf20Sopenharmony_ci} 74718c2ecf20Sopenharmony_ci 74728c2ecf20Sopenharmony_ci__hidden void free_tep_format_field(struct tep_format_field *field) 74738c2ecf20Sopenharmony_ci{ 74748c2ecf20Sopenharmony_ci free(field->type); 74758c2ecf20Sopenharmony_ci if (field->alias != field->name) 74768c2ecf20Sopenharmony_ci free(field->alias); 74778c2ecf20Sopenharmony_ci free(field->name); 74788c2ecf20Sopenharmony_ci free(field); 74798c2ecf20Sopenharmony_ci} 74808c2ecf20Sopenharmony_ci 74818c2ecf20Sopenharmony_cistatic void free_format_fields(struct tep_format_field *field) 74828c2ecf20Sopenharmony_ci{ 74838c2ecf20Sopenharmony_ci struct tep_format_field *next; 74848c2ecf20Sopenharmony_ci 74858c2ecf20Sopenharmony_ci while (field) { 74868c2ecf20Sopenharmony_ci next = field->next; 74878c2ecf20Sopenharmony_ci free_tep_format_field(field); 74888c2ecf20Sopenharmony_ci field = next; 74898c2ecf20Sopenharmony_ci } 74908c2ecf20Sopenharmony_ci} 74918c2ecf20Sopenharmony_ci 74928c2ecf20Sopenharmony_cistatic void free_formats(struct tep_format *format) 74938c2ecf20Sopenharmony_ci{ 74948c2ecf20Sopenharmony_ci free_format_fields(format->common_fields); 74958c2ecf20Sopenharmony_ci free_format_fields(format->fields); 74968c2ecf20Sopenharmony_ci} 74978c2ecf20Sopenharmony_ci 74988c2ecf20Sopenharmony_ci__hidden void free_tep_event(struct tep_event *event) 74998c2ecf20Sopenharmony_ci{ 75008c2ecf20Sopenharmony_ci free(event->name); 75018c2ecf20Sopenharmony_ci free(event->system); 75028c2ecf20Sopenharmony_ci 75038c2ecf20Sopenharmony_ci free_formats(&event->format); 75048c2ecf20Sopenharmony_ci 75058c2ecf20Sopenharmony_ci free(event->print_fmt.format); 75068c2ecf20Sopenharmony_ci free_args(event->print_fmt.args); 75078c2ecf20Sopenharmony_ci free_parse_args(event->print_fmt.print_cache); 75088c2ecf20Sopenharmony_ci free(event); 75098c2ecf20Sopenharmony_ci} 75108c2ecf20Sopenharmony_ci 75118c2ecf20Sopenharmony_ci/** 75128c2ecf20Sopenharmony_ci * tep_free - free a tep handle 75138c2ecf20Sopenharmony_ci * @tep: the tep handle to free 75148c2ecf20Sopenharmony_ci */ 75158c2ecf20Sopenharmony_civoid tep_free(struct tep_handle *tep) 75168c2ecf20Sopenharmony_ci{ 75178c2ecf20Sopenharmony_ci struct cmdline_list *cmdlist, *cmdnext; 75188c2ecf20Sopenharmony_ci struct func_list *funclist, *funcnext; 75198c2ecf20Sopenharmony_ci struct printk_list *printklist, *printknext; 75208c2ecf20Sopenharmony_ci struct tep_function_handler *func_handler; 75218c2ecf20Sopenharmony_ci struct event_handler *handle; 75228c2ecf20Sopenharmony_ci int i; 75238c2ecf20Sopenharmony_ci 75248c2ecf20Sopenharmony_ci if (!tep) 75258c2ecf20Sopenharmony_ci return; 75268c2ecf20Sopenharmony_ci 75278c2ecf20Sopenharmony_ci cmdlist = tep->cmdlist; 75288c2ecf20Sopenharmony_ci funclist = tep->funclist; 75298c2ecf20Sopenharmony_ci printklist = tep->printklist; 75308c2ecf20Sopenharmony_ci 75318c2ecf20Sopenharmony_ci tep->ref_count--; 75328c2ecf20Sopenharmony_ci if (tep->ref_count) 75338c2ecf20Sopenharmony_ci return; 75348c2ecf20Sopenharmony_ci 75358c2ecf20Sopenharmony_ci if (tep->cmdlines) { 75368c2ecf20Sopenharmony_ci for (i = 0; i < tep->cmdline_count; i++) 75378c2ecf20Sopenharmony_ci free(tep->cmdlines[i].comm); 75388c2ecf20Sopenharmony_ci free(tep->cmdlines); 75398c2ecf20Sopenharmony_ci } 75408c2ecf20Sopenharmony_ci 75418c2ecf20Sopenharmony_ci while (cmdlist) { 75428c2ecf20Sopenharmony_ci cmdnext = cmdlist->next; 75438c2ecf20Sopenharmony_ci free(cmdlist->comm); 75448c2ecf20Sopenharmony_ci free(cmdlist); 75458c2ecf20Sopenharmony_ci cmdlist = cmdnext; 75468c2ecf20Sopenharmony_ci } 75478c2ecf20Sopenharmony_ci 75488c2ecf20Sopenharmony_ci if (tep->func_map) { 75498c2ecf20Sopenharmony_ci for (i = 0; i < (int)tep->func_count; i++) { 75508c2ecf20Sopenharmony_ci free(tep->func_map[i].func); 75518c2ecf20Sopenharmony_ci free(tep->func_map[i].mod); 75528c2ecf20Sopenharmony_ci } 75538c2ecf20Sopenharmony_ci free(tep->func_map); 75548c2ecf20Sopenharmony_ci } 75558c2ecf20Sopenharmony_ci 75568c2ecf20Sopenharmony_ci while (funclist) { 75578c2ecf20Sopenharmony_ci funcnext = funclist->next; 75588c2ecf20Sopenharmony_ci free(funclist->func); 75598c2ecf20Sopenharmony_ci free(funclist->mod); 75608c2ecf20Sopenharmony_ci free(funclist); 75618c2ecf20Sopenharmony_ci funclist = funcnext; 75628c2ecf20Sopenharmony_ci } 75638c2ecf20Sopenharmony_ci 75648c2ecf20Sopenharmony_ci while (tep->func_handlers) { 75658c2ecf20Sopenharmony_ci func_handler = tep->func_handlers; 75668c2ecf20Sopenharmony_ci tep->func_handlers = func_handler->next; 75678c2ecf20Sopenharmony_ci free_func_handle(func_handler); 75688c2ecf20Sopenharmony_ci } 75698c2ecf20Sopenharmony_ci 75708c2ecf20Sopenharmony_ci if (tep->printk_map) { 75718c2ecf20Sopenharmony_ci for (i = 0; i < (int)tep->printk_count; i++) 75728c2ecf20Sopenharmony_ci free(tep->printk_map[i].printk); 75738c2ecf20Sopenharmony_ci free(tep->printk_map); 75748c2ecf20Sopenharmony_ci } 75758c2ecf20Sopenharmony_ci 75768c2ecf20Sopenharmony_ci while (printklist) { 75778c2ecf20Sopenharmony_ci printknext = printklist->next; 75788c2ecf20Sopenharmony_ci free(printklist->printk); 75798c2ecf20Sopenharmony_ci free(printklist); 75808c2ecf20Sopenharmony_ci printklist = printknext; 75818c2ecf20Sopenharmony_ci } 75828c2ecf20Sopenharmony_ci 75838c2ecf20Sopenharmony_ci for (i = 0; i < tep->nr_events; i++) 75848c2ecf20Sopenharmony_ci free_tep_event(tep->events[i]); 75858c2ecf20Sopenharmony_ci 75868c2ecf20Sopenharmony_ci while (tep->handlers) { 75878c2ecf20Sopenharmony_ci handle = tep->handlers; 75888c2ecf20Sopenharmony_ci tep->handlers = handle->next; 75898c2ecf20Sopenharmony_ci free_handler(handle); 75908c2ecf20Sopenharmony_ci } 75918c2ecf20Sopenharmony_ci 75928c2ecf20Sopenharmony_ci free(tep->events); 75938c2ecf20Sopenharmony_ci free(tep->sort_events); 75948c2ecf20Sopenharmony_ci free(tep->func_resolver); 75958c2ecf20Sopenharmony_ci free_tep_plugin_paths(tep); 75968c2ecf20Sopenharmony_ci 75978c2ecf20Sopenharmony_ci free(tep); 75988c2ecf20Sopenharmony_ci} 75998c2ecf20Sopenharmony_ci 76008c2ecf20Sopenharmony_civoid tep_unref(struct tep_handle *tep) 76018c2ecf20Sopenharmony_ci{ 76028c2ecf20Sopenharmony_ci tep_free(tep); 76038c2ecf20Sopenharmony_ci} 7604