Tzvetomir Stoyanov (VMware)tools lib traceevent: Hide non API functionsa41c3216 years agoHistory
7603 lines · 162.9 KB · C
RawDownload
// 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 resolver

Lines 1–500 of 7603.