Bug#867440: trace-cmd: diff for NMU version 2.6.1-0.1

Message ID 20170913122212.346624bgypdkkrpm@breakpoint.cc
State New
Headers show
Series
  • Bug#867440: trace-cmd: diff for NMU version 2.6.1-0.1
Related show

Commit Message

Sebastian Andrzej Siewior Sept. 13, 2017, 12:22 p.m.
Control: tags 867440 + patch
Control: tags 867440 + pending

Dear maintainer,

I've prepared an NMU for trace-cmd (versioned as 2.6.1-0.1) and
uploaded it to DELAYED/5. Please feel free to tell me if I
should delay it longer.

Regards.

Patch

diff -Nru trace-cmd-2.6/COPYING.LIB trace-cmd-2.6.1/COPYING.LIB
--- trace-cmd-2.6/COPYING.LIB	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/COPYING.LIB	2017-05-02 19:35:16.000000000 +0200
@@ -3,7 +3,7 @@ 
                        Version 2.1, February 1999
 
  Copyright (C) 1991, 1999 Free Software Foundation, Inc.
-     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
diff -Nru trace-cmd-2.6/cpu.h trace-cmd-2.6.1/cpu.h
--- trace-cmd-2.6/cpu.h	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/cpu.h	2017-05-02 19:35:16.000000000 +0200
@@ -20,45 +20,48 @@ 
 #ifndef _CPU_H
 #define _CPU_H
 
-static inline int cpu_isset(guint64 *cpu_mask, gint cpu)
+#include <stdint.h>
+#include <stdbool.h>
+
+static inline int cpu_isset(uint64_t *cpu_mask, int cpu)
 {
-	guint64 mask;
+	uint64_t mask;
 
 	mask = *(cpu_mask + (cpu >> 6));
 
 	return mask & (1ULL << (cpu & ((1ULL << 6) - 1)));
 }
 
-static inline gboolean cpu_allset(guint64 *cpu_mask, gint max_cpus)
+static inline bool cpu_allset(uint64_t *cpu_mask, int max_cpus)
 {
-	gint cpu;
+	int cpu;
 
 	for (cpu = 0; cpu < max_cpus; cpu++) {
 		if (!cpu_isset(cpu_mask, cpu))
-			return FALSE;
+			return false;
 	}
-	return TRUE;
+	return true;
 }
 
-static inline void cpu_set(guint64 *cpu_mask, gint cpu)
+static inline void cpu_set(uint64_t *cpu_mask, int cpu)
 {
-	guint64 *mask;
+	uint64_t *mask;
 
 	mask = cpu_mask + (cpu >> 6);
 	*mask |= (1ULL << (cpu & ((1ULL << 6) - 1)));
 }
 
-static inline void cpu_clear(guint64 *cpu_mask, gint cpu)
+static inline void cpu_clear(uint64_t *cpu_mask, int cpu)
 {
-	guint64 *mask;
+	uint64_t *mask;
 
 	mask = cpu_mask + (cpu >> 6);
 	*mask &= ~(1ULL << (cpu & ((1ULL << 6) - 1)));
 }
 
-static inline void set_cpus(guint64 *cpu_mask, gint cpus)
+static inline void set_cpus(uint64_t *cpu_mask, int cpus)
 {
-	gint idx;
+	int idx;
 
 	for (idx = 0; idx < (cpus >> 6); idx++) {
 		*(cpu_mask + idx) = -1ULL;
@@ -67,22 +70,22 @@ 
 	*(cpu_mask) = (1ULL << (cpus & ((1ULL << 6) - 1))) - 1;
 }
 
-static inline gboolean cpus_equal(guint64 *a_mask, guint64 *b_mask,
-				  gint cpus)
+static inline bool cpus_equal(uint64_t *a_mask, uint64_t *b_mask,
+				  int cpus)
 {
-	gint idx;
+	int idx;
 
 	for (idx = 0; idx < (cpus >> 6) + 1; idx++) {
 		if (*(a_mask + idx) != *(b_mask + idx))
-			return FALSE;
+			return false;
 	}
-	return TRUE;
+	return true;
 }
 
 /* Hamming weight */
-static inline guint hweight(guint mask)
+static inline unsigned int hweight(unsigned int mask)
 {
-	guint64 w = mask;
+	uint64_t w = mask;
 
 	w -= (w >> 1) & 0x5555555555555555ul;
 	w =  (w & 0x3333333333333333ul) + ((w >> 2) & 0x3333333333333333ul);
@@ -90,10 +93,10 @@ 
 	return (w * 0x0101010101010101ul) >> 56;
 }
 
-static inline guint cpu_weight(guint64 *cpu_mask, guint cpus)
+static inline unsigned int cpu_weight(uint64_t *cpu_mask, unsigned int cpus)
 {
-	guint weight = 0;
-	gint idx;
+	unsigned int weight = 0;
+	int idx;
 
 	for (idx = 0; idx < (cpus >> 6) + 1; idx++)
 		weight += hweight(*(cpu_mask + idx));
diff -Nru trace-cmd-2.6/ctracecmd.i trace-cmd-2.6.1/ctracecmd.i
--- trace-cmd-2.6/ctracecmd.i	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/ctracecmd.i	2017-05-02 19:35:16.000000000 +0200
@@ -15,6 +15,7 @@ 
 
 %{
 #include "trace-cmd.h"
+#include "event-utils.h"
 %}
 
 
diff -Nru trace-cmd-2.6/debian/changelog trace-cmd-2.6.1/debian/changelog
--- trace-cmd-2.6/debian/changelog	2016-07-17 14:40:56.000000000 +0200
+++ trace-cmd-2.6.1/debian/changelog	2017-09-12 21:50:27.000000000 +0200
@@ -1,3 +1,11 @@ 
+trace-cmd (2.6.1-0.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * Update to v2.6.1:
+    Fixs segfault while processing certain trace files (Closes: #867440).
+
+ -- Sebastian Andrzej Siewior <sebastian@breakpoint.cc>  Tue, 12 Sep 2017 21:50:27 +0200
+
 trace-cmd (2.6-0.1) unstable; urgency=medium
 
   * Non-maintainer upload.
diff -Nru trace-cmd-2.6/Documentation/trace-cmd-record.1.txt trace-cmd-2.6.1/Documentation/trace-cmd-record.1.txt
--- trace-cmd-2.6/Documentation/trace-cmd-record.1.txt	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/Documentation/trace-cmd-record.1.txt	2017-05-02 19:35:16.000000000 +0200
@@ -263,6 +263,11 @@ 
     timestamp to gettimeofday which will allow wall time output from the
     timestamps reading the created 'trace.dat' file.
 
+*--max-graph-depth* 'depth'::
+    Set the maximum depth the function_graph tracer will trace into a function.
+    A value of one will only show where userspace enters the kernel but not any
+    functions called in the kernel. The default is zero, which means no limit.
+
 *--profile*::
     With the *--profile* option, "trace-cmd" will enable tracing that can
     be used with trace-cmd-report(1) --profile option. If a tracer *-p* is
@@ -286,6 +291,14 @@ 
 
     See trace-cmd-profile(1) for format.
 
+*--ts-offset offset*::
+    Add an offset for the timestamp in the trace.dat file. This will add a
+    offset option into the trace.dat file such that a trace-cmd report will
+    offset all the timestamps of the events by the given offset. The offset
+    is in raw units. That is, if the event timestamps are in nanoseconds
+    the offset will also be in nanoseconds even if the displayed units are
+    in microseconds.
+
 *--stderr*::
     Have output go to stderr instead of stdout, but the output of the command
     executed will not be changed. This is useful if you want to monitor the
diff -Nru trace-cmd-2.6/Documentation/trace-cmd-report.1.txt trace-cmd-2.6.1/Documentation/trace-cmd-report.1.txt
--- trace-cmd-2.6/Documentation/trace-cmd-report.1.txt	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/Documentation/trace-cmd-report.1.txt	2017-05-02 19:35:16.000000000 +0200
@@ -131,6 +131,17 @@ 
     -F '.*:COMM != "trace-cmd"'
 ------------------------------------------
 
+*-I*::
+    Do not print events where the HARDIRQ latency flag is set.
+    This will filter out most events that are from interrupt context.
+    Note, it may not filter out function traced functions that are
+    in interrupt context but were called before the kernel "in interrupt"
+    flag was set.
+
+*-S*::
+    Do not print events where the SOFTIRQ latency flag is set.
+    This will filter out most events that are from soft interrupt context.
+
 *-v*::
     This causes the following filters of *-F* to filter out the matching
     events.
@@ -237,6 +248,48 @@ 
     If the trace.dat file recorded uname during the run, this will retrieve that
     information.
 
+*--ts-offset* offset::
+    Add (or subtract if negative) an offset for all timestamps of the previous
+    data file specified with *-i*. This is useful to merge sort multiple trace.dat
+    files where the difference in the timestamp is known. For example if a trace
+    is done on a virtual guest, and another trace is done on the host. If the
+    host timestamp is 1000 units ahead of the guest, the following can be done:
+
+    trace-cmd report -i host.dat --ts-offset -1000 -i guest.dat
+
+    This will subtract 1000 timestamp units from all the host events as it merges
+    with the guest.dat events. Note, the units is for the raw units recorded in
+    the trace. If the units are nanoseconds, the addition (or subtraction) from
+    the offset will be nanoseconds even if the displayed units are microseconds.
+
+*--ts2secs* HZ::
+    Convert the current clock source into a second (nanosecond resolution)
+    output. When using clocks like x86-tsc, if the frequency is known,
+    by passing in the clock frequency, this will convert the time to seconds.
+
+    This option affects any trace.dat file given with *-i* proceeding it.
+    If this option comes before any *-i* option, then that value becomes
+    the default conversion for all other trace.dat files. If another
+    --ts2secs option appears after a *-i* trace.dat file, than that option
+    will override the default value.
+
+    Example: On a 3.4 GHz machine
+
+      trace-cmd record -p function -C x86-tsc
+
+      trace-cmd report --ts2ns 3400000000
+
+     The report will convert the cycles timestamps into a readable second
+     display. The default display resolution is microseconds, unless *-t*
+     is used.
+
+     The value of --ts-offset must still be in the raw timestamp units, even
+     with this option. The offset will be converted as well.
+
+*--ts-diff*::
+     Show the time differences between events. The difference will appear in
+     parenthesis just after the timestamp.
+
 EXAMPLES
 --------
 
diff -Nru trace-cmd-2.6/event-parse.c trace-cmd-2.6.1/event-parse.c
--- trace-cmd-2.6/event-parse.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/event-parse.c	2017-05-02 19:35:16.000000000 +0200
@@ -23,6 +23,7 @@ 
  *  Frederic Weisbecker gave his permission to relicense the code to
  *  the Lesser General Public License.
  */
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -31,8 +32,10 @@ 
 #include <errno.h>
 #include <stdint.h>
 #include <limits.h>
+#include <linux/string.h>
+#include <linux/time64.h>
 
-#include <netinet/ip6.h>
+#include <netinet/in.h>
 #include "event-parse.h"
 #include "event-utils.h"
 
@@ -418,7 +421,7 @@ 
 }
 
 static struct func_map *
-find_func(struct pevent *pevent, unsigned long long addr)
+__find_func(struct pevent *pevent, unsigned long long addr)
 {
 	struct func_map *func;
 	struct func_map key;
@@ -434,6 +437,71 @@ 
 	return func;
 }
 
+struct func_resolver {
+	pevent_func_resolver_t *func;
+	void		       *priv;
+	struct func_map	       map;
+};
+
+/**
+ * pevent_set_function_resolver - set an alternative function resolver
+ * @pevent: handle for the pevent
+ * @resolver: function to be used
+ * @priv: resolver function private state.
+ *
+ * Some tools may have already a way to resolve kernel functions, allow them to
+ * keep using it instead of duplicating all the entries inside
+ * pevent->funclist.
+ */
+int pevent_set_function_resolver(struct pevent *pevent,
+				 pevent_func_resolver_t *func, void *priv)
+{
+	struct func_resolver *resolver = malloc(sizeof(*resolver));
+
+	if (resolver == NULL)
+		return -1;
+
+	resolver->func = func;
+	resolver->priv = priv;
+
+	free(pevent->func_resolver);
+	pevent->func_resolver = resolver;
+
+	return 0;
+}
+
+/**
+ * pevent_reset_function_resolver - reset alternative function resolver
+ * @pevent: handle for the pevent
+ *
+ * Stop using whatever alternative resolver was set, use the default
+ * one instead.
+ */
+void pevent_reset_function_resolver(struct pevent *pevent)
+{
+	free(pevent->func_resolver);
+	pevent->func_resolver = NULL;
+}
+
+static struct func_map *
+find_func(struct pevent *pevent, unsigned long long addr)
+{
+	struct func_map *map;
+
+	if (!pevent->func_resolver)
+		return __find_func(pevent, addr);
+
+	map = &pevent->func_resolver->map;
+	map->mod  = NULL;
+	map->addr = addr;
+	map->func = pevent->func_resolver->func(pevent->func_resolver->priv,
+						&map->addr, &map->mod);
+	if (map->func == NULL)
+		return NULL;
+
+	return map;
+}
+
 /**
  * pevent_find_function - find a function by a given address
  * @pevent: handle for the pevent
@@ -783,6 +851,7 @@ 
 		free(arg->bitmask.bitmask);
 		break;
 	case PRINT_DYNAMIC_ARRAY:
+	case PRINT_DYNAMIC_ARRAY_LEN:
 		free(arg->dynarray.index);
 		break;
 	case PRINT_OP:
@@ -1680,6 +1749,9 @@ 
 	type = process_arg(event, left, &token);
 
  again:
+	if (type == EVENT_ERROR)
+		goto out_free;
+
 	/* Handle other operations in the arguments */
 	if (type == EVENT_OP && strcmp(token, ":") != 0) {
 		type = process_op(event, left, &token);
@@ -1882,6 +1954,7 @@ 
 		   strcmp(token, "*") == 0 ||
 		   strcmp(token, "^") == 0 ||
 		   strcmp(token, "/") == 0 ||
+		   strcmp(token, "%") == 0 ||
 		   strcmp(token, "<") == 0 ||
 		   strcmp(token, ">") == 0 ||
 		   strcmp(token, "<=") == 0 ||
@@ -1939,6 +2012,12 @@ 
 			goto out_warn_free;
 
 		type = process_arg_token(event, right, tok, type);
+		if (type == EVENT_ERROR) {
+			free_arg(right);
+			/* token was freed in process_arg_token() via *tok */
+			token = NULL;
+			goto out_free;
+		}
 
 		if (right->type == PRINT_OP &&
 		    get_op_prio(arg->op.op) < get_op_prio(right->op.op)) {
@@ -2322,6 +2401,12 @@ 
 				break;
 			*val = left + right;
 			break;
+		case '~':
+			ret = arg_num_eval(arg->op.right, &right);
+			if (!ret)
+				break;
+			*val = ~right;
+			break;
 		default:
 			do_warning("unknown op '%s'", arg->op.op);
 			ret = 0;
@@ -2658,6 +2743,42 @@ 
 }
 
 static enum event_type
+process_dynamic_array_len(struct event_format *event, struct print_arg *arg,
+			  char **tok)
+{
+	struct format_field *field;
+	enum event_type type;
+	char *token;
+
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto out_free;
+
+	arg->type = PRINT_DYNAMIC_ARRAY_LEN;
+
+	/* Find the field */
+	field = pevent_find_field(event, token);
+	if (!field)
+		goto out_free;
+
+	arg->dynarray.field = field;
+	arg->dynarray.index = 0;
+
+	if (read_expected(EVENT_DELIM, ")") < 0)
+		goto out_err;
+
+	type = read_token(&token);
+	*tok = token;
+
+	return type;
+
+ out_free:
+	free_token(token);
+ out_err:
+	*tok = NULL;
+	return EVENT_ERROR;
+}
+
+static enum event_type
 process_paren(struct event_format *event, struct print_arg *arg, char **tok)
 {
 	struct print_arg *item_arg;
@@ -2904,6 +3025,10 @@ 
 		free_token(token);
 		return process_dynamic_array(event, arg, tok);
 	}
+	if (strcmp(token, "__get_dynamic_array_len") == 0) {
+		free_token(token);
+		return process_dynamic_array_len(event, arg, tok);
+	}
 
 	func = find_func_handler(event->pevent, token);
 	if (func) {
@@ -3577,6 +3702,9 @@ 
 		case '/':
 			val = left / right;
 			break;
+		case '%':
+			val = left % right;
+			break;
 		case '*':
 			val = left * right;
 			break;
@@ -3584,14 +3712,25 @@ 
 			goto out_warning_op;
 		}
 		break;
+	case PRINT_DYNAMIC_ARRAY_LEN:
+		offset = pevent_read_number(pevent,
+					    data + arg->dynarray.field->offset,
+					    arg->dynarray.field->size);
+		/*
+		 * The total allocated length of the dynamic array is
+		 * stored in the top half of the field, and the offset
+		 * is in the bottom half of the 32 bit field.
+		 */
+		val = (unsigned long long)(offset >> 16);
+		break;
 	case PRINT_DYNAMIC_ARRAY:
 		/* Without [], we pass the address to the dynamic data */
 		offset = pevent_read_number(pevent,
 					    data + arg->dynarray.field->offset,
 					    arg->dynarray.field->size);
 		/*
-		 * The actual length of the dynamic array is stored
-		 * in the top half of the field, and the offset
+		 * The total allocated length of the dynamic array is
+		 * stored in the top half of the field, and the offset
 		 * is in the bottom half of the 32 bit field.
 		 */
 		offset &= 0xffff;
@@ -3623,7 +3762,7 @@ 
 	{ "NET_TX_SOFTIRQ", 2 },
 	{ "NET_RX_SOFTIRQ", 3 },
 	{ "BLOCK_SOFTIRQ", 4 },
-	{ "BLOCK_IOPOLL_SOFTIRQ", 5 },
+	{ "IRQ_POLL_SOFTIRQ", 5 },
 	{ "TASKLET_SOFTIRQ", 6 },
 	{ "SCHED_SOFTIRQ", 7 },
 	{ "HRTIMER_SOFTIRQ", 8 },
@@ -3724,7 +3863,7 @@ 
 	struct format_field *field;
 	struct printk_map *printk;
 	long long val, fval;
-	unsigned long addr;
+	unsigned long long addr;
 	char *str;
 	unsigned char *hex;
 	int print;
@@ -3757,13 +3896,30 @@ 
 		 */
 		if (!(field->flags & FIELD_IS_ARRAY) &&
 		    field->size == pevent->long_size) {
-			addr = *(unsigned long *)(data + field->offset);
+
+			/* Handle heterogeneous recording and processing
+			 * architectures
+			 *
+			 * CASE I:
+			 * Traces recorded on 32-bit devices (32-bit
+			 * addressing) and processed on 64-bit devices:
+			 * In this case, only 32 bits should be read.
+			 *
+			 * CASE II:
+			 * Traces recorded on 64 bit devices and processed
+			 * on 32-bit devices:
+			 * In this case, 64 bits must be read.
+			 */
+			addr = (pevent->long_size == 8) ?
+				*(unsigned long long *)(data + field->offset) :
+				(unsigned long long)*(unsigned int *)(data + field->offset);
+
 			/* Check if it matches a print format */
 			printk = find_printk(pevent, addr);
 			if (printk)
 				trace_seq_puts(s, printk->printk);
 			else
-				trace_seq_printf(s, "%lx", addr);
+				trace_seq_printf(s, "%llx", addr);
 			break;
 		}
 		str = malloc(len + 1);
@@ -4595,73 +4751,80 @@ 
 	return 1;
 }
 
-static void print_event_fields(struct trace_seq *s, void *data,
-			       int size __maybe_unused,
-			       struct event_format *event)
+void pevent_print_field(struct trace_seq *s, void *data,
+			struct format_field *field)
 {
-	struct format_field *field;
 	unsigned long long val;
 	unsigned int offset, len, i;
+	struct pevent *pevent = field->event->pevent;
 
-	field = event->format.fields;
-	while (field) {
-		trace_seq_printf(s, " %s=", field->name);
-		if (field->flags & FIELD_IS_ARRAY) {
-			offset = field->offset;
-			len = field->size;
-			if (field->flags & FIELD_IS_DYNAMIC) {
-				val = pevent_read_number(event->pevent, data + offset, len);
-				offset = val;
-				len = offset >> 16;
-				offset &= 0xffff;
-			}
-			if (field->flags & FIELD_IS_STRING &&
-			    is_printable_array(data + offset, len)) {
-				trace_seq_printf(s, "%s", (char *)data + offset);
-			} else {
-				trace_seq_puts(s, "ARRAY[");
-				for (i = 0; i < len; i++) {
-					if (i)
-						trace_seq_puts(s, ", ");
-					trace_seq_printf(s, "%02x",
-							 *((unsigned char *)data + offset + i));
-				}
-				trace_seq_putc(s, ']');
-				field->flags &= ~FIELD_IS_STRING;
-			}
+	if (field->flags & FIELD_IS_ARRAY) {
+		offset = field->offset;
+		len = field->size;
+		if (field->flags & FIELD_IS_DYNAMIC) {
+			val = pevent_read_number(pevent, data + offset, len);
+			offset = val;
+			len = offset >> 16;
+			offset &= 0xffff;
+		}
+		if (field->flags & FIELD_IS_STRING &&
+		    is_printable_array(data + offset, len)) {
+			trace_seq_printf(s, "%s", (char *)data + offset);
 		} else {
-			val = pevent_read_number(event->pevent, data + field->offset,
-						 field->size);
-			if (field->flags & FIELD_IS_POINTER) {
-				trace_seq_printf(s, "0x%llx", val);
-			} else if (field->flags & FIELD_IS_SIGNED) {
-				switch (field->size) {
-				case 4:
-					/*
-					 * If field is long then print it in hex.
-					 * A long usually stores pointers.
-					 */
-					if (field->flags & FIELD_IS_LONG)
-						trace_seq_printf(s, "0x%x", (int)val);
-					else
-						trace_seq_printf(s, "%d", (int)val);
-					break;
-				case 2:
-					trace_seq_printf(s, "%2d", (short)val);
-					break;
-				case 1:
-					trace_seq_printf(s, "%1d", (char)val);
-					break;
-				default:
-					trace_seq_printf(s, "%lld", val);
-				}
-			} else {
+			trace_seq_puts(s, "ARRAY[");
+			for (i = 0; i < len; i++) {
+				if (i)
+					trace_seq_puts(s, ", ");
+				trace_seq_printf(s, "%02x",
+						 *((unsigned char *)data + offset + i));
+			}
+			trace_seq_putc(s, ']');
+			field->flags &= ~FIELD_IS_STRING;
+		}
+	} else {
+		val = pevent_read_number(pevent, data + field->offset,
+					 field->size);
+		if (field->flags & FIELD_IS_POINTER) {
+			trace_seq_printf(s, "0x%llx", val);
+		} else if (field->flags & FIELD_IS_SIGNED) {
+			switch (field->size) {
+			case 4:
+				/*
+				 * If field is long then print it in hex.
+				 * A long usually stores pointers.
+				 */
 				if (field->flags & FIELD_IS_LONG)
-					trace_seq_printf(s, "0x%llx", val);
+					trace_seq_printf(s, "0x%x", (int)val);
 				else
-					trace_seq_printf(s, "%llu", val);
+					trace_seq_printf(s, "%d", (int)val);
+				break;
+			case 2:
+				trace_seq_printf(s, "%2d", (short)val);
+				break;
+			case 1:
+				trace_seq_printf(s, "%1d", (char)val);
+				break;
+			default:
+				trace_seq_printf(s, "%lld", val);
 			}
+		} else {
+			if (field->flags & FIELD_IS_LONG)
+				trace_seq_printf(s, "0x%llx", val);
+			else
+				trace_seq_printf(s, "%llu", val);
 		}
+	}
+}
+
+void pevent_print_fields(struct trace_seq *s, void *data,
+			 int size __maybe_unused, struct event_format *event)
+{
+	struct format_field *field;
+
+	field = event->format.fields;
+	while (field) {
+		trace_seq_printf(s, " %s=", field->name);
+		pevent_print_field(s, data, field);
 		field = field->next;
 	}
 }
@@ -4687,7 +4850,7 @@ 
 
 	if (event->flags & EVENT_FL_FAILED) {
 		trace_seq_printf(s, "[FAILED TO PARSE]");
-		print_event_fields(s, data, size, event);
+		pevent_print_fields(s, data, size, event);
 		return;
 	}
 
@@ -4765,8 +4928,8 @@ 
 				else
 					ls = 2;
 
-				if (*(ptr+1) == 'F' ||
-				    *(ptr+1) == 'f') {
+				if (*(ptr+1) == 'F' || *(ptr+1) == 'f' ||
+				    *(ptr+1) == 'S' || *(ptr+1) == 's') {
 					ptr++;
 					show_func = *ptr;
 				} else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') {
@@ -4824,17 +4987,16 @@ 
 						break;
 					}
 				}
-				if (pevent->long_size == 8 && ls &&
+				if (pevent->long_size == 8 && ls == 1 &&
 				    sizeof(long) != 8) {
 					char *p;
 
-					ls = 2;
 					/* make %l into %ll */
-					p = strchr(format, 'l');
-					if (p)
+					if (ls == 1 && (p = strchr(format, 'l')))
 						memmove(p+1, p, strlen(p)+1);
 					else if (strcmp(format, "%p") == 0)
 						strcpy(format, "0x%llx");
+					ls = 2;
 				}
 				switch (ls) {
 				case -2:
@@ -5030,11 +5192,11 @@ 
 }
 
 /**
- * pevent_data_pid - parse the PID from raw data
+ * pevent_data_pid - parse the PID from record
  * @pevent: a handle to the pevent
  * @rec: the record to parse
  *
- * This returns the PID from a raw data.
+ * This returns the PID from a record.
  */
 int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec)
 {
@@ -5042,6 +5204,32 @@ 
 }
 
 /**
+ * pevent_data_preempt_count - parse the preempt count from the record
+ * @pevent: a handle to the pevent
+ * @rec: the record to parse
+ *
+ * This returns the preempt count from a record.
+ */
+int pevent_data_preempt_count(struct pevent *pevent, struct pevent_record *rec)
+{
+	return parse_common_pc(pevent, rec->data);
+}
+
+/**
+ * pevent_data_flags - parse the latency flags from the record
+ * @pevent: a handle to the pevent
+ * @rec: the record to parse
+ *
+ * This returns the latency flags from a record.
+ *
+ *  Use trace_flag_type enum for the flags (see event-parse.h).
+ */
+int pevent_data_flags(struct pevent *pevent, struct pevent_record *rec)
+{
+	return parse_common_flags(pevent, rec->data);
+}
+
+/**
  * pevent_data_comm_from_pid - return the command line from PID
  * @pevent: a handle to the pevent
  * @pid: the PID of the task to search for
@@ -5162,7 +5350,7 @@ 
 	int print_pretty = 1;
 
 	if (event->pevent->print_raw || (event->flags & EVENT_FL_PRINTRAW))
-		print_event_fields(s, record->data, record->size, event);
+		pevent_print_fields(s, record->data, record->size, event);
 	else {
 
 		if (event->handler && !(event->flags & EVENT_FL_NOHANDLE))
@@ -5189,41 +5377,45 @@ 
 	return false;
 }
 
-void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
-			struct pevent_record *record, bool use_trace_clock)
+/**
+ * pevent_find_event_by_record - return the event from a given record
+ * @pevent: a handle to the pevent
+ * @record: The record to get the event from
+ *
+ * Returns the associated event for a given record, or NULL if non is
+ * is found.
+ */
+struct event_format *
+pevent_find_event_by_record(struct pevent *pevent, struct pevent_record *record)
 {
-	static const char *spaces = "                    "; /* 20 spaces */
-	struct event_format *event;
-	unsigned long secs;
-	unsigned long usecs;
-	unsigned long nsecs;
-	const char *comm;
-	void *data = record->data;
 	int type;
-	int pid;
-	int len;
-	int p;
-	bool use_usec_format;
-
-	use_usec_format = is_timestamp_in_us(pevent->trace_clock,
-							use_trace_clock);
-	if (use_usec_format) {
-		secs = record->ts / NSECS_PER_SEC;
-		nsecs = record->ts - secs * NSECS_PER_SEC;
-	}
 
 	if (record->size < 0) {
 		do_warning("ug! negative record size %d", record->size);
-		return;
+		return NULL;
 	}
 
-	type = trace_parse_common_type(pevent, data);
+	type = trace_parse_common_type(pevent, record->data);
 
-	event = pevent_find_event(pevent, type);
-	if (!event) {
-		do_warning("ug! no event found for type %d", type);
-		return;
-	}
+	return pevent_find_event(pevent, type);
+}
+
+/**
+ * pevent_print_event_task - Write the event task comm, pid and CPU
+ * @pevent: a handle to the pevent
+ * @s: the trace_seq to write to
+ * @event: the handle to the record's event
+ * @record: The record to get the event from
+ *
+ * Writes the tasks comm, pid and CPU to @s.
+ */
+void pevent_print_event_task(struct pevent *pevent, struct trace_seq *s,
+			     struct event_format *event,
+			     struct pevent_record *record)
+{
+	void *data = record->data;
+	const char *comm;
+	int pid;
 
 	pid = parse_common_pid(pevent, data);
 	comm = find_cmdline(pevent, pid);
@@ -5231,24 +5423,78 @@ 
 	if (pevent->latency_format) {
 		trace_seq_printf(s, "%8.8s-%-5d %3d",
 		       comm, pid, record->cpu);
-		pevent_data_lat_fmt(pevent, s, record);
 	} else
 		trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu);
+}
+
+/**
+ * pevent_print_event_time - Write the event timestamp
+ * @pevent: a handle to the pevent
+ * @s: the trace_seq to write to
+ * @event: the handle to the record's event
+ * @record: The record to get the event from
+ * @use_trace_clock: Set to parse according to the @pevent->trace_clock
+ *
+ * Writes the timestamp of the record into @s.
+ */
+void pevent_print_event_time(struct pevent *pevent, struct trace_seq *s,
+			     struct event_format *event,
+			     struct pevent_record *record,
+			     bool use_trace_clock)
+{
+	unsigned long secs;
+	unsigned long usecs;
+	unsigned long nsecs;
+	int p;
+	bool use_usec_format;
+
+	use_usec_format = is_timestamp_in_us(pevent->trace_clock,
+							use_trace_clock);
+	if (use_usec_format) {
+		secs = record->ts / NSEC_PER_SEC;
+		nsecs = record->ts - secs * NSEC_PER_SEC;
+	}
+
+	if (pevent->latency_format) {
+		pevent_data_lat_fmt(pevent, s, record);
+	}
 
 	if (use_usec_format) {
 		if (pevent->flags & PEVENT_NSEC_OUTPUT) {
 			usecs = nsecs;
 			p = 9;
 		} else {
-			usecs = (nsecs + 500) / NSECS_PER_USEC;
+			usecs = (nsecs + 500) / NSEC_PER_USEC;
+			/* To avoid usecs larger than 1 sec */
+			if (usecs >= USEC_PER_SEC) {
+				usecs -= USEC_PER_SEC;
+				secs++;
+			}
 			p = 6;
 		}
 
-		trace_seq_printf(s, " %5lu.%0*lu: %s: ",
-					secs, p, usecs, event->name);
+		trace_seq_printf(s, " %5lu.%0*lu:", secs, p, usecs);
 	} else
-		trace_seq_printf(s, " %12llu: %s: ",
-					record->ts, event->name);
+		trace_seq_printf(s, " %12llu:", record->ts);
+}
+
+/**
+ * pevent_print_event_data - Write the event data section
+ * @pevent: a handle to the pevent
+ * @s: the trace_seq to write to
+ * @event: the handle to the record's event
+ * @record: The record to get the event from
+ *
+ * Writes the parsing of the record's data to @s.
+ */
+void pevent_print_event_data(struct pevent *pevent, struct trace_seq *s,
+			     struct event_format *event,
+			     struct pevent_record *record)
+{
+	static const char *spaces = "                    "; /* 20 spaces */
+	int len;
+
+	trace_seq_printf(s, " %s: ", event->name);
 
 	/* Space out the event names evenly. */
 	len = strlen(event->name);
@@ -5258,6 +5504,23 @@ 
 	pevent_event_info(s, event, record);
 }
 
+void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
+			struct pevent_record *record, bool use_trace_clock)
+{
+	struct event_format *event;
+
+	event = pevent_find_event_by_record(pevent, record);
+	if (!event) {
+		do_warning("ug! no event found for type %d",
+			   trace_parse_common_type(pevent, record->data));
+		return;
+	}
+
+	pevent_print_event_task(pevent, s, event, record);
+	pevent_print_event_time(pevent, s, event, record, use_trace_clock);
+	pevent_print_event_data(pevent, s, event, record);
+}
+
 static int events_id_cmp(const void *a, const void *b)
 {
 	struct event_format * const * ea = a;
@@ -5897,12 +6160,7 @@ 
 	const char *msg;
 
 	if (errnum >= 0) {
-		msg = strerror_r(errnum, buf, buflen);
-		if (msg != buf) {
-			size_t len = strlen(msg);
-			memcpy(buf, msg, min(buflen - 1, len));
-			*(buf + min(buflen - 1, len)) = '\0';
-		}
+		str_error_r(errnum, buf, buflen);
 		return 0;
 	}
 
@@ -6568,6 +6826,7 @@ 
 	free(pevent->trace_clock);
 	free(pevent->events);
 	free(pevent->sort_events);
+	free(pevent->func_resolver);
 
 	free(pevent);
 }
diff -Nru trace-cmd-2.6/event-parse.h trace-cmd-2.6.1/event-parse.h
--- trace-cmd-2.6/event-parse.h	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/event-parse.h	2017-05-02 19:35:16.000000000 +0200
@@ -172,9 +172,6 @@ 
 #define PEVENT_PLUGIN_OPTIONS_NAME MAKE_STR(PEVENT_PLUGIN_OPTIONS)
 #define PEVENT_PLUGIN_ALIAS_NAME MAKE_STR(PEVENT_PLUGIN_ALIAS)
 
-#define NSECS_PER_SEC		1000000000ULL
-#define NSECS_PER_USEC		1000ULL
-
 enum format_flags {
 	FIELD_IS_ARRAY		= 1,
 	FIELD_IS_POINTER	= 2,
@@ -294,6 +291,7 @@ 
 	PRINT_OP,
 	PRINT_FUNC,
 	PRINT_BITMASK,
+	PRINT_DYNAMIC_ARRAY_LEN,
 };
 
 struct print_arg {
@@ -453,6 +451,10 @@ 
 struct func_map;
 struct func_list;
 struct event_handler;
+struct func_resolver;
+
+typedef char *(pevent_func_resolver_t)(void *priv,
+				       unsigned long long *addrp, char **modp);
 
 struct pevent {
 	int ref_count;
@@ -481,6 +483,7 @@ 
 	int cmdline_count;
 
 	struct func_map *func_map;
+	struct func_resolver *func_resolver;
 	struct func_list *funclist;
 	unsigned int func_count;
 
@@ -613,6 +616,9 @@ 
 	TRACE_FLAG_SOFTIRQ		= 0x10,
 };
 
+int pevent_set_function_resolver(struct pevent *pevent,
+				 pevent_func_resolver_t *func, void *priv);
+void pevent_reset_function_resolver(struct pevent *pevent);
 int pevent_register_comm(struct pevent *pevent, const char *comm, int pid);
 int pevent_register_trace_clock(struct pevent *pevent, const char *trace_clock);
 int pevent_register_function(struct pevent *pevent, char *name,
@@ -621,6 +627,16 @@ 
 				 unsigned long long addr);
 int pevent_pid_is_registered(struct pevent *pevent, int pid);
 
+void pevent_print_event_task(struct pevent *pevent, struct trace_seq *s,
+			     struct event_format *event,
+			     struct pevent_record *record);
+void pevent_print_event_time(struct pevent *pevent, struct trace_seq *s,
+			     struct event_format *event,
+			     struct pevent_record *record,
+			     bool use_trace_clock);
+void pevent_print_event_data(struct pevent *pevent, struct trace_seq *s,
+			     struct event_format *event,
+			     struct pevent_record *record);
 void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
 			struct pevent_record *record, bool use_trace_clock);
 
@@ -687,17 +703,26 @@ 
 struct event_format *
 pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name);
 
+struct event_format *
+pevent_find_event_by_record(struct pevent *pevent, struct pevent_record *record);
+
 void pevent_data_lat_fmt(struct pevent *pevent,
 			 struct trace_seq *s, struct pevent_record *record);
 int pevent_data_type(struct pevent *pevent, struct pevent_record *rec);
 struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type);
 int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec);
+int pevent_data_preempt_count(struct pevent *pevent, struct pevent_record *rec);
+int pevent_data_flags(struct pevent *pevent, struct pevent_record *rec);
 const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid);
 struct cmdline;
 struct cmdline *pevent_data_pid_from_comm(struct pevent *pevent, const char *comm,
 					  struct cmdline *next);
 int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline);
 
+void pevent_print_field(struct trace_seq *s, void *data,
+			struct format_field *field);
+void pevent_print_fields(struct trace_seq *s, void *data,
+			 int size __maybe_unused, struct event_format *event);
 void pevent_event_info(struct trace_seq *s, struct event_format *event,
 		       struct pevent_record *record);
 int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum,
diff -Nru trace-cmd-2.6/event-utils.h trace-cmd-2.6.1/event-utils.h
--- trace-cmd-2.6/event-utils.h	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/event-utils.h	2017-05-02 19:35:16.000000000 +0200
@@ -20,23 +20,17 @@ 
 #ifndef __UTIL_H
 #define __UTIL_H
 
-#include <string.h>
 #include <ctype.h>
-#include <stdarg.h>
 
 /* Can be overridden */
-void die(const char *fmt, ...);
-void *malloc_or_die(unsigned int size);
 void warning(const char *fmt, ...);
 void pr_stat(const char *fmt, ...);
 void vpr_stat(const char *fmt, va_list ap);
 
 /* Always available */
-void __die(const char *fmt, ...);
 void __warning(const char *fmt, ...);
 void __pr_stat(const char *fmt, ...);
 
-void __vdie(const char *fmt, ...);
 void __vwarning(const char *fmt, ...);
 void __vpr_stat(const char *fmt, ...);
 
diff -Nru trace-cmd-2.6/include/linux/string.h trace-cmd-2.6.1/include/linux/string.h
--- trace-cmd-2.6/include/linux/string.h	1970-01-01 01:00:00.000000000 +0100
+++ trace-cmd-2.6.1/include/linux/string.h	2017-05-02 19:35:16.000000000 +0200
@@ -0,0 +1,6 @@ 
+#ifndef __LINUX_STRING_H_
+#define __LINUX_STRING_H_
+
+char *str_error_r(int errnum, char *buf, size_t buflen);
+
+#endif
diff -Nru trace-cmd-2.6/include/linux/time64.h trace-cmd-2.6.1/include/linux/time64.h
--- trace-cmd-2.6/include/linux/time64.h	1970-01-01 01:00:00.000000000 +0100
+++ trace-cmd-2.6.1/include/linux/time64.h	2017-05-02 19:35:16.000000000 +0200
@@ -0,0 +1,12 @@ 
+#ifndef _TOOLS_LINUX_TIME64_H
+#define _TOOLS_LINUX_TIME64_H
+
+#define MSEC_PER_SEC	1000L
+#define USEC_PER_MSEC	1000L
+#define NSEC_PER_USEC	1000L
+#define NSEC_PER_MSEC	1000000L
+#define USEC_PER_SEC	1000000L
+#define NSEC_PER_SEC	1000000000L
+#define FSEC_PER_SEC	1000000000000000LL
+
+#endif /* _LINUX_TIME64_H */
diff -Nru trace-cmd-2.6/kbuffer-parse.c trace-cmd-2.6.1/kbuffer-parse.c
--- trace-cmd-2.6/kbuffer-parse.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/kbuffer-parse.c	2017-05-02 19:35:16.000000000 +0200
@@ -315,6 +315,7 @@ 
 		extend += delta;
 		delta = extend;
 		ptr += 4;
+		length = 0;
 		break;
 
 	case OLD_RINGBUF_TYPE_TIME_STAMP:
diff -Nru trace-cmd-2.6/kernel-shark.c trace-cmd-2.6.1/kernel-shark.c
--- trace-cmd-2.6/kernel-shark.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/kernel-shark.c	2017-05-02 19:35:16.000000000 +0200
@@ -18,6 +18,7 @@ 
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
 #include <fcntl.h>
@@ -29,12 +30,15 @@ 
 #include <errno.h>
 #include <getopt.h>
 #include <libgen.h>
+#include <dlfcn.h>
 
 #include "trace-compat.h"
 #include "trace-capture.h"
 #include "trace-cmd.h"
+#include "trace-local.h"
 #include "trace-gui.h"
 #include "kernel-shark.h"
+#include "kshark-plugin.h"
 #include "event-utils.h"
 #include "version.h"
 
@@ -58,8 +62,10 @@ 
 #define default_input_file "trace.dat"
 static char *input_file;
 
-void usage(char *prog)
+void usage(char **argv)
 {
+	char *prog = basename(argv[0]);
+
 	printf("Usage: %s\n", prog);
 	printf("  -h	Display this help message\n");
 	printf("  -v	Display version and exit\n");
@@ -221,10 +227,13 @@ 
 {
 	GString *gstr;
 	gchar *str;
+	gchar *gfile;
 
+	gfile = g_strdup(file);
 	gstr = g_string_new("kernelshark");
-	g_string_append_printf(gstr, "(%s)", basename(file));
+	g_string_append_printf(gstr, "(%s)", basename(gfile));
 	str = g_string_free(gstr, FALSE);
+	g_free(gfile);
 
 	gtk_window_set_title(GTK_WINDOW(window), str);
 	g_free(str);
@@ -743,7 +752,6 @@ 
 	struct filter_task *hide_tasks;
 	GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview);
 	GtkTreeModel *model;
-	TraceViewStore *store;
 	gboolean keep;
 	gchar *selections[] = { "Sync List Filter with Graph Filter",
 				"Sync Graph Filter with List Filter",
@@ -761,8 +769,6 @@ 
 	if (!model)
 		return;
 
-	store = TRACE_VIEW_STORE(model);
-
 	/* If they are already equal, then just perminently sync them */
 	if (filter_task_compare(info->ginfo->task_filter,
 				info->list_task_filter) &&
@@ -894,7 +900,6 @@ 
 {
 	GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview);
 	GtkTreeModel *model;
-	TraceViewStore *store;
 	int i;
 
 	if (!accept)
@@ -904,8 +909,6 @@ 
 	if (!model)
 		return;
 
-	store = TRACE_VIEW_STORE(model);
-
 	filter_task_clear(task_filter);
 
 	if (selected) {
@@ -955,7 +958,6 @@ 
 	GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview);
 	struct graph_info *ginfo = info->ginfo;
 	GtkTreeModel *model;
-	TraceViewStore *store;
 	gint *selected;
 	gint *tasks;
 
@@ -966,8 +968,6 @@ 
 	if (!model)
 		return;
 
-	store = TRACE_VIEW_STORE(model);
-
 	tasks = trace_graph_task_list(ginfo);
 	selected = filter_task_pids(task_filter);
 
@@ -1451,6 +1451,49 @@ 
 }
 
 static void
+handle_display_event_clicked (gpointer data, gboolean raw)
+{
+	struct shark_info *info = data;
+	struct pevent_record *record;
+	struct pevent *pevent;
+	TraceViewRecord *vrec;
+	GtkTreeModel *model;
+	guint64 offset;
+	gint row;
+	gint cpu;
+
+	row = trace_view_get_selected_row(GTK_WIDGET(info->treeview));
+	if (row < 0)
+		return;
+
+	model = gtk_tree_view_get_model(GTK_TREE_VIEW(info->treeview));
+	vrec = trace_view_store_get_row(TRACE_VIEW_STORE(model), row);
+	offset = vrec->offset;
+
+	record = tracecmd_read_at(info->handle, offset, &cpu);
+	if (!record)
+		return;
+
+	pevent = tracecmd_get_pevent(info->handle);
+	trace_show_record_dialog(GTK_WINDOW(info->window),
+				 pevent, record, raw);
+
+	free_record(record);
+}
+
+static void
+display_event_clicked (gpointer data)
+{
+	handle_display_event_clicked(data, FALSE);
+}
+
+static void
+display_raw_event_clicked (gpointer data)
+{
+	handle_display_event_clicked(data, TRUE);
+}
+
+static void
 filter_graph_hide_task_clicked (gpointer data)
 {
 	struct shark_info *info = data;
@@ -1516,12 +1559,13 @@ 
 	static GtkWidget *menu_filter_graph_add_task;
 	static GtkWidget *menu_filter_graph_hide_task;
 	static GtkWidget *menu_filter_graph_clear_tasks;
+	static GtkWidget *menu_display_event;
+	static GtkWidget *menu_display_raw_event;
 	struct pevent_record *record;
 	TraceViewRecord *vrec;
 	GtkTreeModel *model;
 	const char *comm;
 	gint pid;
-	gint len;
 	guint64 offset;
 	gint row;
 	gint cpu;
@@ -1593,6 +1637,21 @@ 
 					  G_CALLBACK (filter_graph_clear_tasks_clicked),
 					  data);
 
+		menu_display_event = gtk_menu_item_new_with_label("Display event");
+		gtk_widget_show(menu_display_event);
+		gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_display_event);
+
+		g_signal_connect_swapped (G_OBJECT (menu_display_event), "activate",
+					  G_CALLBACK (display_event_clicked),
+					  data);
+
+		menu_display_raw_event = gtk_menu_item_new_with_label("Display raw event");
+		gtk_widget_show(menu_display_raw_event);
+		gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_display_raw_event);
+
+		g_signal_connect_swapped (G_OBJECT (menu_display_raw_event), "activate",
+					  G_CALLBACK (display_raw_event_clicked),
+					  data);
 	}
 
 	row = trace_view_get_selected_row(GTK_WIDGET(info->treeview));
@@ -1608,8 +1667,6 @@ 
 			pid = pevent_data_pid(ginfo->pevent, record);
 			comm = pevent_data_comm_from_pid(ginfo->pevent, pid);
 
-			len = strlen(comm) + 50;
-
 			if (info->sync_task_filters) {
 				if (trace_graph_filter_task_find_pid(ginfo, pid))
 					set_menu_label(menu_filter_add_task, comm, pid,
@@ -1667,6 +1724,8 @@ 
 
 			gtk_widget_show(menu_filter_add_task);
 			gtk_widget_show(menu_filter_hide_task);
+			gtk_widget_show(menu_display_event);
+			gtk_widget_show(menu_display_raw_event);
 			free_record(record);
 		}
 	} else {
@@ -1674,6 +1733,8 @@ 
 		gtk_widget_hide(menu_filter_hide_task);
 		gtk_widget_hide(menu_filter_graph_add_task);
 		gtk_widget_hide(menu_filter_graph_hide_task);
+		gtk_widget_hide(menu_display_event);
+		gtk_widget_hide(menu_display_raw_event);
 	}
 
 	if (ginfo->filter_enabled)
@@ -1744,6 +1805,57 @@ 
 	return FALSE;
 }
 
+static struct plugin_list {
+	struct plugin_list		*next;
+	const char			*file;
+} *plugins;
+static struct plugin_list **plugin_next = &plugins;
+
+static void add_plugin(const char *file)
+{
+	struct stat st;
+	int ret;
+
+	ret = stat(default_input_file, &st);
+	if (ret < 0) {
+		warning("plugin %s not found", file);
+		return;
+	}
+
+	*plugin_next = calloc(sizeof(struct plugin_list), 1);
+	if (!*plugin_next)
+		die("failed to allocat memory for plugin");
+
+	(*plugin_next)->file = file;
+	plugin_next = &(*plugin_next)->next;
+}
+
+static void handle_plugins(struct shark_info *info)
+{
+	kshark_plugin_load_func func;
+	struct plugin_list *plugin;
+	void *handle;
+
+	while ((plugin = plugins)) {
+		plugins = plugin->next;
+
+		handle = dlopen(plugin->file, RTLD_NOW | RTLD_GLOBAL);
+		free(plugin);
+		if (!handle) {
+			warning("cound not load plugin '%s'\n%s\n",
+				plugin->file, dlerror());
+			continue;
+		}
+		func = dlsym(handle, KSHARK_PLUGIN_LOADER_NAME);
+		if (!func) {
+			warning("cound not find func '%s' in plugin '%s'\n%s\n",
+				KSHARK_PLUGIN_LOADER_NAME, plugin->file, dlerror());
+			continue;
+		}
+		func(info);
+	}
+}
+
 static void sig_end(int sig)
 {
 	fprintf(stderr, "kernelshark: Received SIGINT\n");
@@ -1773,15 +1885,17 @@ 
 	int ret;
 	int c;
 
+#if !GLIB_CHECK_VERSION(2, 32, 0)
 	g_thread_init(NULL);
+#endif
 	gdk_threads_init();
 
 	gtk_init(&argc, &argv);
 
-	while ((c = getopt(argc, argv, "hvi:")) != -1) {
+	while ((c = getopt(argc, argv, "hvi:p:")) != -1) {
 		switch(c) {
 		case 'h':
-			usage(basename(argv[0]));
+			usage(argv);
 			return;
 		case 'v':
 			printf("%s - %s\n",
@@ -1791,6 +1905,9 @@ 
 		case 'i':
 			input_file = optarg;
 			break;
+		case 'p':
+			add_plugin(optarg);
+			break;
 		default:
 			/* assume the other options are for gtk */
 			break;
@@ -1799,7 +1916,7 @@ 
 
 	if ((argc - optind) >= 1) {
 		if (input_file)
-			usage(basename(argv[0]));
+			usage(argv);
 		input_file = argv[optind];
 	}
 
@@ -2378,9 +2495,19 @@ 
 
 	gtk_widget_set_size_request(window, TRACE_WIDTH, TRACE_HEIGHT);
 
+	handle_plugins(info);
+
 	gdk_threads_enter();
+
+	/*
+	 * The showing of the window will configure the graph and it will
+	 * waste time drawing the events. But after the window appears and
+	 * a border is displayed, the graph gets shown again.
+	 */
+	info->ginfo->no_draw = TRUE;
 	gtk_widget_show (window);
 
+	info->ginfo->no_draw = FALSE;
 	gtk_main ();
 	gdk_threads_leave();
 }
diff -Nru trace-cmd-2.6/kshark-plugin.h trace-cmd-2.6.1/kshark-plugin.h
--- trace-cmd-2.6/kshark-plugin.h	1970-01-01 01:00:00.000000000 +0100
+++ trace-cmd-2.6.1/kshark-plugin.h	2017-05-02 19:35:16.000000000 +0200
@@ -0,0 +1,35 @@ 
+/*
+ * Copyright (C) 2016 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License (not later!)
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not,  see <http://www.gnu.org/licenses>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef _KSHARK_PLUGIN_H
+#define _KSHARK_PLUGIN_H
+
+#define KSHARK_PLUGIN_LOADER kshark_plugin_loader
+#define KSHARK_PLUGIN_UNLOADER kshark_plugin_unloader
+
+#define _MAKE_STR(x)	#x
+#define MAKE_STR(x)	_MAKE_STR(x)
+#define KSHARK_PLUGIN_LOADER_NAME MAKE_STR(KSHARK_PLUGIN_LOADER)
+#define KSHARK_PLUGIN_UNLOADER_NAME MAKE_STR(KSHARK_PLUGIN_UNLOADER)
+
+typedef int (*kshark_plugin_load_func)(void *info);
+typedef int (*kshark_plugin_unload_func)(void *info);
+
+
+#endif
diff -Nru trace-cmd-2.6/Makefile trace-cmd-2.6.1/Makefile
--- trace-cmd-2.6/Makefile	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/Makefile	2017-05-02 19:35:16.000000000 +0200
@@ -1,7 +1,7 @@ 
 # trace-cmd version
 TC_VERSION = 2
 TC_PATCHLEVEL = 6
-TC_EXTRAVERSION =
+TC_EXTRAVERSION = 1
 
 # Kernel Shark version
 KS_VERSION = 0
@@ -47,7 +47,10 @@ 
 html_install_SQ = '$(subst ','\'',$(html_install))'
 img_install = $(prefix)/share/kernelshark/html/images
 img_install_SQ = '$(subst ','\'',$(img_install))'
-libdir ?= lib
+libdir ?= $(prefix)/lib
+libdir_SQ = '$(subst ','\'',$(libdir))'
+includedir = $(prefix)/include/trace-cmd
+includedir_SQ = '$(subst ','\'',$(includedir))'
 
 export man_dir man_dir_SQ html_install html_install_SQ INSTALL
 export img_install img_install_SQ
@@ -56,17 +59,28 @@ 
 ifeq ($(prefix),$(HOME))
 plugin_dir = $(HOME)/.trace-cmd/plugins
 python_dir = $(HOME)/.trace-cmd/python
+var_dir = $(HOME)/.trace-cmd/
 else
-plugin_dir = $(prefix)/$(libdir)/trace-cmd/plugins
-python_dir = $(prefix)/$(libdir)/trace-cmd/python
+plugin_dir = $(libdir)/trace-cmd/plugins
+python_dir = $(libdir)/trace-cmd/python
 PLUGIN_DIR = -DPLUGIN_DIR="$(plugin_dir)"
 PYTHON_DIR = -DPYTHON_DIR="$(python_dir)"
 PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))'
 PYTHON_DIR_SQ = '$(subst ','\'',$(PYTHON_DIR))'
+var_dir = /var
 endif
 
+VAR_DIR = -DVAR_DIR="$(var_dir)"
+VAR_DIR_SQ = '$(subst ','\'',$(VAR_DIR))'
+var_dir_SQ = '$(subst ','\'',$(var_dir))'
+
 HELP_DIR = -DHELP_DIR=$(html_install)
 HELP_DIR_SQ = '$(subst ','\'',$(HELP_DIR))'
+#' emacs highlighting gets confused by the above escaped quote.
+
+BASH_COMPLETE_DIR ?= /etc/bash_completion.d
+
+export var_dir
 
 # copy a bit from Linux kbuild
 
@@ -77,6 +91,12 @@ 
   VERBOSE = 0
 endif
 
+SWIG_DEFINED := $(shell if swig -help &> /dev/null; then echo 1; else echo 0; fi)
+ifeq ($(SWIG_DEFINED), 0)
+BUILD_PYTHON := report_noswig
+NO_PYTHON = 1
+endif
+
 ifndef NO_PYTHON
 PYTHON		:= ctracecmd.so
 PYTHON_GUI	:= ctracecmd.so ctracecmdgui.so
@@ -216,7 +236,7 @@ 
 TRACECMD_VERSION = $(TC_VERSION).$(TC_PATCHLEVEL).$(TC_EXTRAVERSION)
 KERNELSHARK_VERSION = $(KS_VERSION).$(KS_PATCHLEVEL).$(KS_EXTRAVERSION)
 
-INCLUDES = -I. -I $(srctree)/../../include $(CONFIG_INCLUDES)
+INCLUDES = -I. -I ./include -I $(srctree)/../../include $(CONFIG_INCLUDES)
 
 include $(src)/features.mk
 
@@ -253,7 +273,7 @@ 
 endif
 
 # Append required CFLAGS
-override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ)
+override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ) $(VAR_DIR)
 override CFLAGS += $(udis86-flags) $(blk-flags)
 
 ifeq ($(VERBOSE),1)
@@ -321,7 +341,8 @@ 
 		trace-xml.o
 TRACE_CMD_OBJS = trace-cmd.o trace-record.o trace-read.o trace-split.o trace-listen.o \
 	 trace-stack.o trace-hist.o trace-mem.o trace-snapshot.o trace-stat.o \
-	 trace-hash.o trace-profile.o trace-stream.o
+	 trace-hash.o trace-profile.o trace-stream.o trace-record.o trace-restore.o \
+	 trace-check-events.o trace-show.o trace-list.o
 TRACE_VIEW_OBJS = trace-view.o trace-view-store.o
 TRACE_GRAPH_OBJS = trace-graph.o trace-plot.o trace-plot-cpu.o trace-plot-task.o
 TRACE_VIEW_MAIN_OBJS = trace-view-main.o $(TRACE_VIEW_OBJS) $(TRACE_GUI_OBJS)
@@ -329,11 +350,12 @@ 
 KERNEL_SHARK_OBJS = $(TRACE_VIEW_OBJS) $(TRACE_GRAPH_OBJS) $(TRACE_GUI_OBJS) \
 	trace-capture.o kernel-shark.o
 
-PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o
+PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o str_error_r.o
 TCMD_LIB_OBJS = $(PEVENT_LIB_OBJS) trace-util.o trace-input.o trace-ftrace.o \
-			trace-output.o trace-record.o trace-recorder.o \
-			trace-restore.o trace-usage.o trace-blk-hack.o \
-			kbuffer-parse.o event-plugin.o trace-hooks.o
+			trace-output.o trace-recorder.o \
+			trace-usage.o trace-blk-hack.o \
+			kbuffer-parse.o event-plugin.o trace-hooks.o \
+			trace-msg.o
 
 PLUGIN_OBJS =
 PLUGIN_OBJS += plugin_jbd2.o
@@ -415,6 +437,8 @@ 
 libtracecmd.a: $(TCMD_LIB_OBJS)
 	$(Q)$(do_build_static_lib)
 
+libs: libtracecmd.so libparsevent.so
+
 trace-util.o: trace_plugin_dir
 
 $(PLUGIN_OBJS): %.o : $(src)/%.c
@@ -562,7 +586,10 @@ 
 
 install_python: $(PYTHON_SO_INSTALL) $(PYTHON_PY_PROGS) $(PYTHON_PY_LIBS) $(PYTHON_PY_PLUGINS)
 
-install_cmd: all_cmd install_plugins install_python
+install_bash_completion: force
+	$(Q)$(call do_install_data,trace-cmd.bash,$(BASH_COMPLETE_DIR))
+
+install_cmd: all_cmd install_plugins install_python install_bash_completion
 	$(Q)$(call do_install,trace-cmd,$(bindir_SQ))
 
 install: install_cmd
@@ -574,6 +601,12 @@ 
 	$(Q)$(call do_install,trace-graph,$(bindir_SQ))
 	$(Q)$(call do_install,kernelshark,$(bindir_SQ))
 
+install_libs: libs
+	$(Q)$(call do_install,libtracecmd.so,$(libdir_SQ))
+	$(Q)$(call do_install,libparsevent.so,$(libdir_SQ))
+	$(Q)$(call do_install,event-parse.h,$(includedir_SQ))
+	$(Q)$(call do_install,trace-cmd.h,$(includedir_SQ))
+
 doc:
 	$(MAKE) -C $(src)/Documentation all
 
@@ -590,6 +623,11 @@ 
 
 ##### PYTHON STUFF #####
 
+report_noswig: force
+	$(Q)echo
+	$(Q)echo "    NO_PYTHON forced: swig not installed, not compling python plugins"
+	$(Q)echo
+
 PYTHON_INCLUDES = `pkg-config --cflags $(PYTHON_VERS)`
 PYTHON_LDFLAGS = `pkg-config --libs $(PYTHON_VERS)` \
 		$(shell python2 -c "import distutils.sysconfig; print distutils.sysconfig.get_config_var('LINKFORSHARED')")
diff -Nru trace-cmd-2.6/parse-filter.c trace-cmd-2.6.1/parse-filter.c
--- trace-cmd-2.6/parse-filter.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/parse-filter.c	2017-05-02 19:35:16.000000000 +0200
@@ -28,11 +28,16 @@ 
 #include "event-utils.h"
 
 #define COMM "COMM"
+#define CPU "CPU"
 
 static struct format_field comm = {
 	.name = "COMM",
 };
 
+static struct format_field cpu = {
+	.name = "CPU",
+};
+
 struct event_list {
 	struct event_list	*next;
 	struct event_format	*event;
@@ -382,14 +387,17 @@ 
 		/* Consider this a field */
 		field = pevent_find_any_field(event, token);
 		if (!field) {
-			if (strcmp(token, COMM) != 0) {
+			/* If token is 'COMM' or 'CPU' then it is special */
+			if (strcmp(token, COMM) == 0) {
+				field = &comm;
+			} else if (strcmp(token, CPU) == 0) {
+				field = &cpu;
+			} else {
 				/* not a field, Make it false */
 				arg->type = FILTER_ARG_BOOLEAN;
 				arg->boolean.value = FILTER_FALSE;
 				break;
 			}
-			/* If token is 'COMM' then it is special */
-			field = &comm;
 		}
 		arg->type = FILTER_ARG_FIELD;
 		arg->field.field = field;
@@ -1164,11 +1172,11 @@ 
 		current_op = current_exp;
 
 	ret = collapse_tree(current_op, parg, error_str);
+	/* collapse_tree() may free current_op, and updates parg accordingly */
+	current_op = NULL;
 	if (ret < 0)
 		goto fail;
 
-	*parg = current_op;
-
 	free(token);
 	return 0;
 
@@ -1626,6 +1634,7 @@ 
 		case FILTER_TRIVIAL_FALSE:
 			if (filter_type->filter->boolean.value)
 				continue;
+			break;
 		case FILTER_TRIVIAL_TRUE:
 			if (!filter_type->filter->boolean.value)
 				continue;
@@ -1718,6 +1727,10 @@ 
 		return (unsigned long)name;
 	}
 
+	/* Handle our dummy "cpu" field */
+	if (field == &cpu)
+		return record->cpu;
+
 	pevent_read_number_field(field, record->data, &val);
 
 	if (!(field->flags & FIELD_IS_SIGNED))
diff -Nru trace-cmd-2.6/parse-utils.c trace-cmd-2.6.1/parse-utils.c
--- trace-cmd-2.6/parse-utils.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/parse-utils.c	2017-05-02 19:35:16.000000000 +0200
@@ -1,3 +1,22 @@ 
+/*
+ * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not,  see <http://www.gnu.org/licenses>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -6,40 +25,6 @@ 
 
 #define __weak __attribute__((weak))
 
-void __vdie(const char *fmt, va_list ap)
-{
-	int ret = errno;
-
-	if (errno)
-		perror("trace-cmd");
-	else
-		ret = -1;
-
-	fprintf(stderr, "  ");
-	vfprintf(stderr, fmt, ap);
-
-	fprintf(stderr, "\n");
-	exit(ret);
-}
-
-void __die(const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	__vdie(fmt, ap);
-	va_end(ap);
-}
-
-void __weak die(const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	__vdie(fmt, ap);
-	va_end(ap);
-}
-
 void __vwarning(const char *fmt, va_list ap)
 {
 	if (errno)
@@ -63,11 +48,6 @@ 
 
 void __weak warning(const char *fmt, ...)
 {
-	va_list ap;
-
-	va_start(ap, fmt);
-	__vwarning(fmt, ap);
-	va_end(ap);
 }
 
 void __vpr_stat(const char *fmt, va_list ap)
@@ -87,24 +67,8 @@ 
 
 void __weak vpr_stat(const char *fmt, va_list ap)
 {
-	__vpr_stat(fmt, ap);
 }
 
 void __weak pr_stat(const char *fmt, ...)
 {
-	va_list ap;
-
-	va_start(ap, fmt);
-	__vpr_stat(fmt, ap);
-	va_end(ap);
-}
-
-void __weak *malloc_or_die(unsigned int size)
-{
-	void *data;
-
-	data = malloc(size);
-	if (!data)
-		die("malloc");
-	return data;
 }
diff -Nru trace-cmd-2.6/plugin_function.c trace-cmd-2.6.1/plugin_function.c
--- trace-cmd-2.6/plugin_function.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/plugin_function.c	2017-05-02 19:35:16.000000000 +0200
@@ -22,6 +22,7 @@ 
 #include <string.h>
 
 #include "trace-cmd.h"
+#include "event-utils.h"
 
 static struct func_stack {
 	int size;
diff -Nru trace-cmd-2.6/plugin_kvm.c trace-cmd-2.6.1/plugin_kvm.c
--- trace-cmd-2.6/plugin_kvm.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/plugin_kvm.c	2017-05-02 19:35:16.000000000 +0200
@@ -151,7 +151,23 @@ 
 	_ER(EXIT_WRITE_DR5,	0x035)		\
 	_ER(EXIT_WRITE_DR6,	0x036)		\
 	_ER(EXIT_WRITE_DR7,	0x037)		\
-	_ER(EXIT_EXCP_BASE,     0x040)		\
+	_ER(EXIT_EXCP_DE,	0x040)		\
+	_ER(EXIT_EXCP_DB,	0x041)		\
+	_ER(EXIT_EXCP_BP,	0x043)		\
+	_ER(EXIT_EXCP_OF,	0x044)		\
+	_ER(EXIT_EXCP_BR,	0x045)		\
+	_ER(EXIT_EXCP_UD,	0x046)		\
+	_ER(EXIT_EXCP_NM,	0x047)		\
+	_ER(EXIT_EXCP_DF,	0x048)		\
+	_ER(EXIT_EXCP_TS,	0x04a)		\
+	_ER(EXIT_EXCP_NP,	0x04b)		\
+	_ER(EXIT_EXCP_SS,	0x04c)		\
+	_ER(EXIT_EXCP_GP,	0x04d)		\
+	_ER(EXIT_EXCP_PF,	0x04e)		\
+	_ER(EXIT_EXCP_MF,	0x050)		\
+	_ER(EXIT_EXCP_AC,	0x051)		\
+	_ER(EXIT_EXCP_MC,	0x052)		\
+	_ER(EXIT_EXCP_XF,	0x053)		\
 	_ER(EXIT_INTR,		0x060)		\
 	_ER(EXIT_NMI,		0x061)		\
 	_ER(EXIT_SMI,		0x062)		\
@@ -197,7 +213,10 @@ 
 	_ER(EXIT_MONITOR,	0x08a)		\
 	_ER(EXIT_MWAIT,		0x08b)		\
 	_ER(EXIT_MWAIT_COND,	0x08c)		\
+	_ER(EXIT_XSETBV,	0x08d)		\
 	_ER(EXIT_NPF, 		0x400)		\
+	_ER(EXIT_AVIC_INCOMPLETE_IPI,		0x401)	\
+	_ER(EXIT_AVIC_UNACCELERATED_ACCESS,	0x402)	\
 	_ER(EXIT_ERR,		-1)
 
 #define _ER(reason, val)	{ #reason, val },
@@ -237,7 +256,7 @@ 
 		}
 	if (!strings)
 		return "UNKNOWN-ISA";
-	for (i = 0; strings[i].val >= 0; i++)
+	for (i = 0; strings[i].str; i++)
 		if (strings[i].val == val)
 			break;
 
diff -Nru trace-cmd-2.6/plugin_python.c trace-cmd-2.6.1/plugin_python.c
--- trace-cmd-2.6/plugin_python.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/plugin_python.c	2017-05-02 19:35:16.000000000 +0200
@@ -20,10 +20,11 @@ 
 "finally:\n"
 "   file.close()\n";
 
-static void load_plugin(struct pevent *pevent, const char *path,
+static int load_plugin(struct pevent *pevent, const char *path,
 			const char *name, void *data)
 {
 	PyObject *globals = data;
+	int err;
 	int len = strlen(path) + strlen(name) + 2;
 	int nlen = strlen(name) + 1;
 	char *full = malloc(len);
@@ -32,7 +33,7 @@ 
 	PyObject *res;
 
 	if (!full || !n)
-		return;
+		return -ENOMEM;
 
 	strcpy(full, path);
 	strcat(full, "/");
@@ -41,9 +42,9 @@ 
 	strcpy(n, name);
 	n[nlen - 4] = '\0';
 
-	asprintf(&load, pyload, full, n);
-	if (!load)
-		return;
+	err = asprintf(&load, pyload, full, n);
+	if (err < 0)
+		return err;
 
 	res = PyRun_String(load, Py_file_input, globals, globals);
 	if (!res) {
@@ -53,6 +54,8 @@ 
 		Py_DECREF(res);
 
 	free(load);
+
+	return 0;
 }
 
 int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
diff -Nru trace-cmd-2.6/str_error_r.c trace-cmd-2.6.1/str_error_r.c
--- trace-cmd-2.6/str_error_r.c	1970-01-01 01:00:00.000000000 +0100
+++ trace-cmd-2.6.1/str_error_r.c	2017-05-02 19:35:16.000000000 +0200
@@ -0,0 +1,26 @@ 
+#undef _GNU_SOURCE
+#include <string.h>
+#include <stdio.h>
+#include <linux/string.h>
+
+/*
+ * The tools so far have been using the strerror_r() GNU variant, that returns
+ * a string, be it the buffer passed or something else.
+ *
+ * But that, besides being tricky in cases where we expect that the function
+ * using strerror_r() returns the error formatted in a provided buffer (we have
+ * to check if it returned something else and copy that instead), breaks the
+ * build on systems not using glibc, like Alpine Linux, where musl libc is
+ * used.
+ *
+ * So, introduce yet another wrapper, str_error_r(), that has the GNU
+ * interface, but uses the portable XSI variant of strerror_r(), so that users
+ * rest asured that the provided buffer is used and it is what is returned.
+ */
+char *str_error_r(int errnum, char *buf, size_t buflen)
+{
+	int err = strerror_r(errnum, buf, buflen);
+	if (err)
+		snprintf(buf, buflen, "INTERNAL ERROR: strerror_r(%d, %p, %zd)=%d", errnum, buf, buflen, err);
+	return buf;
+}
diff -Nru trace-cmd-2.6/trace-capture.c trace-cmd-2.6.1/trace-capture.c
--- trace-cmd-2.6/trace-capture.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-capture.c	2017-05-02 19:35:16.000000000 +0200
@@ -18,6 +18,7 @@ 
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
 #include <fcntl.h>
@@ -37,6 +38,7 @@ 
 
 #include "trace-cmd.h"
 #include "trace-gui.h"
+#include "trace-local.h"
 #include "kernel-shark.h"
 #include "version.h"
 
@@ -83,8 +85,6 @@ 
 	return !str[i];
 }
 
-static gboolean settings_saved;
-
 static GString *get_home_settings_new(void)
 {
 	char *path = getenv("HOME");
@@ -1584,7 +1584,7 @@ 
 void tracecmd_capture_clicked(gpointer data)
 {
 	struct shark_info *info = data;
-	char *tracing;
+	const char *tracing;
 
 	tracing = tracecmd_get_tracing_dir();
 
diff -Nru trace-cmd-2.6/trace-check-events.c trace-cmd-2.6.1/trace-check-events.c
--- trace-cmd-2.6/trace-check-events.c	1970-01-01 01:00:00.000000000 +0100
+++ trace-cmd-2.6.1/trace-check-events.c	2017-05-02 19:35:16.000000000 +0200
@@ -0,0 +1,66 @@ 
+/*
+ * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License (not later!)
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not,  see <http://www.gnu.org/licenses>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+
+#include "trace-local.h"
+
+void trace_check_events(int argc, char **argv)
+{
+	const char *tracing;
+	int ret, c;
+	struct pevent *pevent = NULL;
+	struct plugin_list *list = NULL;
+
+	while ((c = getopt(argc-1, argv+1, "+hN")) >= 0) {
+		switch (c) {
+		case 'h':
+		default:
+			usage(argv);
+			break;
+		case 'N':
+			tracecmd_disable_plugins = 1;
+			break;
+		}
+	}
+	tracing = tracecmd_get_tracing_dir();
+
+	if (!tracing) {
+		printf("Can not find or mount tracing directory!\n"
+		       "Either tracing is not configured for this "
+		       "kernel\n"
+		       "or you do not have the proper permissions to "
+		       "mount the directory");
+		exit(EINVAL);
+	}
+
+	pevent = pevent_alloc();
+	if (!pevent)
+		exit(EINVAL);
+	list = tracecmd_load_plugins(pevent);
+	ret = tracecmd_fill_local_events(tracing, pevent);
+	if (ret || pevent->parsing_failures)
+		ret = EINVAL;
+	tracecmd_unload_plugins(list, pevent);
+	pevent_free(pevent);
+
+	return;
+}
diff -Nru trace-cmd-2.6/trace-cmd.bash trace-cmd-2.6.1/trace-cmd.bash
--- trace-cmd-2.6/trace-cmd.bash	1970-01-01 01:00:00.000000000 +0100
+++ trace-cmd-2.6.1/trace-cmd.bash	2017-05-02 19:35:16.000000000 +0200
@@ -0,0 +1,51 @@ 
+_trace_cmd_complete()
+{
+    local cur=""
+    local prev=""
+
+    # Not to use COMP_WORDS to avoid buggy behavior of Bash when
+    # handling with words including ":", like:
+    #
+    # prev="${COMP_WORDS[COMP_CWORD-1]}"
+    # cur="${COMP_WORDS[COMP_CWORD]}"
+    #
+    # Instead, we use _get_comp_words_by_ref() magic.
+    _get_comp_words_by_ref -n : cur prev
+
+    case "$prev" in
+        trace-cmd)
+            local cmds=$(trace-cmd --help 2>/dev/null | \
+                                grep " - " | sed 's/^ *//; s/ -.*//')
+            COMPREPLY=( $(compgen -W "${cmds}" -- "${cur}") )
+            ;;
+        -e)
+            local events=$(trace-cmd list -e)
+            local prefix=${cur%%:*}
+
+            COMPREPLY=( $(compgen -W "${events}" -- "${cur}") )
+
+            # This is still to handle the "*:*" special case
+            if [[ -n "$prefix" ]]; then
+                local reply_n=${#COMPREPLY[*]}
+                for (( i = 0; i < $reply_n; i++)); do
+                    COMPREPLY[$i]=${COMPREPLY[i]##${prefix}:}
+                done
+            fi
+            ;;
+        -p)
+            local plugins=$(trace-cmd list -p)
+            COMPREPLY=( $(compgen -W "${plugins}" -- "${cur}") )
+            ;;
+        -l|-n|-g)
+            # This is extremely slow still (may take >1sec).
+            local funcs=$(trace-cmd list -f | sed 's/ .*//')
+            COMPREPLY=( $(compgen -W "${funcs}" -- "${cur}") )
+            ;;
+        *)
+            # By default, we list files
+            local files=$(ls --color=never)
+            COMPREPLY=( $(compgen -W "${files}" -- "$cur") )
+            ;;
+    esac
+}
+complete -F _trace_cmd_complete trace-cmd
diff -Nru trace-cmd-2.6/trace-cmd.c trace-cmd-2.6.1/trace-cmd.c
--- trace-cmd-2.6/trace-cmd.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-cmd.c	2017-05-02 19:35:16.000000000 +0200
@@ -23,12 +23,15 @@ 
 #include <unistd.h>
 #include <dirent.h>
 #include <errno.h>
+#include <stdlib.h>
 
 #include "trace-local.h"
 
 int silence_warnings;
 int show_status;
 
+int debug;
+
 void warning(const char *fmt, ...)
 {
 	va_list ap;
@@ -72,681 +75,67 @@ 
 	return data;
 }
 
-static void dump_file_content(const char *path)
-{
-	char buf[BUFSIZ];
-	ssize_t n;
-	FILE *fp;
-
-	fp = fopen(path, "r");
-	if (!fp)
-		die("reading %s", path);
-
-	do {
-		n = fread(buf, 1, BUFSIZ, fp);
-		if (n > 0)
-			fwrite(buf, 1, n, stdout);
-	} while (n > 0);
-	fclose(fp);
-}
-
-void show_file(const char *name)
-{
-	char *path;
-
-	path = tracecmd_get_tracing_file(name);
-	dump_file_content(path);
-	tracecmd_put_tracing_file(path);
-}
-
-typedef int (*process_file_func)(char *buf, int len);
-
-static void process_file_re(process_file_func func,
-			    const char *name, const char *re)
-{
-	regex_t reg;
-	char *path;
-	char *buf = NULL;
-	char *str;
-	FILE *fp;
-	ssize_t n;
-	size_t l = strlen(re);
-
-	/* Just in case :-p */
-	if (!re || l == 0) {
-		show_file(name);
-		return;
-	}
-
-	/* Handle the newline at end of names for the user */
-	str = malloc_or_die(l + 3);
-	strcpy(str, re);
-	if (re[l-1] == '$')
-		strcpy(&str[l-1], "\n*$");
-		
-	if (regcomp(&reg, str, REG_ICASE|REG_NOSUB))
-		die("invalid function regex '%s'", re);
-
-	free(str);
-
-	path = tracecmd_get_tracing_file(name);
-	fp = fopen(path, "r");
-	if (!fp)
-		die("reading %s", path);
-	tracecmd_put_tracing_file(path);
-
-	do {
-		n = getline(&buf, &l, fp);
-		if (n > 0 && regexec(&reg, buf, 0, NULL, 0) == 0)
-			func(buf, n);
-	} while (n > 0);
-	free(buf);
-	fclose(fp);
-
-	regfree(&reg);
-}
-
-static int show_file_write(char *buf, int len)
-{
-	return fwrite(buf, 1, len, stdout);
-}
-
-static void show_file_re(const char *name, const char *re)
-{
-	process_file_re(show_file_write, name, re);
-}
-
-static char *get_event_file(const char *type, char *buf, int len)
-{
-	char *system;
-	char *event;
-	char *path;
-	char *file;
-
-	if (buf[len-1] == '\n')
-		buf[len-1] = '\0';
-
-	system = strtok(buf, ":");
-	if (!system)
-		die("no system found in %s", buf);
-
-	event = strtok(NULL, ":");
-	if (!event)
-		die("no event found in %s\n", buf);
-
-	path = tracecmd_get_tracing_file("events");
-	file = malloc_or_die(strlen(path) + strlen(system) + strlen(event) +
-			     strlen(type) + strlen("///") + 1);
-	sprintf(file, "%s/%s/%s/%s", path, system, event, type);
-	tracecmd_put_tracing_file(path);
-
-	return file;
-}
-
-static int event_filter_write(char *buf, int len)
-{
-	char *file;
-
-	if (buf[len-1] == '\n')
-		buf[len-1] = '\0';
-
-	printf("%s\n", buf);
-
-	file = get_event_file("filter", buf, len);
-	dump_file_content(file);
-	free(file);
-	printf("\n");
-
-	return 0;
-}
-
-static int event_trigger_write(char *buf, int len)
-{
-	char *file;
-
-	if (buf[len-1] == '\n')
-		buf[len-1] = '\0';
-
-	printf("%s\n", buf);
-
-	file = get_event_file("trigger", buf, len);
-	dump_file_content(file);
-	free(file);
-	printf("\n");
-
-	return 0;
-}
-
-static int event_format_write(char *fbuf, int len)
-{
-	char *file = get_event_file("format", fbuf, len);
-	char *buf = NULL;
-	size_t l;
-	FILE *fp;
-	int n;
-
-	/* The get_event_file() crops system in fbuf */
-	printf("system: %s\n", fbuf);
-
-	/* Don't print the print fmt, it's ugly */
-
-	fp = fopen(file, "r");
-	if (!fp)
-		die("reading %s", file);
-
-	do {
-		n = getline(&buf, &l, fp);
-		if (n > 0) {
-			if (strncmp(buf, "print fmt", 9) == 0)
-				break;
-			fwrite(buf, 1, n, stdout);
-		}
-	} while (n > 0);
-	fclose(fp);
-	free(buf);
-	free(file);
-
-	return 0;
-}
-
-static void show_event_filter_re(const char *re)
-{
-	process_file_re(event_filter_write, "available_events", re);
-}
-
-static void show_event_trigger_re(const char *re)
-{
-	process_file_re(event_trigger_write, "available_events", re);
-}
-
-static void show_event_format_re(const char *re)
-{
-	process_file_re(event_format_write, "available_events", re);
-}
 
-void show_instance_file(struct buffer_instance *instance, const char *name)
-{
-	char *path;
-
-	path = get_instance_file(instance, name);
-	dump_file_content(path);
-	tracecmd_put_tracing_file(path);
-}
-
-enum {
-	SHOW_EVENT_FORMAT		= 1 << 0,
-	SHOW_EVENT_FILTER		= 1 << 1,
-	SHOW_EVENT_TRIGGER		= 1 << 2,
+/**
+ * struct command
+ * @name command name
+ * @run function to execute on command `name`
+ */
+struct command {
+	char *name;
+	void (*run)(int argc, char **argv);
 };
 
-static void show_events(const char *eventre, int flags)
-{
-	if (flags && !eventre)
-		die("When specifying event files, an event must be named");
-
-	if (eventre) {
-		if (flags & SHOW_EVENT_FORMAT)
-			show_event_format_re(eventre);
-
-		else if (flags & SHOW_EVENT_FILTER)
-			show_event_filter_re(eventre);
-
-		else if (flags & SHOW_EVENT_TRIGGER)
-			show_event_trigger_re(eventre);
-		else
-			show_file_re("available_events", eventre);
-	} else
-		show_file("available_events");
-}
-
-static void show_tracers(void)
-{
-	show_file("available_tracers");
-}
-
-static void show_options(void)
-{
-	show_file("trace_options");
-}
-
-static void show_clocks(void)
-{
-	show_file("trace_clock");
-}
-
-static void show_functions(const char *funcre)
-{
-	if (funcre)
-		show_file_re("available_filter_functions", funcre);
-	else
-		show_file("available_filter_functions");
-}
-
-static void show_buffers(void)
-{
-	struct dirent *dent;
-	DIR *dir;
-	char *path;
-	int printed = 0;
-
-	path = tracecmd_get_tracing_file("instances");
-	dir = opendir(path);
-	tracecmd_put_tracing_file(path);
-	if (!dir)
-		die("Can not read instance directory");
-
-	while ((dent = readdir(dir))) {
-		const char *name = dent->d_name;
-
-		if (strcmp(name, ".") == 0 ||
-		    strcmp(name, "..") == 0)
-			continue;
-
-		printf("%s\n", name);
-		printed = 1;
-	}
-	closedir(dir);
-
-	if (!printed)
-		printf("No buffer instances defined\n");
-}
-
-static void show_plugins(void)
-{
-	struct pevent *pevent;
-	struct plugin_list *list;
-	struct trace_seq s;
-
-	pevent = pevent_alloc();
-	if (!pevent)
-		die("Can not allocate pevent\n");
-
-	trace_seq_init(&s);
-
-	list = tracecmd_load_plugins(pevent);
-	trace_util_print_plugins(&s, "  ", "\n", list);
-	trace_seq_do_printf(&s);
-	tracecmd_unload_plugins(list, pevent);
-	pevent_free(pevent);
-}
-
-static void show_plugin_options(void)
-{
-	struct pevent *pevent;
-	struct plugin_list *list;
-	struct trace_seq s;
-
-	tracecmd_ftrace_load_options();
-
-	pevent = pevent_alloc();
-	if (!pevent)
-		die("Can not allocate pevent\n");
-
-	trace_seq_init(&s);
-
-	list = tracecmd_load_plugins(pevent);
-	trace_util_print_plugin_options(&s);
-	trace_seq_do_printf(&s);
-	tracecmd_unload_plugins(list, pevent);
-	pevent_free(pevent);
-}
 
-enum {
-	OPT_tracing_on			= 255,
-	OPT_current_tracer		= 254,
-	OPT_buffer_size_kb		= 253,
-	OPT_buffer_total_size_kb	= 252,
-	OPT_ftrace_filter		= 251,
-	OPT_ftrace_notrace		= 250,
-	OPT_ftrace_pid			= 249,
-	OPT_graph_function		= 248,
-	OPT_graph_notrace		= 247,
-	OPT_cpumask			= 246,
+/**
+ * Lookup table that maps command names to functions
+ */
+struct command commands[] = {
+	{"report", trace_report},
+	{"snapshot", trace_snapshot},
+	{"hist", trace_hist},
+	{"mem", trace_mem},
+	{"listen", trace_listen},
+	{"split", trace_split},
+	{"restore", trace_restore},
+	{"stack", trace_stack},
+	{"check-events", trace_check_events},
+	{"record", trace_record},
+	{"start", trace_record},
+	{"extract", trace_record},
+	{"stop", trace_record},
+	{"stream", trace_record},
+	{"profile", trace_record},
+	{"restart", trace_record},
+	{"reset", trace_record},
+	{"stat", trace_stat},
+	{"options", trace_option},
+	{"show", trace_show},
+	{"list", trace_list},
+	{"help", trace_usage},
+	{"-h", trace_usage},
 };
 
+#define ARRAY_SIZE(_a) (sizeof(_a) / sizeof(_a[0]))
+
 int main (int argc, char **argv)
 {
-	int c;
+	int i;
 
 	errno = 0;
 
 	if (argc < 2)
-		usage(argv);
-
-	if (strcmp(argv[1], "report") == 0) {
-		trace_report(argc, argv);
-		exit(0);
-	} else if (strcmp(argv[1], "snapshot") == 0) {
-		trace_snapshot(argc, argv);
-		exit(0);
-	} else if (strcmp(argv[1], "hist") == 0) {
-		trace_hist(argc, argv);
-		exit(0);
-	} else if (strcmp(argv[1], "mem") == 0) {
-		trace_mem(argc, argv);
-		exit(0);
-	} else if (strcmp(argv[1], "listen") == 0) {
-		trace_listen(argc, argv);
-		exit(0);
-	} else if (strcmp(argv[1], "split") == 0) {
-		trace_split(argc, argv);
-		exit(0);
-	} else if (strcmp(argv[1], "restore") == 0) {
-		trace_restore(argc, argv);
-		exit(0);
-	} else if (strcmp(argv[1], "stack") == 0) {
-		trace_stack(argc, argv);
-		exit(0);
-	} else if (strcmp(argv[1], "check-events") == 0) {
-		const char *tracing;
-		int ret;
-		struct pevent *pevent = NULL;
-		struct plugin_list *list = NULL;
-
-		while ((c = getopt(argc-1, argv+1, "+hN")) >= 0) {
-			switch (c) {
-			case 'h':
-			default:
-				usage(argv);
-				break;
-			case 'N':
-				tracecmd_disable_plugins = 1;
-				break;
-			}
-		}
-		tracing = tracecmd_get_tracing_dir();
+		trace_usage(argc, argv);
 
-		if (!tracing) {
-			printf("Can not find or mount tracing directory!\n"
-				"Either tracing is not configured for this "
-				"kernel\n"
-				"or you do not have the proper permissions to "
-				"mount the directory");
-			exit(EINVAL);
-		}
-
-		pevent = pevent_alloc();
-		if (!pevent)
-			exit(EINVAL);
-		list = tracecmd_load_plugins(pevent);
-		ret = tracecmd_fill_local_events(tracing, pevent);
-		if (ret || pevent->parsing_failures)
-			ret = EINVAL;
-		tracecmd_unload_plugins(list, pevent);
-		pevent_free(pevent);
-		exit(ret);
-
-	} else if (strcmp(argv[1], "record") == 0 ||
-		   strcmp(argv[1], "start") == 0 ||
-		   strcmp(argv[1], "extract") == 0 ||
-		   strcmp(argv[1], "stop") == 0 ||
-		   strcmp(argv[1], "stream") == 0 ||
-		   strcmp(argv[1], "profile") == 0 ||
-		   strcmp(argv[1], "restart") == 0 ||
-		   strcmp(argv[1], "reset") == 0) {
-		trace_record(argc, argv);
-		exit(0);
-
-	} else if (strcmp(argv[1], "stat") == 0) {
-		trace_stat(argc, argv);
-		exit(0);
-
-	} else if (strcmp(argv[1], "options") == 0) {
-		show_plugin_options();
-		exit(0);
-	} else if (strcmp(argv[1], "show") == 0) {
-		const char *buffer = NULL;
-		const char *file = "trace";
-		const char *cpu = NULL;
-		struct buffer_instance *instance = &top_instance;
-		char cpu_path[128];
-		char *path;
-		int snap = 0;
-		int pipe = 0;
-		int show_name = 0;
-		int option_index = 0;
-		int stop = 0;
-		static struct option long_options[] = {
-			{"tracing_on", no_argument, NULL, OPT_tracing_on},
-			{"current_tracer", no_argument, NULL, OPT_current_tracer},
-			{"buffer_size", no_argument, NULL, OPT_buffer_size_kb},
-			{"buffer_total_size", no_argument, NULL, OPT_buffer_total_size_kb},
-			{"ftrace_filter", no_argument, NULL, OPT_ftrace_filter},
-			{"ftrace_notrace", no_argument, NULL, OPT_ftrace_notrace},
-			{"ftrace_pid", no_argument, NULL, OPT_ftrace_pid},
-			{"graph_function", no_argument, NULL, OPT_graph_function},
-			{"graph_notrace", no_argument, NULL, OPT_graph_notrace},
-			{"cpumask", no_argument, NULL, OPT_cpumask},
-			{"help", no_argument, NULL, '?'},
-			{NULL, 0, NULL, 0}
-		};
-
-		while ((c = getopt_long(argc-1, argv+1, "B:c:fsp",
-					long_options, &option_index)) >= 0) {
-			switch (c) {
-			case 'h':
-				usage(argv);
-				break;
-			case 'B':
-				if (buffer)
-					die("Can only show one buffer at a time");
-				buffer = optarg;
-				instance = create_instance(optarg);
-				break;
-			case 'c':
-				if (cpu)
-					die("Can only show one CPU at a time");
-				cpu = optarg;
-				break;
-			case 'f':
-				show_name = 1;
-				break;
-			case 's':
-				snap = 1;
-				if (pipe)
-					die("Can not have -s and -p together");
-				break;
-			case 'p':
-				pipe = 1;
-				if (snap)
-					die("Can not have -s and -p together");
-				break;
-			case OPT_tracing_on:
-				show_instance_file(instance, "tracing_on");
-				stop = 1;
-				break;
-			case OPT_current_tracer:
-				show_instance_file(instance, "current_tracer");
-				stop = 1;
-				break;
-			case OPT_buffer_size_kb:
-				show_instance_file(instance, "buffer_size_kb");
-				stop = 1;
-				break;
-			case OPT_buffer_total_size_kb:
-				show_instance_file(instance, "buffer_total_size_kb");
-				stop = 1;
-				break;
-			case OPT_ftrace_filter:
-				show_instance_file(instance, "set_ftrace_filter");
-				stop = 1;
-				break;
-			case OPT_ftrace_notrace:
-				show_instance_file(instance, "set_ftrace_notrace");
-				stop = 1;
-				break;
-			case OPT_ftrace_pid:
-				show_instance_file(instance, "set_ftrace_pid");
-				stop = 1;
-				break;
-			case OPT_graph_function:
-				show_instance_file(instance, "set_graph_function");
-				stop = 1;
-				break;
-			case OPT_graph_notrace:
-				show_instance_file(instance, "set_graph_notrace");
-				stop = 1;
-				break;
-			case OPT_cpumask:
-				show_instance_file(instance, "tracing_cpumask");
-				stop = 1;
-				break;
-			default:
-				usage(argv);
-			}
-		}
-		if (stop)
-			exit(0);
-		if (pipe)
-			file = "trace_pipe";
-		else if (snap)
-			file = "snapshot";
-
-		if (cpu) {
-			snprintf(cpu_path, 128, "per_cpu/cpu%d/%s", atoi(cpu), file);
-			file = cpu_path;
-		}
-			
-		if (buffer) {
-			path = malloc_or_die(strlen(buffer) + strlen("instances//") +
-					     strlen(file) + 1);
-			sprintf(path, "instances/%s/%s", buffer, file);
-			file = path;
-		}
-
-		if (show_name) {
-			char *name;
-			name = tracecmd_get_tracing_file(file);
-			printf("%s\n", name);
-			tracecmd_put_tracing_file(name);
-		}
-		show_file(file);
-		if (buffer)
-			free(path);
-
-		exit(0);
-	} else if (strcmp(argv[1], "list") == 0) {
-		int events = 0;
-		int tracer = 0;
-		int options = 0;
-		int funcs = 0;
-		int buffers = 0;
-		int clocks = 0;
-		int plug = 0;
-		int plug_op = 0;
-		int flags = 0;
-		int show_all = 1;
-		int i;
-		const char *arg;
-		const char *funcre = NULL;
-		const char *eventre = NULL;
-
-		for (i = 2; i < argc; i++) {
-			arg = NULL;
-			if (argv[i][0] == '-') {
-				if (i < argc - 1) {
-					if (argv[i+1][0] != '-')
-						arg = argv[i+1];
-				}
-				switch (argv[i][1]) {
-				case 'h':
-					usage(argv);
-					break;
-				case 'e':
-					events = 1;
-					eventre = arg;
-					show_all = 0;
-					break;
-				case 'B':
-					buffers = 1;
-					show_all = 0;
-					break;
-				case 'C':
-					clocks = 1;
-					show_all = 0;
-					break;
-				case 'F':
-					flags |= SHOW_EVENT_FORMAT;
-					break;
-				case 'R':
-					flags |= SHOW_EVENT_TRIGGER;
-					break;
-				case 'l':
-					flags |= SHOW_EVENT_FILTER;
-					break;
-				case 'p':
-				case 't':
-					tracer = 1;
-					show_all = 0;
-					break;
-				case 'P':
-					plug = 1;
-					show_all = 0;
-					break;
-				case 'O':
-					plug_op = 1;
-					show_all = 0;
-					break;
-				case 'o':
-					options = 1;
-					show_all = 0;
-					break;
-				case 'f':
-					funcs = 1;
-					funcre = arg;
-					show_all = 0;
-					break;
-				default:
-					fprintf(stderr, "list: invalid option -- '%c'\n",
-						argv[optind][1]);
-					usage(argv);
-				}
-			}
+	for (i = 0; i < ARRAY_SIZE(commands); ++i) {
+		if (strcmp(argv[1], commands[i].name) == 0 ){
+			commands[i].run(argc, argv);
+			goto out;
 		}
-
-		if (events)
-			show_events(eventre, flags);
-
-		if (tracer)
-			show_tracers();
-
-		if (options)
-			show_options();
-
-		if (plug)
-			show_plugins();
-
-		if (plug_op)
-			show_plugin_options();
-
-		if (funcs)
-			show_functions(funcre);
-
-		if (buffers)
-			show_buffers();
-
-		if (clocks)
-			show_clocks();
-
-		if (show_all) {
-			printf("events:\n");
-			show_events(NULL, 0);
-			printf("\ntracers:\n");
-			show_tracers();
-			printf("\noptions:\n");
-			show_options();
-		}
-
-		exit(0);
-
-	} else if (strcmp(argv[1], "-h") == 0 ||
-		   strcmp(argv[1], "help") == 0) {
-		usage(argv);
-	} else {
-		fprintf(stderr, "unknown command: %s\n", argv[1]);
-		usage(argv);
 	}
 
-	return 0;
+	/* No valid command found, show help */
+	trace_usage(argc, argv);
+out:
+	exit(0);
 }
-
diff -Nru trace-cmd-2.6/trace-cmd.h trace-cmd-2.6.1/trace-cmd.h
--- trace-cmd-2.6/trace-cmd.h	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-cmd.h	2017-05-02 19:35:16.000000000 +0200
@@ -20,8 +20,6 @@ 
 #ifndef _TRACE_CMD_H
 #define _TRACE_CMD_H
 
-#include <stdlib.h>
-#include "event-utils.h"
 #include "event-parse.h"
 
 #define TRACECMD_ERR_MSK	((unsigned long)(-1) & ~((1UL << 14) - 1))
@@ -29,10 +27,10 @@ 
 #define TRACECMD_ERROR(ret)	((void *)((unsigned long)(ret) | TRACECMD_ERR_MSK))
 #define TRACECMD_PTR2ERR(ptr)	((unisgned long)(ptr) & ~TRACECMD_ERR_MSK)
 
-void parse_cmdlines(struct pevent *pevent, char *file, int size);
-void parse_trace_clock(struct pevent *pevent, char *file, int size);
-void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size);
-void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size);
+void tracecmd_parse_cmdlines(struct pevent *pevent, char *file, int size);
+void tracecmd_parse_trace_clock(struct pevent *pevent, char *file, int size);
+void tracecmd_parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size);
+void tracecmd_parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size);
 
 extern int tracecmd_disable_sys_plugins;
 extern int tracecmd_disable_plugins;
@@ -63,6 +61,7 @@ 
 struct tracecmd_input;
 struct tracecmd_output;
 struct tracecmd_recorder;
+struct hook_list;
 
 static inline int tracecmd_host_bigendian(void)
 {
@@ -89,6 +88,7 @@ 
 	TRACECMD_OPTION_TRACECLOCK,
 	TRACECMD_OPTION_UNAME,
 	TRACECMD_OPTION_HOOK,
+	TRACECMD_OPTION_OFFSET,
 };
 
 enum {
@@ -104,6 +104,11 @@ 
 	int long_size;
 };
 
+typedef void (*tracecmd_show_data_func)(struct tracecmd_input *handle,
+					struct pevent_record *record);
+typedef void (*tracecmd_handle_init_func)(struct tracecmd_input *handle,
+					  struct hook_list *hook, int global);
+
 struct tracecmd_input *tracecmd_alloc(const char *file);
 struct tracecmd_input *tracecmd_alloc_fd(int fd);
 struct tracecmd_input *tracecmd_open(const char *file);
@@ -125,6 +130,11 @@ 
 const char *tracecmd_buffer_instance_name(struct tracecmd_input *handle, int indx);
 struct tracecmd_input *tracecmd_buffer_instance_handle(struct tracecmd_input *handle, int indx);
 int tracecmd_is_buffer_instance(struct tracecmd_input *handle);
+void tracecmd_create_top_instance(char *name);
+void tracecmd_remove_instances(void);
+
+void tracecmd_set_ts_offset(struct tracecmd_input *handle, unsigned long long offset);
+void tracecmd_set_ts2secs(struct tracecmd_input *handle, unsigned long long hz);
 
 void tracecmd_print_events(struct tracecmd_input *handle, const char *regex);
 
@@ -160,6 +170,9 @@ 
 tracecmd_read_next_data(struct tracecmd_input *handle, int *rec_cpu);
 
 struct pevent_record *
+tracecmd_peek_next_data(struct tracecmd_input *handle, int *rec_cpu);
+
+struct pevent_record *
 tracecmd_read_at(struct tracecmd_input *handle, unsigned long long offset,
 		 int *cpu);
 struct pevent_record *
@@ -186,6 +199,10 @@ 
 int tracecmd_ftrace_overrides(struct tracecmd_input *handle, struct tracecmd_ftrace *finfo);
 struct pevent *tracecmd_get_pevent(struct tracecmd_input *handle);
 bool tracecmd_get_use_trace_clock(struct tracecmd_input *handle);
+tracecmd_show_data_func
+tracecmd_get_show_data_func(struct tracecmd_input *handle);
+void tracecmd_set_show_data_func(struct tracecmd_input *handle,
+				 tracecmd_show_data_func func);
 
 char *tracecmd_get_tracing_file(const char *name);
 void tracecmd_put_tracing_file(char *name);
@@ -268,19 +285,36 @@ 
 void tracecmd_stop_recording(struct tracecmd_recorder *recorder);
 void tracecmd_stat_cpu(struct trace_seq *s, int cpu);
 long tracecmd_flush_recording(struct tracecmd_recorder *recorder);
+void tracecmd_filter_pid(int pid, int exclude);
+int tracecmd_add_event(const char *event_str, int stack);
+void tracecmd_enable_events(void);
+void tracecmd_disable_all_tracing(int disable_tracer);
+void tracecmd_disable_tracing(void);
+void tracecmd_enable_tracing(void);
+
+/* for clients */
+int tracecmd_msg_send_init_data(int fd);
+int tracecmd_msg_metadata_send(int fd, const char *buf, int size);
+int tracecmd_msg_finish_sending_metadata(int fd);
+void tracecmd_msg_send_close_msg(void);
+
+/* for server */
+int tracecmd_msg_initial_setting(int fd, int *cpus, int *pagesize);
+int tracecmd_msg_send_port_array(int fd, int total_cpus, int *ports);
+int tracecmd_msg_collect_metadata(int ifd, int ofd);
 
 /* --- Plugin handling --- */
 extern struct pevent_plugin_option trace_ftrace_options[];
 
-void trace_util_add_options(const char *name, struct pevent_plugin_option *options);
+int trace_util_add_options(const char *name, struct pevent_plugin_option *options);
 void trace_util_remove_options(struct pevent_plugin_option *options);
-void trace_util_add_option(const char *name, const char *val);
-void trace_util_load_plugins(struct pevent *pevent, const char *suffix,
-			     void (*load_plugin)(struct pevent *pevent,
-						 const char *path,
-						 const char *name,
-						 void *data),
-			     void *data);
+int trace_util_add_option(const char *name, const char *val);
+int trace_util_load_plugins(struct pevent *pevent, const char *suffix,
+			    int (*load_plugin)(struct pevent *pevent,
+					       const char *path,
+					       const char *name,
+					       void *data),
+			    void *data);
 struct pevent_plugin_option *trace_util_read_plugin_options(void);
 void trace_util_free_options(struct pevent_plugin_option *options);
 char **trace_util_find_plugin_files(const char *suffix);
diff -Nru trace-cmd-2.6/trace-cmd-local.h trace-cmd-2.6.1/trace-cmd-local.h
--- trace-cmd-2.6/trace-cmd-local.h	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-cmd-local.h	2017-05-02 19:35:16.000000000 +0200
@@ -23,6 +23,7 @@ 
 /* Local for trace-input.c and trace-output.c */
 
 #include "trace-cmd.h"
+#include "event-utils.h"
 
 static ssize_t __do_write(int fd, const void *data, size_t size)
 {
diff -Nru trace-cmd-2.6/trace-dialog.c trace-cmd-2.6.1/trace-dialog.c
--- trace-cmd-2.6/trace-dialog.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-dialog.c	2017-05-02 19:35:16.000000000 +0200
@@ -28,6 +28,7 @@ 
 #include "trace-compat.h"
 #include "trace-cmd.h"
 #include "trace-gui.h"
+#include "trace-local.h"
 
 #define DIALOG_WIDTH	500
 #define DIALOG_HEIGHT	550
@@ -209,9 +210,9 @@ 
 
 	g_string_append(str, "\n");
 
-	if (errno) {
+	if (err) {
 		g_string_prepend(str, "\n");
-		g_string_prepend(str, strerror(errno));
+		g_string_prepend(str, strerror(err));
 	}
 
 	errno = 0;
@@ -349,6 +350,9 @@ 
 		parent = GTK_WINDOW(parent_window);
 
 	switch (type) {
+	case TRACE_GUI_OTHER:
+		mtype = GTK_MESSAGE_OTHER;
+		break;
 	case TRACE_GUI_INFO:
 		mtype = GTK_MESSAGE_INFO;
 		break;
@@ -382,6 +386,51 @@ 
 	return result;
 }
 
+static void read_raw_events(struct trace_seq *s,
+			    struct event_format *event,
+			    struct pevent_record *record)
+{
+	struct format_field **fields;
+	int i;
+
+	fields = pevent_event_fields(event);
+	if (!fields)
+		return;
+
+	for (i = 0; fields[i]; i++) {
+		trace_seq_printf(s, "%s: ", fields[i]->name);
+		pevent_print_field(s, record->data, fields[i]);
+		trace_seq_putc(s, '\n');
+	}
+
+	free(fields);
+}
+
+void trace_show_record_dialog(GtkWindow *parent, struct pevent *pevent,
+			      struct pevent_record *record, gboolean raw)
+{
+	struct event_format *event;
+	struct trace_seq s;
+	int type;
+
+	trace_seq_init(&s);
+
+	type = pevent_data_type(pevent, record);
+	event = pevent_data_event_from_type(pevent, type);
+
+	if (raw)
+		read_raw_events(&s, event, record);
+	else
+		pevent_print_event(pevent, &s, record, FALSE);
+
+	if (s.buffer_size) {
+		trace_seq_terminate(&s);
+		trace_dialog(parent, TRACE_GUI_OTHER, s.buffer);
+	}
+
+	trace_seq_destroy(&s);
+}
+
 /**
  * trace_get_file_dialog - pop up a file dialog to get a file
  * @title: the title of the dialog
diff -Nru trace-cmd-2.6/trace-ftrace.c trace-cmd-2.6.1/trace-ftrace.c
--- trace-cmd-2.6/trace-ftrace.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-ftrace.c	2017-05-02 19:35:16.000000000 +0200
@@ -297,7 +297,7 @@ 
 	struct tracecmd_ftrace *finfo = context;
 	struct pevent_record *rec;
 	unsigned long long val, pid;
-	int cpu = record->cpu;
+	int cpu;
 
 	ret_event_check(finfo, event->pevent);
 
@@ -307,7 +307,7 @@ 
 	if (pevent_get_field_val(s, event, "func", record, &val, 1))
 		return trace_seq_putc(s, '!');
 
-	rec = tracecmd_peek_data(tracecmd_curr_thread_handle, cpu);
+	rec = tracecmd_peek_next_data(tracecmd_curr_thread_handle, &cpu);
 	if (rec)
 		rec = get_return_for_leaf(s, cpu, pid, val, rec, finfo);
 
diff -Nru trace-cmd-2.6/trace-graph.c trace-cmd-2.6.1/trace-graph.c
--- trace-cmd-2.6/trace-graph.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-graph.c	2017-05-02 19:35:16.000000000 +0200
@@ -18,12 +18,15 @@ 
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <gtk/gtk.h>
 
+#include <sys/time.h>
+
 #include "trace-compat.h"
 #include "trace-cmd.h"
 #include "trace-local.h"
@@ -45,6 +48,8 @@ 
 # define dprintf(l, x...)	do { if (0) printf(x); } while (0)
 #endif
 
+#define TIME_DRAW	0
+
 #define MAX_WIDTH	10000
 
 #define PLOT_SIZE	10
@@ -186,6 +191,8 @@ 
 	printf("%lu.%06lu", sec, usec);
 }
 
+static int null_int_array[] = { -1 };
+
 static void init_event_cache(struct graph_info *ginfo)
 {
 	ginfo->ftrace_sched_switch_id = -1;
@@ -193,6 +200,13 @@ 
 	ginfo->event_wakeup_id = -1;
 	ginfo->event_wakeup_new_id = -1;
 
+	ginfo->hard_irq_entry_ids = NULL;
+	ginfo->hard_irq_exit_ids = NULL;
+	ginfo->soft_irq_entry_ids = NULL;
+	ginfo->soft_irq_exit_ids = NULL;
+
+	ginfo->no_irqs = TRUE;
+
 	ginfo->event_pid_field = NULL;
 	ginfo->event_comm_field = NULL;
 	ginfo->ftrace_pid_field = NULL;
@@ -1140,6 +1154,107 @@ 
 	return ret;
 }
 
+static void enter_id(gint **ids, gint id, gint *len)
+{
+	*ids = realloc(*ids, sizeof(gint) * (*len + 2));
+	(*ids)[*len] = id;
+	(*len)++;
+	(*ids)[*len] = -1;
+}
+
+enum graph_irq_type
+trace_graph_check_irq(struct graph_info *ginfo,
+		      struct pevent_record *record)
+{
+	struct event_format *event;
+	struct event_format **events;
+	gint id;
+	int i;
+
+	if (!ginfo->hard_irq_entry_ids) {
+		gint hard_irq_entry_len = 0;
+		gint hard_irq_exit_len = 0;
+		gint soft_irq_entry_len = 0;
+		gint soft_irq_exit_len = 0;
+
+		event = pevent_find_event_by_name(ginfo->pevent,
+						  NULL, "irq_handler_exit");
+		if (event)
+			enter_id(&ginfo->hard_irq_exit_ids, event->id,
+				 &hard_irq_exit_len);
+		else
+			ginfo->hard_irq_exit_ids = null_int_array;
+
+		event = pevent_find_event_by_name(ginfo->pevent,
+						  NULL, "irq_handler_entry");
+		if (event)
+			enter_id(&ginfo->hard_irq_entry_ids, event->id,
+				 &hard_irq_entry_len);
+		else
+			ginfo->hard_irq_entry_ids = null_int_array;
+
+		event = pevent_find_event_by_name(ginfo->pevent,
+						  NULL, "softirq_exit");
+		if (event)
+			enter_id(&ginfo->soft_irq_exit_ids, event->id,
+				 &soft_irq_exit_len);
+		else
+			ginfo->soft_irq_exit_ids = null_int_array;
+
+		event = pevent_find_event_by_name(ginfo->pevent,
+						  NULL, "softirq_entry");
+		if (event)
+			enter_id(&ginfo->soft_irq_entry_ids, event->id,
+				 &soft_irq_entry_len);
+		else
+			ginfo->soft_irq_entry_ids = null_int_array;
+
+		events = pevent_list_events(ginfo->pevent, EVENT_SORT_SYSTEM);
+
+		for (i = 0; events[i]; i++) {
+			event = events[i];
+			if (strcmp(event->system, "irq_vectors") == 0) {
+				ginfo->no_irqs = FALSE;
+				break;
+			}
+		}
+
+		for (; events[i]; i++) {
+			event = events[i];
+			if (strcmp(event->system, "irq_vectors") != 0)
+				break;
+			if (strcmp(event->name + strlen(event->name) - 5,
+				   "_exit") == 0)
+				enter_id(&ginfo->hard_irq_exit_ids, event->id,
+					 &hard_irq_exit_len);
+			else if (strcmp(event->name + strlen(event->name) - 6,
+					"_entry") == 0)
+				enter_id(&ginfo->hard_irq_entry_ids, event->id,
+					 &hard_irq_entry_len);
+		}
+	}
+
+	id = pevent_data_type(ginfo->pevent, record);
+
+	for (i = 0; ginfo->hard_irq_exit_ids[i] != -1; i++)
+		if (id == ginfo->hard_irq_exit_ids[i])
+			return GRAPH_HARDIRQ_EXIT;
+
+	for (i = 0; ginfo->hard_irq_entry_ids[i] != -1; i++)
+		if (id == ginfo->hard_irq_entry_ids[i])
+			return GRAPH_HARDIRQ_ENTRY;
+
+	for (i = 0; ginfo->soft_irq_exit_ids[i] != -1; i++)
+		if (id == ginfo->soft_irq_exit_ids[i])
+			return GRAPH_SOFTIRQ_EXIT;
+
+	for (i = 0; ginfo->soft_irq_entry_ids[i] != -1; i++)
+		if (id == ginfo->soft_irq_entry_ids[i])
+			return GRAPH_SOFTIRQ_ENTRY;
+
+	return GRAPH_IRQ_NONE;
+}
+
 static void draw_info_box(struct graph_info *ginfo, const gchar *buffer,
 			  gint x, gint y)
 {
@@ -1213,16 +1328,13 @@ 
 static void draw_plot_info(struct graph_info *ginfo, struct graph_plot *plot,
 			   gint x, gint y)
 {
-	struct pevent *pevent;
-	guint64 time;
 	unsigned long sec, usec;
 	struct trace_seq s;
+	guint64 time;
 
 	time =  convert_x_to_time(ginfo, x);
 	convert_nano(time, &sec, &usec);
 
-	pevent = ginfo->pevent;
-
 	trace_seq_init(&s);
 
 	dprintf(3, "start=%llu end=%llu time=%llu\n",
@@ -1243,7 +1355,6 @@ 
 
 static void draw_latency(struct graph_info *ginfo, gint x, gint y)
 {
-	struct pevent *pevent;
 	unsigned long sec, usec;
 	struct trace_seq s;
 	gboolean neg;
@@ -1262,8 +1373,6 @@ 
 
 	convert_nano(time, &sec, &usec);
 
-	pevent = ginfo->pevent;
-
 	trace_seq_init(&s);
 	trace_seq_printf(&s, "Diff: %s%ld.%06lu secs", neg ? "-":"", sec, usec);
 
@@ -1311,7 +1420,7 @@ 
 	ginfo->start_x = (ginfo->view_start_time - ginfo->start_time) *
 		ginfo->resolution;
 
-	dprintf(1, "new resolution = %f\n", resolution);
+	dprintf(1, "new resolution = %.16f\n", resolution);
 	return 0;
 }
 
@@ -1726,16 +1835,9 @@ 
 }
 
 static void draw_plot_box(struct graph_info *ginfo, int i,
-			  unsigned long long start,
-			  unsigned long long end,
+			  gint x1, gint x2,
 			  gboolean fill, GdkGC *gc)
 {
-	gint x1;
-	gint x2;
-
-	x1 = convert_time_to_x(ginfo, start);
-	x2 = convert_time_to_x(ginfo, end);
-
 	gdk_draw_rectangle(ginfo->curr_pixmap, gc,
 			   fill,
 			   x1, PLOT_BOX_TOP(i),
@@ -1748,8 +1850,11 @@ 
 	static PangoFontDescription *font;
 	PangoLayout *layout;
 	static gint width_16;
-	struct plot_info info;
-	gint x;
+	struct plot_info *info;
+	gboolean skip_box = FALSE;
+	gboolean skip_line = FALSE;
+	gint x = 0;
+	gint x2;
 
 	/* Calculate the size of 16 characters */
 	if (!width_16) {
@@ -1766,25 +1871,46 @@ 
 		g_object_unref(layout);
 	}
 
-	trace_graph_plot_event(ginfo, plot, record, &info);
+	trace_graph_plot_event(ginfo, plot, record);
+	info = &plot->info;
 
-	if (info.box) {
-		if (info.bcolor != plot->last_color) {
-			plot->last_color = info.bcolor;
+	if (info->box) {
+		x = convert_time_to_x(ginfo, info->bstart);
+		x2 = convert_time_to_x(ginfo, info->bend);
+		skip_box = (x == x2 && x == info->last_box_x);
+		if (!skip_box && x == info->last_box_x)
+			x++;
+		info->last_box_x = x2;
+		skip_box = 0;
+		if (skip_box)
+			plot->last_color = -1;
+	}
+
+	if (info->box && !skip_box) {
+		if (info->bcolor != plot->last_color) {
+			plot->last_color = info->bcolor;
 			set_color(ginfo->draw, plot->gc, plot->last_color);
 		}
 
-		draw_plot_box(ginfo, plot->pos, info.bstart, info.bend,
-			      info.bfill, plot->gc);
+		draw_plot_box(ginfo, plot->pos, x, x2, info->bfill, plot->gc);
+	}
+
+	if (info->line) {
+		x = convert_time_to_x(ginfo, info->ltime);
+		skip_line = x == info->last_line_x;
+		info->last_line_x = x;
+		if (skip_line)
+			plot->last_color = -1;
 	}
 
-	if (info.line) {
-		if (info.lcolor != plot->last_color) {
-			plot->last_color = info.lcolor;
+	if (info->line && !skip_line) {
+
+		if (info->lcolor != plot->last_color) {
+			plot->last_color = info->lcolor;
 			set_color(ginfo->draw, plot->gc, plot->last_color);
 		}
 
-		x = draw_plot_line(ginfo, plot->pos, info.ltime, plot->gc);
+		x = draw_plot_line(ginfo, plot->pos, info->ltime, plot->gc);
 
 		/* Figure out if we can show the text for the previous record */
 
@@ -1803,13 +1929,14 @@ 
 		plot->p2 = plot->p3;
 	}
 
-	if (!record && plot->p2)
+	if (!skip_line && !skip_box && !record && plot->p2)
 		draw_event_label(ginfo, plot->pos,
 				 plot->p1, plot->p2, ginfo->draw_width, width_16, font);
 }
 
 static void draw_plots(struct graph_info *ginfo, gint new_width)
 {
+	struct timeval tv_start, tv_stop;
 	struct plot_list *list;
 	struct graph_plot *plot;
 	struct pevent_record *record;
@@ -1828,6 +1955,8 @@ 
 		plot->p2 = 0;
 		plot->p3 = 0;
 		plot->last_color = -1;
+		plot->info.last_line_x = -1;
+		plot->info.last_box_x = -1;
 
 		gdk_draw_line(ginfo->curr_pixmap, ginfo->draw->style->black_gc,
 			      0, PLOT_LINE(i), new_width, PLOT_LINE(i));
@@ -1840,6 +1969,7 @@ 
 	tracecmd_set_all_cpus_to_timestamp(ginfo->handle,
 					   ginfo->view_start_time);
 
+	gettimeofday(&tv_start, NULL);
 	trace_set_cursor(GDK_WATCH);
 
 	/* Shortcut if we don't have any task plots */
@@ -1901,6 +2031,14 @@ 
 		plot->gc = NULL;
 	}
 	trace_put_cursor();
+	gettimeofday(&tv_stop, NULL);
+	if (tv_start.tv_usec > tv_stop.tv_usec) {
+		tv_stop.tv_usec += 1000000;
+		tv_stop.tv_sec--;
+	}
+	if (TIME_DRAW)
+		printf("Time to draw: %ld.%06ld\n", tv_stop.tv_sec - tv_start.tv_sec,
+		       tv_stop.tv_usec - tv_start.tv_usec);
 }
 
 
@@ -2236,7 +2374,8 @@ 
 
 	gtk_widget_set_size_request(widget, ginfo->draw_width, ginfo->draw_height);
 
-	redraw_pixmap_backend(ginfo);
+	if (!ginfo->no_draw)
+		redraw_pixmap_backend(ginfo);
 
 	/* debug */
 	ginfo->hadj_value = gtk_adjustment_get_value(ginfo->hadj);
@@ -2379,6 +2518,13 @@ 
 	return info;
 }
 
+static void free_int_array(int **array)
+{
+	if (*array != null_int_array)
+		free(*array);
+	*array = NULL;
+}
+
 void trace_graph_free_info(struct graph_info *ginfo)
 {
 	if (ginfo->handle) {
@@ -2390,6 +2536,11 @@ 
 		ginfo->cursor = 0;
 	}
 	ginfo->handle = NULL;
+
+	free_int_array(&ginfo->hard_irq_entry_ids);
+	free_int_array(&ginfo->hard_irq_exit_ids);
+	free_int_array(&ginfo->soft_irq_entry_ids);
+	free_int_array(&ginfo->soft_irq_exit_ids);
 }
 
 static int load_handle(struct graph_info *ginfo,
diff -Nru trace-cmd-2.6/trace-graph.h trace-cmd-2.6.1/trace-graph.h
--- trace-cmd-2.6/trace-graph.h	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-graph.h	2017-05-02 19:35:16.000000000 +0200
@@ -39,6 +39,14 @@ 
 	PLOT_TYPE_TASK,
 };
 
+enum graph_irq_type {
+	GRAPH_IRQ_NONE,
+	GRAPH_HARDIRQ_ENTRY,
+	GRAPH_HARDIRQ_EXIT,
+	GRAPH_SOFTIRQ_ENTRY,
+	GRAPH_SOFTIRQ_EXIT
+};
+
 struct graph_plot;
 
 struct plot_info {
@@ -50,6 +58,8 @@ 
 	unsigned long long	bstart;
 	unsigned long long	bend;
 	gboolean		bfill;
+	gint			last_box_x;
+	gint			last_line_x;
 };
 
 /*
@@ -101,8 +111,7 @@ 
 		      unsigned long long time);
 	int (*plot_event)(struct graph_info *ginfo,
 			  struct graph_plot *plot,
-			  struct pevent_record *record,
-			  struct plot_info *info);
+			  struct pevent_record *record);
 	void (*end)(struct graph_info *, struct graph_plot *);
 	int (*display_last_event)(struct graph_info *ginfo, struct graph_plot *plot,
 				  struct trace_seq *s, unsigned long long time);
@@ -122,7 +131,8 @@ 
 	void				*private;
 
 	/* Used for drawing */
-	gint				 last_color;
+	struct plot_info		info;
+	gint				last_color;
 	gint				p1, p2, p3;
 	GdkGC				*gc;
 };
@@ -183,6 +193,8 @@ 
 	guint64			view_end_time;	/* visible end time */
 	gint			start_x;	/* virutal start of visible area */
 
+	gboolean		no_draw;	/* skip drawing the events */
+
 	guint64			cursor;		/* time of cursor (double clicked) */
 
 	gdouble			resolution;	/* pixels / time */
@@ -218,6 +230,10 @@ 
 	gint			event_sched_switch_id;
 	gint			event_wakeup_id;
 	gint			event_wakeup_new_id;
+	gint			*hard_irq_entry_ids;
+	gint			*hard_irq_exit_ids;
+	gint			*soft_irq_entry_ids;
+	gint			*soft_irq_exit_ids;
 	struct format_field	*event_prev_state;
 	struct format_field	*event_pid_field;
 	struct format_field	*event_comm_field;
@@ -228,6 +244,8 @@ 
 	struct format_field	*wakeup_new_pid_field;
 	struct format_field	*wakeup_new_success_field;
 
+	gboolean		no_irqs;
+
 	gboolean		read_comms;	/* Read all comms on first load */
 
 	struct filter_task	*task_filter;
@@ -298,6 +316,8 @@ 
 int trace_graph_check_sched_wakeup(struct graph_info *ginfo,
 				   struct pevent_record *record,
 				   gint *pid);
+enum graph_irq_type trace_graph_check_irq(struct graph_info *ginfo,
+		      struct pevent_record *record);
 gboolean trace_graph_filter_on_task(struct graph_info *ginfo, gint pid);
 gboolean trace_graph_filter_on_event(struct graph_info *ginfo, struct pevent_record *record);
 
@@ -362,8 +382,7 @@ 
 
 int trace_graph_plot_event(struct graph_info *ginfo,
 			   struct graph_plot *plot,
-			   struct pevent_record *record,
-			   struct plot_info *info);
+			   struct pevent_record *record);
 
 void trace_graph_plot_end(struct graph_info *ginfo,
 			  struct graph_plot *plot);
diff -Nru trace-cmd-2.6/trace-graph-main.c trace-cmd-2.6.1/trace-graph-main.c
--- trace-cmd-2.6/trace-graph-main.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-graph-main.c	2017-05-02 19:35:16.000000000 +0200
@@ -17,6 +17,7 @@ 
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
+#include <stdlib.h>
 #include <gtk/gtk.h>
 #include <getopt.h>
 #include <string.h>
@@ -26,6 +27,7 @@ 
 #include <libgen.h>
 
 #include "trace-cmd.h"
+#include "event-utils.h"
 #include "trace-graph.h"
 #include "trace-filter.h"
 #include "trace-gui.h"
@@ -481,7 +483,9 @@ 
 
 	gtk_widget_set_size_request(window, TRACE_WIDTH, TRACE_HEIGHT);
 
+	ginfo->no_draw = TRUE;
 	gtk_widget_show (window);
+	ginfo->no_draw = FALSE;
 	gtk_main ();
 }
 
diff -Nru trace-cmd-2.6/trace-gui.h trace-cmd-2.6.1/trace-gui.h
--- trace-cmd-2.6/trace-gui.h	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-gui.h	2017-05-02 19:35:16.000000000 +0200
@@ -23,6 +23,7 @@ 
 #include <gtk/gtk.h>
 
 enum trace_dialog_type {
+	TRACE_GUI_OTHER,
 	TRACE_GUI_INFO,
 	TRACE_GUI_WARNING,
 	TRACE_GUI_ERROR,
@@ -61,4 +62,10 @@ 
 		       GtkTreeModel *(*combo_model_create)(gpointer data),
 		       gpointer data);
 
+struct pevent;
+struct pevent_record;
+
+void trace_show_record_dialog(GtkWindow *parent, struct pevent *pevent,
+			      struct pevent_record *record, gboolean raw);
+
 #endif /* _TRACE_GUI */
diff -Nru trace-cmd-2.6/trace-hooks.c trace-cmd-2.6.1/trace-hooks.c
--- trace-cmd-2.6/trace-hooks.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-hooks.c	2017-05-02 19:35:16.000000000 +0200
@@ -19,9 +19,11 @@ 
  */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <ctype.h>
 
 #include "trace-cmd.h"
+#include "event-utils.h"
 
 struct hook_list *tracecmd_create_event_hook(const char *arg)
 {
@@ -37,12 +39,16 @@ 
 	int ch;
 	int i;
 
-	hook = malloc_or_die(sizeof(*hook));
+	hook = malloc(sizeof(*hook));
+	if (!hook)
+		return NULL;
 	memset(hook, 0, sizeof(*hook));
 
 	str = strdup(arg);
-	if (!str)
-		die("malloc");
+	if (!str) {
+		free(hook);
+		return NULL;
+	}
 
 	hook->str = str;
 	hook->hook = arg;
@@ -157,7 +163,7 @@ 
 	return hook;
 
 invalid_tok:
-	die("Invalid hook format '%s'", arg);
+	warning("Invalid hook format '%s'", arg);
 	return NULL;
 }
 
diff -Nru trace-cmd-2.6/trace-input.c trace-cmd-2.6.1/trace-input.c
--- trace-cmd-2.6/trace-input.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-input.c	2017-05-02 19:35:16.000000000 +0200
@@ -36,7 +36,10 @@ 
 #include <ctype.h>
 #include <errno.h>
 
+#include <linux/time64.h>
+
 #include "trace-cmd-local.h"
+#include "trace-local.h"
 #include "kbuffer.h"
 #include "list.h"
 
@@ -48,12 +51,22 @@ 
 /* for debugging read instead of mmap */
 static int force_read = 0;
 
+struct page_map {
+	struct list_head	list;
+	off64_t			offset;
+	off64_t			size;
+	void			*map;
+	int			ref_count;
+};
+
 struct page {
 	struct list_head	list;
 	off64_t			offset;
 	struct tracecmd_input	*handle;
+	struct page_map		*page_map;
 	void			*map;
 	int			ref_count;
+	int			cpu;
 	long long		lost_events;
 #if DEBUG_RECORD
 	struct pevent_record	*records;
@@ -67,7 +80,9 @@ 
 	unsigned long long	offset;
 	unsigned long long	size;
 	unsigned long long	timestamp;
+	struct list_head	page_maps;
 	struct list_head	pages;
+	struct page_map		*page_map;
 	struct pevent_record	*next;
 	struct page		*page;
 	struct kbuffer		*kbuf;
@@ -88,6 +103,7 @@ 
 	int			fd;
 	int			long_size;
 	int			page_size;
+	int			page_map_size;
 	int			cpus;
 	int			ref;
 	int			nr_buffers;	/* buffer instances */
@@ -96,6 +112,7 @@ 
 	bool			use_pipe;
 	struct cpu_data 	*cpu_data;
 	unsigned long long	ts_offset;
+	double			ts2secs;
 	char *			cpustats;
 	char *			uname;
 	struct input_buffer_instance	*buffers;
@@ -108,6 +125,9 @@ 
 	size_t			ftrace_files_start;
 	size_t			event_files_start;
 	size_t			total_file_size;
+
+	/* For custom profilers. */
+	tracecmd_show_data_func	show_data_func;
 };
 
 __thread struct tracecmd_input *tracecmd_curr_thread_handle;
@@ -365,8 +385,10 @@ 
 	int ret;
 
 	buf = malloc(size + 1);
-	if (!buf)
-		die("malloc");
+	if (!buf) {
+		warning("Insufficient memory");
+		return 0;
+	}
 
 	strncpy(buf, file, size);
 	buf[size] = 0;
@@ -464,7 +486,7 @@ 
 
 	buf = strdup(regex);
 	if (!buf)
-		die("malloc");
+		return -ENOMEM;
 
 	sstr = strtok(buf, ":");
 	estr = strtok(NULL, ":");
@@ -672,7 +694,7 @@ 
 	}
 	buf[size] = 0;
 
-	parse_proc_kallsyms(pevent, buf, size);
+	tracecmd_parse_proc_kallsyms(pevent, buf, size);
 
 	free(buf);
 	return 0;
@@ -700,7 +722,7 @@ 
 
 	buf[size] = 0;
 
-	parse_ftrace_printk(handle->pevent, buf, size);
+	tracecmd_parse_ftrace_printk(handle->pevent, buf, size);
 
 	free(buf);
 
@@ -792,12 +814,121 @@ 
 	return 0;
 }
 
+static unsigned long long normalize_size(unsigned long long size)
+{
+	/* page_map_size must be a power of two */
+	if (!(size & (size - 1)))
+		return size;
+
+	do {
+		size &= size - 1;
+	} while (size & (size - 1));
+
+	return size;
+}
+
+static void free_page_map(struct page_map *page_map)
+{
+	page_map->ref_count--;
+	if (page_map->ref_count)
+		return;
+
+	munmap(page_map->map, page_map->size);
+	list_del(&page_map->list);
+	free(page_map);
+}
+
+static void *allocate_page_map(struct tracecmd_input *handle,
+			       struct page *page, int cpu, off64_t offset)
+{
+	struct cpu_data *cpu_data = &handle->cpu_data[cpu];
+	struct page_map *page_map;
+	off64_t map_size;
+	off64_t map_offset;
+	void *map;
+	int ret;
+
+	if (handle->read_page) {
+		map = malloc(handle->page_size);
+		if (!map)
+			return NULL;
+		ret = read_page(handle, offset, cpu, map);
+		if (ret < 0) {
+			free(map);
+			return NULL;
+		}
+		return map;
+	}
+
+	map_size = handle->page_map_size;
+	map_offset = offset & ~(map_size - 1);
+
+	if (map_offset < cpu_data->file_offset) {
+		map_size -= cpu_data->file_offset - map_offset;
+		map_offset = cpu_data->file_offset;
+	}
+
+	page_map = cpu_data->page_map;
+
+	if (page_map && page_map->offset == map_offset)
+		goto out;
+
+	list_for_each_entry(page_map, &cpu_data->page_maps, list) {
+		if (page_map->offset == map_offset)
+			goto out;
+	}
+
+	page_map = calloc(1, sizeof(*page_map));
+	if (!page_map)
+		return NULL;
+
+	if (map_offset + map_size > cpu_data->file_offset + cpu_data->file_size)
+		map_size -= map_offset + map_size -
+			(cpu_data->file_offset + cpu_data->file_size);
+
+ again:
+	page_map->size = map_size;
+	page_map->offset = map_offset;
+
+	page_map->map = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE,
+			 handle->fd, map_offset);
+
+	if (page->map == MAP_FAILED) {
+		/* Try a smaller map */
+		map_size >>= 1;
+		if (map_size < handle->page_size) {
+			free(page_map);
+			return NULL;
+		}
+		handle->page_map_size = map_size;
+		map_offset = offset & ~(map_size - 1);
+		/*
+		 * Note, it is now possible to get duplicate memory
+		 * maps. But that's fine, the previous maps with
+		 * larger sizes will eventually be unmapped.
+		 */
+		goto again;
+	}
+
+	list_add(&page_map->list, &cpu_data->page_maps);
+ out:
+	if (cpu_data->page_map != page_map) {
+		struct page_map *old_map = cpu_data->page_map;
+		cpu_data->page_map = page_map;
+		page_map->ref_count++;
+		if (old_map)
+			free_page_map(old_map);
+	}
+	page->page_map = page_map;
+	page_map->ref_count++;
+	return page_map->map + offset - page_map->offset;
+}
+
 static struct page *allocate_page(struct tracecmd_input *handle,
 				  int cpu, off64_t offset)
 {
 	struct cpu_data *cpu_data = &handle->cpu_data[cpu];
 	struct page *page;
-	int ret;
 
 	list_for_each_entry(page, &cpu_data->pages, list) {
 		if (page->offset == offset) {
@@ -813,22 +944,9 @@ 
 	memset(page, 0, sizeof(*page));
 	page->offset = offset;
 	page->handle = handle;
+	page->cpu = cpu;
 
-	if (handle->read_page) {
-		page->map = malloc(handle->page_size);
-		if (page->map) {
-			ret = read_page(handle, offset, cpu, page->map);
-			if (ret < 0) {
-				free(page->map);
-				page->map = NULL;
-			}
-		}
-	} else {
-		page->map = mmap(NULL, handle->page_size, PROT_READ, MAP_PRIVATE,
-				 handle->fd, offset);
-		if (page->map == MAP_FAILED)
-			page->map = NULL;
-	}
+	page->map = allocate_page_map(handle, page, cpu, offset);
 
 	if (!page->map) {
 		free(page);
@@ -853,7 +971,7 @@ 
 	if (handle->read_page)
 		free(page->map);
 	else
-		munmap(page->map, handle->page_size);
+		free_page_map(page->page_map);
 
 	list_del(&page->list);
 	free(page);
@@ -944,11 +1062,16 @@ 
 	}
 
 	kbuffer_load_subbuffer(kbuf, ptr);
-	if (kbuffer_subbuffer_size(kbuf) > handle->page_size)
-		die("bad page read, with size of %d",
+	if (kbuffer_subbuffer_size(kbuf) > handle->page_size) {
+		warning("bad page read, with size of %d",
 		    kbuffer_subbuffer_size(kbuf));
+		return -1;
+	}
 	handle->cpu_data[cpu].timestamp = kbuffer_timestamp(kbuf) + handle->ts_offset;
 
+	if (handle->ts2secs)
+		handle->cpu_data[cpu].timestamp *= handle->ts2secs;
+
 	return 0;
 }
 
@@ -1669,6 +1792,11 @@ 
 
 	handle->cpu_data[cpu].timestamp = ts + handle->ts_offset;
 
+	if (handle->ts2secs) {
+		handle->cpu_data[cpu].timestamp *= handle->ts2secs;
+		ts *= handle->ts2secs;
+	}
+
 	index = kbuffer_curr_offset(kbuf);
 
 	record = malloc(sizeof(*record));
@@ -1743,31 +1871,57 @@ 
 struct pevent_record *
 tracecmd_read_next_data(struct tracecmd_input *handle, int *rec_cpu)
 {
-	unsigned long long ts;
 	struct pevent_record *record;
-	int first_record = 1;
-	int next;
+	int next_cpu;
+
+	record = tracecmd_peek_next_data(handle, &next_cpu);
+	if (!record)
+		return NULL;
+
+	if (rec_cpu)
+		*rec_cpu = next_cpu;
+
+	return tracecmd_read_data(handle, next_cpu);
+}
+
+/**
+ * tracecmd_peek_next_data - return the next record
+ * @handle: input handle to the trace.dat file
+ * @rec_cpu: return pointer to the CPU that the record belongs to
+ *
+ * This returns the next record by time. This is different than
+ * tracecmd_peek_data in that it looks at all CPUs. It does a peek
+ * at each CPU and the record with the earliest time stame is
+ * returned. If @rec_cpu is not NULL it gets the CPU id the record was
+ * on. It does not increment the CPU iterator.
+ */
+struct pevent_record *
+tracecmd_peek_next_data(struct tracecmd_input *handle, int *rec_cpu)
+{
+	unsigned long long ts;
+	struct pevent_record *record, *next_record = NULL;
+	int next_cpu;
 	int cpu;
 
 	if (rec_cpu)
 		*rec_cpu = -1;
 
-	next = -1;
+	next_cpu = -1;
 	ts = 0;
 
 	for (cpu = 0; cpu < handle->cpus; cpu++) {
 		record = tracecmd_peek_data(handle, cpu);
-		if (record && (first_record || record->ts < ts)) {
+		if (record && (!next_record || record->ts < ts)) {
 			ts = record->ts;
-			next = cpu;
-			first_record = 0;
+			next_cpu = cpu;
+			next_record = record;
 		}
 	}
 
-	if (next >= 0) {
+	if (next_record) {
 		if (rec_cpu)
-			*rec_cpu = next;
-		return tracecmd_read_data(handle, next);
+			*rec_cpu = next_cpu;
+		return next_record;
 	}
 
 	return NULL;
@@ -1881,6 +2035,7 @@ 
 	cpu_data->timestamp = 0;
 
 	list_head_init(&cpu_data->pages);
+	list_head_init(&cpu_data->page_maps);
 
 	if (!cpu_data->size) {
 		printf("CPU %d is empty\n", cpu);
@@ -1929,6 +2084,22 @@ 
 	return 0;
 }
 
+void tracecmd_set_ts_offset(struct tracecmd_input *handle,
+			    unsigned long long offset)
+{
+	handle->ts_offset = offset;
+}
+
+void tracecmd_set_ts2secs(struct tracecmd_input *handle,
+			 unsigned long long hz)
+{
+	double ts2secs;
+
+	ts2secs = (double)NSEC_PER_SEC / (double)hz;
+	handle->ts2secs = ts2secs;
+	handle->use_trace_clock = false;
+}
+
 static int handle_options(struct tracecmd_input *handle)
 {
 	unsigned long long offset;
@@ -1951,7 +2122,9 @@ 
 		if (do_read_check(handle, &size, 4))
 			return -1;
 		size = __data2host4(handle->pevent, size);
-		buf = malloc_or_die(size);
+		buf = malloc(size);
+		if (!buf)
+			return -ENOMEM;
 		if (do_read_check(handle, buf, size))
 			return -1;
 
@@ -1968,13 +2141,23 @@ 
 			offset = strtoll(buf, NULL, 0);
 			/* Convert from micro to nano */
 			offset *= 1000;
-			handle->ts_offset = offset;
+			handle->ts_offset += offset;
+			break;
+		case TRACECMD_OPTION_OFFSET:
+			/*
+			 * Similar to date option, but just adds an
+			 * offset to the timestamp.
+			 */
+			if (handle->flags & TRACECMD_FL_IGNORE_DATE)
+				break;
+			offset = strtoll(buf, NULL, 0);
+			handle->ts_offset += offset;
 			break;
 		case TRACECMD_OPTION_CPUSTAT:
 			buf[size-1] = '\n';
 			cpustats = realloc(cpustats, cpustats_size + size + 1);
 			if (!cpustats)
-				die("realloc");
+				return -ENOMEM;
 			memcpy(cpustats + cpustats_size, buf, size);
 			cpustats_size += size;
 			cpustats[cpustats_size] = 0;
@@ -1985,16 +2168,20 @@ 
 			handle->buffers = realloc(handle->buffers,
 						  sizeof(*handle->buffers) * handle->nr_buffers);
 			if (!handle->buffers)
-				die("realloc");
+				return -ENOMEM;
 			buffer = &handle->buffers[handle->nr_buffers - 1];
 			buffer->name = strdup(buf + 8);
-			if (!buffer->name)
-				die("strdup");
+			if (!buffer->name) {
+				free(handle->buffers);
+				handle->buffers = NULL;
+				return -ENOMEM;
+			}
 			offset = *(unsigned long long *)buf;
 			buffer->offset = __data2host8(handle->pevent, offset);
 			break;
 		case TRACECMD_OPTION_TRACECLOCK:
-			handle->use_trace_clock = true;
+			if (!handle->ts2secs)
+				handle->use_trace_clock = true;
 			break;
 		case TRACECMD_OPTION_UNAME:
 			handle->uname = strdup(buf);
@@ -2024,6 +2211,8 @@ 
 	enum kbuffer_long_size long_size;
 	enum kbuffer_endian endian;
 	unsigned long long size;
+	unsigned long long max_size = 0;
+	unsigned long long pages;
 	char buf[10];
 	int cpu;
 
@@ -2084,6 +2273,8 @@ 
 
 		handle->cpu_data[cpu].file_offset = offset;
 		handle->cpu_data[cpu].file_size = size;
+		if (size > max_size)
+			max_size = size;
 
 		if (size && (offset + size > handle->total_file_size)) {
 			/* this happens if the file got truncated */
@@ -2093,7 +2284,19 @@ 
 			errno = EINVAL;
 			goto out_free;
 		}
+	}
 
+	/* Calculate about a meg of pages for buffering */
+	pages = handle->page_size ? max_size / handle->page_size : 0;
+	if (!pages)
+		pages = 1;
+	pages = normalize_size(pages);
+	handle->page_map_size = handle->page_size * pages;
+	if (handle->page_map_size < handle->page_size)
+		handle->page_map_size = handle->page_size;
+
+
+	for (cpu = 0; cpu < handle->cpus; cpu++) {
 		if (init_cpu(handle, cpu))
 			goto out_free;
 	}
@@ -2135,7 +2338,7 @@ 
 	if (read_data_and_size(handle, &cmdlines, &size) < 0)
 		return -1;
 	cmdlines[size] = 0;
-	parse_cmdlines(pevent, cmdlines, size);
+	tracecmd_parse_cmdlines(pevent, cmdlines, size);
 	free(cmdlines);
 	return 0;
 }
@@ -2149,7 +2352,7 @@ 
 	if (read_data_and_size(handle, &trace_clock, &size) < 0)
 		return -1;
 	trace_clock[size] = 0;
-	parse_trace_clock(pevent, trace_clock, size);
+	tracecmd_parse_trace_clock(pevent, trace_clock, size);
 	free(trace_clock);
 	return 0;
 }
@@ -2186,7 +2389,7 @@ 
 		if (read_and_parse_trace_clock(handle, pevent) < 0) {
 			char clock[] = "[local]";
 			warning("File has trace_clock bug, using local clock");
-			parse_trace_clock(pevent, clock, 8);
+			tracecmd_parse_trace_clock(pevent, clock, 8);
 		}
 	}
 
@@ -2542,6 +2745,8 @@ 
 		free_page(handle, cpu);
 		if (handle->cpu_data && handle->cpu_data[cpu].kbuf) {
 			kbuffer_free(handle->cpu_data[cpu].kbuf);
+			if (handle->cpu_data[cpu].page_map)
+				free_page_map(handle->cpu_data[cpu].page_map);
 
 			if (!list_empty(&handle->cpu_data[cpu].pages))
 				warning("pages still allocated on cpu %d%s",
@@ -3001,3 +3206,23 @@ 
 {
 	return handle->use_trace_clock;
 }
+
+/**
+ * tracecmd_get_show_data_func - return the show data func
+ * @handle: input handle for the trace.dat file
+ */
+tracecmd_show_data_func
+tracecmd_get_show_data_func(struct tracecmd_input *handle)
+{
+	return handle->show_data_func;
+}
+
+/**
+ * tracecmd_set_show_data_func - set the show data func
+ * @handle: input handle for the trace.dat file
+ */
+void tracecmd_set_show_data_func(struct tracecmd_input *handle,
+				 tracecmd_show_data_func func)
+{
+	handle->show_data_func = func;
+}
diff -Nru trace-cmd-2.6/trace-list.c trace-cmd-2.6.1/trace-list.c
--- trace-cmd-2.6/trace-list.c	1970-01-01 01:00:00.000000000 +0100
+++ trace-cmd-2.6.1/trace-list.c	2017-05-02 19:35:16.000000000 +0200
@@ -0,0 +1,492 @@ 
+/*
+ * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License (not later!)
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not,  see <http://www.gnu.org/licenses>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <stdlib.h>
+
+#include "trace-local.h"
+
+
+static void dump_file_content(const char *path)
+{
+	char buf[BUFSIZ];
+	ssize_t n;
+	FILE *fp;
+
+	fp = fopen(path, "r");
+	if (!fp)
+		die("reading %s", path);
+
+	do {
+		n = fread(buf, 1, BUFSIZ, fp);
+		if (n > 0)
+			fwrite(buf, 1, n, stdout);
+	} while (n > 0);
+	fclose(fp);
+}
+
+
+
+void show_instance_file(struct buffer_instance *instance, const char *name)
+{
+	char *path;
+
+	path = get_instance_file(instance, name);
+	dump_file_content(path);
+	tracecmd_put_tracing_file(path);
+}
+
+enum {
+	SHOW_EVENT_FORMAT		= 1 << 0,
+	SHOW_EVENT_FILTER		= 1 << 1,
+	SHOW_EVENT_TRIGGER		= 1 << 2,
+};
+
+
+void show_file(const char *name)
+{
+	char *path;
+
+	path = tracecmd_get_tracing_file(name);
+	dump_file_content(path);
+	tracecmd_put_tracing_file(path);
+}
+
+typedef int (*process_file_func)(char *buf, int len);
+
+static void process_file_re(process_file_func func,
+			    const char *name, const char *re)
+{
+	regex_t reg;
+	char *path;
+	char *buf = NULL;
+	char *str;
+	FILE *fp;
+	ssize_t n;
+	size_t l = strlen(re);
+
+	/* Just in case :-p */
+	if (!re || l == 0) {
+		show_file(name);
+		return;
+	}
+
+	/* Handle the newline at end of names for the user */
+	str = malloc(l + 3);
+	if (!str)
+		die("Failed to allocate reg ex %s", re);
+	strcpy(str, re);
+	if (re[l-1] == '$')
+		strcpy(&str[l-1], "\n*$");
+
+	if (regcomp(&reg, str, REG_ICASE|REG_NOSUB))
+		die("invalid function regex '%s'", re);
+
+	free(str);
+
+	path = tracecmd_get_tracing_file(name);
+	fp = fopen(path, "r");
+	if (!fp)
+		die("reading %s", path);
+	tracecmd_put_tracing_file(path);
+
+	do {
+		n = getline(&buf, &l, fp);
+		if (n > 0 && regexec(&reg, buf, 0, NULL, 0) == 0)
+			func(buf, n);
+	} while (n > 0);
+	free(buf);
+	fclose(fp);
+
+	regfree(&reg);
+}
+
+static int show_file_write(char *buf, int len)
+{
+	return fwrite(buf, 1, len, stdout);
+}
+
+static void show_file_re(const char *name, const char *re)
+{
+	process_file_re(show_file_write, name, re);
+}
+
+static char *get_event_file(const char *type, char *buf, int len)
+{
+	char *system;
+	char *event;
+	char *path;
+	char *file;
+
+	if (buf[len-1] == '\n')
+		buf[len-1] = '\0';
+
+	system = strtok(buf, ":");
+	if (!system)
+		die("no system found in %s", buf);
+
+	event = strtok(NULL, ":");
+	if (!event)
+		die("no event found in %s\n", buf);
+
+	path = tracecmd_get_tracing_file("events");
+	file = malloc(strlen(path) + strlen(system) + strlen(event) +
+		      strlen(type) + strlen("///") + 1);
+	if (!file)
+		die("Failed to allocate event file %s %s", system, event);
+	sprintf(file, "%s/%s/%s/%s", path, system, event, type);
+	tracecmd_put_tracing_file(path);
+
+	return file;
+}
+
+static int event_filter_write(char *buf, int len)
+{
+	char *file;
+
+	if (buf[len-1] == '\n')
+		buf[len-1] = '\0';
+
+	printf("%s\n", buf);
+
+	file = get_event_file("filter", buf, len);
+	dump_file_content(file);
+	free(file);
+	printf("\n");
+
+	return 0;
+}
+
+static int event_trigger_write(char *buf, int len)
+{
+	char *file;
+
+	if (buf[len-1] == '\n')
+		buf[len-1] = '\0';
+
+	printf("%s\n", buf);
+
+	file = get_event_file("trigger", buf, len);
+	dump_file_content(file);
+	free(file);
+	printf("\n");
+
+	return 0;
+}
+
+static int event_format_write(char *fbuf, int len)
+{
+	char *file = get_event_file("format", fbuf, len);
+	char *buf = NULL;
+	size_t l;
+	FILE *fp;
+	int n;
+
+	/* The get_event_file() crops system in fbuf */
+	printf("system: %s\n", fbuf);
+
+	/* Don't print the print fmt, it's ugly */
+
+	fp = fopen(file, "r");
+	if (!fp)
+		die("reading %s", file);
+
+	do {
+		n = getline(&buf, &l, fp);
+		if (n > 0) {
+			if (strncmp(buf, "print fmt", 9) == 0)
+				break;
+			fwrite(buf, 1, n, stdout);
+		}
+	} while (n > 0);
+	fclose(fp);
+	free(buf);
+	free(file);
+
+	return 0;
+}
+
+
+static void show_event_filter_re(const char *re)
+{
+	process_file_re(event_filter_write, "available_events", re);
+}
+
+
+static void show_event_trigger_re(const char *re)
+{
+	process_file_re(event_trigger_write, "available_events", re);
+}
+
+
+static void show_event_format_re(const char *re)
+{
+	process_file_re(event_format_write, "available_events", re);
+}
+
+
+static void show_events(const char *eventre, int flags)
+{
+	if (flags && !eventre)
+		die("When specifying event files, an event must be named");
+
+	if (eventre) {
+		if (flags & SHOW_EVENT_FORMAT)
+			show_event_format_re(eventre);
+
+		else if (flags & SHOW_EVENT_FILTER)
+			show_event_filter_re(eventre);
+
+		else if (flags & SHOW_EVENT_TRIGGER)
+			show_event_trigger_re(eventre);
+		else
+			show_file_re("available_events", eventre);
+	} else
+		show_file("available_events");
+}
+
+
+static void show_tracers(void)
+{
+	show_file("available_tracers");
+}
+
+
+static void show_options(void)
+{
+	show_file("trace_options");
+}
+
+
+static void show_clocks(void)
+{
+	show_file("trace_clock");
+}
+
+
+static void show_functions(const char *funcre)
+{
+	if (funcre)
+		show_file_re("available_filter_functions", funcre);
+	else
+		show_file("available_filter_functions");
+}
+
+
+static void show_buffers(void)
+{
+	struct dirent *dent;
+	DIR *dir;
+	char *path;
+	int printed = 0;
+
+	path = tracecmd_get_tracing_file("instances");
+	dir = opendir(path);
+	tracecmd_put_tracing_file(path);
+	if (!dir)
+		die("Can not read instance directory");
+
+	while ((dent = readdir(dir))) {
+		const char *name = dent->d_name;
+
+		if (strcmp(name, ".") == 0 ||
+		    strcmp(name, "..") == 0)
+			continue;
+
+		printf("%s\n", name);
+		printed = 1;
+	}
+	closedir(dir);
+
+	if (!printed)
+		printf("No buffer instances defined\n");
+}
+
+
+static void show_plugin_options(void)
+{
+	struct pevent *pevent;
+	struct plugin_list *list;
+	struct trace_seq s;
+
+	tracecmd_ftrace_load_options();
+
+	pevent = pevent_alloc();
+	if (!pevent)
+		die("Can not allocate pevent\n");
+
+	trace_seq_init(&s);
+
+	list = tracecmd_load_plugins(pevent);
+	trace_util_print_plugin_options(&s);
+	trace_seq_do_printf(&s);
+	tracecmd_unload_plugins(list, pevent);
+	pevent_free(pevent);
+}
+
+
+void trace_option(int argc, char **argv)
+{
+	show_plugin_options();
+}
+
+
+static void show_plugins(void)
+{
+	struct pevent *pevent;
+	struct plugin_list *list;
+	struct trace_seq s;
+
+	pevent = pevent_alloc();
+	if (!pevent)
+		die("Can not allocate pevent\n");
+
+	trace_seq_init(&s);
+
+	list = tracecmd_load_plugins(pevent);
+	trace_util_print_plugins(&s, "  ", "\n", list);
+	trace_seq_do_printf(&s);
+	tracecmd_unload_plugins(list, pevent);
+	pevent_free(pevent);
+}
+
+
+void trace_list(int argc, char **argv)
+{
+	int events = 0;
+	int tracer = 0;
+	int options = 0;
+	int funcs = 0;
+	int buffers = 0;
+	int clocks = 0;
+	int plug = 0;
+	int plug_op = 0;
+	int flags = 0;
+	int show_all = 1;
+	int i;
+	const char *arg;
+	const char *funcre = NULL;
+	const char *eventre = NULL;
+
+	for (i = 2; i < argc; i++) {
+		arg = NULL;
+		if (argv[i][0] == '-') {
+			if (i < argc - 1) {
+				if (argv[i+1][0] != '-')
+					arg = argv[i+1];
+			}
+			switch (argv[i][1]) {
+			case 'h':
+				usage(argv);
+				break;
+			case 'e':
+				events = 1;
+				eventre = arg;
+				show_all = 0;
+				break;
+			case 'B':
+				buffers = 1;
+				show_all = 0;
+				break;
+			case 'C':
+				clocks = 1;
+				show_all = 0;
+				break;
+			case 'F':
+				flags |= SHOW_EVENT_FORMAT;
+				break;
+			case 'R':
+				flags |= SHOW_EVENT_TRIGGER;
+				break;
+			case 'l':
+				flags |= SHOW_EVENT_FILTER;
+				break;
+			case 'p':
+			case 't':
+				tracer = 1;
+				show_all = 0;
+				break;
+			case 'P':
+				plug = 1;
+				show_all = 0;
+				break;
+			case 'O':
+				plug_op = 1;
+				show_all = 0;
+				break;
+			case 'o':
+				options = 1;
+				show_all = 0;
+				break;
+			case 'f':
+				funcs = 1;
+				funcre = arg;
+				show_all = 0;
+				break;
+			case '-':
+				if (strcmp(argv[i], "--debug") == 0) {
+					debug = true;
+					break;
+				}
+				fprintf(stderr, "list: invalid option -- '%s'\n",
+					argv[i]);
+			default:
+				fprintf(stderr, "list: invalid option -- '%c'\n",
+					argv[i][1]);
+				usage(argv);
+			}
+		}
+	}
+
+	if (events)
+		show_events(eventre, flags);
+
+	if (tracer)
+		show_tracers();
+
+	if (options)
+		show_options();
+
+	if (plug)
+		show_plugins();
+
+	if (plug_op)
+		show_plugin_options();
+
+	if (funcs)
+		show_functions(funcre);
+
+	if (buffers)
+		show_buffers();
+
+	if (clocks)
+		show_clocks();
+
+	if (show_all) {
+		printf("events:\n");
+		show_events(NULL, 0);
+		printf("\ntracers:\n");
+		show_tracers();
+		printf("\noptions:\n");
+		show_options();
+	}
+
+	return;
+
+}
diff -Nru trace-cmd-2.6/trace-listen.c trace-cmd-2.6.1/trace-listen.c
--- trace-cmd-2.6/trace-listen.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-listen.c	2017-05-02 19:35:16.000000000 +0200
@@ -33,9 +33,15 @@ 
 #include <errno.h>
 
 #include "trace-local.h"
+#include "trace-msg.h"
 
 #define MAX_OPTION_SIZE 4096
 
+#define _VAR_DIR_Q(dir)		#dir
+#define VAR_DIR_Q(dir)		_VAR_DIR_Q(dir)
+
+#define VAR_RUN_DIR		VAR_DIR_Q(VAR_DIR) "/run"
+
 static char *default_output_dir = ".";
 static char *output_dir;
 static char *default_output_file = "trace";
@@ -43,11 +49,11 @@ 
 
 static FILE *logfp;
 
-static int debug;
+static int backlog = 5;
 
-static int use_tcp;
+static int proto_ver;
 
-static int backlog = 5;
+static int do_daemon;
 
 #define  TEMP_FILE_STR "%s.%s:%s.cpu%d", output_file, host, port, cpu
 static char *get_temp_file(const char *host, const char *port, int cpu)
@@ -56,7 +62,9 @@ 
 	int size;
 
 	size = snprintf(file, 0, TEMP_FILE_STR);
-	file = malloc_or_die(size + 1);
+	file = malloc(size + 1);
+	if (!file)
+		return NULL;
 	sprintf(file, TEMP_FILE_STR);
 
 	return file;
@@ -112,10 +120,9 @@ 
 	return 0;
 }
 
-static int done;
 static void finish(int sig)
 {
-	done = 1;
+	done = true;
 }
 
 #define LOG_BUF_SIZE 1024
@@ -144,16 +151,36 @@ 
 	fprintf(fp, "%.*s", r, buf);
 }
 
-static void plog(const char *fmt, ...)
+void plog(const char *fmt, ...)
 {
 	va_list ap;
 
 	va_start(ap, fmt);
 	__plog("", fmt, ap, stdout);
 	va_end(ap);
+	/* Make sure it gets to the screen, in case we crash afterward */
+	fflush(stdout);
+}
+
+static void make_pid_name(int mode, char *buf)
+{
+	snprintf(buf, PATH_MAX, VAR_RUN_DIR "/trace-cmd-net.pid");
 }
 
-static void pdie(const char *fmt, ...)
+static void remove_pid_file(void)
+{
+	char buf[PATH_MAX];
+	int mode = do_daemon;
+
+	if (!do_daemon)
+		return;
+
+	make_pid_name(mode, buf);
+
+	unlink(buf);
+}
+
+void pdie(const char *fmt, ...)
 {
 	va_list ap;
 	char *str = "";
@@ -167,11 +194,14 @@ 
 		fprintf(logfp, "\n%s\n", str);
 	else
 		fprintf(stderr, "\n%s\n", str);
+
+	remove_pid_file();
+
 	exit(-1);
 }
 
-static void process_udp_child(int sfd, const char *host, const char *port,
-			      int cpu, int page_size)
+static int process_udp_child(int sfd, const char *host, const char *port,
+			     int cpu, int page_size)
 {
 	struct sockaddr_storage peer_addr;
 	socklen_t peer_addr_len;
@@ -185,6 +215,9 @@ 
 	signal_setup(SIGUSR1, finish);
 
 	tempfile = get_temp_file(host, port, cpu);
+	if (!tempfile)
+		return -ENOMEM;
+
 	fd = open(tempfile, O_WRONLY | O_TRUNC | O_CREAT, 0644);
 	if (fd < 0)
 		pdie("creating %s", tempfile);
@@ -275,13 +308,18 @@ 
 static void fork_udp_reader(int sfd, const char *node, const char *port,
 			    int *pid, int cpu, int pagesize)
 {
+	int ret;
+
 	*pid = fork();
 
 	if (*pid < 0)
 		pdie("creating udp reader");
 
-	if (!*pid)
-		process_udp_child(sfd, node, port, cpu, pagesize);
+	if (!*pid) {
+		ret = process_udp_child(sfd, node, port, cpu, pagesize);
+		if (ret < 0)
+			pdie("Problem with udp reader %d", ret);
+	}
 
 	close(sfd);
 }
@@ -307,79 +345,140 @@ 
 
 static int communicate_with_client(int fd, int *cpus, int *pagesize)
 {
+	char *last_proto = NULL;
 	char buf[BUFSIZ];
 	char *option;
 	int options;
 	int size;
 	int n, s, t, i;
+	int ret = -EINVAL;
 
 	/* Let the client know what we are */
 	write(fd, "tracecmd", 8);
 
+ try_again:
 	/* read back the CPU count */
 	n = read_string(fd, buf, BUFSIZ);
 	if (n == BUFSIZ)
 		/** ERROR **/
-		return -1;
+		return -EINVAL;
 
 	*cpus = atoi(buf);
 
-	plog("cpus=%d\n", *cpus);
-	if (*cpus < 0)
-		return -1;
+	/* Is the client using the new protocol? */
+	if (*cpus == -1) {
+		if (memcmp(buf, V2_CPU, n) != 0) {
+			/* If it did not send a version, then bail */
+			if (memcmp(buf, "-1V", 3)) {
+				plog("Unknown string %s\n", buf);
+				goto out;
+			}
+			/* Skip "-1" */
+			plog("Cannot handle the protocol %s\n", buf+2);
 
-	/* next read the page size */
-	n = read_string(fd, buf, BUFSIZ);
-	if (n == BUFSIZ)
-		/** ERROR **/
-		return -1;
+			/* If it returned the same command as last time, bail! */
+			if (last_proto && strncmp(last_proto, buf, n) == 0) {
+				plog("Repeat of version %s sent\n", last_proto);
+				goto out;
+			}
+			free(last_proto);
+			last_proto = malloc(n + 1);
+			if (last_proto) {
+				memcpy(last_proto, buf, n);
+				last_proto[n] = 0;
+			}
+			/* Return the highest protocol we can use */
+			write(fd, "V2", 3);
+			goto try_again;
+		}
 
-	*pagesize = atoi(buf);
+		/* Let the client know we use v2 protocol */
+		write(fd, "V2", 3);
 
-	plog("pagesize=%d\n", *pagesize);
-	if (*pagesize <= 0)
-		return -1;
+		/* read the rest of dummy data */
+		n = read(fd, buf, sizeof(V2_MAGIC));
+		if (memcmp(buf, V2_MAGIC, n) != 0)
+			goto out;
+
+		/* We're off! */
+		write(fd, "OK", 2);
+
+		proto_ver = V2_PROTOCOL;
+
+		/* read the CPU count, the page size, and options */
+		if (tracecmd_msg_initial_setting(fd, cpus, pagesize) < 0)
+			goto out;
+	} else {
+		/* The client is using the v1 protocol */
+
+		plog("cpus=%d\n", *cpus);
+		if (*cpus < 0)
+			goto out;
 
-	/* Now the number of options */
-	n = read_string(fd, buf, BUFSIZ);
-	if (n == BUFSIZ)
-		/** ERROR **/
-		return -1;
+		/* next read the page size */
+		n = read_string(fd, buf, BUFSIZ);
+		if (n == BUFSIZ)
+			/** ERROR **/
+			goto out;
 
-	options = atoi(buf);
+		*pagesize = atoi(buf);
 
-	for (i = 0; i < options; i++) {
-		/* next is the size of the options */
+		plog("pagesize=%d\n", *pagesize);
+		if (*pagesize <= 0)
+			goto out;
+
+		/* Now the number of options */
 		n = read_string(fd, buf, BUFSIZ);
-		if (n == BUFSIZ)
+ 		if (n == BUFSIZ)
 			/** ERROR **/
-			return -1;
-		size = atoi(buf);
-		/* prevent a client from killing us */
-		if (size > MAX_OPTION_SIZE)
-			return -1;
-		option = malloc_or_die(size);
-		do {
-			t = size;
-			s = 0;
-			s = read(fd, option+s, t);
-			if (s <= 0)
-				return -1;
-			t -= s;
-			s = size - t;
-		} while (t);
+			return -EINVAL;
+
+		options = atoi(buf);
 
-		s = process_option(option);
-		free(option);
-		/* do we understand this option? */
-		if (!s)
-			return -1;
+		for (i = 0; i < options; i++) {
+			/* next is the size of the options */
+			n = read_string(fd, buf, BUFSIZ);
+			if (n == BUFSIZ)
+				/** ERROR **/
+				goto out;
+			size = atoi(buf);
+			/* prevent a client from killing us */
+			if (size > MAX_OPTION_SIZE)
+				goto out;
+
+			ret = -ENOMEM;
+			option = malloc(size);
+			if (!option)
+				goto out;
+
+			ret = -EIO;
+			do {
+				t = size;
+				s = 0;
+				s = read(fd, option+s, t);
+				if (s <= 0)
+					goto out;
+				t -= s;
+				s = size - t;
+			} while (t);
+
+			s = process_option(option);
+			free(option);
+			/* do we understand this option? */
+			ret = -EINVAL;
+			if (!s)
+				goto out;
+		}
 	}
 
 	if (use_tcp)
 		plog("Using TCP for live connection\n");
 
-	return 0;
+	ret = 0;
+ out:
+	free(last_proto);
+
+	return ret;
 }
 
 static int create_client_file(const char *node, const char *port)
@@ -408,6 +507,8 @@ 
 			pid_array[cpu] = 0;
 		}
 	}
+
+	free(pid_array);
 }
 
 static int *create_all_readers(int cpus, const char *node, const char *port,
@@ -421,8 +522,16 @@ 
 	int cpu;
 	int pid;
 
-	port_array = malloc_or_die(sizeof(int) * cpus);
-	pid_array = malloc_or_die(sizeof(int) * cpus);
+	port_array = malloc(sizeof(int) * cpus);
+	if (!port_array)
+		return NULL;
+
+	pid_array = malloc(sizeof(int) * cpus);
+	if (!pid_array) {
+		free(port_array);
+		return NULL;
+	}
+
 	memset(pid_array, 0, sizeof(int) * cpus);
 
 	start_port = START_PORT_SEARCH;
@@ -442,14 +551,20 @@ 
 		start_port = udp_port + 1;
 	}
 
-	/* send the client a comma deliminated set of port numbers */
-	for (cpu = 0; cpu < cpus; cpu++) {
-		snprintf(buf, BUFSIZ, "%s%d",
-			 cpu ? "," : "", port_array[cpu]);
-		write(fd, buf, strlen(buf));
+	if (proto_ver == V2_PROTOCOL) {
+		/* send set of port numbers to the client */
+		if (tracecmd_msg_send_port_array(fd, cpus, port_array) < 0)
+			goto out_free;
+	} else {
+		/* send the client a comma deliminated set of port numbers */
+		for (cpu = 0; cpu < cpus; cpu++) {
+			snprintf(buf, BUFSIZ, "%s%d",
+				 cpu ? "," : "", port_array[cpu]);
+			write(fd, buf, strlen(buf));
+		}
+		/* end with null terminator */
+		write(fd, "\0", 1);
 	}
-	/* end with null terminator */
-	write(fd, "\0", 1);
 
 	return pid_array;
 
@@ -495,40 +610,57 @@ 
 	}
 }
 
-static void put_together_file(int cpus, int ofd, const char *node,
+static int put_together_file(int cpus, int ofd, const char *node,
 			      const char *port)
 {
 	char **temp_files;
 	int cpu;
+	int ret = -ENOMEM;
 
 	/* Now put together the file */
-	temp_files = malloc_or_die(sizeof(*temp_files) * cpus);
+	temp_files = malloc(sizeof(*temp_files) * cpus);
+	if (!temp_files)
+		return -ENOMEM;
 
-	for (cpu = 0; cpu < cpus; cpu++)
+	for (cpu = 0; cpu < cpus; cpu++) {
 		temp_files[cpu] = get_temp_file(node, port, cpu);
+		if (!temp_files[cpu])
+			goto out;
+	}
 
 	tracecmd_attach_cpu_data_fd(ofd, cpus, temp_files);
+	ret = 0;
+ out:
+	for (cpu--; cpu >= 0; cpu--) {
+		put_temp_file(temp_files[cpu]);
+	}
 	free(temp_files);
+	return ret;
 }
 
-static void process_client(const char *node, const char *port, int fd)
+static int process_client(const char *node, const char *port, int fd)
 {
 	int *pid_array;
 	int pagesize;
 	int cpus;
 	int ofd;
+	int ret;
 
-	if (communicate_with_client(fd, &cpus, &pagesize) < 0)
-		return;
+	ret = communicate_with_client(fd, &cpus, &pagesize);
+	if (ret < 0)
+		return ret;
 
 	ofd = create_client_file(node, port);
 
 	pid_array = create_all_readers(cpus, node, port, pagesize, fd);
 	if (!pid_array)
-		return;
+		return -ENOMEM;
 
 	/* Now we are ready to start reading data from the client */
-	collect_metadata_from_client(fd, ofd);
+	if (proto_ver == V2_PROTOCOL)
+		tracecmd_msg_collect_metadata(fd, ofd);
+	else
+		collect_metadata_from_client(fd, ofd);
 
 	/* wait a little to let our readers finish reading */
 	sleep(1);
@@ -539,9 +671,11 @@ 
 	/* wait a little to have the readers clean up */
 	sleep(1);
 
-	put_together_file(cpus, ofd, node, port);
+	ret = put_together_file(cpus, ofd, node, port);
 
 	destroy_all_readers(cpus, pid_array, node, port);
+
+	return ret;
 }
 
 static int do_fork(int cfd)
@@ -604,23 +738,33 @@ 
 }
 
 static int *client_pids;
+static int free_pids;
 static int saved_pids;
-static int size_pids;
-#define PIDS_BLOCK 32
 
 static void add_process(int pid)
 {
-	if (!client_pids) {
-		size_pids = PIDS_BLOCK;
-		client_pids = malloc_or_die(sizeof(*client_pids) * size_pids);
-	} else if (!(saved_pids % PIDS_BLOCK)) {
-		size_pids += PIDS_BLOCK;
+	int *client = NULL;
+	int i;
+
+	if (free_pids) {
+		for (i = 0; i < saved_pids; i++) {
+			if (!client_pids[i]) {
+				client = &client_pids[i];
+				break;
+			}
+		}
+		free_pids--;
+		if (!client)
+			warning("Could not find free pid");
+	}
+	if (!client) {
 		client_pids = realloc(client_pids,
-				      sizeof(*client_pids) * size_pids);
+				      sizeof(*client_pids) * (saved_pids + 1));
 		if (!client_pids)
-			pdie("realloc of pids");
+			pdie("allocating pids");
+		client = &client_pids[saved_pids++];
 	}
-	client_pids[saved_pids++] = pid;
+	*client = pid;
 }
 
 static void remove_process(int pid)
@@ -635,14 +779,8 @@ 
 	if (i == saved_pids)
 		return;
 
-	saved_pids--;
-
-	if (saved_pids == i)
-		return;
-
-	memmove(&client_pids[i], &client_pids[i+1],
-		sizeof(*client_pids) * (saved_pids - i));
-
+	client_pids[i] = 0;
+	free_pids++;
 }
 
 static void kill_clients(void)
@@ -651,6 +789,8 @@ 
 	int i;
 
 	for (i = 0; i < saved_pids; i++) {
+		if (!client_pids[i])
+			continue;
 		kill(client_pids[i], SIGINT);
 		waitpid(client_pids[i], &status, 0);
 	}
@@ -658,7 +798,7 @@ 
 	saved_pids = 0;
 }
 
-static void clean_up(int sig)
+static void clean_up(void)
 {
 	int status;
 	int ret;
@@ -682,9 +822,10 @@ 
 	do {
 		cfd = accept(sfd, (struct sockaddr *)&peer_addr,
 			     &peer_addr_len);
-		printf("connected!\n");
-		if (cfd < 0 && errno == EINTR)
+		if (cfd < 0 && errno == EINTR) {
+			clean_up();
 			continue;
+		}
 		if (cfd < 0)
 			pdie("connecting");
 
@@ -693,6 +834,34 @@ 
 			add_process(pid);
 
 	} while (!done);
+	/* Get any final stragglers */
+	clean_up();
+}
+
+static void make_pid_file(void)
+{
+	char buf[PATH_MAX];
+	int mode = do_daemon;
+	int fd;
+
+	if (!do_daemon)
+		return;
+
+	make_pid_name(mode, buf);
+
+	fd = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+	if (fd < 0) {
+		perror(buf);
+		return;
+	}
+
+	sprintf(buf, "%d\n", getpid());
+	write(fd, buf, strlen(buf));
+	close(fd);
+}
+
+static void sigstub(int sig)
+{
 }
 
 static void do_listen(char *port)
@@ -702,7 +871,9 @@ 
 	int sfd, s;
 
 	if (!debug)
-		signal_setup(SIGCHLD, clean_up);
+		signal_setup(SIGCHLD, sigstub);
+
+	make_pid_file();
 
 	memset(&hints, 0, sizeof(hints));
 	hints.ai_family = AF_UNSPEC;
@@ -736,10 +907,14 @@ 
 	do_accept_loop(sfd);
 
 	kill_clients();
+
+	remove_pid_file();
 }
 
 static void start_daemon(void)
 {
+	do_daemon = 1;
+
 	if (daemon(1, 0) < 0)
 		die("starting daemon");
 }
diff -Nru trace-cmd-2.6/trace-local.h trace-cmd-2.6.1/trace-local.h
--- trace-cmd-2.6/trace-local.h	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-local.h	2017-05-02 19:35:16.000000000 +0200
@@ -24,6 +24,9 @@ 
 #include <dirent.h>	/* for DIR */
 
 #include "trace-cmd.h"
+#include "event-utils.h"
+
+extern int debug;
 
 /* fix stupid glib guint64 typecasts and printf formats */
 typedef unsigned long long u64;
@@ -62,6 +65,8 @@ 
 
 void trace_restore(int argc, char **argv);
 
+void trace_check_events(int argc, char **argv);
+
 void trace_stack(int argc, char **argv);
 
 void trace_option(int argc, char **argv);
@@ -74,10 +79,14 @@ 
 
 void trace_stat(int argc, char **argv);
 
+void trace_show(int argc, char **argv);
+
+void trace_list(int argc, char **argv);
+
+void trace_usage(int argc, char **argv);
+
 struct hook_list;
 
-int trace_profile_record(struct tracecmd_input *handle,
-			 struct pevent_record *record, int cpu);
 void trace_init_profile(struct tracecmd_input *handle, struct hook_list *hooks,
 			int global);
 int trace_profile(void);
@@ -85,12 +94,11 @@ 
 
 struct tracecmd_input *
 trace_stream_init(struct buffer_instance *instance, int cpu, int fd, int cpus,
-		  int profile, struct hook_list *hooks, int global);
-int trace_stream_read(struct pid_record_data *pids, int nr_pids, struct timeval *tv,
-		      int profile);
+		  struct hook_list *hooks,
+		  tracecmd_handle_init_func handle_init, int global);
+int trace_stream_read(struct pid_record_data *pids, int nr_pids, struct timeval *tv);
 
-void trace_show_data(struct tracecmd_input *handle, struct pevent_record *record,
-		     int profile);
+void trace_show_data(struct tracecmd_input *handle, struct pevent_record *record);
 
 /* --- event interation --- */
 
@@ -143,7 +151,7 @@ 
 struct buffer_instance {
 	struct buffer_instance	*next;
 	const char		*name;
-	const char		*cpumask;
+	char			*cpumask;
 	struct event_list	*events;
 	struct event_list	**event_next;
 
@@ -183,6 +191,13 @@ 
 void update_first_instance(struct buffer_instance *instance, int topt);
 
 void show_instance_file(struct buffer_instance *instance, const char *name);
+
 int count_cpus(void);
 
+/* No longer in event-utils.h */
+void die(const char *fmt, ...); /* Can be overriden */
+void *malloc_or_die(unsigned int size); /* Can be overridden */
+void __die(const char *fmt, ...);
+void __vdie(const char *fmt, ...);
+
 #endif /* __TRACE_LOCAL_H */
diff -Nru trace-cmd-2.6/trace-msg.c trace-cmd-2.6.1/trace-msg.c
--- trace-cmd-2.6/trace-msg.c	1970-01-01 01:00:00.000000000 +0100
+++ trace-cmd-2.6.1/trace-msg.c	2017-05-02 19:35:16.000000000 +0200
@@ -0,0 +1,700 @@ 
+/*
+ * trace-msg.c : define message protocol for communication between clients and
+ *               a server
+ *
+ * Copyright (C) 2013 Hitachi, Ltd.
+ * Created by Yoshihiro YUNOMAE <yoshihiro.yunomae.ez@hitachi.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not,  see <http://www.gnu.org/licenses>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <errno.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <linux/types.h>
+
+#include "trace-cmd-local.h"
+#include "trace-local.h"
+#include "trace-msg.h"
+
+typedef __u32 u32;
+typedef __be32 be32;
+
+/* Two (4k) pages is the max transfer for now */
+#define MSG_MAX_LEN			8192
+
+					/* size + cmd */
+#define MSG_HDR_LEN			((sizeof(be32)) + (sizeof(be32)))
+
+#define MSG_DATA_LEN			(MSG_MAX_LEN - MSG_HDR_LEN)
+
+					/* - header size for error msg */
+#define MSG_META_MAX_LEN		(MSG_MAX_LEN - MIN_META_SIZE)
+
+
+#define MIN_TINIT_SIZE	offsetof(struct tracecmd_msg, data.tinit.opt)
+
+/* Not really the minimum, but I couldn't think of a better name */
+#define MIN_RINIT_SIZE offsetof(struct tracecmd_msg, data.rinit.port_array)
+
+#define MIN_META_SIZE 	offsetof(struct tracecmd_msg, data.meta.buf)
+
+/* for both client and server */
+bool use_tcp;
+int cpu_count;
+
+/* for client */
+static int psfd;
+unsigned int page_size;
+int *client_ports;
+bool send_metadata;
+
+/* for server */
+static int *port_array;
+bool done;
+
+struct tracecmd_msg_str {
+	be32 size;
+	char buf[];
+} __attribute__((packed));
+
+struct tracecmd_msg_opt {
+	be32 size;
+	be32 opt_cmd;
+	struct tracecmd_msg_str str;
+};
+
+struct tracecmd_msg_tinit {
+	be32 cpus;
+	be32 page_size;
+	be32 opt_num;
+	struct tracecmd_msg_opt *opt;
+} __attribute__((packed));
+
+struct tracecmd_msg_rinit {
+	be32 cpus;
+	be32 *port_array;
+} __attribute__((packed));
+
+struct tracecmd_msg_meta {
+	be32 size;
+	void *buf;
+} __attribute__((packed));
+
+struct tracecmd_msg_error {
+	be32 size;
+	be32 cmd;
+	union {
+		struct tracecmd_msg_tinit tinit;
+		struct tracecmd_msg_rinit rinit;
+		struct tracecmd_msg_meta meta;
+	} data;
+} __attribute__((packed));
+
+enum tracecmd_msg_cmd {
+	MSG_CLOSE	= 1,
+	MSG_TINIT	= 4,
+	MSG_RINIT	= 5,
+	MSG_SENDMETA	= 6,
+	MSG_FINMETA	= 7,
+};
+
+struct tracecmd_msg {
+	be32 size;
+	be32 cmd;
+	union {
+		struct tracecmd_msg_tinit tinit;
+		struct tracecmd_msg_rinit rinit;
+		struct tracecmd_msg_meta meta;
+		struct tracecmd_msg_error err;
+	} data;
+} __attribute__((packed));
+
+struct tracecmd_msg *errmsg;
+
+static int msg_write(int fd, struct tracecmd_msg *msg, int size, void *addr)
+{
+	int ret;
+
+	ret = __do_write_check(fd, msg, size);
+	if (ret < 0)
+		return ret;
+	if (ntohl(msg->size) <= size)
+		return 0;
+	return __do_write_check(fd, addr, ntohl(msg->size) - size);
+}
+
+static ssize_t msg_do_write_check(int fd, struct tracecmd_msg *msg)
+{
+	int ret;
+
+	switch (ntohl(msg->cmd)) {
+	case MSG_TINIT:
+		ret = msg_write(fd, msg, MIN_TINIT_SIZE, msg->data.tinit.opt);
+		break;
+	case MSG_RINIT:
+		ret = msg_write(fd, msg, MIN_RINIT_SIZE, msg->data.rinit.port_array);
+		break;
+	case MSG_SENDMETA:
+		ret = msg_write(fd, msg, MIN_META_SIZE, msg->data.meta.buf);
+		break;
+	default:
+		ret = __do_write_check(fd, msg, ntohl(msg->size));
+	}
+
+	return ret;
+}
+
+enum msg_opt_command {
+	MSGOPT_USETCP = 1,
+};
+
+static int make_tinit(struct tracecmd_msg *msg)
+{
+	struct tracecmd_msg_opt *opt;
+	int opt_num = 0;
+	int size = MIN_TINIT_SIZE;
+
+	if (use_tcp) {
+		opt_num++;
+		opt = malloc(sizeof(*opt));
+		if (!opt)
+			return -ENOMEM;
+		opt->size = htonl(sizeof(*opt));
+		opt->opt_cmd = htonl(MSGOPT_USETCP);
+		msg->data.tinit.opt = opt;
+		size += sizeof(*opt);
+	}
+
+	msg->data.tinit.cpus = htonl(cpu_count);
+	msg->data.tinit.page_size = htonl(page_size);
+	msg->data.tinit.opt_num = htonl(opt_num);
+
+	msg->size = htonl(size);
+
+	return 0;
+}
+
+static int make_rinit(struct tracecmd_msg *msg)
+{
+	int size = MIN_RINIT_SIZE;
+	be32 *ptr;
+	be32 port;
+	int i;
+
+	msg->data.rinit.cpus = htonl(cpu_count);
+
+	msg->data.rinit.port_array = malloc(sizeof(*port_array) * cpu_count);
+	if (!msg->data.rinit.port_array)
+		return -ENOMEM;
+
+	size += sizeof(*port_array) * cpu_count;
+
+	ptr = msg->data.rinit.port_array;
+
+	for (i = 0; i < cpu_count; i++) {
+		/* + rrqports->cpus or rrqports->port_array[i] */
+		port = htonl(port_array[i]);
+		*ptr = port;
+		ptr++;
+	}
+
+	msg->size = htonl(size);
+
+	return 0;
+}
+
+static int tracecmd_msg_create(u32 cmd, struct tracecmd_msg *msg)
+{
+	int ret = 0;
+
+	memset(msg, 0, sizeof(*msg));
+	msg->cmd = htonl(cmd);
+
+	switch (cmd) {
+	case MSG_TINIT:
+		return make_tinit(msg);
+	case MSG_RINIT:
+		return make_rinit(msg);
+	case MSG_CLOSE:
+	case MSG_SENDMETA: /* meta data is not stored here. */
+	case MSG_FINMETA:
+		break;
+	}
+
+	msg->size = htonl(MSG_HDR_LEN);
+
+	return ret;
+}
+
+static void msg_free(struct tracecmd_msg *msg)
+{
+	switch (ntohl(msg->cmd)) {
+	case MSG_TINIT:
+		free(msg->data.tinit.opt);
+		break;
+	case MSG_RINIT:
+		free(msg->data.rinit.port_array);
+		break;
+	case MSG_SENDMETA:
+		free(msg->data.meta.buf);
+		break;
+	}
+}
+
+static int tracecmd_msg_send(int fd, u32 cmd)
+{
+	struct tracecmd_msg msg;
+	int ret = 0;
+
+	if (cmd > MSG_FINMETA) {
+		plog("Unsupported command: %d\n", cmd);
+		return -EINVAL;
+	}
+
+	ret = tracecmd_msg_create(cmd, &msg);
+	if (ret < 0)
+		return ret;
+
+	ret = msg_do_write_check(fd, &msg);
+	if (ret < 0)
+		ret = -ECOMM;
+
+	msg_free(&msg);
+
+	return ret;
+}
+
+static int msg_read(int fd, void *buf, u32 size, int *n)
+{
+	int r;
+
+	while (size) {
+		r = read(fd, buf + *n, size);
+		if (r < 0) {
+			if (errno == EINTR)
+				continue;
+			return -errno;
+		} else if (!r)
+			return -ENOTCONN;
+		size -= r;
+		*n += r;
+	}
+
+	return 0;
+}
+
+static int msg_read_extra(int fd, void *buf, int *n,
+			  int size, int min_size, void **addr)
+{
+	int rsize;
+	int ret;
+
+	rsize = min_size - *n;
+	ret = msg_read(fd, buf, rsize, n);
+	if (ret < 0)
+		return ret;
+	size -= *n;
+	if (size < 0)
+		return -ENOMSG;
+	*addr = malloc(size);
+	if (!*addr)
+		return -ENOMEM;
+	*n = 0;
+	return msg_read(fd, *addr, size, n);
+}
+
+static int tracecmd_msg_read_extra(int fd, struct tracecmd_msg *msg, int *n)
+{
+	int size = ntohl(msg->size);
+	int rsize;
+	int ret;
+
+	switch (ntohl(msg->cmd)) {
+	case MSG_TINIT:
+		msg->data.tinit.opt = NULL;
+
+		rsize = MIN_TINIT_SIZE - *n;
+
+		ret = msg_read(fd, msg, rsize, n);
+		if (ret < 0)
+			return ret;
+
+		if (size > *n) {
+			size -= *n;
+			msg->data.tinit.opt = malloc(size);
+			if (!msg->data.tinit.opt)
+				return -ENOMEM;
+			*n = 0;
+			return msg_read(fd, msg->data.tinit.opt, size, n);
+		}
+		return 0;
+	case MSG_RINIT:
+		return msg_read_extra(fd, msg, n, size, MIN_RINIT_SIZE,
+				      (void **)&msg->data.rinit.port_array);
+	case MSG_SENDMETA:
+		return msg_read_extra(fd, msg, n, size, MIN_META_SIZE,
+				      (void **)&msg->data.meta.buf);
+	}
+
+	return msg_read(fd, msg, size - MSG_HDR_LEN, n);
+}
+
+/*
+ * Read header information of msg first, then read all data
+ */
+static int tracecmd_msg_recv(int fd, struct tracecmd_msg *msg)
+{
+	u32 size = 0;
+	int n = 0;
+	int ret;
+
+	ret = msg_read(fd, msg, MSG_HDR_LEN, &n);
+	if (ret < 0)
+		return ret;
+
+	size = ntohl(msg->size);
+	if (size > MSG_MAX_LEN)
+		/* too big */
+		goto error;
+	else if (size < MSG_HDR_LEN)
+		/* too small */
+		goto error;
+	else if (size > MSG_HDR_LEN)
+		return tracecmd_msg_read_extra(fd, msg, &n);
+
+	return 0;
+error:
+	plog("Receive an invalid message(size=%d)\n", size);
+	return -ENOMSG;
+}
+
+#define MSG_WAIT_MSEC	5000
+static int msg_wait_to = MSG_WAIT_MSEC;
+
+/*
+ * A return value of 0 indicates time-out
+ */
+static int tracecmd_msg_recv_wait(int fd, struct tracecmd_msg *msg)
+{
+	struct pollfd pfd;
+	int ret;
+
+	pfd.fd = fd;
+	pfd.events = POLLIN;
+	ret = poll(&pfd, 1, debug ? -1 : msg_wait_to);
+	if (ret < 0)
+		return -errno;
+	else if (ret == 0)
+		return -ETIMEDOUT;
+
+	return tracecmd_msg_recv(fd, msg);
+}
+
+static int tracecmd_msg_wait_for_msg(int fd, struct tracecmd_msg *msg)
+{
+	u32 cmd;
+	int ret;
+
+	ret = tracecmd_msg_recv_wait(fd, msg);
+	if (ret < 0) {
+		if (ret == -ETIMEDOUT)
+			warning("Connection timed out\n");
+		return ret;
+	}
+
+	cmd = ntohl(msg->cmd);
+	if (cmd == MSG_CLOSE)
+		return -ECONNABORTED;
+
+	return 0;
+}
+
+static int tracecmd_msg_send_and_wait_for_msg(int fd, u32 cmd, struct tracecmd_msg *msg)
+{
+	int ret;
+
+	ret = tracecmd_msg_send(fd, cmd);
+	if (ret < 0)
+		return ret;
+
+	ret = tracecmd_msg_wait_for_msg(fd, msg);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+int tracecmd_msg_send_init_data(int fd)
+{
+	struct tracecmd_msg msg;
+	int i, cpus;
+	int ret;
+
+	ret = tracecmd_msg_send_and_wait_for_msg(fd, MSG_TINIT, &msg);
+	if (ret < 0)
+		return ret;
+
+	cpus = ntohl(msg.data.rinit.cpus);
+	client_ports = malloc_or_die(sizeof(int) * cpus);
+	for (i = 0; i < cpus; i++)
+		client_ports[i] = ntohl(msg.data.rinit.port_array[i]);
+
+	/* Next, send meta data */
+	send_metadata = true;
+
+	return 0;
+}
+
+static bool process_option(struct tracecmd_msg_opt *opt)
+{
+	/* currently the only option we have is to us TCP */
+	if (ntohl(opt->opt_cmd) == MSGOPT_USETCP) {
+		use_tcp = true;
+		return true;
+	}
+	return false;
+}
+
+static void error_operation_for_server(struct tracecmd_msg *msg)
+{
+	u32 cmd;
+
+	cmd = ntohl(msg->cmd);
+
+	warning("Message: cmd=%d size=%d\n", cmd, ntohl(msg->size));
+}
+
+#define MAX_OPTION_SIZE 4096
+
+int tracecmd_msg_initial_setting(int fd, int *cpus, int *pagesize)
+{
+	struct tracecmd_msg_opt *opt;
+	struct tracecmd_msg msg;
+	int options, i, s;
+	int ret;
+	int offset = 0;
+	u32 size = MIN_TINIT_SIZE;
+	u32 cmd;
+
+	ret = tracecmd_msg_recv_wait(fd, &msg);
+	if (ret < 0) {
+		if (ret == -ETIMEDOUT)
+			warning("Connection timed out\n");
+		return ret;
+	}
+
+	cmd = ntohl(msg.cmd);
+	if (cmd != MSG_TINIT) {
+		ret = -EINVAL;
+		goto error;
+	}
+
+	*cpus = ntohl(msg.data.tinit.cpus);
+	plog("cpus=%d\n", *cpus);
+	if (*cpus < 0) {
+		ret = -EINVAL;
+		goto error;
+	}
+
+	*pagesize = ntohl(msg.data.tinit.page_size);
+	plog("pagesize=%d\n", *pagesize);
+	if (*pagesize <= 0) {
+		ret = -EINVAL;
+		goto error;
+	}
+
+	options = ntohl(msg.data.tinit.opt_num);
+	for (i = 0; i < options; i++) {
+		if (size + sizeof(*opt) > ntohl(msg.size)) {
+			plog("Not enough message for options\n");
+			ret = -EINVAL;
+			goto error;
+		}
+		opt = (void *)msg.data.tinit.opt + offset;
+		offset += ntohl(opt->size);
+		size += ntohl(opt->size);
+		if (ntohl(msg.size) < size) {
+			plog("Not enough message for options\n");
+			ret = -EINVAL;
+			goto error;
+		}
+		/* prevent a client from killing us */
+		if (ntohl(opt->size) > MAX_OPTION_SIZE) {
+			plog("Exceed MAX_OPTION_SIZE\n");
+			ret = -EINVAL;
+			goto error;
+		}
+		s = process_option(opt);
+		/* do we understand this option? */
+		if (!s) {
+			plog("Cannot understand(%d:%d:%d)\n",
+			     i, ntohl(opt->size), ntohl(opt->opt_cmd));
+			ret = -EINVAL;
+			goto error;
+		}
+	}
+
+	return 0;
+
+error:
+	error_operation_for_server(&msg);
+	return ret;
+}
+
+int tracecmd_msg_send_port_array(int fd, int total_cpus, int *ports)
+{
+	int ret;
+
+	cpu_count = total_cpus;
+	port_array = ports;
+
+	ret = tracecmd_msg_send(fd, MSG_RINIT);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+void tracecmd_msg_send_close_msg(void)
+{
+	tracecmd_msg_send(psfd, MSG_CLOSE);
+}
+
+int tracecmd_msg_metadata_send(int fd, const char *buf, int size)
+{
+	struct tracecmd_msg msg;
+	int n;
+	int ret;
+	int count = 0;
+
+	ret = tracecmd_msg_create(MSG_SENDMETA, &msg);
+	if (ret < 0)
+		return ret;
+
+	msg.data.meta.buf = malloc(MSG_META_MAX_LEN);
+	if (!msg.data.meta.buf)
+		return -ENOMEM;
+
+	msg.data.meta.size = htonl(MSG_META_MAX_LEN);
+	msg.size = htonl(MIN_META_SIZE + MSG_META_MAX_LEN);
+
+	n = size;
+	do {
+		if (n > MSG_META_MAX_LEN) {
+			memcpy(msg.data.meta.buf, buf+count, MSG_META_MAX_LEN);
+			n -= MSG_META_MAX_LEN;
+			count += MSG_META_MAX_LEN;
+		} else {
+			msg.size = htonl(MIN_META_SIZE + n);
+			msg.data.meta.size = htonl(n);
+			memcpy(msg.data.meta.buf, buf+count, n);
+			n = 0;
+		}
+		ret = msg_do_write_check(fd, &msg);
+		if (ret < 0)
+			break;
+	} while (n);
+
+	msg_free(&msg);
+	return ret;
+}
+
+int tracecmd_msg_finish_sending_metadata(int fd)
+{
+	int ret;
+
+	ret = tracecmd_msg_send(fd, MSG_FINMETA);
+	if (ret < 0)
+		return ret;
+
+	/* psfd will be used for closing */
+	psfd = fd;
+	return 0;
+}
+
+int tracecmd_msg_collect_metadata(int ifd, int ofd)
+{
+	struct tracecmd_msg msg;
+	u32 s, t, n, cmd;
+	int ret;
+
+	do {
+		ret = tracecmd_msg_recv_wait(ifd, &msg);
+		if (ret < 0) {
+			if (ret == -ETIMEDOUT)
+				warning("Connection timed out\n");
+			else
+				warning("reading client");
+			return ret;
+		}
+
+		cmd = ntohl(msg.cmd);
+		if (cmd == MSG_FINMETA) {
+			/* Finish receiving meta data */
+			break;
+		} else if (cmd != MSG_SENDMETA)
+			goto error;
+
+		n = ntohl(msg.data.meta.size);
+		t = n;
+		s = 0;
+		do {
+			s = write(ofd, msg.data.meta.buf+s, t);
+			if (s < 0) {
+				if (errno == EINTR)
+					continue;
+				warning("writing to file");
+				return -errno;
+			}
+			t -= s;
+			s = n - t;
+		} while (t);
+	} while (cmd == MSG_SENDMETA);
+
+	/* check the finish message of the client */
+	while (!done) {
+		ret = tracecmd_msg_recv(ifd, &msg);
+		if (ret < 0) {
+			warning("reading client");
+			return ret;
+		}
+
+		cmd = ntohl(msg.cmd);
+		if (cmd == MSG_CLOSE)
+			/* Finish this connection */
+			break;
+		else {
+			warning("Not accept the message %d", ntohl(msg.cmd));
+			ret = -EINVAL;
+			goto error;
+		}
+	}
+
+	return 0;
+
+error:
+	error_operation_for_server(&msg);
+	return ret;
+}
diff -Nru trace-cmd-2.6/trace-msg.h trace-cmd-2.6.1/trace-msg.h
--- trace-cmd-2.6/trace-msg.h	1970-01-01 01:00:00.000000000 +0100
+++ trace-cmd-2.6.1/trace-msg.h	2017-05-02 19:35:16.000000000 +0200
@@ -0,0 +1,28 @@ 
+#ifndef _TRACE_MSG_H_
+#define _TRACE_MSG_H_
+
+#include <stdbool.h>
+
+#define UDP_MAX_PACKET	(65536 - 20)
+#define V2_MAGIC	"677768\0"
+#define V2_CPU		"-1V2"
+
+#define V1_PROTOCOL	1
+#define V2_PROTOCOL	2
+
+/* for both client and server */
+extern bool use_tcp;
+extern int cpu_count;
+
+/* for client */
+extern unsigned int page_size;
+extern int *client_ports;
+extern bool send_metadata;
+
+/* for server */
+extern bool done;
+
+void plog(const char *fmt, ...);
+void pdie(const char *fmt, ...);
+
+#endif /* _TRACE_MSG_H_ */
diff -Nru trace-cmd-2.6/trace-output.c trace-cmd-2.6.1/trace-output.c
--- trace-cmd-2.6/trace-output.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-output.c	2017-05-02 19:35:16.000000000 +0200
@@ -37,6 +37,7 @@ 
 
 #include "trace-cmd-local.h"
 #include "list.h"
+#include "trace-msg.h"
 #include "version.h"
 
 /* We can't depend on the host size for size_t, all must be 64 bit */
@@ -82,6 +83,9 @@ 
 static stsize_t
 do_write_check(struct tracecmd_output *handle, const void *data, tsize_t size)
 {
+	if (send_metadata)
+		return tracecmd_msg_metadata_send(handle->fd, data, size);
+
 	return __do_write_check(handle->fd, data, size);
 }
 
@@ -169,8 +173,10 @@ 
 	int fd;
 
 	fd = open(file, O_RDONLY);
-	if (fd < 0)
-		die("Can't read '%s'", file);
+	if (fd < 0) {
+		warning("Can't read '%s'", file);
+		return 0; /* Caller will fail with zero */
+	}
 	size = get_size_fd(fd);
 	close(fd);
 
@@ -202,8 +208,10 @@ 
 	int fd;
 
 	fd = open(file, O_RDONLY);
-	if (fd < 0)
-		die("Can't read '%s'", file);
+	if (fd < 0) {
+		warning("Can't read '%s'", file);
+		return 0;
+	}
 	size = copy_file_fd(handle, fd);
 	close(fd);
 
@@ -231,7 +239,7 @@ 
 	if (!tracing)
 		return NULL;
 
-	file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
+	file = malloc(strlen(tracing) + strlen(name) + 2);
 	if (!file)
 		return NULL;
 
@@ -258,8 +266,10 @@ 
 		return ENODEV;
 
 	fd = open(path, O_WRONLY);
-	if (fd < 0)
-		die ("Can't %s ftrace", set ? "enable" : "disable");
+	if (fd < 0) {
+		warning("Can't %s ftrace", set ? "enable" : "disable");
+		return EIO;
+	}
 
 	if (write(fd, val, 1) < 0)
 		ret = -1;
@@ -325,8 +335,10 @@ 
 		return -1;
 
 	fd = open(path, O_RDONLY);
-	if (fd < 0)
-		die("can't read '%s'", path);
+	if (fd < 0) {
+		warning("can't read '%s'", path);
+		return -1;
+	}
 
 	size = get_size_fd(fd);
 
@@ -401,8 +413,14 @@ 
 			break;
 
 	if (!slist) {
-		slist = malloc_or_die(sizeof(*slist));
+		slist = malloc(sizeof(*slist));
+		if (!slist)
+			goto err_mem;
 		slist->name = strdup(system);
+		if (!slist->name) {
+			free(slist);
+			goto err_mem;
+		}
 		slist->next = *systems;
 		slist->events = NULL;
 		*systems = slist;
@@ -413,12 +431,23 @@ 
 			break;
 
 	if (!elist) {
-		elist = malloc_or_die(sizeof(*elist));
+		elist = malloc(sizeof(*elist));
+		if (!elist)
+			goto err_mem;
 		elist->name = strdup(event);
 		elist->file = strdup(path);
+		if (!elist->name || !elist->file) {
+			free(elist->name);
+			free(elist->file);
+			free(elist);
+			goto err_mem;
+		}
 		elist->next = slist->events;
 		slist->events = elist;
 	}
+	return;
+ err_mem:
+	warning("Insufficient memory");
 }
 
 static void free_list_events(struct list_event_system *list)
@@ -463,8 +492,10 @@ 
 	events_path = get_tracing_file(handle, "events");
 	events_len = strlen(events_path);
 
-	path = malloc_or_die(events_len + strlen(str) +
-			     strlen("/format") + 2);
+	path = malloc(events_len + strlen(str) +
+		      strlen("/format") + 2);
+	if (!path)
+		return;
 	path[0] = '\0';
 	strcat(path, events_path);
 	strcat(path, "/");
@@ -516,7 +547,7 @@ 
 
 	str = strdup(list->glob);
 	if (!str)
-		die("strdup - no memory");
+		goto err_mem;
 
 	/* system and event names are separated by a ':' */
 	ptr = strchr(str, ':');
@@ -533,7 +564,9 @@ 
 	}
 
 	ptr = str;
-	str = malloc_or_die(strlen(ptr) + 3);
+	str = malloc(strlen(ptr) + 3);
+	if (!str)
+		goto err_mem;
 	str[0] = '\0';
 	strcat(str, ptr);
 	strcat(str, "/*");
@@ -546,6 +579,9 @@ 
 
 	free(ptr);
 	free(str);
+	return;
+ err_mem:
+	warning("Insufficient memory");
 }
 
 static int read_ftrace_files(struct tracecmd_output *handle)
@@ -880,12 +916,19 @@ 
 	handle->nr_options++;
 
 	option = malloc(sizeof(*option));
-	if (!option)
-		die("Could not allocate space for option");
+	if (!option) {
+		warning("Could not allocate space for option");
+		return NULL;
+	}
 
 	option->id = id;
 	option->size = size;
-	option->data = malloc_or_die(size);
+	option->data = malloc(size);
+	if (!option->data) {
+		warning("Insufficient memory");
+		free(option);
+		return NULL;
+	}
 	memcpy(option->data, data, size);
 	list_add_tail(&option->list, &handle->options);
 
@@ -1044,10 +1087,10 @@ 
 	if (do_write_check(handle, "flyrecord", 10))
 		goto out_free;
 
-	offsets = malloc_or_die(sizeof(*offsets) * cpus);
+	offsets = malloc(sizeof(*offsets) * cpus);
 	if (!offsets)
 		goto out_free;
-	sizes = malloc_or_die(sizeof(*sizes) * cpus);
+	sizes = malloc(sizeof(*sizes) * cpus);
 	if (!sizes)
 		goto out_free;
 
diff -Nru trace-cmd-2.6/trace-plot.c trace-cmd-2.6.1/trace-plot.c
--- trace-cmd-2.6/trace-plot.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-plot.c	2017-05-02 19:35:16.000000000 +0200
@@ -17,8 +17,10 @@ 
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
+#include <stdlib.h>
 #include <string.h>
 #include "trace-graph.h"
+#include "trace-local.h"
 
 void trace_graph_plot_free(struct graph_info *ginfo)
 {
@@ -336,9 +338,11 @@ 
 
 int trace_graph_plot_event(struct graph_info *ginfo,
 			   struct graph_plot *plot,
-			   struct pevent_record *record,
-			   struct plot_info *info)
+			   struct pevent_record *record)
+
 {
+	struct plot_info *info = &plot->info;
+
 	info->line = FALSE;
 	info->box = FALSE;
 	info->bfill = TRUE;
@@ -346,7 +350,7 @@ 
 	if (!plot->cb->plot_event)
 		return 0;
 
-	return plot->cb->plot_event(ginfo, plot, record, info);
+	return plot->cb->plot_event(ginfo, plot, record);
 }
 
 void trace_graph_plot_end(struct graph_info *ginfo,
diff -Nru trace-cmd-2.6/trace-plot-cpu.c trace-cmd-2.6.1/trace-plot-cpu.c
--- trace-cmd-2.6/trace-plot-cpu.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-plot-cpu.c	2017-05-02 19:35:16.000000000 +0200
@@ -17,9 +17,11 @@ 
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
+#include <stdlib.h>
 #include <string.h>
 
 #include "trace-graph.h"
+#include "trace-local.h"
 #include "cpu.h"
 
 struct cpu_plot_info {
@@ -194,9 +196,7 @@ 
 			   unsigned long long time)
 {
 	struct cpu_plot_info *cpu_info = plot->private;
-	int cpu;
 
-	cpu = cpu_info->cpu;
 	cpu_info->last_time = 0ULL;
 	cpu_info->last_pid = -1;
 	free_record(cpu_info->last_record);
@@ -209,7 +209,6 @@ 
 {
 	struct tracecmd_input *handle = ginfo->handle;
 	struct pevent_record *trecord;
-	int filter;
 	int sched_pid;
 	int orig_pid;
 	int is_sched_switch;
@@ -226,9 +225,9 @@ 
 	if (!trecord)
 		return;
 
-	filter = filter_record(ginfo, trecord,
-			       &orig_pid, &sched_pid,
-			       &is_sched_switch);
+	filter_record(ginfo, trecord,
+		      &orig_pid, &sched_pid,
+		      &is_sched_switch);
 	cpu_info->last_pid = is_sched_switch ? sched_pid : orig_pid;
 	cpu_info->last_record = trecord;
 	cpu_info->last_time = trecord->ts;
@@ -239,21 +238,18 @@ 
 
 static int cpu_plot_event(struct graph_info *ginfo,
 			  struct graph_plot *plot,
-			  struct pevent_record *record,
-			  struct plot_info *info)
+			  struct pevent_record *record)
 {
 	struct cpu_plot_info *cpu_info = plot->private;
+	struct plot_info *info = &plot->info;
 	int sched_pid;
 	int orig_pid;
 	int is_sched_switch;
 	int filter;
 	int box_filter;
 	int pid;
-	int cpu;
 	int ret = 1;
 
-	cpu = cpu_info->cpu;
-
 	if (!record) {
 		if (!cpu_info->last_record)
 			update_last_record(ginfo, cpu_info, record);
@@ -283,8 +279,6 @@ 
 	cpu_info->last_record = record;
 	tracecmd_record_ref(record);
 
-	cpu = cpu_info->cpu;
-
 	filter = filter_record(ginfo, record, &orig_pid, &sched_pid, &is_sched_switch);
 
 	/* set pid to record, or next task on sched_switch */
@@ -374,6 +368,7 @@ 
 	struct cpu_plot_info *cpu_info = plot->private;
 	struct event_format *event;
 	struct pevent_record *record;
+	struct pevent_record *next_record;
 	struct pevent *pevent;
 	unsigned long sec, usec;
 	const char *comm;
@@ -434,10 +429,18 @@ 
 	}
 
 	trace_seq_printf(s, "%lu.%06lu", sec, usec);
-	if (pid)
-		trace_seq_printf(s, " %s-%d", comm, pid);
-	else
-		trace_seq_puts(s, " <idle>");
+
+	next_record = tracecmd_peek_data(ginfo->handle, cpu);
+
+	if (next_record && next_record->missed_events) {
+		trace_seq_puts(s, " MISSED EVENTS");
+	} else {
+
+		if (pid)
+			trace_seq_printf(s, " %s-%d", comm, pid);
+		else
+			trace_seq_puts(s, " <idle>");
+	}
 
 	free_record(record);
 
diff -Nru trace-cmd-2.6/trace-plot-task.c trace-cmd-2.6.1/trace-plot-task.c
--- trace-cmd-2.6/trace-plot-task.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-plot-task.c	2017-05-02 19:35:16.000000000 +0200
@@ -17,10 +17,12 @@ 
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
+#include <stdlib.h>
 #include <string.h>
 
 #include "trace-graph.h"
 #include "trace-filter.h"
+#include "trace-local.h"
 
 #define RED 0xff
 #define GREEN (0xff<<16)
@@ -34,6 +36,7 @@ 
 	unsigned long long	display_wake_time;
 	int			wake_color;
 	int			last_cpu;
+	gboolean		in_irq;
 };
 
 static void convert_nano(unsigned long long time, unsigned long *sec,
@@ -69,7 +72,7 @@ 
 		return FALSE;
 
 	pevent_read_number_field(ginfo->event_prev_state, record->data, &val);
-	return val ? FALSE : TRUE;
+	return val & ((1 << 11) - 1)? FALSE : TRUE;
 }
 
 static gboolean record_matches_pid(struct graph_info *ginfo,
@@ -328,6 +331,37 @@ 
 	task_info->last_cpu = -1;
 	task_info->wake_time = 0ULL;
 	task_info->display_wake_time = 0ULL;
+	task_info->in_irq = FALSE;
+}
+
+static gboolean record_is_interrupt(struct graph_info *ginfo,
+				    struct pevent_record *record,
+				    gboolean check_type)
+{
+	gboolean in_irq;
+
+	if (ginfo->no_irqs)
+		return FALSE;
+
+	in_irq = !!(pevent_data_flags(ginfo->pevent, record) &
+		    (TRACE_FLAG_HARDIRQ | TRACE_FLAG_SOFTIRQ));
+
+	/*
+	 * An irq exit event can also cause us to exit irq
+	 * even if the next event is an irq.
+	 * Treat exiting irqs (hard and soft) as non interrupts.
+	 */
+	if (check_type && in_irq) {
+		switch (trace_graph_check_irq(ginfo, record)) {
+		case GRAPH_HARDIRQ_EXIT:
+		case GRAPH_SOFTIRQ_EXIT:
+			in_irq = FALSE;
+			break;
+		default:
+			break;
+		}
+	}
+	return in_irq;
 }
 
 static void update_last_record(struct graph_info *ginfo,
@@ -404,6 +438,7 @@ 
 			task_info->last_records[cpu] = trecord;
 			task_info->last_cpu = trecord->cpu;
 			task_info->last_time = trecord->ts;
+			task_info->in_irq = record_is_interrupt(ginfo, trecord, TRUE);
 			break;
 		}
 
@@ -413,11 +448,13 @@ 
 
 static int task_plot_event(struct graph_info *ginfo,
 			   struct graph_plot *plot,
-			   struct pevent_record *record,
-			   struct plot_info *info)
+			   struct pevent_record *record)
 {
 	struct task_plot_info *task_info = plot->private;
+	struct plot_info *info = &plot->info;
+	struct pevent_record *next_record;
 	gboolean match;
+	gboolean in_irq;
 	int sched_pid;
 	int rec_pid;
 	int is_wakeup;
@@ -435,6 +472,8 @@ 
 			info->bstart = task_info->last_time;
 			info->bend = ginfo->view_end_time;
 			info->bcolor = hash_cpu(task_info->last_cpu);
+			info->bfill = !task_info->in_irq;
+			task_info->in_irq = FALSE;
 		}
 		for (cpu = 0; cpu < ginfo->cpus; cpu++) {
 			free_record(task_info->last_records[cpu]);
@@ -446,7 +485,6 @@ 
 	match = record_matches_pid(ginfo, record, pid, &rec_pid,
 				   &sched_pid, &is_sched, &is_wakeup);
 
-
 	if (!match && record->cpu != task_info->last_cpu) {
 		if (!task_info->last_records[record->cpu]) {
 			task_info->last_records[record->cpu] = record;
@@ -489,6 +527,17 @@ 
 			return 1;
 		}
 
+		in_irq = record_is_interrupt(ginfo, record, TRUE);
+
+		/* It takes two events to be in an irq */
+		if (in_irq) {
+			next_record = tracecmd_peek_data(ginfo->handle, record->cpu);
+			if (next_record)
+				in_irq = record_is_interrupt(ginfo, next_record, FALSE);
+			else
+				in_irq = 0;
+		}
+
 		if (task_info->last_cpu != record->cpu) {
 			if (task_info->last_cpu >= 0) {
 				/* Switched CPUs */
@@ -496,6 +545,7 @@ 
 				info->bcolor = hash_cpu(task_info->last_cpu);
 				info->bstart = task_info->last_time;
 				info->bend = record->ts;
+				info->bfill = !task_info->in_irq;
 			}
 			task_info->last_time = record->ts;
 		}
@@ -521,16 +571,30 @@ 
 				info->bcolor = hash_cpu(task_info->last_cpu);
 				info->bstart = task_info->last_time;
 				info->bend = record->ts;
+				info->bfill = !task_info->in_irq;
 				task_info->last_cpu = -1;
 				if (is_running(ginfo, record)) {
 					task_info->wake_time = record->ts;
 					task_info->wake_color = RED;
 				} else
 					task_info->wake_time = 0;
-			} else
+			} else {
 				task_info->wake_time = 0;
-		} else
+				task_info->in_irq = in_irq;
+			}
+		} else {
+			/* Hollow out when we are in an irq */
+			if (task_info->in_irq != in_irq) {
+				info->box = TRUE;
+				info->bcolor = hash_cpu(task_info->last_cpu);
+				info->bstart = task_info->last_time;
+				info->bend = record->ts;
+				info->bfill = !task_info->in_irq;
+				task_info->last_time = record->ts;
+			}
 			task_info->wake_time = 0;
+			task_info->in_irq = in_irq;
+		}
 
 		return 1;
 	}
@@ -726,6 +790,14 @@ 
 	if (pid == task_info->pid || sched_pid == task_info->pid)
 		trace_seq_printf(s, " CPU: %03d", cpu);
 
+	if (record_is_interrupt(ginfo, record, TRUE)) {
+		struct pevent_record *next_record;
+
+		next_record = tracecmd_peek_data(ginfo->handle, record->cpu);
+		if (record_is_interrupt(ginfo, next_record, FALSE))
+			trace_seq_puts(s, "\n(in interrupt)");
+	}
+
 	free_record(record);
 
 	return 1;
diff -Nru trace-cmd-2.6/trace-profile.c trace-cmd-2.6.1/trace-profile.c
--- trace-cmd-2.6/trace-profile.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-profile.c	2017-05-02 19:35:16.000000000 +0200
@@ -29,6 +29,8 @@ 
 #include "trace-local.h"
 #include "trace-hash.h"
 
+#include <linux/time64.h>
+
 #ifdef WARN_NO_AUDIT
 # warning "lib audit not found, using raw syscalls "	\
 	"(install libaudit-devel and try again)"
@@ -46,12 +48,12 @@ 
 
 static unsigned long long nsecs_per_sec(unsigned long long ts)
 {
-	return ts / NSECS_PER_SEC;
+	return ts / NSEC_PER_SEC;
 }
 
 static unsigned long long mod_to_usec(unsigned long long ts)
 {
-	return ((ts % NSECS_PER_SEC) + NSECS_PER_USEC / 2) / NSECS_PER_USEC;
+	return ((ts % NSEC_PER_SEC) + NSEC_PER_USEC / 2) / NSEC_PER_USEC;
 }
 
 struct handle_data;
@@ -226,7 +228,9 @@ 
 {
 	struct start_data *start;
 
-	start = malloc_or_die(sizeof(*start));
+	start = malloc(sizeof(*start));
+	if (!start)
+		return NULL;
 	memset(start, 0, sizeof(*start));
 	start->hash.key = trace_hash(search_val);
 	start->search_val = search_val;
@@ -283,7 +287,9 @@ 
 	if (item)
 		return event_from_item(item);
 
-	event_hash = malloc_or_die(sizeof(*event_hash));
+	event_hash = malloc(sizeof(*event_hash));
+	if (!event_hash)
+		return NULL;
 	memset(event_hash, 0, sizeof(*event_hash));
 
 	event_hash->event_data = edata->event_data;
@@ -369,7 +375,11 @@ 
 
 	item = trace_hash_find(&event_hash->stacks, key, match_stack, &match);
 	if (!item) {
-		stack = malloc_or_die(sizeof(*stack) + size);
+		stack = malloc(sizeof(*stack) + size);
+		if (!stack) {
+			warning("Could not allocate stack");
+			return;
+		}
 		memset(stack, 0, sizeof(*stack));
 		memcpy(&stack->caller, caller, size);
 		stack->size = size;
@@ -419,6 +429,8 @@ 
 		delta = 0;
 
 	event_hash = find_start_event_hash(task, event_data, start);
+	if (!event_hash)
+		return NULL;
 	event_hash->count++;
 	event_hash->time_total += delta;
 	event_hash->last_time = delta;
@@ -485,7 +497,11 @@ 
 	unsigned long long key = trace_hash(pid);
 	struct task_data *task;
 
-	task = malloc_or_die(sizeof(*task));
+	task = malloc(sizeof(*task));
+	if (!task) {
+		warning("Could not allocate task");
+		return NULL;
+	}
 	memset(task, 0, sizeof(*task));
 
 	task->pid = pid;
@@ -532,7 +548,11 @@ 
 {
 	const char *comm;
 
-	task->comm = malloc_or_die(field->size + 1);
+	task->comm = malloc(field->size + 1);
+	if (!task->comm) {
+		warning("Could not allocate task comm");
+		return;
+	}
 	comm = record->data + field->offset;
 	memcpy(task->comm, comm, field->size);
 	task->comm[field->size] = 0;
@@ -559,6 +579,8 @@ 
 					 record->data, &pid);
 		proxy = task;
 		task = find_task(task->handle, pid);
+		if (!task)
+			return;
 		proxy->proxy = task;
 	}
 
@@ -580,6 +602,10 @@ 
 	edata.val = val;
 
 	event_hash = find_event_hash(task, &edata);
+	if (!event_hash) {
+		warning("failed to allocate event_hash");
+		return;
+	}
 
 	event_hash->count++;
 	task->last_event = event_hash;
@@ -612,6 +638,8 @@ 
 	unsigned long long val;
 
 	task = find_event_task(h, event_data, record, pid);
+	if (!task)
+		return NULL;
 
 	pevent_read_number_field(event_data->start_match_field, record->data,
 				 &val);
@@ -631,10 +659,17 @@ 
 	unsigned long long val;
 
 	task = find_event_task(h, event_data, record, pid);
+	if (!task)
+		return NULL;
 
 	pevent_read_number_field(event_data->end_match_field, record->data,
 				 &val);
 	start = add_start(task, event_data, record, val, val);
+	if (!start) {
+		warning("Failed to allocate start of task");
+		return NULL;
+	}
+		
 	task->last_start = start;
 	task->last_event = NULL;
 
@@ -653,11 +688,17 @@ 
 		task = handle_end_event(h, event_data, record, pid);
 
 	/* If this is the start of a event pair (end is set) */
-	if (event_data->end)
+	if (event_data->end) {
 		task = handle_start_event(h, event_data, record, pid);
+		/* handle_start_event only returns NULL on error */
+		if (!task)
+			return -1;
+	}
 
 	if (!task) {
 		task = find_task(h, pid);
+		if (!task)
+			return -1;
 		task->proxy = NULL;
 		task->last_start = NULL;
 		task->last_event = NULL;
@@ -704,8 +745,8 @@ 
 	return NULL;
 }
 
-int trace_profile_record(struct tracecmd_input *handle,
-			 struct pevent_record *record, int cpu)
+static void trace_profile_record(struct tracecmd_input *handle,
+				struct pevent_record *record)
 {
 	static struct handle_data *last_handle;
 	struct pevent_record *stack_record;
@@ -714,6 +755,7 @@ 
 	struct handle_data *h;
 	struct pevent *pevent;
 	unsigned long long pid;
+	int cpu = record->cpu;
 	int id;
 
 	if (last_handle && last_handle->handle == handle)
@@ -738,13 +780,15 @@ 
 	event_data = find_event_data(h, id);
 
 	if (!event_data)
-		return -1;
+		return;
 
 
 	/* Get this current PID */
 	pevent_read_number_field(h->common_pid, record->data, &pid);
 
 	task = find_task(h, pid);
+	if (!task)
+		return;
 	stack_record = task->last_stack;
 
 	if (event_data->handle_event)
@@ -757,8 +801,6 @@ 
 		free_record(stack_record);
 		task->last_stack = NULL;
 	}
-
-	return 0;
 }
 
 static struct event_data *
@@ -778,7 +820,11 @@ 
 			die("No 'common_pid' found in event");
 	}
 
-	event_data = malloc_or_die(sizeof(*event_data));
+	event_data = malloc(sizeof(*event_data));
+	if (!event_data) {
+		warning("Could not allocate event_data");
+		return NULL;
+	}
 	memset(event_data, 0, sizeof(*event_data));
 	event_data->id = event->id;
 	event_data->event = event;
@@ -859,6 +905,9 @@ 
 	end = add_event(h, end_event->system, end_event->name,
 			EVENT_TYPE_USER_MATE);
 
+	if (!start || !end)
+		return;
+
 	mate_events(h, start, pid_field, end_match_field, end, start_match_field,
 		    migrate, global);
 }
@@ -975,6 +1024,8 @@ 
 				 record->data, &next_pid);
 
 	task = find_task(h, prev_pid);
+	if (!task)
+		return -1;
 	if (!task->comm)
 		add_task_comm(task, h->switch_prev_comm, record);
 
@@ -989,6 +1040,9 @@ 
 	task->last_event = NULL;
 
 	task = find_task(h, next_pid);
+	if (!task)
+		return -1;
+
 	if (!task->comm)
 		add_task_comm(task, h->switch_next_comm, record);
 
@@ -1023,6 +1077,8 @@ 
 	void *caller;
 
 	task = find_task(h, pid);
+	if (!task)
+		return -1;
 
 	if (task->last_stack) {
 		free_record(task->last_stack);
@@ -1088,6 +1144,8 @@ 
 	void *caller;
 
 	task = handle_start_event(h, event_data, record, pid);
+	if (!task)
+		return -1;
 
 	/*
 	 * If a stack trace hasn't been used for a previous task,
@@ -1122,6 +1180,8 @@ 
 	struct task_data *task;
 
 	task = handle_end_event(h, event_data, record, pid);
+	if (!task)
+		return -1;
 	/* Do not match stacks with function graph exit events */
 	task->last_event = NULL;
 
@@ -1144,6 +1204,9 @@ 
 	}
 
 	task = find_task(h, pid);
+	if (!task)
+		return -1;
+
 	free(task->comm);
 	task->comm = NULL;
 
@@ -1161,6 +1224,8 @@ 
 	unsigned long long success;
 
 	proxy = find_task(h, pid);
+	if (!proxy)
+		return -1;
 
 	/* If present, data_field holds "success" */
 	if (event_data->data_field) {
@@ -1176,6 +1241,9 @@ 
 				 record->data, &pid);
 
 	task = find_task(h, pid);
+	if (!task)
+		return -1;
+
 	if (!task->comm)
 		add_task_comm(task, h->wakeup_comm, record);
 
@@ -1233,7 +1301,12 @@ 
 	int ret;
 	int i;
 
-	h = malloc_or_die(sizeof(*h));
+	tracecmd_set_show_data_func(handle, trace_profile_record);
+	h = malloc(sizeof(*h));
+	if (!h) {
+		warning("Could not allocate handle");
+		return;
+	};
 	memset(h, 0, sizeof(*h));
 	h->next = handles;
 	handles = h;
@@ -1256,14 +1329,23 @@ 
 		h->cpus = count_cpus();
 
 	list_head_init(&h->migrate_starts);
-	h->cpu_starts = malloc_or_die(sizeof(*h->cpu_starts) * h->cpus);
+	h->cpu_starts = malloc(sizeof(*h->cpu_starts) * h->cpus);
+	if (!h->cpu_starts)
+		goto free_handle;
+
 	for (i = 0; i < h->cpus; i++)
 		list_head_init(&h->cpu_starts[i]);
 
-	h->cpu_data = malloc_or_die(h->cpus * sizeof(*h->cpu_data));
+	h->cpu_data = malloc(h->cpus * sizeof(*h->cpu_data));
+	if (!h->cpu_data)
+		goto free_starts;
+
 	memset(h->cpu_data, 0, h->cpus * sizeof(h->cpu_data));
 
-	h->global_task = malloc_or_die(sizeof(struct task_data));
+	h->global_task = malloc(sizeof(struct task_data));
+	if (!h->global_task)
+		goto free_data;
+
 	memset(h->global_task, 0, sizeof(struct task_data));
 	init_task(h, h->global_task);
 	h->global_task->comm = strdup("Global Events");
@@ -1436,6 +1518,16 @@ 
 
 		free(fields);
 	}
+	return;
+
+ free_data:
+	free(h->cpu_data);
+ free_starts:
+	free(h->cpu_starts);
+ free_handle:
+	handles = h->next;
+	free(h);
+	warning("Failed handle allocations");
 }
 
 static void output_event_stack(struct pevent *pevent, struct stack_data *stack)
@@ -1577,7 +1669,11 @@ 
 		return NULL;
 	}
 
-	chain = malloc_or_die(sizeof(*chain) * nr_chains);
+	chain = malloc(sizeof(*chain) * nr_chains);
+	if (!chain) {
+		warning("Could not allocate chain");
+		return NULL;
+	}
 	memset(chain, 0, sizeof(*chain) * nr_chains);
 
 	x = 0;
@@ -1813,7 +1909,11 @@ 
 		}
 	}
 
-	stacks = malloc_or_die(sizeof(*stacks) * nr_stacks);
+	stacks = malloc(sizeof(*stacks) * nr_stacks);
+	if (!stacks) {
+		warning("Could not allocate stacks");
+		return;
+	}
 
 	nr_stacks = 0;
 	trace_hash_for_each_bucket(bucket, stack_hash) {
@@ -1942,7 +2042,11 @@ 
 		}
 	}
 
-	events = malloc_or_die(sizeof(*events) * nr_events);
+	events = malloc(sizeof(*events) * nr_events);
+	if (!events) {
+		warning("Could not allocate events");
+		return;
+	}
 
 	i = 0;
 	trace_hash_for_each_bucket(bucket, &task->event_hash) {
@@ -1975,7 +2079,11 @@ 
 		}
 	}
 
-	events = malloc_or_die(sizeof(*events) * nr_events);
+	events = malloc(sizeof(*events) * nr_events);
+	if (!events) {
+		warning("Could not allocate events");
+		return;
+	}
 
 	i = 0;
 	trace_hash_for_each_bucket(bucket, &group->event_hash) {
@@ -2111,7 +2219,11 @@ 
 		}
 	}
 
-	tasks = malloc_or_die(sizeof(*tasks) * nr_tasks);
+	tasks = malloc(sizeof(*tasks) * nr_tasks);
+	if (!tasks) {
+		warning("Could not allocate tasks");
+		return;
+	}
 
 	nr_tasks = 0;
 
@@ -2149,7 +2261,11 @@ 
 	if (nr_groups == 0)
 		return;
 
-	groups = malloc_or_die(sizeof(*groups) * nr_groups);
+	groups = malloc(sizeof(*groups) * nr_groups);
+	if (!groups) {
+		warning("Could not allocate groups");
+		return;
+	}
 
 	nr_groups = 0;
 
@@ -2295,7 +2411,11 @@ 
 	if (item) {
 		grp = group_from_item(item);
 	} else {
-		grp = malloc_or_die(sizeof(*grp));
+		grp = malloc(sizeof(*grp));
+		if (!grp) {
+			warning("Could not allocate group");
+			return;
+		}
 		memset(grp, 0, sizeof(*grp));
 
 		grp->comm = strdup(task->comm);
diff -Nru trace-cmd-2.6/trace-read.c trace-cmd-2.6.1/trace-read.c
--- trace-cmd-2.6/trace-read.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-read.c	2017-05-02 19:35:16.000000000 +0200
@@ -72,8 +72,11 @@ 
 struct input_files {
 	struct list_head	list;
 	const char		*file;
+	unsigned long long	tsoffset;
+	unsigned long long	ts2secs;
 };
 static struct list_head input_files;
+static struct input_files *last_input_file;
 
 struct pid_list {
 	struct pid_list		*next;
@@ -104,7 +107,11 @@ 
 static int profile;
 
 static int buffer_breaks = 0;
-static int debug = 0;
+
+static int no_irqs;
+static int no_softirqs;
+
+static int tsdiff;
 
 static struct format_field *wakeup_task;
 static struct format_field *wakeup_success;
@@ -284,16 +291,22 @@ 
 {
 	struct input_files *item;
 
-	item = malloc_or_die(sizeof(*item));
+	item = malloc(sizeof(*item));
+	if (!item)
+		die("Failed to allocate for %s", file);
+	memset(item, 0, sizeof(*item));
 	item->file = file;
 	list_add_tail(&item->list, &input_files);
+	last_input_file = item;
 }
 
 static void add_handle(struct tracecmd_input *handle, const char *file)
 {
 	struct handle_list *item;
 
-	item = malloc_or_die(sizeof(*item));
+	item = malloc(sizeof(*item));
+	if (!item)
+		die("Failed ot allocate for %s", file);
 	memset(item, 0, sizeof(*item));
 	item->handle = handle;
 	if (file) {
@@ -334,7 +347,9 @@ 
 {
 	struct filter_str *ftr;
 
-	ftr = malloc_or_die(sizeof(*ftr));
+	ftr = malloc(sizeof(*ftr));
+	if (!ftr)
+		die("Failed to allocate for filter %s", filter);
 	ftr->filter = strdup(filter);
 	if (!ftr->filter)
 		die("malloc");
@@ -359,7 +374,9 @@ 
 
 	pid = strtok_r(pids, ",", &sav);
 	while (pid) {
-		list = malloc_or_die(sizeof(*list));
+		list = malloc(sizeof(*list));
+		if (!list)
+			die("Failed to allocate for arg %s", arg);
 		list->pid = pid;
 		list->free = free;
 		list->next = *head;
@@ -397,7 +414,9 @@ 
 #define __STR "%s"
 
 	if (!curr_filter) {
-		filter = malloc_or_die(len);
+		filter = malloc(len);
+		if (!filter)
+			die("Failed to allocate for filter %s", curr_filter);
 		sprintf(filter, ".*:" FILTER_FMT, pid, pid, pid);
 	} else {
 
@@ -493,7 +512,9 @@ 
 		filter = filter_strings;
 		filter_strings = filter->next;
 
-		event_filter = malloc_or_die(sizeof(*event_filter));
+		event_filter = malloc(sizeof(*event_filter));
+		if (!event_filter)
+			die("Failed to allocate for event filter");
 		event_filter->next = NULL;
 		event_filter->filter = pevent_filter_alloc(pevent);
 		if (!event_filter->filter)
@@ -586,7 +607,9 @@ 
 		return;
 	}
 
-	info = malloc_or_die(sizeof(*info));
+	info = malloc(sizeof(*info));
+	if (!info)
+		die("Failed to allocate wakeup info");
 	info->hash.key = val;
 	info->start = start;
 	trace_hash_add(&wakeup_hash, &info->hash);
@@ -739,23 +762,26 @@ 
 	trace_hash_free(&wakeup_hash);
 }
 
-void trace_show_data(struct tracecmd_input *handle, struct pevent_record *record,
-		     int profile)
+void trace_show_data(struct tracecmd_input *handle, struct pevent_record *record)
 {
+	tracecmd_show_data_func func = tracecmd_get_show_data_func(handle);
 	struct pevent *pevent;
 	struct trace_seq s;
 	int cpu = record->cpu;
 	bool use_trace_clock;
-
-	pevent = tracecmd_get_pevent(handle);
+	static unsigned long long last_ts;
+	unsigned long long diff_ts;
+	char buf[50];
 
 	test_save(record, cpu);
 
-	if (profile) {
-		trace_profile_record(handle, record, cpu);
+	if (func) {
+		func(handle, record);
 		return;
 	}
 
+	pevent = tracecmd_get_pevent(handle);
+
 	trace_seq_init(&s);
 	if (record->missed_events > 0)
 		trace_seq_printf(&s, "CPU:%d [%lld EVENTS DROPPED]\n",
@@ -772,7 +798,27 @@ 
 		}
 	}
 	use_trace_clock = tracecmd_get_use_trace_clock(handle);
-	pevent_print_event(pevent, &s, record, use_trace_clock);
+	if (tsdiff) {
+		struct event_format *event;
+		unsigned long long rec_ts = record->ts;
+
+		event = pevent_find_event_by_record(pevent, record);
+		pevent_print_event_task(pevent, &s, event, record);
+		pevent_print_event_time(pevent, &s, event, record,
+					use_trace_clock);
+		buf[0] = 0;
+		if (use_trace_clock && !(pevent->flags & PEVENT_NSEC_OUTPUT))
+			rec_ts = (rec_ts + 500) / 1000;
+		if (last_ts) {
+			diff_ts = rec_ts - last_ts;
+			snprintf(buf, 50, "(+%lld)", diff_ts);
+			buf[49] = 0;
+		}
+		last_ts = rec_ts;
+		trace_seq_printf(&s, " %-8s", buf);
+		pevent_print_event_data(pevent, &s, event, record);
+	} else
+		pevent_print_event(pevent, &s, record, use_trace_clock);
 	if (s.len && *(s.buffer + s.len - 1) == '\n')
 		s.len--;
 	if (debug) {
@@ -813,7 +859,7 @@ 
 			}
 		}
 	}
-		
+
 	trace_seq_do_printf(&s);
 	trace_seq_destroy(&s);
 
@@ -837,10 +883,20 @@ 
 }
 
 static int
-test_filters(struct filter *event_filters, struct pevent_record *record, int neg)
+test_filters(struct pevent *pevent, struct filter *event_filters,
+	     struct pevent_record *record, int neg)
 {
 	int found = 0;
 	int ret = FILTER_NONE;
+	int flags;
+
+	if (no_irqs || no_softirqs) {
+		flags = pevent_data_flags(pevent, record);
+		if (no_irqs && (flags & TRACE_FLAG_HARDIRQ))
+			return FILTER_MISS;
+		if (no_softirqs && (flags & TRACE_FLAG_SOFTIRQ))
+			return FILTER_MISS;
+	}
 
 	while (event_filters) {
 		ret = pevent_filter_match(event_filters->filter, record);
@@ -890,11 +946,15 @@ 
 		init = 1;
 
 		list_for_each_entry(h, &handle_list, list) {
-			info = malloc_or_die(sizeof(*info));
+			info = malloc(sizeof(*info));
+			if (!info)
+				die("Failed to allocate handle");
 			info->handles = h;
 			info->nr_cpus = tracecmd_cpus(h->handle);
 
-			info->cpus = malloc_or_die(sizeof(*info->cpus) * info->nr_cpus);
+			info->cpus = malloc(sizeof(*info->cpus) * info->nr_cpus);
+			if (!info->cpus)
+				die("Failed to allocate for %d cpus", info->nr_cpus);
 			memset(info->cpus, 0, sizeof(*info->cpus));
 
 			pevent = tracecmd_get_pevent(h->handle);
@@ -932,7 +992,7 @@ 
 	 * being filtered out.
 	 */
 	if (id == info->stacktrace_id) {
-		ret = test_filters(handles->event_filter_out, record, 1);
+		ret = test_filters(pevent, handles->event_filter_out, record, 1);
 		if (ret != FILTER_MATCH)
 			return cpu_info->last_printed;
 		return 0;
@@ -945,6 +1005,7 @@ 
 static struct pevent_record *get_next_record(struct handle_list *handles)
 {
 	struct pevent_record *record;
+	struct pevent *pevent;
 	int found = 0;
 	int cpu;
 	int ret;
@@ -955,6 +1016,8 @@ 
 	if (handles->done)
 		return NULL;
 
+	pevent = tracecmd_get_pevent(handles->handle);
+
 	do {
 		if (filter_cpus) {
 			long long last_stamp = -1;
@@ -980,7 +1043,7 @@ 
 			record = tracecmd_read_next_data(handles->handle, &cpu);
 
 		if (record) {
-			ret = test_filters(handles->event_filters, record, 0);
+			ret = test_filters(pevent, handles->event_filters, record, 0);
 			switch (ret) {
 			case FILTER_NOEXIST:
 				/* Stack traces may still filter this */
@@ -993,7 +1056,8 @@ 
 			case FILTER_NONE:
 			case FILTER_MATCH:
 				/* Test the negative filters (-v) */
-				ret = test_filters(handles->event_filter_out, record, 1);
+				ret = test_filters(pevent, handles->event_filter_out,
+						   record, 1);
 				if (ret != FILTER_MATCH) {
 					found = 1;
 					break;
@@ -1114,7 +1178,8 @@ 
 			last_hook->next = tracecmd_hooks(handles->handle);
 		else
 			hooks = tracecmd_hooks(handles->handle);
-		trace_init_profile(handles->handle, hooks, global);
+		if (profile)
+			trace_init_profile(handles->handle, hooks, global);
 
 		process_filters(handles);
 
@@ -1156,7 +1221,7 @@ 
 		}
 		if (last_record) {
 			print_handle_file(last_handle);
-			trace_show_data(last_handle->handle, last_record, profile);
+			trace_show_data(last_handle->handle, last_record);
 			free_handle_record(last_handle);
 		}
 	} while (last_record);
@@ -1254,10 +1319,12 @@ 
 	if (ret < 0)
 		die("Can't stat file %s", file);
 
-	buf = malloc_or_die(st.st_size);
+	buf = malloc(st.st_size);
+	if (!buf)
+		die("Failed to allocate for function buffer");
 	read_file_fd(fd, buf, st.st_size);
 	close(fd);
-	parse_proc_kallsyms(pevent, buf, st.st_size);
+	tracecmd_parse_proc_kallsyms(pevent, buf, st.st_size);
 	free(buf);
 }
 
@@ -1292,7 +1359,9 @@ 
 	for (str = list; str; str = str->next) {
 		char *match;
 
-		match = malloc_or_die(strlen(str->event) + 3);
+		match = malloc(strlen(str->event) + 3);
+		if (!match)
+			die("Failed to allocate for match string '%s'", str->event);
 		sprintf(match, "^%s$", str->event);
 
 		ret = regcomp(&regex, match, REG_ICASE|REG_NOSUB);
@@ -1321,6 +1390,9 @@ 
 }
 
 enum {
+	OPT_tsdiff	= 239,
+	OPT_ts2secs	= 240,
+	OPT_tsoffset	= 241,
 	OPT_bycomm	= 242,
 	OPT_debug	= 243,
 	OPT_uname	= 244,
@@ -1350,6 +1422,9 @@ 
 	struct input_files *inputs;
 	struct handle_list *handles;
 	enum output_type otype;
+	unsigned long long tsoffset = 0;
+	unsigned long long ts2secs = 0;
+	unsigned long long ts2sc;
 	int show_stat = 0;
 	int show_funcs = 0;
 	int show_endian = 0;
@@ -1399,11 +1474,14 @@ 
 			{"profile", no_argument, NULL, OPT_profile},
 			{"uname", no_argument, NULL, OPT_uname},
 			{"by-comm", no_argument, NULL, OPT_bycomm},
+			{"ts-offset", required_argument, NULL, OPT_tsoffset},
+			{"ts2secs", required_argument, NULL, OPT_ts2secs},
+			{"ts-diff", no_argument, NULL, OPT_tsdiff},
 			{"help", no_argument, NULL, '?'},
 			{NULL, 0, NULL, 0}
 		};
 
-		c = getopt_long (argc-1, argv+1, "+hi:H:feGpRr:tPNn:LlEwF:VvTqO:",
+		c = getopt_long (argc-1, argv+1, "+hSIi:H:feGpRr:tPNn:LlEwF:VvTqO:",
 			long_options, &option_index);
 		if (c == -1)
 			break;
@@ -1413,8 +1491,11 @@ 
 			break;
 		case 'i':
 			if (input_file) {
-				if (!multi_inputs)
+				if (!multi_inputs) {
 					add_input(input_file);
+					if (tsoffset)
+						last_input_file->tsoffset = tsoffset;
+				}
 				multi_inputs++;
 				add_input(optarg);
 			} else
@@ -1432,6 +1513,12 @@ 
 		case 'f':
 			show_funcs = 1;
 			break;
+		case 'I':
+			no_irqs = 1;
+			break;
+		case 'S':
+			no_softirqs = 1;
+			break;
 		case 'P':
 			show_printk = 1;
 			break;
@@ -1442,7 +1529,9 @@ 
 			tracecmd_disable_plugins = 1;
 			break;
 		case 'n':
-			*nohandler_ptr = malloc_or_die(sizeof(struct event_str));
+			*nohandler_ptr = malloc(sizeof(struct event_str));
+			if (!*nohandler_ptr)
+				die("Failed to allocate for '-n %s'", optarg);
 			(*nohandler_ptr)->event = optarg;
 			(*nohandler_ptr)->next = NULL;
 			nohandler_ptr = &(*nohandler_ptr)->next;
@@ -1463,7 +1552,9 @@ 
 			raw = 1;
 			break;
 		case 'r':
-			*raw_ptr = malloc_or_die(sizeof(struct event_str));
+			*raw_ptr = malloc(sizeof(struct event_str));
+			if (*raw_ptr)
+				die("Failed to allocate '-r %s'", optarg);
 			(*raw_ptr)->event = optarg;
 			(*raw_ptr)->next = NULL;
 			raw_ptr = &(*raw_ptr)->next;
@@ -1535,6 +1626,23 @@ 
 		case OPT_bycomm:
 			trace_profile_set_merge_like_comms();
 			break;
+		case OPT_ts2secs:
+			ts2sc = atoll(optarg);
+			if (multi_inputs)
+				last_input_file->ts2secs = ts2sc;
+			else
+				ts2secs = ts2sc;
+			break;
+		case OPT_tsoffset:
+			tsoffset = atoll(optarg);
+			if (multi_inputs)
+				last_input_file->tsoffset = tsoffset;
+			if (!input_file)
+				die("--ts-offset must come after -i");
+			break;
+		case OPT_tsdiff:
+			tsdiff = 1;
+			break;
 		default:
 			usage(argv);
 		}
@@ -1549,9 +1657,11 @@ 
 	if (!input_file)
 		input_file = default_input_file;
 
-	if (!multi_inputs)
+	if (!multi_inputs) {
 		add_input(input_file);
-	else if (show_wakeup)
+		if (tsoffset)
+			last_input_file->tsoffset = tsoffset;
+	} else if (show_wakeup)
 		die("Wakeup tracing can only be done on a single input file");
 
 	list_for_each_entry(inputs, &input_files, list) {
@@ -1574,6 +1684,14 @@ 
 			return;
 		}
 
+		if (inputs->tsoffset)
+			tracecmd_set_ts_offset(handle, inputs->tsoffset);
+
+		if (inputs->ts2secs)
+			tracecmd_set_ts2secs(handle, inputs->ts2secs);
+		else if (ts2secs)
+			tracecmd_set_ts2secs(handle, ts2secs);
+
 		pevent = tracecmd_get_pevent(handle);
 
 		if (nanosec)
diff -Nru trace-cmd-2.6/trace-record.c trace-cmd-2.6.1/trace-record.c
--- trace-cmd-2.6/trace-record.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-record.c	2017-05-02 19:35:16.000000000 +0200
@@ -46,6 +46,7 @@ 
 #include <errno.h>
 
 #include "trace-local.h"
+#include "trace-msg.h"
 
 #define _STR(x) #x
 #define STR(x) _STR(x)
@@ -60,29 +61,23 @@ 
 #define STAMP		"stamp"
 #define FUNC_STACK_TRACE "func_stack_trace"
 
-#define UDP_MAX_PACKET (65536 - 20)
-
 enum trace_type {
 	TRACE_TYPE_RECORD	= 1,
 	TRACE_TYPE_START	= (1 << 1),
 	TRACE_TYPE_STREAM	= (1 << 2),
 	TRACE_TYPE_EXTRACT	= (1 << 3),
-	TRACE_TYPE_PROFILE	= (1 << 4) | TRACE_TYPE_STREAM,
 };
 
-static int rt_prio;
+static tracecmd_handle_init_func handle_init = NULL;
 
-static int use_tcp;
+static int rt_prio;
 
 static int keep;
 
-static unsigned int page_size;
-
 static const char *output_file = "trace.dat";
 
 static int latency;
 static int sleep_time = 1000;
-static int cpu_count;
 static int recorder_threads;
 static struct pid_record_data *pids;
 static int buffers;
@@ -91,7 +86,6 @@ 
 static int clear_function_filters;
 
 static char *host;
-static int *client_ports;
 static int sfd;
 static struct tracecmd_output *network_handle;
 
@@ -113,6 +107,7 @@ 
 /* Try a few times to get an accurate date */
 static int date2ts_tries = 5;
 
+static int proto_ver = V2_PROTOCOL;
 static struct func_list *graph_funcs;
 
 static int func_stack;
@@ -122,12 +117,16 @@ 
 struct filter_pids {
 	struct filter_pids *next;
 	int pid;
+	int exclude;
 };
 
 static struct filter_pids *filter_pids;
 static int nr_filter_pids;
 static int len_filter_pids;
 
+static int have_set_event_pid;
+static int have_event_fork;
+
 struct opt_list {
 	struct opt_list *next;
 	const char	*option;
@@ -210,12 +209,14 @@ 
 	if (keep)
 		return;
 
-	reset = malloc_or_die(sizeof(*reset));
+	reset = malloc(sizeof(*reset));
+	if (!reset)
+		die("Failed to allocate reset");
 	reset->path = strdup(file);
 	reset->reset = strdup(val);
 	reset->prio = prio;
 	if (!reset->path || !reset->reset)
-		die("malloc");
+		die("Failed to allocate reset path or val");
 
 	while (*last && (*last)->prio > prio)
 		last = &(*last)->next;
@@ -232,7 +233,9 @@ 
 	if (keep)
 		return;
 
-	reset = malloc_or_die(sizeof(*reset));
+	reset = malloc(sizeof(*reset));
+	if (!reset)
+		die("Failed to allocate reset");
 	reset->path = strdup(file);
 
 	reset->next = reset_triggers;
@@ -289,6 +292,35 @@ 
 	buffers++;
 }
 
+static void test_set_event_pid(void)
+{
+	static int tested;
+	struct stat st;
+	char *path;
+	int ret;
+
+	if (tested)
+		return;
+
+	path = tracecmd_get_tracing_file("set_event_pid");
+	ret = stat(path, &st);
+	if (!ret) {
+		have_set_event_pid = 1;
+		reset_save_file(path, RESET_DEFAULT_PRIO);
+	}
+	tracecmd_put_tracing_file(path);
+
+	path = tracecmd_get_tracing_file("options/event-fork");
+	ret = stat(path, &st);
+	if (!ret) {
+		have_event_fork = 1;
+		reset_save_file(path, RESET_DEFAULT_PRIO);
+	}
+	tracecmd_put_tracing_file(path);
+
+	tested = 1;
+}
+
 /**
  * create_instance - allocate a new buffer instance
  * @name: The name of the instance (instance will point to this)
@@ -300,7 +332,9 @@ 
 {
 	struct buffer_instance *instance;
 
-	instance = malloc_or_die(sizeof(*instance));
+	instance = malloc(sizeof(*instance));
+	if (!instance)
+		return NULL;
 	memset(instance, 0, sizeof(*instance));
 	instance->name = name;
 
@@ -352,6 +386,8 @@ 
 		free(instance_path);
 
 		instance = create_instance(name);
+		if (!instance)
+			die("Failed to create instance");
 		add_instance(instance);
 	}
 
@@ -445,11 +481,15 @@ 
 
 	if (name) {
 		size = snprintf(file, 0, "%s.%s.cpu%d", output_file, name, cpu);
-		file = malloc_or_die(size + 1);
+		file = malloc(size + 1);
+		if (!file)
+			die("Failed to allocate temp file for %s", name);
 		sprintf(file, "%s.%s.cpu%d", output_file, name, cpu);
 	} else {
 		size = snprintf(file, 0, "%s.cpu%d", output_file, cpu);
-		file = malloc_or_die(size + 1);
+		file = malloc(size + 1);
+		if (!file)
+			die("Failed to allocate temp file for %s", name);
 		sprintf(file, "%s.cpu%d", output_file, cpu);
 	}
 
@@ -564,7 +604,6 @@ 
 static void stop_threads(enum trace_type type)
 {
 	struct timeval tv = { 0, 0 };
-	int profile = (type & TRACE_TYPE_PROFILE) == TRACE_TYPE_PROFILE;
 	int ret;
 	int i;
 
@@ -581,7 +620,7 @@ 
 	/* Flush out the pipes */
 	if (type & TRACE_TYPE_STREAM) {
 		do {
-			ret = trace_stream_read(pids, recorder_threads, &tv, profile);
+			ret = trace_stream_read(pids, recorder_threads, &tv);
 		} while (ret > 0);
 	}
 
@@ -686,8 +725,10 @@ 
 	char *path;
 
 	if (instance->name) {
-		buf = malloc_or_die(strlen(instance->name) +
+		buf = malloc(strlen(instance->name) +
 			     strlen(file) + strlen("instances//") + 1);
+		if (!buf)
+			die("Failed to allocate name for %s/%s", instance->name, file);
 		sprintf(buf, "instances/%s/%s", instance->name, file);
 
 		path = tracecmd_get_tracing_file(buf);
@@ -708,8 +749,10 @@ 
 	if (!instance->name)
 		return NULL;
 
-	buf = malloc_or_die(strlen(instance->name) +
-			    strlen("instances/") + 1);
+	buf = malloc(strlen(instance->name) +
+		     strlen("instances/") + 1);
+	if (!buf)
+		die("Failed to allocate for instance %s", instance->name);
 	sprintf(buf, "instances/%s", instance->name);
 
 	path = tracecmd_get_tracing_file(buf);
@@ -756,13 +799,16 @@ 
 	fclose(fp);
 }
 
-static void add_filter_pid(int pid)
+static void add_filter_pid(int pid, int exclude)
 {
 	struct filter_pids *p;
 	char buf[100];
 
-	p = malloc_or_die(sizeof(*p));
+	p = malloc(sizeof(*p));
+	if (!p)
+		die("Failed to allocate pid filter");
 	p->next = filter_pids;
+	p->exclude = exclude;
 	p->pid = pid;
 	filter_pids = p;
 	nr_filter_pids++;
@@ -832,6 +878,8 @@ 
 	struct filter_pids *pid;
 
 	for (pid = filter_pids; pid; pid = pid->next) {
+		if (pid->exclude)
+			continue;
 		snprintf(buf, 100, "%d ", pid->pid);
 		update_ftrace_pid(buf, reset);
 		/* Only reset the first entry */
@@ -841,7 +889,6 @@ 
 
 static void update_event_filters(struct buffer_instance *instance);
 static void update_pid_event_filters(struct buffer_instance *instance);
-static void enable_tracing(void);
 
 /**
  * make_pid_filter - create a filter string to all pids against @field
@@ -859,10 +906,15 @@ 
 	struct filter_pids *p;
 	char *filter;
 	char *orit;
+	char *match;
 	char *str;
 	int curr_len = 0;
 	int len;
 
+	/* Use the new method if possible */
+	if (have_set_event_pid)
+		return NULL;
+
 	len = len_filter_pids + (strlen(field) + strlen("(==)||")) * nr_filter_pids;
 
 	if (curr_filter) {
@@ -875,7 +927,9 @@ 
 		strcat(filter, ")&&(");
 		curr_len = strlen(filter);
 	} else
-		filter = malloc_or_die(len);
+		filter = malloc(len);
+	if (!filter)
+		die("Failed to allocate pid filter");
 
 	/* Last '||' that is not used will cover the \0 */
 	str = filter + curr_len;
@@ -885,7 +939,11 @@ 
 			orit = "";
 		else
 			orit = "||";
-		len = sprintf(str, "%s(%s==%d)", orit, field, p->pid);
+		if (p->exclude)
+			match = "!=";
+		else
+			match = "==";
+		len = sprintf(str, "%s(%s%s%d)", orit, field, match, p->pid);
 		str += len;
 	}
 
@@ -901,7 +959,7 @@ 
 	int pid = getpid();
 
 	if (filter_task)
-		add_filter_pid(pid);
+		add_filter_pid(pid, 0);
 
 	if (!filter_pids)
 		return;
@@ -913,11 +971,25 @@ 
 		update_pid_event_filters(instance);
 }
 
+void tracecmd_filter_pid(int pid, int exclude)
+{
+	struct buffer_instance *instance;
+
+	add_filter_pid(pid, exclude);
+	common_pid_filter = make_pid_filter(NULL, "common_pid");
+
+	if (!filter_pids)
+		return;
+
+	update_ftrace_pids(1);
+	for_all_instances(instance)
+		update_pid_event_filters(instance);
+}
+
 static pid_t trace_waitpid(enum trace_type type, pid_t pid, int *status, int options)
 {
 	struct timeval tv = { 1, 0 };
 	int ret;
-	int profile = (type & TRACE_TYPE_PROFILE) == TRACE_TYPE_PROFILE;
 
 	if (type & TRACE_TYPE_STREAM)
 		options |= WNOHANG;
@@ -928,7 +1000,7 @@ 
 			return ret;
 
 		if (type & TRACE_TYPE_STREAM)
-			trace_stream_read(pids, recorder_threads, &tv, profile);
+			trace_stream_read(pids, recorder_threads, &tv);
 	} while (1);
 }
 #ifndef NO_PTRACE
@@ -948,7 +1020,9 @@ 
 
 	if (!curr_filter) {
 		/* No need for +1 as we don't use the "||" */
-		filter = malloc_or_die(len);
+		filter = malloc(len);
+		if (!filter)
+			die("Failed to allocate pid filter");
 		sprintf(filter, "(%s==%d)", field, pid);
 	} else {
 		int indx = strlen(curr_filter);
@@ -973,6 +1047,8 @@ 
 
 static void update_sched_events(struct buffer_instance *instance, int pid)
 {
+	if (have_set_event_pid)
+		return;
 	/*
 	 * Also make sure that the sched_switch to this pid
 	 * and wakeups of this pid are also traced.
@@ -983,15 +1059,34 @@ 
 	append_sched_event(instance->sched_wakeup_new_event, "pid", pid);
 }
 
+static int open_instance_fd(struct buffer_instance *instance,
+			    const char *file, int flags);
+
+static void add_event_pid(const char *buf, int len)
+{
+	struct buffer_instance *instance;
+	int fd;
+
+	for_all_instances(instance) {
+		fd = open_instance_fd(instance, "set_event_pid", O_WRONLY);
+		write(fd, buf, len);
+		close(fd);
+	}
+}
+
 static void add_new_filter_pid(int pid)
 {
 	struct buffer_instance *instance;
 	char buf[100];
+	int len;
 
-	add_filter_pid(pid);
-	sprintf(buf, "%d", pid);
+	add_filter_pid(pid, 0);
+	len = sprintf(buf, "%d", pid);
 	update_ftrace_pid(buf, 0);
 
+	if (have_set_event_pid)
+		return add_event_pid(buf, len);
+
 	common_pid_filter = append_pid_filter(common_pid_filter, "common_pid", pid);
 
 	for_all_instances(instance) {
@@ -1010,7 +1105,7 @@ 
 		do_ptrace = 0;
 		return;
 	}
-	add_filter_pid(pid);
+	add_filter_pid(pid, 0);
 }
 
 static void enable_ptrace(void)
@@ -1077,7 +1172,7 @@ 
 		 (!WIFEXITED(status) || pid != main_pid));
 }
 #else
-static inline void ptrace_wait(int main_pid) { }
+static inline void ptrace_wait(enum trace_type type, int main_pid) { }
 static inline void enable_ptrace(void) { }
 static inline void ptrace_attach(int pid) { }
 
@@ -1086,12 +1181,11 @@ 
 static void trace_or_sleep(enum trace_type type)
 {
 	struct timeval tv = { 1 , 0 };
-	int profile = (type & TRACE_TYPE_PROFILE) == TRACE_TYPE_PROFILE;
 
 	if (do_ptrace && filter_pid >= 0)
 		ptrace_wait(type, filter_pid);
 	else if (type & TRACE_TYPE_STREAM)
-		trace_stream_read(pids, recorder_threads, &tv, profile);
+		trace_stream_read(pids, recorder_threads, &tv);
 	else
 		sleep(10);
 }
@@ -1106,7 +1200,7 @@ 
 	if (!pid) {
 		/* child */
 		update_task_filter();
-		enable_tracing();
+		tracecmd_enable_tracing();
 		enable_ptrace();
 		/*
 		 * If we are using stderr for stdout, switch
@@ -1125,7 +1219,7 @@ 
 		}
 	}
 	if (do_ptrace) {
-		add_filter_pid(pid);
+		add_filter_pid(pid, 0);
 		ptrace_wait(type, pid);
 	} else
 		trace_waitpid(type, pid, &status, 0);
@@ -1195,7 +1289,9 @@ 
 {
 	struct opt_list *opt;
 
-	opt = malloc_or_die(sizeof(*opt));
+	opt = malloc(sizeof(*opt));
+	if (!opt)
+		die("Failed to allocate option");
 	opt->next = options;
 	options = opt;
 	opt->option = option;
@@ -1474,7 +1570,7 @@ 
 	int fd;
 	int ret;
 
-	fd = open(file, O_WRONLY);
+	fd = open(file, O_WRONLY | O_TRUNC);
 	if (fd < 0)
 		die("opening to '%s'", file);
 	ret = write(fd, str, strlen(str));
@@ -1660,7 +1756,8 @@ 
 		reset = reset_files;
 		reset_files = reset->next;
 
-		write_file(reset->path, reset->reset, "reset");
+		if (!keep)
+			write_file(reset->path, reset->reset, "reset");
 		free(reset->path);
 		free(reset->reset);
 		free(reset);
@@ -1735,24 +1832,36 @@ 
 	write(fd, "1", 1);
 }
 
+static int open_instance_fd(struct buffer_instance *instance,
+			    const char *file, int flags)
+{
+	int fd;
+	char *path;
+
+	path = get_instance_file(instance, file);
+	fd = open(path, flags);
+	if (fd < 0) {
+		/* instances may not be created yet */
+		if (is_top_instance(instance))
+			die("opening '%s'", path);
+	}
+	tracecmd_put_tracing_file(path);
+
+	return fd;
+}
+
 static int open_tracing_on(struct buffer_instance *instance)
 {
 	int fd = instance->tracing_on_fd;
-	char *path;
 
 	/* OK, we keep zero for stdin */
 	if (fd > 0)
 		return fd;
 
-	path = get_instance_file(instance, "tracing_on");
-	fd = open(path, O_RDWR | O_CLOEXEC);
+	fd = open_instance_fd(instance, "tracing_on", O_RDWR | O_CLOEXEC);
 	if (fd < 0) {
-		/* instances may not be created yet */
-		if (is_top_instance(instance))
-			die("opening '%s'", path);
 		return fd;
 	}
-	tracecmd_put_tracing_file(path);
 	instance->tracing_on_fd = fd;
 
 	return fd;
@@ -1795,7 +1904,7 @@ 
 	return ret;
 }
 
-static void enable_tracing(void)
+void tracecmd_enable_tracing(void)
 {
 	struct buffer_instance *instance;
 
@@ -1808,7 +1917,7 @@ 
 		reset_max_latency();
 }
 
-static void disable_tracing(void)
+void tracecmd_disable_tracing(void)
 {
 	struct buffer_instance *instance;
 
@@ -1816,9 +1925,9 @@ 
 		write_tracing_on(instance, 0);
 }
 
-static void disable_all(int disable_tracer)
+void tracecmd_disable_all_tracing(int disable_tracer)
 {
-	disable_tracing();
+	tracecmd_disable_tracing();
 
 	if (disable_tracer) {
 		disable_func_stack_trace();
@@ -1870,7 +1979,9 @@ 
 					free_it = 1;
 					len = common_len + strlen(event->pid_filter) +
 						strlen(event->filter) + strlen("()&&(||)") + 1;
-					event_filter = malloc_or_die(len);
+					event_filter = malloc(len);
+					if (!event_filter)
+						die("Failed to allocate event_filter");
 					sprintf(event_filter, "(%s)&&(%s||%s)",
 						event->filter, common_pid_filter,
 						event->pid_filter);
@@ -1878,7 +1989,9 @@ 
 					free_it = 1;
 					len = common_len + strlen(event->filter) +
 						strlen("()&&()") + 1;
-					event_filter = malloc_or_die(len);
+					event_filter = malloc(len);
+					if (!event_filter)
+						die("Failed to allocate event_filter");
 					sprintf(event_filter, "(%s)&&(%s)",
 						event->filter, common_pid_filter);
 				}
@@ -1891,7 +2004,9 @@ 
 					free_it = 1;
 					len = common_len + strlen(event->pid_filter) +
 						strlen("||") + 1;
-					event_filter = malloc_or_die(len);
+					event_filter = malloc(len);
+					if (!event_filter)
+						die("Failed to allocate event_filter");
 					sprintf(event_filter, "%s||%s",
 						common_pid_filter, event->pid_filter);
 				} else
@@ -1905,8 +2020,55 @@ 
 	}
 }
 
+static void update_pid_filters(struct buffer_instance *instance)
+{
+	struct filter_pids *p;
+	char *filter;
+	char *str;
+	int len;
+	int ret;
+	int fd;
+
+	fd = open_instance_fd(instance, "set_event_pid",
+			      O_WRONLY | O_CLOEXEC | O_TRUNC);
+	if (fd < 0)
+		die("Failed to access set_event_pid");
+
+	len = len_filter_pids + nr_filter_pids;
+	filter = malloc(len);
+	if (!filter)
+		die("Failed to allocate pid filter");
+
+	str = filter;
+
+	for (p = filter_pids; p; p = p->next) {
+		if (p->exclude)
+			continue;
+		len = sprintf(str, "%d ", p->pid);
+		str += len;
+	}
+
+	if (filter == str)
+		goto out;
+
+	len = str - filter;
+	str = filter;
+	do {
+		ret = write(fd, str, len);
+		if (ret < 0)
+			die("Failed to write to set_event_pid");
+		str += ret;
+		len -= ret;
+	} while (ret >= 0 && len);
+
+ out:
+	close(fd);
+}
+
 static void update_pid_event_filters(struct buffer_instance *instance)
 {
+	if (have_set_event_pid)
+		return update_pid_filters(instance);
 	/*
 	 * Also make sure that the sched_switch to this pid
 	 * and wakeups of this pid are also traced.
@@ -1919,27 +2081,25 @@ 
 	update_event_filters(instance);
 }
 
-static void set_mask(struct buffer_instance *instance)
-{
-	const char *mask = instance->cpumask;
-	struct stat st;
-	char cpumask[4096]; /* Don't expect more than 32768 CPUS */
-	char *path;
-	int fd;
-	int ret;
+#define MASK_STR_MAX 4096 /* Don't expect more than 32768 CPUS */
 
-	if (!mask)
-		return;
+static char *alloc_mask_from_hex(const char *str)
+{
+	char *cpumask;
 
-	if (strcmp(mask, "-1") == 0) {
+	if (strcmp(str, "-1") == 0) {
 		/* set all CPUs */
 		int bytes = (cpu_count + 7) / 8;
 		int last = cpu_count % 8;
 		int i;
 
-		if (bytes > 4095) {
+		cpumask = malloc(MASK_STR_MAX);
+		if (!cpumask)
+			die("can't allocate cpumask");
+
+		if (bytes > (MASK_STR_MAX-1)) {
 			warning("cpumask can't handle more than 32768 CPUS!");
-			bytes = 4095;
+			bytes = MASK_STR_MAX-1;
 		}
 
 		sprintf(cpumask, "%x", (1 << last) - 1);
@@ -1948,18 +2108,32 @@ 
 			cpumask[i] = 'f';
 
 		cpumask[i+1] = 0;
-
-		mask = cpumask;
+	} else {
+		cpumask = strdup(str);
+		if (!cpumask)
+			die("can't allocate cpumask");
 	}
 
+	return cpumask;
+}
+
+static void set_mask(struct buffer_instance *instance)
+{
+	struct stat st;
+	char *path;
+	int fd;
+	int ret;
+
+	if (!instance->cpumask)
+		return;
+
 	path = get_instance_file(instance, "tracing_cpumask");
 	if (!path)
 		die("could not allocate path");
 
 	ret = stat(path, &st);
 	if (ret < 0) {
-		if (mask)
-			warning("%s not found", path);
+		warning("%s not found", path);
 		goto out;
 	}
 
@@ -1967,12 +2141,13 @@ 
 	if (fd < 0)
 		die("could not open %s\n", path);
 
-	if (mask)
-		write(fd, mask, strlen(mask));
+	write(fd, instance->cpumask, strlen(instance->cpumask));
 	
 	close(fd);
  out:
 	tracecmd_put_tracing_file(path);
+	free(instance->cpumask);
+	instance->cpumask = NULL;
 }
 
 static void enable_events(struct buffer_instance *instance)
@@ -1991,6 +2166,11 @@ 
 	}
 }
 
+void tracecmd_enable_events(void)
+{
+	enable_events(first_instance);
+}
+
 static void set_clock(struct buffer_instance *instance)
 {
 	char *path;
@@ -2021,6 +2201,20 @@ 
 	write_instance_file(instance, "trace_clock", instance->clock, "clock");
 }
 
+static void set_max_graph_depth(struct buffer_instance *instance, char *max_graph_depth)
+{
+	char *path;
+	int ret;
+
+	path = get_instance_file(instance, "max_graph_depth");
+	reset_save_file(path, RESET_DEFAULT_PRIO);
+	tracecmd_put_tracing_file(path);
+	ret = write_instance_file(instance, "max_graph_depth", max_graph_depth,
+				  NULL);
+	if (ret < 0)
+		die("could not write to max_graph_depth");
+}
+
 static struct event_list *
 create_event(struct buffer_instance *instance, char *path, struct event_list *old_event)
 {
@@ -2029,7 +2223,9 @@ 
 	char *p;
 	int ret;
 
-	event = malloc_or_die(sizeof(*event));
+	event = malloc(sizeof(*event));
+	if (!event)
+		die("Failed to allocate event");
 	*event = *old_event;
 	add_event(instance, event);
 
@@ -2042,7 +2238,9 @@ 
 		if (*p == '/')
 			break;
 	*p = '\0';
-	p = malloc_or_die(strlen(path) + strlen("/enable") + 1);
+	p = malloc(strlen(path) + strlen("/enable") + 1);
+	if (!p)
+		die("Failed to allocate enable path for %s", path);
 	sprintf(p, "%s/enable", path);
 	ret = stat(p, &st);
 	if (ret >= 0)
@@ -2051,7 +2249,9 @@ 
 		free(p);
 
 	if (event->trigger) {
-		p = malloc_or_die(strlen(path) + strlen("/trigger") + 1);
+		p = malloc(strlen(path) + strlen("/trigger") + 1);
+		if (!p)
+			die("Failed to allocate trigger path for %s", path);
 		sprintf(p, "%s/trigger", path);
 		ret = stat(p, &st);
 		if (ret > 0)
@@ -2073,7 +2273,9 @@ 
 	if (*event)
 		return;
 
-	path = malloc_or_die(strlen(sched->filter_file) + strlen(sched_path) + 2);
+	path = malloc(strlen(sched->filter_file) + strlen(sched_path) + 2);
+	if (!path)
+		die("Failed to allocate path for %s", sched_path);
 
 	sprintf(path, "%s", sched->filter_file);
 
@@ -2108,7 +2310,9 @@ 
 	int ret;
 	int i;
 
-	p = malloc_or_die(strlen(file) + strlen("events//filter") + 1);
+	p = malloc(strlen(file) + strlen("events//filter") + 1);
+	if (!p)
+		die("Failed to allocate event filter path for %s", file);
 	sprintf(p, "events/%s/filter", file);
 
 	path = get_instance_file(instance, p);
@@ -2127,7 +2331,7 @@ 
 		path = globbuf.gl_pathv[i];
 
 		event = create_event(instance, path, old_event);
-		printf("%s\n", path);
+		pr_stat("%s\n", path);
 
 		len = strlen(path);
 
@@ -2177,7 +2381,9 @@ 
 
 	if (ptr) {
 		len = ptr - name;
-		str = malloc_or_die(strlen(name) + 1); /* may add '*' */
+		str = malloc(strlen(name) + 1); /* may add '*' */
+		if (!str)
+			die("Failed to allocate event for %s", name);
 		strcpy(str, name);
 		str[len] = '/';
 		ptr++;
@@ -2197,7 +2403,9 @@ 
 	ret = expand_event_files(instance, name, event);
 
 	len = strlen(name) + strlen("*/") + 1;
-	str = malloc_or_die(len);
+	str = malloc(len);
+	if (!str)
+		die("Failed to allocate event for %s", name);
 	snprintf(str, len, "*/%s", name);
 	ret2 = expand_event_files(instance, str, event);
 	free(str);
@@ -2441,20 +2649,26 @@ 
 	exit(0);
 }
 
-static void communicate_with_listener(int fd)
+static void check_first_msg_from_server(int fd)
 {
 	char buf[BUFSIZ];
-	ssize_t n;
-	int cpu, i;
 
-	n = read(fd, buf, 8);
+	read(fd, buf, 8);
 
 	/* Make sure the server is the tracecmd server */
 	if (memcmp(buf, "tracecmd", 8) != 0)
 		die("server not tracecmd server");
+}
 
-	/* write the number of CPUs we have (in ASCII) */
+static void communicate_with_listener_v1(int fd)
+{
+	char buf[BUFSIZ];
+	ssize_t n;
+	int cpu, i;
+
+	check_first_msg_from_server(fd);
 
+	/* write the number of CPUs we have (in ASCII) */
 	sprintf(buf, "%d", cpu_count);
 
 	/* include \0 */
@@ -2488,7 +2702,9 @@ 
 		/* No options */
 		write(fd, "0", 2);
 
-	client_ports = malloc_or_die(sizeof(int) * cpu_count);
+	client_ports = malloc(sizeof(int) * cpu_count);
+	if (!client_ports)
+		die("Failed to allocate client ports for %d cpus", cpu_count);
 
 	/*
 	 * Now we will receive back a comma deliminated list
@@ -2509,6 +2725,56 @@ 
 	}
 }
 
+static void communicate_with_listener_v2(int fd)
+{
+	if (tracecmd_msg_send_init_data(fd) < 0)
+		die("Cannot communicate with server");
+}
+
+static void check_protocol_version(int fd)
+{
+	char buf[BUFSIZ];
+	int n;
+
+	check_first_msg_from_server(fd);
+
+	/*
+	 * Write the protocol version, the magic number, and the dummy
+	 * option(0) (in ASCII). The client understands whether the client
+	 * uses the v2 protocol or not by checking a reply message from the
+	 * server. If the message is "V2", the server uses v2 protocol. On the
+	 * other hands, if the message is just number strings, the server
+	 * returned port numbers. So, in that time, the client understands the
+	 * server uses the v1 protocol. However, the old server tells the
+	 * client port numbers after reading cpu_count, page_size, and option.
+	 * So, we add the dummy number (the magic number and 0 option) to the
+	 * first client message.
+	 */
+	write(fd, V2_CPU, sizeof(V2_CPU));
+
+	/* read a reply message */
+	n = read(fd, buf, BUFSIZ);
+
+	if (n < 0 || !buf[0]) {
+		/* the server uses the v1 protocol, so we'll use it */
+		proto_ver = V1_PROTOCOL;
+		plog("Use the v1 protocol\n");
+	} else {
+		if (memcmp(buf, "V2", n) != 0)
+			die("Cannot handle the protocol %s", buf);
+		/* OK, let's use v2 protocol */
+		write(fd, V2_MAGIC, sizeof(V2_MAGIC));
+
+		n = read(fd, buf, BUFSIZ - 1);
+		if (n != 2 || memcmp(buf, "OK", 2) != 0) {
+			if (n < 0)
+				n  = 0;
+			buf[n] = 0;
+			die("Cannot handle the protocol %s", buf);
+		}
+	}
+}
+
 static void setup_network(void)
 {
 	struct addrinfo hints;
@@ -2536,6 +2802,7 @@ 
 	hints.ai_family = AF_UNSPEC;
 	hints.ai_socktype = SOCK_STREAM;
 
+again:
 	s = getaddrinfo(server, port, &hints, &result);
 	if (s != 0)
 		die("getaddrinfo: %s", gai_strerror(s));
@@ -2556,23 +2823,38 @@ 
 
 	freeaddrinfo(result);
 
-	communicate_with_listener(sfd);
+	if (proto_ver == V2_PROTOCOL) {
+		check_protocol_version(sfd);
+		if (proto_ver == V1_PROTOCOL) {
+			/* reconnect to the server for using the v1 protocol */
+			close(sfd);
+			goto again;
+		}
+		communicate_with_listener_v2(sfd);
+	}
+
+	if (proto_ver == V1_PROTOCOL)
+		communicate_with_listener_v1(sfd);
 
 	/* Now create the handle through this socket */
 	network_handle = tracecmd_create_init_fd_glob(sfd, listed_events);
 
+	if (proto_ver == V2_PROTOCOL)
+		tracecmd_msg_finish_sending_metadata(sfd);
+
 	/* OK, we are all set, let'r rip! */
 }
 
 static void finish_network(void)
 {
+	if (proto_ver == V2_PROTOCOL)
+		tracecmd_msg_send_close_msg();
 	close(sfd);
 	free(host);
 }
 
 static void start_threads(enum trace_type type, int global)
 {
-	int profile = (type & TRACE_TYPE_PROFILE) == TRACE_TYPE_PROFILE;
 	struct buffer_instance *instance;
 	int *brass = NULL;
 	int i = 0;
@@ -2582,12 +2864,14 @@ 
 		setup_network();
 
 	/* make a thread for every CPU we have */
-	pids = malloc_or_die(sizeof(*pids) * cpu_count * (buffers + 1));
+	pids = malloc(sizeof(*pids) * cpu_count * (buffers + 1));
+	if (!pids)
+		die("Failed to allocat pids for %d cpus", cpu_count);
 
 	memset(pids, 0, sizeof(*pids) * cpu_count * (buffers + 1));
 
 	for_all_instances(instance) {
-		int x;
+		int x, pid;
 		for (x = 0; x < cpu_count; x++) {
 			if (type & TRACE_TYPE_STREAM) {
 				brass = pids[i].brass;
@@ -2596,7 +2880,7 @@ 
 					die("pipe");
 				pids[i].stream = trace_stream_init(instance, x,
 								   brass[0], cpu_count,
-								   profile, hooks,
+								   hooks, handle_init,
 								   global);
 				if (!pids[i].stream)
 					die("Creating stream for %d", i);
@@ -2606,9 +2890,11 @@ 
 			pids[i].instance = instance;
 			/* Make sure all output is flushed before forking */
 			fflush(stdout);
-			pids[i++].pid = create_recorder(instance, x, type, brass);
+			pid = pids[i++].pid = create_recorder(instance, x, type, brass);
 			if (brass)
 				close(brass[1]);
+			if (pid > 0)
+				add_filter_pid(pid, 1);
 		}
 	}
 	recorder_threads = i;
@@ -2703,7 +2989,13 @@ 
 		trace_seq_do_printf(&instance->s_print[cpu]);
 }
 
-static void record_data(char *date2ts)
+enum {
+	DATA_FL_NONE		= 0,
+	DATA_FL_DATE		= 1,
+	DATA_FL_OFFSET		= 2,
+};
+
+static void record_data(char *date2ts, int flags)
 {
 	struct tracecmd_option **buffer_options;
 	struct tracecmd_output *handle;
@@ -2722,7 +3014,9 @@ 
 		if (!cpu_count)
 			return;
 
-		temp_files = malloc_or_die(sizeof(*temp_files) * cpu_count);
+		temp_files = malloc(sizeof(*temp_files) * cpu_count);
+		if (!temp_files)
+			die("Failed to allocate temp_files for %d cpus", cpu_count);
 
 		for (i = 0; i < cpu_count; i++)
 			temp_files[i] = get_temp_file(&top_instance, i);
@@ -2740,9 +3034,18 @@ 
 		if (!handle)
 			die("Error creating output file");
 
-		if (date2ts)
-			tracecmd_add_option(handle, TRACECMD_OPTION_DATE,
-					    strlen(date2ts)+1, date2ts);
+		if (date2ts) {
+			int type = 0;
+
+			if (flags & DATA_FL_DATE)
+				type = TRACECMD_OPTION_DATE;
+			else if (flags & DATA_FL_OFFSET)
+				type = TRACECMD_OPTION_OFFSET;
+
+			if (type)
+				tracecmd_add_option(handle, type,
+						    strlen(date2ts)+1, date2ts);
+		}
 
 		/* Only record the top instance under TRACECMD_OPTION_CPUSTAT*/
 		if (!no_top_instance()) {
@@ -2761,7 +3064,9 @@ 
 		add_uname(handle);
 
 		if (buffers) {
-			buffer_options = malloc_or_die(sizeof(*buffer_options) * buffers);
+			buffer_options = malloc(sizeof(*buffer_options) * buffers);
+			if (!buffer_options)
+				die("Failed to allocate buffer options");
 			i = 0;
 			for_each_instance(instance) {
 				buffer_options[i++] = tracecmd_add_buffer_option(handle, instance->name);
@@ -2792,13 +3097,16 @@ 
 	tracecmd_output_close(handle);
 }
 
-static void write_func_file(struct buffer_instance *instance,
+static int write_func_file(struct buffer_instance *instance,
 			    const char *file, struct func_list **list)
 {
 	struct func_list *item;
 	char *path;
 	int fd;
-	int ret;
+	int ret = -1;
+
+	if (!*list)
+		return 0;
 
 	path = get_instance_file(instance, file);
 
@@ -2818,15 +3126,16 @@ 
 		free(item);
 	}
 	close(fd);
-
+	ret = 0;
  free:
 	tracecmd_put_tracing_file(path);
-	return;
+	return ret;
  failed:
 	die("Failed to write %s to %s.\n"
 	    "Perhaps this function is not available for tracing.\n"
 	    "run 'trace-cmd list -f %s' to see if it is.",
 	    item->func, file, item->func);
+	return ret;
 }
 
 static int functions_filtered(struct buffer_instance *instance)
@@ -2861,11 +3170,32 @@ 
 
 static void set_funcs(struct buffer_instance *instance)
 {
-	write_func_file(instance, "set_ftrace_filter", &instance->filter_funcs);
-	write_func_file(instance, "set_ftrace_notrace", &instance->notrace_funcs);
+	int set_notrace = 0;
+	int ret;
+
+	ret = write_func_file(instance, "set_ftrace_filter", &instance->filter_funcs);
+	if (ret < 0)
+		die("set_ftrace_filter does not exist. Can not filter functions");
+
 	/* graph tracing currently only works for top instance */
-	if (is_top_instance(instance))
-		write_func_file(instance, "set_graph_function", &graph_funcs);
+	if (is_top_instance(instance)) {
+		ret = write_func_file(instance, "set_graph_function", &graph_funcs);
+		if (ret < 0)
+			die("set_graph_function does not exist.");
+		if (instance->plugin && strcmp(instance->plugin, "function_graph") == 0) {
+			ret = write_func_file(instance, "set_graph_notrace",
+					      &instance->notrace_funcs);
+			if (!ret)
+				set_notrace = 1;
+		}
+		if (!set_notrace) {
+			ret = write_func_file(instance, "set_ftrace_notrace",
+					      &instance->notrace_funcs);
+			if (ret < 0)
+				die("set_ftrace_notrace does not exist. Can not filter functions");
+		}
+	} else
+		write_func_file(instance, "set_ftrace_notrace", &instance->notrace_funcs);
 
 	/* make sure we are filtering functions */
 	if (func_stack && is_top_instance(instance)) {
@@ -2880,7 +3210,9 @@ 
 {
 	struct func_list *item;
 
-	item = malloc_or_die(sizeof(*item));
+	item = malloc(sizeof(*item));
+	if (!item)
+		die("Failed to allocate function descriptor");
 	item->func = func;
 	item->next = *list;
 	*list = item;
@@ -2942,8 +3274,10 @@ 
 		goto out;
 
 	len = strlen(path);
-	file = malloc_or_die(len + strlen("trace_pipe_raw") + 32);
-	page = malloc_or_die(page_size);
+	file = malloc(len + strlen("trace_pipe_raw") + 32);
+	page = malloc(page_size);
+	if (!file || !page)
+		die("Failed to allocate time_stamp info");
 
 	while ((dent = readdir(dir))) {
 		const char *name = dent->d_name;
@@ -2993,12 +3327,12 @@ 
 		r = read(fd, buffer, BUFSIZ);
 		if (r <= 0)
 			continue;
-		if (size) {
+		if (size)
 			buf = realloc(buf, size+r+1);
-			if (!buf)
-				die("malloc");
-		} else
-			buf = malloc_or_die(r+1);
+		else
+			buf = malloc(r+1);
+		if (!buf)
+			die("Failed to allocate instance file buffer");
 		memcpy(buf+size, buffer, r);
 		size += r;
 	} while (r);
@@ -3074,15 +3408,15 @@ 
 	}
 
 	for (i = 0; i < date2ts_tries; i++) {
-		disable_tracing();
+		tracecmd_disable_tracing();
 		clear_trace();
-		enable_tracing();
+		tracecmd_enable_tracing();
 
 		gettimeofday(&start, NULL);
 		write(tfd, STAMP, 5);
 		gettimeofday(&end, NULL);
 
-		disable_tracing();
+		tracecmd_disable_tracing();
 		ts = find_time_stamp(pevent);
 		if (!ts)
 			continue;
@@ -3306,7 +3640,7 @@ 
 	struct buffer_instance *instance;
 	char *path;
 	int i;
-	const char const *files[] = { "set_ftrace_filter",
+	const char * const files[] = { "set_ftrace_filter",
 				      "set_ftrace_notrace",
 				      "set_graph_function",
 				      "set_graph_notrace",
@@ -3342,7 +3676,7 @@ 
 	}
 }
 
-static void remove_instances(void)
+void tracecmd_remove_instances(void)
 {
 	struct buffer_instance *instance;
 	char *path;
@@ -3364,6 +3698,25 @@ 
 	}
 }
 
+/**
+ * tracecmd_create_top_instance - create a top named instance
+ * @name: name of the instance to use.
+ *
+ * This is a library function for tools that want to do their tracing inside of
+ * an instance.  All it does is create an instance and set it as a top instance,
+ * you don't want to call this more than once, and you want to call
+ * tracecmd_remove_instances to undo your work.
+ */
+void tracecmd_create_top_instance(char *name)
+{
+	struct buffer_instance *instance;
+
+	instance = create_instance(name);
+	add_instance(instance);
+	update_first_instance(instance, 0);
+	make_instances();
+}
+
 static void check_plugin(const char *plugin)
 {
 	char *buf;
@@ -3478,8 +3831,10 @@ 
 	struct buffer_instance *instance;
 
 	for_all_instances(instance) {
-		instance->s_save = malloc_or_die(sizeof(struct trace_seq) * cpu_count);
-		instance->s_print = malloc_or_die(sizeof(struct trace_seq) * cpu_count);
+		instance->s_save = malloc(sizeof(struct trace_seq) * cpu_count);
+		instance->s_print = malloc(sizeof(struct trace_seq) * cpu_count);
+		if (!instance->s_save || !instance->s_print)
+			die("Failed to allocate instance info");
 	}
 }
 
@@ -3567,7 +3922,9 @@ 
 {
 	struct tracecmd_event_list *list;
 
-	list = malloc_or_die(sizeof(*list));
+	list = malloc(sizeof(*list));
+	if (!list)
+		die("Failed to allocate list for event");
 	list->next = listed_events;
 	list->glob = event;
 	listed_events = list;
@@ -3584,7 +3941,9 @@ 
 		listed_events = list->next;
 		free(list);
 	}
-	list = malloc_or_die(sizeof(*list));
+	list = malloc(sizeof(*list));
+	if (!list)
+		die("Failed to allocate list for all events");
 	list->next = NULL;
 	list->glob = ALL_EVENTS;
 	listed_events = list;
@@ -3604,7 +3963,9 @@ 
 		strcat(event->trigger, "\n");
 		strcat(event->trigger, trigger);
 	} else {
-		event->trigger = malloc_or_die(strlen(trigger) + 1);
+		event->trigger = malloc(strlen(trigger) + 1);
+		if (!event->trigger)
+			die("Failed to allocate event trigger");
 		sprintf(event->trigger, "%s", trigger);
 	}
 }
@@ -3663,7 +4024,9 @@ 
 	}
 
 	if (!event) {
-		event = malloc_or_die(sizeof(*event));
+		event = malloc(sizeof(*event));
+		if (!event)
+			die("Failed to allocate event");
 		memset(event, 0, sizeof(*event));
 		event->event = event_str;
 		add_event(instance, event);
@@ -3680,10 +4043,14 @@ 
 	return 0;
 }
 
+int tracecmd_add_event(const char *event_str, int stack)
+{
+	return profile_add_event(first_instance, event_str, stack);
+}
+
 static void enable_profile(struct buffer_instance *instance)
 {
 	int stacktrace = 0;
-	int ret;
 	int i;
 	char *trigger_events[] = {
 		"sched:sched_switch",
@@ -3705,10 +4072,7 @@ 
 	if (!instance->plugin) {
 		if (trace_check_file_exists(instance, "max_graph_depth")) {
 			instance->plugin = "function_graph";
-			ret = write_instance_file(instance, "max_graph_depth",
-						  "1", NULL);
-			if (ret < 0)
-				die("could not write to max_graph_depth");
+			set_max_graph_depth(instance, "1");
 		} else
 			warning("Kernel does not support max_graph_depth\n"
 				" Skipping user/kernel profiling");
@@ -3746,10 +4110,14 @@ 
 	len = strlen(event);
 	len += strlen(system) + 2;
 
-	event_name = malloc_or_die(len);
+	event_name = malloc(len);
+	if (!event_name)
+		die("Failed to allocate %s/%s", system, event);
 	sprintf(event_name, "%s:%s", system, event);
 
-	event_list = malloc_or_die(sizeof(*event_list));
+	event_list = malloc(sizeof(*event_list));
+	if (!event_list)
+		die("Failed to allocate event list for %s", event_name);
 	memset(event_list, 0, sizeof(*event_list));
 	event_list->event = event_name;
 	add_event(instance, event_list);
@@ -3789,12 +4157,16 @@ 
 }
 
 enum {
-	OPT_bycomm	= 250,
-	OPT_stderr	= 251,
-	OPT_profile	= 252,
-	OPT_nosplice	= 253,
-	OPT_funcstack	= 254,
-	OPT_date	= 255,
+
+	OPT_debug		= 247,
+	OPT_max_graph_depth	= 248,
+	OPT_tsoffset		= 249,
+	OPT_bycomm		= 250,
+	OPT_stderr		= 251,
+	OPT_profile		= 252,
+	OPT_nosplice		= 253,
+	OPT_funcstack		= 254,
+	OPT_date		= 255,
 };
 
 void trace_record (int argc, char **argv)
@@ -3803,7 +4175,7 @@ 
 	const char *output = NULL;
 	const char *option;
 	struct event_list *event = NULL;
-	struct event_list *last_event;
+	struct event_list *last_event = NULL;
 	struct buffer_instance *instance = &top_instance;
 	enum trace_type type = 0;
 	char *pids;
@@ -3824,7 +4196,10 @@ 
 	int neg_event = 0;
 	int date = 0;
 	int manual = 0;
+	char *max_graph_depth = NULL;
 	int topt = 0;
+	int do_child = 0;
+	int data_flags = 0;
 
 	int c;
 
@@ -3841,8 +4216,8 @@ 
 	else if ((stream = strcmp(argv[1], "stream") == 0))
 		; /* do nothing */
 	else if ((profile = strcmp(argv[1], "profile") == 0)) {
+		handle_init = trace_init_profile;
 		events = 1;
-
 	} else if (strcmp(argv[1], "stop") == 0) {
 		for (;;) {
 			int c;
@@ -3856,6 +4231,8 @@ 
 				break;
 			case 'B':
 				instance = create_instance(optarg);
+				if (!instance)
+					die("Failed to create instance");
 				add_instance(instance);
 				break;
 			case 'a':
@@ -3872,7 +4249,7 @@ 
 
 		}
 		update_first_instance(instance, topt);
-		disable_tracing();
+		tracecmd_disable_tracing();
 		exit(0);
 	} else if (strcmp(argv[1], "restart") == 0) {
 		for (;;) {
@@ -3887,6 +4264,8 @@ 
 				break;
 			case 'B':
 				instance = create_instance(optarg);
+				if (!instance)
+					die("Failed to create instance");
 				add_instance(instance);
 				break;
 			case 'a':
@@ -3903,7 +4282,7 @@ 
 
 		}
 		update_first_instance(instance, topt);
-		enable_tracing();
+		tracecmd_enable_tracing();
 		exit(0);
 	} else if (strcmp(argv[1], "reset") == 0) {
 		/* if last arg is -a, then -b and -d apply to all instances */
@@ -3934,6 +4313,8 @@ 
 			case 'B':
 				last_specified_all = 0;
 				instance = create_instance(optarg);
+				if (!instance)
+					die("Failed to create instance");
 				add_instance(instance);
 				/* -d will remove keep */
 				instance->keep = 1;
@@ -3965,11 +4346,11 @@ 
 			}
 		}
 		update_first_instance(instance, topt);
-		disable_all(1);
+		tracecmd_disable_all_tracing(1);
 		set_buffer_size();
 		clear_filters();
 		clear_triggers();
-		remove_instances();
+		tracecmd_remove_instances();
 		clear_func_filters();
 		exit(0);
 	} else
@@ -3985,6 +4366,9 @@ 
 			{"profile", no_argument, NULL, OPT_profile},
 			{"stderr", no_argument, NULL, OPT_stderr},
 			{"by-comm", no_argument, NULL, OPT_bycomm},
+			{"ts-offset", required_argument, NULL, OPT_tsoffset},
+			{"max-graph-depth", required_argument, NULL, OPT_max_graph_depth},
+			{"debug", no_argument, NULL, OPT_debug},
 			{"help", no_argument, NULL, '?'},
 			{NULL, 0, NULL, 0}
 		};
@@ -4010,7 +4394,9 @@ 
 			break;
 		case 'e':
 			events = 1;
-			event = malloc_or_die(sizeof(*event));
+			event = malloc(sizeof(*event));
+			if (!event)
+				die("Failed to allocate event %s", optarg);
 			memset(event, 0, sizeof(*event));
 			event->event = optarg;
 			add_event(instance, event);
@@ -4035,8 +4421,10 @@ 
 				strcat(last_event->filter, ")");
 			} else {
 				last_event->filter =
-					malloc_or_die(strlen(optarg) +
-						      strlen("()") + 1);
+					malloc(strlen(optarg) +
+					       strlen("()") + 1);
+				if (!last_event->filter)
+					die("Failed to allocate filter %s", optarg);
 				sprintf(last_event->filter, "(%s)", optarg);
 			}
 			break;
@@ -4048,27 +4436,35 @@ 
 			break;
 
 		case 'F':
+			test_set_event_pid();
 			filter_task = 1;
 			break;
 		case 'G':
 			global = 1;
 			break;
 		case 'P':
+			test_set_event_pid();
 			pids = strdup(optarg);
 			if (!pids)
 				die("strdup");
 			pid = strtok_r(pids, ",", &sav);
 			while (pid) {
-				add_filter_pid(atoi(pid));
+				add_filter_pid(atoi(pid), 0);
 				pid = strtok_r(NULL, ",", &sav);
 			}
 			free(pids);
 			break;
 		case 'c':
+			test_set_event_pid();
+			if (!have_event_fork) {
 #ifdef NO_PTRACE
-			die("-c invalid: ptrace not supported");
+				die("-c invalid: ptrace not supported");
 #endif
-			do_ptrace = 1;
+				do_ptrace = 1;
+			} else {
+				save_option("event-fork");
+				do_child = 1;
+			}
 			break;
 		case 'C':
 			instance->clock = optarg;
@@ -4177,7 +4573,7 @@ 
 			max_kb = atoi(optarg);
 			break;
 		case 'M':
-			instance->cpumask = optarg;
+			instance->cpumask = alloc_mask_from_hex(optarg);
 			break;
 		case 't':
 			if (extract)
@@ -4190,6 +4586,8 @@ 
 			break;
 		case 'B':
 			instance = create_instance(optarg);
+			if (!instance)
+				die("Failed to create instance");
 			add_instance(instance);
 			if (profile)
 				instance->profile = 1;
@@ -4202,6 +4600,9 @@ 
 			break;
 		case OPT_date:
 			date = 1;
+			if (data_flags & DATA_FL_OFFSET)
+				die("Can not use both --date and --ts-offset");
+			data_flags |= DATA_FL_DATE;
 			break;
 		case OPT_funcstack:
 			func_stack = 1;
@@ -4210,6 +4611,7 @@ 
 			recorder_flags |= TRACECMD_RECORD_NOSPLICE;
 			break;
 		case OPT_profile:
+			handle_init = trace_init_profile;
 			instance->profile = 1;
 			events = 1;
 			break;
@@ -4224,13 +4626,30 @@ 
 		case OPT_bycomm:
 			trace_profile_set_merge_like_comms();
 			break;
+		case OPT_tsoffset:
+			date2ts = strdup(optarg);
+			if (data_flags & DATA_FL_DATE)
+				die("Can not use both --date and --ts-offset");
+			data_flags |= DATA_FL_OFFSET;
+			break;
+		case OPT_max_graph_depth:
+			free(max_graph_depth);
+			max_graph_depth = strdup(optarg);
+			if (!max_graph_depth)
+				die("Could not allocate option");
+			break;
+		case OPT_debug:
+			debug = 1;
+			break;
 		default:
 			usage(argv);
 		}
 	}
 
 	if (do_ptrace && !filter_task && (filter_pid < 0))
-		die(" -c can only be used with -F or -P");
+		die(" -c can only be used with -F (or -P with event-fork support)");
+	if (do_child && !filter_task &&! filter_pid)
+		die(" -c can only be used with -P or -F");
 
 	if ((argc - optind) >= 2) {
 		if (start)
@@ -4295,7 +4714,7 @@ 
 
 	if (!extract) {
 		fset = set_ftrace(!disable, total_disable);
-		disable_all(1);
+		tracecmd_disable_all_tracing(1);
 
 		for_all_instances(instance)
 			set_clock(instance);
@@ -4323,8 +4742,7 @@ 
 	else if (extract)
 		type = TRACE_TYPE_EXTRACT;
 	else if (profile)
-		/* PROFILE includes the STREAM bit */
-		type = TRACE_TYPE_PROFILE;
+		type = TRACE_TYPE_STREAM;
 	else
 		type = TRACE_TYPE_START;
 
@@ -4332,6 +4750,12 @@ 
 
 	set_options();
 
+	if (max_graph_depth) {
+		for_all_instances(instance)
+			set_max_graph_depth(instance, max_graph_depth);
+		free(max_graph_depth);
+	}
+
 	allocate_seq();
 
 	if (type & (TRACE_TYPE_RECORD | TRACE_TYPE_STREAM)) {
@@ -4346,7 +4770,7 @@ 
 	} else {
 		if (!(type & (TRACE_TYPE_RECORD | TRACE_TYPE_STREAM))) {
 			update_task_filter();
-			enable_tracing();
+			tracecmd_enable_tracing();
 			exit(0);
 		}
 
@@ -4354,7 +4778,7 @@ 
 			run_cmd(type, (argc - optind) - 1, &argv[optind + 1]);
 		else {
 			update_task_filter();
-			enable_tracing();
+			tracecmd_enable_tracing();
 			/* We don't ptrace ourself */
 			if (do_ptrace && filter_pid >= 0)
 				ptrace_attach(filter_pid);
@@ -4364,7 +4788,7 @@ 
 				trace_or_sleep(type);
 		}
 
-		disable_tracing();
+		tracecmd_disable_tracing();
 		if (!latency)
 			stop_threads(type);
 	}
@@ -4372,7 +4796,7 @@ 
 	record_stats();
 
 	if (!keep)
-		disable_all(0);
+		tracecmd_disable_all_tracing(0);
 
 	/* extract records the date after extraction */
 	if (extract && date) {
@@ -4380,12 +4804,12 @@ 
 		 * We need to start tracing, don't let other traces
 		 * screw with our trace_marker.
 		 */
-		disable_all(1);
+		tracecmd_disable_all_tracing(1);
 		date2ts = get_date_to_ts();
 	}
 
 	if (record || extract) {
-		record_data(date2ts);
+		record_data(date2ts, data_flags);
 		delete_thread_data();
 	} else
 		print_stats();
@@ -4402,7 +4826,7 @@ 
 
 	set_plugin("nop");
 
-	remove_instances();
+	tracecmd_remove_instances();
 
 	/* If tracing_on was enabled before we started, set it on now */
 	for_all_instances(instance) {
diff -Nru trace-cmd-2.6/trace-recorder.c trace-cmd-2.6.1/trace-recorder.c
--- trace-cmd-2.6/trace-recorder.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-recorder.c	2017-05-02 19:35:16.000000000 +0200
@@ -34,6 +34,7 @@ 
 #include <errno.h>
 
 #include "trace-cmd.h"
+#include "event-utils.h"
 
 struct tracecmd_recorder {
 	int		fd;
@@ -116,7 +117,7 @@ 
 	char *path = NULL;
 	int ret;
 
-	recorder = malloc_or_die(sizeof(*recorder));
+	recorder = malloc(sizeof(*recorder));
 	if (!recorder)
 		return NULL;
 
@@ -155,7 +156,7 @@ 
 	recorder->fd1 = fd;
 	recorder->fd2 = fd2;
 
-	path = malloc_or_die(strlen(buffer) + 40);
+	path = malloc(strlen(buffer) + 40);
 	if (!path)
 		goto out_free;
 
@@ -167,14 +168,14 @@ 
 	if (recorder->trace_fd < 0)
 		goto out_free;
 
-	free(path);
-
 	if ((recorder->flags & TRACECMD_RECORD_NOSPLICE) == 0) {
 		ret = pipe(recorder->brass);
 		if (ret < 0)
 			goto out_free;
 	}
 
+	free(path);
+
 	return recorder;
 
  out_free:
diff -Nru trace-cmd-2.6/trace-show.c trace-cmd-2.6.1/trace-show.c
--- trace-cmd-2.6/trace-show.c	1970-01-01 01:00:00.000000000 +0100
+++ trace-cmd-2.6.1/trace-show.c	2017-05-02 19:35:16.000000000 +0200
@@ -0,0 +1,176 @@ 
+/*
+ * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License (not later!)
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not,  see <http://www.gnu.org/licenses>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+
+#include "trace-local.h"
+
+enum {
+	OPT_tracing_on			= 255,
+	OPT_current_tracer		= 254,
+	OPT_buffer_size_kb		= 253,
+	OPT_buffer_total_size_kb	= 252,
+	OPT_ftrace_filter		= 251,
+	OPT_ftrace_notrace		= 250,
+	OPT_ftrace_pid			= 249,
+	OPT_graph_function		= 248,
+	OPT_graph_notrace		= 247,
+	OPT_cpumask			= 246,
+};
+
+void trace_show(int argc, char **argv)
+{
+	const char *buffer = NULL;
+	const char *file = "trace";
+	const char *cpu = NULL;
+	struct buffer_instance *instance = &top_instance;
+	char cpu_path[128];
+	char *path;
+	int snap = 0;
+	int pipe = 0;
+	int show_name = 0;
+	int option_index = 0;
+	int stop = 0;
+	int c;
+	static struct option long_options[] = {
+		{"tracing_on", no_argument, NULL, OPT_tracing_on},
+		{"current_tracer", no_argument, NULL, OPT_current_tracer},
+		{"buffer_size", no_argument, NULL, OPT_buffer_size_kb},
+		{"buffer_total_size", no_argument, NULL, OPT_buffer_total_size_kb},
+		{"ftrace_filter", no_argument, NULL, OPT_ftrace_filter},
+		{"ftrace_notrace", no_argument, NULL, OPT_ftrace_notrace},
+		{"ftrace_pid", no_argument, NULL, OPT_ftrace_pid},
+		{"graph_function", no_argument, NULL, OPT_graph_function},
+		{"graph_notrace", no_argument, NULL, OPT_graph_notrace},
+		{"cpumask", no_argument, NULL, OPT_cpumask},
+		{"help", no_argument, NULL, '?'},
+		{NULL, 0, NULL, 0}
+	};
+
+	while ((c = getopt_long(argc-1, argv+1, "B:c:fsp",
+				long_options, &option_index)) >= 0) {
+		switch (c) {
+		case 'h':
+			usage(argv);
+			break;
+		case 'B':
+			if (buffer)
+				die("Can only show one buffer at a time");
+			buffer = optarg;
+			instance = create_instance(optarg);
+			if (!instance)
+				die("Failed to create instance");
+			break;
+		case 'c':
+			if (cpu)
+				die("Can only show one CPU at a time");
+			cpu = optarg;
+			break;
+		case 'f':
+			show_name = 1;
+			break;
+		case 's':
+			snap = 1;
+			if (pipe)
+				die("Can not have -s and -p together");
+			break;
+		case 'p':
+			pipe = 1;
+			if (snap)
+				die("Can not have -s and -p together");
+			break;
+		case OPT_tracing_on:
+			show_instance_file(instance, "tracing_on");
+			stop = 1;
+			break;
+		case OPT_current_tracer:
+			show_instance_file(instance, "current_tracer");
+			stop = 1;
+			break;
+		case OPT_buffer_size_kb:
+			show_instance_file(instance, "buffer_size_kb");
+			stop = 1;
+			break;
+		case OPT_buffer_total_size_kb:
+			show_instance_file(instance, "buffer_total_size_kb");
+			stop = 1;
+			break;
+		case OPT_ftrace_filter:
+			show_instance_file(instance, "set_ftrace_filter");
+			stop = 1;
+			break;
+		case OPT_ftrace_notrace:
+			show_instance_file(instance, "set_ftrace_notrace");
+			stop = 1;
+			break;
+		case OPT_ftrace_pid:
+			show_instance_file(instance, "set_ftrace_pid");
+			stop = 1;
+			break;
+		case OPT_graph_function:
+			show_instance_file(instance, "set_graph_function");
+			stop = 1;
+			break;
+		case OPT_graph_notrace:
+			show_instance_file(instance, "set_graph_notrace");
+			stop = 1;
+			break;
+		case OPT_cpumask:
+			show_instance_file(instance, "tracing_cpumask");
+			stop = 1;
+			break;
+		default:
+			usage(argv);
+		}
+	}
+	if (stop)
+		exit(0);
+	if (pipe)
+		file = "trace_pipe";
+	else if (snap)
+		file = "snapshot";
+
+	if (cpu) {
+		snprintf(cpu_path, 128, "per_cpu/cpu%d/%s", atoi(cpu), file);
+		file = cpu_path;
+	}
+
+	if (buffer) {
+		path = malloc(strlen(buffer) + strlen("instances//") +
+			      strlen(file) + 1);
+		if (!path)
+			die("Failed to allocate instance path %s", file);
+		sprintf(path, "instances/%s/%s", buffer, file);
+		file = path;
+	}
+
+	if (show_name) {
+		char *name;
+		name = tracecmd_get_tracing_file(file);
+		printf("%s\n", name);
+		tracecmd_put_tracing_file(name);
+	}
+	show_file(file);
+	if (buffer)
+		free(path);
+
+	return;
+}
diff -Nru trace-cmd-2.6/trace-snapshot.c trace-cmd-2.6.1/trace-snapshot.c
--- trace-cmd-2.6/trace-snapshot.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-snapshot.c	2017-05-02 19:35:16.000000000 +0200
@@ -42,7 +42,8 @@ 
 
 	n = write(fd, val, strlen(val));
 	if (n < 0)
-		die("failed to write '%d' to %s\n", path);
+		die("failed to write to %s\n", path);
+
 	tracecmd_put_tracing_file(path);
 	close(fd);
 }
diff -Nru trace-cmd-2.6/trace-split.c trace-cmd-2.6.1/trace-split.c
--- trace-cmd-2.6/trace-split.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-split.c	2017-05-02 19:35:16.000000000 +0200
@@ -244,8 +244,11 @@ 
 
 			if (cpu_data[cpu].page)
 				write_page(pevent, &cpu_data[cpu], long_size);
-			else
-				cpu_data[cpu].page = malloc_or_die(page_size);
+			else {
+				cpu_data[cpu].page = malloc(page_size);
+				if (!cpu_data[cpu].page)
+					die("Failed to allocate page");
+			}
 
 			memset(cpu_data[cpu].page, 0, page_size);
 			ptr = cpu_data[cpu].page;
@@ -361,10 +364,14 @@ 
 	ohandle = tracecmd_copy(handle, output_file);
 
 	cpus = tracecmd_cpus(handle);
-	cpu_data = malloc_or_die(sizeof(*cpu_data) * cpus);
+	cpu_data = malloc(sizeof(*cpu_data) * cpus);
+	if (!cpu_data)
+		die("Failed to allocate cpu_data for %d cpus", cpus);
 
 	for (cpu = 0; cpu < cpus; cpu++) {
-		file = malloc_or_die(strlen(output_file) + 50);
+		file = malloc(strlen(output_file) + 50);
+		if (!file)
+			die("Failed to allocate file for %s %s %d", dir, base, cpu);
 		sprintf(file, "%s/.tmp.%s.%d", dir, base, cpu);
 		fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
 		cpu_data[cpu].cpu = cpu;
@@ -386,7 +393,9 @@ 
 		parse_cpu(handle, cpu_data, start,
 			  end, count, percpu, -1, type);
 
-	cpu_list = malloc_or_die(sizeof(*cpu_list) * cpus);
+	cpu_list = malloc(sizeof(*cpu_list) * cpus);
+	if (!cpu_list)
+		die("Failed to allocate cpu_list for %d cpus", cpus);
 	for (cpu = 0; cpu < cpus; cpu ++)
 		cpu_list[cpu] = cpu_data[cpu].file;
 
@@ -530,7 +539,9 @@ 
 	}
 
 	current = start_ns;
-	output_file = malloc_or_die(strlen(output) + 50);
+	output_file = malloc(strlen(output) + 50);
+	if (!output_file)
+		die("Failed to allocate for %s", output);
 	c = 1;
 
 	do {
diff -Nru trace-cmd-2.6/trace-stat.c trace-cmd-2.6.1/trace-stat.c
--- trace-cmd-2.6/trace-stat.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-stat.c	2017-05-02 19:35:16.000000000 +0200
@@ -74,9 +74,9 @@ 
 {
 	char *file;
 
-	file = malloc_or_die(strlen(dir) + strlen(name) + 2);
+	file = malloc(strlen(dir) + strlen(name) + 2);
 	if (!file)
-		die("malloc");
+		die("Failed to allocate %s/%s", dir, name);
 
 	sprintf(file, "%s/%s", dir, name);
 	return file;
@@ -158,7 +158,9 @@ 
 {
 	struct event_iter *iter;
 
-	iter = malloc_or_die(sizeof(*iter));
+	iter = malloc(sizeof(*iter));
+	if (!iter)
+		die("Failed to allocate event_iter for path %s", path);
 	memset(iter, 0, sizeof(*iter));
 
 	iter->system_dir = opendir(path);
@@ -902,6 +904,8 @@ 
 			break;
 		case 'B':
 			instance = create_instance(optarg);
+			if (!instance)
+				die("Failed to create instance");
 			add_instance(instance);
 			/* top instance requires direct access */
 			if (!topt && is_top_instance(first_instance))
diff -Nru trace-cmd-2.6/trace-stream.c trace-cmd-2.6.1/trace-stream.c
--- trace-cmd-2.6/trace-stream.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-stream.c	2017-05-02 19:35:16.000000000 +0200
@@ -35,7 +35,8 @@ 
  */
 struct tracecmd_input *
 trace_stream_init(struct buffer_instance *instance, int cpu, int fd, int cpus,
-		  int profile, struct hook_list *hooks, int global)
+		  struct hook_list *hooks,
+		  tracecmd_handle_init_func handle_init, int global)
 {
 	struct tracecmd_input *trace_input;
 	struct tracecmd_output *trace_output;
@@ -75,8 +76,8 @@ 
 	if (tracecmd_read_headers(trace_input) < 0)
 		goto fail_free_input;
 
-	if (profile)
-		trace_init_profile(trace_input, hooks, global);
+	if (handle_init)
+		handle_init(trace_input, hooks, global);
 
  make_pipe:
 	/* Do not block on this pipe */
@@ -98,8 +99,7 @@ 
 	return NULL;
 }
 
-int trace_stream_read(struct pid_record_data *pids, int nr_pids, struct timeval *tv,
-		      int profile)
+int trace_stream_read(struct pid_record_data *pids, int nr_pids, struct timeval *tv)
 {
 	struct pevent_record *record;
 	struct pid_record_data *pid;
@@ -127,7 +127,7 @@ 
 			last_pid = pid;
 	}
 	if (last_pid) {
-		trace_show_data(last_pid->instance->handle, last_pid->record, profile);
+		trace_show_data(last_pid->instance->handle, last_pid->record);
 		free_record(last_pid->record);
 		last_pid->record = NULL;
 		return 1;
diff -Nru trace-cmd-2.6/trace-usage.c trace-cmd-2.6.1/trace-usage.c
--- trace-cmd-2.6/trace-usage.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-usage.c	2017-05-02 19:35:16.000000000 +0200
@@ -52,6 +52,7 @@ 
 		"          --profile enable tracing options needed for report --profile\n"
 		"          --func-stack perform a stack trace for function tracer\n"
 		"             (use with caution)\n"
+		"          --max-graph-depth limit function_graph depth\n"
 	},
 	{
 		"start",
@@ -139,6 +140,8 @@ 
 		"          -P show printk list\n"
 		"          -E show event files stored\n"
 		"          -F filter to filter output on\n"
+		"          -I filter out events with the HARDIRQ flag set\n"
+		"          -S filter out events with the SOFTIRQ flag set\n"
 		"          -t print out full timestamp. Do not truncate to 6 places.\n"
 		"          -R raw format: ignore print format and only show field data\n"
 		"          -r raw format the events that match the option\n"
@@ -159,6 +162,13 @@ 
 		"          -H Allows users to hook two events together for timings\n"
 		"             (used with --profile)\n"
 		"          --by-comm used with --profile, merge events for related comms\n"
+		"          --ts-offset will add amount to timestamp of all events of the\n"
+		"                     previous data file.\n"
+		"          --ts2secs HZ, pass in the timestamp frequency (per second)\n"
+		"                     to convert the displayed timestamps to seconds\n"
+		"                     Affects the previous data file, unless there was no\n"
+		"                     previous data file, in which case it becomes default\n"
+		"           --ts-diff Show the delta timestamp between events.\n"
 	},
 	{
 		"stream",
@@ -317,3 +327,9 @@ 
 	printf("\n");
 	exit(-1);
 }
+
+
+void trace_usage(int argc, char **argv)
+{
+	usage(argv);
+}
diff -Nru trace-cmd-2.6/trace-util.c trace-cmd-2.6.1/trace-util.c
--- trace-cmd-2.6/trace-util.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-util.c	2017-05-02 19:35:16.000000000 +0200
@@ -32,6 +32,7 @@ 
 #include <sys/stat.h>
 
 #include "trace-cmd.h"
+#include "event-utils.h"
 
 #define LOCAL_PLUGIN_DIR ".trace-cmd/plugins"
 #define TRACEFS_PATH "/sys/kernel/tracing"
@@ -88,11 +89,19 @@ 
 		for (op = reg->options; op->name; op++) {
 			char *alias = op->plugin_alias ? op->plugin_alias : op->file;
 
-			name = malloc_or_die(strlen(op->name) + strlen(alias) + 2);
+			name = malloc(strlen(op->name) + strlen(alias) + 2);
+			if (!name) {
+				warning("Failed to allocate plugin option %s:%s",
+					alias, op->name);
+				break;
+			}
 			sprintf(name, "%s:%s", alias, op->name);
 			list = realloc(list, count + 2);
-			if (!list)
-				die("realloc");
+			if (!list) {
+				warning("Failed to allocate plugin list for %s", name);
+				free(name);
+				break;
+			}
 			list[count++] = name;
 			list[count] = NULL;
 		}
@@ -108,7 +117,7 @@ 
 }
 
 static int process_option(const char *plugin, const char *option, const char *val);
-static void update_option(const char *file, struct pevent_plugin_option *option);
+static int update_option(const char *file, struct pevent_plugin_option *option);
 
 /**
  * trace_util_add_options - Add a set of options by a plugin
@@ -117,19 +126,25 @@ 
  *
  * Sets the options with the values that have been added by user.
  */
-void trace_util_add_options(const char *name, struct pevent_plugin_option *options)
+int trace_util_add_options(const char *name, struct pevent_plugin_option *options)
 {
 	struct registered_plugin_options *reg;
+	int ret;
 
-	reg = malloc_or_die(sizeof(*reg));
+	reg = malloc(sizeof(*reg));
+	if (!reg)
+		return -ENOMEM;
 	reg->next = registered_options;
 	reg->options = options;
 	registered_options = reg;
 
 	while (options->name) {
-		update_option("ftrace", options);
+		ret = update_option("ftrace", options);
+		if (ret < 0)
+			return ret;
 		options++;
 	}
+	return 0;
 }
 
 /**
@@ -184,7 +199,7 @@ 
 		*p = '\0';
 		*option = strdup(p + 1);
 		if (!*option)
-			die("malloc");
+			return;
 	}
 }
 
@@ -223,7 +238,7 @@ 
 
 	option_str = strdup(name);
 	if (!option_str)
-		die("malloc");
+		return NULL;
 
 	parse_option_name(&option_str, &plugin);
 	option = find_registered_option(plugin, option_str);
@@ -265,7 +280,7 @@ 
  * is set (note, some options just take a boolean, so @val must be either
  * "1" or "0" or "true" or "false").
  */
-void trace_util_add_option(const char *name, const char *val)
+int trace_util_add_option(const char *name, const char *val)
 {
 	struct trace_plugin_options *op;
 	char *option_str;
@@ -273,7 +288,7 @@ 
 	
 	option_str = strdup(name);
 	if (!option_str)
-		die("malloc");
+		return -ENOMEM;
 
 	parse_option_name(&option_str, &plugin);
 
@@ -292,7 +307,7 @@ 
 		if (val) {
 			op->value = strdup(val);
 			if (!op->value)
-				die("malloc");
+				goto out_free;
 		} else
 			op->value = NULL;
 
@@ -307,7 +322,9 @@ 
 
 	/* If not found, create */
 	if (!op) {
-		op = malloc_or_die(sizeof(*op));
+		op = malloc(sizeof(*op));
+		if (!op)
+			return -ENOMEM;
 		memset(op, 0, sizeof(*op));
 		op->next = trace_plugin_options;
 		trace_plugin_options = op;
@@ -318,18 +335,21 @@ 
 		if (val) {
 			op->value = strdup(val);
 			if (!op->value)
-				die("malloc");
+				goto out_free;
 		}
 	}
 
-	process_option(plugin, option_str, val);
+	return process_option(plugin, option_str, val);
+ out_free:
+	free(option_str);
+	return -ENOMEM;
 }
 
 static void print_op_data(struct trace_seq *s, const char *name,
 			  const char *op)
 {
-		if (op)
-			trace_seq_printf(s, "%8s:\t%s\n", name, op);
+	if (op)
+		trace_seq_printf(s, "%8s:\t%s\n", name, op);
 }
 
 /**
@@ -359,8 +379,8 @@ 
 	}
 }
 
-void parse_cmdlines(struct pevent *pevent,
-		    char *file, int size __maybe_unused)
+void tracecmd_parse_cmdlines(struct pevent *pevent,
+			     char *file, int size __maybe_unused)
 {
 	char *comm;
 	char *line;
@@ -388,8 +408,8 @@ 
 	free(clock);
 }
 
-void parse_trace_clock(struct pevent *pevent,
-			char *file, int size __maybe_unused)
+void tracecmd_parse_trace_clock(struct pevent *pevent,
+				char *file, int size __maybe_unused)
 {
 	char *line;
 	char *next = NULL;
@@ -403,7 +423,7 @@ 
 	}
 }
 
-void parse_proc_kallsyms(struct pevent *pevent,
+void tracecmd_parse_proc_kallsyms(struct pevent *pevent,
 			 char *file, unsigned int size __maybe_unused)
 {
 	unsigned long long addr;
@@ -434,8 +454,12 @@ 
 		if (mod)
 			mod[strlen(mod) - 1] = 0;
 
-		/* Hack for arm arch that adds a lot of bogus '$a' functions */
-		if (func[0] != '$')
+		/*
+		 * Hacks for
+		 *  - arm arch that adds a lot of bogus '$a' functions
+		 *  - x86-64 that reports per-cpu variable offsets as absolute
+		 */
+		if (func[0] != '$' && ch != 'A' && ch != 'a')
 			pevent_register_function(pevent, func, addr, mod);
 		free(func);
 		free(mod);
@@ -444,7 +468,7 @@ 
 	}
 }
 
-void parse_ftrace_printk(struct pevent *pevent,
+void tracecmd_parse_ftrace_printk(struct pevent *pevent,
 			 char *file, unsigned int size __maybe_unused)
 {
 	unsigned long long addr;
@@ -505,7 +529,7 @@ 
 
 	op_val = strdup(val);
 	if (!op_val)
-		die("malloc");
+		return -ENOMEM;
 	lower_case(op_val);
 
 	if (strcmp(val, "1") == 0 || strcmp(val, "true") == 0)
@@ -531,7 +555,7 @@ 
 	return update_option_value(op, val);
 }
 
-static void update_option(const char *file, struct pevent_plugin_option *option)
+static int update_option(const char *file, struct pevent_plugin_option *option)
 {
 	struct trace_plugin_options *op;
 	char *plugin;
@@ -539,12 +563,12 @@ 
 	if (option->plugin_alias) {
 		plugin = strdup(option->plugin_alias);
 		if (!plugin)
-			die("malloc");
+			return -ENOMEM;
 	} else {
 		char *p;
 		plugin = strdup(file);
 		if (!plugin)
-			die("malloc");
+			return -ENOMEM;
 		p = strstr(plugin, ".");
 		if (p)
 			*p = '\0';
@@ -578,10 +602,11 @@ 
 
  out:
 	free(plugin);
+	return 0;
 }
 
-static void load_plugin(struct pevent *pevent, const char *path,
-			const char *file, void *data)
+static int load_plugin(struct pevent *pevent, const char *path,
+		       const char *file, void *data)
 {
 	struct plugin_list **plugin_list = data;
 	pevent_plugin_load_func func;
@@ -590,8 +615,11 @@ 
 	const char *alias;
 	char *plugin;
 	void *handle;
+	int ret;
 
-	plugin = malloc_or_die(strlen(path) + strlen(file) + 2);
+	plugin = malloc(strlen(path) + strlen(file) + 2);
+	if (!plugin)
+		return -ENOMEM;
 
 	strcpy(plugin, path);
 	strcat(plugin, "/");
@@ -611,7 +639,9 @@ 
 	options = dlsym(handle, PEVENT_PLUGIN_OPTIONS_NAME);
 	if (options) {
 		while (options->name) {
-			update_option(alias, options);
+			ret = update_option(alias, options);
+			if (ret < 0)
+				goto out_free;
 			options++;
 		}
 	}
@@ -623,7 +653,9 @@ 
 		goto out_free;
 	}
 
-	list = malloc_or_die(sizeof(*list));
+	list = malloc(sizeof(*list));
+	if (!list)
+		goto out_free;
 	list->next = *plugin_list;
 	list->handle = handle;
 	list->name = plugin;
@@ -631,10 +663,11 @@ 
 
 	pr_stat("registering plugin: %s", plugin);
 	func(pevent);
-	return;
+	return 0;
 
  out_free:
 	free(plugin);
+	return -1;
 }
 
 static int mount_debugfs(void)
@@ -645,7 +678,7 @@ 
 	/* make sure debugfs exists */
 	ret = stat(DEBUGFS_PATH, &st);
 	if (ret < 0)
-		die("debugfs is not configured on this kernel");
+		return -1;
 
 	ret = mount("nodev", DEBUGFS_PATH,
 		    "debugfs", 0, NULL);
@@ -691,8 +724,10 @@ 
 			break;
 		if (!debug_str && strcmp(type, "debugfs") == 0) {
 			debug_str = strdup(fspath);
-			if (!debug_str)
+			if (!debug_str) {
+				fclose(fp);
 				return NULL;
+			}
 		}
 	}
 	fclose(fp);
@@ -705,6 +740,7 @@ 
 			} else {
 				if (mount_debugfs() < 0) {
 					warning("debugfs not mounted, please mount");
+					free(debug_str);
 					return NULL;
 				}
 				strcpy(fspath, DEBUGFS_PATH);
@@ -745,7 +781,7 @@ 
 {
 	char *file;
 
-	file = malloc_or_die(strlen(dir) + strlen(name) + 2);
+	file = malloc(strlen(dir) + strlen(name) + 2);
 	if (!file)
 		return NULL;
 
@@ -769,16 +805,15 @@ 
 char **tracecmd_add_list(char **list, const char *name, int len)
 {
 	if (!list)
-		list = malloc_or_die(sizeof(*list) * 2);
-	else {
+		list = malloc(sizeof(*list) * 2);
+	else
 		list = realloc(list, sizeof(*list) * (len + 2));
-		if (!list)
-			die("Can not allocate list");
-	}
+	if (!list)
+		return NULL;
 
 	list[len] = strdup(name);
 	if (!list[len])
-		die("Can not allocate list");
+		return NULL;
 
 	list[len + 1] = NULL;
 
@@ -822,12 +857,11 @@ 
 int *tracecmd_add_id(int *list, int id, int len)
 {
 	if (!list)
-		list = malloc_or_die(sizeof(*list) * 2);
-	else {
+		list = malloc(sizeof(*list) * 2);
+	else
 		list = realloc(list, sizeof(*list) * (len + 2));
-		if (!list)
-			die("Can ont allocate list");
-	}
+	if (!list)
+		return NULL;
 
 	list[len++] = id;
 	list[len] = -1;
@@ -1000,7 +1034,11 @@ 
 	if (fd < 0)
 		return -1;
 
-	buf = malloc_or_die(BUFSIZ + 1);
+	buf = malloc(BUFSIZ + 1);
+	if (!buf) {
+		len = -1;
+		goto out;
+	}
 
 	while ((r = read(fd, buf + len, BUFSIZ)) > 0) {
 		len += r;
@@ -1264,9 +1302,9 @@ 
 static void
 trace_util_load_plugins_dir(struct pevent *pevent, const char *suffix,
 			    const char *path,
-			    void (*load_plugin)(struct pevent *pevent,
-						const char *path,
-						const char *name,
+			    int (*load_plugin)(struct pevent *pevent,
+					       const char *path,
+					       const char *name,
 						void *data),
 			    void *data)
 {
@@ -1311,8 +1349,8 @@ 
 	char **files;
 };
 
-static void add_plugin_file(struct pevent *pevent, const char *path,
-			    const char *name, void *data)
+static int add_plugin_file(struct pevent *pevent, const char *path,
+			   const char *name, void *data)
 {
 	struct add_plugin_data *pdata = data;
 	char **ptr;
@@ -1320,7 +1358,7 @@ 
 	int i;
 
 	if (pdata->ret)
-		return;
+		return 0;
 
 	size = pdata->index + 2;
 	ptr = realloc(pdata->files, sizeof(char *) * size);
@@ -1334,7 +1372,7 @@ 
 	pdata->files = ptr;
 	pdata->index++;
 	pdata->files[pdata->index] = NULL;
-	return;
+	return 0;
 
  out_free:
 	for (i = 0; i < pdata->index; i++)
@@ -1342,21 +1380,22 @@ 
 	free(pdata->files);
 	pdata->files = NULL;
 	pdata->ret = errno;
+	return -ENOMEM;
 }
 
-void trace_util_load_plugins(struct pevent *pevent, const char *suffix,
-			     void (*load_plugin)(struct pevent *pevent,
-						 const char *path,
-						 const char *name,
-						 void *data),
-			     void *data)
+int trace_util_load_plugins(struct pevent *pevent, const char *suffix,
+			    int (*load_plugin)(struct pevent *pevent,
+					       const char *path,
+					       const char *name,
+					       void *data),
+			    void *data)
 {
 	char *home;
 	char *path;
         char *envdir;
 
 	if (tracecmd_disable_plugins)
-		return;
+		return -EBUSY;
 
 /* If a system plugin directory was defined, check that first */
 #ifdef PLUGIN_DIR
@@ -1374,9 +1413,11 @@ 
 	home = getenv("HOME");
 
 	if (!home)
-		return;
+		return -EINVAL;
 
-	path = malloc_or_die(strlen(home) + strlen(LOCAL_PLUGIN_DIR) + 2);
+	path = malloc(strlen(home) + strlen(LOCAL_PLUGIN_DIR) + 2);
+	if (!path)
+		return -ENOMEM;
 
 	strcpy(path, home);
 	strcat(path, "/");
@@ -1385,6 +1426,7 @@ 
 	trace_util_load_plugins_dir(pevent, suffix, path, load_plugin, data);
 
 	free(path);
+	return 0;
 }
 
 /**
@@ -1407,7 +1449,6 @@ 
 
 	memset(&pdata, 0, sizeof(pdata));
 
-
 	trace_util_load_plugins(NULL, suffix, add_plugin_file, &pdata);
 
 	if (pdata.ret)
@@ -1439,14 +1480,16 @@ 
 	struct pevent_plugin_option	*options;
 };
 
-static void append_option(struct plugin_option_read *options,
-			  struct pevent_plugin_option *option,
-			  const char *alias, void *handle)
+static int append_option(struct plugin_option_read *options,
+			 struct pevent_plugin_option *option,
+			 const char *alias, void *handle)
 {
 	struct pevent_plugin_option *op;
 
 	while (option->name) {
-		op = malloc_or_die(sizeof(*op));
+		op = malloc(sizeof(*op));
+		if (!op)
+			return -ENOMEM;
 		*op = *option;
 		op->next = options->options;
 		options->options = op;
@@ -1454,9 +1497,10 @@ 
 		op->handle = handle;
 		option++;
 	}
+	return 0;
 }
 
-static void read_options(struct pevent *pevent, const char *path,
+static int read_options(struct pevent *pevent, const char *path,
 			 const char *file, void *data)
 {
 	struct plugin_option_read *options = data;
@@ -1466,7 +1510,9 @@ 
 	char *plugin;
 	void *handle;
 
-	plugin = malloc_or_die(strlen(path) + strlen(file) + 2);
+	plugin = malloc(strlen(path) + strlen(file) + 2);
+	if (!plugin)
+		return -ENOMEM;
 
 	strcpy(plugin, path);
 	strcat(plugin, "/");
@@ -1496,6 +1542,7 @@ 
 		dlclose(handle);
  out_free:
 	free(plugin);
+	return 0;
 }
 
 struct pevent_plugin_option *trace_util_read_plugin_options(void)
@@ -1563,10 +1610,10 @@ 
 	if (!tracing) {
 		tracing = tracecmd_find_tracing_dir();
 		if (!tracing)
-			die("Can't find tracing dir");
+			return NULL;
 	}
 
-	file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
+	file = malloc(strlen(tracing) + strlen(name) + 2);
 	if (!file)
 		return NULL;
 
@@ -1578,3 +1625,49 @@ 
 {
 	free(name);
 }
+
+void __vdie(const char *fmt, va_list ap)
+{
+	int ret = errno;
+
+	if (errno)
+		perror("trace-cmd");
+	else
+		ret = -1;
+
+	fprintf(stderr, "  ");
+	vfprintf(stderr, fmt, ap);
+
+	fprintf(stderr, "\n");
+	exit(ret);
+}
+
+void __die(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	__vdie(fmt, ap);
+	va_end(ap);
+}
+
+#define __weak __attribute__((weak))
+
+void __weak die(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	__vdie(fmt, ap);
+	va_end(ap);
+}
+
+void __weak *malloc_or_die(unsigned int size)
+{
+	void *data;
+
+	data = malloc(size);
+	if (!data)
+		die("malloc");
+	return data;
+}
diff -Nru trace-cmd-2.6/trace-view.c trace-cmd-2.6.1/trace-view.c
--- trace-cmd-2.6/trace-view.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-view.c	2017-05-02 19:35:16.000000000 +0200
@@ -18,6 +18,7 @@ 
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
 #include <gtk/gtk.h>
@@ -30,6 +31,7 @@ 
 #include "trace-compat.h"
 #include "cpu.h"
 #include "event-utils.h"
+#include "trace-local.h"
 
 enum {
 	COL_INDEX,
@@ -335,9 +337,7 @@ 
 
 static void select_row_from_path(GtkTreeView *tree, GtkTreePath *path)
 {
-	GtkTreeSelection *selection;
-
-	selection = gtk_tree_view_get_selection(tree);
+	gtk_tree_view_get_selection(tree);
 	gtk_tree_view_set_cursor(tree, path, NULL, FALSE);
 }
 
@@ -864,6 +864,8 @@ 
 	path = gtk_tree_model_get_path(model, &iter);
 	select_row_from_path(info->treeview, path);
 	gtk_tree_path_free(path);
+
+	gtk_widget_grab_focus(GTK_WIDGET(info->entry));
 }
 
 void trace_view_search_setup(GtkBox *box, GtkTreeView *treeview)
diff -Nru trace-cmd-2.6/trace-view-main.c trace-cmd-2.6.1/trace-view-main.c
--- trace-cmd-2.6/trace-view-main.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-view-main.c	2017-05-02 19:35:16.000000000 +0200
@@ -26,6 +26,7 @@ 
 #include <libgen.h>
 
 #include "trace-cmd.h"
+#include "event-utils.h"
 #include "trace-view.h"
 #include "trace-xml.h"
 #include "trace-filter.h"
@@ -283,6 +284,26 @@ 
 	info->filter_enabled = 0;
 }
 
+static void
+display_event_clicked (gpointer data)
+{
+	struct trace_tree_info *info = data;
+
+	return;
+	trace_view_update_filters(info->trace_tree, NULL, NULL);
+	info->filter_enabled = 0;
+}
+
+static void
+display_raw_event_clicked (gpointer data)
+{
+	struct trace_tree_info *info = data;
+
+	return;
+	trace_view_update_filters(info->trace_tree, NULL, NULL);
+	info->filter_enabled = 0;
+}
+
 static gboolean
 do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data)
 {
@@ -292,6 +313,8 @@ 
 	static GtkWidget *menu_filter_add_task;
 	static GtkWidget *menu_filter_hide_task;
 	static GtkWidget *menu_filter_clear_tasks;
+	static GtkWidget *menu_display_event;
+	static GtkWidget *menu_display_raw_event;
 	struct pevent *pevent;
 	struct pevent_record *record;
 	TraceViewRecord *vrec;
@@ -339,6 +362,22 @@ 
 					  G_CALLBACK (filter_clear_tasks_clicked),
 					  data);
 
+
+		menu_display_event = gtk_menu_item_new_with_label("Display event");
+		gtk_widget_show(menu_display_event);
+		gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_display_event);
+
+		g_signal_connect_swapped (G_OBJECT (menu_display_event), "activate",
+					  G_CALLBACK (display_event_clicked),
+					  data);
+
+		menu_display_raw_event = gtk_menu_item_new_with_label("Display raw event");
+		gtk_widget_show(menu_display_raw_event);
+		gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_display_raw_event);
+
+		g_signal_connect_swapped (G_OBJECT (menu_display_raw_event), "activate",
+					  G_CALLBACK (display_raw_event_clicked),
+					  data);
 	}
 
 	row = trace_view_get_selected_row(GTK_WIDGET(info->trace_tree));
@@ -384,11 +423,16 @@ 
 
 			gtk_widget_show(menu_filter_add_task);
 			gtk_widget_show(menu_filter_hide_task);
+
+			gtk_widget_show(menu_display_event);
+			gtk_widget_show(menu_display_raw_event);
 			free_record(record);
 		}
 	} else {
 		gtk_widget_hide(menu_filter_add_task);
 		gtk_widget_hide(menu_filter_hide_task);
+		gtk_widget_hide(menu_display_event);
+		gtk_widget_hide(menu_display_raw_event);
 	}
 
 	if (info->filter_enabled)
diff -Nru trace-cmd-2.6/trace-view-store.c trace-cmd-2.6.1/trace-view-store.c
--- trace-cmd-2.6/trace-view-store.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-view-store.c	2017-05-02 19:35:16.000000000 +0200
@@ -1156,9 +1156,8 @@ 
 gint get_next_pid(TraceViewStore *store, struct pevent *pevent, struct pevent_record *record)
 {
 	unsigned long long val;
-	int ret;
 
-	ret = pevent_read_number_field(store->sched_switch_next_field, record->data, &val);
+	pevent_read_number_field(store->sched_switch_next_field, record->data, &val);
 
 	return val;
 }
@@ -1166,9 +1165,8 @@ 
 gint get_wakeup_pid(TraceViewStore *store, struct pevent *pevent, struct pevent_record *record)
 {
 	unsigned long long val;
-	int ret;
 
-	ret = pevent_read_number_field(store->sched_wakeup_pid_field, record->data, &val);
+	pevent_read_number_field(store->sched_wakeup_pid_field, record->data, &val);
 
 	return val;
 }
@@ -1176,9 +1174,8 @@ 
 gint get_wakeup_new_pid(TraceViewStore *store, struct pevent *pevent, struct pevent_record *record)
 {
 	unsigned long long val;
-	int ret;
 
-	ret = pevent_read_number_field(store->sched_wakeup_new_pid_field, record->data, &val);
+	pevent_read_number_field(store->sched_wakeup_new_pid_field, record->data, &val);
 
 	return val;
 }
diff -Nru trace-cmd-2.6/trace-xml.c trace-cmd-2.6.1/trace-xml.c
--- trace-cmd-2.6/trace-xml.c	2016-05-28 13:21:12.000000000 +0200
+++ trace-cmd-2.6.1/trace-xml.c	2017-05-02 19:35:16.000000000 +0200
@@ -28,6 +28,7 @@ 
 
 #include "trace-cmd.h"
 #include "trace-xml.h"
+#include "trace-local.h"
 
 struct tracecmd_xml_handle {
 	xmlTextWriterPtr	writer;