Upgrade libtraceevent to libtraceevent-1.7.1 am: e50996d4ce am: 5ca0b9f527 am: 469cb9091d

Original change: https://android-review.googlesource.com/c/platform/external/libtraceevent/+/2394172

Change-Id: I9f49550ee21b814d17a765432e84836dc41e8a20
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.gitignore b/.gitignore
index e203d72..39a013b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,12 +2,17 @@
 TRACEEVENT-CFLAGS
 libtraceevent-dynamic-list
 libtraceevent.so.*
+.pc
+patches
 *.o
 build_prefix
 build_uninstall
 *~
 \#*\#
+.#*
 *.cmd
 *.so
 .*.d
 ep_version.h
+libtraceevent.pc
+lib/
diff --git a/Documentation/libtraceevent-commands.txt b/Documentation/libtraceevent-commands.txt
index 185ff16..cea3001 100644
--- a/Documentation/libtraceevent-commands.txt
+++ b/Documentation/libtraceevent-commands.txt
@@ -3,7 +3,7 @@
 
 NAME
 ----
-tep_register_comm, tep_override_comm, tep_pid_is_registered,
+tep_register_comm, tep_override_comm, tep_is_pid_registered,
 tep_data_comm_from_pid, tep_data_pid_from_comm, tep_cmdline_pid -
 Manage pid to process name mappings.
 
diff --git a/Documentation/libtraceevent-field_get_val.txt b/Documentation/libtraceevent-field_get_val.txt
index 69d51bf..6a5f1cd 100644
--- a/Documentation/libtraceevent-field_get_val.txt
+++ b/Documentation/libtraceevent-field_get_val.txt
@@ -64,10 +64,10 @@
 {
 	int len;
 	char *comm;
-	struct tep_event_format *event;
+	struct tep_event *event;
 	unsigned long long val;
 
-	event = tep_find_event_by_record(pevent, record);
+	event = tep_find_event_by_record(tep, record);
 	if (event != NULL) {
 		if (tep_get_common_field_val(NULL, event, "common_type",
 					     record, &val, 0) == 0) {
diff --git a/Documentation/libtraceevent-func_apis.txt b/Documentation/libtraceevent-func_apis.txt
index a465d63..1b836a1 100644
--- a/Documentation/libtraceevent-func_apis.txt
+++ b/Documentation/libtraceevent-func_apis.txt
@@ -3,10 +3,8 @@
 
 NAME
 ----
-tep_find_function, tep_find_function_address, tep_set_function_resolver,
-tep_reset_function_resolver, tep_register_function, tep_register_print_string,
-tep_get_function_count -
-function related tep APIs
+tep_set_function_resolver, tep_reset_function_resolver, tep_register_function, tep_register_print_string,
+tep_get_function_count - function related tep APIs
 
 SYNOPSIS
 --------
@@ -17,8 +15,6 @@
 typedef char pass:[*](*tep_func_resolver_t*)(void pass:[*]_priv_, unsigned long long pass:[*]_addrp_, char pass:[**]_modp_);
 int *tep_set_function_resolver*(struct tep_handle pass:[*]_tep_, tep_func_resolver_t pass:[*]_func_, void pass:[*]_priv_);
 void *tep_reset_function_resolver*(struct tep_handle pass:[*]_tep_);
-const char pass:[*]*tep_find_function*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_);
-unsigned long long *tep_find_function_address*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_);
 int *tep_register_function*(struct tep_handle pass:[*]_tep_, char pass:[*]_name_, unsigned long long _addr_, char pass:[*]_mod_);
 int *tep_register_print_string*(struct tep_handle pass:[*]_tep_, const char pass:[*]_fmt_, unsigned long long _addr_);
 int *tep_get_function_count*(struct tep_handle *_tep_)
@@ -38,8 +34,8 @@
 The *tep_set_function_resolver()* function registers _func_ as an alternative
 kernel functions resolver. The _tep_ argument is trace event parser context.
 The _priv_ argument is a custom context of the _func_ function. The function
-resolver is used by the APIs *tep_find_function()*,
-*tep_find_function_address()*, and *tep_print_func_field()* to resolve
+resolver is used by the APIs *tep_find_function*(3),
+*tep_find_function_address*(3), and *tep_print_func_field()* to resolve
 a function address to a function name.
 
 The *tep_reset_function_resolver()* function resets the kernel functions
@@ -51,14 +47,6 @@
 address. The given address does not have to be exact, it will select
 the function that would contain it.
 
-The *tep_find_function()* function returns the function name, which contains the
-given address _addr_. The _tep_ argument is the trace event parser context.
-
-The *tep_find_function_address()* function returns the function start address,
-by given address _addr_. The _addr_ does not have to be exact, it will select
-the function that would contain it. The _tep_ argument is the trace event
-parser context.
-
 The *tep_register_function()* function registers a function name mapped to an
 address and (optional) module. This mapping is used in case the function tracer
 or events have "%pS" parameter in its format string. It is common to pass in
@@ -84,12 +72,6 @@
 The *tep_set_function_resolver()* function returns 0 in case of success, or -1
 in case of an error.
 
-The *tep_find_function()* function returns the function name, or NULL in case
-it cannot be found.
-
-The *tep_find_function_address()* function returns the function start address,
-or 0 in case it cannot be found.
-
 The *tep_register_function()* function returns 0 in case of success. In case of
 an error -1 is returned, and errno is set to the appropriate error number.
 
diff --git a/Documentation/libtraceevent-func_find.txt b/Documentation/libtraceevent-func_find.txt
index 20982e9..26fac68 100644
--- a/Documentation/libtraceevent-func_find.txt
+++ b/Documentation/libtraceevent-func_find.txt
@@ -3,7 +3,7 @@
 
 NAME
 ----
-tep_find_function,tep_find_function_address - Find function name / start address.
+tep_find_function,tep_find_function_address,tep_find_function_info - Find function name / start address.
 
 SYNOPSIS
 --------
@@ -13,6 +13,8 @@
 
 const char pass:[*]*tep_find_function*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_);
 unsigned long long *tep_find_function_address*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_);
+int *tep_find_function_info*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_, const char pass:[**]_name_,
+			   unsigned long long pass:[*]_start_, unsigned long pass:[*]_size_);
 --
 
 DESCRIPTION
@@ -28,6 +30,11 @@
 by given address _addr_. The _addr_ does not have to be exact, it will select the
 function that would contain it. The _tep_ argument is the trace event parser context.
 
+The *tep_find_function_info()* function retrieves the _name_, starting address (_start_),
+and the function text _size_ of the function at _address_, if it is found. Note,
+if the _tep_ handle has a function resolver (used by perf), then _size_ is set to
+zero.
+
 RETURN VALUE
 ------------
 The *tep_find_function()* function returns the function name, or NULL in case
@@ -36,6 +43,9 @@
 The *tep_find_function_address()* function returns the function start address,
 or 0 in case it cannot be found.
 
+The *tep_find_function_info()* function returns 1 if a function is found for the
+given address, or 0 if it is not.
+
 EXAMPLE
 -------
 [source,c]
@@ -44,12 +54,45 @@
 ...
 struct tep_handle *tep = tep_alloc();
 ...
-void show_function( unsigned long long addr)
+void show_function_name(unsigned long long addr)
 {
 	const char *fname = tep_find_function(tep, addr);
-	unsigned long long fstart = tep_find_function_address(tep, addr);
 
-	/* addr is in function named fname, starting at fstart address, at offset (addr - fstart) */
+	if (fname)
+		printf("Found function %s at 0x%0llx\n", fname, addr);
+	else
+		printf("No function found at 0x%0llx\n", addr);
+}
+
+void show_function_start_addr(unsigned long long addr)
+{
+	const char *fname = tep_find_function(tep, addr);
+	unsigned long long fstart;
+
+	if (!fname) {
+		printf("No function found at 0x%0llx\n", addr);
+		return;
+	}
+
+	fstart = tep_find_function_address(tep, addr);
+	printf("Function %s at 0x%llx starts at 0x%0llx\n",
+	       fname, addr, fstart);
+}
+
+void show_function_info(unsigned long long addr)
+{
+	const char *fname;
+	unsigned long long fstart;
+	unsigned long size;
+
+	ret = tep_find_function_info(tep, addr, &fname, &fstart, &size);
+	if (!ret) {
+		printf("No function found at 0x%0lx\n", addr);
+		return;
+	}
+
+	printf("Function %s at 0x%lx starts at 0x%0lx and is %ld in size\n",
+	       fname, addr, fstart, size);
 }
 ...
 --
diff --git a/Documentation/libtraceevent-handle.txt b/Documentation/libtraceevent-handle.txt
index 0d6afda..64528eb 100644
--- a/Documentation/libtraceevent-handle.txt
+++ b/Documentation/libtraceevent-handle.txt
@@ -3,7 +3,7 @@
 
 NAME
 ----
-tep_alloc, tep_free,tep_ref, tep_unref,tep_get_ref - Create, destroy, manage
+tep_alloc, tep_free,tep_ref, tep_unref,tep_get_ref, tep_kbuffer - Create, destroy, manage
 references of trace event parser context.
 
 SYNOPSIS
@@ -40,6 +40,10 @@
 
 The *tep_ref_get()* functions gets the current references of the _tep_ handler.
 
+The *tep_kbuffer()* function allocates a kbuffer descriptor that can be used to
+parse raw data that is represented by the _tep_ handle descriptor. It must be freed
+with *kbuf_free(3)*.
+
 RETURN VALUE
 ------------
 *tep_alloc()* returns a pointer to a newly created tep_handle structure.
@@ -48,6 +52,9 @@
 *tep_ref_get()* returns the current references of _tep_.
 If _tep_ is NULL, 0 is returned.
 
+*tep_kbuffer()* returns a kbuffer descriptor that can parse the raw data that
+represents the tep handle. Must be freed with *kbuf_free(3)*.
+
 EXAMPLE
 -------
 [source,c]
diff --git a/Documentation/libtraceevent-kbuffer-create.txt b/Documentation/libtraceevent-kbuffer-create.txt
new file mode 100644
index 0000000..12e5d6c
--- /dev/null
+++ b/Documentation/libtraceevent-kbuffer-create.txt
@@ -0,0 +1,207 @@
+libtraceevent(3)
+================
+
+NAME
+----
+kbuffer_alloc, kbuffer_free, kbuffer_load_subbuffer, kbuffer_subbuffer_size, kbuffer_start_of_data - Creating of kbuffer element to parse
+the Linux kernel tracing ring buffer
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <kbuffer.h>*
+
+enum kbuffer_endian {
+	KBUFFER_ENDIAN_BIG,
+	KBUFFER_ENDIAN_LITTLE,
+	KBUFFER_ENDIAN_SAME_AS_HOST,
+};
+
+enum kbuffer_long_size {
+	KBUFFER_LSIZE_4,
+	KBUFFER_LSIZE_8,
+	KBUFFER_LSIZE_SAME_AS_HOST,
+};
+
+struct kbuffer;
+struct tep_handle;
+
+struct kbuffer pass:[*]*kbuffer_alloc*(enum kbuffer_long_size _size_, enum kbuffer_endian _endian_);
+void *kbuffer_free*(struct kbuffer pass:[*]_kbuf_);
+int *kbuffer_load_subbuffer*(struct kbuffer pass:[*]_kbuf_, void pass:[*]_subbuffer_);
+int *kbuffer_subbuffer_size*(struct kbuffer pass:[*]_kbuf);
+int *kbuffer_start_of_data*(struct kbuffer pass:[*]_kbuf_);
+--
+
+DESCRIPTION
+-----------
+These functions create a _kbuffer_ handle that can be used to parse the raw sub buffers
+of the Linux kernel tracing ring buffer. The ring buffer is found in the tracefs
+directory, and can be retrieved by *tracefs_instance_get_file(3)* at
+*per_cpu/cpuX/trace_pipe_raw* where *X* is replaced by the per CPU number of
+the specified ring buffer. The ring buffer inside the kernel is split up per
+CPU, such that the raw ring buffer must be retrieved per CPU as well.
+
+The *kbuffer_alloc()* will create a descriptor that can be used to manage a sub buffer
+read by the ring buffer. The _size_ parameter denotes what the word size is
+for the given buffer (note, this works from reading raw data from machines other
+than the machine that is calling this function). The _endian_ denotes the endian
+for the machine.
+
+If _endian_ is set to _KBUFFER_ENDIAN_SAME_AS_HOST_ the endian will be set to the same
+as the host endianess, which is useful when the application is reading the
+ring buffer data directly from the same machine it is running on.
+
+If _size_ is set to _KBUFFER_LSIZE_SAME_AS_HOST_, if the word size is 8, it will
+set the kbuffer descriptor to long size of 8. But if the size is 4, then it
+will then perform a *uname(2)* call, and if the _machine_ field has the string "64"
+in it, it will be set to 8 byte long size and not 4 byte. This is because the
+ring buffer long size is dependent on the kernel and not user space.
+
+The *kbuffer_free()* function will free the resources created by *kbuffer_alloc()*.
+
+The *kbuffer_load_subbuffer()* will take a _subbuffer_ which is a raw data blob
+from the tracefs *trace_pipe_raw* file. The Linux tracing ring buffer is broken up
+into sub buffers. Each sub buffer is as stand alone data segment that has all the
+information to split out the individual events and time stamps. This sub buffer
+is what kbuffer uses to walk the events.
+
+The *kbuffer_subbuffer_size()* returns the location of the end of the last event
+on the sub-buffer. It does not return the size of the sub-buffer itself.
+
+The *kbuffer_start_of_data()* function returns the offset of where the actual
+data load of the sub-buffer begins.
+
+RETURN VALUE
+------------
+*kbuffer_alloc()* returns an allocated kbuffer descriptor or NULL on error.
+The returned descriptor must be freed with *kbuffer_free()*
+
+*kbuffer_load_subbuffer()* returns 0 on success and -1 on error.
+
+*kbuffer_subbuffer_size()* returns the index on the subbuffer where the end
+of the last event is located.
+
+*kbuffer_start_of_data()* returns the offset of where the data begins on the
+sub-buffer loaded in _kbuf_.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <kbuffer.h>
+
+int main (int argc, char **argv)
+{
+	unsigned long long ts;
+	struct kbuffer *kbuf;
+	struct stat st;
+	char *buf;
+	void *event;
+	int ret;
+	int fd;
+	int i = 0;
+
+	if (argc < 2) {
+		printf("usage: %s raw-subbuffer-page\n", argv[0]);
+		printf(" Try: dd count=1 bs=4096 if=/sys/kernel/tracing/per_cpu/cpu0/trace_pipe_raw of=/tmp/file\n");
+		exit(0);
+	}
+
+	if (stat(argv[1], &st) < 0) {
+		perror("stat");
+		exit(-1);
+	}
+
+	buf = malloc(st.st_size);
+	if (!buf) {
+		perror("Allocating buffer");
+		exit(-1);
+	}
+
+	fd = open(argv[1], O_RDONLY);
+	if (fd < 0) {
+		perror(argv[1]);
+		exit(-1);
+	}
+
+	ret = read(fd, buf, st.st_size);
+	if (ret < 0) {
+		perror("Reading buffer");
+		exit(-1);
+	}
+	close(fd);
+
+	kbuf = kbuffer_alloc(KBUFFER_ENDIAN_SAME_AS_HOST,
+			     KBUFFER_LSIZE_SAME_AS_HOST);
+	if (!kbuf) {
+		perror("Creating kbuffer");
+		exit(-1);
+	}
+	ret = kbuffer_load_subbuffer(kbuf, buf);
+	if (ret < 0) {
+		perror("Loading sub bufer");
+		exit(-1);
+	}
+
+	if (kbuffer_subbuffer_size(kbuf) > st.st_size) {
+		fprintf(stderr, "kbuffer is bigger than raw size %d > %ld\n",
+			kbuffer_subbuffer_size(kbuf), st.st_size);
+		exit(-1);
+	}
+
+	printf("Kbuffer data starts at %d\n", kbuffer_start_of_data(kbuf));
+	do {
+		event = kbuffer_read_event(kbuf, &ts);
+		if (event) {
+			printf(" event %3d ts:%lld\n", i++, ts);
+			event = kbuffer_next_event(kbuf, NULL);
+		}
+	} while (event);
+
+	if (!event)
+		printf("Finished sub buffer\n");
+
+	kbuffer_free(kbuf);
+
+	return 0;
+}
+--
+FILES
+-----
+[verse]
+--
+*event-parse.h*
+	Header file to include in order to have access to the library APIs.
+*-ltraceevent*
+	Linker switch to add when building a program that uses the library.
+--
+
+SEE ALSO
+--------
+*libtraceevent*(3), *trace-cmd*(1)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*.
+--
+REPORTING BUGS
+--------------
+Report bugs to  <linux-trace-devel@vger.kernel.org>
+
+LICENSE
+-------
+libtraceevent is Free Software licensed under the GNU LGPL 2.1
+
+RESOURCES
+---------
+https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/
diff --git a/Documentation/libtraceevent-kbuffer-read.txt b/Documentation/libtraceevent-kbuffer-read.txt
new file mode 100644
index 0000000..68184ad
--- /dev/null
+++ b/Documentation/libtraceevent-kbuffer-read.txt
@@ -0,0 +1,246 @@
+libtraceevent(3)
+================
+
+NAME
+----
+kbuffer_read_event, kbuffer_next_event, kbuffer_missed_events, kbuffer_event_size, kbuffer_curr_size,
+kbuffer_curr_offset, kbuffer_curr_index -
+Functions to read through the kbuffer sub buffer.
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <kbuffer.h>*
+
+void pass:[*]*kbuffer_read_event*(struct kbuffer pass:[*]_kbuf_, unsigned long long pass:[*]_ts_);
+void pass:[*]*kbuffer_next_event*(struct kbuffer pass:[*]_kbuf_, unsigned long long pass:[*]_ts_);
+void pass:[*]*kbuffer_read_at_offset*(struct kbuffer pass:[*]_kbuf_, int _offset_, unsigned long long pass:[*]_ts_);
+int *kbuffer_missed_events*(struct kbuffer pass:[*]_kbuf_);
+int *kbuffer_event_size*(struct kbuffer pass:[*]_kbuf_);
+int *kbuffer_curr_size*(struct kbuffer pass:[*]_kbuf_);
+int *kbuffer_curr_offset*(struct kbuffer pass:[*]_kbuf_);
+int *kbuffer_curr_index*(struct kbuffer pass:[*]_kbuf_);
+--
+
+DESCRIPTION
+-----------
+The function *kbuffer_read_event()* reads the next event in the _kbuf_ descriptor
+and if _ts_ is non NULL, will place its timestamp into it. This does not modify the _kbuf_
+descriptor, and calling this function mulitple times will return the same result.
+
+The function *kbuffer_next_event()* will return the next event in the _kbuf_ descriptor.
+It will also set the _ts_ to the timestamp of the returned event. NULL is returned
+if there are no more events and _ts_ will be undefined. Note, if this is called directly
+after a *kbuffer_load_subbuffer()* then it will likely give an unexpected result, as it
+will return the second event and not the first event. Usually this function is only used
+to move to the next event and to know if there's any more events to read, and
+*kbuffer_read_event()* is always called first.
+
+The function *kbuffer_read_at_offset()* returns the event located at a given _offset_ from
+the beginning of the sub-buffer. This offset can be retrieved by *kbuffer_curr_offset()*.
+If _ts_ points to an unsigned long long, then it will be set to the event at the given
+offset's timestamp.
+
+If the sub-buffer had missed events before it, then *kbuffer_missed_events()* will return
+the non zero. If it returns -1, that means there were missed events, but the exact number
+of missed events is unknown. If it returns a positive number, then the number of missed events
+is the return value.
+
+The *kbuffer_event_size()* function returns the size of the data portion of the current event
+(the one that would be returned by *kbuffer_read_event()*.
+
+The *kbuffer_curr_size()* function returns the entire record size of the current event
+(the one that would be returned by *kbuffer_read_event()*. The difference here is that the
+return value includes the size of the event record meta data that is not part of what
+is returned by *kbuffer_read_event()*.
+
+The *kbuffer_curr_offset()* function returns the offset from the beginning of the sub-buffer
+of where the current event's meta data for the record begins. The first event will
+not be at offset zero. This offset can be used to retrieve the event with
+*kbuffer_read_at_offset()*.
+
+The *kbuffer_curr_index()* function returns the index from the beginning of the data
+portion of the sub-buffer where the current evnet's meta data is located.
+The first event will likely be zero, but may not be if there's a timestamp attached to it.
+
+RETURN VALUE
+------------
+*kbuffer_read_event()* returns the event that the _kbuf_ descriptor is currently at,
+or NULL if the last event was passed (by *kbuffer_next_event()*).
+
+*kbuffer_next_event()* returns the next event after the current event or NULL if there
+are no more events.
+
+*kbuffer_read_at_offset()* returns the event at a given _offset_ from the start of
+the sub-buffer stored in _kbuf_, or NULL if there exists no event. Note, _offset_
+only needs to be an offset that lands on the record, or is at the start of it. It does
+not need to be exactly at the beginning of the record.
+
+*kbuffer_missed_events()* returns 0 if there were no missed events before loaded sub-buffer.
+Returns -1 if there were an unknown number of missed events, or if the number of missed events
+is known, that number will be returned.
+
+*kbuffer_event_size()* returns the size of the data payload of the current event of _kbuf_.
+
+*kbuffer_curr_size()* returns the size of the entire record of the current event of _kbuf_.
+This includes the size of the meta data for that record.
+
+*kbuf_curr_offset()* returns the offset of the current record from the beginning of the _kbuf_
+sub-buffer.
+
+*kbuf_curr_index()* returns the index of the current record from the beginning of the _kbuf_
+data section.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <kbuffer.h>
+
+int main (int argc, char **argv)
+{
+	unsigned long long ts;
+	struct kbuffer *kbuf;
+	struct stat st;
+	char *buf;
+	void *event;
+	int save_offset = -1;
+	int record_size;
+	int offset;
+	int index;
+	int size;
+	int ret;
+	int fd;
+	int i = 0;
+
+	if (argc < 2) {
+		printf("usage: %s raw-subbuffer-page\n", argv[0]);
+		printf(" Try: dd count=1 bs=4096 if=/sys/kernel/tracing/per_cpu/cpu0/trace_pipe_raw of=/tmp/file\n");
+		exit(0);
+	}
+
+	if (stat(argv[1], &st) < 0) {
+		perror("stat");
+		exit(-1);
+	}
+
+	buf = malloc(st.st_size);
+	if (!buf) {
+		perror("Allocating buffer");
+		exit(-1);
+	}
+
+	fd = open(argv[1], O_RDONLY);
+	if (fd < 0) {
+		perror(argv[1]);
+		exit(-1);
+	}
+
+	ret = read(fd, buf, st.st_size);
+	if (ret < 0) {
+		perror("Reading buffer");
+		exit(-1);
+	}
+	close(fd);
+
+	kbuf = kbuffer_alloc(KBUFFER_ENDIAN_SAME_AS_HOST,
+			     KBUFFER_LSIZE_SAME_AS_HOST);
+	if (!kbuf) {
+		perror("Creating kbuffer");
+		exit(-1);
+	}
+	ret = kbuffer_load_subbuffer(kbuf, buf);
+	if (ret < 0) {
+		perror("Loading sub bufer");
+		exit(-1);
+	}
+
+	if (kbuffer_subbuffer_size(kbuf) > st.st_size) {
+		fprintf(stderr, "kbuffer is bigger than raw size %d > %ld\n",
+			kbuffer_subbuffer_size(kbuf), st.st_size);
+		exit(-1);
+	}
+
+	ret = kbuffer_missed_events(kbuf);
+	if (ret) {
+		if (ret > 0)
+			printf("Missed %d events before this buffer\n", ret);
+		else
+			printf("Missed unknown number of events before this buffer\n");
+	}
+	do {
+		event = kbuffer_read_event(kbuf, &ts);
+		if (event) {
+			record_size = kbuffer_curr_size(kbuf);
+			offset = kbuffer_curr_offset(kbuf);
+			index = kbuffer_curr_index(kbuf);
+			size = kbuffer_event_size(kbuf);
+
+			if (i == 20)
+				save_offset = offset;
+			printf(" event %3d ts:%lld\trecord_size:%d size:%d\tindex:%d offset:%d\n",
+			       i++, ts, record_size, size, index, offset);
+			event = kbuffer_next_event(kbuf, NULL);
+		}
+	} while (event);
+
+	if (!event)
+		printf("Finished sub buffer\n");
+
+	if (save_offset > 0) {
+		event = kbuffer_read_at_offset(kbuf, save_offset, &ts);
+		if (!event) {
+			fprintf(stderr, "Funny, can't find event 20 at offset %d\n", save_offset);
+			exit(-1);
+		}
+		record_size = kbuffer_curr_size(kbuf);
+		offset = kbuffer_curr_offset(kbuf);
+		index = kbuffer_curr_index(kbuf);
+		size = kbuffer_event_size(kbuf);
+
+		printf("\n saved event 20 ts:%lld\trecord_size:%d size:%d\tindex:%d offset:%d\n\n",
+		       ts, record_size, size, index, offset);
+	}
+	kbuffer_free(kbuf);
+
+	return 0;
+}
+--
+FILES
+-----
+[verse]
+--
+*event-parse.h*
+	Header file to include in order to have access to the library APIs.
+*-ltraceevent*
+	Linker switch to add when building a program that uses the library.
+--
+
+SEE ALSO
+--------
+*libtraceevent*(3), *trace-cmd*(1)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*.
+--
+REPORTING BUGS
+--------------
+Report bugs to  <linux-trace-devel@vger.kernel.org>
+
+LICENSE
+-------
+libtraceevent is Free Software licensed under the GNU LGPL 2.1
+
+RESOURCES
+---------
+https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/
diff --git a/Documentation/libtraceevent-kbuffer-timestamp.txt b/Documentation/libtraceevent-kbuffer-timestamp.txt
new file mode 100644
index 0000000..d7de225
--- /dev/null
+++ b/Documentation/libtraceevent-kbuffer-timestamp.txt
@@ -0,0 +1,208 @@
+libtraceevent(3)
+================
+
+NAME
+----
+kbuffer_timestamp, kbuffer_subbuf_timestamp -
+Functions that read various data of a kbuffer descriptor
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <kbuffer.h>*
+
+unsigned long long *kbuffer_timestamp*(struct kbuffer pass:[*]_kbuf_);
+unsigned long long *kbuffer_subbuf_timestamp*(struct kbuffer pass:[*]_kbuf_, void pass:[*]_subbuf_);
+--
+
+DESCRIPTION
+-----------
+The function *kbuffer_timestamp()* returns the timestamp of the current event of _kbuf_.
+
+The function *kbuffer_subbuf_timestamp()* returns the timestamp for the sub-buffer
+that was loaded in _kbuf_. This usually is (but not guaranteed to be) the timestamp
+of the first event on the sub-buffer.
+
+The function *kbuffer_start_of_data()* returns the offset of where the delta
+
+RETURN VALUE
+------------
+*kbuffer_read_event()* returns the event that the _kbuf_ descriptor is currently at,
+or NULL if the last event was passed (by *kbuffer_next_event()*).
+
+*kbuffer_next_event()* returns the next event after the current event or NULL if there
+are no more events.
+
+*kbuffer_read_at_offset()* returns the event at a given _offset_ from the start of
+the sub-buffer stored in _kbuf_, or NULL if there exists no event. Note, _offset_
+only needs to be an offset that lands on the record, or is at the start of it. It does
+not need to be exactly at the beginning of the record.
+
+*kbuffer_missed_events()* returns 0 if there were no missed events before loaded sub-buffer.
+Returns -1 if there were an unknown number of missed events, or if the number of missed events
+is known, that number will be returned.
+
+*kbuffer_event_size()* returns the size of the data payload of the current event of _kbuf_.
+
+*kbuffer_curr_size()* returns the size of the entire record of the current event of _kbuf_.
+This includes the size of the meta data for that record.
+
+*kbuf_curr_offset()* returns the offset of the current record from the beginning of the _kbuf_
+sub-buffer.
+
+*kbuf_curr_index()* returns the index of the current record from the beginning of the _kbuf_
+data section.
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <kbuffer.h>
+
+int main (int argc, char **argv)
+{
+	unsigned long long ts;
+	struct kbuffer *kbuf;
+	struct stat st;
+	char *buf;
+	void *event;
+	int save_offset = -1;
+	int record_size;
+	int offset;
+	int index;
+	int size;
+	int ret;
+	int fd;
+	int i = 0;
+
+	if (argc < 2) {
+		printf("usage: %s raw-subbuffer-page\n", argv[0]);
+		printf(" Try: dd count=1 bs=4096 if=/sys/kernel/tracing/per_cpu/cpu0/trace_pipe_raw of=/tmp/file\n");
+		exit(0);
+	}
+
+	if (stat(argv[1], &st) < 0) {
+		perror("stat");
+		exit(-1);
+	}
+
+	buf = malloc(st.st_size);
+	if (!buf) {
+		perror("Allocating buffer");
+		exit(-1);
+	}
+
+	fd = open(argv[1], O_RDONLY);
+	if (fd < 0) {
+		perror(argv[1]);
+		exit(-1);
+	}
+
+	ret = read(fd, buf, st.st_size);
+	if (ret < 0) {
+		perror("Reading buffer");
+		exit(-1);
+	}
+	close(fd);
+
+	kbuf = kbuffer_alloc(KBUFFER_ENDIAN_SAME_AS_HOST,
+			     KBUFFER_LSIZE_SAME_AS_HOST);
+	if (!kbuf) {
+		perror("Creating kbuffer");
+		exit(-1);
+	}
+	ret = kbuffer_load_subbuffer(kbuf, buf);
+	if (ret < 0) {
+		perror("Loading sub bufer");
+		exit(-1);
+	}
+
+	if (kbuffer_subbuffer_size(kbuf) > st.st_size) {
+		fprintf(stderr, "kbuffer is bigger than raw size %d > %ld\n",
+			kbuffer_subbuffer_size(kbuf), st.st_size);
+		exit(-1);
+	}
+
+	ret = kbuffer_missed_events(kbuf);
+	if (ret) {
+		if (ret > 0)
+			printf("Missed %d events before this buffer\n", ret);
+		else
+			printf("Missed unknown number of events before this buffer\n");
+	}
+	do {
+		event = kbuffer_read_event(kbuf, &ts);
+		if (event) {
+			record_size = kbuffer_curr_size(kbuf);
+			offset = kbuffer_curr_offset(kbuf);
+			index = kbuffer_curr_index(kbuf);
+			size = kbuffer_event_size(kbuf);
+
+			if (i == 20)
+				save_offset = offset;
+			printf(" event %3d ts:%lld\trecord_size:%d size:%d\tindex:%d offset:%d\n",
+			       i++, ts, record_size, size, index, offset);
+			event = kbuffer_next_event(kbuf, NULL);
+		}
+	} while (event);
+
+	if (!event)
+		printf("Finished sub buffer\n");
+
+	if (save_offset > 0) {
+		event = kbuffer_read_at_offset(kbuf, save_offset, &ts);
+		if (!event) {
+			fprintf(stderr, "Funny, can't find event 20 at offset %d\n", save_offset);
+			exit(-1);
+		}
+		record_size = kbuffer_curr_size(kbuf);
+		offset = kbuffer_curr_offset(kbuf);
+		index = kbuffer_curr_index(kbuf);
+		size = kbuffer_event_size(kbuf);
+
+		printf("\n saved event 20 ts:%lld\trecord_size:%d size:%d\tindex:%d offset:%d\n\n",
+		       ts, record_size, size, index, offset);
+	}
+	kbuffer_free(kbuf);
+
+	return 0;
+}
+--
+FILES
+-----
+[verse]
+--
+*event-parse.h*
+	Header file to include in order to have access to the library APIs.
+*-ltraceevent*
+	Linker switch to add when building a program that uses the library.
+--
+
+SEE ALSO
+--------
+*libtraceevent*(3), *trace-cmd*(1)
+
+AUTHOR
+------
+[verse]
+--
+*Steven Rostedt* <rostedt@goodmis.org>, author of *libtraceevent*.
+--
+REPORTING BUGS
+--------------
+Report bugs to  <linux-trace-devel@vger.kernel.org>
+
+LICENSE
+-------
+libtraceevent is Free Software licensed under the GNU LGPL 2.1
+
+RESOURCES
+---------
+https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/
diff --git a/Documentation/libtraceevent-kvm-plugin.txt b/Documentation/libtraceevent-kvm-plugin.txt
new file mode 100644
index 0000000..a02e786
--- /dev/null
+++ b/Documentation/libtraceevent-kvm-plugin.txt
@@ -0,0 +1,252 @@
+libtraceevent(3)
+================
+
+NAME
+----
+tep_plugin_kvm_get_func, tep_plugin_kvm_put_func - Add function name for instruction pointer of kvm plugin
+
+SYNOPSIS
+--------
+[verse]
+--
+*#include <event-parse.h>*
+
+const char pass:[*]*tep_plugin_kvm_get_func*(struct tep_event pass:[*]event,
+				    struct tep_record pass:[*]record,
+				    unsigned long long pass:[*]paddr);
+void *tep_plugin_kvm_put_func*(const char pass:[*]func);
+--
+
+DESCRIPTION
+-----------
+The functions *tep_plugin_kvm_get_func()* and *tep_plugin_kvm_put_func()*
+are not to be called by an application, but instead are to be defined by
+an application.
+
+Certain events (like kvm_exit and kvm_entry) have the instruction pointer
+of where in the guest the context changed from guest to host. As the host
+only knows the instruction pointer and does not have information about what
+function in the guest that instruction pointer belongs to, it can only print
+the address.
+
+But the application may have more information about the guest, and know where
+the guest was when the exit occurred, and also even know the function name
+of that address.
+
+The KVM plugin for libtraceevent is called on these events, and then calls
+*tep_plugin_kvm_get_func()* to see if that function can resolve the instruction
+pointer address to a real function name. If the return is non NULL, it will
+print the function in the output for that event.
+
+These functions are currently defined as weak functions within the plugin, as
+to not require them to be defined elsewhere. For an application to override
+the weak function, it will need to define the function in a file that gets
+compiled with *-rdynamic*. That will tell the dynamic linker to examine that
+object file and use function names to resolve weak functions in other shared
+objects (in this case the KVM plugin shared object).
+
+If the application defines *tep_plugin_kvm_get_func()*, it must use the above
+prototype. The _event_ will hold the KVM event that has the instruction pointer
+field. The _record_ will be the instance of that event. The application's function
+does not need to use these parameters, but they may be useful for finding the
+function name for the address. The _paddr_ is a pointer to a 64 bit value (where
+only 32 bits may be used on 32 bit machines). This value is the instruction
+pointer to look up. If the application knows the start address of the function
+as well, it can set _paddr_ to that address, and the KVM plugin will also
+append a "+offset" to the function name where the offset is the original
+value in _paddr_ minus the value in _paddr_ when it is called. Finally,
+the application should return the function name as a nul terminated string
+if one is found.
+
+If the returned string of *tep_plugin_kvm_get_func()* was allocated, the KVM plugin
+will call *tep_plugin_kvm_put_func()* when it is through with it, passing the
+value returned by *tep_plugin_kvm_get_func()* as _func_. This allows the application
+to free it if necessary.
+
+RETURN VALUE
+------------
+The *tep_plugin_kvm_get_func()* is not to be called by the application but instead
+is to be defined by the application. It should return a nul terminated string representing
+the function for the given instruction pointer passed to it by reference in _paddr_. It
+can then optionally update the _paddr_ to a value that holds the start of the function.
+The string returned may be freed by the *tep_plugin_kvm_put_func()* that the application
+should define to clean up the string.
+
+The below example needs to be compiled with the *-rdynamic* flag so that the dynamic
+linker can resolve the *tep_plugin_kvm_get_func()* and *tep_plugin_kvm_put_func()* functions.
+
+When run against a trace.dat file produced by *trace-cmd(1)* recording the kvm_exit and
+kvm_entry events on a guest, and then the guest's /proc/kallsyms file is passed as the
+second parameter, the output produced will look something like:
+
+[source,c]
+--
+CPU 0/KVM-20407 83156.177626 [000] kvm_exit     reason APIC_ACCESS rip 0xffffffffb0056ee2 exit native_apic_mem_write+0x2 info 10b0 0
+CPU 0/KVM-20407 83156.177632 [000] kvm_entry     vcpu 0 rip 0xffffffffb0056ee8 enter native_apic_mem_write+0x8
+--
+
+But without those callbacks, it would look like:
+
+[source,c]
+--
+CPU 0/KVM-20407 83156.177626 [000] kvm_exit     reason APIC_ACCESS rip 0xffffffffb0056ee2 info 10b0 0
+CPU 0/KVM-20407 83156.177632 [000] kvm_entry     vcpu 0 rip 0xffffffffb0056ee8
+--
+
+EXAMPLE
+-------
+[source,c]
+--
+#include <stdio.h>
+#include <stdlib.h>
+#include <event-parse.h>
+#include <trace-cmd.h>
+#include <sys/stat.h>
+
+static struct tep_handle *tep;
+
+const char *tep_plugin_kvm_get_func(struct tep_event *event, struct tep_record *record,
+				    unsigned long long *paddr)
+{
+	const char *func;
+	char *event_func;
+	char *ename;
+
+	func = tep_find_function(tep, *paddr);
+	if (!func)
+		return NULL;
+
+	if (strcmp(event->name, "kvm_exit") == 0)
+		ename = "exit";
+	else
+		ename = "enter";
+
+	/*
+	 * Normally, passing back func directly is sufficient and then
+	 * tep_plugin_kvm_put_func() would not be required. But this example
+	 * is showing how to handle allocation of the returned string.
+	 */
+	event_func = malloc(strlen(ename) + strlen(func) + 2);
+	if (!event_func)
+		return NULL;
+	sprintf(event_func, "%s %s", ename, func);
+
+	*paddr = tep_find_function_address(tep, *paddr);
+
+	return event_func;
+}
+
+void tep_plugin_kvm_put_func(const char *func)
+{
+	char *f = (char *)func;
+
+	free(f);
+}
+
+static int show_event(struct tracecmd_input *handle, struct tep_event *event,
+		      struct tep_record *record, int cpu, void *data)
+{
+	static struct trace_seq seq;
+	tep = data;
+
+	if (!seq.buffer)
+		trace_seq_init(&seq);
+
+	trace_seq_reset(&seq);
+	tep_print_event(tracecmd_get_tep(handle), &seq, record,
+			"%s-%d\t%6.1000d [%03d] %s\t%s\n",
+			TEP_PRINT_COMM, TEP_PRINT_PID,
+			TEP_PRINT_TIME, TEP_PRINT_CPU,
+			TEP_PRINT_NAME, TEP_PRINT_INFO);
+	trace_seq_terminate(&seq);
+	trace_seq_do_printf(&seq);
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	struct tracecmd_input *handle;
+	struct tep_handle *guest_tep;
+	struct stat st;
+	FILE *fp;
+	char *buf;
+
+	if (argc < 3) {
+		printf("usage: trace.dat guest_kallsyms_file\n");
+		exit(-1);
+	}
+
+	handle = tracecmd_open(argv[1], 0);
+	if (!handle) {
+		perror(argv[1]);
+		exit(-1);
+	}
+
+	/* Just for kallsyms parsing */
+	guest_tep = tep_alloc();
+	if (!guest_tep)
+		exit(-1);
+
+	if (stat(argv[2], &st) < 0) {
+		perror(argv[2]);
+		exit(-1);
+	}
+
+	buf = malloc(st.st_size + 1);
+	if (!buf)
+		exit(-1);
+
+	fp = fopen(argv[2], "r");
+	if (!fp) {
+		perror(argv[2]);
+		exit(-1);
+	}
+
+	if (fread(buf, st.st_size, 1, fp) < 0) {
+		perror(argv[2]);
+		exit(-1);
+	}
+
+	buf[st.st_size] = '\0';
+
+	if (tep_parse_kallsyms(guest_tep, buf) < 0) {
+		printf("Failed to parse %s\n", argv[2]);
+		exit(-1);
+	}
+	free(buf);
+
+	tracecmd_follow_event(handle, "kvm", "kvm_exit", show_event, guest_tep);
+	tracecmd_follow_event(handle, "kvm", "kvm_entry", show_event, guest_tep);
+
+	tracecmd_iterate_events(handle, NULL, 0, NULL, NULL);
+
+	tep_free(guest_tep);
+	tracecmd_close(handle);
+}
+--
+
+FILES
+-----
+[verse]
+--
+*event-parse.h*
+	Header file to include in order to have access to the library APIs.
+*-ltraceevent*
+	Linker switch to add when building a program that uses the library.
+--
+
+SEE ALSO
+--------
+*libtraceevent*(3), *trace-cmd*(1)
+
+REPORTING BUGS
+--------------
+Report bugs to  <linux-trace-devel@vger.kernel.org>
+
+LICENSE
+-------
+libtraceevent is Free Software licensed under the GNU LGPL 2.1
+
+RESOURCES
+---------
+https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/
diff --git a/Documentation/libtraceevent-page_size.txt b/Documentation/libtraceevent-page_size.txt
index 7ffeb79..6d0dd36 100644
--- a/Documentation/libtraceevent-page_size.txt
+++ b/Documentation/libtraceevent-page_size.txt
@@ -3,7 +3,7 @@
 
 NAME
 ----
-tep_get_page_size, tep_set_page_size - Get / set the size of a memory page on
+tep_get_page_size, tep_set_page_size, tep_get_sub_buffer_size - Get / set the size of a memory page on
 the machine, where the trace is generated
 
 SYNOPSIS
@@ -14,6 +14,7 @@
 
 int *tep_get_page_size*(struct tep_handle pass:[*]_tep_);
 void *tep_set_page_size*(struct tep_handle pass:[*]_tep_, int _page_size_);
+int *tep_get_sub_buffer_size*(struct tep_handle pass:[*]_tep_);
 --
 
 DESCRIPTION
@@ -27,10 +28,17 @@
 The _tep_ argument is trace event parser context.
 The _page_size_ argument is the size of a memory page, in bytes.
 
+The *tep_get_sub_buffer_size()* returns the size of each "sub buffer" of the
+ring buffer. The Linux kernel ring buffer is broken up into sections called
+sub buffers. This returns the size of those buffers.
+
 RETURN VALUE
 ------------
 The *tep_get_page_size()* function returns size of the memory page, in bytes.
 
+The *tep_get_sub_buffer_size()* function returns the number of bytes each sub
+buffer is made up of.
+
 EXAMPLE
 -------
 [source,c]
diff --git a/Documentation/libtraceevent-plugins.txt b/Documentation/libtraceevent-plugins.txt
index 24d8ad8..4ca78d4 100644
--- a/Documentation/libtraceevent-plugins.txt
+++ b/Documentation/libtraceevent-plugins.txt
@@ -3,7 +3,8 @@
 
 NAME
 ----
-tep_load_plugins, tep_unload_plugins, tep_load_plugins_hook, tep_add_plugin_path - Load / unload traceevent plugins.
+tep_load_plugins, tep_unload_plugins, tep_load_plugins_hook, tep_add_plugin_path,
+tep_plugin_add_option - Load / unload traceevent plugins.
 
 SYNOPSIS
 --------
@@ -21,6 +22,7 @@
 			   void pass:[*]_data_);
 int *tep_add_plugin_path*(struct tep_handle pass:[*]tep, char pass:[*]path,
 			  enum tep_plugin_load_priority prio);
+int *tep_plugin_add_option*(const char pass:[*]_name_, const char pass:[*]_val_);
 --
 
 DESCRIPTION
@@ -76,6 +78,11 @@
 Where the plugins in TEP_PLUGIN_LAST" will take precedence over the
 plugins in the other directories.
 
+The *tep_plugin_add_option()* sets options defined by a plugin. The _name_ is the
+name of the option to set to _val_. Plugins can add options to change its behavior
+and *tep_plugin_add_option()* is used by the application to make those modifications.
+
+
 RETURN VALUE
 ------------
 The *tep_load_plugins()* function returns a list of successfully loaded plugins,
diff --git a/Documentation/libtraceevent.txt b/Documentation/libtraceevent.txt
index 6476070..0502769 100644
--- a/Documentation/libtraceevent.txt
+++ b/Documentation/libtraceevent.txt
@@ -26,10 +26,12 @@
 	void *tep_set_long_size*(struct tep_handle pass:[*]_tep_, int _long_size_);
 	int *tep_get_page_size*(struct tep_handle pass:[*]_tep_);
 	void *tep_set_page_size*(struct tep_handle pass:[*]_tep_, int _page_size_);
+	int *tep_get_sub_buffer_size*(struct tep_handle pass:[*]_tep_);
 	int *tep_get_header_page_size*(struct tep_handle pass:[*]_tep_);
 	int *tep_get_header_timestamp_size*(struct tep_handle pass:[*]_tep_);
 	bool *tep_is_old_format*(struct tep_handle pass:[*]_tep_);
 	int *tep_strerror*(struct tep_handle pass:[*]_tep_, enum tep_errno _errnum_, char pass:[*]_buf_, size_t _buflen_);
+	struct kbuffer pass:[*]*tep_kbuffer*(struct tep_handle pass:[*]:_tep_);
 
 Register / unregister APIs:
 	int *tep_register_function*(struct tep_handle pass:[*]_tep_, char pass:[*]_name_, unsigned long long _addr_, char pass:[*]_mod_);
@@ -38,6 +40,19 @@
 	int *tep_register_print_string*(struct tep_handle pass:[*]_tep_, const char pass:[*]_fmt_, unsigned long long _addr_);
 	int *tep_register_print_function*(struct tep_handle pass:[*]_tep_, tep_func_handler _func_, enum tep_func_arg_type _ret_type_, char pass:[*]_name_, _..._);
 	int *tep_unregister_print_function*(struct tep_handle pass:[*]_tep_, tep_func_handler _func_, char pass:[*]_name_);
+	int *tep_get_function_count*(struct tep_handle *_tep_);
+
+Trace printk parsing:
+	void *tep_print_printk*(struct tep_handle pass:[*]tep);
+	void *tep_print_funcs*(struct tep_handle pass:[*]tep);
+	void *tep_set_test_filters*(struct tep_handle pass:[*]tep, int test_filters);
+	void *tep_plugin_print_options*(struct trace_seq pass:[*]s);
+	int *tep_plugin_add_option*(const char pass:[*]_name_, const char pass:[*]_val_);
+
+Meta data parsing:
+	int *tep_parse_saved_cmdlines*(struct tep_handle pass:[*]_tep_, const char pass:[*]_buf_);
+	int *tep_parse_printk_formats*(struct tep_handle pass:[*]_tep_, const char pass:[*]_buf_);
+	int *tep_parse_kallsyms*(struct tep_handle pass:[*]_tep_, const char pass:[*]_buf_);
 
 Plugins management:
 	struct tep_plugin_list pass:[*]*tep_load_plugins*(struct tep_handle pass:[*]_tep_);
@@ -47,6 +62,14 @@
 	int *tep_plugin_add_options*(const char pass:[*]_name_, struct tep_plugin_option pass:[*]_options_);
 	void *tep_plugin_remove_options*(struct tep_plugin_option pass:[*]_options_);
 	void *tep_print_plugins*(struct trace_seq pass:[*]_s_, const char pass:[*]_prefix_, const char pass:[*]_suffix_, const struct tep_plugin_list pass:[*]_list_);
+	void *tep_load_plugins_hook*(struct tep_handle pass:[*]_tep_, const char pass:[*]_suffix_,
+			   void (pass:[*]_load_plugin_)(struct tep_handle pass:[*]tep,
+					       const char pass:[*]path,
+					       const char pass:[*]name,
+					       void pass:[*]data),
+			   void pass:[*]_data_);
+	int *tep_add_plugin_path*(struct tep_handle pass:[*]tep, char pass:[*]path,
+			  enum tep_plugin_load_priority prio);
 
 Event related APIs:
 	struct tep_event pass:[*]*tep_get_event*(struct tep_handle pass:[*]_tep_, int _index_);
@@ -93,6 +116,8 @@
 	void *tep_reset_function_resolver*(struct tep_handle pass:[*]_tep_);
 	const char pass:[*]*tep_find_function*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_);
 	unsigned long long *tep_find_function_address*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_);
+	int *tep_find_function_info*(struct tep_handle pass:[*]_tep_, unsigned long long _addr_, const char pass:[**]_name_,
+			   unsigned long long pass:[*]_start_, unsigned long pass:[*]_size_);
 
 Filter management:
 	struct tep_event_filter pass:[*]*tep_filter_alloc*(struct tep_handle pass:[*]_tep_);
@@ -132,6 +157,12 @@
 Control library logs:
 	int *tep_set_loglevel*(enum tep_loglevel _level_);
 
+KVM plugin calllbacks: (Defined by the application and complied with -rdynamic)
+	const char pass:[*]*tep_plugin_kvm_get_func*(struct tep_event pass:[*]event,
+				    struct tep_record pass:[*]record,
+				    unsigned long long pass:[*]paddr);
+	void *tep_plugin_kvm_put_func*(const char pass:[*]func);
+
 Trace sequences:
 *#include <trace-seq.h>*
 	void *trace_seq_init*(struct trace_seq pass:[*]_s_);
@@ -144,6 +175,24 @@
 	void *trace_seq_terminate*(struct trace_seq pass:[*]_s_);
 	int *trace_seq_do_fprintf*(struct trace_seq pass:[*]_s_, FILE pass:[*]_fp_);
 	int *trace_seq_do_printf*(struct trace_seq pass:[*]_s_);
+
+kbuffer parsing:
+#include <kbuffer.h>
+	struct kbuffer pass:[*]*kbuffer_alloc*(enum kbuffer_long_size _size_, enum kbuffer_endian _endian_);
+	void *kbuffer_free*(struct kbuffer pass:[*]_kbuf_);
+	int *kbuffer_load_subbuffer*(struct kbuffer pass:[*]_kbuf_, void pass:[*]_subbuffer_);
+	int *kbuffer_subbuffer_size*(struct kbuffer pass:[*]_kbuf);
+	int *kbuffer_start_of_data*(struct kbuffer pass:[*]_kbuf_);
+	unsigned long long *kbuffer_timestamp*(struct kbuffer pass:[*]_kbuf_);
+	unsigned long long *kbuffer_subbuf_timestamp*(struct kbuffer pass:[*]_kbuf_, void pass:[*]_subbuf_);
+	void pass:[*]*kbuffer_read_event*(struct kbuffer pass:[*]_kbuf_, unsigned long long pass:[*]_ts_);
+	void pass:[*]*kbuffer_next_event*(struct kbuffer pass:[*]_kbuf_, unsigned long long pass:[*]_ts_);
+	void pass:[*]*kbuffer_read_at_offset*(struct kbuffer pass:[*]_kbuf_, int _offset_, unsigned long long pass:[*]_ts_);
+	int *kbuffer_missed_events*(struct kbuffer pass:[*]_kbuf_);
+	int *kbuffer_event_size*(struct kbuffer pass:[*]_kbuf_);
+	int *kbuffer_curr_size*(struct kbuffer pass:[*]_kbuf_);
+	int *kbuffer_curr_offset*(struct kbuffer pass:[*]_kbuf_);
+	int *kbuffer_curr_index*(struct kbuffer pass:[*]_kbuf_);
 --
 
 DESCRIPTION
diff --git a/METADATA b/METADATA
index e07e64d..764071d 100644
--- a/METADATA
+++ b/METADATA
@@ -1,14 +1,19 @@
-name: "libtraceevent"
-description:
-    "libtraceevent is a library that provides APIs to access and configure "
-    "kernel trace events through the tracefs filesystem."
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update libtraceevent
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
 
+name: "libtraceevent"
+description: "libtraceevent is a library that provides APIs to access and configure kernel trace events through the tracefs filesystem."
 third_party {
   url {
     type: GIT
     value: "https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git"
   }
-  version: "libtraceevent-1.5.2"
-  last_upgrade_date { year: 2022 month: 5 day: 02 }
+  version: "libtraceevent-1.7.1"
   license_type: RESTRICTED
+  last_upgrade_date {
+    year: 2023
+    month: 1
+    day: 18
+  }
 }
diff --git a/Makefile b/Makefile
index e99e7a9..20d90be 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 # libtraceevent version
 EP_VERSION = 1
-EP_PATCHLEVEL = 6
-EP_EXTRAVERSION = dev
+EP_PATCHLEVEL = 7
+EP_EXTRAVERSION = 1
 EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION)
 
 MAKEFLAGS += --no-print-directory
@@ -46,8 +46,8 @@
 
 libdir_relative ?= $(libdir_relative_temp)
 prefix ?= /usr/local
-libdir = $(prefix)/$(libdir_relative)
-man_dir = $(prefix)/share/man
+libdir ?= $(prefix)/$(libdir_relative)
+man_dir ?= $(prefix)/share/man
 man_dir_SQ = '$(subst ','\'',$(man_dir))'
 pkgconfig_dir ?= $(word 1,$(shell $(PKG_CONFIG) 		\
 			--variable pc_path pkg-config | tr ":" " "))
@@ -130,7 +130,7 @@
   CFLAGS := -g -Wall
 endif
 
-LIBS = -ldl
+LIBS ?= -ldl
 export LIBS
 
 set_plugin_dir := 1
@@ -164,6 +164,9 @@
 override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ)
 override CFLAGS += $(udis86-flags) -D_GNU_SOURCE
 
+# Make sure 32 bit stat() works on large file systems
+override CFLAGS += -D_FILE_OFFSET_BITS=64
+
 ifeq ($(VERBOSE),1)
   Q =
 else
@@ -378,7 +381,7 @@
 	@$(foreach file,$(shell cat $(BUILD_OUTPUT)/build_uninstall),$(call uninstall_file,$(file)))
 
 PHONY += doc
-doc:
+doc: check_doc
 	$(Q)$(call descend,$(src)/Documentation,)
 
 PHONY += doc-clean
@@ -389,6 +392,9 @@
 doc-install:
 	$(Q)$(call descend,$(src)/Documentation,install)
 
+check_doc: force
+	$(Q)$(src)/check-manpages.sh $(src)/Documentation
+
 
 PHONY += doc-uninstall
 doc-uninstall:
diff --git a/check-manpages.sh b/check-manpages.sh
new file mode 100755
index 0000000..4e9850f
--- /dev/null
+++ b/check-manpages.sh
@@ -0,0 +1,78 @@
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1
+# Copyright (C) 2022, Google Inc, Steven Rostedt <rostedt@goodmis.org>
+#
+# This checks if any function is listed in a man page that is not listed
+# in the main man page.
+
+if [ $# -lt 1 ]; then
+	echo "usage: check-manpages man-page-path"
+	exit 1
+fi
+
+cd $1
+
+MAIN=libtraceevent
+MAIN_FILE=${MAIN}.txt
+
+PROCESSED=""
+
+# Ignore man pages that do not contain functions
+IGNORE=""
+
+for man in ${MAIN}-*.txt; do
+
+	for a in `sed -ne '/^NAME/,/^SYNOP/{/^[a-z]/{s/, *$//;s/,/\n/g;s/ //g;s/-.*$/-/;/-/{s/-//p;q};p}}' $man`; do
+		if [ "${PROCESSED/:${a} /}" != "${PROCESSED}" ]; then
+			P="${PROCESSED/:${a} */}"
+			echo "Found ${a} in ${man} and in ${P/* /}"
+		fi
+		PROCESSED="${man}:${a} ${PROCESSED}"
+		if [ "${IGNORE/$man/}" != "${IGNORE}" ]; then
+			continue
+		fi
+		if ! grep -q '\*'${a}'\*' $MAIN_FILE; then
+			if [ "$last" == "" ]; then
+				echo
+			fi
+			if [ "$last" != "$man" ]; then
+				echo "Missing functions from $MAIN_FILE that are in $man"
+				last=$man
+			fi
+			echo "   ${a}"
+		fi
+	done
+done
+
+DEPRECATED="*tep_print_field*"
+
+# Should not be used by applications, only internal use by trace-cmd
+IGNORE="*kbuffer_set_old_format* *kbuffer_raw_get* *kbuffer_ptr_delta* *kbuffer_translate_data*"
+
+HEADER=event-parse.h
+
+sed -ne 's/^[a-z].*[ \*]\([a-z_][a-z_]*\)(.*/\1/p' -e 's/^\([a-z_][a-z_]*\)(.*/\1/p' ../include/traceevent/{event-parse,trace-seq,kbuffer}.h | while read f; do
+	if ! grep -q '\*'${f}'\*' $MAIN_FILE; then
+		if [ "${DEPRECATED/\*$f\*/}" != "${DEPRECATED}" ]; then
+			continue;
+		fi
+		if [ "${IGNORE/\*$f\*/}" != "${IGNORE}" ]; then
+			continue;
+		fi
+		for head in event-parse.h trace-seq.h kbuffer.h; do
+			if grep -q $f ../include/traceevent/$head; then
+				if [ "$HEADER" != "$head" ]; then
+					last=""
+					HEADER=$head
+					break
+				fi
+			fi
+		done
+		if [ "$last" == "" ]; then
+			echo
+			echo "Missing functions from $MAIN_FILE that are in $HEADER"
+			last=$f
+		fi
+		echo "   ${f}"
+	fi
+done
diff --git a/include/traceevent/event-parse.h b/include/traceevent/event-parse.h
index 0b911e1..2171ad7 100644
--- a/include/traceevent/event-parse.h
+++ b/include/traceevent/event-parse.h
@@ -14,6 +14,10 @@
 
 #include "trace-seq.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #ifndef __maybe_unused
 #define __maybe_unused __attribute__((unused))
 #endif
@@ -240,6 +244,7 @@
 	TEP_PRINT_BITMASK,
 	TEP_PRINT_DYNAMIC_ARRAY_LEN,
 	TEP_PRINT_HEX_STR,
+	TEP_PRINT_CPUMASK,
 };
 
 struct tep_print_arg {
@@ -523,6 +528,9 @@
 const char *tep_find_function(struct tep_handle *tep, unsigned long long addr);
 unsigned long long
 tep_find_function_address(struct tep_handle *tep, unsigned long long addr);
+int tep_find_function_info(struct tep_handle *tep, unsigned long long addr,
+			   const char **name, unsigned long long *start,
+			   unsigned long *size);
 unsigned long long tep_read_number(struct tep_handle *tep, const void *ptr, int size);
 int tep_read_number_field(struct tep_format_field *field, const void *data,
 			  unsigned long long *value);
@@ -594,6 +602,8 @@
 void tep_unref(struct tep_handle *tep);
 int tep_get_ref(struct tep_handle *tep);
 
+struct kbuffer *tep_kbuffer(struct tep_handle *tep);
+
 /* for debugging */
 void tep_print_funcs(struct tep_handle *tep);
 void tep_print_printk(struct tep_handle *tep);
@@ -774,8 +784,40 @@
 };
 void tep_set_loglevel(enum tep_loglevel level);
 
+/*
+ * Part of the KVM plugin. Will pass the current @event and @record
+ * as well as a pointer to the address to a guest kernel function.
+ * This is currently a weak function defined in the KVM plugin and
+ * should never be called. But a tool can override it, and this will
+ * be called when the kvm plugin has an address it needs the function
+ * name of.
+ *
+ * This function should return the function name for the given address
+ * and optionally, it can update @paddr to include the start of the function
+ * such that the kvm plugin can include an offset.
+ *
+ * For an application to be able to override the weak version in the
+ * plugin, it must be compiled with the gcc -rdynamic option that will
+ * allow the dynamic linker to use the application's function to
+ * override this callback.
+ */
+const char *tep_plugin_kvm_get_func(struct tep_event *event,
+				    struct tep_record *record,
+				    unsigned long long *paddr);
+
+/*
+ * tep_plugin_kvm_put_func() is another weak function that can be used
+ * to call back into the application if the function name returned by
+ * tep_plugin_kvm_get_func() needs to be freed.
+ */
+void tep_plugin_kvm_put_func(const char *func);
+
 /* DEPRECATED */
 void tep_print_field(struct trace_seq *s, void *data,
 		     struct tep_format_field *field);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _PARSE_EVENTS_H */
diff --git a/include/traceevent/kbuffer.h b/include/traceevent/kbuffer.h
index a2b5220..ca638bc 100644
--- a/include/traceevent/kbuffer.h
+++ b/include/traceevent/kbuffer.h
@@ -13,11 +13,13 @@
 enum kbuffer_endian {
 	KBUFFER_ENDIAN_BIG,
 	KBUFFER_ENDIAN_LITTLE,
+	KBUFFER_ENDIAN_SAME_AS_HOST,
 };
 
 enum kbuffer_long_size {
 	KBUFFER_LSIZE_4,
 	KBUFFER_LSIZE_8,
+	KBUFFER_LSIZE_SAME_AS_HOST,
 };
 
 enum {
diff --git a/include/traceevent/trace-seq.h b/include/traceevent/trace-seq.h
index d68ec69..217492f 100644
--- a/include/traceevent/trace-seq.h
+++ b/include/traceevent/trace-seq.h
@@ -10,6 +10,10 @@
 #include <stdarg.h>
 #include <stdio.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* ----------------------- trace_seq ----------------------- */
 
 #ifndef TRACE_SEQ_BUF_SIZE
@@ -52,4 +56,8 @@
 extern int trace_seq_do_fprintf(struct trace_seq *s, FILE *fp);
 extern int trace_seq_do_printf(struct trace_seq *s);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _TRACE_SEQ_H */
diff --git a/plugins/plugin_function.c b/plugins/plugin_function.c
index 7777569..2d6509b 100644
--- a/plugins/plugin_function.c
+++ b/plugins/plugin_function.c
@@ -233,9 +233,11 @@
 			break;
 
 		func = tep_find_function(event->tep, addr);
-		if (func)
-			trace_seq_printf(s, "=> %s (%llx)\n", func, addr);
-		else
+		if (func) {
+			trace_seq_puts(s, "=> ");
+			show_function(s, event->tep, func, addr);
+			trace_seq_printf(s, " (%llx)\n", addr);
+		} else
 			trace_seq_printf(s, "=> %llx\n", addr);
 	}
 
diff --git a/plugins/plugin_kvm.c b/plugins/plugin_kvm.c
index 51ceeb9..9852c35 100644
--- a/plugins/plugin_kvm.c
+++ b/plugins/plugin_kvm.c
@@ -10,6 +10,8 @@
 #include "event-parse.h"
 #include "trace-seq.h"
 
+#define __weak __attribute__((weak))
+
 #ifdef HAVE_UDIS86
 
 #include <udis86.h>
@@ -273,15 +275,49 @@
 	return 0;
 }
 
+__weak const char *tep_plugin_kvm_get_func(struct tep_event *event,
+					   struct tep_record *record,
+					   unsigned long long *val)
+{
+	return NULL;
+}
+
+__weak void tep_plugin_kvm_put_func(const char *func)
+{
+}
+
+
+static void add_rip_function(struct trace_seq *s, struct tep_record *record,
+			     struct tep_event *event, unsigned long long rip)
+{
+	unsigned long long ip = rip;
+	const char *func;
+
+	func = tep_plugin_kvm_get_func(event, record, &ip);
+	if (func) {
+		trace_seq_printf(s, " %s", func);
+		/* The application may upate ip to the start of the function */
+		if (ip != rip)
+			trace_seq_printf(s, "+0x%0llx", rip - ip);
+		tep_plugin_kvm_put_func(func);
+	}
+}
+
 static int kvm_exit_handler(struct trace_seq *s, struct tep_record *record,
 			    struct tep_event *event, void *context)
 {
 	unsigned long long info1 = 0, info2 = 0;
+	unsigned long long rip;
 
 	if (print_exit_reason(s, record, event, "exit_reason") < 0)
 		return -1;
 
-	tep_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1);
+	if (tep_get_field_val(s, event, "guest_rip", record, &rip, 1) < 0)
+		return -1;
+
+	trace_seq_printf(s, " rip 0x%llx", rip);
+
+	add_rip_function(s, record, event, rip);
 
 	if (tep_get_field_val(s, event, "info1", record, &info1, 0) >= 0
 	    && tep_get_field_val(s, event, "info2", record, &info2, 0) >= 0)
@@ -290,6 +326,22 @@
 	return 0;
 }
 
+static int kvm_entry_handler(struct trace_seq *s, struct tep_record *record,
+			    struct tep_event *event, void *context)
+{
+	unsigned long long rip;
+
+	tep_print_num_field(s, " vcpu %u", event, "vcpu_id", record, 1);
+
+	if (tep_get_field_val(s, event, "rip", record, &rip, 1) < 0)
+		return -1;
+
+	trace_seq_printf(s, " rip 0x%llx", rip);
+	add_rip_function(s, record, event, rip);
+
+	return 0;
+}
+
 #define KVM_EMUL_INSN_F_CR0_PE (1 << 0)
 #define KVM_EMUL_INSN_F_EFL_VM (1 << 1)
 #define KVM_EMUL_INSN_F_CS_D   (1 << 2)
@@ -329,12 +381,12 @@
 			     flags & KVM_EMUL_INSN_F_CS_D,
 			     flags & KVM_EMUL_INSN_F_CS_L);
 
-	trace_seq_printf(s, "%llx:%llx: %s%s", csbase, rip, disasm,
-			 failed ? " FAIL" : "");
+	trace_seq_printf(s, "%llx:%llx", csbase, rip);
+	add_rip_function(s, record, event, rip);
+	trace_seq_printf(s, ": %s%s", disasm, failed ? " FAIL" : "");
 	return 0;
 }
 
-
 static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct tep_record *record,
 					    struct tep_event *event, void *context)
 {
@@ -352,7 +404,13 @@
 static int kvm_nested_vmexit_handler(struct trace_seq *s, struct tep_record *record,
 				     struct tep_event *event, void *context)
 {
-	tep_print_num_field(s, "rip %llx ", event, "rip", record, 1);
+	unsigned long long rip;
+
+	if (tep_get_field_val(s, event, "rip", record, &rip, 1) < 0)
+		return -1;
+
+	trace_seq_printf(s, " rip %llx", rip);
+	add_rip_function(s, record, event, rip);
 
 	return kvm_nested_vmexit_inject_handler(s, record, event, context);
 }
@@ -456,6 +514,9 @@
 	tep_register_event_handler(tep, -1, "kvm", "kvm_exit",
 				   kvm_exit_handler, NULL);
 
+	tep_register_event_handler(tep, -1, "kvm", "kvm_entry",
+				   kvm_entry_handler, NULL);
+
 	tep_register_event_handler(tep, -1, "kvm", "kvm_emulate_insn",
 				   kvm_emulate_insn_handler, NULL);
 
@@ -496,6 +557,9 @@
 	tep_unregister_event_handler(tep, -1, "kvm", "kvm_exit",
 				     kvm_exit_handler, NULL);
 
+	tep_unregister_event_handler(tep, -1, "kvm", "kvm_entry",
+				     kvm_entry_handler, NULL);
+
 	tep_unregister_event_handler(tep, -1, "kvm", "kvm_emulate_insn",
 				     kvm_emulate_insn_handler, NULL);
 
diff --git a/src/event-parse-local.h b/src/event-parse-local.h
index fd4bbcf..c6bfc61 100644
--- a/src/event-parse-local.h
+++ b/src/event-parse-local.h
@@ -85,6 +85,10 @@
 	struct tep_event *last_event;
 
 	struct tep_plugins_dir *plugins_dir;
+
+	const char *input_buf;
+	unsigned long long input_buf_ptr;
+	unsigned long long input_buf_siz;
 };
 
 enum tep_print_parse_type {
@@ -113,11 +117,11 @@
 unsigned long long data2host8(struct tep_handle *tep, unsigned long long data);
 
 /* access to the internal parser */
-int peek_char(void);
-void init_input_buf(const char *buf, unsigned long long size);
-unsigned long long get_input_buf_ptr(void);
-const char *get_input_buf(void);
-enum tep_event_type read_token(char **tok);
+int peek_char(struct tep_handle *tep);
+void init_input_buf(struct tep_handle *tep, const char *buf, unsigned long long size);
+unsigned long long get_input_buf_ptr(struct tep_handle *tep);
+const char *get_input_buf(struct tep_handle *tep);
+enum tep_event_type read_token(struct tep_handle *tep, char **tok);
 void free_token(char *tok);
 
 #endif /* _PARSE_EVENTS_INT_H */
diff --git a/src/event-parse.c b/src/event-parse.c
index f862f49..e655087 100644
--- a/src/event-parse.c
+++ b/src/event-parse.c
@@ -28,10 +28,6 @@
 #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;
 
@@ -62,21 +58,22 @@
  *
  * Initializes the internal buffer that tep_read_token() will parse.
  */
-__hidden void init_input_buf(const char *buf, unsigned long long size)
+__hidden void init_input_buf(struct tep_handle *tep, const char *buf,
+		unsigned long long size)
 {
-	input_buf = buf;
-	input_buf_siz = size;
-	input_buf_ptr = 0;
+	tep->input_buf = buf;
+	tep->input_buf_siz = size;
+	tep->input_buf_ptr = 0;
 }
 
-__hidden const char *get_input_buf(void)
+__hidden const char *get_input_buf(struct tep_handle *tep)
 {
-	return input_buf;
+	return tep->input_buf;
 }
 
-__hidden unsigned long long get_input_buf_ptr(void)
+__hidden unsigned long long get_input_buf_ptr(struct tep_handle *tep)
 {
-	return input_buf_ptr;
+	return tep->input_buf_ptr;
 }
 
 struct event_handler {
@@ -614,6 +611,43 @@
 }
 
 /**
+ * tep_find_function_info - find a function by a given address
+ * @tep: a handle to the trace event parser context
+ * @addr: the address to find the function with
+ * @name: Return the name of the function (if found)
+ * @start: Return the start of the function (if found)
+ * @size: Return the size of the function (if found)
+ *
+ * Returns 1 if found, and 0 if it is not.
+ *  If found then @name will point to the name of the function.
+ *                @start: will contain the starting address of the function.
+ *                @size: will contain the size of the function.
+ */
+int tep_find_function_info(struct tep_handle *tep, unsigned long long addr,
+			   const char **name, unsigned long long *start,
+			   unsigned long *size)
+{
+	struct func_map *map;
+
+	map = find_func(tep, addr);
+	if (!map)
+		return 0;
+
+	if (name)
+		*name = map->func;
+	if (start)
+		*start = map->addr;
+	if (size) {
+		if (!tep->func_resolver)
+			*size = map[1].addr - map->addr;
+		else
+			*size = 0;
+	}
+
+	return 1;
+}
+
+/**
  * tep_find_function - find a function by a given address
  * @tep: a handle to the trace event parser context
  * @addr: the address to find the function with
@@ -739,8 +773,11 @@
 		if (errno)
 			goto out;
 
-		if (n != 2 || !func_end)
+		if (n != 2 || !func_end) {
+			tep_warning("Failed to parse kallsyms n=%d func_end=%d",
+				    n, func_end);
 			goto out;
+		}
 
 		func = line + func_start;
 		/*
@@ -1080,6 +1117,7 @@
 		free(arg->string.string);
 		break;
 	case TEP_PRINT_BITMASK:
+	case TEP_PRINT_CPUMASK:
 		free(arg->bitmask.bitmask);
 		break;
 	case TEP_PRINT_DYNAMIC_ARRAY:
@@ -1127,12 +1165,12 @@
 	return TEP_EVENT_OP;
 }
 
-static int __read_char(void)
+static int __read_char(struct tep_handle *tep)
 {
-	if (input_buf_ptr >= input_buf_siz)
+	if (tep->input_buf_ptr >= tep->input_buf_siz)
 		return -1;
 
-	return input_buf[input_buf_ptr++];
+	return tep->input_buf[tep->input_buf_ptr++];
 }
 
 /**
@@ -1140,12 +1178,12 @@
  *
  * Returns the next character read, or -1 if end of buffer.
  */
-__hidden int peek_char(void)
+__hidden int peek_char(struct tep_handle *tep)
 {
-	if (input_buf_ptr >= input_buf_siz)
+	if (tep->input_buf_ptr >= tep->input_buf_siz)
 		return -1;
 
-	return input_buf[input_buf_ptr];
+	return tep->input_buf[tep->input_buf_ptr];
 }
 
 static int extend_token(char **tok, char *buf, int size)
@@ -1167,9 +1205,10 @@
 	return 0;
 }
 
-static enum tep_event_type force_token(const char *str, char **tok);
+static enum tep_event_type force_token(struct tep_handle *tep, const char *str,
+		char **tok);
 
-static enum tep_event_type __read_token(char **tok)
+static enum tep_event_type __read_token(struct tep_handle *tep, char **tok)
 {
 	char buf[BUFSIZ];
 	int ch, last_ch, quote_ch, next_ch;
@@ -1180,7 +1219,7 @@
 	*tok = NULL;
 
 
-	ch = __read_char();
+	ch = __read_char(tep);
 	if (ch < 0)
 		return TEP_EVENT_NONE;
 
@@ -1201,9 +1240,9 @@
 	case TEP_EVENT_OP:
 		switch (ch) {
 		case '-':
-			next_ch = peek_char();
+			next_ch = peek_char(tep);
 			if (next_ch == '>') {
-				buf[i++] = __read_char();
+				buf[i++] = __read_char(tep);
 				break;
 			}
 			/* fall through */
@@ -1213,10 +1252,10 @@
 		case '>':
 		case '<':
 			last_ch = ch;
-			ch = peek_char();
+			ch = peek_char(tep);
 			if (ch != last_ch)
 				goto test_equal;
-			buf[i++] = __read_char();
+			buf[i++] = __read_char(tep);
 			switch (last_ch) {
 			case '>':
 			case '<':
@@ -1236,9 +1275,9 @@
 		return type;
 
  test_equal:
-		ch = peek_char();
+		ch = peek_char(tep);
 		if (ch == '=')
-			buf[i++] = __read_char();
+			buf[i++] = __read_char(tep);
 		goto out;
 
 	case TEP_EVENT_DQUOTE:
@@ -1258,29 +1297,34 @@
 				i = 0;
 			}
 			last_ch = ch;
-			ch = __read_char();
+			ch = __read_char(tep);
 			buf[i++] = ch;
 			/* the '\' '\' will cancel itself */
 			if (ch == '\\' && last_ch == '\\')
 				last_ch = 0;
 			/* Break out if the file is corrupted and giving non print chars */
+			if (ch <= 0)
+				break;
 		} while ((ch != quote_ch && isprint(ch)) || last_ch == '\\' || ch == '\n');
 		/* remove the last quote */
 		i--;
 
+		if (ch <= 0)
+			type = TEP_EVENT_NONE;
+
 		/*
 		 * For strings (double quotes) check the next token.
 		 * If it is another string, concatinate the two.
 		 */
 		if (type == TEP_EVENT_DQUOTE) {
-			unsigned long long save_input_buf_ptr = input_buf_ptr;
+			unsigned long long save_input_buf_ptr = tep->input_buf_ptr;
 
 			do {
-				ch = __read_char();
+				ch = __read_char(tep);
 			} while (isspace(ch));
 			if (ch == '"')
 				goto concat;
-			input_buf_ptr = save_input_buf_ptr;
+			tep->input_buf_ptr = save_input_buf_ptr;
 		}
 
 		goto out;
@@ -1291,7 +1335,7 @@
 		break;
 	}
 
-	while (get_type(peek_char()) == type) {
+	while (get_type(peek_char(tep)) == type) {
 		if (i == (BUFSIZ - 1)) {
 			buf[i] = 0;
 			tok_size += BUFSIZ;
@@ -1300,7 +1344,7 @@
 				return TEP_EVENT_NONE;
 			i = 0;
 		}
-		ch = __read_char();
+		ch = __read_char(tep);
 		buf[i++] = ch;
 	}
 
@@ -1321,22 +1365,23 @@
 		if (strcmp(*tok, "LOCAL_PR_FMT") == 0) {
 			free(*tok);
 			*tok = NULL;
-			return force_token("\"%s\" ", tok);
+			return force_token(tep, "\"%s\" ", tok);
 		} else if (strcmp(*tok, "STA_PR_FMT") == 0) {
 			free(*tok);
 			*tok = NULL;
-			return force_token("\" sta:%pM\" ", tok);
+			return force_token(tep, "\" sta:%pM\" ", tok);
 		} else if (strcmp(*tok, "VIF_PR_FMT") == 0) {
 			free(*tok);
 			*tok = NULL;
-			return force_token("\" vif:%p(%d)\" ", tok);
+			return force_token(tep, "\" vif:%p(%d)\" ", tok);
 		}
 	}
 
 	return type;
 }
 
-static enum tep_event_type force_token(const char *str, char **tok)
+static enum tep_event_type force_token(struct tep_handle *tep, const char *str,
+		char **tok)
 {
 	const char *save_input_buf;
 	unsigned long long save_input_buf_ptr;
@@ -1344,18 +1389,18 @@
 	enum tep_event_type type;
 	
 	/* save off the current input pointers */
-	save_input_buf = input_buf;
-	save_input_buf_ptr = input_buf_ptr;
-	save_input_buf_siz = input_buf_siz;
+	save_input_buf = tep->input_buf;
+	save_input_buf_ptr = tep->input_buf_ptr;
+	save_input_buf_siz = tep->input_buf_siz;
 
-	init_input_buf(str, strlen(str));
+	init_input_buf(tep, str, strlen(str));
 
-	type = __read_token(tok);
+	type = __read_token(tep, tok);
 
 	/* reset back to original token */
-	input_buf = save_input_buf;
-	input_buf_ptr = save_input_buf_ptr;
-	input_buf_siz = save_input_buf_siz;
+	tep->input_buf = save_input_buf;
+	tep->input_buf_ptr = save_input_buf_ptr;
+	tep->input_buf_siz = save_input_buf_siz;
 
 	return type;
 }
@@ -1379,12 +1424,12 @@
  *
  * Returns the token type.
  */
-__hidden enum tep_event_type read_token(char **tok)
+__hidden enum tep_event_type read_token(struct tep_handle *tep, char **tok)
 {
 	enum tep_event_type type;
 
 	for (;;) {
-		type = __read_token(tok);
+		type = __read_token(tep, tok);
 		if (type != TEP_EVENT_SPACE)
 			return type;
 
@@ -1397,12 +1442,12 @@
 }
 
 /* no newline */
-static enum tep_event_type read_token_item(char **tok)
+static enum tep_event_type read_token_item(struct tep_handle *tep, char **tok)
 {
 	enum tep_event_type type;
 
 	for (;;) {
-		type = __read_token(tok);
+		type = __read_token(tep, tok);
 		if (type != TEP_EVENT_SPACE && type != TEP_EVENT_NEWLINE)
 			return type;
 		free_token(*tok);
@@ -1443,33 +1488,35 @@
 	return 0;
 }
 
-static int __read_expect_type(enum tep_event_type expect, char **tok, int newline_ok)
+static int __read_expect_type(struct tep_handle *tep, enum tep_event_type expect,
+		char **tok, int newline_ok)
 {
 	enum tep_event_type type;
 
 	if (newline_ok)
-		type = read_token(tok);
+		type = read_token(tep, tok);
 	else
-		type = read_token_item(tok);
+		type = read_token_item(tep, tok);
 	return test_type(type, expect);
 }
 
-static int read_expect_type(enum tep_event_type expect, char **tok)
+static int read_expect_type(struct tep_handle *tep, enum tep_event_type expect,
+		char **tok)
 {
-	return __read_expect_type(expect, tok, 1);
+	return __read_expect_type(tep, expect, tok, 1);
 }
 
-static int __read_expected(enum tep_event_type expect, const char *str,
-			   int newline_ok)
+static int __read_expected(struct tep_handle *tep, enum tep_event_type expect,
+		const char *str, int newline_ok)
 {
 	enum tep_event_type type;
 	char *token;
 	int ret;
 
 	if (newline_ok)
-		type = read_token(&token);
+		type = read_token(tep, &token);
 	else
-		type = read_token_item(&token);
+		type = read_token_item(tep, &token);
 
 	ret = test_type_token(type, token, expect, str);
 
@@ -1478,27 +1525,29 @@
 	return ret;
 }
 
-static int read_expected(enum tep_event_type expect, const char *str)
+static int read_expected(struct tep_handle *tep, enum tep_event_type expect,
+		const char *str)
 {
-	return __read_expected(expect, str, 1);
+	return __read_expected(tep, expect, str, 1);
 }
 
-static int read_expected_item(enum tep_event_type expect, const char *str)
+static int read_expected_item(struct tep_handle *tep, enum tep_event_type expect,
+		const char *str)
 {
-	return __read_expected(expect, str, 0);
+	return __read_expected(tep, expect, str, 0);
 }
 
-static char *event_read_name(void)
+static char *event_read_name(struct tep_handle *tep)
 {
 	char *token;
 
-	if (read_expected(TEP_EVENT_ITEM, "name") < 0)
+	if (read_expected(tep, TEP_EVENT_ITEM, "name") < 0)
 		return NULL;
 
-	if (read_expected(TEP_EVENT_OP, ":") < 0)
+	if (read_expected(tep, TEP_EVENT_OP, ":") < 0)
 		return NULL;
 
-	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
+	if (read_expect_type(tep, TEP_EVENT_ITEM, &token) < 0)
 		goto fail;
 
 	return token;
@@ -1508,18 +1557,18 @@
 	return NULL;
 }
 
-static int event_read_id(void)
+static int event_read_id(struct tep_handle *tep)
 {
 	char *token;
 	int id;
 
-	if (read_expected_item(TEP_EVENT_ITEM, "ID") < 0)
+	if (read_expected_item(tep, TEP_EVENT_ITEM, "ID") < 0)
 		return -1;
 
-	if (read_expected(TEP_EVENT_OP, ":") < 0)
+	if (read_expected(tep, TEP_EVENT_OP, ":") < 0)
 		return -1;
 
-	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
+	if (read_expect_type(tep, TEP_EVENT_ITEM, &token) < 0)
 		goto fail;
 
 	id = strtoul(token, NULL, 0);
@@ -1607,7 +1656,8 @@
 	return 0;
 }
 
-static int event_read_fields(struct tep_event *event, struct tep_format_field **fields)
+static int event_read_fields(struct tep_handle *tep, struct tep_event *event,
+		struct tep_format_field **fields)
 {
 	struct tep_format_field *field = NULL;
 	enum tep_event_type type;
@@ -1620,7 +1670,7 @@
 	do {
 		unsigned int size_dynamic = 0;
 
-		type = read_token(&token);
+		type = read_token(tep, &token);
 		if (type == TEP_EVENT_NEWLINE) {
 			free_token(token);
 			return count;
@@ -1632,7 +1682,7 @@
 			goto fail;
 		free_token(token);
 
-		type = read_token(&token);
+		type = read_token(tep, &token);
 		/*
 		 * The ftrace fields may still use the "special" name.
 		 * Just ignore it.
@@ -1640,14 +1690,14 @@
 		if (event->flags & TEP_EVENT_FL_ISFTRACE &&
 		    type == TEP_EVENT_ITEM && strcmp(token, "special") == 0) {
 			free_token(token);
-			type = read_token(&token);
+			type = read_token(tep, &token);
 		}
 
 		if (test_type_token(type, token, TEP_EVENT_OP, ":") < 0)
 			goto fail;
 
 		free_token(token);
-		if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
+		if (read_expect_type(tep, TEP_EVENT_ITEM, &token) < 0)
 			goto fail;
 
 		last_token = token;
@@ -1660,7 +1710,7 @@
 
 		/* read the rest of the type */
 		for (;;) {
-			type = read_token(&token);
+			type = read_token(tep, &token);
 			if (type == TEP_EVENT_ITEM ||
 			    (type == TEP_EVENT_OP && strcmp(token, "*") == 0) ||
 			    /*
@@ -1698,7 +1748,7 @@
 					goto fail;
 
 				delim = " ";
-				while ((type = read_token(&token)) != TEP_EVENT_NONE) {
+				while ((type = read_token(tep, &token)) != TEP_EVENT_NONE) {
 					if (type == TEP_EVENT_DELIM) {
 						if (token[0] == '(')
 							depth++;
@@ -1737,7 +1787,7 @@
 
 			field->flags |= TEP_FIELD_IS_ARRAY;
 
-			type = read_token(&token);
+			type = read_token(tep, &token);
 
 			if (type == TEP_EVENT_ITEM)
 				field->arraylen = strtoul(token, NULL, 0);
@@ -1763,7 +1813,7 @@
 				/* We only care about the last token */
 				field->arraylen = strtoul(token, NULL, 0);
 				free_token(token);
-				type = read_token(&token);
+				type = read_token(tep, &token);
 				if (type == TEP_EVENT_NONE) {
 					free(brackets);
 					do_warning_event(event, "failed to find token");
@@ -1776,12 +1826,12 @@
 			ret = append(&brackets, "", "]");
 			if (ret < 0) {
 				free(brackets);
-				goto fail;
+				goto fail_expect;
 			}
 
 			/* add brackets to type */
 
-			type = read_token(&token);
+			type = read_token(tep, &token);
 			/*
 			 * If the next token is not an OP, then it is of
 			 * the format: type [] item;
@@ -1797,7 +1847,7 @@
 				size_dynamic = type_size(field->name);
 				free_token(field->name);
 				field->name = field->alias = token;
-				type = read_token(&token);
+				type = read_token(tep, &token);
 			} else {
 				ret = append(&field->type, "", brackets);
 				if (ret < 0) {
@@ -1821,27 +1871,27 @@
 			goto fail;
 		free_token(token);
 
-		if (read_expected(TEP_EVENT_ITEM, "offset") < 0)
+		if (read_expected(tep, TEP_EVENT_ITEM, "offset") < 0)
 			goto fail_expect;
 
-		if (read_expected(TEP_EVENT_OP, ":") < 0)
+		if (read_expected(tep, TEP_EVENT_OP, ":") < 0)
 			goto fail_expect;
 
-		if (read_expect_type(TEP_EVENT_ITEM, &token))
+		if (read_expect_type(tep, TEP_EVENT_ITEM, &token))
 			goto fail;
 		field->offset = strtoul(token, NULL, 0);
 		free_token(token);
 
-		if (read_expected(TEP_EVENT_OP, ";") < 0)
+		if (read_expected(tep, TEP_EVENT_OP, ";") < 0)
 			goto fail_expect;
 
-		if (read_expected(TEP_EVENT_ITEM, "size") < 0)
+		if (read_expected(tep, TEP_EVENT_ITEM, "size") < 0)
 			goto fail_expect;
 
-		if (read_expected(TEP_EVENT_OP, ":") < 0)
+		if (read_expected(tep, TEP_EVENT_OP, ":") < 0)
 			goto fail_expect;
 
-		if (read_expect_type(TEP_EVENT_ITEM, &token))
+		if (read_expect_type(tep, TEP_EVENT_ITEM, &token))
 			goto fail;
 		field->size = strtoul(token, NULL, 0);
 		free_token(token);
@@ -1856,10 +1906,10 @@
 		if ((field->flags & TEP_FIELD_IS_DYNAMIC) && field->size == 2)
 			field->flags |= TEP_FIELD_IS_STRING | TEP_FIELD_IS_ARRAY;
 
-		if (read_expected(TEP_EVENT_OP, ";") < 0)
+		if (read_expected(tep, TEP_EVENT_OP, ";") < 0)
 			goto fail_expect;
 
-		type = read_token(&token);
+		type = read_token(tep, &token);
 		if (type != TEP_EVENT_NEWLINE) {
 			/* newer versions of the kernel have a "signed" type */
 			if (test_type_token(type, token, TEP_EVENT_ITEM, "signed"))
@@ -1867,26 +1917,26 @@
 
 			free_token(token);
 
-			if (read_expected(TEP_EVENT_OP, ":") < 0)
+			if (read_expected(tep, TEP_EVENT_OP, ":") < 0)
 				goto fail_expect;
 
-			if (read_expect_type(TEP_EVENT_ITEM, &token))
+			if (read_expect_type(tep, TEP_EVENT_ITEM, &token))
 				goto fail;
 
 			if (strtoul(token, NULL, 0))
 				field->flags |= TEP_FIELD_IS_SIGNED;
 
 			free_token(token);
-			if (read_expected(TEP_EVENT_OP, ";") < 0)
+			if (read_expected(tep, TEP_EVENT_OP, ";") < 0)
 				goto fail_expect;
 
-			if (read_expect_type(TEP_EVENT_NEWLINE, &token))
+			if (read_expect_type(tep, TEP_EVENT_NEWLINE, &token))
 				goto fail;
 		}
 
 		free_token(token);
 
-		if (field->flags & TEP_FIELD_IS_ARRAY) {
+		if (field->flags & (TEP_FIELD_IS_ARRAY | TEP_FIELD_IS_DYNAMIC)) {
 			if (field->arraylen)
 				field->elementsize = field->size / field->arraylen;
 			else if (field->flags & TEP_FIELD_IS_DYNAMIC)
@@ -1902,6 +1952,7 @@
 
 		*fields = field;
 		fields = &field->next;
+		field = NULL;
 
 	} while (1);
 
@@ -1923,22 +1974,22 @@
 	char *token;
 	int ret;
 
-	if (read_expected_item(TEP_EVENT_ITEM, "format") < 0)
+	if (read_expected_item(event->tep, TEP_EVENT_ITEM, "format") < 0)
 		return -1;
 
-	if (read_expected(TEP_EVENT_OP, ":") < 0)
+	if (read_expected(event->tep, TEP_EVENT_OP, ":") < 0)
 		return -1;
 
-	if (read_expect_type(TEP_EVENT_NEWLINE, &token))
+	if (read_expect_type(event->tep, TEP_EVENT_NEWLINE, &token))
 		goto fail;
 	free_token(token);
 
-	ret = event_read_fields(event, &event->format.common_fields);
+	ret = event_read_fields(event->tep, event, &event->format.common_fields);
 	if (ret < 0)
 		return ret;
 	event->format.nr_common = ret;
 
-	ret = event_read_fields(event, &event->format.fields);
+	ret = event_read_fields(event->tep, event, &event->format.fields);
 	if (ret < 0)
 		return ret;
 	event->format.nr_fields = ret;
@@ -1960,7 +2011,7 @@
 	enum tep_event_type type;
 	char *token;
 
-	type = read_token(&token);
+	type = read_token(event->tep, &token);
 	*tok = token;
 
 	return process_arg_token(event, arg, tok, type);
@@ -2066,7 +2117,7 @@
 	top->op.right = arg;
 
 	free_token(token);
-	type = read_token_item(&token);
+	type = read_token_item(event->tep, &token);
 	*tok = token;
 
 	return type;
@@ -2144,6 +2195,120 @@
 	return arg->op.prio;
 }
 
+static int consolidate_op_arg(struct tep_print_arg *arg)
+{
+	unsigned long long val, left, right;
+	int ret = 0;
+
+	if (arg->type != TEP_PRINT_OP)
+		return 0;
+
+	if (arg->op.left)
+		ret = consolidate_op_arg(arg->op.left);
+	if (ret < 0)
+		return ret;
+
+	if (arg->op.right)
+		ret = consolidate_op_arg(arg->op.right);
+	if (ret < 0)
+		return ret;
+
+	if (!arg->op.left || !arg->op.right)
+		return 0;
+
+	if (arg->op.left->type != TEP_PRINT_ATOM ||
+	    arg->op.right->type != TEP_PRINT_ATOM)
+		return 0;
+
+	/* Two atoms, we can do the operation now. */
+	left = strtoull(arg->op.left->atom.atom, NULL, 0);
+	right = strtoull(arg->op.right->atom.atom, NULL, 0);
+
+	switch (arg->op.op[0]) {
+	case '>':
+		switch (arg->op.op[1]) {
+		case '>':
+			val = left >> right;
+			break;
+		case '=':
+			val = left >= right;
+			break;
+		default:
+			val = left > right;
+			break;
+		}
+		break;
+	case '<':
+		switch (arg->op.op[1]) {
+		case '<':
+			val = left << right;
+			break;
+		case '=':
+			val = left <= right;
+			break;
+		default:
+			val = left < right;
+			break;
+		}
+		break;
+	case '&':
+		switch (arg->op.op[1]) {
+		case '&':
+			val = left && right;
+			break;
+		default:
+			val = left & right;
+			break;
+		}
+		break;
+	case '|':
+		switch (arg->op.op[1]) {
+		case '|':
+			val = left || right;
+			break;
+		default:
+			val = left | right;
+			break;
+		}
+		break;
+	case '-':
+		val = left - right;
+		break;
+	case '+':
+		val = left + right;
+		break;
+	case '*':
+		val = left * right;
+		break;
+	case '^':
+		val = left ^ right;
+		break;
+	case '/':
+		val = left / right;
+		break;
+	case '%':
+		val = left % right;
+		break;
+	case '=':
+		/* Only '==' is called here */
+		val = left == right;
+		break;
+	case '!':
+		/* Only '!=' is called here. */
+		val = left != right;
+		break;
+	default:
+		return 0;
+	}
+
+	free_arg(arg->op.left);
+	free_arg(arg->op.right);
+
+	arg->type = TEP_PRINT_ATOM;
+	free(arg->op.op);
+	return asprintf(&arg->atom.atom, "%lld", val) < 0 ? -1 : 0;
+}
+
 /* Note, *tok does not get freed, but will most likely be saved */
 static enum tep_event_type
 process_op(struct tep_event *event, struct tep_print_arg *arg, char **tok)
@@ -2203,6 +2368,7 @@
 		arg->type = TEP_PRINT_OP;
 		arg->op.op = token;
 		arg->op.left = left;
+		arg->op.right = NULL;
 		arg->op.prio = 0;
 
 		/* it will set arg->op.right */
@@ -2246,7 +2412,7 @@
 			goto out_free;
 		}
 
-		type = read_token_item(&token);
+		type = read_token_item(event->tep, &token);
 		*tok = token;
 
 		/* could just be a type pointer */
@@ -2308,6 +2474,7 @@
 		arg->type = TEP_PRINT_OP;
 		arg->op.op = token;
 		arg->op.left = left;
+		arg->op.right = NULL;
 
 		arg->op.prio = 0;
 
@@ -2351,7 +2518,7 @@
 	char *field;
 	char *token;
 
-	type = read_token_item(&token);
+	type = read_token_item(event->tep, &token);
 	/*
 	 * Check if REC happens to be surrounded by parenthesis, and
 	 * return if that's the case, as "(REC)->" is valid.
@@ -2367,7 +2534,7 @@
 
 	free_token(token);
 
-	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
+	if (read_expect_type(event->tep, TEP_EVENT_ITEM, &token) < 0)
 		goto out_free;
 	field = token;
 
@@ -2384,7 +2551,7 @@
 		is_symbolic_field = 0;
 	}
 
-	type = read_token(&token);
+	type = read_token(event->tep, &token);
 	*tok = token;
 
 	return type;
@@ -2412,19 +2579,31 @@
 
 	type = process_arg(event, field, &token);
 
-	if (test_type_token(type, token, TEP_EVENT_DELIM, next_token)) {
-		errno = EINVAL;
-		ret = -1;
-		free_arg(field);
-		goto out_free_token;
+	/* We do allow operators */
+	if (type == TEP_EVENT_OP) {
+		type = process_op(event, field, &token);
+
+		if (consolidate_op_arg(field) < 0)
+			type = TEP_EVENT_ERROR;
+
+		if (type == TEP_EVENT_ERROR)
+			goto out_error;
 	}
 
+	if (test_type_token(type, token, TEP_EVENT_DELIM, next_token))
+		goto out_error;
+
 	*print_arg = field;
 
 out_free_token:
 	free_token(token);
 
 	return ret;
+out_error:
+	errno = EINVAL;
+	ret = -1;
+	free_arg(field);
+	goto out_free_token;
 }
 
 static char *arg_eval (struct tep_print_arg *arg);
@@ -2437,6 +2616,10 @@
 	int len;
 
 	len = strlen(type);
+	if (len < 2) {
+		do_warning("invalid type: %s", type);
+		return val;
+	}
 
 	if (pointer) {
 
@@ -2692,6 +2875,7 @@
 	case TEP_PRINT_STRING:
 	case TEP_PRINT_BSTRING:
 	case TEP_PRINT_BITMASK:
+	case TEP_PRINT_CPUMASK:
 	default:
 		do_warning("invalid eval type %d", arg->type);
 		ret = 0;
@@ -2721,6 +2905,7 @@
 	case TEP_PRINT_STRING:
 	case TEP_PRINT_BSTRING:
 	case TEP_PRINT_BITMASK:
+	case TEP_PRINT_CPUMASK:
 	default:
 		do_warning("invalid eval type %d", arg->type);
 		break;
@@ -2740,7 +2925,7 @@
 
 	do {
 		free_token(token);
-		type = read_token_item(&token);
+		type = read_token_item(event->tep, &token);
 		if (test_type_token(type, token, TEP_EVENT_OP, "{"))
 			break;
 
@@ -2794,7 +2979,7 @@
 		list = &field->next;
 
 		free_token(token);
-		type = read_token_item(&token);
+		type = read_token_item(event->tep, &token);
 	} while (type == TEP_EVENT_DELIM && strcmp(token, ",") == 0);
 
 	*tok = token;
@@ -2838,10 +3023,10 @@
 
 	arg->flags.field = field;
 
-	type = read_token_item(&token);
+	type = read_token_item(event->tep, &token);
 	if (event_item_type(type)) {
 		arg->flags.delim = token;
-		type = read_token_item(&token);
+		type = read_token_item(event->tep, &token);
 	}
 
 	if (test_type_token(type, token, TEP_EVENT_DELIM, ","))
@@ -2852,7 +3037,7 @@
 		goto out_free;
 
 	free_token(token);
-	type = read_token_item(tok);
+	type = read_token_item(event->tep, tok);
 	return type;
 
 out_free_field:
@@ -2891,7 +3076,7 @@
 		goto out_free;
 
 	free_token(token);
-	type = read_token_item(tok);
+	type = read_token_item(event->tep, tok);
 	return type;
 
 out_free_field:
@@ -2915,7 +3100,7 @@
 	if (alloc_and_process_delim(event, ")", &arg->hex.size))
 		goto free_field;
 
-	return read_token_item(tok);
+	return read_token_item(event->tep, tok);
 
 free_field:
 	free_arg(arg->hex.field);
@@ -2953,7 +3138,7 @@
 	if (alloc_and_process_delim(event, ")", &arg->int_array.el_size))
 		goto free_size;
 
-	return read_token_item(tok);
+	return read_token_item(event->tep, tok);
 
 free_size:
 	free_arg(arg->int_array.count);
@@ -2980,7 +3165,7 @@
 	 * The item within the parenthesis is another field that holds
 	 * the index into where the array starts.
 	 */
-	type = read_token(&token);
+	type = read_token(event->tep, &token);
 	*tok = token;
 	if (type != TEP_EVENT_ITEM)
 		goto out_free;
@@ -2994,11 +3179,11 @@
 	arg->dynarray.field = field;
 	arg->dynarray.index = 0;
 
-	if (read_expected(TEP_EVENT_DELIM, ")") < 0)
+	if (read_expected(event->tep, TEP_EVENT_DELIM, ")") < 0)
 		goto out_free;
 
 	free_token(token);
-	type = read_token_item(&token);
+	type = read_token_item(event->tep, &token);
 	*tok = token;
 	if (type != TEP_EVENT_OP || strcmp(token, "[") != 0)
 		return type;
@@ -3019,7 +3204,7 @@
 		goto out_free_arg;
 
 	free_token(token);
-	type = read_token_item(tok);
+	type = read_token_item(event->tep, tok);
 	return type;
 
  out_free_arg:
@@ -3038,7 +3223,7 @@
 	enum tep_event_type type;
 	char *token;
 
-	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
+	if (read_expect_type(event->tep, TEP_EVENT_ITEM, &token) < 0)
 		goto out_free;
 
 	arg->type = TEP_PRINT_DYNAMIC_ARRAY_LEN;
@@ -3051,11 +3236,11 @@
 	arg->dynarray.field = field;
 	arg->dynarray.index = 0;
 
-	if (read_expected(TEP_EVENT_DELIM, ")") < 0)
+	if (read_expected(event->tep, TEP_EVENT_DELIM, ")") < 0)
 		goto out_err;
 
 	free_token(token);
-	type = read_token(&token);
+	type = read_token(event->tep, &token);
 	*tok = token;
 
 	return type;
@@ -3100,7 +3285,7 @@
 		goto out_free;
 
 	free_token(token);
-	type = read_token_item(&token);
+	type = read_token_item(event->tep, &token);
 
 	/*
 	 * If the next token is an item or another open paren, then
@@ -3142,13 +3327,12 @@
 
 
 static enum tep_event_type
-process_str(struct tep_event *event __maybe_unused, struct tep_print_arg *arg,
-	    char **tok)
+process_str(struct tep_event *event, struct tep_print_arg *arg, char **tok)
 {
 	enum tep_event_type type;
 	char *token;
 
-	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
+	if (read_expect_type(event->tep, TEP_EVENT_ITEM, &token) < 0)
 		goto out_free;
 
 	arg->type = TEP_PRINT_STRING;
@@ -3156,10 +3340,10 @@
 	arg->string.offset = -1;
 	arg->string.field = NULL;
 
-	if (read_expected(TEP_EVENT_DELIM, ")") < 0)
+	if (read_expected(event->tep, TEP_EVENT_DELIM, ")") < 0)
 		goto out_err;
 
-	type = read_token(&token);
+	type = read_token(event->tep, &token);
 	*tok = token;
 
 	return type;
@@ -3172,13 +3356,12 @@
 }
 
 static enum tep_event_type
-process_bitmask(struct tep_event *event __maybe_unused, struct tep_print_arg *arg,
-		char **tok)
+process_bitmask(struct tep_event *event, struct tep_print_arg *arg, char **tok)
 {
 	enum tep_event_type type;
 	char *token;
 
-	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
+	if (read_expect_type(event->tep, TEP_EVENT_ITEM, &token) < 0)
 		goto out_free;
 
 	arg->type = TEP_PRINT_BITMASK;
@@ -3186,10 +3369,10 @@
 	arg->bitmask.offset = -1;
 	arg->bitmask.field = NULL;
 
-	if (read_expected(TEP_EVENT_DELIM, ")") < 0)
+	if (read_expected(event->tep, TEP_EVENT_DELIM, ")") < 0)
 		goto out_err;
 
-	type = read_token(&token);
+	type = read_token(event->tep, &token);
 	*tok = token;
 
 	return type;
@@ -3201,6 +3384,17 @@
 	return TEP_EVENT_ERROR;
 }
 
+static enum tep_event_type
+process_cpumask(struct tep_event *event __maybe_unused, struct tep_print_arg *arg,
+		char **tok)
+{
+	enum tep_event_type type = process_bitmask(event, arg, tok);
+	if (type != TEP_EVENT_ERROR)
+		arg->type = TEP_PRINT_CPUMASK;
+
+	return type;
+}
+
 static struct tep_function_handler *
 find_func_handler(struct tep_handle *tep, char *func_name)
 {
@@ -3280,7 +3474,7 @@
 		free_token(token);
 	}
 
-	type = read_token(&token);
+	type = read_token(event->tep, &token);
 	*tok = token;
 
 	return type;
@@ -3306,14 +3500,14 @@
 	free_token(token);
 
 	/* We don't care what the second parameter is of the __builtin_expect() */
-	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
+	if (read_expect_type(event->tep, TEP_EVENT_ITEM, &token) < 0)
 		goto out_free;
 
-	if (read_expected(TEP_EVENT_DELIM, ")") < 0)
+	if (read_expected(event->tep, TEP_EVENT_DELIM, ")") < 0)
 		goto out_free;
 
 	free_token(token);
-	type = read_token_item(tok);
+	type = read_token_item(event->tep, tok);
 	return type;
 
 out_free:
@@ -3323,6 +3517,95 @@
 }
 
 static enum tep_event_type
+process_sizeof(struct tep_event *event, struct tep_print_arg *arg, char **tok)
+{
+	struct tep_format_field *field;
+	enum tep_event_type type;
+	char *token = NULL;
+	bool ok = false;
+	int ret;
+
+	type = read_token_item(event->tep, &token);
+
+	arg->type = TEP_PRINT_ATOM;
+
+	/* We handle some sizeof types */
+	if (strcmp(token, "unsigned") == 0) {
+		free_token(token);
+		type = read_token_item(event->tep, &token);
+
+		if (type == TEP_EVENT_ERROR)
+			goto error;
+
+		if (type != TEP_EVENT_ITEM)
+			ok = true;
+	}
+
+	if (ok || strcmp(token, "int") == 0) {
+		arg->atom.atom = strdup("4");
+
+	} else if (strcmp(token, "long") == 0) {
+		free_token(token);
+		type = read_token_item(event->tep, &token);
+
+		if (token && strcmp(token, "long") == 0) {
+			arg->atom.atom = strdup("8");
+		} else {
+			switch (event->tep->long_size) {
+			case 4:
+				arg->atom.atom = strdup("4");
+				break;
+			case 8:
+				arg->atom.atom = strdup("8");
+				break;
+			default:
+				/* long size not defined yet, fail to parse it */
+				goto error;
+			}
+			/* The token is the next token */
+			ok = true;
+		}
+	} else if (strcmp(token, "REC") == 0) {
+
+		free_token(token);
+		type = read_token_item(event->tep, &token);
+
+		if (test_type_token(type, token,  TEP_EVENT_OP, "->"))
+			goto error;
+		free_token(token);
+
+		if (read_expect_type(event->tep, TEP_EVENT_ITEM, &token) < 0)
+			goto error;
+
+		field = tep_find_any_field(event, token);
+		/* Can't handle arrays (yet) */
+		if (!field || field->flags & TEP_FIELD_IS_ARRAY)
+			goto error;
+
+		ret = asprintf(&arg->atom.atom, "%d", field->size);
+		if (ret < 0)
+			goto error;
+
+	} else if (!ok) {
+		goto error;
+	}
+
+	if (!ok) {
+		free_token(token);
+		type = read_token_item(event->tep, tok);
+	}
+	if (test_type_token(type, token,  TEP_EVENT_DELIM, ")"))
+		goto error;
+
+	free_token(token);
+	return read_token_item(event->tep, tok);
+error:
+	free_token(token);
+	*tok = NULL;
+	return TEP_EVENT_ERROR;
+}
+
+static enum tep_event_type
 process_function(struct tep_event *event, struct tep_print_arg *arg,
 		 char *token, char **tok)
 {
@@ -3360,8 +3643,15 @@
 		free_token(token);
 		return process_bitmask(event, arg, tok);
 	}
+	if (strcmp(token, "__get_cpumask") == 0 ||
+	    strcmp(token, "__get_rel_cpumask") == 0) {
+		free_token(token);
+		return process_cpumask(event, arg, tok);
+	}
 	if (strcmp(token, "__get_dynamic_array") == 0 ||
-	    strcmp(token, "__get_rel_dynamic_array") == 0) {
+	    strcmp(token, "__get_rel_dynamic_array") == 0 ||
+	    strcmp(token, "__get_sockaddr") == 0 ||
+	    strcmp(token, "__get_sockaddr_rel") == 0) {
 		free_token(token);
 		return process_dynamic_array(event, arg, tok);
 	}
@@ -3374,6 +3664,10 @@
 		free_token(token);
 		return process_builtin_expect(event, arg, tok);
 	}
+	if (strcmp(token, "sizeof") == 0) {
+		free_token(token);
+		return process_sizeof(event, arg, tok);
+	}
 
 	func = find_func_handler(event->tep, token);
 	if (func) {
@@ -3404,7 +3698,7 @@
 		}
 		atom = token;
 		/* test the next token */
-		type = read_token_item(&token);
+		type = read_token_item(event->tep, &token);
 
 		/*
 		 * If the next token is a parenthesis, then this
@@ -3429,7 +3723,7 @@
 				return TEP_EVENT_ERROR;
 			}
 			free_token(token);
-			type = read_token_item(&token);
+			type = read_token_item(event->tep, &token);
 		}
 
 		arg->type = TEP_PRINT_ATOM;
@@ -3440,7 +3734,7 @@
 	case TEP_EVENT_SQUOTE:
 		arg->type = TEP_PRINT_ATOM;
 		arg->atom.atom = token;
-		type = read_token_item(&token);
+		type = read_token_item(event->tep, &token);
 		break;
 	case TEP_EVENT_DELIM:
 		if (strcmp(token, "(") == 0) {
@@ -3481,7 +3775,7 @@
 
 	do {
 		if (type == TEP_EVENT_NEWLINE) {
-			type = read_token_item(&token);
+			type = read_token_item(event->tep, &token);
 			continue;
 		}
 
@@ -3506,6 +3800,10 @@
 		if (type == TEP_EVENT_OP) {
 			type = process_op(event, arg, &token);
 			free_token(token);
+
+			if (consolidate_op_arg(arg) < 0)
+				type = TEP_EVENT_ERROR;
+
 			if (type == TEP_EVENT_ERROR) {
 				*list = NULL;
 				free_arg(arg);
@@ -3536,16 +3834,16 @@
 	char *token;
 	int ret;
 
-	if (read_expected_item(TEP_EVENT_ITEM, "print") < 0)
+	if (read_expected_item(event->tep, TEP_EVENT_ITEM, "print") < 0)
 		return -1;
 
-	if (read_expected(TEP_EVENT_ITEM, "fmt") < 0)
+	if (read_expected(event->tep, TEP_EVENT_ITEM, "fmt") < 0)
 		return -1;
 
-	if (read_expected(TEP_EVENT_OP, ":") < 0)
+	if (read_expected(event->tep, TEP_EVENT_OP, ":") < 0)
 		return -1;
 
-	if (read_expect_type(TEP_EVENT_DQUOTE, &token) < 0)
+	if (read_expect_type(event->tep, TEP_EVENT_DQUOTE, &token) < 0)
 		goto fail;
 
  concat:
@@ -3553,7 +3851,7 @@
 	event->print_fmt.args = NULL;
 
 	/* ok to have no arg */
-	type = read_token_item(&token);
+	type = read_token_item(event->tep, &token);
 
 	if (type == TEP_EVENT_NONE)
 		return 0;
@@ -3943,9 +4241,9 @@
 {
 	/* Test for overflow */
 	if (field->offset + field->size > size) {
-		if (*offset)
+		if (offset)
 			*offset = 0;
-		if (*len)
+		if (len)
 			*len = 0;
 		return;
 	}
@@ -3954,6 +4252,18 @@
 		*offset += field->offset + field->size;
 }
 
+static bool check_data_offset_size(struct tep_event *event, const char *field_name,
+				    int data_size, int field_offset, int field_size)
+{
+	/* Check to make sure the field is within the data */
+	if (field_offset + field_size <= data_size)
+		return false;
+
+	tep_warning("Event '%s' field '%s' goes beyond the size of the event (%d > %d)",
+		    event->name, field_name, field_offset + field_size, data_size);
+	return true;
+}
+
 static unsigned long long
 eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg *arg)
 {
@@ -3980,6 +4290,12 @@
 			if (!arg->field.field)
 				goto out_warning_field;
 		}
+		if (check_data_offset_size(event, arg->field.name, size,
+					   arg->field.field->offset,
+					   arg->field.field->size)) {
+			val = 0;
+			break;
+		}
 		/* must be a number */
 		val = tep_read_number(tep, data + arg->field.field->offset,
 				      arg->field.field->size);
@@ -3996,6 +4312,7 @@
 	case TEP_PRINT_STRING:
 	case TEP_PRINT_BSTRING:
 	case TEP_PRINT_BITMASK:
+	case TEP_PRINT_CPUMASK:
 		return 0;
 	case TEP_PRINT_FUNC: {
 		struct trace_seq s;
@@ -4047,6 +4364,11 @@
 			default:
 				goto default_op; /* oops, all bets off */
 			}
+			if (check_data_offset_size(event, arg->field.name, size,
+						   offset, field_size)) {
+				val = 0;
+				break;
+			}
 			val = tep_read_number(tep,
 					      data + offset, field_size);
 			if (typearg)
@@ -4156,7 +4478,11 @@
 		/* Without [], we pass the address to the dynamic data */
 		dynamic_offset_field(tep, arg->dynarray.field, data, size,
 				     &offset, NULL);
-		val = (unsigned long long)((unsigned long)data + offset);
+		if (check_data_offset_size(event, arg->field.name, size,
+					   offset, 0)) {
+			val = (unsigned long)data;
+			break;
+		}
 		val = (unsigned long)data + offset;
 		break;
 	default: /* not sure what to do there */
@@ -4277,6 +4603,161 @@
 	free(str);
 }
 
+#define log10(n)               \
+(			       \
+	n < 10UL ? 0 :	       \
+	n < 100UL ? 1 :	       \
+	n < 1000UL ? 2 :       \
+	n < 10000UL ? 3 :      \
+	n < 100000UL ? 4 :     \
+	n < 1000000UL ? 5 :    \
+	n < 10000000UL ? 6 :   \
+	n < 100000000UL ? 7 :  \
+	n < 1000000000UL ? 8 : \
+	9		       \
+)
+
+/* ilog10(0) should be 1 but the 0 simplifies below math */
+#define ilog10(n)    \
+(                     \
+	n == 0 ? 0UL : \
+	n == 1 ? 10UL : \
+	n == 2 ? 100UL : \
+	n == 3 ? 1000UL : \
+	n == 4 ? 10000UL : \
+	n == 5 ? 100000UL : \
+	n == 6 ? 1000000UL : \
+	n == 7 ? 10000000UL : \
+	n == 8 ? 100000000UL : \
+		 1000000000UL   \
+)
+
+static unsigned int cpumask_worst_size(unsigned int nr_bits)
+{
+	/*
+	 * Printing all the CPUs separated by a comma is a decent bound for the
+	 * maximum memory required to print a cpumask (a slightly better bound
+	 * is chunks of 2 bits set, i.e. 0-1,3-4,6-7...).
+	 *
+	 * e.g. for nr_bits=132:
+	 * - 131 commas
+	 * - 10 * 1 chars for CPUS [0, 9]
+	 * - 90 * 2 chars for CPUS [10-99]
+	 * - 32 * 3 chars for CPUS [100-131]
+	 */
+	unsigned int last_cpu = nr_bits - 1;
+	unsigned int nr_chars = nr_bits - 1;
+	int last_lvl = log10(last_cpu);
+
+	/* All log10 levels before the last one have all values used */
+	for (int lvl = 0; lvl < last_lvl; lvl++) {
+		int nr_values = ilog10(lvl + 1) - ilog10(lvl);
+
+		nr_chars += nr_values * (lvl + 1);
+	}
+	/* Last level is incomplete */
+	nr_chars += (nr_bits - ilog10(last_lvl)) * (last_lvl + 1);
+
+	return nr_chars;
+}
+
+static void print_cpumask_to_seq(struct tep_handle *tep,
+				 struct trace_seq *s, const char *format,
+				 int len_arg, const void *data, int size)
+{
+	int firstone = -1, firstzero = -1;
+	int nr_bits = size * 8;
+	bool first = true;
+	int str_size = 0;
+	char buf[12]; /* '-' + log10(2^32) + 1 digits + '\0' */
+	char *str;
+	int index;
+	int i;
+
+	str = malloc(cpumask_worst_size(nr_bits) + 1);
+	if (!str) {
+		do_warning("%s: not enough memory!", __func__);
+		return;
+	}
+
+	for (i = 0; i < size; i++) {
+		unsigned char byte;
+		int fmtsize;
+
+		if (tep->file_bigendian)
+			index = size - (i + 1);
+		else
+			index = i;
+
+		/* Byte by byte scan, not the best... */
+		byte = *(((unsigned char *)data) + index);
+more:
+		/* First find a bit set to one...*/
+		if (firstone < 0 && byte) {
+			/*
+			 * Set all lower bits, so a later ffz on this same byte
+			 * is guaranteed to find a later bit.
+			 */
+			firstone = ffs(byte) - 1;
+			byte |= (1 << firstone) - 1;
+			firstone += i * 8;
+		}
+
+		if (firstone < 0)
+			continue;
+
+		/* ...Then find a bit set to zero */
+		if ((~byte) & 0xFF) {
+			/*
+			 * Clear all lower bits, so a later ffs on this same
+			 * byte is guaranteed to find a later bit.
+			 */
+			firstzero = ffs(~byte) - 1;
+			byte &= ~((1 << (firstzero)) - 1);
+			firstzero += i * 8;
+		} else if (i == size - 1) { /* ...Or reach the end of the mask */
+			firstzero = nr_bits;
+			byte = 0;
+		} else {
+			continue;
+		}
+
+		/* We've found a bit set to one, and a later bit set to zero. */
+		if (!first) {
+			str[str_size] = ',';
+			str_size++;
+		}
+		first = false;
+
+		/* It takes {log10(number) + 1} chars to format a number */
+		fmtsize = log10(firstone) + 1;
+		snprintf(buf, fmtsize + 1, "%d", firstone);
+		memcpy(str + str_size, buf, fmtsize);
+		str_size += fmtsize;
+
+		if (firstzero > firstone + 1) {
+			fmtsize = log10(firstzero - 1) + 2;
+			snprintf(buf, fmtsize + 1, "-%d", firstzero - 1);
+			memcpy(str + str_size, buf, fmtsize);
+			str_size += fmtsize;
+		}
+
+		firstzero = firstone = -1;
+		if (byte)
+			goto more;
+	}
+
+	str[str_size] = 0;
+	str_size++;
+
+	if (len_arg >= 0)
+		trace_seq_printf(s, format, len_arg, str);
+	else
+		trace_seq_printf(s, format, str);
+
+	free(str);
+}
+
 static void print_str_arg(struct trace_seq *s, void *data, int size,
 			  struct tep_event *event, const char *format,
 			  int len_arg, struct tep_print_arg *arg)
@@ -4466,10 +4947,10 @@
 	case TEP_PRINT_STRING: {
 		if (!arg->string.field) {
 			arg->string.field = tep_find_any_field(event, arg->string.string);
+			if (!arg->string.field)
+				break;
 			arg->string.offset = arg->string.field->offset;
 		}
-		if (!arg->string.field)
-			break;
 		dynamic_offset_field(tep, arg->string.field, data, size, &offset, &len);
 		/* Do not attempt to save zero length dynamic strings */
 		if (!len)
@@ -4483,12 +4964,24 @@
 	case TEP_PRINT_BITMASK: {
 		if (!arg->bitmask.field) {
 			arg->bitmask.field = tep_find_any_field(event, arg->bitmask.bitmask);
+			if (!arg->bitmask.field)
+				break;
+			arg->bitmask.offset = arg->bitmask.field->offset;
+		}
+		dynamic_offset_field(tep, arg->bitmask.field, data, size, &offset, &len);
+		print_bitmask_to_seq(tep, s, format, len_arg,
+				     data + offset, len);
+		break;
+	}
+	case TEP_PRINT_CPUMASK: {
+		if (!arg->bitmask.field) {
+			arg->bitmask.field = tep_find_any_field(event, arg->bitmask.bitmask);
 			arg->bitmask.offset = arg->bitmask.field->offset;
 		}
 		if (!arg->bitmask.field)
 			break;
 		dynamic_offset_field(tep, arg->bitmask.field, data, size, &offset, &len);
-		print_bitmask_to_seq(tep, s, format, len_arg,
+		print_cpumask_to_seq(tep, s, format, len_arg,
 				     data + offset, len);
 		break;
 	}
@@ -4790,8 +5283,10 @@
 				arg->next = NULL;
 				arg->type = TEP_PRINT_BSTRING;
 				arg->string.string = strdup(bptr);
-				if (!arg->string.string)
+				if (!arg->string.string) {
+					free(arg);
 					goto out_free;
+				}
 				bptr += strlen(bptr) + 1;
 				*next = arg;
 				next = &arg->next;
@@ -5485,6 +5980,7 @@
 				trace_seq_printf(s, "%llu", val);
 		}
 	}
+	trace_seq_terminate(s);
 }
 
 static int print_parse_data(struct tep_print_parse *parse, struct trace_seq *s,
@@ -5498,7 +5994,7 @@
 	struct tep_print_parse *start_parse;
 	struct tep_print_parse *parse;
 	struct tep_print_arg *arg;
-	bool has_0x;
+	bool has_0x = false;
 
 	parse = parse_ptr ? *parse_ptr : event->print_fmt.print_cache;
 
@@ -5536,7 +6032,7 @@
 		if (has_0x)
 			trace_seq_puts(s, "0x");
 
-		print_parse_data(parse, s, data, field->size, event);
+		print_parse_data(parse, s, data, size, event);
 
 		if (parse_ptr)
 			*parse_ptr = parse->next;
@@ -6272,8 +6768,13 @@
 	       (hardirq && softirq) ? 'H' :
 	       hardirq ? 'h' : softirq ? 's' : '.');
 
-	if (pc)
-		trace_seq_printf(&sq, "%x", pc);
+	if (pc & 0xf)
+		trace_seq_printf(&sq, "%x", pc & 0xf);
+	else
+		trace_seq_printf(&sq, ".");
+
+	if (pc & 0xf0)
+		trace_seq_printf(&sq, "%x", pc >> 4);
 	else
 		trace_seq_printf(&sq, ".");
 
@@ -6999,6 +7500,9 @@
 	case TEP_PRINT_BITMASK:
 		printf("__get_bitmask(%s)", args->bitmask.bitmask);
 		break;
+	case TEP_PRINT_CPUMASK:
+		printf("__get_cpumask(%s)", args->bitmask.bitmask);
+		break;
 	case TEP_PRINT_TYPE:
 		printf("(%s)", args->typecast.type);
 		print_args(args->typecast.item);
@@ -7024,7 +7528,7 @@
 	}
 }
 
-static void parse_header_field(const char *field,
+static void parse_header_field(struct tep_handle *tep, const char *field,
 			       int *offset, int *size, int mandatory)
 {
 	unsigned long long save_input_buf_ptr;
@@ -7032,16 +7536,16 @@
 	char *token;
 	int type;
 
-	save_input_buf_ptr = input_buf_ptr;
-	save_input_buf_siz = input_buf_siz;
+	save_input_buf_ptr = tep->input_buf_ptr;
+	save_input_buf_siz = tep->input_buf_siz;
 
-	if (read_expected(TEP_EVENT_ITEM, "field") < 0)
+	if (read_expected(tep, TEP_EVENT_ITEM, "field") < 0)
 		return;
-	if (read_expected(TEP_EVENT_OP, ":") < 0)
+	if (read_expected(tep, TEP_EVENT_OP, ":") < 0)
 		return;
 
 	/* type */
-	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
+	if (read_expect_type(tep, TEP_EVENT_ITEM, &token) < 0)
 		goto fail;
 	free_token(token);
 
@@ -7049,39 +7553,39 @@
 	 * If this is not a mandatory field, then test it first.
 	 */
 	if (mandatory) {
-		if (read_expected(TEP_EVENT_ITEM, field) < 0)
+		if (read_expected(tep, TEP_EVENT_ITEM, field) < 0)
 			return;
 	} else {
-		if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
+		if (read_expect_type(tep, TEP_EVENT_ITEM, &token) < 0)
 			goto fail;
 		if (strcmp(token, field) != 0)
 			goto discard;
 		free_token(token);
 	}
 
-	if (read_expected(TEP_EVENT_OP, ";") < 0)
+	if (read_expected(tep, TEP_EVENT_OP, ";") < 0)
 		return;
-	if (read_expected(TEP_EVENT_ITEM, "offset") < 0)
+	if (read_expected(tep, TEP_EVENT_ITEM, "offset") < 0)
 		return;
-	if (read_expected(TEP_EVENT_OP, ":") < 0)
+	if (read_expected(tep, TEP_EVENT_OP, ":") < 0)
 		return;
-	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
+	if (read_expect_type(tep, TEP_EVENT_ITEM, &token) < 0)
 		goto fail;
 	*offset = atoi(token);
 	free_token(token);
-	if (read_expected(TEP_EVENT_OP, ";") < 0)
+	if (read_expected(tep, TEP_EVENT_OP, ";") < 0)
 		return;
-	if (read_expected(TEP_EVENT_ITEM, "size") < 0)
+	if (read_expected(tep, TEP_EVENT_ITEM, "size") < 0)
 		return;
-	if (read_expected(TEP_EVENT_OP, ":") < 0)
+	if (read_expected(tep, TEP_EVENT_OP, ":") < 0)
 		return;
-	if (read_expect_type(TEP_EVENT_ITEM, &token) < 0)
+	if (read_expect_type(tep, TEP_EVENT_ITEM, &token) < 0)
 		goto fail;
 	*size = atoi(token);
 	free_token(token);
-	if (read_expected(TEP_EVENT_OP, ";") < 0)
+	if (read_expected(tep, TEP_EVENT_OP, ";") < 0)
 		return;
-	type = read_token(&token);
+	type = read_token(tep, &token);
 	if (type != TEP_EVENT_NEWLINE) {
 		/* newer versions of the kernel have a "signed" type */
 		if (type != TEP_EVENT_ITEM)
@@ -7092,17 +7596,17 @@
 
 		free_token(token);
 
-		if (read_expected(TEP_EVENT_OP, ":") < 0)
+		if (read_expected(tep, TEP_EVENT_OP, ":") < 0)
 			return;
 
-		if (read_expect_type(TEP_EVENT_ITEM, &token))
+		if (read_expect_type(tep, TEP_EVENT_ITEM, &token))
 			goto fail;
 
 		free_token(token);
-		if (read_expected(TEP_EVENT_OP, ";") < 0)
+		if (read_expected(tep, TEP_EVENT_OP, ";") < 0)
 			return;
 
-		if (read_expect_type(TEP_EVENT_NEWLINE, &token))
+		if (read_expect_type(tep, TEP_EVENT_NEWLINE, &token))
 			goto fail;
 	}
  fail:
@@ -7110,8 +7614,8 @@
 	return;
 
  discard:
-	input_buf_ptr = save_input_buf_ptr;
-	input_buf_siz = save_input_buf_siz;
+	tep->input_buf_ptr = save_input_buf_ptr;
+	tep->input_buf_siz = save_input_buf_siz;
 	*offset = 0;
 	*size = 0;
 	free_token(token);
@@ -7146,15 +7650,15 @@
 		tep->old_format = 1;
 		return -1;
 	}
-	init_input_buf(buf, size);
+	init_input_buf(tep, buf, size);
 
-	parse_header_field("timestamp", &tep->header_page_ts_offset,
+	parse_header_field(tep, "timestamp", &tep->header_page_ts_offset,
 			   &tep->header_page_ts_size, 1);
-	parse_header_field("commit", &tep->header_page_size_offset,
+	parse_header_field(tep, "commit", &tep->header_page_size_offset,
 			   &tep->header_page_size_size, 1);
-	parse_header_field("overwrite", &tep->header_page_overwrite,
+	parse_header_field(tep, "overwrite", &tep->header_page_overwrite,
 			   &ignore, 0);
-	parse_header_field("data", &tep->header_page_data_offset,
+	parse_header_field(tep, "data", &tep->header_page_data_offset,
 			   &tep->header_page_data_size, 1);
 
 	return 0;
@@ -7231,13 +7735,13 @@
 	struct tep_event *event;
 	int ret;
 
-	init_input_buf(buf, size);
+	init_input_buf(tep, buf, size);
 
 	*eventp = event = alloc_event();
 	if (!event)
 		return TEP_ERRNO__MEM_ALLOC_FAILED;
 
-	event->name = event_read_name();
+	event->name = event_read_name(tep);
 	if (!event->name) {
 		/* Bad event? */
 		ret = TEP_ERRNO__MEM_ALLOC_FAILED;
@@ -7251,7 +7755,7 @@
 			event->flags |= TEP_EVENT_FL_ISBPRINT;
 	}
 		
-	event->id = event_read_id();
+	event->id = event_read_id(tep);
 	if (event->id < 0) {
 		ret = TEP_ERRNO__READ_ID_FAILED;
 		/*
diff --git a/src/kbuffer-parse.c b/src/kbuffer-parse.c
index 7499950..390a789 100644
--- a/src/kbuffer-parse.c
+++ b/src/kbuffer-parse.c
@@ -6,6 +6,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdbool.h>
+
+#include <sys/utsname.h>
 
 #include "kbuffer.h"
 
@@ -14,6 +17,9 @@
 
 #define COMMIT_MASK ((1 << 27) - 1)
 
+/* Absolute time stamps do not have the 5 MSB, take from the real time stamp */
+#define TS_MSB		(0xf8ULL << 56)
+
 enum {
 	KBUFFER_FL_HOST_BIG_ENDIAN	= (1<<0),
 	KBUFFER_FL_BIG_ENDIAN		= (1<<1),
@@ -156,6 +162,24 @@
 
 static int __next_event(struct kbuffer *kbuf);
 
+/*
+ * Just because sizeof(long) is 4 bytes, doesn't mean the OS isn't
+ * 64bits
+ */
+static bool host_is_32bit(void)
+{
+	struct utsname buf;
+	int ret;
+
+	ret = uname(&buf);
+	if (ret < 0) {
+		/* Oh well, just assume it is 32 bit */
+		return true;
+	}
+	/* If the uname machine value contains 64, assume the kernel is 64 bit */
+	return strstr(buf.machine, "64") == NULL;
+}
+
 /**
  * kbuffer_alloc - allocat a new kbuffer
  * @size;	enum to denote size of word
@@ -172,6 +196,10 @@
 	switch (size) {
 	case KBUFFER_LSIZE_4:
 		break;
+	case KBUFFER_LSIZE_SAME_AS_HOST:
+		if (sizeof(long) != 8 && host_is_32bit())
+			break;
+		/* fallthrough */
 	case KBUFFER_LSIZE_8:
 		flags |= KBUFFER_FL_LONG_8;
 		break;
@@ -181,6 +209,7 @@
 
 	switch (endian) {
 	case KBUFFER_ENDIAN_LITTLE:
+	case KBUFFER_ENDIAN_SAME_AS_HOST:
 		break;
 	case KBUFFER_ENDIAN_BIG:
 		flags |= KBUFFER_FL_BIG_ENDIAN;
@@ -195,8 +224,11 @@
 
 	kbuf->flags = flags;
 
-	if (host_is_bigendian())
+	if (host_is_bigendian()) {
+		if (endian == KBUFFER_ENDIAN_SAME_AS_HOST)
+			flags |= KBUFFER_FL_BIG_ENDIAN;
 		kbuf->flags |= KBUFFER_FL_HOST_BIG_ENDIAN;
+	}
 
 	if (do_swap(kbuf)) {
 		kbuf->read_8 = __read_8_sw;
@@ -347,7 +379,7 @@
 translate_data(struct kbuffer *kbuf, void *data, void **rptr,
 	       unsigned long long *delta, int *length)
 {
-	unsigned long long extend;
+	unsigned long long extend, msb = 0;
 	unsigned int type_len_ts;
 	unsigned int type_len;
 
@@ -362,13 +394,15 @@
 		*length = read_4(kbuf, data);
 		break;
 
-	case KBUFFER_TYPE_TIME_EXTEND:
 	case KBUFFER_TYPE_TIME_STAMP:
+		msb = kbuf->timestamp & TS_MSB;
+		/* fall through */
+	case KBUFFER_TYPE_TIME_EXTEND:
 		extend = read_4(kbuf, data);
 		data += 4;
 		extend <<= TS_SHIFT;
 		extend += *delta;
-		*delta = extend;
+		*delta = extend | msb;
 		*length = 0;
 		break;
 
diff --git a/src/parse-filter.c b/src/parse-filter.c
index 5df1770..e448ee2 100644
--- a/src/parse-filter.c
+++ b/src/parse-filter.c
@@ -30,7 +30,7 @@
 	struct tep_event	*event;
 };
 
-static void show_error(char *error_buf, const char *fmt, ...)
+static void show_error(struct tep_handle *tep, char *error_buf, const char *fmt, ...)
 {
 	unsigned long long index;
 	const char *input;
@@ -38,8 +38,8 @@
 	int len;
 	int i;
 
-	input = get_input_buf();
-	index = get_input_buf_ptr();
+	input = get_input_buf(tep);
+	index = get_input_buf_ptr(tep);
 	len = input ? strlen(input) : 0;
 
 	if (len) {
@@ -57,20 +57,20 @@
 	va_end(ap);
 }
 
-static enum tep_event_type filter_read_token(char **tok)
+static enum tep_event_type filter_read_token(struct tep_handle *tep, char **tok)
 {
 	enum tep_event_type type;
 	char *token = NULL;
 
 	do {
 		free_token(token);
-		type = read_token(&token);
+		type = read_token(tep, &token);
 	} while (type == TEP_EVENT_NEWLINE || type == TEP_EVENT_SPACE);
 
 	/* If token is = or ! check to see if the next char is ~ */
 	if (token &&
 	    (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) &&
-	    peek_char() == '~') {
+	    peek_char(tep) == '~') {
 		/* append it */
 		*tok = malloc(3);
 		if (*tok == NULL) {
@@ -80,7 +80,7 @@
 		sprintf(*tok, "%c%c", *token, '~');
 		free_token(token);
 		/* Now remove the '~' from the buffer */
-		read_token(&token);
+		read_token(tep, &token);
 		free_token(token);
 	} else
 		*tok = token;
@@ -337,7 +337,7 @@
 
 	arg = allocate_arg();
 	if (arg == NULL) {
-		show_error(error_str, "failed to allocate filter arg");
+		show_error(event->tep, error_str, "failed to allocate filter arg");
 		return TEP_ERRNO__MEM_ALLOC_FAILED;
 	}
 
@@ -351,7 +351,7 @@
 		arg->value.str = strdup(token);
 		if (!arg->value.str) {
 			free_arg(arg);
-			show_error(error_str, "failed to allocate string filter arg");
+			show_error(event->tep, error_str, "failed to allocate string filter arg");
 			return TEP_ERRNO__MEM_ALLOC_FAILED;
 		}
 		break;
@@ -383,7 +383,7 @@
 		break;
 	default:
 		free_arg(arg);
-		show_error(error_str, "expected a value but found %s", token);
+		show_error(event->tep, error_str, "expected a value but found %s", token);
 		return TEP_ERRNO__UNEXPECTED_TYPE;
 	}
 	*parg = arg;
@@ -437,7 +437,8 @@
 }
 
 static enum tep_errno
-add_right(struct tep_filter_arg *op, struct tep_filter_arg *arg, char *error_str)
+add_right(struct tep_handle *tep, struct tep_filter_arg *op,
+		struct tep_filter_arg *arg, char *error_str)
 {
 	struct tep_filter_arg *left;
 	char *str;
@@ -468,7 +469,7 @@
 		case TEP_FILTER_ARG_FIELD:
 			break;
 		default:
-			show_error(error_str, "Illegal rvalue");
+			show_error(tep, error_str, "Illegal rvalue");
 			return TEP_ERRNO__ILLEGAL_RVALUE;
 		}
 
@@ -514,7 +515,7 @@
 
 			/* Left arg must be a field */
 			if (left->type != TEP_FILTER_ARG_FIELD) {
-				show_error(error_str,
+				show_error(tep, error_str,
 					   "Illegal lvalue for string comparison");
 				return TEP_ERRNO__ILLEGAL_LVALUE;
 			}
@@ -532,14 +533,14 @@
 			case TEP_FILTER_CMP_NOT_REGEX:
 				ret = regcomp(&op->str.reg, str, REG_ICASE|REG_NOSUB);
 				if (ret) {
-					show_error(error_str,
+					show_error(tep, error_str,
 						   "RegEx '%s' did not compute",
 						   str);
 					return TEP_ERRNO__INVALID_REGEX;
 				}
 				break;
 			default:
-				show_error(error_str,
+				show_error(tep, error_str,
 					   "Illegal comparison for string");
 				return TEP_ERRNO__ILLEGAL_STRING_CMP;
 			}
@@ -549,7 +550,7 @@
 			op->str.field = left->field.field;
 			op->str.val = strdup(str);
 			if (!op->str.val) {
-				show_error(error_str, "Failed to allocate string filter");
+				show_error(tep, error_str, "Failed to allocate string filter");
 				return TEP_ERRNO__MEM_ALLOC_FAILED;
 			}
 			/*
@@ -557,7 +558,7 @@
 			 */
 			op->str.buffer = malloc(op->str.field->size + 1);
 			if (!op->str.buffer) {
-				show_error(error_str, "Failed to allocate string filter");
+				show_error(tep, error_str, "Failed to allocate string filter");
 				return TEP_ERRNO__MEM_ALLOC_FAILED;
 			}
 			/* Null terminate this buffer */
@@ -575,7 +576,7 @@
 			switch (op->num.type) {
 			case TEP_FILTER_CMP_REGEX:
 			case TEP_FILTER_CMP_NOT_REGEX:
-				show_error(error_str,
+				show_error(tep, error_str,
 					   "Op not allowed with integers");
 				return TEP_ERRNO__ILLEGAL_INTEGER_CMP;
 
@@ -597,7 +598,7 @@
 	return 0;
 
  out_fail:
-	show_error(error_str, "Syntax error");
+	show_error(tep, error_str, "Syntax error");
 	return TEP_ERRNO__SYNTAX_ERROR;
 }
 
@@ -748,15 +749,16 @@
 };
 
 static enum tep_errno
-reparent_op_arg(struct tep_filter_arg *parent, struct tep_filter_arg *old_child,
-		struct tep_filter_arg *arg, char *error_str)
+reparent_op_arg(struct tep_handle *tep, struct tep_filter_arg *parent,
+		struct tep_filter_arg *old_child, struct tep_filter_arg *arg,
+		char *error_str)
 {
 	struct tep_filter_arg *other_child;
 	struct tep_filter_arg **ptr;
 
 	if (parent->type != TEP_FILTER_ARG_OP &&
 	    arg->type != TEP_FILTER_ARG_OP) {
-		show_error(error_str, "can not reparent other than OP");
+		show_error(tep, error_str, "can not reparent other than OP");
 		return TEP_ERRNO__REPARENT_NOT_OP;
 	}
 
@@ -768,7 +770,7 @@
 		ptr = &old_child->op.left;
 		other_child = old_child->op.right;
 	} else {
-		show_error(error_str, "Error in reparent op, find other child");
+		show_error(tep, error_str, "Error in reparent op, find other child");
 		return TEP_ERRNO__REPARENT_FAILED;
 	}
 
@@ -789,7 +791,7 @@
 	else if (parent->op.left == old_child)
 		ptr = &parent->op.left;
 	else {
-		show_error(error_str, "Error in reparent op");
+		show_error(tep, error_str, "Error in reparent op");
 		return TEP_ERRNO__REPARENT_FAILED;
 	}
 
@@ -800,8 +802,8 @@
 }
 
 /* Returns either filter_vals (success) or tep_errno (failfure) */
-static int test_arg(struct tep_filter_arg *parent, struct tep_filter_arg *arg,
-		    char *error_str)
+static int test_arg(struct tep_handle *tep, struct tep_filter_arg *parent,
+		struct tep_filter_arg *arg, char *error_str)
 {
 	int lval, rval;
 
@@ -818,47 +820,47 @@
 		return FILTER_VAL_NORM;
 
 	case TEP_FILTER_ARG_EXP:
-		lval = test_arg(arg, arg->exp.left, error_str);
+		lval = test_arg(tep, arg, arg->exp.left, error_str);
 		if (lval != FILTER_VAL_NORM)
 			return lval;
-		rval = test_arg(arg, arg->exp.right, error_str);
+		rval = test_arg(tep, arg, arg->exp.right, error_str);
 		if (rval != FILTER_VAL_NORM)
 			return rval;
 		return FILTER_VAL_NORM;
 
 	case TEP_FILTER_ARG_NUM:
-		lval = test_arg(arg, arg->num.left, error_str);
+		lval = test_arg(tep, arg, arg->num.left, error_str);
 		if (lval != FILTER_VAL_NORM)
 			return lval;
-		rval = test_arg(arg, arg->num.right, error_str);
+		rval = test_arg(tep, arg, arg->num.right, error_str);
 		if (rval != FILTER_VAL_NORM)
 			return rval;
 		return FILTER_VAL_NORM;
 
 	case TEP_FILTER_ARG_OP:
 		if (arg->op.type != TEP_FILTER_OP_NOT) {
-			lval = test_arg(arg, arg->op.left, error_str);
+			lval = test_arg(tep, arg, arg->op.left, error_str);
 			switch (lval) {
 			case FILTER_VAL_NORM:
 				break;
 			case FILTER_VAL_TRUE:
 				if (arg->op.type == TEP_FILTER_OP_OR)
 					return FILTER_VAL_TRUE;
-				rval = test_arg(arg, arg->op.right, error_str);
+				rval = test_arg(tep, arg, arg->op.right, error_str);
 				if (rval != FILTER_VAL_NORM)
 					return rval;
 
-				return reparent_op_arg(parent, arg, arg->op.right,
+				return reparent_op_arg(tep, parent, arg, arg->op.right,
 						       error_str);
 
 			case FILTER_VAL_FALSE:
 				if (arg->op.type == TEP_FILTER_OP_AND)
 					return FILTER_VAL_FALSE;
-				rval = test_arg(arg, arg->op.right, error_str);
+				rval = test_arg(tep, arg, arg->op.right, error_str);
 				if (rval != FILTER_VAL_NORM)
 					return rval;
 
-				return reparent_op_arg(parent, arg, arg->op.right,
+				return reparent_op_arg(tep, parent, arg, arg->op.right,
 						       error_str);
 
 			default:
@@ -866,7 +868,7 @@
 			}
 		}
 
-		rval = test_arg(arg, arg->op.right, error_str);
+		rval = test_arg(tep, arg, arg->op.right, error_str);
 		switch (rval) {
 		case FILTER_VAL_NORM:
 		default:
@@ -878,7 +880,7 @@
 			if (arg->op.type == TEP_FILTER_OP_NOT)
 				return FILTER_VAL_FALSE;
 
-			return reparent_op_arg(parent, arg, arg->op.left,
+			return reparent_op_arg(tep, parent, arg, arg->op.left,
 					       error_str);
 
 		case FILTER_VAL_FALSE:
@@ -887,25 +889,25 @@
 			if (arg->op.type == TEP_FILTER_OP_NOT)
 				return FILTER_VAL_TRUE;
 
-			return reparent_op_arg(parent, arg, arg->op.left,
+			return reparent_op_arg(tep, parent, arg, arg->op.left,
 					       error_str);
 		}
 
 		return rval;
 	default:
-		show_error(error_str, "bad arg in filter tree");
+		show_error(tep, error_str, "bad arg in filter tree");
 		return TEP_ERRNO__BAD_FILTER_ARG;
 	}
 	return FILTER_VAL_NORM;
 }
 
 /* Remove any unknown event fields */
-static int collapse_tree(struct tep_filter_arg *arg,
+static int collapse_tree(struct tep_handle *tep, struct tep_filter_arg *arg,
 			 struct tep_filter_arg **arg_collapsed, char *error_str)
 {
 	int ret;
 
-	ret = test_arg(arg, arg, error_str);
+	ret = test_arg(tep, arg, arg, error_str);
 	switch (ret) {
 	case FILTER_VAL_NORM:
 		break;
@@ -918,7 +920,7 @@
 			arg->type = TEP_FILTER_ARG_BOOLEAN;
 			arg->boolean.value = ret == FILTER_VAL_TRUE;
 		} else {
-			show_error(error_str, "Failed to allocate filter arg");
+			show_error(tep, error_str, "Failed to allocate filter arg");
 			ret = TEP_ERRNO__MEM_ALLOC_FAILED;
 		}
 		break;
@@ -954,7 +956,7 @@
 
 	do {
 		free(token);
-		type = filter_read_token(&token);
+		type = filter_read_token(event->tep, &token);
 		switch (type) {
 		case TEP_EVENT_SQUOTE:
 		case TEP_EVENT_DQUOTE:
@@ -965,7 +967,7 @@
 			if (!left_item)
 				left_item = arg;
 			else if (current_exp) {
-				ret = add_right(current_exp, arg, error_str);
+				ret = add_right(event->tep, current_exp, arg, error_str);
 				if (ret < 0)
 					goto fail;
 				left_item = NULL;
@@ -985,20 +987,20 @@
 
 		case TEP_EVENT_DELIM:
 			if (*token == ',') {
-				show_error(error_str, "Illegal token ','");
+				show_error(event->tep, error_str, "Illegal token ','");
 				ret = TEP_ERRNO__ILLEGAL_TOKEN;
 				goto fail;
 			}
 
 			if (*token == '(') {
 				if (left_item) {
-					show_error(error_str,
+					show_error(event->tep, error_str,
 						   "Open paren can not come after item");
 					ret = TEP_ERRNO__INVALID_PAREN;
 					goto fail;
 				}
 				if (current_exp) {
-					show_error(error_str,
+					show_error(event->tep, error_str,
 						   "Open paren can not come after expression");
 					ret = TEP_ERRNO__INVALID_PAREN;
 					goto fail;
@@ -1007,7 +1009,7 @@
 				ret = process_filter(event, &arg, error_str, 0);
 				if (ret != TEP_ERRNO__UNBALANCED_PAREN) {
 					if (ret == 0) {
-						show_error(error_str,
+						show_error(event->tep, error_str,
 							   "Unbalanced number of '('");
 						ret = TEP_ERRNO__UNBALANCED_PAREN;
 					}
@@ -1024,7 +1026,7 @@
 				}
 
 				if (current_op)
-					ret = add_right(current_op, arg, error_str);
+					ret = add_right(event->tep, current_op, arg, error_str);
 				else
 					current_exp = arg;
 
@@ -1071,7 +1073,7 @@
 					goto fail_syntax;
 				break;
 			case OP_NONE:
-				show_error(error_str,
+				show_error(event->tep, error_str,
 					   "Unknown op token %s", token);
 				ret = TEP_ERRNO__UNKNOWN_TOKEN;
 				goto fail;
@@ -1096,14 +1098,14 @@
 				if (arg == NULL)
 					goto fail_alloc;
 				if (current_op)
-					ret = add_right(current_op, arg, error_str);
+					ret = add_right(event->tep, current_op, arg, error_str);
 				if (ret < 0)
 					goto fail;
 				current_exp = arg;
 				ret = process_filter(event, &arg, error_str, 1);
 				if (ret < 0)
 					goto fail;
-				ret = add_right(current_exp, arg, error_str);
+				ret = add_right(event->tep, current_exp, arg, error_str);
 				if (ret < 0)
 					goto fail;
 				break;
@@ -1118,7 +1120,7 @@
 					goto fail_alloc;
 
 				if (current_op)
-					ret = add_right(current_op, arg, error_str);
+					ret = add_right(event->tep,current_op, arg, error_str);
 				if (ret < 0)
 					goto fail;
 				ret = add_left(arg, left_item);
@@ -1150,7 +1152,7 @@
 	if (!current_op)
 		current_op = current_exp;
 
-	ret = collapse_tree(current_op, parg, error_str);
+	ret = collapse_tree(event->tep, current_op, parg, error_str);
 	/* collapse_tree() may free current_op, and updates parg accordingly */
 	current_op = NULL;
 	if (ret < 0)
@@ -1160,11 +1162,11 @@
 	return 0;
 
  fail_alloc:
-	show_error(error_str, "failed to allocate filter arg");
+	show_error(event->tep, error_str, "failed to allocate filter arg");
 	ret = TEP_ERRNO__MEM_ALLOC_FAILED;
 	goto fail;
  fail_syntax:
-	show_error(error_str, "Syntax error");
+	show_error(event->tep, error_str, "Syntax error");
 	ret = TEP_ERRNO__SYNTAX_ERROR;
  fail:
 	free_arg(current_op);
@@ -1180,7 +1182,7 @@
 {
 	int ret;
 
-	init_input_buf(filter_str, strlen(filter_str));
+	init_input_buf(event->tep, filter_str, strlen(filter_str));
 
 	ret = process_filter(event, parg, error_str, 0);
 	if (ret < 0)
@@ -1238,7 +1240,7 @@
 static void filter_init_error_buf(struct tep_event_filter *filter)
 {
 	/* clear buffer to reset show error */
-	init_input_buf("", 0);
+	init_input_buf(filter->tep, "", 0);
 	filter->error_buffer[0] = '\0';
 }
 
diff --git a/src/parse-utils.c b/src/parse-utils.c
index 09059ed..9c38e1e 100644
--- a/src/parse-utils.c
+++ b/src/parse-utils.c
@@ -11,6 +11,7 @@
 
 #include "event-utils.h"
 #include "event-parse.h"
+#include "kbuffer.h"
 
 #define __weak __attribute__((weak))
 
@@ -122,3 +123,29 @@
 }
 
 void vpr_stat(const char *fmt, va_list ap) __attribute__((weak, alias("__vpr_stat")));
+
+/**
+ * tep_kbuffer - return an allocated kbuffer that can be used for the tep handle
+ * @tep: the handle that will work with the kbuffer descriptor
+ *
+ * Allocates and returns a new kbuffer.
+ * The return must be freed by kbuffer_free();
+ */
+struct kbuffer *tep_kbuffer(struct tep_handle *tep)
+{
+	enum kbuffer_endian endian;
+	int long_size;
+
+	long_size = tep_get_long_size(tep);
+	if (long_size == 8)
+		long_size = KBUFFER_LSIZE_8;
+	else
+		long_size = KBUFFER_LSIZE_4;
+
+	if (tep_is_file_bigendian(tep))
+		endian = KBUFFER_ENDIAN_BIG;
+	else
+		endian = KBUFFER_ENDIAN_LITTLE;
+
+	return kbuffer_alloc(long_size, endian);
+}
diff --git a/utest/.gitignore b/utest/.gitignore
new file mode 100644
index 0000000..3620cd0
--- /dev/null
+++ b/utest/.gitignore
@@ -0,0 +1 @@
+trace-utest
diff --git a/utest/traceevent-utest.c b/utest/traceevent-utest.c
index 99900de..ebd5eb9 100644
--- a/utest/traceevent-utest.c
+++ b/utest/traceevent-utest.c
@@ -100,6 +100,126 @@
 };
 static void *dyn_str_old_event_data = (void *)dyn_str_old_data;
 
+#define CPUMASK_EVENT_SYSTEM "ipi"
+#define CPUMASK_EVENT_FIELD  "cpumask"
+static const char cpumask_event_format[] =
+	"name: ipi_send_cpumask\n"
+	"ID: 3\n"
+	"format:\n"
+	"\tfield:unsigned short common_type;\toffset:0;\tsize:2;\n"
+	"\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\n"
+	"\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\n"
+	"\tfield:int common_pid;\toffset:4;\tsize:4;\n"
+	"\n"
+	"\tfield:__data_loc cpumask_t *[] cpumask;\toffset:8;\tsize:4;\tsigned:0;\n"
+	"\n"
+	"print fmt: \"cpumask=%s\", __get_cpumask(cpumask)\n";
+
+/* Mind the endianness! */
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define DECL_CPUMASK_EVENT_DATA(name, args...)			\
+	static char cpumask_##name##_event_data[] = {		\
+	/* common type */		3, 0x00,                \
+	/* common flags */		0x00,                   \
+	/* common_preempt_count */	0x00,                   \
+	/* common_pid */		0x00, 0x00, 0x00, 0x00, \
+	/* [offset, size] */            16, 0x00, 8, 0x00,      \
+	/* padding */			0x00, 0x00, 0x00, 0x00, \
+	/* cpumask */                   args,                   \
+}
+#else
+#define DECL_CPUMASK_EVENT_DATA(name, args...)			\
+static char cpumask_##name##_event_data[] = {                       \
+	/* common type */		0x00, 3,                \
+	/* common flags */		0x00,                   \
+	/* common_preempt_count */	0x00,                   \
+	/* common_pid */		0x00, 0x00, 0x00, 0x00, \
+	/* [offset, size] */            0x00, 8, 0x00, 16,      \
+	/* padding */			0x00, 0x00, 0x00, 0x00, \
+	/* cpumask */                   args,                   \
+}
+#endif
+
+#define SIZEOF_LONG0_FMT "[FAILED TO PARSE] s4=0 u4=0 s8=0 u8=0x0"
+#define SIZEOF_LONG4_FMT "int=4 unsigned=4 unsigned int=4 long=4 unsigned long=4 long long=8 unsigned long long=8 s4=4 u4=4 s8=8 u8=8"
+#define SIZEOF_LONG8_FMT "int=4 unsigned=4 unsigned int=4 long=8 unsigned long=8 long long=8 unsigned long long=8 s4=4 u4=4 s8=8 u8=8"
+
+static const char size_of_event[] =
+	"name: sizeof_event\n"
+	"ID: 23\n"
+	"format:\n"
+	"\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n"
+	"\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n"
+	"\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\tsigned:0;\n"
+	"\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n"
+	"\n"
+        "\tfield:int s4;\toffset:8;\tsize:4;\tsigned:1;\n"
+        "\tfield:unsigned int u4;\toffset:12;\tsize:4;\tsigned:0;\n"
+        "\tfield:long long s8;\toffset:16;\tsize:8;\tsigned:1;\n"
+        "\tfield:unsigned long long u8;\toffset:24;\tsize:8;\tsigned:0;\n"
+	"\n"
+	"print fmt: \"int=%d unsigned=%d unsigned int=%d long=%d unsigned long=%d long long=%d unsigned long long=%d s4=%d u4=%d s8=%d u8=%d\", "
+	"sizeof(int), sizeof(unsigned), sizeof(unsigned int), sizeof(long), sizeof(unsigned long), "
+	"sizeof(long long), sizeof(unsigned long long), sizeof(REC->s4), "
+	"sizeof(REC->u4), sizeof(REC->s8), sizeof(REC->u8))\n";
+static char sizeof_data[] = {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+	/* common type */		23, 0x00,
+#else
+	/* common type */		0x00, 23
+#endif
+	/* common flags */		0x00,
+	/* common_preempt_count */	0x00,
+	/* common_pid */		0x00, 0x00, 0x00, 0x00,
+	/* irq */			0x00, 0x00, 0x00, 0x00,
+
+	/* s4 */			0x00, 0x00, 0x00, 0x00,
+	/* u4 */			0x00, 0x00, 0x00, 0x00,
+	/* s8 */			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* u8 */			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+static void *sizeof_event_data = (void *)sizeof_data;
+
+DECL_CPUMASK_EVENT_DATA(full, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
+#define CPUMASK_FULL     "ARRAY[ff, ff, ff, ff, ff, ff, ff, ff]"
+#define CPUMASK_FULL_FMT "cpumask=0-63"
+
+DECL_CPUMASK_EVENT_DATA(empty, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+#define CPUMASK_EMPTY     "ARRAY[00, 00, 00, 00, 00, 00, 00, 00]"
+#define CPUMASK_EMPTY_FMT "cpumask="
+
+DECL_CPUMASK_EVENT_DATA(half, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55);
+#define CPUMASK_HALF     "ARRAY[55, 55, 55, 55, 55, 55, 55, 55]"
+#define CPUMASK_HALF_FMT "cpumask=0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62"
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+DECL_CPUMASK_EVENT_DATA(bytep1, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
+#define CPUMASK_BYTEP1     "ARRAY[01, 80, 00, 00, 00, 00, 00, 00]"
+#define CPUMASK_BYTEP1_FMT "cpumask=0,15"
+
+DECL_CPUMASK_EVENT_DATA(bytep2, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00);
+#define CPUMASK_BYTEP2     "ARRAY[01, 00, 80, 00, 00, 00, 00, 00]"
+#define CPUMASK_BYTEP2_FMT "cpumask=0,23"
+
+DECL_CPUMASK_EVENT_DATA(bytepn, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80);
+#define CPUMASK_BYTEPN     "ARRAY[01, 00, 00, 00, 00, 00, 00, 80]"
+#define CPUMASK_BYTEPN_FMT "cpumask=0,63"
+
+#else
+
+DECL_CPUMASK_EVENT_DATA(bytep1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01);
+#define CPUMASK_BYTEP1     "ARRAY[00, 00, 00, 00, 00, 00, 80, 01]"
+#define CPUMASK_BYTEP1_FMT "cpumask=0,15"
+
+DECL_CPUMASK_EVENT_DATA(bytep2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x01);
+#define CPUMASK_BYTEP2     "ARRAY[00, 00, 00, 00, 00, 80, 00, 01]"
+#define CPUMASK_BYTEP2_FMT "cpumask=0,23"
+
+DECL_CPUMASK_EVENT_DATA(bytepn, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01);
+#define CPUMASK_BYTEPN     "ARRAY[80, 00, 00, 00, 00, 00, 80, 01]"
+#define CPUMASK_BYTEPN_FMT "cpumask=0,63"
+#endif
+
 static struct tep_handle *test_tep;
 static struct trace_seq *test_seq;
 static struct trace_seq seq_storage;
@@ -139,6 +259,125 @@
 	parse_dyn_str(dyn_str_old_event, dyn_str_old_event_data, sizeof(dyn_str_old_data));
 }
 
+static void parse_cpumask(const char *format, void *data, int size,
+			  const char* expected_raw, const char* expected)
+{
+	struct tep_format_field *field;
+	struct tep_event *event;
+	struct tep_record record;
+
+	record.data = data;
+	record.size = size;
+
+	CU_TEST(tep_parse_format(test_tep, &event,
+				 format, strlen(format),
+				 CPUMASK_EVENT_SYSTEM) == TEP_ERRNO__SUCCESS);
+
+	field = tep_find_any_field(event, CPUMASK_EVENT_FIELD);
+	CU_TEST(field != NULL);
+
+	trace_seq_reset(test_seq);
+	tep_print_field_content(test_seq, data, size, field);
+	CU_TEST(strcmp(test_seq->buffer, expected_raw) == 0);
+
+	trace_seq_reset(test_seq);
+	tep_print_event(test_tep, test_seq, &record, "%s", TEP_PRINT_INFO);
+	trace_seq_do_printf(test_seq);
+	CU_TEST(strcmp(test_seq->buffer, expected) == 0);
+}
+
+static void test_parse_cpumask_full(void)
+{
+	parse_cpumask(cpumask_event_format,
+		      cpumask_full_event_data, sizeof(cpumask_full_event_data),
+		      CPUMASK_FULL, CPUMASK_FULL_FMT);
+}
+
+static void test_parse_cpumask_empty(void)
+{
+	parse_cpumask(cpumask_event_format,
+		      cpumask_empty_event_data, sizeof(cpumask_empty_event_data),
+		      CPUMASK_EMPTY, CPUMASK_EMPTY_FMT);
+}
+
+static void test_parse_cpumask_half(void)
+{
+	parse_cpumask(cpumask_event_format,
+		      cpumask_half_event_data, sizeof(cpumask_half_event_data),
+		      CPUMASK_HALF, CPUMASK_HALF_FMT);
+}
+
+static void test_parse_cpumask_bytep1(void)
+{
+	parse_cpumask(cpumask_event_format,
+		      cpumask_bytep1_event_data, sizeof(cpumask_bytep1_event_data),
+		      CPUMASK_BYTEP1, CPUMASK_BYTEP1_FMT);
+}
+
+static void test_parse_cpumask_bytep2(void)
+{
+	parse_cpumask(cpumask_event_format,
+		      cpumask_bytep2_event_data, sizeof(cpumask_bytep2_event_data),
+		      CPUMASK_BYTEP2, CPUMASK_BYTEP2_FMT);
+}
+
+static void test_parse_cpumask_bytepn(void)
+{
+	parse_cpumask(cpumask_event_format,
+		      cpumask_bytepn_event_data, sizeof(cpumask_bytepn_event_data),
+		      CPUMASK_BYTEPN, CPUMASK_BYTEPN_FMT);
+}
+
+static void test_parse_sizeof(int long_size, int value, const char *system,
+			      const char *test_str)
+{
+	struct tep_event *event;
+	struct tep_record record;
+	char *sizeof_event;
+	char *p;
+
+	tep_set_long_size(test_tep, long_size);
+
+	record.data = sizeof_event_data;
+	record.size = sizeof(sizeof_data);
+
+	sizeof_event = strdup(size_of_event);
+	CU_TEST(sizeof_event != NULL);
+
+	/* Set a new id */
+	p = strstr(sizeof_event, "ID: 2");
+	p[5] = '0' + value;
+
+	/* Handles endianess */
+	*(unsigned short *)sizeof_data = 20 + value;
+
+	CU_TEST(tep_parse_format(test_tep, &event, sizeof_event,
+				 strlen(sizeof_event),
+				 system) == TEP_ERRNO__SUCCESS);
+
+	trace_seq_reset(test_seq);
+	tep_print_event(test_tep, test_seq, &record, "%s", TEP_PRINT_INFO);
+	trace_seq_do_printf(test_seq);
+	CU_TEST(strcmp(test_seq->buffer, test_str) == 0);
+
+	free(sizeof_event);
+}
+
+static void test_parse_sizeof8(void)
+{
+	test_parse_sizeof(8, 3, "sizeof8", SIZEOF_LONG8_FMT);
+}
+
+static void test_parse_sizeof4(void)
+{
+	test_parse_sizeof(4, 4, "sizeof4", SIZEOF_LONG4_FMT);
+}
+
+static void test_parse_sizeof_undef(void)
+{
+	test_parse_sizeof(0, 5, "sizeof_undef", SIZEOF_LONG0_FMT);
+}
+
 static int test_suite_destroy(void)
 {
 	tep_free(test_tep);
@@ -169,4 +408,22 @@
 		    test_parse_dyn_str_event);
 	CU_add_test(suite, "parse old dynamic string event",
 		    test_parse_dyn_str_old_event);
+	CU_add_test(suite, "parse full cpumask",
+		    test_parse_cpumask_full);
+	CU_add_test(suite, "parse empty cpumask",
+		    test_parse_cpumask_empty);
+	CU_add_test(suite, "parse half-filled cpumask",
+		    test_parse_cpumask_half);
+	CU_add_test(suite, "parse cpumask spanning 2 bytes",
+		    test_parse_cpumask_bytep1);
+	CU_add_test(suite, "parse cpumask spanning 3 bytes",
+		    test_parse_cpumask_bytep2);
+	CU_add_test(suite, "parse cpumask spanning all bytes",
+		    test_parse_cpumask_bytepn);
+	CU_add_test(suite, "parse sizeof() 8byte values",
+		    test_parse_sizeof8);
+	CU_add_test(suite, "parse sizeof() 4byte values",
+		    test_parse_sizeof4);
+	CU_add_test(suite, "parse sizeof() no long size defined",
+		    test_parse_sizeof_undef);
 }