aboutsummaryrefslogblamecommitdiffstats
path: root/parse-events.h
blob: 5afbd1a6b25da2091a509be0afd7d961b72d63aa (plain) (tree)



















                                                                             


                       
                   
                  
 



                                         






                                                               
               

                                       
                                                                                  



                                                                           
                                                                          
                                         

  








                                                                               
                                     






                                   
                    









                                                                                

                                                     



                                                            
 
              
                    

                                                             
                                                               
                                                                     
 
                                                              
                                               
 
                                                 




                                                                    
 





                                             


                                     
                                     



                                      
                                       



















                                               
                                       




























                                         




                                       








                                       

                               
                       

                                              









                     
                            
                 
                   













                                                         
                                                         







                                        
                     
                                        




                                          
                                        
                                          


      


                                       



                                            

  





                          











                      











                                                                       



                    
                     
 
               

                      





                                    
                                  






















                                       
                                     

                                          
















                                       

                      


                                              
 
                                       
                                                      
 

                                        

  
                       

                                       
                             
                             
 








                                

                                                        


                            
                                                             







                                               

                                                      


                          
                                                             









                                                 

                                                            


                                
                                                             













                                                  


                                                                                          
 








                                               
                                                                     
                                                               


                                                                  
                                                             
 
                                                                   
                                               
 

                                                                                  
 
                                                                                        
 
                                                                                                  
                                                                  



                                                                      
 


                                                                                            
 
                                                                                 

                                                                             
                                                                                        

                                                                          
 
                                                                      
 
                     


                                                                                    
                                                                     
                                                                
                                                                                  
                                                               
                                                                      
                                                                       
                                              
 
                                                                                      

                                                                             




















































                                                                               

                                         
 



                                                                  
                           
 
                   

                                                
 






















                                                               

                             

  














                          


                           

                         
                       
                      



                       




                        





                                              











                                             







                                       

                                       





                                       

                                        





                                                     

                                                      
























                                                                



                             

  







                                                             


                                                      

                                                      
                                                             
                                                                
 
                                                     
 

                                                                           


                                                           



                                                                   

                                                                               


                                                                                 
                            
/*
 * 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */
#ifndef _PARSE_EVENTS_H
#define _PARSE_EVENTS_H

#include <stdarg.h>
#include <regex.h>

#ifndef __unused
#define __unused __attribute__ ((unused))
#endif

/* ----------------------- trace_seq ----------------------- */


#ifndef TRACE_SEQ_SIZE
#define TRACE_SEQ_SIZE 4096
#endif

struct record {
	unsigned long long	ts;
	unsigned long long	offset;
	long long		missed_events;	/* buffer dropped events before */
	int			record_size;	/* size of binary record */
	int			size;		/* size of data */
	void			*data;
	int			cpu;
	int			locked;		/* Do not allow freeing */
	void			*private;
};

/*
 * Trace sequences are used to allow a function to call several other functions
 * to create a string of data to use (up to a max of PAGE_SIZE).
 */

struct trace_seq {
	char			buffer[TRACE_SEQ_SIZE];
	unsigned int		len;
	unsigned int		readpos;
	int			full;
};

static inline void
trace_seq_init(struct trace_seq *s)
{
	s->len = 0;
	s->readpos = 0;
	s->full = 0;
}

extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
	__attribute__ ((format (printf, 2, 3)));
extern int trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
	__attribute__ ((format (printf, 2, 0)));

extern int trace_seq_puts(struct trace_seq *s, const char *str);
extern int trace_seq_putc(struct trace_seq *s, unsigned char c);

extern void trace_seq_terminate(struct trace_seq *s);

extern int trace_seq_do_printf(struct trace_seq *s);


/* ----------------------- pevent ----------------------- */

struct pevent;
struct event_format;

typedef int (*pevent_event_handler_func)(struct trace_seq *s,
					 struct record *record,
					 struct event_format *event);

typedef int (*pevent_plugin_load_func)(struct pevent *pevent);
typedef int (*pevent_plugin_unload_func)(void);

#define PEVENT_PLUGIN_LOADER pevent_plugin_loader
#define PEVENT_PLUGIN_UNLOADER pevent_plugin_unloader
#define _MAKE_STR(x)	#x
#define MAKE_STR(x)	_MAKE_STR(x)
#define PEVENT_PLUGIN_LOADER_NAME MAKE_STR(PEVENT_PLUGIN_LOADER)
#define PEVENT_PLUGIN_UNLOADER_NAME MAKE_STR(PEVENT_PLUGIN_UNLOADER)

#define NSECS_PER_SEC		1000000000ULL
#define NSECS_PER_USEC		1000ULL

enum format_flags {
	FIELD_IS_ARRAY		= 1,
	FIELD_IS_POINTER	= 2,
	FIELD_IS_SIGNED		= 4,
	FIELD_IS_STRING		= 8,
	FIELD_IS_DYNAMIC	= 16,
	FIELD_IS_LONG		= 32,
};

struct format_field {
	struct format_field	*next;
	struct event_format	*event;
	char			*type;
	char			*name;
	int			offset;
	int			size;
	unsigned long		flags;
};

struct format {
	int			nr_common;
	int			nr_fields;
	struct format_field	*common_fields;
	struct format_field	*fields;
};

struct print_arg_atom {
	char			*atom;
};

struct print_arg_string {
	char			*string;
	int			offset;
};

struct print_arg_field {
	char			*name;
	struct format_field	*field;
};

struct print_flag_sym {
	struct print_flag_sym	*next;
	char			*value;
	char			*str;
};

struct print_arg_typecast {
	char 			*type;
	struct print_arg	*item;
};

struct print_arg_flags {
	struct print_arg	*field;
	char			*delim;
	struct print_flag_sym	*flags;
};

struct print_arg_symbol {
	struct print_arg	*field;
	struct print_flag_sym	*symbols;
};

struct print_arg_dynarray {
	struct format_field	*field;
	struct print_arg	*index;
};

struct print_arg;

struct print_arg_op {
	char			*op;
	int			prio;
	struct print_arg	*left;
	struct print_arg	*right;
};

struct pevent_function_handler;

struct print_arg_func {
	struct pevent_function_handler	*func;
	struct print_arg		*args;
};

enum print_arg_type {
	PRINT_NULL,
	PRINT_ATOM,
	PRINT_FIELD,
	PRINT_FLAGS,
	PRINT_SYMBOL,
	PRINT_TYPE,
	PRINT_STRING,
	PRINT_DYNAMIC_ARRAY,
	PRINT_OP,
	PRINT_FUNC,
};

struct print_arg {
	struct print_arg		*next;
	enum print_arg_type		type;
	union {
		struct print_arg_atom		atom;
		struct print_arg_field		field;
		struct print_arg_typecast	typecast;
		struct print_arg_flags		flags;
		struct print_arg_symbol		symbol;
		struct print_arg_func		func;
		struct print_arg_string		string;
		struct print_arg_op		op;
		struct print_arg_dynarray	dynarray;
	};
};

struct print_fmt {
	char			*format;
	struct print_arg	*args;
};

struct event_format {
	struct pevent		*pevent;
	char			*name;
	int			id;
	int			flags;
	struct format		format;
	struct print_fmt	print_fmt;
	char			*system;
	pevent_event_handler_func handler;
};

enum {
	EVENT_FL_ISFTRACE	= 0x01,
	EVENT_FL_ISPRINT	= 0x02,
	EVENT_FL_ISBPRINT	= 0x04,
	EVENT_FL_ISFUNCENT	= 0x10,
	EVENT_FL_ISFUNCRET	= 0x20,

	EVENT_FL_FAILED		= 0x80000000
};

enum event_sort_type {
	EVENT_SORT_ID,
	EVENT_SORT_NAME,
	EVENT_SORT_SYSTEM,
};

enum event_type {
	EVENT_ERROR,
	EVENT_NONE,
	EVENT_SPACE,
	EVENT_NEWLINE,
	EVENT_OP,
	EVENT_DELIM,
	EVENT_ITEM,
	EVENT_DQUOTE,
	EVENT_SQUOTE,
};

typedef unsigned long long (*pevent_func_handler)(struct trace_seq *s,
					     unsigned long long *args);

enum pevent_func_arg_type {
	PEVENT_FUNC_ARG_VOID,
	PEVENT_FUNC_ARG_INT,
	PEVENT_FUNC_ARG_LONG,
	PEVENT_FUNC_ARG_STRING,
	PEVENT_FUNC_ARG_PTR,
	PEVENT_FUNC_ARG_MAX_TYPES
};

struct cmdline;
struct cmdline_list;
struct func_map;
struct func_list;
struct event_handler;

struct pevent {
	int ref_count;

	int header_page_ts_offset;
	int header_page_ts_size;
	int header_page_size_offset;
	int header_page_size_size;
	int header_page_data_offset;
	int header_page_data_size;
	int header_page_overwrite;

	int file_bigendian;
	int host_bigendian;

	int latency_format;

	int old_format;

	int cpus;
	int long_size;

	struct cmdline *cmdlines;
	struct cmdline_list *cmdlist;
	int cmdline_count;

	struct func_map *func_map;
	struct func_list *funclist;
	unsigned int func_count;

	struct printk_map *printk_map;
	struct printk_list *printklist;
	unsigned int printk_count;

	struct event_format **events;
	int nr_events;
	struct event_format **sort_events;
	enum event_sort_type last_type;

	int type_offset;
	int type_size;

	int pid_offset;
	int pid_size;

 	int pc_offset;
	int pc_size;

	int flags_offset;
	int flags_size;

	int ld_offset;
	int ld_size;

	int print_raw;

	struct format_field *bprint_ip_field;
	struct format_field *bprint_fmt_field;
	struct format_field *bprint_buf_field;

	struct event_handler *handlers;
	struct pevent_function_handler *func_handlers;

	/* cache */
	struct event_format *last_event;
};

/* Can be overridden */
void die(char *fmt, ...);
void *malloc_or_die(unsigned int size);
void warning(char *fmt, ...);
void pr_stat(char *fmt, ...);

/* Always available */
void __die(char *fmt, ...);
void __warning(char *fmt, ...);
void __pr_stat(char *fmt, ...);

void __vdie(char *fmt, ...);
void __vwarning(char *fmt, ...);
void __vpr_stat(char *fmt, ...);

static inline unsigned short
__data2host2(struct pevent *pevent, unsigned short data)
{
	unsigned short swap;

	if (pevent->host_bigendian == pevent->file_bigendian)
		return data;

	swap = ((data & 0xffULL) << 8) |
		((data & (0xffULL << 8)) >> 8);

	return swap;
}

static inline unsigned int
__data2host4(struct pevent *pevent, unsigned int data)
{
	unsigned int swap;

	if (pevent->host_bigendian == pevent->file_bigendian)
		return data;

	swap = ((data & 0xffULL) << 24) |
		((data & (0xffULL << 8)) << 8) |
		((data & (0xffULL << 16)) >> 8) |
		((data & (0xffULL << 24)) >> 24);

	return swap;
}

static inline unsigned long long
__data2host8(struct pevent *pevent, unsigned long long data)
{
	unsigned long long swap;

	if (pevent->host_bigendian == pevent->file_bigendian)
		return data;

	swap = ((data & 0xffULL) << 56) |
		((data & (0xffULL << 8)) << 40) |
		((data & (0xffULL << 16)) << 24) |
		((data & (0xffULL << 24)) << 8) |
		((data & (0xffULL << 32)) >> 8) |
		((data & (0xffULL << 40)) >> 24) |
		((data & (0xffULL << 48)) >> 40) |
		((data & (0xffULL << 56)) >> 56);

	return swap;
}

#define data2host2(pevent, ptr)		__data2host2(pevent, *(unsigned short *)(ptr))
#define data2host4(pevent, ptr)		__data2host4(pevent, *(unsigned int *)(ptr))
#define data2host8(pevent, ptr)		__data2host8(pevent, *(unsigned long long *)(ptr))

/* taken from kernel/trace/trace.h */
enum trace_flag_type {
	TRACE_FLAG_IRQS_OFF		= 0x01,
	TRACE_FLAG_IRQS_NOSUPPORT	= 0x02,
	TRACE_FLAG_NEED_RESCHED		= 0x04,
	TRACE_FLAG_HARDIRQ		= 0x08,
	TRACE_FLAG_SOFTIRQ		= 0x10,
};

int pevent_register_comm(struct pevent *pevent, char *comm, int pid);
int pevent_register_function(struct pevent *pevent, char *name,
			     unsigned long long addr, char *mod);
int pevent_register_print_string(struct pevent *pevent, char *fmt,
				 unsigned long long addr);
int pevent_pid_is_registered(struct pevent *pevent, int pid);

void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
			struct record *record);

int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
			     int long_size);

int pevent_parse_event(struct pevent *pevent, char *buf, unsigned long size, char *sys);

int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name,
				  pevent_event_handler_func func);
int pevent_register_print_function(struct pevent *pevent,
				   pevent_func_handler func,
				   enum pevent_func_arg_type ret_type,
				   char *name, ...);

struct format_field *pevent_find_common_field(struct event_format *event, const char *name);
struct format_field *pevent_find_field(struct event_format *event, const char *name);
struct format_field *pevent_find_any_field(struct event_format *event, const char *name);

const char *pevent_find_function(struct pevent *pevent, unsigned long long addr);
unsigned long long
pevent_find_function_address(struct pevent *pevent, unsigned long long addr);
unsigned long long pevent_read_number(struct pevent *pevent, const void *ptr, int size);
int pevent_read_number_field(struct format_field *field, const void *data,
			     unsigned long long *value);

struct event_format *pevent_find_event(struct pevent *pevent, int id);

struct event_format *
pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name);

void pevent_data_lat_fmt(struct pevent *pevent,
			 struct trace_seq *s, struct record *record);
int pevent_data_type(struct pevent *pevent, struct record *rec);
struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type);
int pevent_data_pid(struct pevent *pevent, struct record *rec);
const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid);
void pevent_event_info(struct trace_seq *s, struct event_format *event,
		       struct record *record);

struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type);
struct format_field **pevent_event_common_fields(struct event_format *event);
struct format_field **pevent_event_fields(struct event_format *event);

static inline int pevent_get_cpus(struct pevent *pevent)
{
	return pevent->cpus;
}

static inline void pevent_set_cpus(struct pevent *pevent, int cpus)
{
	pevent->cpus = cpus;
}

static inline int pevent_get_long_size(struct pevent *pevent)
{
	return pevent->long_size;
}

static inline void pevent_set_long_size(struct pevent *pevent, int long_size)
{
	pevent->long_size = long_size;
}

static inline int pevent_is_file_bigendian(struct pevent *pevent)
{
	return pevent->file_bigendian;
}

static inline void pevent_set_file_bigendian(struct pevent *pevent, int endian)
{
	pevent->file_bigendian = endian;
}

static inline int pevent_is_host_bigendian(struct pevent *pevent)
{
	return pevent->host_bigendian;
}

static inline void pevent_set_host_bigendian(struct pevent *pevent, int endian)
{
	pevent->host_bigendian = endian;
}

static inline int pevent_is_latency_format(struct pevent *pevent)
{
	return pevent->latency_format;
}

static inline void pevent_set_latency_format(struct pevent *pevent, int lat)
{
	pevent->latency_format = lat;
}

struct pevent *pevent_alloc(void);
void pevent_free(struct pevent *pevent);
void pevent_ref(struct pevent *pevent);
void pevent_unref(struct pevent *pevent);

/* access to the internal parser */
void pevent_buffer_init(const char *buf, unsigned long long size);
enum event_type pevent_read_token(char **tok);
void pevent_free_token(char *token);
int pevent_peek_char(void);

/* for debugging */
void pevent_print_funcs(struct pevent *pevent);
void pevent_print_printk(struct pevent *pevent);

/* ----------------------- filtering ----------------------- */

enum filter_boolean_type {
	FILTER_FALSE,
	FILTER_TRUE,
};

enum filter_op_type {
	FILTER_OP_AND = 1,
	FILTER_OP_OR,
	FILTER_OP_NOT,
};

enum filter_cmp_type {
	FILTER_CMP_NONE,
	FILTER_CMP_EQ,
	FILTER_CMP_NE,
	FILTER_CMP_GT,
	FILTER_CMP_LT,
	FILTER_CMP_GE,
	FILTER_CMP_LE,
	FILTER_CMP_MATCH,
	FILTER_CMP_NOT_MATCH,
	FILTER_CMP_REGEX,
	FILTER_CMP_NOT_REGEX,
};

enum filter_exp_type {
	FILTER_EXP_NONE,
	FILTER_EXP_ADD,
	FILTER_EXP_SUB,
	FILTER_EXP_MUL,
	FILTER_EXP_DIV,
	FILTER_EXP_MOD,
	FILTER_EXP_RSHIFT,
	FILTER_EXP_LSHIFT,
	FILTER_EXP_AND,
	FILTER_EXP_OR,
	FILTER_EXP_XOR,
	FILTER_EXP_NOT,
};

enum filter_arg_type {
	FILTER_ARG_NONE,
	FILTER_ARG_BOOLEAN,
	FILTER_ARG_VALUE,
	FILTER_ARG_FIELD,
	FILTER_ARG_EXP,
	FILTER_ARG_OP,
	FILTER_ARG_NUM,
	FILTER_ARG_STR,
};

enum filter_value_type {
	FILTER_NUMBER,
	FILTER_STRING
};

struct fliter_arg;

struct filter_arg_boolean {
	enum filter_boolean_type	value;
};

struct filter_arg_field {
	struct format_field	*field;
};

struct filter_arg_value {
	enum filter_value_type	type;
	union {
		char			*str;
		unsigned long long	val;
	};
};

struct filter_arg_op {
	enum filter_op_type	type;
	struct filter_arg	*left;
	struct filter_arg	*right;
};

struct filter_arg_num {
	enum filter_cmp_type	type;
	struct filter_arg	*left;
	struct filter_arg	*right;
};

struct filter_arg_str {
	enum filter_cmp_type	type;
	struct format_field	*field;
	char			*val;
	char			*buffer;
	regex_t			reg;
};

struct filter_arg {
	enum filter_arg_type	type;
	union {
		struct filter_arg_boolean	bool;
		struct filter_arg_field		field;
		struct filter_arg_value		value;
		struct filter_arg_op		op;
		struct filter_arg_num		num;
		struct filter_arg_str		str;
	};
};

struct filter_type {
	int			event_id;
	struct event_format	*event;
	struct filter_arg	*filter;
};

struct event_filter {
	struct pevent		*pevent;
	int			filters;
	struct filter_type	*event_filters;
};

struct event_filter *pevent_filter_alloc(struct pevent *pevent);

#define FILTER_NONE		-2
#define FILTER_NOEXIST		-1
#define FILTER_MISS		0
#define FILTER_MATCH		1

enum filter_trivial_type {
	FILTER_TRIVIAL_FALSE,
	FILTER_TRIVIAL_TRUE,
	FILTER_TRIVIAL_BOTH,
};

int pevent_filter_add_filter_str(struct event_filter *filter,
				 const char *filter_str,
				 char **error_str);


int pevent_filter_match(struct event_filter *filter,
			struct record *record);

int pevent_event_filtered(struct event_filter *filter,
			  int event_id);

void pevent_filter_reset(struct event_filter *filter);

void pevent_filter_clear_trivial(struct event_filter *filter,
				 enum filter_trivial_type type);

void pevent_filter_free(struct event_filter *filter);

char *pevent_filter_make_string(struct event_filter *filter, int event_id);

int pevent_filter_remove_event(struct event_filter *filter,
			       int event_id);

int pevent_filter_event_has_trivial(struct event_filter *filter,
				    int event_id,
				    enum filter_trivial_type type);

int pevent_filter_copy(struct event_filter *dest, struct event_filter *source);

int pevent_update_trivial(struct event_filter *dest, struct event_filter *source,
			  enum filter_trivial_type type);

#endif /* _PARSE_EVENTS_H */