// SPDX-License-Identifier: LGPL-2.1/* * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> * * * The parts for function graph printing was taken and modified from the * Linux Kernel that were written by * - Copyright (C) 2009 Frederic Weisbecker, * Frederic Weisbecker gave his permission to relicense the code to * the Lesser General Public License. */#include <inttypes.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <ctype.h>#include <errno.h>#include <stdint.h>#include <limits.h>#include <linux/time64.h> #include <netinet/in.h>#include "event-parse.h" #include "event-parse-local.h"#include "event-utils.h"#include "trace-seq.h" static const char *input_buf;static unsigned long long input_buf_ptr;static unsigned long long input_buf_siz; static int is_flag_field;static int is_symbolic_field; static int show_warning = 1; #define do_warning(fmt, ...) \ do { \ if (show_warning) \ warning(fmt, ##__VA_ARGS__); \ } while (0) #define do_warning_event(event, fmt, ...) \ do { \ if (!show_warning) \ continue; \ \ if (event) \ warning("[%s:%s] " fmt, event->system, \ event->name, ##__VA_ARGS__); \ else \ warning(fmt, ##__VA_ARGS__); \ } while (0) /** * init_input_buf - init buffer for parsing * @buf: buffer to parse * @size: the size of the buffer * * Initializes the internal buffer that tep_read_token() will parse. */__hidden void init_input_buf(const char *buf, unsigned long long size){ input_buf = buf; input_buf_siz = size; input_buf_ptr = 0;} __hidden const char *get_input_buf(void){ return input_buf;} __hidden unsigned long long get_input_buf_ptr(void){ return input_buf_ptr;} struct event_handler { struct event_handler *next; int id; const char *sys_name; const char *event_name; tep_event_handler_func func; void *context;}; struct func_params { struct func_params *next; enum tep_func_arg_type type;}; struct tep_function_handler { struct tep_function_handler *next; enum tep_func_arg_type ret_type; char *name; tep_func_handler func; struct func_params *params; int nr_args;}; static unsigned long longprocess_defined_func(struct trace_seq *s, void *data, int size, struct tep_event *event, struct tep_print_arg *arg); static void free_func_handle(struct tep_function_handler *func); void breakpoint(void){ static int x; x++;} static struct tep_print_arg *alloc_arg(void){ return calloc(1, sizeof(struct tep_print_arg));} struct tep_cmdline { char *comm; int pid;}; static int cmdline_cmp(const void *a, const void *b){ const struct tep_cmdline *ca = a; const struct tep_cmdline *cb = b; if (ca->pid < cb->pid) return -1; if (ca->pid > cb->pid) return 1; return 0;} /* Looking for where to place the key */static int cmdline_slot_cmp(const void *a, const void *b){ const struct tep_cmdline *ca = a; const struct tep_cmdline *cb = b; const struct tep_cmdline *cb1 = cb + 1; if (ca->pid < cb->pid) return -1; if (ca->pid > cb->pid) { if (ca->pid <= cb1->pid) return 0; return 1; } return 0;} struct cmdline_list { struct cmdline_list *next; char *comm; int pid;}; static int cmdline_init(struct tep_handle *tep){ struct cmdline_list *cmdlist = tep->cmdlist; struct cmdline_list *item; struct tep_cmdline *cmdlines; int i; cmdlines = malloc(sizeof(*cmdlines) * tep->cmdline_count); if (!cmdlines) return -1; i = 0; while (cmdlist) { cmdlines[i].pid = cmdlist->pid; cmdlines[i].comm = cmdlist->comm; i++; item = cmdlist; cmdlist = cmdlist->next; free(item); } qsort(cmdlines, tep->cmdline_count, sizeof(*cmdlines), cmdline_cmp); tep->cmdlines = cmdlines; tep->cmdlist = NULL; return 0;} static const char *find_cmdline(struct tep_handle *tep, int pid){ const struct tep_cmdline *comm; struct tep_cmdline key; if (!pid) return "<idle>"; if (!tep->cmdlines && cmdline_init(tep)) return "<not enough memory for cmdlines!>"; key.pid = pid; comm = bsearch(&key, tep->cmdlines, tep->cmdline_count, sizeof(*tep->cmdlines), cmdline_cmp); if (comm) return comm->comm; return "<...>";} /** * tep_is_pid_registered - return if a pid has a cmdline registered * @tep: a handle to the trace event parser context * @pid: The pid to check if it has a cmdline registered with. * * Returns true if the pid has a cmdline mapped to it * false otherwise. */bool tep_is_pid_registered(struct tep_handle *tep, int pid){ const struct tep_cmdline *comm; struct tep_cmdline key; if (!pid) return true; if (!tep->cmdlines && cmdline_init(tep)) return false; key.pid = pid; comm = bsearch(&key, tep->cmdlines, tep->cmdline_count, sizeof(*tep->cmdlines), cmdline_cmp); if (comm) return true; return false;} /* * If the command lines have been converted to an array, then * we must add this pid. This is much slower than when cmdlines * are added before the array is initialized. */static int add_new_comm(struct tep_handle *tep, const char *comm, int pid, bool override){ struct tep_cmdline *cmdlines = tep->cmdlines; struct tep_cmdline *cmdline; struct tep_cmdline key; char *new_comm; int cnt; if (!pid) return 0; /* avoid duplicates */ key.pid = pid; cmdline = bsearch(&key, tep->cmdlines, tep->cmdline_count, sizeof(*tep->cmdlines), cmdline_cmp); if (cmdline) { if (!override) { errno = EEXIST; return -1; } new_comm = strdup(comm); if (!new_comm) { errno = ENOMEM; return -1; } free(cmdline->comm); cmdline->comm = new_comm; return 0; } cmdlines = realloc(cmdlines, sizeof(*cmdlines) * (tep->cmdline_count + 1)); if (!cmdlines) { errno = ENOMEM; return -1; } tep->cmdlines = cmdlines; key.comm = strdup(comm); if (!key.comm) { errno = ENOMEM; return -1; } if (!tep->cmdline_count) { /* no entries yet */ tep->cmdlines[0] = key; tep->cmdline_count++; return 0; } /* Now find where we want to store the new cmdline */ cmdline = bsearch(&key, tep->cmdlines, tep->cmdline_count - 1, sizeof(*tep->cmdlines), cmdline_slot_cmp); cnt = tep->cmdline_count; if (cmdline) { /* cmdline points to the one before the spot we want */ cmdline++; cnt -= cmdline - tep->cmdlines; } else { /* The new entry is either before or after the list */ if (key.pid > tep->cmdlines[tep->cmdline_count - 1].pid) { tep->cmdlines[tep->cmdline_count++] = key; return 0; } cmdline = &tep->cmdlines[0]; } memmove(cmdline + 1, cmdline, (cnt * sizeof(*cmdline))); *cmdline = key; tep->cmdline_count++; return 0;} static int _tep_register_comm(struct tep_handle *tep, const char *comm, int pid, bool override){ struct cmdline_list *item; if (tep->cmdlines) return add_new_comm(tep, comm, pid, override); item = malloc(sizeof(*item)); if (!item) return -1; if (comm) item->comm = strdup(comm); else item->comm = strdup("<...>"); if (!item->comm) { free(item); return -1; } item->pid = pid; item->next = tep->cmdlist; tep->cmdlist = item; tep->cmdline_count++; return 0;} /** * tep_register_comm - register a pid / comm mapping * @tep: a handle to the trace event parser context * @comm: the command line to register * @pid: the pid to map the command line to * * This adds a mapping to search for command line names with * a given pid. The comm is duplicated. If a command with the same pid * already exist, -1 is returned and errno is set to EEXIST */int tep_register_comm(struct tep_handle *tep, const char *comm, int pid){ return _tep_register_comm(tep, comm, pid, false);} /** * tep_override_comm - register a pid / comm mapping * @tep: a handle to the trace event parser context * @comm: the command line to register * @pid: the pid to map the command line to * * This adds a mapping to search for command line names with * a given pid. The comm is duplicated. If a command with the same pid * already exist, the command string is udapted with the new one */int tep_override_comm(struct tep_handle *tep, const char *comm, int pid){ if (!tep->cmdlines && cmdline_init(tep)) { errno = ENOMEM; return -1; } return _tep_register_comm(tep, comm, pid, true);} struct func_map { unsigned long long addr; char *func; char *mod;}; struct func_list { struct func_list *next; unsigned long long addr; char *func; char *mod;}; static int func_cmp(const void *a, const void *b){ const struct func_map *fa = a; const struct func_map *fb = b; if (fa->addr < fb->addr) return -1; if (fa->addr > fb->addr) return 1; return 0;} /* * We are searching for a record in between, not an exact * match. */static int func_bcmp(const void *a, const void *b){ const struct func_map *fa = a; const struct func_map *fb = b; if ((fa->addr == fb->addr) || (fa->addr > fb->addr && fa->addr < (fb+1)->addr)) return 0; if (fa->addr < fb->addr) return -1; return 1;} static int func_map_init(struct tep_handle *tep){ struct func_list *funclist; struct func_list *item; struct func_map *func_map; int i; func_map = malloc(sizeof(*func_map) * (tep->func_count + 1)); if (!func_map) return -1; funclist = tep->funclist; i = 0; while (funclist) { func_map[i].func = funclist->func; func_map[i].addr = funclist->addr; func_map[i].mod = funclist->mod; i++; item = funclist; funclist = funclist->next; free(item); } qsort(func_map, tep->func_count, sizeof(*func_map), func_cmp); /* * Add a special record at the end. */ func_map[tep->func_count].func = NULL; func_map[tep->func_count].addr = 0; func_map[tep->func_count].mod = NULL; tep->func_map = func_map; tep->funclist = NULL; return 0;} static struct func_map *__find_func(struct tep_handle *tep, unsigned long long addr){ struct func_map *func; struct func_map key; if (!tep->func_map) func_map_init(tep); key.addr = addr; func = bsearch(&key, tep->func_map, tep->func_count, sizeof(*tep->func_map), func_bcmp); return func;} struct func_resolver { tep_func_resolver_t *func; void *priv; struct func_map map;}; /** * tep_set_function_resolver - set an alternative function resolverLines 1–500 of 7603. Load more
// SPDX-License-Identifier: LGPL-2.1 /* * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> * * * The parts for function graph printing was taken and modified from the * Linux Kernel that were written by * - Copyright (C) 2009 Frederic Weisbecker, * Frederic Weisbecker gave his permission to relicense the code to * the Lesser General Public License. */ #include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <ctype.h> #include <errno.h> #include <stdint.h> #include <limits.h> #include <linux/time64.h> #include <netinet/in.h> #include "event-parse.h" #include "event-parse-local.h" #include "event-utils.h" #include "trace-seq.h" static const char *input_buf; static unsigned long long input_buf_ptr; static unsigned long long input_buf_siz; static int is_flag_field; static int is_symbolic_field; static int show_warning = 1; #define do_warning(fmt, ...) \ do { \ if (show_warning) \ warning(fmt, ##__VA_ARGS__); \ } while (0) #define do_warning_event(event, fmt, ...) \ do { \ if (!show_warning) \ continue; \ \ if (event) \ warning("[%s:%s] " fmt, event->system, \ event->name, ##__VA_ARGS__); \ else \ warning(fmt, ##__VA_ARGS__); \ } while (0) /** * init_input_buf - init buffer for parsing * @buf: buffer to parse * @size: the size of the buffer * * Initializes the internal buffer that tep_read_token() will parse. */ __hidden void init_input_buf(const char *buf, unsigned long long size) { input_buf = buf; input_buf_siz = size; input_buf_ptr = 0; } __hidden const char *get_input_buf(void) { return input_buf; } __hidden unsigned long long get_input_buf_ptr(void) { return input_buf_ptr; } struct event_handler { struct event_handler *next; int id; const char *sys_name; const char *event_name; tep_event_handler_func func; void *context; }; struct func_params { struct func_params *next; enum tep_func_arg_type type; }; struct tep_function_handler { struct tep_function_handler *next; enum tep_func_arg_type ret_type; char *name; tep_func_handler func; struct func_params *params; int nr_args; }; static unsigned long long process_defined_func(struct trace_seq *s, void *data, int size, struct tep_event *event, struct tep_print_arg *arg); static void free_func_handle(struct tep_function_handler *func); void breakpoint(void) { static int x; x++; } static struct tep_print_arg *alloc_arg(void) { return calloc(1, sizeof(struct tep_print_arg)); } struct tep_cmdline { char *comm; int pid; }; static int cmdline_cmp(const void *a, const void *b) { const struct tep_cmdline *ca = a; const struct tep_cmdline *cb = b; if (ca->pid < cb->pid) return -1; if (ca->pid > cb->pid) return 1; return 0; } /* Looking for where to place the key */ static int cmdline_slot_cmp(const void *a, const void *b) { const struct tep_cmdline *ca = a; const struct tep_cmdline *cb = b; const struct tep_cmdline *cb1 = cb + 1; if (ca->pid < cb->pid) return -1; if (ca->pid > cb->pid) { if (ca->pid <= cb1->pid) return 0; return 1; } return 0; } struct cmdline_list { struct cmdline_list *next; char *comm; int pid; }; static int cmdline_init(struct tep_handle *tep) { struct cmdline_list *cmdlist = tep->cmdlist; struct cmdline_list *item; struct tep_cmdline *cmdlines; int i; cmdlines = malloc(sizeof(*cmdlines) * tep->cmdline_count); if (!cmdlines) return -1; i = 0; while (cmdlist) { cmdlines[i].pid = cmdlist->pid; cmdlines[i].comm = cmdlist->comm; i++; item = cmdlist; cmdlist = cmdlist->next; free(item); } qsort(cmdlines, tep->cmdline_count, sizeof(*cmdlines), cmdline_cmp); tep->cmdlines = cmdlines; tep->cmdlist = NULL; return 0; } static const char *find_cmdline(struct tep_handle *tep, int pid) { const struct tep_cmdline *comm; struct tep_cmdline key; if (!pid) return "<idle>"; if (!tep->cmdlines && cmdline_init(tep)) return "<not enough memory for cmdlines!>"; key.pid = pid; comm = bsearch(&key, tep->cmdlines, tep->cmdline_count, sizeof(*tep->cmdlines), cmdline_cmp); if (comm) return comm->comm; return "<...>"; } /** * tep_is_pid_registered - return if a pid has a cmdline registered * @tep: a handle to the trace event parser context * @pid: The pid to check if it has a cmdline registered with. * * Returns true if the pid has a cmdline mapped to it * false otherwise. */ bool tep_is_pid_registered(struct tep_handle *tep, int pid) { const struct tep_cmdline *comm; struct tep_cmdline key; if (!pid) return true; if (!tep->cmdlines && cmdline_init(tep)) return false; key.pid = pid; comm = bsearch(&key, tep->cmdlines, tep->cmdline_count, sizeof(*tep->cmdlines), cmdline_cmp); if (comm) return true; return false; } /* * If the command lines have been converted to an array, then * we must add this pid. This is much slower than when cmdlines * are added before the array is initialized. */ static int add_new_comm(struct tep_handle *tep, const char *comm, int pid, bool override) { struct tep_cmdline *cmdlines = tep->cmdlines; struct tep_cmdline *cmdline; struct tep_cmdline key; char *new_comm; int cnt; if (!pid) return 0; /* avoid duplicates */ key.pid = pid; cmdline = bsearch(&key, tep->cmdlines, tep->cmdline_count, sizeof(*tep->cmdlines), cmdline_cmp); if (cmdline) { if (!override) { errno = EEXIST; return -1; } new_comm = strdup(comm); if (!new_comm) { errno = ENOMEM; return -1; } free(cmdline->comm); cmdline->comm = new_comm; return 0; } cmdlines = realloc(cmdlines, sizeof(*cmdlines) * (tep->cmdline_count + 1)); if (!cmdlines) { errno = ENOMEM; return -1; } tep->cmdlines = cmdlines; key.comm = strdup(comm); if (!key.comm) { errno = ENOMEM; return -1; } if (!tep->cmdline_count) { /* no entries yet */ tep->cmdlines[0] = key; tep->cmdline_count++; return 0; } /* Now find where we want to store the new cmdline */ cmdline = bsearch(&key, tep->cmdlines, tep->cmdline_count - 1, sizeof(*tep->cmdlines), cmdline_slot_cmp); cnt = tep->cmdline_count; if (cmdline) { /* cmdline points to the one before the spot we want */ cmdline++; cnt -= cmdline - tep->cmdlines; } else { /* The new entry is either before or after the list */ if (key.pid > tep->cmdlines[tep->cmdline_count - 1].pid) { tep->cmdlines[tep->cmdline_count++] = key; return 0; } cmdline = &tep->cmdlines[0]; } memmove(cmdline + 1, cmdline, (cnt * sizeof(*cmdline))); *cmdline = key; tep->cmdline_count++; return 0; } static int _tep_register_comm(struct tep_handle *tep, const char *comm, int pid, bool override) { struct cmdline_list *item; if (tep->cmdlines) return add_new_comm(tep, comm, pid, override); item = malloc(sizeof(*item)); if (!item) return -1; if (comm) item->comm = strdup(comm); else item->comm = strdup("<...>"); if (!item->comm) { free(item); return -1; } item->pid = pid; item->next = tep->cmdlist; tep->cmdlist = item; tep->cmdline_count++; return 0; } /** * tep_register_comm - register a pid / comm mapping * @tep: a handle to the trace event parser context * @comm: the command line to register * @pid: the pid to map the command line to * * This adds a mapping to search for command line names with * a given pid. The comm is duplicated. If a command with the same pid * already exist, -1 is returned and errno is set to EEXIST */ int tep_register_comm(struct tep_handle *tep, const char *comm, int pid) { return _tep_register_comm(tep, comm, pid, false); } /** * tep_override_comm - register a pid / comm mapping * @tep: a handle to the trace event parser context * @comm: the command line to register * @pid: the pid to map the command line to * * This adds a mapping to search for command line names with * a given pid. The comm is duplicated. If a command with the same pid * already exist, the command string is udapted with the new one */ int tep_override_comm(struct tep_handle *tep, const char *comm, int pid) { if (!tep->cmdlines && cmdline_init(tep)) { errno = ENOMEM; return -1; } return _tep_register_comm(tep, comm, pid, true); } struct func_map { unsigned long long addr; char *func; char *mod; }; struct func_list { struct func_list *next; unsigned long long addr; char *func; char *mod; }; static int func_cmp(const void *a, const void *b) { const struct func_map *fa = a; const struct func_map *fb = b; if (fa->addr < fb->addr) return -1; if (fa->addr > fb->addr) return 1; return 0; } /* * We are searching for a record in between, not an exact * match. */ static int func_bcmp(const void *a, const void *b) { const struct func_map *fa = a; const struct func_map *fb = b; if ((fa->addr == fb->addr) || (fa->addr > fb->addr && fa->addr < (fb+1)->addr)) return 0; if (fa->addr < fb->addr) return -1; return 1; } static int func_map_init(struct tep_handle *tep) { struct func_list *funclist; struct func_list *item; struct func_map *func_map; int i; func_map = malloc(sizeof(*func_map) * (tep->func_count + 1)); if (!func_map) return -1; funclist = tep->funclist; i = 0; while (funclist) { func_map[i].func = funclist->func; func_map[i].addr = funclist->addr; func_map[i].mod = funclist->mod; i++; item = funclist; funclist = funclist->next; free(item); } qsort(func_map, tep->func_count, sizeof(*func_map), func_cmp); /* * Add a special record at the end. */ func_map[tep->func_count].func = NULL; func_map[tep->func_count].addr = 0; func_map[tep->func_count].mod = NULL; tep->func_map = func_map; tep->funclist = NULL; return 0; } static struct func_map * __find_func(struct tep_handle *tep, unsigned long long addr) { struct func_map *func; struct func_map key; if (!tep->func_map) func_map_init(tep); key.addr = addr; func = bsearch(&key, tep->func_map, tep->func_count, sizeof(*tep->func_map), func_bcmp); return func; } struct func_resolver { tep_func_resolver_t *func; void *priv; struct func_map map; }; /** * tep_set_function_resolver - set an alternative function resolver