diff --git a/SOURCES/ltrace-0.7.91-account_execl.patch b/SOURCES/ltrace-0.7.91-account_execl.patch
new file mode 100644
index 0000000..2aa4ba0
--- /dev/null
+++ b/SOURCES/ltrace-0.7.91-account_execl.patch
@@ -0,0 +1,834 @@
+From 0cf4ab66e9927e101a51dd9fa9adc6c8dc56b5e7 Mon Sep 17 00:00:00 2001
+From: Petr Machata <pmachata@redhat.com>
+Date: Thu, 21 Nov 2013 20:25:53 +0100
+Subject: [PATCH] Consider exec and exit events an end of outstanding calls
+
+- This cleans up a lot of stuff.  The actual substance is addition of
+  account_current_callstack in handle_event.c (which however uses
+  those cleaned-up interfaces).
+
+- trace-exec.exp was extended to check that the exec syscall can be
+  seen in -c output.  That's one of the symptoms of what this fixes.
+---
+ Makefile.am                           |    8 +-
+ common.h                              |    2 -
+ forward.h                             |    1 +
+ handle_event.c                        |  225 ++++++++++++++++++++-------------
+ libltrace.c                           |    5 +-
+ options.h                             |    8 +-
+ output.c                              |   86 +++----------
+ output.h                              |    5 +-
+ proc.h                                |    2 +-
+ summary.c                             |   89 +++++++++++++-
+ summary.h                             |   35 +++++
+ testsuite/ltrace.minor/trace-exec.exp |   16 ++-
+ 12 files changed, 299 insertions(+), 183 deletions(-)
+ create mode 100644 summary.h
+
+diff --git a/Makefile.am b/Makefile.am
+index d711aec..efcf18a 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -54,10 +54,10 @@ ltrace_LDADD = \
+ 
+ noinst_HEADERS = bits.h backend.h breakpoint.h common.h debug.h		\
+ 	defs.h demangle.h dict.h forward.h ltrace-elf.h ltrace.h	\
+-	options.h output.h proc.h read_config_file.h library.h		\
+-	filter.h glob.h vect.h type.h value.h value_dict.h callback.h	\
+-	expr.h fetch.h vect.h param.h printf.h zero.h lens.h		\
+-	lens_default.h lens_enum.h memstream.h prototype.h
++	options.h output.h proc.h read_config_file.h summary.h		\
++	library.h filter.h glob.h vect.h type.h value.h value_dict.h	\
++	callback.h expr.h fetch.h vect.h param.h printf.h zero.h	\
++	lens.h lens_default.h lens_enum.h memstream.h prototype.h
+ 
+ dist_man1_MANS = ltrace.1
+ dist_man5_MANS = ltrace.conf.5
+diff --git a/common.h b/common.h
+index a53c5db..7259ba4 100644
+--- a/common.h
++++ b/common.h
+@@ -54,8 +54,6 @@ extern void handle_event(Event * event);
+ 
+ extern pid_t execute_program(const char * command, char ** argv);
+ 
+-extern void show_summary(void);
+-
+ struct breakpoint;
+ struct library_symbol;
+ 
+diff --git a/forward.h b/forward.h
+index 8641213..58d8f05 100644
+--- a/forward.h
++++ b/forward.h
+@@ -34,6 +34,7 @@ struct param_enum;
+ struct process;
+ struct protolib;
+ struct prototype;
++struct timedelta;
+ struct value;
+ struct value_dict;
+ struct vect;
+diff --git a/handle_event.c b/handle_event.c
+index 9ed62a2..6fa7e98 100644
+--- a/handle_event.c
++++ b/handle_event.c
+@@ -32,7 +32,6 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+-#include <sys/time.h>
+ #include <stdbool.h>
+ 
+ #include "backend.h"
+@@ -41,8 +40,9 @@
+ #include "fetch.h"
+ #include "library.h"
+ #include "proc.h"
+-#include "value_dict.h"
+ #include "prototype.h"
++#include "summary.h"
++#include "value_dict.h"
+ 
+ static void handle_signal(Event *event);
+ static void handle_exit(Event *event);
+@@ -419,32 +419,11 @@ handle_signal(Event *event) {
+ 	continue_after_signal(event->proc->pid, event->e_un.signum);
+ }
+ 
+-static void
+-handle_exit(Event *event) {
+-	debug(DEBUG_FUNCTION, "handle_exit(pid=%d, status=%d)", event->proc->pid, event->e_un.ret_val);
+-	if (event->proc->state != STATE_IGNORED) {
+-		output_line(event->proc, "+++ exited (status %d) +++",
+-				event->e_un.ret_val);
+-	}
+-	remove_process(event->proc);
+-}
+-
+-static void
+-handle_exit_signal(Event *event) {
+-	debug(DEBUG_FUNCTION, "handle_exit_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
+-	if (event->proc->state != STATE_IGNORED) {
+-		output_line(event->proc, "+++ killed by %s +++",
+-				shortsignal(event->proc, event->e_un.signum));
+-	}
+-	remove_process(event->proc);
+-}
+-
+-static void
+-output_syscall(struct process *proc, const char *name, enum tof tof,
+-	       void (*output)(enum tof, struct process *,
+-			      struct library_symbol *))
++static int
++init_syscall_symbol(struct library_symbol *libsym, const char *name)
+ {
+ 	static struct library syscall_lib;
++
+ 	if (syscall_lib.protolib == NULL) {
+ 		struct protolib *protolib
+ 			= protolib_cache_load(&g_protocache, "syscalls", 0, 1);
+@@ -475,10 +454,91 @@ output_syscall(struct process *proc, const char *name, enum tof tof,
+ 		syscall_lib.protolib = protolib;
+ 	}
+ 
++	if (library_symbol_init(libsym, 0, name, 0, LS_TOPLT_NONE) < 0)
++		return -1;
++
++	libsym->lib = &syscall_lib;
++	return 0;
++}
++
++/* Account the unfinished functions on the call stack.  */
++static void
++account_current_callstack(struct process *proc)
++{
++	if (! options.summary)
++		return;
++
++	struct timedelta spent[proc->callstack_depth];
++
++	size_t i;
++	for (i = 0; i < proc->callstack_depth; ++i) {
++		struct callstack_element *elem = &proc->callstack[i];
++		spent[i] = calc_time_spent(elem->enter_time);
++	}
++
++	for (i = 0; i < proc->callstack_depth; ++i) {
++		struct callstack_element *elem = &proc->callstack[i];
++		struct library_symbol syscall, *libsym = NULL;
++		if (elem->is_syscall) {
++			const char *name = sysname(proc, elem->c_un.syscall);
++			if (init_syscall_symbol(&syscall, name) >= 0)
++				libsym = &syscall;
++
++		} else {
++			libsym = elem->c_un.libfunc;
++		}
++
++		if (libsym != NULL) {
++			summary_account_call(libsym, spent[i]);
++
++			if (elem->is_syscall)
++				library_symbol_destroy(&syscall);
++		}
++	}
++}
++
++static void
++handle_exit(Event *event) {
++	debug(DEBUG_FUNCTION, "handle_exit(pid=%d, status=%d)", event->proc->pid, event->e_un.ret_val);
++	if (event->proc->state != STATE_IGNORED) {
++		output_line(event->proc, "+++ exited (status %d) +++",
++				event->e_un.ret_val);
++	}
++
++	account_current_callstack(event->proc);
++	remove_process(event->proc);
++}
++
++static void
++handle_exit_signal(Event *event) {
++	debug(DEBUG_FUNCTION, "handle_exit_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
++	if (event->proc->state != STATE_IGNORED) {
++		output_line(event->proc, "+++ killed by %s +++",
++				shortsignal(event->proc, event->e_un.signum));
++	}
++
++	account_current_callstack(event->proc);
++	remove_process(event->proc);
++}
++
++static void
++output_syscall(struct process *proc, const char *name, enum tof tof,
++	       bool left, struct timedelta *spent)
++{
++	if (left)
++		assert(spent == NULL);
++
+ 	struct library_symbol syscall;
+-	if (library_symbol_init(&syscall, 0, name, 0, LS_TOPLT_NONE) >= 0) {
+-		syscall.lib = &syscall_lib;
+-		(*output)(tof, proc, &syscall);
++	if (init_syscall_symbol(&syscall, name) >= 0) {
++		if (left) {
++			if (! options.summary)
++				output_left(tof, proc, &syscall);
++		} else if (options.summary) {
++			summary_account_call(&syscall, *spent);
++		} else {
++			output_right(tof, proc, &syscall, spent);
++		}
++
+ 		library_symbol_destroy(&syscall);
+ 	}
+ }
+@@ -486,17 +546,19 @@ output_syscall(struct process *proc, const char *name, enum tof tof,
+ static void
+ output_syscall_left(struct process *proc, const char *name)
+ {
+-	output_syscall(proc, name, LT_TOF_SYSCALL, &output_left);
++	output_syscall(proc, name, LT_TOF_SYSCALL, true, NULL);
+ }
+ 
+ static void
+-output_syscall_right(struct process *proc, const char *name)
++output_syscall_right(struct process *proc, const char *name,
++		     struct timedelta *spent)
+ {
+-	output_syscall(proc, name, LT_TOF_SYSCALLR, &output_right);
++	output_syscall(proc, name, LT_TOF_SYSCALLR, false, spent);
+ }
+ 
+ static void
+-handle_syscall(Event *event) {
++handle_syscall(Event *event)
++{
+ 	debug(DEBUG_FUNCTION, "handle_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
+ 	if (event->proc->state != STATE_IGNORED) {
+ 		callstack_push_syscall(event->proc, event->e_un.sysnum);
+@@ -526,6 +588,8 @@ handle_exec(Event *event)
+ 	}
+ 	output_line(proc, "--- Called exec() ---");
+ 
++	account_current_callstack(proc);
++
+ 	if (process_exec(proc) < 0) {
+ 		fprintf(stderr,
+ 			"couldn't reinitialize process %d after exec\n", pid);
+@@ -549,74 +613,58 @@ handle_arch_syscall(Event *event) {
+ 	continue_process(event->proc->pid);
+ }
+ 
+-struct timeval current_time_spent;
+-
+ static void
+-calc_time_spent(struct process *proc)
++handle_x_sysret(Event *event, char *(*name_cb)(struct process *, int))
+ {
+-	struct timeval tv;
+-	struct timezone tz;
+-	struct timeval diff;
+-	struct callstack_element *elem;
+-
+-	debug(DEBUG_FUNCTION, "calc_time_spent(pid=%d)", proc->pid);
+-	elem = &proc->callstack[proc->callstack_depth - 1];
+-
+-	gettimeofday(&tv, &tz);
++	debug(DEBUG_FUNCTION, "handle_x_sysret(pid=%d, sysnum=%d)",
++	      event->proc->pid, event->e_un.sysnum);
+ 
+-	diff.tv_sec = tv.tv_sec - elem->time_spent.tv_sec;
+-	if (tv.tv_usec >= elem->time_spent.tv_usec) {
+-		diff.tv_usec = tv.tv_usec - elem->time_spent.tv_usec;
+-	} else {
+-		diff.tv_sec--;
+-		diff.tv_usec = 1000000 + tv.tv_usec - elem->time_spent.tv_usec;
+-	}
+-	current_time_spent = diff;
+-}
++	unsigned d = event->proc->callstack_depth;
++	assert(d > 0);
++	struct callstack_element *elem = &event->proc->callstack[d - 1];
++	assert(elem->is_syscall);
+ 
+-static void
+-handle_sysret(Event *event) {
+-	debug(DEBUG_FUNCTION, "handle_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
+ 	if (event->proc->state != STATE_IGNORED) {
+-		if (opt_T || options.summary) {
+-			calc_time_spent(event->proc);
+-		}
++		struct timedelta spent = calc_time_spent(elem->enter_time);
+ 		if (options.syscalls)
+ 			output_syscall_right(event->proc,
+-					     sysname(event->proc,
+-						     event->e_un.sysnum));
++					     name_cb(event->proc,
++						     event->e_un.sysnum),
++					     &spent);
+ 
+-		assert(event->proc->callstack_depth > 0);
+-		unsigned d = event->proc->callstack_depth - 1;
+-		assert(event->proc->callstack[d].is_syscall);
+ 		callstack_pop(event->proc);
+ 	}
+ 	continue_after_syscall(event->proc, event->e_un.sysnum, 1);
+ }
+ 
+ static void
+-handle_arch_sysret(Event *event) {
+-	debug(DEBUG_FUNCTION, "handle_arch_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
+-	if (event->proc->state != STATE_IGNORED) {
+-		if (opt_T || options.summary) {
+-			calc_time_spent(event->proc);
+-		}
+-		if (options.syscalls)
+-			output_syscall_right(event->proc,
+-					     arch_sysname(event->proc,
+-							  event->e_un.sysnum));
+-		callstack_pop(event->proc);
+-	}
+-	continue_process(event->proc->pid);
++handle_sysret(Event *event)
++{
++	handle_x_sysret(event, &sysname);
++}
++
++static void
++handle_arch_sysret(Event *event)
++{
++	handle_x_sysret(event, &arch_sysname);
+ }
+ 
+ static void
+ output_right_tos(struct process *proc)
+ {
+ 	size_t d = proc->callstack_depth;
++	assert(d > 0);
+ 	struct callstack_element *elem = &proc->callstack[d - 1];
+-	if (proc->state != STATE_IGNORED)
+-		output_right(LT_TOF_FUNCTIONR, proc, elem->c_un.libfunc);
++	assert(! elem->is_syscall);
++
++	if (proc->state != STATE_IGNORED) {
++		struct timedelta spent = calc_time_spent(elem->enter_time);
++		if (options.summary)
++			summary_account_call(elem->c_un.libfunc, spent);
++		else
++			output_right(LT_TOF_FUNCTIONR, proc, elem->c_un.libfunc,
++				     &spent);
++	}
+ }
+ 
+ #ifndef ARCH_HAVE_SYMBOL_RET
+@@ -645,14 +693,8 @@ handle_breakpoint(Event *event)
+ 
+ 	for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
+ 		if (brk_addr == event->proc->callstack[i].return_addr) {
+-			for (j = event->proc->callstack_depth - 1; j > i; j--) {
++			for (j = event->proc->callstack_depth - 1; j > i; j--)
+ 				callstack_pop(event->proc);
+-			}
+-			if (event->proc->state != STATE_IGNORED) {
+-				if (opt_T || options.summary) {
+-					calc_time_spent(event->proc);
+-				}
+-			}
+ 
+ 			struct library_symbol *libsym =
+ 			    event->proc->callstack[i].c_un.libfunc;
+@@ -705,11 +747,14 @@ handle_breakpoint(Event *event)
+ 	/* breakpoint_on_hit may delete its own breakpoint, so we have
+ 	 * to look it up again.  */
+ 	if ((sbp = address2bpstruct(leader, brk_addr)) != NULL) {
++
+ 		if (event->proc->state != STATE_IGNORED
+ 		    && sbp->libsym != NULL) {
+ 			event->proc->stack_pointer = get_stack_pointer(event->proc);
+ 			callstack_push_symfunc(event->proc, sbp);
+-			output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym);
++			if (! options.summary)
++				output_left(LT_TOF_FUNCTION, event->proc,
++					    sbp->libsym);
+ 		}
+ 
+ 		breakpoint_on_continue(sbp, event->proc);
+@@ -743,7 +788,7 @@ callstack_push_syscall(struct process *proc, int sysnum)
+ 	proc->callstack_depth++;
+ 	if (opt_T || options.summary) {
+ 		struct timezone tz;
+-		gettimeofday(&elem->time_spent, &tz);
++		gettimeofday(&elem->enter_time, &tz);
+ 	}
+ }
+ 
+@@ -781,7 +826,7 @@ callstack_push_symfunc(struct process *proc, struct breakpoint *bp)
+ 
+ 	if (opt_T || options.summary) {
+ 		struct timezone tz;
+-		gettimeofday(&elem->time_spent, &tz);
++		gettimeofday(&elem->enter_time, &tz);
+ 	}
+ }
+ 
+diff --git a/libltrace.c b/libltrace.c
+index 2d910a1..0112c9f 100644
+--- a/libltrace.c
++++ b/libltrace.c
+@@ -32,11 +32,12 @@
+ #include <string.h>
+ #include <unistd.h>
+ 
++#include "backend.h"
+ #include "common.h"
+ #include "proc.h"
+-#include "read_config_file.h"
+-#include "backend.h"
+ #include "prototype.h"
++#include "read_config_file.h"
++#include "summary.h"
+ 
+ char *command = NULL;
+ 
+diff --git a/options.h b/options.h
+index 6c28ed9..d0df3a7 100644
+--- a/options.h
++++ b/options.h
+@@ -1,6 +1,6 @@
+ /*
+  * This file is part of ltrace.
+- * Copyright (C) 2012 Petr Machata, Red Hat Inc.
++ * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2009,2010 Joe Damato
+  * Copyright (C) 1998,2002,2008 Juan Cespedes
+  * Copyright (C) 2006 Ian Wienand
+@@ -103,12 +103,6 @@ int parse_colon_separated_list(const char *paths, struct vect *vec);
+ /* Vector of struct opt_F_t.  */
+ extern struct vect opt_F;
+ 
+-struct opt_c_struct {
+-	int count;
+-	struct timeval tv;
+-};
+-extern struct dict *dict_opt_c;
+-
+ extern char **process_options(int argc, char **argv);
+ 
+ #endif /* _OPTIONS_H_ */
+diff --git a/output.c b/output.c
+index edf4522..82b6a5e 100644
+--- a/output.c
++++ b/output.c
+@@ -44,16 +44,12 @@
+ #include "param.h"
+ #include "proc.h"
+ #include "prototype.h"
++#include "summary.h"
+ #include "type.h"
+ #include "value.h"
+ #include "value_dict.h"
+ 
+-/* TODO FIXME XXX: include in common.h: */
+-extern struct timeval current_time_spent;
+-
+-struct dict *dict_opt_c = NULL;
+-
+-static struct process *current_proc = 0;
++static struct process *current_proc = NULL;
+ static size_t current_depth = 0;
+ static int current_column = 0;
+ 
+@@ -498,9 +494,8 @@ void
+ output_left(enum tof type, struct process *proc,
+ 	    struct library_symbol *libsym)
+ {
+-	if (options.summary) {
+-		return;
+-	}
++	assert(! options.summary);
++
+ 	if (current_proc) {
+ 		fprintf(options.output, " <unfinished ...>\n");
+ 		current_column = 0;
+@@ -572,70 +567,21 @@ output_left(enum tof type, struct process *proc,
+ 	stel->out.need_delim = need_delim;
+ }
+ 
+-static void
+-free_stringp_cb(const char **stringp, void *data)
+-{
+-	free((char *)*stringp);
+-}
+-
+ void
+-output_right(enum tof type, struct process *proc, struct library_symbol *libsym)
++output_right(enum tof type, struct process *proc, struct library_symbol *libsym,
++	     struct timedelta *spent)
+ {
++	assert(! options.summary);
++
+ 	struct prototype *func = lookup_symbol_prototype(proc, libsym);
+ 	if (func == NULL)
+ 		return;
+ 
+-again:
+-	if (options.summary) {
+-		if (dict_opt_c == NULL) {
+-			dict_opt_c = malloc(sizeof(*dict_opt_c));
+-			if (dict_opt_c == NULL) {
+-			oom:
+-				fprintf(stderr,
+-					"Can't allocate memory for "
+-					"keeping track of -c.\n");
+-				free(dict_opt_c);
+-				options.summary = 0;
+-				goto again;
+-			}
+-			DICT_INIT(dict_opt_c, char *, struct opt_c_struct,
+-				  dict_hash_string, dict_eq_string, NULL);
+-		}
+-
+-		struct opt_c_struct *st
+-			= DICT_FIND_REF(dict_opt_c, &libsym->name,
+-					struct opt_c_struct);
+-		if (st == NULL) {
+-			const char *na = strdup(libsym->name);
+-			struct opt_c_struct new_st = {.count = 0, .tv = {0, 0}};
+-			if (na == NULL
+-			    || DICT_INSERT(dict_opt_c, &na, &new_st) < 0) {
+-				free((char *)na);
+-				DICT_DESTROY(dict_opt_c, const char *,
+-					     struct opt_c_struct,
+-					     free_stringp_cb, NULL, NULL);
+-				goto oom;
+-			}
+-			st = DICT_FIND_REF(dict_opt_c, &libsym->name,
+-					   struct opt_c_struct);
+-			assert(st != NULL);
+-		}
+-
+-		if (st->tv.tv_usec + current_time_spent.tv_usec > 1000000) {
+-			st->tv.tv_usec += current_time_spent.tv_usec - 1000000;
+-			st->tv.tv_sec++;
+-		} else {
+-			st->tv.tv_usec += current_time_spent.tv_usec;
+-		}
+-		st->count++;
+-		st->tv.tv_sec += current_time_spent.tv_sec;
+-		return;
+-	}
+-
+-	if (current_proc && (current_proc != proc ||
+-			    current_depth != proc->callstack_depth)) {
++	if (current_proc != NULL
++		    && (current_proc != proc
++			|| current_depth != proc->callstack_depth)) {
+ 		fprintf(options.output, " <unfinished ...>\n");
+-		current_proc = 0;
++		current_proc = NULL;
+ 	}
+ 	if (current_proc != proc) {
+ 		begin_of_line(proc, type == LT_TOF_FUNCTIONR, 1);
+@@ -689,10 +635,12 @@ again:
+ 		value_destroy(&retval);
+ 
+ 	if (opt_T) {
++		assert(spent != NULL);
+ 		fprintf(options.output, " <%lu.%06d>",
+-			(unsigned long)current_time_spent.tv_sec,
+-			(int)current_time_spent.tv_usec);
++			(unsigned long) spent->tm.tv_sec,
++			(int) spent->tm.tv_usec);
+ 	}
++
+ 	fprintf(options.output, "\n");
+ 
+ #if defined(HAVE_LIBUNWIND)
+@@ -746,7 +694,7 @@ again:
+ 	}
+ #endif /* defined(HAVE_LIBUNWIND) */
+ 
+-	current_proc = 0;
++	current_proc = NULL;
+ 	current_column = 0;
+ }
+ 
+diff --git a/output.h b/output.h
+index b9f0518..2e74d61 100644
+--- a/output.h
++++ b/output.h
+@@ -1,6 +1,6 @@
+ /*
+  * This file is part of ltrace.
+- * Copyright (C) 2011, 2012 Petr Machata, Red Hat Inc.
++ * Copyright (C) 2011, 2012, 2013 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2009 Juan Cespedes
+  *
+  * This program is free software; you can redistribute it and/or
+@@ -28,7 +28,8 @@ void output_line(struct process *proc, const char *fmt, ...);
+ void output_left(enum tof type, struct process *proc,
+ 		 struct library_symbol *libsym);
+ void output_right(enum tof type, struct process *proc,
+-		  struct library_symbol *libsym);
++		  struct library_symbol *libsym,
++		  struct timedelta *spent);
+ 
+ /* This function is for emitting lists of comma-separated strings.
+  *
+diff --git a/proc.h b/proc.h
+index e8032fa..64f8fe2 100644
+--- a/proc.h
++++ b/proc.h
+@@ -66,7 +66,7 @@ struct callstack_element {
+ 	} c_un;
+ 	int is_syscall;
+ 	arch_addr_t return_addr;
+-	struct timeval time_spent;
++	struct timeval enter_time;
+ 	struct fetch_context *fetch_context;
+ 	struct value_dict *arguments;
+ 	struct output_state out;
+diff --git a/summary.c b/summary.c
+index 9e22086..9103f71 100644
+--- a/summary.c
++++ b/summary.c
+@@ -22,11 +22,15 @@
+ 
+ #include "config.h"
+ 
++#include <sys/time.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+-#include <sys/time.h>
++#include <string.h>
+ 
+-#include "common.h"
++#include "summary.h"
++#include "dict.h"
++#include "library.h"
++#include "options.h"
+ 
+ struct entry_st {
+ 	const char *name;
+@@ -40,6 +44,32 @@ struct fill_struct_data {
+ 	unsigned long tot_usecs;
+ };
+ 
++struct opt_c_struct {
++	int count;
++	struct timeval tv;
++};
++
++static struct dict *dict_opt_c;
++
++struct timedelta
++calc_time_spent(struct timeval start)
++{
++	struct timeval tv;
++	gettimeofday(&tv, NULL);
++
++	struct timeval diff;
++	diff.tv_sec = tv.tv_sec - start.tv_sec;
++	if (tv.tv_usec >= start.tv_usec) {
++		diff.tv_usec = tv.tv_usec - start.tv_usec;
++	} else {
++		diff.tv_sec--;
++		diff.tv_usec = 1000000 + tv.tv_usec - start.tv_usec;
++	}
++
++	struct timedelta ret = { diff };
++	return ret;
++}
++
+ static enum callback_status
+ fill_struct(const char **namep, struct opt_c_struct *st, void *u)
+ {
+@@ -114,3 +144,58 @@ show_summary(void)
+ 
+ 	vect_destroy(&cdata.entries, NULL, NULL);
+ }
++
++static void
++free_stringp_cb(const char **stringp, void *data)
++{
++	free((char *)*stringp);
++}
++
++void
++summary_account_call(struct library_symbol *libsym, struct timedelta spent)
++{
++	assert(options.summary);
++
++	if (dict_opt_c == NULL) {
++		dict_opt_c = malloc(sizeof(*dict_opt_c));
++		if (dict_opt_c == NULL) {
++		oom:
++			fprintf(stderr,
++				"Can't allocate memory for "
++				"keeping track of -c.\n");
++			free(dict_opt_c);
++			options.summary = 0;
++			return;
++		}
++		DICT_INIT(dict_opt_c, char *, struct opt_c_struct,
++			  dict_hash_string, dict_eq_string, NULL);
++	}
++
++	struct opt_c_struct *st = DICT_FIND_REF(dict_opt_c, &libsym->name,
++						struct opt_c_struct);
++	if (st == NULL) {
++		const char *na = strdup(libsym->name);
++		struct opt_c_struct new_st = {.count = 0, .tv = {0, 0}};
++		if (na == NULL
++		    || DICT_INSERT(dict_opt_c, &na, &new_st) < 0) {
++			free((char *) na);
++			DICT_DESTROY(dict_opt_c, const char *,
++				     struct opt_c_struct,
++				     free_stringp_cb, NULL, NULL);
++			goto oom;
++		}
++		st = DICT_FIND_REF(dict_opt_c, &libsym->name,
++				   struct opt_c_struct);
++		assert(st != NULL);
++	}
++
++	if (st->tv.tv_usec + spent.tm.tv_usec > 1000000) {
++		st->tv.tv_usec += spent.tm.tv_usec - 1000000;
++		st->tv.tv_sec++;
++	} else {
++		st->tv.tv_usec += spent.tm.tv_usec;
++	}
++	st->count++;
++	st->tv.tv_sec += spent.tm.tv_sec;
++	return;
++}
+diff --git a/summary.h b/summary.h
+new file mode 100644
+index 0000000..f680ef9
+--- /dev/null
++++ b/summary.h
+@@ -0,0 +1,35 @@
++/*
++ * This file is part of ltrace.
++ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
++ *
++ * 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; either version 2 of the
++ * License, or (at your option) any later version.
++ *
++ * 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, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
++ * 02110-1301 USA
++ */
++
++#ifndef _SUMMARY_H_
++#define _SUMMARY_H_
++
++#include "forward.h"
++
++struct timedelta {
++	struct timeval tm;
++};
++
++struct timedelta calc_time_spent(struct timeval start);
++void summary_account_call(struct library_symbol *libsym,
++			  struct timedelta spent);
++void show_summary(void);
++
++#endif /* _SUMMARY_H_ */
+diff --git a/testsuite/ltrace.minor/trace-exec.exp b/testsuite/ltrace.minor/trace-exec.exp
+index 7a953de..57260f8 100644
+--- a/testsuite/ltrace.minor/trace-exec.exp
++++ b/testsuite/ltrace.minor/trace-exec.exp
+@@ -1,5 +1,5 @@
+ # This file is part of ltrace.
+-# Copyright (C) 2012 Petr Machata, Red Hat Inc.
++# Copyright (C) 2012, 2013 Petr Machata, Red Hat Inc.
+ #
+ # This program is free software; you can redistribute it and/or
+ # modify it under the terms of the GNU General Public License as
+@@ -16,22 +16,30 @@
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ # 02110-1301 USA
+ 
+-ltraceMatch [ltraceRun -xmain -- [ltraceCompile {} [ltraceSource c {
++set bin1 [ltraceCompile {} [ltraceSource c {
+     #include <unistd.h>
+     #include <stdlib.h>
+     int main(int argc, char ** argv) {
+ 	execl(argv[1], argv[1], NULL);
+ 	abort();
+     }
+-}]] [ltraceCompile {} [ltraceSource c {
++}]]
++
++set bin2 [ltraceCompile {} [ltraceSource c {
+     #include <stdio.h>
+     int main(void) {
+ 	return puts("Hello, World.");
+     }
+-}]]] {
++}]]
++
++ltraceMatch [ltraceRun -xmain -- $bin1 $bin2] {
+     {{^execl\(} == 1}
+     {{^puts\(.*\) .*= 14} == 1}
+     {{^main\(} == 2}
+ }
+ 
++ltraceMatch [ltraceRun -c -- $bin1 $bin2] {
++    {{exec} > 0}
++}
++
+ ltraceDone
+-- 
+1.7.6.5
+
diff --git a/SOURCES/ltrace-0.7.91-breakpoint-on_install.patch b/SOURCES/ltrace-0.7.91-breakpoint-on_install.patch
new file mode 100644
index 0000000..15959a3
--- /dev/null
+++ b/SOURCES/ltrace-0.7.91-breakpoint-on_install.patch
@@ -0,0 +1,81 @@
+From 56134ff5442bee4e128b189bb86cfc97dcb6f60a Mon Sep 17 00:00:00 2001
+From: Petr Machata <pmachata@redhat.com>
+Date: Fri, 10 Jan 2014 20:05:15 +0100
+Subject: [PATCH 1/2] Add a new per-breakpoint callback on_install
+
+---
+ breakpoint.h  |    9 ++++++++-
+ breakpoints.c |   11 ++++++++++-
+ 2 files changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/breakpoint.h b/breakpoint.h
+index 95964a8..c36f673 100644
+--- a/breakpoint.h
++++ b/breakpoint.h
+@@ -1,6 +1,6 @@
+ /*
+  * This file is part of ltrace.
+- * Copyright (C) 2012, 2013 Petr Machata, Red Hat Inc.
++ * Copyright (C) 2012,2013,2014 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2009 Juan Cespedes
+  *
+  * This program is free software; you can redistribute it and/or
+@@ -46,6 +46,7 @@
+ struct bp_callbacks {
+ 	void (*on_hit)(struct breakpoint *bp, struct process *proc);
+ 	void (*on_continue)(struct breakpoint *bp, struct process *proc);
++	void (*on_install)(struct breakpoint *bp, struct process *proc);
+ 	void (*on_retract)(struct breakpoint *bp, struct process *proc);
+ 
+ 	/* Create a new breakpoint that should handle return from the
+@@ -84,6 +85,12 @@ void breakpoint_on_continue(struct breakpoint *bp, struct process *proc);
+  * the instruction underneath it).  */
+ void breakpoint_on_retract(struct breakpoint *bp, struct process *proc);
+ 
++/* Call ON_INSTALL handler of BP, if any is set.  This should be
++ * called after the breakpoint is enabled for the first time, not
++ * every time it's enabled (such as after stepping over a site of a
++ * temporarily disabled breakpoint).  */
++void breakpoint_on_install(struct breakpoint *bp, struct process *proc);
++
+ /* Call GET_RETURN_BP handler of BP, if any is set.  If none is set,
+  * call CREATE_DEFAULT_RETURN_BP to obtain one.  */
+ int breakpoint_get_return_bp(struct breakpoint **ret,
+diff --git a/breakpoints.c b/breakpoints.c
+index 947cb71..c3fa275 100644
+--- a/breakpoints.c
++++ b/breakpoints.c
+@@ -1,6 +1,6 @@
+ /*
+  * This file is part of ltrace.
+- * Copyright (C) 2006,2007,2011,2012,2013 Petr Machata, Red Hat Inc.
++ * Copyright (C) 2006,2007,2011,2012,2013,2014 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2009 Juan Cespedes
+  * Copyright (C) 1998,2001,2002,2003,2007,2008,2009 Juan Cespedes
+  * Copyright (C) 2006 Ian Wienand
+@@ -85,6 +85,14 @@ breakpoint_on_retract(struct breakpoint *bp, struct process *proc)
+ 		(bp->cbs->on_retract)(bp, proc);
+ }
+ 
++void
++breakpoint_on_install(struct breakpoint *bp, struct process *proc)
++{
++	assert(bp != NULL);
++	if (bp->cbs != NULL && bp->cbs->on_install != NULL)
++		(bp->cbs->on_install)(bp, proc);
++}
++
+ int
+ breakpoint_get_return_bp(struct breakpoint **ret,
+ 			 struct breakpoint *bp, struct process *proc)
+@@ -229,6 +237,7 @@ breakpoint_turn_on(struct breakpoint *bp, struct process *proc)
+ 	if (bp->enabled == 1) {
+ 		assert(proc->pid != 0);
+ 		enable_breakpoint(proc, bp);
++		breakpoint_on_install(bp, proc);
+ 	}
+ 	return 0;
+ }
+-- 
+1.7.6.5
+
diff --git a/SOURCES/ltrace-0.7.91-cant_open.patch b/SOURCES/ltrace-0.7.91-cant_open.patch
new file mode 100644
index 0000000..4d3a0d4
--- /dev/null
+++ b/SOURCES/ltrace-0.7.91-cant_open.patch
@@ -0,0 +1,36 @@
+diff -urp ltrace-0.7.91/libltrace.c master/libltrace.c
+--- ltrace-0.7.91/libltrace.c	2014-01-14 16:31:37.696174464 +0100
++++ master/libltrace.c	2013-11-21 14:06:38.623701688 +0100
+@@ -113,9 +117,13 @@ ltrace_init(int argc, char **argv) {
+ 	if (command) {
+ 		/* Check that the binary ABI is supported before
+ 		 * calling execute_program.  */
+-		struct ltelf lte;
+-		ltelf_init(&lte, command);
+-		ltelf_destroy(&lte);
++		{
++			struct ltelf lte;
++			if (ltelf_init(&lte, command) == 0)
++				ltelf_destroy(&lte);
++			else
++				exit(EXIT_FAILURE);
++		}
+ 
+ 		pid_t pid = execute_program(command, argv);
+ 		struct process *proc = open_program(command, pid);
+diff -urp ltrace-0.7.91/ltrace-elf.c master/ltrace-elf.c
+--- ltrace-0.7.91/ltrace-elf.c	2014-01-14 16:31:37.688174420 +0100
++++ master/ltrace-elf.c	2013-11-22 18:17:11.767721609 +0100
+@@ -361,8 +361,11 @@ ltelf_init(struct ltelf *lte, const char
+ {
+ 	memset(lte, 0, sizeof *lte);
+ 	lte->fd = open(filename, O_RDONLY);
+-	if (lte->fd == -1)
++	if (lte->fd == -1) {
++		fprintf(stderr, "Can't open %s: %s\n", filename,
++			strerror(errno));
+ 		return 1;
++	}
+ 
+ 	elf_version(EV_CURRENT);
+ 
diff --git a/SOURCES/ltrace-0.7.91-man.patch b/SOURCES/ltrace-0.7.91-man.patch
new file mode 100644
index 0000000..d7a7dbf
--- /dev/null
+++ b/SOURCES/ltrace-0.7.91-man.patch
@@ -0,0 +1,45 @@
+diff -up ltrace-0.7.91/options.c\~ ltrace-0.7.91/options.c
+--- ltrace-0.7.91/options.c~	2013-10-22 11:54:21.000000000 +0200
++++ ltrace-0.7.91/options.c	2014-01-13 15:38:51.362221740 +0100
+@@ -128,6 +128,8 @@ usage_debug(void) {
+ 			"\n"
+ 			"Debugging options are mixed using bitwise-or.\n"
+ 			"Note that the meanings and values are subject to change.\n"
++			"Also note that these values are used inconsistently in ltrace, and the\n"
++			"only debuglevel that you can rely on is -D77 that will show everything.\n"
+ 		   );
+ }
+ 
+diff -up ltrace-0.7.91/ltrace.1\~ ltrace-0.7.91/ltrace.1
+--- ltrace-0.7.91/ltrace.1~	2013-10-23 17:44:13.000000000 +0200
++++ ltrace-0.7.91/ltrace.1	2014-01-13 15:51:24.236730677 +0100
+@@ -1,5 +1,5 @@
+ .\" -*-nroff-*-
+-.\" Copyright (c) 2012, 2013 Petr Machata, Red Hat Inc.
++.\" Copyright (c) 2012,2013,2014 Petr Machata, Red Hat Inc.
+ .\" Copyright (c) 1997-2005 Juan Cespedes <cespedes@debian.org>
+ .\"
+ .\" This program is free software; you can redistribute it and/or
+@@ -118,9 +118,9 @@ Besides removing any initial underscore 
+ this makes C++ function names readable.
+ .IP "\-D, \-\-debug \fRmask\fI"
+ Show debugging output of \fBltrace\fR itself.  \fImask\fR is a number
+-with internal meaning that's not really well defined at all.
+-\fImask\fR of 77 shows all debug messages, which is what you usually
+-need.
++describing which debug messages should be displayed.  Use the option
++\-Dh to see what can be used, but note that currently the only
++reliable debugmask is 77, which shows all debug messages.
+ .IP "\-e \fIfilter"
+ A qualifying expression which modifies which library calls to trace.
+ The format of the filter expression is described in the section
+@@ -156,7 +156,8 @@ dependency ordering.  If you want to mak
+ library are actually called, use \fB-x @\fIlibrary_pattern\fR instead.
+ .IP \-L
+ When no -e option is given, don't assume the default action of
+-\fB@MAIN\fR.
++\fB@MAIN\fR.  In practice this means that library calls will not be
++traced.
+ .IP "\-n, \-\-indent \fInr"
+ Indent trace output by \fInr\fR spaces for each level of call
+ nesting. Using this option makes the program flow visualization easy
diff --git a/SOURCES/ltrace-0.7.91-ppc64-fork.patch b/SOURCES/ltrace-0.7.91-ppc64-fork.patch
new file mode 100644
index 0000000..53c66fd
--- /dev/null
+++ b/SOURCES/ltrace-0.7.91-ppc64-fork.patch
@@ -0,0 +1,52 @@
+From 35742523e3daa0e59de0c1c3fdd8e5ff52891967 Mon Sep 17 00:00:00 2001
+From: Petr Machata <pmachata@redhat.com>
+Date: Thu, 9 Jan 2014 23:41:50 +0100
+Subject: [PATCH] Fix a problem in tracing across fork on PPC64
+
+In order to avoid single-stepping through large portions of the
+dynamic linker, ltrace remembers at which address the instruction that
+resolved a PLT slot is.  It then puts a breakpoint to this address so
+that it can fast-forward to that address next time it needs to catch a
+PLT slot being resolved.
+
+When a process is cloned, the pointer to this breakpoint is simply
+copied over to the new process, instead of being looked up in the new
+process structures.  This patches fixes this.
+---
+ sysdeps/linux-gnu/ppc/plt.c |   14 +++++++++++++-
+ 1 files changed, 13 insertions(+), 1 deletions(-)
+
+diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
+index 3ec1397..8715da6 100644
+--- a/sysdeps/linux-gnu/ppc/plt.c
++++ b/sysdeps/linux-gnu/ppc/plt.c
+@@ -1,6 +1,6 @@
+ /*
+  * This file is part of ltrace.
+- * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
++ * Copyright (C) 2012,2013,2014 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2004,2008,2009 Juan Cespedes
+  * Copyright (C) 2006 Paul Gilliam
+  *
+@@ -1157,6 +1157,18 @@ int
+ arch_process_clone(struct process *retp, struct process *proc)
+ {
+ 	retp->arch = proc->arch;
++
++	if (retp->arch.dl_plt_update_bp != NULL) {
++		/* Point it to the corresponding breakpoint in RETP.
++		 * It must be there, this part of PROC has already
++		 * been cloned to RETP.  */
++		retp->arch.dl_plt_update_bp
++			= address2bpstruct(retp,
++					   retp->arch.dl_plt_update_bp->addr);
++
++		assert(retp->arch.dl_plt_update_bp != NULL);
++	}
++
+ 	return 0;
+ }
+ 
+-- 
+1.7.6.5
+
diff --git a/SOURCES/ltrace-0.7.91-ppc64-unprelink.patch b/SOURCES/ltrace-0.7.91-ppc64-unprelink.patch
new file mode 100644
index 0000000..a5929e3
--- /dev/null
+++ b/SOURCES/ltrace-0.7.91-ppc64-unprelink.patch
@@ -0,0 +1,221 @@
+From a0093ca43cf40d7e5f6cebeb64156062d2de46d9 Mon Sep 17 00:00:00 2001
+From: Petr Machata <pmachata@redhat.com>
+Date: Fri, 10 Jan 2014 20:06:51 +0100
+Subject: [PATCH 2/2] Don't crash untraced calls via PLT in prelinked PPC64
+ binaries
+
+In prelinked binaries, ltrace has to unprelinks PLT slots in order to
+catch calls done through PLT.  This makes the calls done through these
+slots invalid, because the special first PLT slot is not initialized,
+and dynamic linker SIGSEGVs because of this.  Ltrace relies on
+arranging breakpoints such that the dynamic linker is not actually
+entered, and moves PC around itself to simulate the effects of a call
+through PLT.
+
+Originally, arch_elf_add_plt_entry was called only for symbols that
+were actually traced.  Later this was changed and it's now called for
+all PLT entries, and the resulting candidate list is filtered
+afterwards.  This gives backends a chance to rename the symbol, as is
+useful with IRELATIVE PLT calls, where symbol name may not be
+available at all.  But the PPC backend was never updated to reflect
+this, and unresolved all symbols for which arch_elf_add_plt_entry was
+called, thus rendering _all_ PLT slots invalid, even those that
+weren't later procted by breakpoints.  Thus calls done through any
+untraced slots failed.
+
+This patch fixes this problem by deferring the unprelinking of PLT
+slots into the on_install hook of breakpoints.
+---
+ sysdeps/linux-gnu/ppc/arch.h |   21 ++++++++-
+ sysdeps/linux-gnu/ppc/plt.c  |   94 +++++++++++++++++++++++++++++++++--------
+ 2 files changed, 94 insertions(+), 21 deletions(-)
+
+diff --git a/sysdeps/linux-gnu/ppc/arch.h b/sysdeps/linux-gnu/ppc/arch.h
+index 2add3b8..bf9b5dc 100644
+--- a/sysdeps/linux-gnu/ppc/arch.h
++++ b/sysdeps/linux-gnu/ppc/arch.h
+@@ -1,6 +1,6 @@
+ /*
+  * This file is part of ltrace.
+- * Copyright (C) 2012,2013 Petr Machata
++ * Copyright (C) 2012,2013,2014 Petr Machata
+  * Copyright (C) 2006 Paul Gilliam
+  * Copyright (C) 2002,2004 Juan Cespedes
+  *
+@@ -87,12 +87,29 @@ enum ppc64_plt_type {
+ 	/* Very similar to PPC_PLT_UNRESOLVED, but for JMP_IREL
+ 	 * slots.  */
+ 	PPC_PLT_IRELATIVE,
++
++	/* Transitional state before the breakpoint is enabled.  */
++	PPC_PLT_NEED_UNRESOLVE,
+ };
+ 
+ #define ARCH_HAVE_LIBRARY_SYMBOL_DATA
++struct ppc_unresolve_data;
+ struct arch_library_symbol_data {
+ 	enum ppc64_plt_type type;
+-	GElf_Addr resolved_value;
++
++	/* State		Contents
++	 *
++	 * PPC_DEFAULT		N/A
++	 * PPC64_PLT_STUB	N/A
++	 * PPC_PLT_UNRESOLVED	PLT entry address.
++	 * PPC_PLT_IRELATIVE	Likewise.
++	 * PPC_PLT_RESOLVED	The original value the slot was resolved to.
++	 * PPC_PLT_NEED_UNRESOLVE	DATA.
++	 */
++	union {
++		GElf_Addr resolved_value;
++		struct ppc_unresolve_data *data;
++	};
+ 
+ 	/* Address of corresponding slot in .plt.  */
+ 	GElf_Addr plt_slot_addr;
+diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
+index 8715da6..332daa8 100644
+--- a/sysdeps/linux-gnu/ppc/plt.c
++++ b/sysdeps/linux-gnu/ppc/plt.c
+@@ -679,6 +679,14 @@ arch_elf_add_func_entry(struct process *proc, struct ltelf *lte,
+ 	return PLT_OK;
+ }
+ 
++struct ppc_unresolve_data {
++	struct ppc_unresolve_data *self; /* A canary.  */
++	GElf_Addr plt_entry_addr;
++	GElf_Addr plt_slot_addr;
++	GElf_Addr plt_slot_value;
++	bool is_irelative;
++};
++
+ enum plt_status
+ arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
+ 		       const char *a_name, GElf_Rela *rela, size_t ndx,
+@@ -778,28 +786,23 @@ arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
+ 	    && (plt_slot_value == plt_entry_addr || plt_slot_value == 0)) {
+ 		libsym->arch.type = PPC_PLT_UNRESOLVED;
+ 		libsym->arch.resolved_value = plt_entry_addr;
+-
+ 	} else {
+-		/* Unresolve the .plt slot.  If the binary was
+-		 * prelinked, this makes the code invalid, because in
+-		 * case of prelinked binary, the dynamic linker
+-		 * doesn't update .plt[0] and .plt[1] with addresses
+-		 * of the resover.  But we don't care, we will never
+-		 * need to enter the resolver.  That just means that
+-		 * we have to un-un-resolve this back before we
+-		 * detach.  */
+-
+-		if (unresolve_plt_slot(proc, plt_slot_addr, plt_entry_addr) < 0) {
+-			library_symbol_destroy(libsym);
++		/* Mark the symbol for later unresolving.  We may not
++		 * do this right away, as this is called by ltrace
++		 * core for all symbols, and only later filtered.  We
++		 * only unresolve the symbol before the breakpoint is
++		 * enabled.  */
++
++		libsym->arch.type = PPC_PLT_NEED_UNRESOLVE;
++		libsym->arch.data = malloc(sizeof *libsym->arch.data);
++		if (libsym->arch.data == NULL)
+ 			goto fail2;
+-		}
+ 
+-		if (! is_irelative) {
+-			mark_as_resolved(libsym, plt_slot_value);
+-		} else {
+-			libsym->arch.type = PPC_PLT_IRELATIVE;
+-			libsym->arch.resolved_value = plt_entry_addr;
+-		}
++		libsym->arch.data->self = libsym->arch.data;
++		libsym->arch.data->plt_entry_addr = plt_entry_addr;
++		libsym->arch.data->plt_slot_addr = plt_slot_addr;
++		libsym->arch.data->plt_slot_value = plt_slot_value;
++		libsym->arch.data->is_irelative = is_irelative;
+ 	}
+ 
+ 	*ret = libsym;
+@@ -999,6 +1002,7 @@ ppc_plt_bp_continue(struct breakpoint *bp, struct process *proc)
+ 		return;
+ 
+ 	case PPC64_PLT_STUB:
++	case PPC_PLT_NEED_UNRESOLVE:
+ 		/* These should never hit here.  */
+ 		break;
+ 	}
+@@ -1050,6 +1054,52 @@ ppc_plt_bp_retract(struct breakpoint *bp, struct process *proc)
+ 	}
+ }
+ 
++static void
++ppc_plt_bp_install(struct breakpoint *bp, struct process *proc)
++{
++	/* This should not be an artificial breakpoint.  */
++	struct library_symbol *libsym = bp->libsym;
++	if (libsym == NULL)
++		libsym = bp->arch.irel_libsym;
++	assert(libsym != NULL);
++
++	if (libsym->arch.type == PPC_PLT_NEED_UNRESOLVE) {
++		/* Unresolve the .plt slot.  If the binary was
++		 * prelinked, this makes the code invalid, because in
++		 * case of prelinked binary, the dynamic linker
++		 * doesn't update .plt[0] and .plt[1] with addresses
++		 * of the resover.  But we don't care, we will never
++		 * need to enter the resolver.  That just means that
++		 * we have to un-un-resolve this back before we
++		 * detach.  */
++
++		struct ppc_unresolve_data *data = libsym->arch.data;
++		libsym->arch.data = NULL;
++		assert(data->self == data);
++
++		GElf_Addr plt_slot_addr = data->plt_slot_addr;
++		GElf_Addr plt_slot_value = data->plt_slot_value;
++		GElf_Addr plt_entry_addr = data->plt_entry_addr;
++
++		if (unresolve_plt_slot(proc, plt_slot_addr,
++				       plt_entry_addr) == 0) {
++			if (! data->is_irelative) {
++				mark_as_resolved(libsym, plt_slot_value);
++			} else {
++				libsym->arch.type = PPC_PLT_IRELATIVE;
++				libsym->arch.resolved_value = plt_entry_addr;
++			}
++		} else {
++			fprintf(stderr, "Couldn't unresolve %s@%p.  Not tracing"
++				" this symbol.\n",
++				breakpoint_name(bp), bp->addr);
++			proc_remove_breakpoint(proc, bp);
++		}
++
++		free(data);
++	}
++}
++
+ int
+ arch_library_init(struct library *lib)
+ {
+@@ -1080,6 +1130,11 @@ arch_library_symbol_init(struct library_symbol *libsym)
+ void
+ arch_library_symbol_destroy(struct library_symbol *libsym)
+ {
++	if (libsym->arch.type == PPC_PLT_NEED_UNRESOLVE) {
++		assert(libsym->arch.data->self == libsym->arch.data);
++		free(libsym->arch.data);
++		libsym->arch.data = NULL;
++	}
+ }
+ 
+ int
+@@ -1115,6 +1170,7 @@ arch_breakpoint_init(struct process *proc, struct breakpoint *bp)
+ 	static struct bp_callbacks cbs = {
+ 		.on_continue = ppc_plt_bp_continue,
+ 		.on_retract = ppc_plt_bp_retract,
++		.on_install = ppc_plt_bp_install,
+ 	};
+ 	breakpoint_set_callbacks(bp, &cbs);
+ 
+-- 
+1.7.6.5
+
diff --git a/SOURCES/ltrace-0.7.91-s390-fetch-syscall.patch b/SOURCES/ltrace-0.7.91-s390-fetch-syscall.patch
new file mode 100644
index 0000000..da50b48
--- /dev/null
+++ b/SOURCES/ltrace-0.7.91-s390-fetch-syscall.patch
@@ -0,0 +1,69 @@
+@@ -, +, @@ 
+   exe->mount("source", "target", "filesystemtype", 0, nil <unfinished ...>
+   mount@SYS("", "target", "filesystemtype", 0, nil)                 = -2
+   <... mount resumed>                                               = -1
+---
+ sysdeps/linux-gnu/s390/fetch.c |   17 ++++++++++++-----
+ 1 files changed, 12 insertions(+), 5 deletions(-)
+--- a/sysdeps/linux-gnu/s390/fetch.c	
++++ a/sysdeps/linux-gnu/s390/fetch.c	
+@@ -23,6 +23,7 @@ 
+ #include <sys/ucontext.h>
+ #include <assert.h>
+ #include <errno.h>
++#include <stdbool.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -61,7 +62,8 @@ s390x(struct fetch_context *ctx)
+ }
+ 
+ static int
+-fetch_register_banks(struct process *proc, struct fetch_context *ctx)
++fetch_register_banks(struct process *proc, struct fetch_context *ctx,
++		     bool syscall_enter)
+ {
+ 	ptrace_area parea;
+ 	parea.len = sizeof(ctx->regs);
+@@ -72,15 +74,20 @@ fetch_register_banks(struct process *proc, struct fetch_context *ctx)
+ 			strerror(errno));
+ 		return -1;
+ 	}
++
++	if (syscall_enter)
++		ctx->regs.gprs[2] = ctx->regs.orig_gpr2;
++
+ 	return 0;
+ }
+ 
+ static int
+-fetch_context_init(struct process *proc, struct fetch_context *context)
++fetch_context_init(struct process *proc, struct fetch_context *context,
++		   bool syscall_enter)
+ {
+ 	context->greg = 2;
+ 	context->freg = 0;
+-	return fetch_register_banks(proc, context);
++	return fetch_register_banks(proc, context, syscall_enter);
+ }
+ 
+ struct fetch_context *
+@@ -89,7 +96,7 @@ arch_fetch_arg_init(enum tof type, struct process *proc,
+ {
+ 	struct fetch_context *context = malloc(sizeof(*context));
+ 	if (context == NULL
+-	    || fetch_context_init(proc, context) < 0) {
++	    || fetch_context_init(proc, context, type == LT_TOF_SYSCALL) < 0) {
+ 		fprintf(stderr, "arch_fetch_arg_init: %s\n",
+ 			strerror(errno));
+ 		free(context);
+@@ -277,7 +284,7 @@ arch_fetch_retval(struct fetch_context *ctx, enum tof type,
+ 		return 0;
+ 	}
+ 
+-	if (fetch_context_init(proc, ctx) < 0)
++	if (fetch_context_init(proc, ctx, false) < 0)
+ 		return -1;
+ 	return arch_fetch_arg_next(ctx, type, proc, info, valuep);
+ }
+-- 
diff --git a/SOURCES/ltrace-0.7.91-s390-irelative.patch b/SOURCES/ltrace-0.7.91-s390-irelative.patch
new file mode 100644
index 0000000..29222c9
--- /dev/null
+++ b/SOURCES/ltrace-0.7.91-s390-irelative.patch
@@ -0,0 +1,67 @@
+@@ -, +, @@ 
+---
+ sysdeps/linux-gnu/s390/arch.h |  2 ++
+ sysdeps/linux-gnu/s390/plt.c  | 22 ++++++++++++++++++++++
+ 2 files changed, 24 insertions(+)
+--- a/sysdeps/linux-gnu/s390/arch.h	
++++ a/sysdeps/linux-gnu/s390/arch.h	
+@@ -1,5 +1,6 @@ 
+ /*
+  * This file is part of ltrace.
++ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2001 IBM Poughkeepsie, IBM Corporation
+  *
+  * This program is free software; you can redistribute it and/or
+@@ -25,6 +26,7 @@ 
+ #define ARCH_HAVE_FETCH_ARG
+ #define ARCH_HAVE_SIZEOF
+ #define ARCH_HAVE_ALIGNOF
++#define ARCH_HAVE_ADD_PLT_ENTRY
+ 
+ #define LT_ELFCLASS	ELFCLASS32
+ #define LT_ELF_MACHINE	EM_S390
+--- a/sysdeps/linux-gnu/s390/plt.c	
++++ a/sysdeps/linux-gnu/s390/plt.c	
+@@ -1,5 +1,6 @@ 
+ /*
+  * This file is part of ltrace.
++ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2004,2008,2009 Juan Cespedes
+  *
+  * This program is free software; you can redistribute it and/or
+@@ -19,9 +20,12 @@ 
+  */
+ 
+ #include <gelf.h>
++#include <stdbool.h>
++
+ #include "proc.h"
+ #include "common.h"
+ #include "library.h"
++#include "trace.h"
+ 
+ GElf_Addr
+ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
+@@ -33,3 +37,21 @@ sym2addr(struct process *proc, struct library_symbol *sym)
+ {
+ 	return sym->enter_addr;
+ }
++
++enum plt_status
++arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
++		       const char *a_name, GElf_Rela *rela, size_t ndx,
++		       struct library_symbol **ret)
++{
++#ifdef R_390_IRELATIVE
++	bool irelative = GELF_R_TYPE(rela->r_info) == R_390_IRELATIVE;
++#else
++	bool irelative = false;
++#endif
++
++	if (irelative)
++		return linux_elf_add_plt_entry_irelative(proc, lte, rela,
++							 ndx, ret);
++
++	return PLT_DEFAULT;
++}
+-- 
diff --git a/SOURCES/ltrace-0.7.91-x86_64-irelative.patch b/SOURCES/ltrace-0.7.91-x86_64-irelative.patch
new file mode 100644
index 0000000..949b5fb
--- /dev/null
+++ b/SOURCES/ltrace-0.7.91-x86_64-irelative.patch
@@ -0,0 +1,156 @@
+@@ -, +, @@ 
+ relocation
+- In general they are.  But IRELATIVE relocations are sorted to come
+  last, and PLT entries are not sorted accordingly.
+---
+ sysdeps/linux-gnu/x86/arch.h |   11 +++++
+ sysdeps/linux-gnu/x86/plt.c  |  101 +++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 111 insertions(+), 1 deletions(-)
+--- a/sysdeps/linux-gnu/x86/arch.h	
++++ a/sysdeps/linux-gnu/x86/arch.h	
+@@ -19,6 +19,10 @@ 
+  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  * 02110-1301 USA
+  */
++#ifndef LTRACE_X86_ARCH_H
++#define LTRACE_X86_ARCH_H
++
++#include "vect.h"
+ 
+ #define BREAKPOINT_VALUE {0xcc}
+ #define BREAKPOINT_LENGTH 1
+@@ -30,9 +34,16 @@ 
+ 
+ #define ARCH_HAVE_ADD_PLT_ENTRY
+ 
++#define ARCH_HAVE_LTELF_DATA
++struct arch_ltelf_data {
++	struct vect plt_map;
++};
++
+ #ifdef __x86_64__
+ #define LT_ELFCLASS	ELFCLASS64
+ #define LT_ELF_MACHINE	EM_X86_64
+ #endif
+ #define LT_ELFCLASS2	ELFCLASS32
+ #define LT_ELF_MACHINE2	EM_386
++
++#endif /* LTRACE_X86_ARCH_H */
+--- a/sysdeps/linux-gnu/x86/plt.c	
++++ a/sysdeps/linux-gnu/x86/plt.c	
+@@ -27,10 +27,19 @@ 
+ #include "library.h"
+ #include "trace.h"
+ 
++static GElf_Addr
++x86_plt_offset(uint32_t i)
++{
++	/* Skip the first PLT entry, which contains a stub to call the
++	 * resolver.  */
++	return (i + 1) * 16;
++}
++
+ GElf_Addr
+ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela)
+ {
+-	return lte->plt_addr + (ndx + 1) * 16;
++	uint32_t i = *VECT_ELEMENT(&lte->arch.plt_map, uint32_t, ndx);
++	return x86_plt_offset(i) + lte->plt_addr;
+ }
+ 
+ void *
+@@ -62,3 +71,93 @@ arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
+ 
+ 	return PLT_DEFAULT;
+ }
++
++int
++arch_elf_init(struct ltelf *lte, struct library *lib)
++{
++	VECT_INIT(&lte->arch.plt_map, unsigned int);
++
++	/* IRELATIVE slots may make the whole situation a fair deal
++	 * more complex.  On x86{,_64}, the PLT slots are not
++	 * presented in the order of the corresponding relocations,
++	 * but in the order it which these symbols are in the symbol
++	 * table.  That's static symbol table, which may be stripped
++	 * off, not dynsym--that doesn't contain IFUNC symbols at all.
++	 * So we have to decode each PLT entry to figure out what
++	 * entry it corresponds to.  We need to interpret the PLT
++	 * table to figure this out.
++	 *
++	 * On i386, the PLT entry format is as follows:
++	 *
++	 *	8048300:   ff 25 0c a0 04 08       jmp    *0x804a00c
++	 *	8048306:   68 20 00 00 00          push   $0x20
++	 *	804830b:   e9 e0 ff ff ff          jmp    80482f0 <_init+0x30>
++	 *
++	 * For PIE binaries it is the following:
++	 *
++	 *	    410:   ff a3 10 00 00 00       jmp    *0x10(%ebx)
++	 *	    416:   68 00 00 00 00          push   $0x0
++	 *	    41b:   e9 d0 ff ff ff          jmp    3f0 <_init+0x30>
++	 *
++	 * On x86_64, it is:
++	 *
++	 *	 400420:   ff 25 f2 0b 20 00       jmpq   *0x200bf2(%rip)        # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
++	 *	 400426:   68 00 00 00 00          pushq  $0x0
++	 *	 40042b:   e9 e0 ff ff ff          jmpq   400410 <_init+0x18>
++	 *
++         * On i386, the argument to push is an offset of relocation to
++	 * use.  The first PLT slot has an offset of 0x0, the second
++	 * 0x8, etc.  On x86_64, it's directly the index that we are
++	 * looking for.
++	 */
++
++	/* Here we scan the PLT table and initialize a map of
++	 * relocation->slot number in lte->arch.plt_map.  */
++
++	size_t i;
++	for (i = 0; i < vect_size(&lte->plt_relocs); ++i) {
++
++		GElf_Addr offset = x86_plt_offset(i);
++		uint32_t reloc_arg = 0;
++
++		uint8_t byte;
++		if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
++		    || byte != 0xff
++		    || elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
++		    || (byte != 0xa3 && byte != 0x25))
++			goto next;
++
++		/* Skip immediate argument in the instruction.  */
++		offset += 4;
++
++		if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
++		    || byte != 0x68
++		    || elf_read_next_u32(lte->plt_data,
++					 &offset, &reloc_arg) < 0) {
++			reloc_arg = 0;
++			goto next;
++		}
++
++		if (lte->ehdr.e_machine == EM_386) {
++			if (reloc_arg % 8 != 0) {
++				reloc_arg = 0;
++				goto next;
++			}
++			reloc_arg /= 8;
++		}
++
++	next:
++		if (VECT_PUSHBACK(&lte->arch.plt_map, &reloc_arg) < 0) {
++			arch_elf_destroy(lte);
++			return -1;
++		}
++	}
++
++	return 0;
++}
++
++void
++arch_elf_destroy(struct ltelf *lte)
++{
++	VECT_DESTROY(&lte->arch.plt_map, uint32_t, NULL, NULL);
++}
+-- 
diff --git a/SPECS/ltrace.spec b/SPECS/ltrace.spec
index 78b4d2c..1a04bf8 100644
--- a/SPECS/ltrace.spec
+++ b/SPECS/ltrace.spec
@@ -1,7 +1,7 @@
 Summary: Tracks runtime library calls from dynamically linked executables
 Name: ltrace
 Version: 0.7.91
-Release: 1%{?dist}
+Release: 7%{?dist}
 URL: http://ltrace.alioth.debian.org/
 License: GPLv2+
 Group: Development/Debuggers
@@ -17,6 +17,40 @@ Source: ltrace-%{version}.tar.bz2
 # Merge of several upstream commits that fixes compilation on ARM.
 Patch0: ltrace-0.7.91-arm.patch
 
+# Upstream patch that fixes accounting of exec, __libc_start_main and
+# others in -c output.
+Patch1: ltrace-0.7.91-account_execl.patch
+
+# Upstream patch that fixes interpretation of PLT on x86_64 when
+# IRELATIVE slots are present.
+# https://bugzilla.redhat.com/show_bug.cgi?id=844998
+Patch2: ltrace-0.7.91-x86_64-irelative.patch
+
+# Upstream patch that fixes fetching of system call arguments on s390.
+# https://bugzilla.redhat.com/show_bug.cgi?id=844998
+Patch3: ltrace-0.7.91-s390-fetch-syscall.patch
+
+# Upstream patch that enables tracing of IRELATIVE PLT slots on s390.
+# https://bugzilla.redhat.com/show_bug.cgi?id=844998
+Patch4: ltrace-0.7.91-s390-irelative.patch
+
+# Fix for a regression in tracing across fork.  Upstream patch.
+# https://bugzilla.redhat.com/show_bug.cgi?id=1052255
+Patch5: ltrace-0.7.91-ppc64-fork.patch
+
+# Fix crashing a prelinked PPC64 binary which makes PLT calls through
+# slots that ltrace doesn't trace.
+# https://bugzilla.redhat.com/show_bug.cgi?id=1051221
+Patch6: ltrace-0.7.91-breakpoint-on_install.patch
+Patch7: ltrace-0.7.91-ppc64-unprelink.patch
+
+# Man page nits.  Backport of an upstream patch.
+# https://bugzilla.redhat.com/show_bug.cgi?id=866394
+Patch8: ltrace-0.7.91-man.patch
+
+# https://bugzilla.redhat.com/show_bug.cgi?id=1053765
+Patch9: ltrace-0.7.91-cant_open.patch
+
 %description
 Ltrace is a debugging program which runs a specified command until the
 command exits.  While the command is executing, ltrace intercepts and
@@ -30,6 +64,15 @@ execution of processes.
 %prep
 %setup -q -n %{name}-%{version}
 %patch0 -p1
+%patch1 -p1
+%patch2 -p1
+%patch3 -p1
+%patch4 -p1
+%patch5 -p1
+%patch6 -p1
+%patch7 -p1
+%patch8 -p1
+%patch9 -p1
 
 %build
 %configure
@@ -54,6 +97,38 @@ echo ====================TESTING END=====================
 %{_datadir}/ltrace
 
 %changelog
+* Fri Jan 24 2014 Daniel Mach <dmach@redhat.com> - 0.7.91-7
+- Mass rebuild 2014-01-24
+
+* Tue Jan 14 2014 Petr Machata <pmachata@redhat.com> - 0.7.91-6
+- Fix a problem when attempting to trace a command that hasn't been
+  found (ltrace-0.7.91-cant_open.patch)
+
+* Tue Jan 14 2014 Petr Machata <pmachata@redhat.com> - 0.7.91-5
+- Fix crashing a prelinked PPC64 binary which makes PLT calls through
+  slots that ltrace doesn't trace.
+  (ltrace-0.7.91-breakpoint-on_install.patch,
+  ltrace-0.7.91-ppc64-unprelink.patch)
+- Fix a problem in tracing across fork on PPC64
+  (ltrace-0.7.91-ppc64-fork.patch)
+- Fix a couple nits in ltrace.1
+  (ltrace-0.7.91-man.patch)
+
+* Fri Dec 27 2013 Daniel Mach <dmach@redhat.com> - 0.7.91-4
+- Mass rebuild 2013-12-27
+
+* Wed Dec  4 2013 Petr Machata <pmachata@redhat.com> - 0.7.91-3
+- Fix interpretation of x86_64 PLT with IRELATIVE slots.
+  (ltrace-0.7.91-x86_64-irelative.patch)
+- Fix fetching of system call arguments on s390.
+  (ltrace-0.7.91-s390-fetch-syscall.patch)
+- Enable tracing of IRELATIVE PLT slots on s390.
+  (ltrace-0.7.91-s390-irelative.patch)
+
+* Thu Nov 21 2013 Petr Machata <pmachata@redhat.com> - 0.7.91-2
+- Fix a problem in including in summary (-c) function calls that don't
+  finish before exec or exit (ltrace-0.7.91-account_execl.patch)
+
 * Tue Nov  5 2013 Petr Machata <pmachata@redhat.com> - 0.7.91-1
 - Rebase to a pre-release 0.8
 - Drop BR on autoconf and friends