cregit-Linux how code gets into the kernel

Release 4.10 tools/lib/traceevent/event-parse.c

/*
 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License (not later!)
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not,  see <http://www.gnu.org/licenses>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  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/string.h>
#include <linux/time64.h>

#include <netinet/in.h>
#include "event-parse.h"
#include "event-utils.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)


static void init_input_buf(const char *buf, unsigned long long size) { input_buf = buf; input_buf_siz = size; input_buf_ptr = 0; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt28100.00%1100.00%
Total28100.00%1100.00%


const char *pevent_get_input_buf(void) { return input_buf; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt12100.00%1100.00%
Total12100.00%1100.00%


unsigned long long pevent_get_input_buf_ptr(void) { return input_buf_ptr; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt12100.00%1100.00%
Total12100.00%1100.00%

struct event_handler { struct event_handler *next; int id; const char *sys_name; const char *event_name; pevent_event_handler_func func; void *context; }; struct pevent_func_params { struct pevent_func_params *next; enum pevent_func_arg_type type; }; struct pevent_function_handler { struct pevent_function_handler *next; enum pevent_func_arg_type ret_type; char *name; pevent_func_handler func; struct pevent_func_params *params; int nr_args; }; static unsigned long long process_defined_func(struct trace_seq *s, void *data, int size, struct event_format *event, struct print_arg *arg); static void free_func_handle(struct pevent_function_handler *func); /** * pevent_buffer_init - init buffer for parsing * @buf: buffer to parse * @size: the size of the buffer * * For use with pevent_read_token(), this initializes the internal * buffer that pevent_read_token() will parse. */
void pevent_buffer_init(const char *buf, unsigned long long size) { init_input_buf(buf, size); }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt22100.00%1100.00%
Total22100.00%1100.00%


void breakpoint(void) { static int x; x++; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt14100.00%1100.00%
Total14100.00%1100.00%


struct print_arg *alloc_arg(void) { return calloc(1, sizeof(struct print_arg)); }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt1780.95%150.00%
arnaldo carvalho de meloarnaldo carvalho de melo419.05%150.00%
Total21100.00%2100.00%

struct cmdline { char *comm; int pid; };
static int cmdline_cmp(const void *a, const void *b) { const struct cmdline *ca = a; const struct cmdline *cb = b; if (ca->pid < cb->pid) return -1; if (ca->pid > cb->pid) return 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt62100.00%1100.00%
Total62100.00%1100.00%

struct cmdline_list { struct cmdline_list *next; char *comm; int pid; };
static int cmdline_init(struct pevent *pevent) { struct cmdline_list *cmdlist = pevent->cmdlist; struct cmdline_list *item; struct cmdline *cmdlines; int i; cmdlines = malloc(sizeof(*cmdlines) * pevent->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, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp); pevent->cmdlines = cmdlines; pevent->cmdlist = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt12992.81%150.00%
arnaldo carvalho de meloarnaldo carvalho de melo107.19%150.00%
Total139100.00%2100.00%


static const char *find_cmdline(struct pevent *pevent, int pid) { const struct cmdline *comm; struct cmdline key; if (!pid) return "<idle>"; if (!pevent->cmdlines && cmdline_init(pevent)) return "<not enough memory for cmdlines!>"; key.pid = pid; comm = bsearch(&key, pevent->cmdlines, pevent->cmdline_count, sizeof(*pevent->cmdlines), cmdline_cmp); if (comm) return comm->comm; return "<...>"; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt8793.55%133.33%
arnaldo carvalho de meloarnaldo carvalho de melo66.45%266.67%
Total93100.00%3100.00%

/** * pevent_pid_is_registered - return if a pid has a cmdline registered * @pevent: handle for the pevent * @pid: The pid to check if it has a cmdline registered with. * * Returns 1 if the pid has a cmdline mapped to it * 0 otherwise. */
int pevent_pid_is_registered(struct pevent *pevent, int pid) { const struct cmdline *comm; struct cmdline key; if (!pid) return 1; if (!pevent->cmdlines && cmdline_init(pevent)) return 0; key.pid = pid; comm = bsearch(&key, pevent->cmdlines, pevent->cmdline_count, sizeof(*pevent->cmdlines), cmdline_cmp); if (comm) return 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt8394.32%150.00%
arnaldo carvalho de meloarnaldo carvalho de melo55.68%150.00%
Total88100.00%2100.00%

/* * 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 pevent *pevent, const char *comm, int pid) { struct cmdline *cmdlines = pevent->cmdlines; const struct cmdline *cmdline; struct cmdline key; if (!pid) return 0; /* avoid duplicates */ key.pid = pid; cmdline = bsearch(&key, pevent->cmdlines, pevent->cmdline_count, sizeof(*pevent->cmdlines), cmdline_cmp); if (cmdline) { errno = EEXIST; return -1; } cmdlines = realloc(cmdlines, sizeof(*cmdlines) * (pevent->cmdline_count + 1)); if (!cmdlines) { errno = ENOMEM; return -1; } cmdlines[pevent->cmdline_count].comm = strdup(comm); if (!cmdlines[pevent->cmdline_count].comm) { free(cmdlines); errno = ENOMEM; return -1; } cmdlines[pevent->cmdline_count].pid = pid; if (cmdlines[pevent->cmdline_count].comm) pevent->cmdline_count++; qsort(cmdlines, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp); pevent->cmdlines = cmdlines; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt20089.69%150.00%
arnaldo carvalho de meloarnaldo carvalho de melo2310.31%150.00%
Total223100.00%2100.00%

/** * pevent_register_comm - register a pid / comm mapping * @pevent: handle for the pevent * @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. */
int pevent_register_comm(struct pevent *pevent, const char *comm, int pid) { struct cmdline_list *item; if (pevent->cmdlines) return add_new_comm(pevent, comm, pid); 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 = pevent->cmdlist; pevent->cmdlist = item; pevent->cmdline_count++; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt9675.00%133.33%
arnaldo carvalho de meloarnaldo carvalho de melo1814.06%133.33%
josef bacikjosef bacik1410.94%133.33%
Total128100.00%3100.00%


int pevent_register_trace_clock(struct pevent *pevent, const char *trace_clock) { pevent->trace_clock = strdup(trace_clock); if (!pevent->trace_clock) { errno = ENOMEM; return -1; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt2352.27%150.00%
yoshihiro yunomaeyoshihiro yunomae2147.73%150.00%
Total44100.00%2100.00%

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; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt62100.00%1100.00%
Total62100.00%1100.00%

/* * 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; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt86100.00%1100.00%
Total86100.00%1100.00%


static int func_map_init(struct pevent *pevent) { struct func_list *funclist; struct func_list *item; struct func_map *func_map; int i; func_map = malloc(sizeof(*func_map) * (pevent->func_count + 1)); if (!func_map) return -1; funclist = pevent->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, pevent->func_count, sizeof(*func_map), func_cmp); /* * Add a special record at the end. */ func_map[pevent->func_count].func = NULL; func_map[pevent->func_count].addr = 0; func_map[pevent->func_count].mod = NULL; pevent->func_map = func_map; pevent->funclist = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt18094.74%150.00%
arnaldo carvalho de meloarnaldo carvalho de melo105.26%150.00%
Total190100.00%2100.00%


static struct func_map * __find_func(struct pevent *pevent, unsigned long long addr) { struct func_map *func; struct func_map key; if (!pevent->func_map) func_map_init(pevent); key.addr = addr; func = bsearch(&key, pevent->func_map, pevent->func_count, sizeof(*pevent->func_map), func_bcmp); return func; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt7398.65%150.00%
arnaldo carvalho de meloarnaldo carvalho de melo11.35%150.00%
Total74100.00%2100.00%

struct func_resolver { pevent_func_resolver_t *func; void *priv; struct func_map map; }; /** * pevent_set_function_resolver - set an alternative function resolver * @pevent: handle for the pevent * @resolver: function to be used * @priv: resolver function private state. * * Some tools may have already a way to resolve kernel functions, allow them to * keep using it instead of duplicating all the entries inside * pevent->funclist. */
int pevent_set_function_resolver(struct pevent *pevent, pevent_func_resolver_t *func, void *priv) { struct func_resolver *resolver = malloc(sizeof(*resolver)); if (resolver == NULL) return -1; resolver->func = func; resolver->priv = priv; free(pevent->func_resolver); pevent->func_resolver = resolver; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo70100.00%1100.00%
Total70100.00%1100.00%

/** * pevent_reset_function_resolver - reset alternative function resolver * @pevent: handle for the pevent * * Stop using whatever alternative resolver was set, use the default * one instead. */
void pevent_reset_function_resolver(struct pevent *pevent) { free(pevent->func_resolver); pevent->func_resolver = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo23100.00%1100.00%
Total23100.00%1100.00%


static struct func_map * find_func(struct pevent *pevent, unsigned long long addr) { struct func_map *map; if (!pevent->func_resolver) return __find_func(pevent, addr); map = &pevent->func_resolver->map; map->mod = NULL; map->addr = addr; map->func = pevent->func_resolver->func(pevent->func_resolver->priv, &map->addr, &map->mod); if (map->func == NULL) return NULL; return map; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo100100.00%1100.00%
Total100100.00%1100.00%

/** * pevent_find_function - find a function by a given address * @pevent: handle for the pevent * @addr: the address to find the function with * * Returns a pointer to the function stored that has the given * address. Note, the address does not have to be exact, it * will select the function that would contain the address. */
const char *pevent_find_function(struct pevent *pevent, unsigned long long addr) { struct func_map *map; map = find_func(pevent, addr); if (!map) return NULL; return map->func; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt44100.00%1100.00%
Total44100.00%1100.00%

/** * pevent_find_function_address - find a function address by a given address * @pevent: handle for the pevent * @addr: the address to find the function with * * Returns the address the function starts at. This can be used in * conjunction with pevent_find_function to print both the function * name and the function offset. */
unsigned long long pevent_find_function_address(struct pevent *pevent, unsigned long long addr) { struct func_map *map; map = find_func(pevent, addr); if (!map) return 0; return map->addr; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt44100.00%1100.00%
Total44100.00%1100.00%

/** * pevent_register_function - register a function with a given address * @pevent: handle for the pevent * @function: the function name to register * @addr: the address the function starts at * @mod: the kernel module the function may be in (NULL for none) * * This registers a function name with an address and module. * The @func passed in is duplicated. */
int pevent_register_function(struct pevent *pevent, char *func, unsigned long long addr, char *mod) { struct func_list *item = malloc(sizeof(*item)); if (!item) return -1; item->next = pevent->funclist; item->func = strdup(func); if (!item->func) goto out_free; if (mod) { item->mod = strdup(mod); if (!item->mod) goto out_free_func; } else item->mod = NULL; item->addr = addr; pevent->funclist = item; pevent->func_count++; return 0; out_free_func: free(item->func); item->func = NULL; out_free: free(item); errno = ENOMEM; return -1; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt9158.71%150.00%
arnaldo carvalho de meloarnaldo carvalho de melo6441.29%150.00%
Total155100.00%2100.00%

/** * pevent_print_funcs - print out the stored functions * @pevent: handle for the pevent * * This prints out the stored functions. */
void pevent_print_funcs(struct pevent *pevent) { int i; if (!pevent->func_map) func_map_init(pevent); for (i = 0; i < (int)pevent->func_count; i++) { printf("%016llx %s", pevent->func_map[i].addr, pevent->func_map[i].func); if (pevent->func_map[i].mod) printf(" [%s]\n", pevent->func_map[i].mod); else printf("\n"); } }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt99100.00%1100.00%
Total99100.00%1100.00%

struct printk_map { unsigned long long addr; char *printk; }; struct printk_list { struct printk_list *next; unsigned long long addr; char *printk; };
static int printk_cmp(const void *a, const void *b) { const struct printk_map *pa = a; const struct printk_map *pb = b; if (pa->addr < pb->addr) return -1; if (pa->addr > pb->addr) return 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt5487.10%150.00%
namhyung kimnamhyung kim812.90%150.00%
Total62100.00%2100.00%


static int printk_map_init(struct pevent *pevent) { struct printk_list *printklist; struct printk_list *item; struct printk_map *printk_map; int i; printk_map = malloc(sizeof(*printk_map) * (pevent->printk_count + 1)); if (!printk_map) return -1; printklist = pevent->printklist; i = 0; while (printklist) { printk_map[i].printk = printklist->printk; printk_map[i].addr = printklist->addr; i++; item = printklist; printklist = printklist->next; free(item); } qsort(printk_map, pevent->printk_count, sizeof(*printk_map), printk_cmp); pevent->printk_map = printk_map; pevent->printklist = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt13190.34%150.00%
arnaldo carvalho de meloarnaldo carvalho de melo149.66%150.00%
Total145100.00%2100.00%


static struct printk_map * find_printk(struct pevent *pevent, unsigned long long addr) { struct printk_map *printk; struct printk_map key; if (!pevent->printk_map && printk_map_init(pevent)) return NULL; key.addr = addr; printk = bsearch(&key, pevent->printk_map, pevent->printk_count, sizeof(*pevent->printk_map), printk_cmp); return printk; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt7293.51%150.00%
arnaldo carvalho de meloarnaldo carvalho de melo56.49%150.00%
Total77100.00%2100.00%

/** * pevent_register_print_string - register a string by its address * @pevent: handle for the pevent * @fmt: the string format to register * @addr: the address the string was located at * * This registers a string by the address it was stored in the kernel. * The @fmt passed in is duplicated. */
int pevent_register_print_string(struct pevent *pevent, const char *fmt, unsigned long long addr) { struct printk_list *item = malloc(sizeof(*item)); char *p; if (!item) return -1; item->next = pevent->printklist; item->addr = addr; /* Strip off quotes and '\n' from the end */ if (fmt[0] == '"') fmt++; item->printk = strdup(fmt); if (!item->printk) goto out_free; p = item->printk + strlen(item->printk) - 1; if (*p == '"') *p = 0; p -= 2; if (strcmp(p, "\\n") == 0) *p = 0; pevent->printklist = item; pevent->printk_count++; return 0; out_free: free(item); errno = ENOMEM; return -1; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt12071.01%250.00%
arnaldo carvalho de meloarnaldo carvalho de melo3621.30%125.00%
namhyung kimnamhyung kim137.69%125.00%
Total169100.00%4100.00%

/** * pevent_print_printk - print out the stored strings * @pevent: handle for the pevent * * This prints the string formats that were stored. */
void pevent_print_printk(struct pevent *pevent) { int i; if (!pevent->printk_map) printk_map_init(pevent); for (i = 0; i < (int)pevent->printk_count; i++) { printf("%016llx %s\n", pevent->printk_map[i].addr, pevent->printk_map[i].printk); } }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt68100.00%1100.00%
Total68100.00%1100.00%


static struct event_format *alloc_event(void) { return calloc(1, sizeof(struct event_format)); }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt1777.27%133.33%
arnaldo carvalho de meloarnaldo carvalho de melo418.18%133.33%
namhyung kimnamhyung kim14.55%133.33%
Total22100.00%3100.00%


static int add_event(struct pevent *pevent, struct event_format *event) { int i; struct event_format **events = realloc(pevent->events, sizeof(event) * (pevent->nr_events + 1)); if (!events) return -1; pevent->events = events; for (i = 0; i < pevent->nr_events; i++) { if (pevent->events[i]->id > event->id) break; } if (i < pevent->