[ltrace] Bring in patches from upstream, add ARM support

Petr Machata pmachata at fedoraproject.org
Thu Jan 31 21:39:41 UTC 2013


commit 4b23d2c6b77a8025bdc5a24231e17329518e70a2
Author: Petr Machata <pmachata at redhat.com>
Date:   Thu Jan 31 22:38:07 2013 +0100

    Bring in patches from upstream, add ARM support

 ltrace-0.7.2-arm.patch  | 1684 ++++++++++++
 ltrace-0.7.2-bits.patch | 6472 +++++++++++++++++++++++++++++++++++++++++++++++
 ltrace-0.7.2-man.patch  |  364 ---
 ltrace.spec             |   21 +-
 4 files changed, 8174 insertions(+), 367 deletions(-)
---
diff --git a/ltrace-0.7.2-arm.patch b/ltrace-0.7.2-arm.patch
new file mode 100644
index 0000000..a469224
--- /dev/null
+++ b/ltrace-0.7.2-arm.patch
@@ -0,0 +1,1684 @@
+diff --git a/Makefile.am b/Makefile.am
+index c3356de..141ff85 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -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.
+ # Copyright (C) 2010 Marc Kleine-Budde, Pengutronix
+ # Copyright (C) 2010 Zachary T Welch, CodeSourcery
+ #
+@@ -33,6 +33,7 @@ noinst_LTLIBRARIES = \
+ 	libltrace.la
+ 
+ libltrace_la_SOURCES = \
++	bits.c \
+ 	breakpoints.c \
+ 	debug.c \
+ 	demangle.c \
+@@ -83,6 +84,7 @@ ltrace_LDADD = \
+ 
+ 
+ noinst_HEADERS = \
++	bits.h \
+ 	backend.h \
+ 	breakpoint.h \
+ 	common.h \
+diff --git a/backend.h b/backend.h
+index cfac65e..a9de3b4 100644
+--- a/backend.h
++++ b/backend.h
+@@ -107,10 +107,6 @@ void *get_stack_pointer(struct process *proc);
+  * function returns.  */
+ void *get_return_addr(struct process *proc, void *stack_pointer);
+ 
+-/* Adjust PROC so that when the current function returns, it returns
+- * to ADDR.  */
+-void set_return_addr(struct process *proc, void *addr);
+-
+ /* Enable breakpoint SBP in process PROC.  */
+ void enable_breakpoint(struct process *proc, struct breakpoint *sbp);
+ 
+diff --git a/bits.c b/bits.c
+new file mode 100644
+index 0000000..bde2e71
+--- /dev/null
++++ b/bits.c
+@@ -0,0 +1,34 @@
++/*
++ * 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
++ */
++
++#include "bits.h"
++
++/* This is called rarely, and any overhead will be lost in ptrace
++ * noise, so the algorithm doesn't need to be terribly clever.  For
++ * the same reason we don't bother defining the corresponding _32
++ * variant.  */
++unsigned
++bitcount(uint64_t u)
++{
++	int c = 0;
++	for (; u > 0; u &= u - 1)
++		c++;
++	return c;
++}
+diff --git a/bits.h b/bits.h
+new file mode 100644
+index 0000000..7dbe478
+--- /dev/null
++++ b/bits.h
+@@ -0,0 +1,29 @@
++/*
++ * 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 _BITS_H_
++#define _BITS_H_
++
++#include <stdint.h>
++
++/* Count bits in U that are 1.  */
++unsigned bitcount(uint64_t u);
++
++#endif /* _BITS_H_ */
+diff --git a/breakpoint.h b/breakpoint.h
+index 18af7a9..963cc66 100644
+--- a/breakpoint.h
++++ b/breakpoint.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 Juan Cespedes
+  *
+  * This program is free software; you can redistribute it and/or
+@@ -82,11 +82,10 @@ int breakpoint_init(struct breakpoint *bp, struct process *proc,
+ 		    arch_addr_t addr, struct library_symbol *libsym);
+ 
+ /* Make a clone of breakpoint BP into the area of memory pointed to by
+- * RETP.  The original breakpoint was assigned to process OLD_PROC,
+- * the cloned breakpoint will be attached to process NEW_PROC.
++ * RETP.  Symbols of cloned breakpoint are looked up in NEW_PROC.
+  * Returns 0 on success or a negative value on failure.  */
+ int breakpoint_clone(struct breakpoint *retp, struct process *new_proc,
+-		     struct breakpoint *bp, struct process *old_proc);
++		     struct breakpoint *bp);
+ 
+ /* Set callbacks.  If CBS is non-NULL, then BP->cbs shall be NULL.  */
+ void breakpoint_set_callbacks(struct breakpoint *bp, struct bp_callbacks *cbs);
+diff --git a/breakpoints.c b/breakpoints.c
+index 8db4e26..7b5530a 100644
+--- a/breakpoints.c
++++ b/breakpoints.c
+@@ -1,6 +1,6 @@
+ /*
+  * This file is part of ltrace.
+- * Copyright (C) 2006,2007,2011,2012 Petr Machata, Red Hat Inc.
++ * Copyright (C) 2006,2007,2011,2012,2013 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
+@@ -117,7 +117,7 @@ arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp)
+ #endif
+ 
+ static void
+-breakpoint_init_base(struct breakpoint *bp, struct process *proc,
++breakpoint_init_base(struct breakpoint *bp,
+ 		     arch_addr_t addr, struct library_symbol *libsym)
+ {
+ 	bp->cbs = NULL;
+@@ -135,7 +135,7 @@ int
+ breakpoint_init(struct breakpoint *bp, struct process *proc,
+ 		arch_addr_t addr, struct library_symbol *libsym)
+ {
+-	breakpoint_init_base(bp, proc, addr, libsym);
++	breakpoint_init_base(bp, addr, libsym);
+ 	return arch_breakpoint_init(proc, bp);
+ }
+ 
+@@ -157,7 +157,7 @@ breakpoint_destroy(struct breakpoint *bp)
+ 
+ int
+ breakpoint_clone(struct breakpoint *retp, struct process *new_proc,
+-		 struct breakpoint *bp, struct process *old_proc)
++		 struct breakpoint *bp)
+ {
+ 	struct library_symbol *libsym = NULL;
+ 	if (bp->libsym != NULL) {
+@@ -165,7 +165,7 @@ breakpoint_clone(struct breakpoint *retp, struct process *new_proc,
+ 		assert(rc == 0);
+ 	}
+ 
+-	breakpoint_init_base(retp, new_proc, bp->addr, libsym);
++	breakpoint_init_base(retp, bp->addr, libsym);
+ 	memcpy(retp->orig_value, bp->orig_value, sizeof(bp->orig_value));
+ 	retp->enabled = bp->enabled;
+ 	if (arch_breakpoint_clone(retp, bp) < 0)
+@@ -211,6 +211,22 @@ insert_breakpoint(struct process *proc, void *addr,
+ 
+ 	assert(addr != 0);
+ 
++	/* We first create the breakpoint to find out what it's real
++	 * address is.  This makes a difference on ARM.
++	 *
++	 * XXX The real problem here is that to create a return
++	 * breakpoint ltrace calls get_return_addr and then
++	 * insert_breakpoint.  So get_return_addr needs to encode all
++	 * the information necessary for breakpoint_init into the
++	 * address itself, so ADDR is potentially mangled.  We filter
++	 * the noise out by first creating the breakpoint on stack,
++	 * and then looking at the address of the created breakpoint.
++	 * Replacing get_return_addr with get_return_breakpoint might
++	 * be a better solution.  */
++	struct breakpoint bp;
++	if (breakpoint_init(&bp, proc, addr, libsym) < 0)
++		return NULL;
++
+ 	/* XXX what we need to do instead is have a list of
+ 	 * breakpoints that are enabled at this address.  The
+ 	 * following works if every breakpoint is the same and there's
+@@ -218,20 +234,21 @@ insert_breakpoint(struct process *proc, void *addr,
+ 	 * will suffice, about the only realistic case where we need
+ 	 * to have more than one breakpoint per address is return from
+ 	 * a recursive library call.  */
+-	struct breakpoint *sbp = dict_find_entry(leader->breakpoints, addr);
+-	if (sbp == NULL) {
++	struct breakpoint *sbp = dict_find_entry(leader->breakpoints, bp.addr);
++	if (sbp != NULL) {
++		breakpoint_destroy(&bp);
++	} else {
++	  //fprintf(stderr, "new BP at %p\n", addr);
+ 		sbp = malloc(sizeof(*sbp));
+-		if (sbp == NULL
+-		    || breakpoint_init(sbp, proc, addr, libsym) < 0) {
+-			free(sbp);
+-			return NULL;
+-		}
+-		if (proc_add_breakpoint(leader, sbp) < 0) {
++		if (sbp == NULL) {
+ 		fail:
+-			breakpoint_destroy(sbp);
+ 			free(sbp);
++			breakpoint_destroy(&bp);
+ 			return NULL;
+ 		}
++		memcpy(sbp, &bp, sizeof(*sbp));
++		if (proc_add_breakpoint(leader, sbp) < 0)
++			goto fail;
+ 	}
+ 
+ 	if (breakpoint_turn_on(sbp, proc) < 0) {
+diff --git a/handle_event.c b/handle_event.c
+index 9dbb696..1eaea09 100644
+--- a/handle_event.c
++++ b/handle_event.c
+@@ -607,7 +607,6 @@ handle_breakpoint(Event *event)
+ 					calc_time_spent(event->proc);
+ 				}
+ 			}
+-			event->proc->return_addr = brk_addr;
+ 
+ 			struct library_symbol *libsym =
+ 			    event->proc->callstack[i].c_un.libfunc;
+@@ -663,8 +662,6 @@ handle_breakpoint(Event *event)
+ 		if (event->proc->state != STATE_IGNORED
+ 		    && sbp->libsym != NULL) {
+ 			event->proc->stack_pointer = get_stack_pointer(event->proc);
+-			event->proc->return_addr =
+-				get_return_addr(event->proc, event->proc->stack_pointer);
+ 			callstack_push_symfunc(event->proc, sbp->libsym);
+ 			output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym);
+ 		}
+@@ -722,9 +719,11 @@ callstack_push_symfunc(struct process *proc, struct library_symbol *sym)
+ 	elem->is_syscall = 0;
+ 	elem->c_un.libfunc = sym;
+ 
+-	elem->return_addr = proc->return_addr;
+-	if (elem->return_addr)
+-		insert_breakpoint(proc, elem->return_addr, NULL);
++	arch_addr_t return_addr = get_return_addr(proc, proc->stack_pointer);
++	struct breakpoint *rbp = NULL;
++	if (return_addr != 0)
++		rbp = insert_breakpoint(proc, return_addr, NULL);
++	elem->return_addr = rbp != NULL ? rbp->addr : 0;
+ 
+ 	if (opt_T || options.summary) {
+ 		struct timezone tz;
+diff --git a/lens_default.c b/lens_default.c
+index ed3d0e1..47b8c70 100644
+--- a/lens_default.c
++++ b/lens_default.c
+@@ -29,6 +29,7 @@
+ #include <stdio.h>
+ #include <string.h>
+ 
++#include "bits.h"
+ #include "proc.h"
+ #include "lens_default.h"
+ #include "value.h"
+@@ -608,15 +609,6 @@ out_bits(FILE *stream, size_t low, size_t high)
+ 		return fprintf(stream, "%zd-%zd", low, high);
+ }
+ 
+-static unsigned
+-bitcount(unsigned u)
+-{
+-	int c = 0;
+-	for (; u > 0; u &= u - 1)
+-		c++;
+-	return c;
+-}
+-
+ static int
+ bitvect_lens_format_cb(struct lens *lens, FILE *stream,
+ 		       struct value *value, struct value_dict *arguments)
+diff --git a/output.c b/output.c
+index fe62bb4..f046df8 100644
+--- a/output.c
++++ b/output.c
+@@ -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) 2010 Joe Damato
+  * Copyright (C) 1997,1998,1999,2001,2002,2003,2004,2007,2008,2009 Juan Cespedes
+  * Copyright (C) 2006 Paul Gilliam, IBM Corporation
+@@ -119,12 +119,15 @@ begin_of_line(struct process *proc, int is_func, int indent)
+ 		}
+ 	}
+ 	if (opt_i) {
+-		if (is_func)
++		if (is_func) {
++			struct callstack_element *stel
++				= &proc->callstack[proc->callstack_depth - 1];
+ 			current_column += fprintf(options.output, "[%p] ",
+-						  proc->return_addr);
+-		else
++						  stel->return_addr);
++		} else {
+ 			current_column += fprintf(options.output, "[%p] ",
+ 						  proc->instruction_pointer);
++		}
+ 	}
+ 	if (options.indent > 0 && indent) {
+ 		output_indent(proc);
+diff --git a/proc.c b/proc.c
+index db3f645..7dfde7c 100644
+--- a/proc.c
++++ b/proc.c
+@@ -314,8 +314,7 @@ clone_single_bp(void *key, void *value, void *u)
+ 
+ 	struct breakpoint *clone = malloc(sizeof(*clone));
+ 	if (clone == NULL
+-	    || breakpoint_clone(clone, data->new_proc,
+-				bp, data->old_proc) < 0) {
++	    || breakpoint_clone(clone, data->new_proc, bp) < 0) {
+ 	fail:
+ 		free(clone);
+ 		data->error = -1;
+@@ -1050,6 +1049,7 @@ proc_each_symbol(struct process *proc, struct library_symbol *start_after,
+ 		return 0;						\
+ 	}
+ 
++DEF_READER(proc_read_8, 8)
+ DEF_READER(proc_read_16, 16)
+ DEF_READER(proc_read_32, 32)
+ DEF_READER(proc_read_64, 64)
+diff --git a/proc.h b/proc.h
+index 04c0ef7..03708dc 100644
+--- a/proc.h
++++ b/proc.h
+@@ -65,7 +65,7 @@ struct callstack_element {
+ 		struct library_symbol * libfunc;
+ 	} c_un;
+ 	int is_syscall;
+-	void * return_addr;
++	arch_addr_t return_addr;
+ 	struct timeval time_spent;
+ 	struct fetch_context *fetch_context;
+ 	struct value_dict *arguments;
+@@ -106,7 +106,6 @@ struct process {
+ 	/* Arch-dependent: */
+ 	void * instruction_pointer;
+ 	void * stack_pointer;      /* To get return addr, args... */
+-	void * return_addr;
+ 	void * arch_ptr;
+ 
+ 	/* XXX We would like to replace this with a pointer to ABI
+@@ -116,11 +115,6 @@ struct process {
+ 	short e_machine;
+ 	char e_class;
+ 
+-	/* XXX this shoudl go to ARM's arch_process_data.  */
+-#ifdef __arm__
+-	int thumb_mode;           /* ARM execution mode: 0: ARM, 1: Thumb */
+-#endif
+-
+ #if defined(HAVE_LIBUNWIND)
+ 	/* libunwind address space */
+ 	unw_addr_space_t unwind_as;
+@@ -254,10 +248,11 @@ struct library_symbol *proc_each_symbol
+ 	 enum callback_status (*cb)(struct library_symbol *, void *),
+ 	 void *data);
+ 
+-/* Read 16, 32 or 64-bit quantity located at ADDR in PROC.  The
++/* Read 8, 16, 32 or 64-bit quantity located at ADDR in PROC.  The
+  * resulting value is stored in *LP.  0 is returned on success or a
+  * negative value on failure.  This uses umovebytes under the hood
+  * (see backend.h).  */
++int proc_read_8(struct process *proc, arch_addr_t addr, uint8_t *lp);
+ int proc_read_16(struct process *proc, arch_addr_t addr, uint16_t *lp);
+ int proc_read_32(struct process *proc, arch_addr_t addr, uint32_t *lp);
+ int proc_read_64(struct process *proc, arch_addr_t addr, uint64_t *lp);
+diff --git a/sysdeps/linux-gnu/alpha/regs.c b/sysdeps/linux-gnu/alpha/regs.c
+index c197225..9ccd8f2 100644
+--- a/sysdeps/linux-gnu/alpha/regs.c
++++ b/sysdeps/linux-gnu/alpha/regs.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
+@@ -58,9 +59,3 @@ get_return_addr(struct process *proc, void *stack_pointer)
+ {
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 26 /* RA */ , 0);
+ }
+-
+-void
+-set_return_addr(struct process *proc, void *addr)
+-{
+-	ptrace(PTRACE_POKEUSER, proc->pid, 26 /* RA */ , addr);
+-}
+diff --git a/sysdeps/linux-gnu/arm/Makefile.am b/sysdeps/linux-gnu/arm/Makefile.am
+index 385424c..4b858ec 100644
+--- a/sysdeps/linux-gnu/arm/Makefile.am
++++ b/sysdeps/linux-gnu/arm/Makefile.am
+@@ -1,4 +1,5 @@
+ # This file is part of ltrace.
++# Copyright (C) 2013 Petr Machata, Red Hat Inc.
+ # Copyright (C) 2010 Marc Kleine-Budde, Pengutronix
+ #
+ # This program is free software; you can redistribute it and/or
+@@ -16,21 +17,11 @@
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ # 02110-1301 USA
+ 
+-noinst_LTLIBRARIES = \
+-	../libcpu.la
++noinst_LTLIBRARIES = ../libcpu.la
+ 
+-___libcpu_la_SOURCES = \
+-	breakpoint.c \
+-	plt.c \
+-	regs.c \
+-	trace.c
++___libcpu_la_SOURCES = breakpoint.c plt.c regs.c trace.c
+ 
+-noinst_HEADERS = \
+-	arch.h \
+-	arch_syscallent.h \
+-	ptrace.h \
+-	signalent.h \
+-	syscallent.h
++noinst_HEADERS = arch.h arch_syscallent.h ptrace.h regs.h signalent.h	\
++	 syscallent.h
+ 
+-MAINTAINERCLEANFILES = \
+-	Makefile.in
++MAINTAINERCLEANFILES = Makefile.in
+diff --git a/sysdeps/linux-gnu/arm/arch.h b/sysdeps/linux-gnu/arm/arch.h
+index 291443a..71cfd5e 100644
+--- a/sysdeps/linux-gnu/arm/arch.h
++++ b/sysdeps/linux-gnu/arm/arch.h
+@@ -1,5 +1,6 @@
+ /*
+  * This file is part of ltrace.
++ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
+  * Copyright (C) 1998,2004,2008 Juan Cespedes
+  *
+  * This program is free software; you can redistribute it and/or
+@@ -31,6 +32,7 @@
+ #define LT_ELFCLASS	ELFCLASS32
+ #define LT_ELF_MACHINE	EM_ARM
+ 
++#define ARCH_HAVE_SW_SINGLESTEP
+ #define ARCH_HAVE_BREAKPOINT_DATA
+ struct arch_breakpoint_data {
+ 	int thumb_mode;
+diff --git a/sysdeps/linux-gnu/arm/breakpoint.c b/sysdeps/linux-gnu/arm/breakpoint.c
+index 2fb9578..fcd43a7 100644
+--- a/sysdeps/linux-gnu/arm/breakpoint.c
++++ b/sysdeps/linux-gnu/arm/breakpoint.c
+@@ -94,14 +94,11 @@ arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp)
+ int
+ arch_breakpoint_init(struct process *proc, struct breakpoint *sbp)
+ {
+-	/* XXX That uintptr_t cast is there temporarily until
+-	 * arch_addr_t becomes integral type.  */
+-	int thumb_mode = ((uintptr_t)sbp->addr) & 1;
+-	if (thumb_mode)
+-		sbp->addr = (void *)((uintptr_t)sbp->addr & ~1);
+-	sbp->arch.thumb_mode = thumb_mode | proc->thumb_mode;
+-	/* XXX This doesn't seem like it belongs here.  */
+-	proc->thumb_mode = 0;
++	/* XXX double cast  */
++	sbp->arch.thumb_mode = ((uintptr_t)sbp->addr) & 1;
++	if (sbp->arch.thumb_mode)
++		/* XXX double cast */
++		sbp->addr = (arch_addr_t)((uintptr_t)sbp->addr & ~1);
+ 	return 0;
+ }
+ 
+diff --git a/sysdeps/linux-gnu/arm/regs.c b/sysdeps/linux-gnu/arm/regs.c
+index 377df62..bd86370 100644
+--- a/sysdeps/linux-gnu/arm/regs.c
++++ b/sysdeps/linux-gnu/arm/regs.c
+@@ -1,5 +1,6 @@
+ /*
+  * This file is part of ltrace.
++ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
+  * Copyright (C) 1998,2002,2004,2008,2009 Juan Cespedes
+  * Copyright (C) 2009 Juan Cespedes
+  *
+@@ -24,9 +25,11 @@
+ #include <sys/types.h>
+ #include <sys/ptrace.h>
+ #include <asm/ptrace.h>
++#include <errno.h>
+ 
+ #include "proc.h"
+ #include "common.h"
++#include "regs.h"
+ 
+ #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
+ # define PTRACE_PEEKUSER PTRACE_PEEKUSR
+@@ -37,13 +40,91 @@
+ #endif
+ 
+ #define off_pc ((void *)60)
+-#define off_lr ((void *)56)
+ #define off_sp ((void *)52)
+ 
+-void *
++int
++arm_get_register(struct process *proc, enum arm_register reg, uint32_t *lp)
++{
++	errno = 0;
++	long l = ptrace(PTRACE_PEEKUSER, proc->pid, (void *)(reg * 4L), 0);
++	if (l == -1 && errno != 0)
++		return -1;
++	*lp = (uint32_t)l;
++	return 0;
++}
++
++int
++arm_get_register_offpc(struct process *proc, enum arm_register reg,
++		       uint32_t *lp)
++{
++	if (arm_get_register(proc, reg, lp) < 0)
++		return -1;
++	if (reg == ARM_REG_PC)
++		*lp += 8;
++	return 0;
++}
++
++int
++arm_get_shifted_register(struct process *proc, uint32_t inst, int carry,
++			 arch_addr_t pc_val, uint32_t *lp)
++{
++	enum arm_register rm = BITS(inst, 0, 3);
++	unsigned long shifttype = BITS(inst, 5, 6);
++
++	uint32_t shift;
++	if (BIT(inst, 4)) {
++		if (arm_get_register_offpc(proc, BITS(inst, 8, 11), &shift) < 0)
++			return -1;
++		shift &= 0xff;
++	} else {
++		shift = BITS(inst, 7, 11);
++	}
++
++	uint32_t res;
++	if (rm == ARM_REG_PC)
++		/* xxx double cast */
++		res = (uintptr_t)pc_val + (BIT(inst, 4) ? 12 : 8);
++	else if (arm_get_register(proc, rm, &res) < 0)
++		return -1;
++
++	switch (shifttype) {
++	case 0:			/* LSL */
++		res = shift >= 32 ? 0 : res << shift;
++		break;
++
++	case 1:			/* LSR */
++		res = shift >= 32 ? 0 : res >> shift;
++		break;
++
++	case 2:			/* ASR */
++		if (shift >= 32)
++			shift = 31;
++		res = ((res & 0x80000000L)
++		       ? ~((~res) >> shift) : res >> shift);
++		break;
++
++	case 3:			/* ROR/RRX */
++		shift &= 31;
++		if (shift == 0)
++			res = (res >> 1) | (carry ? 0x80000000L : 0);
++		else
++			res = (res >> shift) | (res << (32 - shift));
++		break;
++	}
++
++	*lp = res & 0xffffffff;
++	return 0;
++}
++
++arch_addr_t
+ get_instruction_pointer(struct process *proc)
+ {
+-	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0);
++	uint32_t reg;
++	if (arm_get_register(proc, ARM_REG_PC, &reg) < 0)
++		/* XXX double cast. */
++		return (arch_addr_t)-1;
++	/* XXX double cast.  */
++	return (arch_addr_t)(uintptr_t)reg;
+ }
+ 
+ void
+@@ -58,28 +139,13 @@ get_stack_pointer(struct process *proc)
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_sp, 0);
+ }
+ 
+-/* really, this is given the *stack_pointer expecting
+- * a CISC architecture; in our case, we don't need that */
+-void *
+-get_return_addr(struct process *proc, void *stack_pointer)
+-{
+-	long addr = ptrace(PTRACE_PEEKUSER, proc->pid, off_lr, 0);
+-
+-	/* Remember & unset the thumb mode bit.  XXX This is really a
+-	 * bit of a hack, as we assume that the following
+-	 * insert_breakpoint call will be related to this address.
+-	 * This interface should really be get_return_breakpoint, or
+-	 * maybe install_return_breakpoint.  */
+-	proc->thumb_mode = addr & 1;
+-	if (proc->thumb_mode)
+-		addr &= ~1;
+-
+-	return (void *)addr;
+-}
+-
+-void
+-set_return_addr(struct process *proc, void *addr)
++arch_addr_t
++get_return_addr(struct process *proc, arch_addr_t stack_pointer)
+ {
+-	long iaddr = (int)addr | proc->thumb_mode;
+-	ptrace(PTRACE_POKEUSER, proc->pid, off_lr, (void *)iaddr);
++	uint32_t reg;
++	if (arm_get_register(proc, ARM_REG_LR, &reg) < 0)
++		/* XXX double cast. */
++		return (arch_addr_t)-1;
++	/* XXX double cast.  */
++	return (arch_addr_t)(uintptr_t)reg;
+ }
+diff --git a/sysdeps/linux-gnu/arm/regs.h b/sysdeps/linux-gnu/arm/regs.h
+new file mode 100644
+index 0000000..1566f92
+--- /dev/null
++++ b/sysdeps/linux-gnu/arm/regs.h
+@@ -0,0 +1,45 @@
++/*
++ * 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
++ */
++
++#define SUBMASK(x) ((1L << ((x) + 1)) - 1)
++#define BIT(obj,st) (((obj) >> (st)) & 1)
++#define BITS(obj,st,fn) (((obj) >> (st)) & SUBMASK((fn) - (st)))
++#define SBITS(obj,st,fn) \
++	((long) (BITS(obj,st,fn) | ((long) BIT(obj,fn) * ~ SUBMASK(fn - st))))
++
++enum arm_register {
++	ARM_REG_SP = 13,
++	ARM_REG_LR = 14,
++	ARM_REG_PC = 15,
++	ARM_REG_CPSR = 16,
++};
++
++/* Write value of register REG to *LP.  Return 0 on success or a
++ * negative value on failure.  */
++int arm_get_register(struct process *proc, enum arm_register reg, uint32_t *lp);
++
++/* Same as above, but if REG==ARM_REG_PC, it returns the value +8.  */
++int arm_get_register_offpc(struct process *proc, enum arm_register reg,
++			   uint32_t *lp);
++
++/* Same as arm_get_register, but shift is performed depending on
++ * instruction INST.  */
++int arm_get_shifted_register(struct process *proc, uint32_t inst, int carry,
++			     arch_addr_t pc, uint32_t *lp);
+diff --git a/sysdeps/linux-gnu/arm/trace.c b/sysdeps/linux-gnu/arm/trace.c
+index fbbf676..8b0734e 100644
+--- a/sysdeps/linux-gnu/arm/trace.c
++++ b/sysdeps/linux-gnu/arm/trace.c
+@@ -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) 1998,2004,2008,2009 Juan Cespedes
+  * Copyright (C) 2006 Ian Wienand
+  *
+@@ -29,10 +29,12 @@
+ #include <sys/ptrace.h>
+ #include <asm/ptrace.h>
+ 
+-#include "proc.h"
++#include "bits.h"
+ #include "common.h"
++#include "proc.h"
+ #include "output.h"
+ #include "ptrace.h"
++#include "regs.h"
+ 
+ #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
+ # define PTRACE_PEEKUSER PTRACE_PEEKUSR
+@@ -46,6 +48,7 @@
+ #define off_r7 ((void *)28)
+ #define off_ip ((void *)48)
+ #define off_pc ((void *)60)
++#define off_cpsr ((void *)64)
+ 
+ void
+ get_arch_dep(struct process *proc)
+@@ -149,3 +152,560 @@ gimme_arg(enum tof type, struct process *proc, int arg_num,
+ 
+ 	return 0;
+ }
++
++static arch_addr_t
++arm_branch_dest(const arch_addr_t pc, const uint32_t insn)
++{
++	/* Bits 0-23 are signed immediate value.  */
++	return pc + ((((insn & 0xffffff) ^ 0x800000) - 0x800000) << 2) + 8;
++}
++
++/* Addresses for calling Thumb functions have the bit 0 set.
++   Here are some macros to test, set, or clear bit 0 of addresses.  */
++/* XXX double cast */
++#define IS_THUMB_ADDR(addr)	((uintptr_t)(addr) & 1)
++#define MAKE_THUMB_ADDR(addr)	((arch_addr_t)((uintptr_t)(addr) | 1))
++#define UNMAKE_THUMB_ADDR(addr) ((arch_addr_t)((uintptr_t)(addr) & ~1))
++
++enum {
++	COND_ALWAYS = 0xe,
++	COND_NV = 0xf,
++	FLAG_C = 0x20000000,
++};
++
++static int
++arm_get_next_pcs(struct process *proc,
++		 const arch_addr_t pc, arch_addr_t next_pcs[2])
++{
++	uint32_t this_instr;
++	uint32_t status;
++	if (proc_read_32(proc, pc, &this_instr) < 0
++	    || arm_get_register(proc, ARM_REG_CPSR, &status) < 0)
++		return -1;
++
++	/* In theory, we sometimes don't even need to add any
++	 * breakpoints at all.  If the conditional bits of the
++	 * instruction indicate that it should not be taken, then we
++	 * can just skip it altogether without bothering.  We could
++	 * also emulate the instruction under the breakpoint.
++	 *
++	 * Here, we make it as simple as possible (though We Accept
++	 * Patches).  */
++	int nr = 0;
++
++	/* ARM can branch either relatively by using a branch
++	 * instruction, or absolutely, by doing arbitrary arithmetic
++	 * with PC as the destination.  */
++	const unsigned cond = BITS(this_instr, 28, 31);
++	const unsigned opcode = BITS(this_instr, 24, 27);
++
++	if (cond == COND_NV)
++		switch (opcode) {
++			arch_addr_t addr;
++		case 0xa:
++		case 0xb:
++			/* Branch with Link and change to Thumb.  */
++			/* XXX double cast.  */
++			addr = (arch_addr_t)
++				((uint32_t)arm_branch_dest(pc, this_instr)
++				 | (((this_instr >> 24) & 0x1) << 1));
++			next_pcs[nr++] = MAKE_THUMB_ADDR(addr);
++			break;
++		}
++	else
++		switch (opcode) {
++			uint32_t operand1, operand2, result = 0;
++		case 0x0:
++		case 0x1:			/* data processing */
++		case 0x2:
++		case 0x3:
++			if (BITS(this_instr, 12, 15) != ARM_REG_PC)
++				break;
++
++			if (BITS(this_instr, 22, 25) == 0
++			    && BITS(this_instr, 4, 7) == 9) {	/* multiply */
++			invalid:
++				fprintf(stderr,
++				"Invalid update to pc in instruction.\n");
++				break;
++			}
++
++			/* BX <reg>, BLX <reg> */
++			if (BITS(this_instr, 4, 27) == 0x12fff1
++			    || BITS(this_instr, 4, 27) == 0x12fff3) {
++				enum arm_register reg = BITS(this_instr, 0, 3);
++				/* XXX double cast: no need to go
++				 * through tmp.  */
++				uint32_t tmp;
++				if (arm_get_register_offpc(proc, reg, &tmp) < 0)
++					return -1;
++				next_pcs[nr++] = (arch_addr_t)tmp;
++				return 0;
++			}
++
++			/* Multiply into PC.  */
++			if (arm_get_register_offpc
++			    (proc, BITS(this_instr, 16, 19), &operand1) < 0)
++				return -1;
++
++			int c = (status & FLAG_C) ? 1 : 0;
++			if (BIT(this_instr, 25)) {
++				uint32_t immval = BITS(this_instr, 0, 7);
++				uint32_t rotate = 2 * BITS(this_instr, 8, 11);
++				operand2 = (((immval >> rotate)
++					     | (immval << (32 - rotate)))
++					    & 0xffffffff);
++			} else {
++				/* operand 2 is a shifted register.  */
++				if (arm_get_shifted_register
++				    (proc, this_instr, c, pc, &operand2) < 0)
++					return -1;
++			}
++
++			switch (BITS(this_instr, 21, 24)) {
++			case 0x0:	/*and */
++				result = operand1 & operand2;
++				break;
++
++			case 0x1:	/*eor */
++				result = operand1 ^ operand2;
++				break;
++
++			case 0x2:	/*sub */
++				result = operand1 - operand2;
++				break;
++
++			case 0x3:	/*rsb */
++				result = operand2 - operand1;
++				break;
++
++			case 0x4:	/*add */
++				result = operand1 + operand2;
++				break;
++
++			case 0x5:	/*adc */
++				result = operand1 + operand2 + c;
++				break;
++
++			case 0x6:	/*sbc */
++				result = operand1 - operand2 + c;
++				break;
++
++			case 0x7:	/*rsc */
++				result = operand2 - operand1 + c;
++				break;
++
++			case 0x8:
++			case 0x9:
++			case 0xa:
++			case 0xb:	/* tst, teq, cmp, cmn */
++				/* Only take the default branch.  */
++				result = 0;
++				break;
++
++			case 0xc:	/*orr */
++				result = operand1 | operand2;
++				break;
++
++			case 0xd:	/*mov */
++				/* Always step into a function.  */
++				result = operand2;
++				break;
++
++			case 0xe:	/*bic */
++				result = operand1 & ~operand2;
++				break;
++
++			case 0xf:	/*mvn */
++				result = ~operand2;
++				break;
++			}
++
++			/* XXX double cast */
++			next_pcs[nr++] = (arch_addr_t)result;
++			break;
++
++		case 0x4:
++		case 0x5:		/* data transfer */
++		case 0x6:
++		case 0x7:
++			/* Ignore if insn isn't load or Rn not PC.  */
++			if (!BIT(this_instr, 20)
++			    || BITS(this_instr, 12, 15) != ARM_REG_PC)
++				break;
++
++			if (BIT(this_instr, 22))
++				goto invalid;
++
++			/* byte write to PC */
++			uint32_t base;
++			if (arm_get_register_offpc
++			    (proc, BITS(this_instr, 16, 19), &base) < 0)
++				return -1;
++
++			if (BIT(this_instr, 24)) {
++				/* pre-indexed */
++				int c = (status & FLAG_C) ? 1 : 0;
++				uint32_t offset;
++				if (BIT(this_instr, 25)) {
++					if (arm_get_shifted_register
++					    (proc, this_instr, c,
++					     pc, &offset) < 0)
++						return -1;
++				} else {
++					offset = BITS(this_instr, 0, 11);
++				}
++
++				if (BIT(this_instr, 23))
++					base += offset;
++				else
++					base -= offset;
++			}
++
++			/* XXX two double casts.  */
++			uint32_t next;
++			if (proc_read_32(proc, (arch_addr_t)base, &next) < 0)
++				return -1;
++			next_pcs[nr++] = (arch_addr_t)next;
++			break;
++
++		case 0x8:
++		case 0x9:		/* block transfer */
++			if (!BIT(this_instr, 20))
++				break;
++			/* LDM */
++			if (BIT(this_instr, 15)) {
++				/* Loading pc.  */
++				int offset = 0;
++				enum arm_register rn = BITS(this_instr, 16, 19);
++				uint32_t rn_val;
++				if (arm_get_register(proc, rn, &rn_val) < 0)
++					return -1;
++
++				int pre = BIT(this_instr, 24);
++				if (BIT(this_instr, 23)) {
++					/* Bit U = up.  */
++					unsigned reglist
++						= BITS(this_instr, 0, 14);
++					offset = bitcount(reglist) * 4;
++					if (pre)
++						offset += 4;
++				} else if (pre) {
++					offset = -4;
++				}
++
++				/* XXX double cast.  */
++				arch_addr_t addr
++					= (arch_addr_t)(rn_val + offset);
++				uint32_t next;
++				if (proc_read_32(proc, addr, &next) < 0)
++					return -1;
++				next_pcs[nr++] = (arch_addr_t)next;
++			}
++			break;
++
++		case 0xb:		/* branch & link */
++		case 0xa:		/* branch */
++			next_pcs[nr++] = arm_branch_dest(pc, this_instr);
++			break;
++
++		case 0xc:
++		case 0xd:
++		case 0xe:		/* coproc ops */
++		case 0xf:		/* SWI */
++			break;
++		}
++
++	/* Otherwise take the next instruction.  */
++	if (cond != COND_ALWAYS || nr == 0)
++		next_pcs[nr++] = pc + 4;
++	return 0;
++}
++
++/* Return the size in bytes of the complete Thumb instruction whose
++ * first halfword is INST1.  */
++
++static int
++thumb_insn_size (unsigned short inst1)
++{
++  if ((inst1 & 0xe000) == 0xe000 && (inst1 & 0x1800) != 0)
++	  return 4;
++  else
++	  return 2;
++}
++
++static int
++thumb_get_next_pcs(struct process *proc,
++		   const arch_addr_t pc, arch_addr_t next_pcs[2])
++{
++	uint16_t inst1;
++	uint32_t status;
++	if (proc_read_16(proc, pc, &inst1) < 0
++	    || arm_get_register(proc, ARM_REG_CPSR, &status) < 0)
++		return -1;
++
++	int nr = 0;
++
++	/* We currently ignore Thumb-2 conditional execution support
++	 * (the IT instruction).  No branches are allowed in IT block,
++	 * and it's not legal to jump in the middle of it, so unless
++	 * we need to singlestep through large swaths of code, which
++	 * we currently don't, we can ignore them.  */
++
++	if ((inst1 & 0xff00) == 0xbd00)	{ /* pop {rlist, pc} */
++		/* Fetch the saved PC from the stack.  It's stored
++		 * above all of the other registers.  */
++		const unsigned offset = bitcount(BITS(inst1, 0, 7)) * 4;
++		uint32_t sp;
++		uint32_t next;
++		/* XXX two double casts */
++		if (arm_get_register(proc, ARM_REG_SP, &sp) < 0
++		    || proc_read_32(proc, (arch_addr_t)(sp + offset),
++				    &next) < 0)
++			return -1;
++		next_pcs[nr++] = (arch_addr_t)next;
++	} else if ((inst1 & 0xf000) == 0xd000) { /* conditional branch */
++		const unsigned long cond = BITS(inst1, 8, 11);
++		if (cond != 0x0f) { /* SWI */
++			next_pcs[nr++] = pc + (SBITS(inst1, 0, 7) << 1);
++			if (cond == COND_ALWAYS)
++				return 0;
++		}
++	} else if ((inst1 & 0xf800) == 0xe000) { /* unconditional branch */
++		next_pcs[nr++] = pc + (SBITS(inst1, 0, 10) << 1);
++	} else if (thumb_insn_size(inst1) == 4) { /* 32-bit instruction */
++		unsigned short inst2;
++		if (proc_read_16(proc, pc + 2, &inst2) < 0)
++			return -1;
++
++		if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000) {
++			/* Branches and miscellaneous control instructions.  */
++
++			if ((inst2 & 0x1000) != 0
++			    || (inst2 & 0xd001) == 0xc000) {
++				/* B, BL, BLX.  */
++
++				const int imm1 = SBITS(inst1, 0, 10);
++				const unsigned imm2 = BITS(inst2, 0, 10);
++				const unsigned j1 = BIT(inst2, 13);
++				const unsigned j2 = BIT(inst2, 11);
++
++				int32_t offset
++					= ((imm1 << 12) + (imm2 << 1));
++				offset ^= ((!j2) << 22) | ((!j1) << 23);
++
++				/* XXX double cast */
++				uint32_t next = (uint32_t)(pc + offset);
++				/* For BLX make sure to clear the low bits.  */
++				if (BIT(inst2, 12) == 0)
++					next = next & 0xfffffffc;
++				/* XXX double cast */
++				next_pcs[nr++] = (arch_addr_t)next;
++				return 0;
++			} else if (inst1 == 0xf3de
++				   && (inst2 & 0xff00) == 0x3f00) {
++				/* SUBS PC, LR, #imm8.  */
++				uint32_t next;
++				if (arm_get_register(proc, ARM_REG_LR,
++						     &next) < 0)
++					return -1;
++				next -= inst2 & 0x00ff;
++				/* XXX double cast */
++				next_pcs[nr++] = (arch_addr_t)next;
++				return 0;
++			} else if ((inst2 & 0xd000) == 0x8000
++				   && (inst1 & 0x0380) != 0x0380) {
++				/* Conditional branch.  */
++				const int sign = SBITS(inst1, 10, 10);
++				const unsigned imm1 = BITS(inst1, 0, 5);
++				const unsigned imm2 = BITS(inst2, 0, 10);
++				const unsigned j1 = BIT(inst2, 13);
++				const unsigned j2 = BIT(inst2, 11);
++
++				int32_t offset = (sign << 20)
++					+ (j2 << 19) + (j1 << 18);
++				offset += (imm1 << 12) + (imm2 << 1);
++				next_pcs[nr++] = pc + offset;
++				if (BITS(inst1, 6, 9) == COND_ALWAYS)
++					return 0;
++			}
++		} else if ((inst1 & 0xfe50) == 0xe810) {
++			int load_pc = 1;
++			int offset;
++			const enum arm_register rn = BITS(inst1, 0, 3);
++
++			if (BIT(inst1, 7) && !BIT(inst1, 8)) {
++				/* LDMIA or POP */
++				if (!BIT(inst2, 15))
++					load_pc = 0;
++				offset = bitcount(inst2) * 4 - 4;
++			} else if (!BIT(inst1, 7) && BIT(inst1, 8)) {
++				/* LDMDB */
++				if (!BIT(inst2, 15))
++					load_pc = 0;
++				offset = -4;
++			} else if (BIT(inst1, 7) && BIT(inst1, 8)) {
++				/* RFEIA */
++				offset = 0;
++			} else if (!BIT(inst1, 7) && !BIT(inst1, 8)) {
++				/* RFEDB */
++				offset = -8;
++			} else {
++				load_pc = 0;
++			}
++
++			if (load_pc) {
++				uint32_t addr;
++				if (arm_get_register(proc, rn, &addr) < 0)
++					return -1;
++				arch_addr_t a = (arch_addr_t)(addr + offset);
++				uint32_t next;
++				if (proc_read_32(proc, a, &next) < 0)
++					return -1;
++				/* XXX double cast */
++				next_pcs[nr++] = (arch_addr_t)next;
++			}
++		} else if ((inst1 & 0xffef) == 0xea4f
++			   && (inst2 & 0xfff0) == 0x0f00) {
++			/* MOV PC or MOVS PC.  */
++			const enum arm_register rn = BITS(inst2, 0, 3);
++			uint32_t next;
++			if (arm_get_register(proc, rn, &next) < 0)
++				return -1;
++			/* XXX double cast */
++			next_pcs[nr++] = (arch_addr_t)next;
++		} else if ((inst1 & 0xff70) == 0xf850
++			   && (inst2 & 0xf000) == 0xf000) {
++			/* LDR PC.  */
++			const enum arm_register rn = BITS(inst1, 0, 3);
++			uint32_t base;
++			if (arm_get_register(proc, rn, &base) < 0)
++				return -1;
++
++			int load_pc = 1;
++			if (rn == ARM_REG_PC) {
++				base = (base + 4) & ~(uint32_t)0x3;
++				if (BIT(inst1, 7))
++					base += BITS(inst2, 0, 11);
++				else
++					base -= BITS(inst2, 0, 11);
++			} else if (BIT(inst1, 7)) {
++				base += BITS(inst2, 0, 11);
++			} else if (BIT(inst2, 11)) {
++				if (BIT(inst2, 10)) {
++					if (BIT(inst2, 9))
++						base += BITS(inst2, 0, 7);
++					else
++						base -= BITS(inst2, 0, 7);
++				}
++			} else if ((inst2 & 0x0fc0) == 0x0000) {
++				const int shift = BITS(inst2, 4, 5);
++				const enum arm_register rm = BITS(inst2, 0, 3);
++				uint32_t v;
++				if (arm_get_register(proc, rm, &v) < 0)
++					return -1;
++				base += v << shift;
++			} else {
++				/* Reserved.  */
++				load_pc = 0;
++			}
++
++			if (load_pc) {
++				/* xxx double casts */
++				uint32_t next;
++				if (proc_read_32(proc,
++						 (arch_addr_t)base, &next) < 0)
++					return -1;
++				next_pcs[nr++] = (arch_addr_t)next;
++			}
++		} else if ((inst1 & 0xfff0) == 0xe8d0
++			   && (inst2 & 0xfff0) == 0xf000) {
++			/* TBB.  */
++			const enum arm_register tbl_reg = BITS(inst1, 0, 3);
++			const enum arm_register off_reg = BITS(inst2, 0, 3);
++
++			uint32_t table;
++			if (tbl_reg == ARM_REG_PC)
++				/* Regcache copy of PC isn't right yet.  */
++				/* XXX double cast */
++				table = (uint32_t)pc + 4;
++			else if (arm_get_register(proc, tbl_reg, &table) < 0)
++				return -1;
++
++			uint32_t offset;
++			if (arm_get_register(proc, off_reg, &offset) < 0)
++				return -1;
++
++			table += offset;
++			uint8_t length;
++			/* XXX double cast */
++			if (proc_read_8(proc, (arch_addr_t)table, &length) < 0)
++				return -1;
++
++			next_pcs[nr++] = pc + 2 * length;
++
++		} else if ((inst1 & 0xfff0) == 0xe8d0
++			   && (inst2 & 0xfff0) == 0xf010) {
++			/* TBH.  */
++			const enum arm_register tbl_reg = BITS(inst1, 0, 3);
++			const enum arm_register off_reg = BITS(inst2, 0, 3);
++
++			uint32_t table;
++			if (tbl_reg == ARM_REG_PC)
++				/* Regcache copy of PC isn't right yet.  */
++				/* XXX double cast */
++				table = (uint32_t)pc + 4;
++			else if (arm_get_register(proc, tbl_reg, &table) < 0)
++				return -1;
++
++			uint32_t offset;
++			if (arm_get_register(proc, off_reg, &offset) < 0)
++				return -1;
++
++			table += 2 * offset;
++			uint16_t length;
++			/* XXX double cast */
++			if (proc_read_16(proc, (arch_addr_t)table, &length) < 0)
++				return -1;
++
++			next_pcs[nr++] = pc + 2 * length;
++		}
++	}
++
++
++	/* Otherwise take the next instruction.  */
++	if (nr == 0)
++		next_pcs[nr++] = pc + thumb_insn_size(inst1);
++	return 0;
++}
++
++enum sw_singlestep_status
++arch_sw_singlestep(struct process *proc, struct breakpoint *sbp,
++		   int (*add_cb)(arch_addr_t, struct sw_singlestep_data *),
++		   struct sw_singlestep_data *add_cb_data)
++{
++	const arch_addr_t pc = get_instruction_pointer(proc);
++
++	uint32_t cpsr;
++	if (arm_get_register(proc, ARM_REG_CPSR, &cpsr) < 0)
++		return SWS_FAIL;
++
++	const unsigned thumb_p = BIT(cpsr, 5);
++	arch_addr_t next_pcs[2] = {};
++	if ((thumb_p ? &thumb_get_next_pcs
++	     : &arm_get_next_pcs)(proc, pc, next_pcs) < 0)
++		return SWS_FAIL;
++
++	int i;
++	for (i = 0; i < 2; ++i) {
++		/* XXX double cast.  */
++		arch_addr_t target
++			= (arch_addr_t)(((uintptr_t)next_pcs[i]) | thumb_p);
++		if (next_pcs[i] != 0 && add_cb(target, add_cb_data) < 0)
++			return SWS_FAIL;
++	}
++
++	debug(1, "PTRACE_CONT");
++	ptrace(PTRACE_CONT, proc->pid, 0, 0);
++	return SWS_OK;
++}
+diff --git a/sysdeps/linux-gnu/ia64/regs.c b/sysdeps/linux-gnu/ia64/regs.c
+index fb79e8a..67873ce 100644
+--- a/sysdeps/linux-gnu/ia64/regs.c
++++ b/sysdeps/linux-gnu/ia64/regs.c
+@@ -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) 2008,2009 Juan Cespedes
+  * Copyright (C) 2006 Ian Wienand
+  *
+@@ -77,9 +77,3 @@ get_return_addr(struct process *proc, void *stack_pointer)
+ 		return NULL;
+ 	return (void *)l;
+ }
+-
+-void
+-set_return_addr(struct process *proc, void *addr)
+-{
+-	ptrace(PTRACE_POKEUSER, proc->pid, PT_B0, addr);
+-}
+diff --git a/sysdeps/linux-gnu/m68k/regs.c b/sysdeps/linux-gnu/m68k/regs.c
+index c2fafe1..e25aefb 100644
+--- a/sysdeps/linux-gnu/m68k/regs.c
++++ b/sysdeps/linux-gnu/m68k/regs.c
+@@ -1,5 +1,6 @@
+ /*
+  * This file is part of ltrace.
++ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
+  * Copyright (C) 1998,2002,2004,2008,2009 Juan Cespedes
+  *
+  * This program is free software; you can redistribute it and/or
+@@ -58,9 +59,3 @@ get_return_addr(struct process *proc, void *stack_pointer)
+ {
+ 	return (void *)ptrace(PTRACE_PEEKTEXT, proc->pid, stack_pointer, 0);
+ }
+-
+-void
+-set_return_addr(struct process *proc, void *addr)
+-{
+-	ptrace(PTRACE_POKETEXT, proc->pid, proc->stack_pointer, addr);
+-}
+diff --git a/sysdeps/linux-gnu/mipsel/regs.c b/sysdeps/linux-gnu/mipsel/regs.c
+index 19f97cb..d6a7a50 100644
+--- a/sysdeps/linux-gnu/mipsel/regs.c
++++ b/sysdeps/linux-gnu/mipsel/regs.c
+@@ -1,5 +1,6 @@
+ /*
+  * This file is part of ltrace.
++ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2008,2009 Juan Cespedes
+  * Copyright (C) 2006 Eric Vaitl, Cisco Systems, Inc.
+  *
+@@ -94,9 +95,3 @@ get_return_addr(struct process *proc, void *stack_pointer)
+ {
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_lr, 0);
+ }
+-
+-void
+-set_return_addr(struct process *proc, void *addr)
+-{
+-	ptrace(PTRACE_POKEUSER, proc->pid, off_lr, addr);
+-}
+diff --git a/sysdeps/linux-gnu/ppc/regs.c b/sysdeps/linux-gnu/ppc/regs.c
+index ed9b398..40d7e7a 100644
+--- a/sysdeps/linux-gnu/ppc/regs.c
++++ b/sysdeps/linux-gnu/ppc/regs.c
+@@ -1,5 +1,6 @@
+ /*
+  * This file is part of ltrace.
++ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2002,2008,2009 Juan Cespedes
+  * Copyright (C) 2009 Juan Cespedes
+  * Copyright (C) 2008 Luis Machado, IBM Corporation
+@@ -63,9 +64,3 @@ get_return_addr(struct process *proc, void *stack_pointer)
+ {
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*PT_LNK, 0);
+ }
+-
+-void
+-set_return_addr(struct process *proc, void *addr)
+-{
+-	ptrace(PTRACE_POKEUSER, proc->pid, sizeof(long)*PT_LNK, addr);
+-}
+diff --git a/sysdeps/linux-gnu/s390/regs.c b/sysdeps/linux-gnu/s390/regs.c
+index 44e8f67..bb16c61 100644
+--- a/sysdeps/linux-gnu/s390/regs.c
++++ b/sysdeps/linux-gnu/s390/regs.c
+@@ -1,5 +1,6 @@
+ /*
+  * This file is part of ltrace.
++ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2002,2004,2008,2009 Juan Cespedes
+  * Copyright (C) 2009 Juan Cespedes
+  * Copyright (C) 2006 Ian Wienand
+@@ -87,13 +88,3 @@ get_return_addr(struct process *proc, void *stack_pointer)
+ #endif
+ 	return (void *)ret;
+ }
+-
+-void
+-set_return_addr(struct process *proc, void *addr)
+-{
+-#ifdef __s390x__
+-	if (proc->mask_32bit)
+-		addr = (void *)((long)addr & PSW_MASK31);
+-#endif
+-	ptrace(PTRACE_POKEUSER, proc->pid, PT_GPR14, addr);
+-}
+diff --git a/sysdeps/linux-gnu/sparc/regs.c b/sysdeps/linux-gnu/sparc/regs.c
+index 8431c9b..c474c83 100644
+--- a/sysdeps/linux-gnu/sparc/regs.c
++++ b/sysdeps/linux-gnu/sparc/regs.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
+  * Copyright (C) 2006 Ian Wienand
+  *
+@@ -65,12 +66,3 @@ get_return_addr(struct process *proc, void *stack_pointer)
+ 		return (void *)a->regs.u_regs[UREG_I6] + 12;
+ 	return (void *)a->regs.u_regs[UREG_I6] + 8;
+ }
+-
+-void
+-set_return_addr(struct process *proc, void *addr)
+-{
+-	proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
+-	if (!a->valid)
+-		return;
+-	ptrace(PTRACE_POKETEXT, proc->pid, a->regs.u_regs[UREG_I6] + 8, addr);
+-}
+diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
+index e57a5ed..3aea082 100644
+--- a/sysdeps/linux-gnu/trace.c
++++ b/sysdeps/linux-gnu/trace.c
+@@ -561,12 +561,12 @@ remove_sw_breakpoints(struct process *proc)
+ 	assert(self != NULL);
+ 	assert(self->super.on_event == process_stopping_on_event);
+ 
+-	int ct = sizeof(self->sws_bp_addrs) / sizeof(*self->sws_bp_addrs);
++	int ct = sizeof(self->sws_bps) / sizeof(*self->sws_bps);
+ 	int i;
+ 	for (i = 0; i < ct; ++i)
+-		if (self->sws_bp_addrs[i] != 0) {
+-			delete_breakpoint(proc, self->sws_bp_addrs[i]);
+-			self->sws_bp_addrs[i] = 0;
++		if (self->sws_bps[i] != NULL) {
++			delete_breakpoint(proc, self->sws_bps[i]->addr);
++			self->sws_bps[i] = NULL;
+ 		}
+ }
+ 
+@@ -586,18 +586,17 @@ sw_singlestep_add_bp(arch_addr_t addr, struct sw_singlestep_data *data)
+ 	struct process_stopping_handler *self = data->self;
+ 	struct process *proc = self->task_enabling_breakpoint;
+ 
+-	int ct = sizeof(self->sws_bp_addrs)
+-		/ sizeof(*self->sws_bp_addrs);
++	int ct = sizeof(self->sws_bps) / sizeof(*self->sws_bps);
+ 	int i;
+ 	for (i = 0; i < ct; ++i)
+-		if (self->sws_bp_addrs[i] == 0) {
+-			self->sws_bp_addrs[i] = addr;
++		if (self->sws_bps[i] == NULL) {
+ 			static struct bp_callbacks cbs = {
+ 				.on_hit = sw_singlestep_bp_on_hit,
+ 			};
+ 			struct breakpoint *bp
+ 				= insert_breakpoint(proc, addr, NULL);
+ 			breakpoint_set_callbacks(bp, &cbs);
++			self->sws_bps[i] = bp;
+ 			return 0;
+ 		}
+ 
+@@ -608,7 +607,9 @@ sw_singlestep_add_bp(arch_addr_t addr, struct sw_singlestep_data *data)
+ static int
+ singlestep(struct process_stopping_handler *self)
+ {
+-	struct process *proc = self->task_enabling_breakpoint;
++	size_t i;
++	for (i = 0; i < sizeof(self->sws_bps) / sizeof(*self->sws_bps); ++i)
++		self->sws_bps[i] = NULL;
+ 
+ 	struct sw_singlestep_data data = { self };
+ 	switch (arch_sw_singlestep(self->task_enabling_breakpoint,
+@@ -617,7 +618,8 @@ singlestep(struct process_stopping_handler *self)
+ 	case SWS_HW:
+ 		/* Otherwise do the default action: singlestep.  */
+ 		debug(1, "PTRACE_SINGLESTEP");
+-		if (ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0)) {
++		if (ptrace(PTRACE_SINGLESTEP,
++			   self->task_enabling_breakpoint->pid, 0, 0)) {
+ 			perror("PTRACE_SINGLESTEP");
+ 			return -1;
+ 		}
+@@ -1038,7 +1040,7 @@ ltrace_exiting_install_handler(struct process *proc)
+ struct process_vfork_handler
+ {
+ 	struct event_handler super;
+-	void *bp_addr;
++	int vfork_bp_refd:1;
+ };
+ 
+ static Event *
+@@ -1049,38 +1051,33 @@ process_vfork_on_event(struct event_handler *super, Event *event)
+ 	      event->proc->pid, event->type);
+ 
+ 	struct process_vfork_handler *self = (void *)super;
+-	struct breakpoint *sbp;
++	struct process *proc = event->proc;
+ 	assert(self != NULL);
+ 
+ 	switch (event->type) {
+ 	case EVENT_BREAKPOINT:
+-		/* Remember the vfork return breakpoint.  */
+-		if (self->bp_addr == 0)
+-			self->bp_addr = event->e_un.brk_addr;
++		/* We turn on the vfork return breakpoint (which
++		 * should be the one that we have tripped over just
++		 * now) one extra time, so that the vfork parent hits
++		 * it as well.  */
++		if (!self->vfork_bp_refd) {
++			struct breakpoint *const sbp =
++				dict_find_entry(proc->leader->breakpoints,
++						event->e_un.brk_addr);
++			assert(sbp != NULL);
++			breakpoint_turn_on(sbp, proc->leader);
++			self->vfork_bp_refd = 1;
++		}
+ 		break;
+ 
+ 	case EVENT_EXIT:
+ 	case EVENT_EXIT_SIGNAL:
+ 	case EVENT_EXEC:
+-		/* Smuggle back in the vfork return breakpoint, so
+-		 * that our parent can trip over it once again.  */
+-		if (self->bp_addr != 0) {
+-			sbp = dict_find_entry(event->proc->leader->breakpoints,
+-					      self->bp_addr);
+-			if (sbp != NULL)
+-				assert(sbp->libsym == NULL);
+-			/* We don't mind failing that, it's not a big
+-			 * deal to not display one extra vfork return.  */
+-			insert_breakpoint(event->proc->parent,
+-					  self->bp_addr, NULL);
+-		}
+-
+-		continue_process(event->proc->parent->pid);
+-
+ 		/* Remove the leader that we artificially set up
+ 		 * earlier.  */
+-		change_process_leader(event->proc, event->proc);
+-		destroy_event_handler(event->proc);
++		change_process_leader(proc, proc);
++		destroy_event_handler(proc);
++		continue_process(proc->parent->pid);
+ 
+ 	default:
+ 		;
+diff --git a/sysdeps/linux-gnu/trace.h b/sysdeps/linux-gnu/trace.h
+index e988f70..5bb8380 100644
+--- a/sysdeps/linux-gnu/trace.h
++++ b/sysdeps/linux-gnu/trace.h
+@@ -64,8 +64,8 @@ struct process_stopping_handler
+ 	/* The pointer being re-enabled.  */
+ 	struct breakpoint *breakpoint_being_enabled;
+ 
+-	/* Artificial atomic skip breakpoint, if any needed.  */
+-	arch_addr_t sws_bp_addrs[2];
++	/* Software singlestep breakpoints, if any needed.  */
++	struct breakpoint *sws_bps[2];
+ 
+ 	/* When all tasks are stopped, this callback gets called.  */
+ 	void (*on_all_stopped)(struct process_stopping_handler *);
+diff --git a/sysdeps/linux-gnu/x86/regs.c b/sysdeps/linux-gnu/x86/regs.c
+index 3886e84..0a42c6e 100644
+--- a/sysdeps/linux-gnu/x86/regs.c
++++ b/sysdeps/linux-gnu/x86/regs.c
+@@ -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) 1998,2002,2004,2008,2009 Juan Cespedes
+  * Copyright (C) 2006 Ian Wienand
+  *
+@@ -107,11 +107,3 @@ get_return_addr(struct process *proc, void *sp)
+ 		ret = conv_32(ret);
+ 	return ret;
+ }
+-
+-void
+-set_return_addr(struct process *proc, void *addr)
+-{
+-	if (proc->e_machine == EM_386)
+-		addr = (void *)((long int)addr & 0xffffffff);
+-	ptrace(PTRACE_POKETEXT, proc->pid, proc->stack_pointer, addr);
+-}
+diff --git a/testsuite/ltrace.torture/Makefile.am b/testsuite/ltrace.torture/Makefile.am
+index daa772f..5a45265 100644
+--- a/testsuite/ltrace.torture/Makefile.am
++++ b/testsuite/ltrace.torture/Makefile.am
+@@ -15,15 +15,9 @@
+ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ #
+ 
+-EXTRA_DIST = \
+-	ia64-sigill.exp \
+-	ia64-sigill.s \
+-	ppc-lwarx.c \
+-	ppc-lwarx.exp \
+-	signals.c \
+-	signals.exp \
+-	vfork-thread.c \
+-	vfork-thread.exp
++EXTRA_DIST = arm-singlestep.exp ia64-sigill.exp ia64-sigill.s	\
++	 ppc-lwarx.c ppc-lwarx.exp signals.c signals.exp	\
++	 vfork-thread.c vfork-thread.exp
+ 
+ CLEANFILES = *.o *.so *.log *.sum *.ltrace setval.tmp \
+ 	signals
+diff --git a/testsuite/ltrace.torture/arm-singlestep.exp b/testsuite/ltrace.torture/arm-singlestep.exp
+new file mode 100644
+index 0000000..0d633d9
+--- /dev/null
++++ b/testsuite/ltrace.torture/arm-singlestep.exp
+@@ -0,0 +1,44 @@
++# 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
++
++if {![istarget arm*-*]} {
++    unsupported "arm-specific test"
++    return
++}
++
++set exe [ltraceCompile {} [ltraceSource c {
++    int puc(void) { return 0; }
++
++    int bar(void);
++    int baz(void);
++    __asm__ ("	.type   bar, %function\n"
++	     "bar:		\n"
++	     "	b puc	\n"
++	     "	.type   baz, %function\n"
++	     "baz:		\n"
++	     "	b puc	\n");
++
++    int main(void) { return bar() + baz(); }
++}]]
++
++ltraceMatch [ltraceRun -L -xbar+baz $exe] {
++    {{bar} == 1}
++    {{baz} == 1}
++}
++
++ltraceDone
diff --git a/ltrace-0.7.2-bits.patch b/ltrace-0.7.2-bits.patch
new file mode 100644
index 0000000..490defd
--- /dev/null
+++ b/ltrace-0.7.2-bits.patch
@@ -0,0 +1,6472 @@
+diff --git a/Makefile.am b/Makefile.am
+index 6e46949..c3356de 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -60,7 +60,8 @@ libltrace_la_SOURCES = \
+ 	zero.c \
+ 	lens.c \
+ 	lens_default.c \
+-	lens_enum.c
++	lens_enum.c \
++	memstream.c
+ 
+ libltrace_la_LIBADD = \
+ 	$(libelf_LIBS) \
+@@ -112,7 +113,8 @@ noinst_HEADERS = \
+ 	zero.h \
+ 	lens.h \
+ 	lens_default.h \
+-	lens_enum.h
++	lens_enum.h \
++	memstream.h
+ 
+ dist_man1_MANS = ltrace.1
+ dist_man5_MANS = ltrace.conf.5
+diff --git a/backend.h b/backend.h
+index 89c05c3..cfac65e 100644
+--- a/backend.h
++++ b/backend.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.
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License as
+@@ -27,12 +27,12 @@
+ #include <gelf.h>
+ 
+ enum process_status {
+-	ps_invalid,	/* Failure.  */
+-	ps_stop,	/* Job-control stop.  */
+-	ps_tracing_stop,
+-	ps_sleeping,
+-	ps_zombie,
+-	ps_other,	/* Necessary other states can be added as needed.  */
++	PS_INVALID,	/* Failure.  */
++	PS_STOP,	/* Job-control stop.  */
++	PS_TRACING_STOP,
++	PS_SLEEPING,
++	PS_ZOMBIE,
++	PS_OTHER,	/* Necessary other states can be added as needed.  */
+ };
+ 
+ /*
+@@ -70,7 +70,7 @@ int wait_for_proc(pid_t pid);
+ int task_kill(pid_t pid, int sig);
+ 
+ /* Called after PID is attached, but before it is continued.  */
+-void trace_set_options(struct Process *proc);
++void trace_set_options(struct process *proc);
+ 
+ /* Called after ltrace forks.  Should attach the newly created child,
+  * in whose context this function is called.  */
+@@ -86,7 +86,7 @@ void untrace_pid(pid_t pid);
+ /* The back end may need to store arbitrary data to a process.  This
+  * is a place where it can initialize PROC->arch_dep.  XXX this should
+  * be dropped in favor of arhc_process_init on pmachata/libs.  */
+-void get_arch_dep(struct Process *proc);
++void get_arch_dep(struct process *proc);
+ 
+ /* Return current instruction pointer of PROC.
+  *
+@@ -95,34 +95,34 @@ void get_arch_dep(struct Process *proc);
+  * that would otherwise support this.  Above we have a definition of
+  * arch_addr_t.  This should be converted to an integral type and
+  * used for target addresses throughout.  */
+-void *get_instruction_pointer(struct Process *proc);
++void *get_instruction_pointer(struct process *proc);
+ 
+ /* Set instruction pointer of PROC to ADDR.  XXX see above.  */
+-void set_instruction_pointer(struct Process *proc, void *addr);
++void set_instruction_pointer(struct process *proc, void *addr);
+ 
+ /* Return current stack pointer of PROC.  XXX see above.  */
+-void *get_stack_pointer(struct Process *proc);
++void *get_stack_pointer(struct process *proc);
+ 
+ /* Find and return caller address, i.e. the address where the current
+  * function returns.  */
+-void *get_return_addr(struct Process *proc, void *stack_pointer);
++void *get_return_addr(struct process *proc, void *stack_pointer);
+ 
+ /* Adjust PROC so that when the current function returns, it returns
+  * to ADDR.  */
+-void set_return_addr(struct Process *proc, void *addr);
++void set_return_addr(struct process *proc, void *addr);
+ 
+ /* Enable breakpoint SBP in process PROC.  */
+-void enable_breakpoint(struct Process *proc, struct breakpoint *sbp);
++void enable_breakpoint(struct process *proc, struct breakpoint *sbp);
+ 
+ /* Disable breakpoint SBP in process PROC.  */
+-void disable_breakpoint(struct Process *proc, struct breakpoint *sbp);
++void disable_breakpoint(struct process *proc, struct breakpoint *sbp);
+ 
+ /* Determine whether the event that we have just seen (and that is
+  * recorded in STATUS) was a syscall.  If it was, return 1.  If it was
+  * a return from syscall, return 2.  In both cases, set *SYSNUM to the
+  * number of said syscall.  If it wasn't a syscall, return 0.  If
+  * there was an error, return -1.  */
+-int syscall_p(struct Process *proc, int status, int *sysnum);
++int syscall_p(struct process *proc, int status, int *sysnum);
+ 
+ /* Continue execution of the process with given PID.  */
+ void continue_process(pid_t pid);
+@@ -136,17 +136,21 @@ void continue_after_signal(pid_t pid, int signum);
+  * is system call, otherwise it's return from a system call.  The
+  * callback should do whatever book-keeping is necessary and continue
+  * the process if necessary.  */
+-void continue_after_syscall(struct Process *proc, int sysnum, int ret_p);
++void continue_after_syscall(struct process *proc, int sysnum, int ret_p);
+ 
+ /* Called after we hit a breakpoint SBP.  Should do whatever
+  * book-keeping is necessary and then continue the process.  */
+-void continue_after_breakpoint(struct Process *proc, struct breakpoint *sbp);
++void continue_after_breakpoint(struct process *proc, struct breakpoint *sbp);
+ 
+ /* Called after we received a vfork.  Should do whatever book-keeping
+  * is necessary and continue the process if necessary.  N.B. right
+  * now, with Linux/GNU the only back end, this is not necessary.  I
+  * imagine other systems may be different.  */
+-void continue_after_vfork(struct Process *proc);
++void continue_after_vfork(struct process *proc);
++
++/* Called after the process exec's.  Should do whatever book-keeping
++ * is necessary and then continue the process.  */
++void continue_after_exec(struct process *proc);
+ 
+ /* Called when trace_me or primary trace_pid fail.  This may plug in
+  * any platform-specific knowledge of why it could be so.  */
+@@ -171,14 +175,14 @@ void os_ltrace_exiting(void);
+ 
+ /* Should copy COUNT bytes from address ADDR of process PROC to local
+  * buffer BUF.  */
+-size_t umovebytes (struct Process *proc, void *addr, void *buf, size_t count);
++size_t umovebytes(struct process *proc, void *addr, void *buf, size_t count);
+ 
+ /* Find out an address of symbol SYM in process PROC, and return.
+  * Returning NULL delays breakpoint insertion and enables heaps of
+  * arch-specific black magic that we should clean up some day.
+  *
+  * XXX the same points as for get_instruction_pointer apply. */
+-void *sym2addr(struct Process *proc, struct library_symbol *sym);
++void *sym2addr(struct process *proc, struct library_symbol *sym);
+ 
+ /* Obtain address of PLT entry corresponding to relocation RELA in
+  * file LTE.  This is NDX-th PLT entry in the file.
+@@ -189,7 +193,7 @@ GElf_Addr arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela);
+ /* Called at some point after we have attached to PROC.  This callback
+  * should insert an introspection breakpoint for handling dynamic
+  * linker library loads.  */
+-int linkmap_init(struct Process *proc, arch_addr_t dyn_addr);
++int linkmap_init(struct process *proc, arch_addr_t dyn_addr);
+ 
+ /* This should produce and return the next event of one of the traced
+  * processes.  The returned pointer will not be freed by the core and
+@@ -198,14 +202,14 @@ int linkmap_init(struct Process *proc, arch_addr_t dyn_addr);
+ struct Event *next_event(void);
+ 
+ /* Called when process PROC was removed.  */
+-void process_removed(struct Process *proc);
++void process_removed(struct process *proc);
+ 
+ /* This should extract entry point address and interpreter (dynamic
+  * linker) bias if possible.  Returns 0 if there were no errors, -1
+  * otherwise.  Sets *ENTRYP and *INTERP_BIASP to non-zero values if
+  * the corresponding value is known, or zero otherwise; this is not
+  * done for pointers that are NULL.  */
+-int process_get_entry(struct Process *proc,
++int process_get_entry(struct process *proc,
+ 		      arch_addr_t *entryp,
+ 		      arch_addr_t *interp_biasp);
+ 
+@@ -232,7 +236,7 @@ void arch_elf_destroy(struct ltelf *lte);
+  * destroy, and clone SBP->arch.  arch_breakpoint_init and
+  * arch_breakpoint_clone return 0 on success or a negative value on
+  * failure.  */
+-int arch_breakpoint_init(struct Process *proc, struct breakpoint *sbp);
++int arch_breakpoint_init(struct process *proc, struct breakpoint *sbp);
+ void arch_breakpoint_destroy(struct breakpoint *sbp);
+ int arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp);
+ 
+@@ -259,19 +263,19 @@ int arch_library_symbol_clone(struct library_symbol *retp,
+  * PROC->arch in case that PROC underwent an exec.  See notes at
+  * process_init, process_destroy, process_clone and process_exec in
+  * proc.h.  */
+-int arch_process_init(struct Process *proc);
+-void arch_process_destroy(struct Process *proc);
+-int arch_process_clone(struct Process *retp, struct Process *proc);
+-int arch_process_exec(struct Process *proc);
++int arch_process_init(struct process *proc);
++void arch_process_destroy(struct process *proc);
++int arch_process_clone(struct process *retp, struct process *proc);
++int arch_process_exec(struct process *proc);
+ 
+ /* The following callbacks have to be implemented in OS backend if
+  * os.h defines OS_HAVE_PROCESS_DATA.  The protocol is same as for,
+  * respectively, arch_process_init, arch_process_destroy,
+  * arch_process_clone and arch_process_exec.  */
+-int os_process_init(struct Process *proc);
+-void os_process_destroy(struct Process *proc);
+-int os_process_clone(struct Process *retp, struct Process *proc);
+-int os_process_exec(struct Process *proc);
++int os_process_init(struct process *proc);
++void os_process_destroy(struct process *proc);
++int os_process_clone(struct process *retp, struct process *proc);
++int os_process_exec(struct process *proc);
+ 
+ /* The following callback has to be implemented in backend if arch.h
+  * defines ARCH_HAVE_GET_SYM_INFO.
+@@ -289,9 +293,9 @@ int arch_get_sym_info(struct ltelf *lte, const char *filename,
+ 		      size_t sym_index, GElf_Rela *rela, GElf_Sym *sym);
+ 
+ enum plt_status {
+-	plt_fail,
+-	plt_ok,
+-	plt_default,
++	PLT_FAIL,
++	PLT_OK,
++	PLT_DEFAULT,
+ };
+ 
+ /* The following callback has to be implemented in backend if arch.h
+@@ -302,22 +306,22 @@ enum plt_status {
+  * The corresponding PLT entry is for symbol called NAME, and it's
+  * I-th relocation in the file.
+  *
+- * If this function returns plt_default, PLT address is obtained by
+- * calling arch_plt_sym_val, and symbol is allocated.  If plt_ok or
+- * plt_default are returned, the chain of symbols passed back in RET
++ * If this function returns PLT_DEFAULT, PLT address is obtained by
++ * calling arch_plt_sym_val, and symbol is allocated.  If PLT_OK or
++ * PLT_DEFAULT are returned, the chain of symbols passed back in RET
+  * is added to library under construction.  */
+-enum plt_status arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
++enum plt_status arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
+ 				       const char *name, GElf_Rela *rela,
+ 				       size_t i, struct library_symbol **ret);
+ 
+ /* This callback needs to be implemented if arch.h defines
+  * ARCH_HAVE_DYNLINK_DONE.  It is called after the dynamic linker is
+  * done with the process startup.  */
+-void arch_dynlink_done(struct Process *proc);
++void arch_dynlink_done(struct process *proc);
+ 
+ /* This callback needs to be implemented if arch.h defines
+  * ARCH_HAVE_SYMBOL_RET.  It is called after a traced call returns.  */
+-void arch_symbol_ret(struct Process *proc, struct library_symbol *libsym);
++void arch_symbol_ret(struct process *proc, struct library_symbol *libsym);
+ 
+ 
+ /* This callback needs to be implemented if arch.h defines
+@@ -327,7 +331,7 @@ void arch_symbol_ret(struct Process *proc, struct library_symbol *libsym);
+  * DYN_ADDR holds the address of the dynamic section.
+  * If the debug area is found, return 0 and fill in the address in *RET.
+  * If the debug area is not found, return a negative value.  */
+-int arch_find_dl_debug(struct Process *proc, arch_addr_t dyn_addr,
++int arch_find_dl_debug(struct process *proc, arch_addr_t dyn_addr,
+ 		       arch_addr_t *ret);
+ 
+ /* If arch.h defines ARCH_HAVE_FETCH_ARG, the following callbacks have
+@@ -340,4 +344,34 @@ int arch_find_dl_debug(struct Process *proc, arch_addr_t dyn_addr,
+  * implemented: arch_fetch_param_pack_start,
+  * arch_fetch_param_pack_end.  See fetch.h for details.  */
+ 
++enum sw_singlestep_status {
++	SWS_FAIL,
++	SWS_OK,
++	SWS_HW,
++};
++struct sw_singlestep_data;
++
++/* The following callback has to be implemented in backend if arch.h
++ * defines ARCH_HAVE_SW_SINGLESTEP.
++ *
++ * This is called before the OS backend requests hardware singlestep.
++ * arch_sw_singlestep should consider whether a singlestep needs to be
++ * done in software.  If not, it returns SWS_HW.  Otherwise it needs
++ * to add one or several breakpoints by calling ADD_CB.  When it is
++ * done, it continues the process as appropriate, and answers either
++ * SWS_OK, or SWS_FAIL, depending on how it went.
++ *
++ * PROC is the process that should perform the singlestep, BP the
++ * breakpoint that we are singlestepping over.  ADD_CB is a callback
++ * to request adding breakpoints that should trap the process after
++ * it's continued.  The arguments to ADD_CB are the address where the
++ * breakpoint should be added, and DATA.  ADD_CB returns 0 on success
++ * or a negative value on failure.  It is expected that
++ * arch_sw_singlestep returns SWS_FAIL if ADD_CB returns error.  */
++enum sw_singlestep_status arch_sw_singlestep(struct process *proc,
++					     struct breakpoint *bp,
++					     int (*add_cb)(arch_addr_t addr,
++						   struct sw_singlestep_data *),
++					     struct sw_singlestep_data *data);
++
+ #endif /* BACKEND_H */
+diff --git a/breakpoint.h b/breakpoint.h
+index 7cd914e..18af7a9 100644
+--- a/breakpoint.h
++++ b/breakpoint.h
+@@ -41,14 +41,12 @@
+ 
+ #include "sysdep.h"
+ #include "library.h"
+-
+-struct Process;
+-struct breakpoint;
++#include "forward.h"
+ 
+ struct bp_callbacks {
+-	void (*on_hit)(struct breakpoint *bp, struct Process *proc);
+-	void (*on_continue)(struct breakpoint *bp, struct Process *proc);
+-	void (*on_retract)(struct breakpoint *bp, struct Process *proc);
++	void (*on_hit)(struct breakpoint *bp, struct process *proc);
++	void (*on_continue)(struct breakpoint *bp, struct process *proc);
++	void (*on_retract)(struct breakpoint *bp, struct process *proc);
+ };
+ 
+ struct breakpoint {
+@@ -61,11 +59,11 @@ struct breakpoint {
+ };
+ 
+ /* Call on-hit handler of BP, if any is set.  */
+-void breakpoint_on_hit(struct breakpoint *bp, struct Process *proc);
++void breakpoint_on_hit(struct breakpoint *bp, struct process *proc);
+ 
+ /* Call on-continue handler of BP.  If none is set, call
+  * continue_after_breakpoint.  */
+-void breakpoint_on_continue(struct breakpoint *bp, struct Process *proc);
++void breakpoint_on_continue(struct breakpoint *bp, struct process *proc);
+ 
+ /* Call on-retract handler of BP, if any is set.  This should be
+  * called before the breakpoints are destroyed.  The reason for a
+@@ -74,21 +72,21 @@ void breakpoint_on_continue(struct breakpoint *bp, struct Process *proc);
+  * be called every time we disable the breakpoint, which is too often
+  * (a breakpoint has to be disabled every time that we need to execute
+  * the instruction underneath it).  */
+-void breakpoint_on_retract(struct breakpoint *bp, struct Process *proc);
++void breakpoint_on_retract(struct breakpoint *bp, struct process *proc);
+ 
+ /* Initialize a breakpoint structure.  That doesn't actually realize
+  * the breakpoint.  The breakpoint is initially assumed to be
+  * disabled.  orig_value has to be set separately.  CBS may be
+  * NULL.  */
+-int breakpoint_init(struct breakpoint *bp, struct Process *proc,
++int breakpoint_init(struct breakpoint *bp, struct process *proc,
+ 		    arch_addr_t addr, struct library_symbol *libsym);
+ 
+ /* Make a clone of breakpoint BP into the area of memory pointed to by
+  * RETP.  The original breakpoint was assigned to process OLD_PROC,
+  * the cloned breakpoint will be attached to process NEW_PROC.
+  * Returns 0 on success or a negative value on failure.  */
+-int breakpoint_clone(struct breakpoint *retp, struct Process *new_proc,
+-		     struct breakpoint *bp, struct Process *old_proc);
++int breakpoint_clone(struct breakpoint *retp, struct process *new_proc,
++		     struct breakpoint *bp, struct process *old_proc);
+ 
+ /* Set callbacks.  If CBS is non-NULL, then BP->cbs shall be NULL.  */
+ void breakpoint_set_callbacks(struct breakpoint *bp, struct bp_callbacks *cbs);
+@@ -98,12 +96,12 @@ void breakpoint_destroy(struct breakpoint *bp);
+ 
+ /* Call enable_breakpoint the first time it's called.  Returns 0 on
+  * success and a negative value on failure.  */
+-int breakpoint_turn_on(struct breakpoint *bp, struct Process *proc);
++int breakpoint_turn_on(struct breakpoint *bp, struct process *proc);
+ 
+ /* Call disable_breakpoint when turned off the same number of times
+  * that it was turned on.  Returns 0 on success and a negative value
+  * on failure.  */
+-int breakpoint_turn_off(struct breakpoint *bp, struct Process *proc);
++int breakpoint_turn_off(struct breakpoint *bp, struct process *proc);
+ 
+ /* Utility function that does what typically needs to be done when a
+  * breakpoint is to be inserted.  It checks whether there is another
+@@ -113,7 +111,7 @@ int breakpoint_turn_off(struct breakpoint *bp, struct Process *proc);
+  * added as well as preexisting breakpoints, it then calls
+  * BREAKPOINT_TURN_ON.  If anything fails, it cleans up and returns
+  * NULL.  Otherwise it returns the breakpoint for ADDR.  */
+-struct breakpoint *insert_breakpoint(struct Process *proc, void *addr,
++struct breakpoint *insert_breakpoint(struct process *proc, void *addr,
+ 				     struct library_symbol *libsym);
+ 
+ /* Name of a symbol associated with BP.  May be NULL.  */
+@@ -127,12 +125,12 @@ struct library *breakpoint_library(const struct breakpoint *bp);
+  *  - proc_remove_breakpoint
+  *  - breakpoint_destroy
+  * XXX */
+-void delete_breakpoint(struct Process *proc, void *addr);
++void delete_breakpoint(struct process *proc, void *addr);
+ 
+ /* XXX some of the following belongs to proc.h/proc.c.  */
+-struct breakpoint *address2bpstruct(struct Process *proc, void *addr);
+-void enable_all_breakpoints(struct Process *proc);
+-void disable_all_breakpoints(struct Process *proc);
+-int breakpoints_init(struct Process *proc);
++struct breakpoint *address2bpstruct(struct process *proc, void *addr);
++void enable_all_breakpoints(struct process *proc);
++void disable_all_breakpoints(struct process *proc);
++int breakpoints_init(struct process *proc);
+ 
+ #endif /* BREAKPOINT_H */
+diff --git a/breakpoints.c b/breakpoints.c
+index 258be93..8db4e26 100644
+--- a/breakpoints.c
++++ b/breakpoints.c
+@@ -42,7 +42,7 @@
+ 
+ #ifndef ARCH_HAVE_TRANSLATE_ADDRESS
+ int
+-arch_translate_address_dyn(struct Process *proc,
++arch_translate_address_dyn(struct process *proc,
+ 		       arch_addr_t addr, arch_addr_t *ret)
+ {
+ 	*ret = addr;
+@@ -60,7 +60,7 @@ arch_translate_address(struct ltelf *lte,
+ #endif
+ 
+ void
+-breakpoint_on_hit(struct breakpoint *bp, struct Process *proc)
++breakpoint_on_hit(struct breakpoint *bp, struct process *proc)
+ {
+ 	assert(bp != NULL);
+ 	if (bp->cbs != NULL && bp->cbs->on_hit != NULL)
+@@ -68,7 +68,7 @@ breakpoint_on_hit(struct breakpoint *bp, struct Process *proc)
+ }
+ 
+ void
+-breakpoint_on_continue(struct breakpoint *bp, struct Process *proc)
++breakpoint_on_continue(struct breakpoint *bp, struct process *proc)
+ {
+ 	assert(bp != NULL);
+ 	if (bp->cbs != NULL && bp->cbs->on_continue != NULL)
+@@ -78,7 +78,7 @@ breakpoint_on_continue(struct breakpoint *bp, struct Process *proc)
+ }
+ 
+ void
+-breakpoint_on_retract(struct breakpoint *bp, struct Process *proc)
++breakpoint_on_retract(struct breakpoint *bp, struct process *proc)
+ {
+ 	assert(bp != NULL);
+ 	if (bp->cbs != NULL && bp->cbs->on_retract != NULL)
+@@ -88,7 +88,7 @@ breakpoint_on_retract(struct breakpoint *bp, struct Process *proc)
+ /*****************************************************************************/
+ 
+ struct breakpoint *
+-address2bpstruct(Process *proc, void *addr)
++address2bpstruct(struct process *proc, void *addr)
+ {
+ 	assert(proc != NULL);
+ 	assert(proc->breakpoints != NULL);
+@@ -99,7 +99,7 @@ address2bpstruct(Process *proc, void *addr)
+ 
+ #ifndef ARCH_HAVE_BREAKPOINT_DATA
+ int
+-arch_breakpoint_init(struct Process *proc, struct breakpoint *sbp)
++arch_breakpoint_init(struct process *proc, struct breakpoint *sbp)
+ {
+ 	return 0;
+ }
+@@ -117,7 +117,7 @@ arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp)
+ #endif
+ 
+ static void
+-breakpoint_init_base(struct breakpoint *bp, struct Process *proc,
++breakpoint_init_base(struct breakpoint *bp, struct process *proc,
+ 		     arch_addr_t addr, struct library_symbol *libsym)
+ {
+ 	bp->cbs = NULL;
+@@ -132,7 +132,7 @@ breakpoint_init_base(struct breakpoint *bp, struct Process *proc,
+  * static lookups of various sections in the ELF file.  We shouldn't
+  * need process for anything.  */
+ int
+-breakpoint_init(struct breakpoint *bp, struct Process *proc,
++breakpoint_init(struct breakpoint *bp, struct process *proc,
+ 		arch_addr_t addr, struct library_symbol *libsym)
+ {
+ 	breakpoint_init_base(bp, proc, addr, libsym);
+@@ -156,8 +156,8 @@ breakpoint_destroy(struct breakpoint *bp)
+ }
+ 
+ int
+-breakpoint_clone(struct breakpoint *retp, struct Process *new_proc,
+-		 struct breakpoint *bp, struct Process *old_proc)
++breakpoint_clone(struct breakpoint *retp, struct process *new_proc,
++		 struct breakpoint *bp, struct process *old_proc)
+ {
+ 	struct library_symbol *libsym = NULL;
+ 	if (bp->libsym != NULL) {
+@@ -175,7 +175,7 @@ breakpoint_clone(struct breakpoint *retp, struct Process *new_proc,
+ }
+ 
+ int
+-breakpoint_turn_on(struct breakpoint *bp, struct Process *proc)
++breakpoint_turn_on(struct breakpoint *bp, struct process *proc)
+ {
+ 	bp->enabled++;
+ 	if (bp->enabled == 1) {
+@@ -186,7 +186,7 @@ breakpoint_turn_on(struct breakpoint *bp, struct Process *proc)
+ }
+ 
+ int
+-breakpoint_turn_off(struct breakpoint *bp, struct Process *proc)
++breakpoint_turn_off(struct breakpoint *bp, struct process *proc)
+ {
+ 	bp->enabled--;
+ 	if (bp->enabled == 0)
+@@ -196,10 +196,10 @@ breakpoint_turn_off(struct breakpoint *bp, struct Process *proc)
+ }
+ 
+ struct breakpoint *
+-insert_breakpoint(struct Process *proc, void *addr,
++insert_breakpoint(struct process *proc, void *addr,
+ 		  struct library_symbol *libsym)
+ {
+-	Process *leader = proc->leader;
++	struct process *leader = proc->leader;
+ 
+ 	/* Only the group leader should be getting the breakpoints and
+ 	 * thus have ->breakpoint initialized.  */
+@@ -243,11 +243,11 @@ insert_breakpoint(struct Process *proc, void *addr,
+ }
+ 
+ void
+-delete_breakpoint(Process *proc, void *addr)
++delete_breakpoint(struct process *proc, void *addr)
+ {
+ 	debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr);
+ 
+-	Process * leader = proc->leader;
++	struct process *leader = proc->leader;
+ 	assert(leader != NULL);
+ 
+ 	struct breakpoint *sbp = dict_find_entry(leader->breakpoints, addr);
+@@ -285,13 +285,14 @@ breakpoint_library(const struct breakpoint *bp)
+ static void
+ enable_bp_cb(void *addr, void *sbp, void *proc)
+ {
+-	debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)", ((Process *)proc)->pid);
++	debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)",
++	      ((struct process *)proc)->pid);
+ 	if (((struct breakpoint *)sbp)->enabled)
+ 		enable_breakpoint(proc, sbp);
+ }
+ 
+ void
+-enable_all_breakpoints(Process *proc)
++enable_all_breakpoints(struct process *proc)
+ {
+ 	debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid);
+ 
+@@ -305,13 +306,15 @@ enable_all_breakpoints(Process *proc)
+ static void
+ disable_bp_cb(void *addr, void *sbp, void *proc)
+ {
+-	debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)", ((Process *)proc)->pid);
++	debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)",
++	      ((struct process *)proc)->pid);
+ 	if (((struct breakpoint *)sbp)->enabled)
+ 		disable_breakpoint(proc, sbp);
+ }
+ 
+ void
+-disable_all_breakpoints(Process *proc) {
++disable_all_breakpoints(struct process *proc)
++{
+ 	debug(DEBUG_FUNCTION, "disable_all_breakpoints(pid=%d)", proc->pid);
+ 	assert(proc->leader == proc);
+ 	dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc);
+@@ -330,7 +333,7 @@ struct entry_breakpoint {
+ };
+ 
+ static void
+-entry_breakpoint_on_hit(struct breakpoint *a, struct Process *proc)
++entry_breakpoint_on_hit(struct breakpoint *a, struct process *proc)
+ {
+ 	struct entry_breakpoint *bp = (void *)a;
+ 	if (proc == NULL || proc->leader == NULL)
+@@ -342,7 +345,7 @@ entry_breakpoint_on_hit(struct breakpoint *a, struct Process *proc)
+ }
+ 
+ int
+-entry_breakpoint_init(struct Process *proc,
++entry_breakpoint_init(struct process *proc,
+ 		      struct entry_breakpoint *bp, arch_addr_t addr,
+ 		      struct library *lib)
+ {
+@@ -360,7 +363,7 @@ entry_breakpoint_init(struct Process *proc,
+ }
+ 
+ int
+-breakpoints_init(Process *proc)
++breakpoints_init(struct process *proc)
+ {
+ 	debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid);
+ 
+diff --git a/configure.ac b/configure.ac
+index 20c84f4..47bd87e 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -21,9 +21,9 @@
+ # 02110-1301 USA
+ 
+ # Process this file with autoconf to produce a configure script.
+-AC_PREREQ(2.65)
++AC_PREREQ([2.65])
+ 
+-AC_INIT([ltrace],[0.7.2],[ltrace-devel at lists.alioth.debian.org])
++AC_INIT([ltrace],[0.7.90-git],[ltrace-devel at lists.alioth.debian.org])
+ AC_CONFIG_HEADERS([config.h])
+ AC_CONFIG_SRCDIR(libltrace.c)
+ AC_CONFIG_MACRO_DIR([config/m4])
+@@ -245,23 +246,48 @@ AC_CHECK_SIZEOF([long])
+ 
+ 
+ # Checks for library functions.
+-AC_FUNC_ERROR_AT_LINE
+ AC_FUNC_FORK
+ AC_CHECK_FUNCS([ \
+ 	alarm \
+ 	atexit \
+-	getcwd \
+ 	gettimeofday \
+ 	memset \
+-	mkdir \
+-	rmdir \
+ 	strchr \
+ 	strdup \
+ 	strerror \
++	strsignal \
+ 	strtol \
+ 	strtoul \
+ ])
+ 
++#
++# Define HAVE_OPEN_MEMSTREAM if open_memstream is available.  glibc
++# before 2.10, eglibc and uClibc all need _GNU_SOURCE defined for
++# open_memstream to become visible, so check for that as well.  If
++# unavailable, require that tmpfile be present.  There's no
++# HAVE_TMPFILE, as we plain require that to be present as a fallback.
++#
++AC_CHECK_FUNCS([open_memstream], [],
++	[AC_MSG_CHECKING([for open_memstream with _GNU_SOURCE])
++	 AC_LINK_IFELSE(
++		[AC_LANG_PROGRAM([[#define _GNU_SOURCE 1
++				   #include <stdio.h>]],
++				 [[char *buf; size_t sz;
++				   return open_memstream(&buf, &sz) != 0;]])],
++
++		 [AC_MSG_RESULT([yes])
++		  AC_DEFINE([HAVE_OPEN_MEMSTREAM], [1],
++			[Define if open_memstream exists.])],
++
++		 [AC_MSG_RESULT([no])
++		  AC_CHECK_FUNC([tmpfile], [],
++			[AC_MSG_ERROR(
++			    [Either open_memstream or tmpfile required.])])])])
++
++#
++# Define HAVE_GETOPT_LONG if that is available.
++#
++AC_CHECK_HEADER([getopt.h], [AC_CHECK_FUNCS([getopt_long])])
+ 
+ #
+ # Debugging
+diff --git a/debug.c b/debug.c
+index 1b03189..ce220fe 100644
+--- a/debug.c
++++ b/debug.c
+@@ -1,5 +1,6 @@
+ /*
+  * This file is part of ltrace.
++ * Copyright (C) 2012 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2003,2008,2009 Juan Cespedes
+  * Copyright (C) 2006 Ian Wienand
+  *
+@@ -23,6 +24,7 @@
+ #include <stdarg.h>
+ 
+ #include "common.h"
++#include "backend.h"
+ 
+ void
+ debug_(int level, const char *file, int line, const char *fmt, ...) {
+@@ -40,95 +42,26 @@ debug_(int level, const char *file, int line, const char *fmt, ...) {
+ 	fflush(options.output);
+ }
+ 
+-/*
+- * The following section provides a way to print things, like hex dumps,
+- * with out using buffered output.  This was written by Steve Munroe of IBM.
+- */
+-
+-#include <stdio.h>
+-#include <errno.h>
+-#include <unistd.h>
+-#include <stdlib.h>
+-#include <sys/ptrace.h>
+-
+-static int
+-xwritehexl(long i) {
+-	int rc = 0;
+-	char text[17];
+-	int j;
+-	unsigned long temp = (unsigned long)i;
+-
+-	for (j = 15; j >= 0; j--) {
+-		char c;
+-		c = (char)((temp & 0x0f) + '0');
+-		if (c > '9') {
+-			c = (char)(c + ('a' - '9' - 1));
+-		}
+-		text[j] = c;
+-		temp = temp >> 4;
+-	}
+-
+-	rc = write(1, text, 16);
+-	return rc;
+-}
+-
+-static int
+-xwritec(char c) {
+-	char temp = c;
+-	char *text = &temp;
+-	int rc = 0;
+-	rc = write(1, text, 1);
+-	return rc;
+-}
+-
+-static int
+-xwritecr(void) {
+-	return xwritec('\n');
+-}
+-
+ static int
+-xwritedump(void *ptr, long addr, int len) {
+-	int rc = 0;
+-	long *tprt = (long *)ptr;
+-	int i;
+-
+-	for (i = 0; i < len; i += 8) {
+-		xwritehexl(addr);
+-		xwritec('-');
+-		xwritec('>');
+-		xwritehexl(*tprt++);
+-		xwritecr();
++xwritedump(long *ptr, arch_addr_t addr, size_t count)
++{
++	size_t i;
++	for (i = 0; i < count; ++i) {
++		if (fprintf(stderr, "%p->%0*lx\n",
++			    addr, 2 * (int)sizeof(long), ptr[i]) < 0)
++			return -1;
+ 		addr += sizeof(long);
+ 	}
+ 
+-	return rc;
++	return 0;
+ }
+ 
+ int
+-xinfdump(long pid, void *ptr, int len) {
+-	int rc;
+-	int i;
+-	long wrdcnt;
+-	long *infwords;
+-	long addr;
+-
+-	wrdcnt = len / sizeof(long) + 1;
+-	infwords = malloc(wrdcnt * sizeof(long));
+-	if (!infwords) {
+-		perror("ltrace: malloc");
+-		exit(1);
+-	}
+-	addr = (long)ptr;
+-
+-	addr = ((addr + sizeof(long) - 1) / sizeof(long)) * sizeof(long);
+-
+-	for (i = 0; i < wrdcnt; ++i) {
+-		infwords[i] = ptrace(PTRACE_PEEKTEXT, pid, (void *)addr, NULL);
+-		addr += sizeof(long);
+-	}
+-
+-	rc = xwritedump(infwords, (long)ptr, len);
+-
+-	free(infwords);
+-	return rc;
++xinfdump(struct process *proc, arch_addr_t addr, size_t length)
++{
++	unsigned char buf[length];
++	size_t got = umovebytes(proc, addr, buf, length);
++	if (got == (size_t)-1)
++		return -1;
++	return xwritedump((long *)buf, addr, got / sizeof(long));
+ }
+diff --git a/debug.h b/debug.h
+index 4775d2f..542dda5 100644
+--- a/debug.h
++++ b/debug.h
+@@ -1,5 +1,6 @@
+ /*
+  * This file is part of ltrace.
++ * Copyright (C) 2012 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2003,2009 Juan Cespedes
+  *
+  * This program is free software; you can redistribute it and/or
+@@ -21,6 +22,9 @@
+ #ifndef _DEBUG_H
+ #define _DEBUG_H
+ 
++#include "backend.h"
++#include "forward.h"
++
+ /* debug levels:
+  */
+ enum {
+@@ -32,8 +36,10 @@ enum {
+ void debug_(int level, const char *file, int line,
+ 		const char *fmt, ...) __attribute__((format(printf,4,5)));
+ 
+-int xinfdump(long, void *, int);
++/* Dump LENGTH bytes of memory starting on address ADDR of inferior
++ * PID.  */
++int xinfdump(struct process *proc, arch_addr_t addr, size_t length);
+ 
+-# define debug(level, expr...) debug_(level, __FILE__, __LINE__, expr)
++#define debug(level, expr...) debug_(level, __FILE__, __LINE__, expr)
+ 
+ #endif
+diff --git a/expr.c b/expr.c
+index 32860fd..552a53c 100644
+--- a/expr.c
++++ b/expr.c
+@@ -21,7 +21,6 @@
+ #include <string.h>
+ #include <assert.h>
+ #include <errno.h>
+-#include <error.h>
+ #include <stdlib.h>
+ 
+ #include "expr.h"
+@@ -327,12 +326,11 @@ expr_eval_constant(struct expr_node *node, long *valuep)
+ struct expr_node *
+ expr_self(void)
+ {
+-	static struct expr_node *node = NULL;
+-	if (node == NULL) {
+-		node = malloc(sizeof(*node));
+-		if (node == NULL)
+-			error(1, errno, "malloc expr_self");
+-		expr_init_self(node);
++	static struct expr_node *nodep = NULL;
++	if (nodep == NULL) {
++		static struct expr_node node;
++		expr_init_self(&node);
++		nodep = &node;
+ 	}
+-	return node;
++	return nodep;
+ }
+diff --git a/fetch.c b/fetch.c
+index 88966a5..cbceefb 100644
+--- a/fetch.c
++++ b/fetch.c
+@@ -27,18 +27,18 @@
+ #include "type.h"
+ 
+ #ifdef ARCH_HAVE_FETCH_ARG
+-struct fetch_context *arch_fetch_arg_init(enum tof type, struct Process *proc,
++struct fetch_context *arch_fetch_arg_init(enum tof type, struct process *proc,
+ 					  struct arg_type_info *ret_info);
+ 
+-struct fetch_context *arch_fetch_arg_clone(struct Process *proc,
++struct fetch_context *arch_fetch_arg_clone(struct process *proc,
+ 					   struct fetch_context *context);
+ 
+ int arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
+-			struct Process *proc, struct arg_type_info *info,
++			struct process *proc, struct arg_type_info *info,
+ 			struct value *valuep);
+ 
+ int arch_fetch_retval(struct fetch_context *ctx, enum tof type,
+-		      struct Process *proc, struct arg_type_info *info,
++		      struct process *proc, struct arg_type_info *info,
+ 		      struct value *valuep);
+ 
+ void arch_fetch_arg_done(struct fetch_context *context);
+@@ -53,7 +53,7 @@ void arch_fetch_param_pack_end(struct fetch_context *context);
+ #else
+ /* Fall back to gimme_arg.  */
+ 
+-long gimme_arg(enum tof type, struct Process *proc, int arg_num,
++long gimme_arg(enum tof type, struct process *proc, int arg_num,
+ 	       struct arg_type_info *info);
+ 
+ struct fetch_context {
+@@ -61,14 +61,14 @@ struct fetch_context {
+ };
+ 
+ struct fetch_context *
+-arch_fetch_arg_init(enum tof type, struct Process *proc,
++arch_fetch_arg_init(enum tof type, struct process *proc,
+ 		    struct arg_type_info *ret_info)
+ {
+ 	return calloc(sizeof(struct fetch_context), 1);
+ }
+ 
+ struct fetch_context *
+-arch_fetch_arg_clone(struct Process *proc, struct fetch_context *context)
++arch_fetch_arg_clone(struct process *proc, struct fetch_context *context)
+ {
+ 	struct fetch_context *ret = malloc(sizeof(*ret));
+ 	if (ret == NULL)
+@@ -78,7 +78,7 @@ arch_fetch_arg_clone(struct Process *proc, struct fetch_context *context)
+ 
+ int
+ arch_fetch_arg_next(struct fetch_context *context, enum tof type,
+-		    struct Process *proc,
++		    struct process *proc,
+ 		    struct arg_type_info *info, struct value *valuep)
+ {
+ 	long l = gimme_arg(type, proc, context->argnum++, info);
+@@ -88,7 +88,7 @@ arch_fetch_arg_next(struct fetch_context *context, enum tof type,
+ 
+ int
+ arch_fetch_retval(struct fetch_context *context, enum tof type,
+-		  struct Process *proc,
++		  struct process *proc,
+ 		  struct arg_type_info *info, struct value *valuep)
+ {
+ 	long l = gimme_arg(type, proc, -1, info);
+@@ -118,21 +118,21 @@ arch_fetch_param_pack_end(struct fetch_context *context)
+ #endif
+ 
+ struct fetch_context *
+-fetch_arg_init(enum tof type, struct Process *proc,
++fetch_arg_init(enum tof type, struct process *proc,
+ 	       struct arg_type_info *ret_info)
+ {
+ 	return arch_fetch_arg_init(type, proc, ret_info);
+ }
+ 
+ struct fetch_context *
+-fetch_arg_clone(struct Process *proc, struct fetch_context *context)
++fetch_arg_clone(struct process *proc, struct fetch_context *context)
+ {
+ 	return arch_fetch_arg_clone(proc, context);
+ }
+ 
+ int
+ fetch_arg_next(struct fetch_context *context, enum tof type,
+-	       struct Process *proc,
++	       struct process *proc,
+ 	       struct arg_type_info *info, struct value *valuep)
+ {
+ 	return arch_fetch_arg_next(context, type, proc, info, valuep);
+@@ -140,7 +140,7 @@ fetch_arg_next(struct fetch_context *context, enum tof type,
+ 
+ int
+ fetch_retval(struct fetch_context *context, enum tof type,
+-	     struct Process *proc,
++	     struct process *proc,
+ 	     struct arg_type_info *info, struct value *valuep)
+ {
+ 	return arch_fetch_retval(context, type, proc, info, valuep);
+diff --git a/fetch.h b/fetch.h
+index 2a13214..3a1644a 100644
+--- a/fetch.h
++++ b/fetch.h
+@@ -38,24 +38,24 @@ struct fetch_context;
+ 
+ /* Initialize argument fetching.  Returns NULL on failure.  RET_INFO
+  * is the return type of the function.  */
+-struct fetch_context *fetch_arg_init(enum tof type, struct Process *proc,
++struct fetch_context *fetch_arg_init(enum tof type, struct process *proc,
+ 				     struct arg_type_info *ret_info);
+ 
+ /* Make a clone of context.  */
+-struct fetch_context *fetch_arg_clone(struct Process *proc,
++struct fetch_context *fetch_arg_clone(struct process *proc,
+ 				      struct fetch_context *context);
+ 
+ /* Load next argument.  The function returns 0 on success or a
+  * negative value on failure.  The extracted value is stored in
+  * *VALUEP.  */
+ int fetch_arg_next(struct fetch_context *context, enum tof type,
+-		   struct Process *proc,
++		   struct process *proc,
+ 		   struct arg_type_info *info, struct value *valuep);
+ 
+ /* Load return value.  The function returns 0 on success or a negative
+  * value on failure.  The extracted value is stored in *VALUEP.  */
+ int fetch_retval(struct fetch_context *context, enum tof type,
+-		 struct Process *proc,
++		 struct process *proc,
+ 		 struct arg_type_info *info, struct value *valuep);
+ 
+ /* Destroy fetch context.  CONTEXT shall be the same memory location
+@@ -74,15 +74,15 @@ void fetch_param_pack_end(struct fetch_context *context);
+ /* The following callbacks have to be implemented in backend if arch.h
+  * defines ARCH_HAVE_FETCH_ARG.  These backend callbacks correspond to
+  * above functions.  */
+-struct fetch_context *arch_fetch_arg_init(enum tof type, struct Process *proc,
++struct fetch_context *arch_fetch_arg_init(enum tof type, struct process *proc,
+ 					  struct arg_type_info *ret_info);
+-struct fetch_context *arch_fetch_arg_clone(struct Process *proc,
++struct fetch_context *arch_fetch_arg_clone(struct process *proc,
+ 					   struct fetch_context *context);
+ int arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
+-			struct Process *proc, struct arg_type_info *info,
++			struct process *proc, struct arg_type_info *info,
+ 			struct value *valuep);
+ int arch_fetch_retval(struct fetch_context *ctx, enum tof type,
+-		      struct Process *proc, struct arg_type_info *info,
++		      struct process *proc, struct arg_type_info *info,
+ 		      struct value *valuep);
+ void arch_fetch_arg_done(struct fetch_context *context);
+ 
+diff --git a/forward.h b/forward.h
+index 85a0630..d334339 100644
+--- a/forward.h
++++ b/forward.h
+@@ -21,7 +21,7 @@
+ /* Important types defined in other header files are declared
+    here.  */
+ struct Event;
+-struct Process;
++struct process;
+ struct arg_type_info;
+ struct breakpoint;
+ struct expr_node;
+diff --git a/glob.c b/glob.c
+index 9af633f..b26637f 100644
+--- a/glob.c
++++ b/glob.c
+@@ -180,7 +180,7 @@ glob_to_regex(const char *glob, char **retp)
+ 			goto fail;
+ 	}
+ 	*retp = buf;
+-	return REG_NOERROR;
++	return 0;
+ }
+ 
+ int
+@@ -188,7 +188,7 @@ globcomp(regex_t *preg, const char *glob, int cflags)
+ {
+ 	char *regex = NULL;
+ 	int status = glob_to_regex(glob, &regex);
+-	if (status != REG_NOERROR)
++	if (status != 0)
+ 		return status;
+ 	assert(regex != NULL);
+ 	status = regcomp(preg, regex, cflags);
+diff --git a/handle_event.c b/handle_event.c
+index 42a7a05..9dbb696 100644
+--- a/handle_event.c
++++ b/handle_event.c
+@@ -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) 2010 Arnaud Patard, Mandriva SA
+  * Copyright (C) 1998,2001,2002,2003,2004,2007,2008,2009 Juan Cespedes
+  * Copyright (C) 2008 Luis Machado, IBM Corporation
+@@ -54,20 +54,20 @@ static void handle_exec(Event *event);
+ static void handle_breakpoint(Event *event);
+ static void handle_new(Event *event);
+ 
+-static void callstack_push_syscall(Process *proc, int sysnum);
+-static void callstack_push_symfunc(Process *proc,
++static void callstack_push_syscall(struct process *proc, int sysnum);
++static void callstack_push_symfunc(struct process *proc,
+ 				   struct library_symbol *sym);
+ /* XXX Stack maintenance should be moved to a dedicated module, or to
+  * proc.c, and push/pop should be visible outside this module.  For
+  * now, because we need this in proc.c, this is non-static.  */
+-void callstack_pop(struct Process *proc);
++void callstack_pop(struct process *proc);
+ 
+-static char * shortsignal(Process *proc, int signum);
+-static char * sysname(Process *proc, int sysnum);
+-static char * arch_sysname(Process *proc, int sysnum);
++static char *shortsignal(struct process *proc, int signum);
++static char *sysname(struct process *proc, int sysnum);
++static char *arch_sysname(struct process *proc, int sysnum);
+ 
+ static Event *
+-call_handler(Process * proc, Event * event)
++call_handler(struct process *proc, Event *event)
+ {
+ 	assert(proc != NULL);
+ 
+@@ -256,7 +256,7 @@ handle_clone(Event *event)
+ {
+ 	debug(DEBUG_FUNCTION, "handle_clone(pid=%d)", event->proc->pid);
+ 
+-	struct Process *proc = malloc(sizeof(*proc));
++	struct process *proc = malloc(sizeof(*proc));
+ 	if (proc == NULL) {
+ 	fail:
+ 		free(proc);
+@@ -297,12 +297,11 @@ handle_clone(Event *event)
+ }
+ 
+ static void
+-handle_new(Event * event) {
+-	Process * proc;
+-
++handle_new(Event *event)
++{
+ 	debug(DEBUG_FUNCTION, "handle_new(pid=%d)", event->e_un.newpid);
+ 
+-	proc = pid2proc(event->e_un.newpid);
++	struct process *proc = pid2proc(event->e_un.newpid);
+ 	if (!proc) {
+ 		pending_new_insert(event->e_un.newpid);
+ 	} else {
+@@ -317,7 +316,8 @@ handle_new(Event * event) {
+ }
+ 
+ static char *
+-shortsignal(Process *proc, int signum) {
++shortsignal(struct process *proc, int signum)
++{
+ 	static char *signalent0[] = {
+ #include "signalent.h"
+ 	};
+@@ -341,7 +341,8 @@ shortsignal(Process *proc, int signum) {
+ }
+ 
+ static char *
+-sysname(Process *proc, int sysnum) {
++sysname(struct process *proc, int sysnum)
++{
+ 	static char result[128];
+ 	static char *syscalent0[] = {
+ #include "syscallent.h"
+@@ -369,7 +370,8 @@ sysname(Process *proc, int sysnum) {
+ }
+ 
+ static char *
+-arch_sysname(Process *proc, int sysnum) {
++arch_sysname(struct process *proc, int sysnum)
++{
+ 	static char result[128];
+ 	static char *arch_syscalent[] = {
+ #include "arch_syscallent.h"
+@@ -388,6 +390,10 @@ arch_sysname(Process *proc, int sysnum) {
+ 	}
+ }
+ 
++#ifndef HAVE_STRSIGNAL
++# define strsignal(SIGNUM) "???"
++#endif
++
+ static void
+ handle_signal(Event *event) {
+ 	debug(DEBUG_FUNCTION, "handle_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
+@@ -420,8 +426,8 @@ handle_exit_signal(Event *event) {
+ }
+ 
+ static void
+-output_syscall(struct Process *proc, const char *name, enum tof tof,
+-	       void (*output)(enum tof, struct Process *,
++output_syscall(struct process *proc, const char *name, enum tof tof,
++	       void (*output)(enum tof, struct process *,
+ 			      struct library_symbol *))
+ {
+ 	struct library_symbol syscall;
+@@ -432,13 +438,13 @@ output_syscall(struct Process *proc, const char *name, enum tof tof,
+ }
+ 
+ static void
+-output_syscall_left(struct Process *proc, const char *name)
++output_syscall_left(struct process *proc, const char *name)
+ {
+ 	output_syscall(proc, name, LT_TOF_SYSCALL, &output_left);
+ }
+ 
+ static void
+-output_syscall_right(struct Process *proc, const char *name)
++output_syscall_right(struct process *proc, const char *name)
+ {
+ 	output_syscall(proc, name, LT_TOF_SYSCALLR, &output_right);
+ }
+@@ -457,8 +463,9 @@ handle_syscall(Event *event) {
+ }
+ 
+ static void
+-handle_exec(Event * event) {
+-	Process * proc = event->proc;
++handle_exec(Event *event)
++{
++	struct process *proc = event->proc;
+ 
+ 	/* Save the PID so that we can use it after unsuccessful
+ 	 * process_exec.  */
+@@ -479,18 +486,7 @@ handle_exec(Event * event) {
+ 		goto untrace;
+ 	}
+ 
+-	continue_process(proc->pid);
+-
+-	/* After the exec, we expect to hit the first executable
+-	 * instruction.
+-	 *
+-	 * XXX TODO It would be nice to have this removed, but then we
+-	 * need to do that also for initial call to wait_for_proc in
+-	 * execute_program.  In that case we could generate a
+-	 * EVENT_FIRST event or something, or maybe this could somehow
+-	 * be rolled into EVENT_NEW.  */
+-	wait_for_proc(proc->pid);
+-	continue_process(proc->pid);
++	continue_after_exec(proc);
+ }
+ 
+ static void
+@@ -510,7 +506,8 @@ handle_arch_syscall(Event *event) {
+ struct timeval current_time_spent;
+ 
+ static void
+-calc_time_spent(Process *proc) {
++calc_time_spent(struct process *proc)
++{
+ 	struct timeval tv;
+ 	struct timezone tz;
+ 	struct timeval diff;
+@@ -568,7 +565,7 @@ handle_arch_sysret(Event *event) {
+ }
+ 
+ static void
+-output_right_tos(struct Process *proc)
++output_right_tos(struct process *proc)
+ {
+ 	size_t d = proc->callstack_depth;
+ 	struct callstack_element *elem = &proc->callstack[d - 1];
+@@ -577,7 +574,7 @@ output_right_tos(struct Process *proc)
+ }
+ 
+ #ifndef ARCH_HAVE_SYMBOL_RET
+-void arch_symbol_ret(struct Process *proc, struct library_symbol *libsym)
++void arch_symbol_ret(struct process *proc, struct library_symbol *libsym)
+ {
+ }
+ #endif
+@@ -587,7 +584,7 @@ handle_breakpoint(Event *event)
+ {
+ 	int i, j;
+ 	struct breakpoint *sbp;
+-	Process *leader = event->proc->leader;
++	struct process *leader = event->proc->leader;
+ 	void *brk_addr = event->e_un.brk_addr;
+ 
+ 	/* The leader has terminated.  */
+@@ -682,7 +679,8 @@ handle_breakpoint(Event *event)
+ }
+ 
+ static void
+-callstack_push_syscall(Process *proc, int sysnum) {
++callstack_push_syscall(struct process *proc, int sysnum)
++{
+ 	struct callstack_element *elem;
+ 
+ 	debug(DEBUG_FUNCTION, "callstack_push_syscall(pid=%d, sysnum=%d)", proc->pid, sysnum);
+@@ -707,7 +705,8 @@ callstack_push_syscall(Process *proc, int sysnum) {
+ }
+ 
+ static void
+-callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
++callstack_push_symfunc(struct process *proc, struct library_symbol *sym)
++{
+ 	struct callstack_element *elem;
+ 
+ 	debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name);
+@@ -734,7 +733,7 @@ callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
+ }
+ 
+ void
+-callstack_pop(struct Process *proc)
++callstack_pop(struct process *proc)
+ {
+ 	struct callstack_element *elem;
+ 	assert(proc->callstack_depth > 0);
+diff --git a/libltrace.c b/libltrace.c
+index 559edfa..b69a0c9 100644
+--- a/libltrace.c
++++ b/libltrace.c
+@@ -21,6 +21,7 @@
+ 
+ #include "config.h"
+ 
++#include <limits.h>
+ #include <sys/param.h>
+ #include <sys/wait.h>
+ #include <errno.h>
+@@ -40,13 +41,13 @@ char *command = NULL;
+ int exiting = 0;		/* =1 if a SIGINT or SIGTERM has been received */
+ 
+ static enum callback_status
+-stop_non_p_processes(Process *proc, void *data)
++stop_non_p_processes(struct process *proc, void *data)
+ {
+ 	int stop = 1;
+ 
+ 	struct opt_p_t *it;
+ 	for (it = opt_p; it != NULL; it = it->next) {
+-		Process * p_proc = pid2proc(it->pid);
++		struct process *p_proc = pid2proc(it->pid);
+ 		if (p_proc == NULL) {
+ 			printf("stop_non_p_processes: %d terminated?\n", it->pid);
+ 			continue;
+@@ -141,7 +142,7 @@ ltrace_init(int argc, char **argv) {
+ 		do_close_elf(&lte);
+ 
+ 		pid_t pid = execute_program(command, argv);
+-		struct Process *proc = open_program(command, pid);
++		struct process *proc = open_program(command, pid);
+ 		if (proc == NULL) {
+ 			fprintf(stderr, "couldn't open program '%s': %s\n",
+ 				command, strerror(errno));
+diff --git a/library.c b/library.c
+index 594472b..b5f6386 100644
+--- a/library.c
++++ b/library.c
+@@ -412,7 +412,7 @@ library_add_symbol(struct library *lib, struct library_symbol *first)
+ }
+ 
+ enum callback_status
+-library_named_cb(struct Process *proc, struct library *lib, void *name)
++library_named_cb(struct process *proc, struct library *lib, void *name)
+ {
+ 	if (name == lib->soname
+ 	    || strcmp(lib->soname, (char *)name) == 0)
+@@ -422,7 +422,7 @@ library_named_cb(struct Process *proc, struct library *lib, void *name)
+ }
+ 
+ enum callback_status
+-library_with_key_cb(struct Process *proc, struct library *lib, void *keyp)
++library_with_key_cb(struct process *proc, struct library *lib, void *keyp)
+ {
+ 	return lib->key == *(arch_addr_t *)keyp ? CBS_STOP : CBS_CONT;
+ }
+diff --git a/library.h b/library.h
+index 555fa80..74e1df2 100644
+--- a/library.h
++++ b/library.h
+@@ -23,12 +23,11 @@
+ #define _LIBRARY_H_
+ 
+ #include <stdint.h>
++
+ #include "callback.h"
++#include "forward.h"
+ #include "sysdep.h"
+ 
+-struct Process;
+-struct library;
+-
+ enum toplt {
+ 	LS_TOPLT_NONE = 0,	/* PLT not used for this symbol. */
+ 	LS_TOPLT_EXEC,		/* PLT for this symbol is executable. */
+@@ -195,7 +194,7 @@ void library_add_symbol(struct library *lib, struct library_symbol *sym);
+ 
+ /* A function that can be used as proc_each_library callback.  Looks
+  * for a library with the name passed in DATA.  PROC is ignored.  */
+-enum callback_status library_named_cb(struct Process *proc,
++enum callback_status library_named_cb(struct process *proc,
+ 				      struct library *lib, void *name);
+ 
+ /* A function that can be used as proc_each_library callback.  Looks
+@@ -203,7 +202,7 @@ enum callback_status library_named_cb(struct Process *proc,
+  *
+  * NOTE: The key is passed as a POINTER to arch_addr_t (that
+  * because in general, arch_addr_t doesn't fit in void*).  */
+-enum callback_status library_with_key_cb(struct Process *proc,
++enum callback_status library_with_key_cb(struct process *proc,
+ 					 struct library *lib, void *keyp);
+ 
+ /* XXX this should really be in backend.h (as on pmachata/revamp
+@@ -220,7 +219,7 @@ int arch_translate_address(struct ltelf *lte,
+ 			   arch_addr_t addr, arch_addr_t *ret);
+ /* This is the same function as arch_translate_address, except it's
+  * used at the point that we don't have ELF available anymore.  */
+-int arch_translate_address_dyn(struct Process *proc,
++int arch_translate_address_dyn(struct process *proc,
+ 			       arch_addr_t addr, arch_addr_t *ret);
+ 
+ #endif /* _LIBRARY_H_ */
+diff --git a/ltrace-elf.c b/ltrace-elf.c
+index c571d2a..1d0f769 100644
+--- a/ltrace-elf.c
++++ b/ltrace-elf.c
+@@ -40,6 +40,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <strings.h>
+ #include <unistd.h>
+ 
+ #include "backend.h"
+@@ -64,7 +65,7 @@ arch_elf_destroy(struct ltelf *lte)
+ #endif
+ 
+ int
+-default_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
++default_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
+ 			  const char *a_name, GElf_Rela *rela, size_t ndx,
+ 			  struct library_symbol **ret)
+ {
+@@ -101,11 +102,11 @@ default_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
+ 
+ #ifndef ARCH_HAVE_ADD_PLT_ENTRY
+ enum plt_status
+-arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
++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)
+ {
+-	return plt_default;
++	return PLT_DEFAULT;
+ }
+ #endif
+ 
+@@ -540,7 +541,7 @@ mark_chain_latent(struct library_symbol *libsym)
+ }
+ 
+ static int
+-populate_plt(struct Process *proc, const char *filename,
++populate_plt(struct process *proc, const char *filename,
+ 	     struct ltelf *lte, struct library *lib,
+ 	     int latent_plts)
+ {
+@@ -565,14 +566,14 @@ populate_plt(struct Process *proc, const char *filename,
+ 		struct library_symbol *libsym = NULL;
+ 		switch (arch_elf_add_plt_entry(proc, lte, name,
+ 					       &rela, i, &libsym)) {
+-		case plt_default:
++		case PLT_DEFAULT:
+ 			if (default_elf_add_plt_entry(proc, lte, name,
+ 						      &rela, i, &libsym) < 0)
+ 			/* fall-through */
+-		case plt_fail:
++		case PLT_FAIL:
+ 				return -1;
+ 			/* fall-through */
+-		case plt_ok:
++		case PLT_OK:
+ 			if (libsym != NULL) {
+ 				/* If we are adding those symbols just
+ 				 * for tracing exports, mark them all
+@@ -614,7 +615,7 @@ symbol_with_address(struct library_symbol *sym, void *addrptr)
+ }
+ 
+ static int
+-populate_this_symtab(struct Process *proc, const char *filename,
++populate_this_symtab(struct process *proc, const char *filename,
+ 		     struct ltelf *lte, struct library *lib,
+ 		     Elf_Data *symtab, const char *strtab, size_t size,
+ 		     struct library_exported_name **names)
+@@ -777,7 +778,7 @@ populate_this_symtab(struct Process *proc, const char *filename,
+ }
+ 
+ static int
+-populate_symtab(struct Process *proc, const char *filename,
++populate_symtab(struct process *proc, const char *filename,
+ 		struct ltelf *lte, struct library *lib,
+ 		int symtabs, int exports)
+ {
+@@ -802,7 +803,7 @@ populate_symtab(struct Process *proc, const char *filename,
+ }
+ 
+ static int
+-read_module(struct library *lib, struct Process *proc,
++read_module(struct library *lib, struct process *proc,
+ 	    const char *filename, GElf_Addr bias, int main)
+ {
+ 	struct ltelf lte = {};
+@@ -942,7 +943,7 @@ fail:
+ }
+ 
+ int
+-ltelf_read_library(struct library *lib, struct Process *proc,
++ltelf_read_library(struct library *lib, struct process *proc,
+ 		   const char *filename, GElf_Addr bias)
+ {
+ 	return read_module(lib, proc, filename, bias, 0);
+@@ -950,7 +951,7 @@ ltelf_read_library(struct library *lib, struct Process *proc,
+ 
+ 
+ struct library *
+-ltelf_read_main_binary(struct Process *proc, const char *path)
++ltelf_read_main_binary(struct process *proc, const char *path)
+ {
+ 	struct library *lib = malloc(sizeof(*lib));
+ 	if (lib == NULL)
+diff --git a/ltrace-elf.h b/ltrace-elf.h
+index 1a1321e..b76d1eb 100644
+--- a/ltrace-elf.h
++++ b/ltrace-elf.h
+@@ -26,11 +26,9 @@
+ 
+ #include <gelf.h>
+ #include <stdlib.h>
+-#include "sysdep.h"
+ 
+-struct Process;
+-struct library;
+-struct library_symbol;
++#include "forward.h"
++#include "sysdep.h"
+ 
+ /* XXX Ok, the original idea was to separate the low-level ELF data
+  * from the abstract "struct library" object, but we use some of the
+@@ -73,21 +71,21 @@ void do_close_elf(struct ltelf *lte);
+ /* XXX is it possible to put breakpoints in VDSO and VSYSCALL
+  * pseudo-libraries?  For now we assume that all libraries can be
+  * opened via a filesystem.  BASE is ignored for ET_EXEC files.  */
+-int ltelf_read_library(struct library *lib, struct Process *proc,
++int ltelf_read_library(struct library *lib, struct process *proc,
+ 		       const char *filename, GElf_Addr bias);
+ 
+ /* Create a library object representing the main binary.  The entry
+  * point address is stored to *ENTRYP.  */
+-struct library *ltelf_read_main_binary(struct Process *proc, const char *path);
++struct library *ltelf_read_main_binary(struct process *proc, const char *path);
+ 
+ /* Create a default PLT entry.  This can be used instead (or in
+- * addition to) returning plt_default from arch_elf_add_plt_entry.
++ * addition to) returning PLT_DEFAULT from arch_elf_add_plt_entry.
+  * RET shall be initialized, the created symbol will be added to the
+  * beginning of the linked list at *RET.  This function doesn't add
+  * the symbol to LTE.  arch_elf_add_plt_entry has the chance to adjust
+- * symbol internals to its liking, and then return either plt_default
+- * or plt_ok.  */
+-int default_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
++ * symbol internals to its liking, and then return either PLT_DEFAULT
++ * or PLT_OK.  */
++int default_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
+ 			      const char *a_name, GElf_Rela *rela, size_t ndx,
+ 			      struct library_symbol **ret);
+ 
+diff --git a/ltrace.1 b/ltrace.1
+index 8b459ee..7f3c5bc 100644
+--- a/ltrace.1
++++ b/ltrace.1
+@@ -1,5 +1,5 @@
+ .\" -*-nroff-*-
+-.\" Copyright (c) 2012 Petr Machata, Red Hat Inc.
++.\" Copyright (c) 2012, 2013 Petr Machata, Red Hat Inc.
+ .\" Copyright (c) 1997-2005 Juan Cespedes <cespedes at debian.org>
+ .\"
+ .\" This program is free software; you can redistribute it and/or
+@@ -17,13 +17,65 @@
+ .\" Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ .\" 02110-1301 USA
+ .\"
+-.TH LTRACE "1" "October 2012" "" "User Commands"
++.TH LTRACE "1" "January 2013" "" "User Commands"
+ .SH NAME
+ ltrace \- A library call tracer
+ 
+ .SH SYNOPSIS
++.\"
++.\" ---------------------------------------------------------------------------
++.\"
++.PP
+ .B ltrace
+-.I "[-bCfghiLrStttV] [-a column] [-A maxelts] [-D level] [-e expr] [-l library_pattern] [-n nr] [-o filename] [-p pid] ... [-s strsize] [-u username] [-w count] [-x extern] ... [--align=column] [--debug=level] [--demangle] [--help] [--indent=nr] [--library=library_pattern] [--no-signals] [--output=filename] [--version] [--where=NR] [command [arg ...]]"
++.\"
++.\" What events to trace:
++.\"
++[\-e \fIfilter\fR|\-L] [\-l|\-\-library=\fIlibrary_pattern\fR]
++[\-x \fIfilter\fR] [\-S] [\-b|\-\-no-signals]
++.\"
++.\" What to display with each event:
++.\"
++[\-i] [\-w|\-\-where=\fInr\fR] [\-r|\-t|\-tt|\-ttt] [\-T]
++.\"
++.\" Output formatting:
++.\"
++[\-F \fIfilename\fR]
++[\-A \fImaxelts\fR] [\-s \fIstrsize\fR] [\-C|\-\-demangle]
++[\-a|\-\-align \fIcolumn\fR] [\-n|\-\-indent \fInr\fR]
++[\-o|\-\-output \fIfilename\fR]
++.\"
++.\" Various:
++.\"
++[\-D|\-\-debug \fImask\fR] [\-u \fIusername\fR]
++.\"
++.\" What processes to trace:
++.\"
++[\-f] [\-p \fIpid\fR] [[\-\-] \fIcommand [arg ...]\fR]
++.\"
++.\" ---------------------------------------------------------------------------
++.\"
++.PP
++.BR ltrace " -c"
++.\"
++.\" What events to trace:
++.\"
++[\-e \fIfilter\fR|\-L] [\-l|\-\-library=\fIlibrary_pattern\fR]
++[\-x \fIfilter\fR] [\-S]
++.\"
++.\" Output formatting:
++.\"
++[\-o|\-\-output \fIfilename\fR]
++.\"
++.\" What processes to trace:
++.\"
++[\-f] [\-p \fIpid\fR] [[\-\-] \fIcommand [arg ...]\fR]
++.\"
++.\" ---------------------------------------------------------------------------
++.\"
++.PP
++.BR ltrace " \-V|\-\-version"
++.PP
++.BR ltrace " \-h|\-\-help"
+ 
+ .SH DESCRIPTION
+ .B ltrace
+@@ -38,77 +90,51 @@ Its use is very similar to
+ .BR strace(1) .
+ 
+ .SH OPTIONS
+-.TP
+-.I \-a, \-\-align column
++.PP
++.IP "\-a, \-\-align \fIcolumn"
+ Align return values in a specific
+ .IR column
+ (default column is 5/8 of screen width).
+-.TP
+-.I \-A maxelts
++.IP "\-A \fImaxelts"
+ Maximum number of array elements to print before suppressing the rest
+ with an ellipsis ("...").  This also limits number of recursive
+ structure expansions.
+-.TP
+-.I \-b, \-\-no-signals
++.IP "\-b, \-\-no-signals"
+ Disable printing of signals recieved by the traced process.
+-.TP
+-.I \-c
+-Count time and calls for each library call and report a summary on program exit.
+-.TP
+-.I \-C, \-\-demangle
++.IP \-c
++Count time and calls for each library call and report a summary on
++program exit.
++.IP "\-C, \-\-demangle"
+ Decode (demangle) low-level symbol names into user-level names.
+ Besides removing any initial underscore prefix used by the system,
+ this makes C++ function names readable.
+-.TP
+-.I \-D, \-\-debug level
+-Show debugging output of
+-.B ltrace
+-itself.
+-.I level
+-must be a sum of some of the following numbers:
+-.RS
+-.TP
+-.B 01
+-DEBUG_GENERAL.  Shows helpful progress information
+-.TP
+-.B 010
+-DEBUG_EVENT.  Shows every event received by a traced program
+-.TP
+-.B 020
+-DEBUG_PROCESS.  Shows every action
+-.B ltrace
+-carries upon a traced process
+-.TP
+-.B 040
+-DEBUG_FUNCTION.  Shows every entry to internal functions
+-.RE
+-.TP
+-.I \-e filter
++.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.
++.IP "\-e \fIfilter"
+ A qualifying expression which modifies which library calls to trace.
+ The format of the filter expression is described in the section
+ \fBFILTER EXPRESSIONS\fR.  If more than one \-e option appears on the
+ command line, the library calls that match any of them are traced.  If
+ no \-e is given, \fB at MAIN\fR is assumed as a default.
+-.TP
+-.I \-f
++.IP \-f
+ Trace child processes as they are created by
+ currently traced processes as a result of the fork(2)
+ or clone(2) system calls.
+ The new process is attached immediately.
+-.TP
+-.I \-F
++.IP "\-F \fIfilename"
+ Load an alternate config file. Normally, /etc/ltrace.conf and
+-~/.ltrace.conf will be read (the latter only if it exists).
+-Use this option to load the given file or files instead of
+-those two default files.
+-.TP
+-.I \-h, \-\-help
++~/.ltrace.conf will be read (the latter only if it exists).  Use this
++option to load the given file or files instead of those two default
++files.  See ltrace.conf(5) for details on the syntax of ltrace
++configuration files.
++.IP "\-h, \-\-help"
+ Show a summary of the options to ltrace and exit.
+-.TP
+-.I \-i
++.IP \-i
+ Print the instruction pointer at the time of the library call.
+-.TP
+-.I \-l, \-\-library library_pattern
++.IP "\-l, \-\-library \fIlibrary_pattern"
+ Display only calls to functions implemented by libraries that match
+ .I library_pattern.
+ Multiple library patters can be specified with several instances of
+@@ -120,71 +146,55 @@ the selected libraries, there's no actual guarantee that the call
+ won't be directed elsewhere due to e.g. LD_PRELOAD or simply
+ dependency ordering.  If you want to make sure that symbols in given
+ library are actually called, use \fB-x @\fIlibrary_pattern\fR instead.
+-.TP
+-.I \-L
++.IP \-L
+ When no -e option is given, don't assume the default action of
+ \fB at MAIN\fR.
+-.TP
+-.I \-n, \-\-indent nr
+-Indent trace output by
+-.I nr
+-number of spaces for each new nested call. Using this option makes
+-the program flow visualization easy to follow.
+-.TP
+-.I \-o, \-\-output filename
+-Write the trace output to the file
+-.I filename
+-rather than to stderr.
+-.TP
+-.I \-p pid
+-Attach to the process with the process ID
+-.I pid
+-and begin tracing.
+-.TP
+-.I \-r
+-Print a relative timestamp with each line of the trace.
+-This records the time difference between the beginning of
+-successive lines.
+-.TP
+-.I \-s strsize
++.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
++to follow.  This indents uselessly also functions that never return,
++such as service functions for throwing exceptions in the C++ runtime.
++.IP "\-o, \-\-output \fIfilename"
++Write the trace output to the file \fIfilename\fR rather than to
++stderr.
++.IP "\-p \fIpid"
++Attach to the process with the process ID \fIpid\fR and begin tracing.
++This option can be used together with passing a command to execute.
++It is possible to attach to several processes by passing more than one
++option \-p.
++.IP \-r
++Print a relative timestamp with each line of the trace.  This records
++the time difference between the beginning of successive lines.
++.IP "\-s \fIstrsize"
+ Specify the maximum string size to print (the default is 32).
+-.TP
+-.I \-S
++.IP \-S
+ Display system calls as well as library calls
+-.TP
+-.I \-t
++.IP \-t
+ Prefix each line of the trace with the time of day.
+-.TP
+-.I \-tt
++.IP \-tt
+ If given twice, the time printed will include the microseconds.
+-.TP
+-.I \-ttt
++.IP \-ttt
+ If given thrice, the time printed will include the microseconds and
+ the leading portion will be printed as the number of seconds since the
+ epoch.
+-.TP
+-.I \-T
++.IP \-T
+ Show  the  time  spent inside each call. This records the time difference
+ between the beginning and the end of each call.
+-.TP
+-.I \-u username
++.IP "\-u \fIusername"
+ Run command with the userid, groupid and supplementary groups of
+ .IR username .
+ This option is only useful when running as root and enables the
+ correct execution of setuid and/or setgid binaries.
+-.TP
+-.I \-w, --where NR
+-Show backtrace of NR stack frames for each traced function. This option enabled
+-only if libunwind support was enabled at compile time.
+-.TP
+-.I \-x filter
++.IP "\-w, --where \fInr"
++Show backtrace of \fInr\fR stack frames for each traced function. This
++option enabled only if libunwind support was enabled at compile time.
++.IP "\-x \fIfilter"
+ A qualifying expression which modifies which symbol table entry points
+ to trace.  The format of the filter expression is described in the
+ section \fBFILTER EXPRESSIONS\fR.  If more than one \-x option appears
+ on the command line, the symbols that match any of them are traced.
+ No entry points are traced if no \-x is given.
+-.TP
+-.I \-V, \-\-version
++.IP "\-V, \-\-version"
+ Show the version number of ltrace and exit.
+ 
+ .SH FILTER EXPRESSIONS
+@@ -235,7 +245,8 @@ path name.
+ 
+ The first rule may lack a sign, in which case \fB+\fR is assumed.  If,
+ on the other hand, the first rule has a \fB-\fR sign, it is as if
+-there was another rule \fB@*\fR in front of it.
++there was another rule \fB@\fR in front of it, which has the effect of
++tracing complement of given rule.
+ 
+ The above rules are used to construct the set of traced symbols.  Each
+ candidate symbol is passed through the chain of above rules.
+diff --git a/ltrace.h b/ltrace.h
+index ee7e27b..3e714a8 100644
+--- a/ltrace.h
++++ b/ltrace.h
+@@ -44,7 +44,7 @@ enum Event_type {
+ typedef struct Event Event;
+ struct Event {
+ 	struct Event * next;
+-	struct Process * proc;
++	struct process *proc;
+ 	Event_type type;
+ 	union {
+ 		int ret_val;     /* EVENT_EXIT */
+diff --git a/ltrace.spec b/ltrace.spec
+deleted file mode 100644
+index 3740190..0000000
+--- a/ltrace.spec
++++ /dev/null
+@@ -1,164 +0,0 @@
+-Summary: Tracks runtime library calls from dynamically linked executables.
+-Name: ltrace
+-Version: 0.3.36
+-Release: 4.2
+-Source: ftp://ftp.debian.org/debian/pool/main/l/ltrace/ltrace_%{version}.orig.tar.gz
+-Patch1: ftp://ftp.debian.org/debian/pool/main/l/ltrace/ltrace_0.3.36-2.diff.gz
+-Patch2: ltrace-ppc64.patch
+-Patch3: ltrace-ppc64-2.patch
+-Patch4: ltrace-s390x.patch
+-Patch5: ltrace-syscallent-update.patch
+-Patch6: ltrace-fixes.patch
+-Patch7: ltrace-ia64.patch
+-License: GPL
+-Group: Development/Debuggers
+-ExclusiveArch: i386 x86_64 ia64 ppc ppc64 s390 s390x alpha sparc
+-Prefix: %{_prefix}
+-BuildRoot: /var/tmp/%{name}-root
+-BuildRequires: elfutils-libelf-devel
+-
+-%description
+-Ltrace is a debugging program which runs a specified command until the
+-command exits.  While the command is executing, ltrace intercepts and
+-records both the dynamic library calls called by the executed process
+-and the signals received by the executed process.  Ltrace can also
+-intercept and print system calls executed by the process.
+-
+-You should install ltrace if you need a sysadmin tool for tracking the
+-execution of processes.
+-
+-%prep
+-%setup -q
+-%patch1 -p1
+-%patch2 -p1
+-%patch3 -p1
+-%patch4 -p1
+-%patch5 -p1
+-%patch6 -p1
+-%patch7 -p1
+-sed -i -e 's/-o root -g root//' Makefile.in
+-
+-%build
+-export CC="gcc`echo $RPM_OPT_FLAGS | sed -n 's/^.*\(-m[36][124]\).*$/ \1/p'`"
+-%configure CC="$CC"
+-make
+-
+-%install
+-make DESTDIR=$RPM_BUILD_ROOT mandir=%{_mandir} install
+-rm -f ChangeLog; mv -f debian/changelog ChangeLog
+-rm -rf $RPM_BUILD_ROOT/%{_prefix}/doc
+-
+-%clean
+-rm -rf $RPM_BUILD_ROOT
+-
+-%files
+-%defattr(-,root,root)
+-%doc COPYING README TODO BUGS ChangeLog
+-%{_prefix}/bin/ltrace
+-%{_mandir}/man1/ltrace.1*
+-%config /etc/ltrace.conf
+-
+-%changelog
+-* Fri Feb 10 2006 Jesse Keating <jkeating at redhat.com> - 0.3.36-4.2
+-- bump again for double-long bug on ppc(64)
+-
+-* Tue Feb 07 2006 Jesse Keating <jkeating at redhat.com> - 0.3.36-4.1
+-- rebuilt for new gcc4.1 snapshot and glibc changes
+-
+-* Mon Jan  9 2006 Jakub Jelinek <jakub at redhat.com> 0.3.36-4
+-- added ppc64 and s390x support (IBM)
+-- added ia64 support (Ian Wienand)
+-
+-* Sat Mar  5 2005 Jakub Jelinek <jakub at redhat.com> 0.3.36-3
+-- rebuilt with GCC 4
+-
+-* Tue Dec 14 2004 Jakub Jelinek <jakub at redhat.com> 0.3.36-2
+-- make x86_64 ltrace trace both 32-bit and 64-bit binaries (#141955,
+-  IT#55600)
+-- fix tracing across execve
+-- fix printf-style format handling on 64-bit arches
+-
+-* Thu Nov 18 2004 Jakub Jelinek <jakub at redhat.com> 0.3.36-1
+-- update to 0.3.36
+-
+-* Mon Oct 11 2004 Jakub Jelinek <jakub at redhat.com> 0.3.35-1
+-- update to 0.3.35
+-- update syscall tables from latest kernel source
+-
+-* Tue Jun 15 2004 Elliot Lee <sopwith at redhat.com>
+-- rebuilt
+-
+-* Tue Jun  8 2004 Jakub Jelinek <jakub at redhat.com> 0.3.32-3
+-- buildreq elfutils-libelf-devel (#124921)
+-
+-* Thu Apr 22 2004 Jakub Jelinek <jakub at redhat.com> 0.3.32-2
+-- fix demangling
+-
+-* Thu Apr 22 2004 Jakub Jelinek <jakub at redhat.com> 0.3.32-1
+-- update to 0.3.32
+-  - fix dict.c assertion (#114359)
+-  - x86_64 support
+-- rewrite elf.[ch] using libelf
+-- don't rely on st_value of SHN_UNDEF symbols in binaries,
+-  instead walk .rel{,a}.plt and compute the addresses (#115299)
+-- fix x86-64 support
+-- some ltrace.conf additions
+-- some format string printing fixes
+-
+-* Fri Feb 13 2004 Elliot Lee <sopwith at redhat.com>
+-- rebuilt
+-
+-* Mon Feb  3 2003 Jakub Jelinek <jakub at redhat.com> 0.3.29-1
+-- update to 0.3.29
+-
+-* Wed Jan 22 2003 Tim Powers <timp at redhat.com>
+-- rebuilt
+-
+-* Sun Sep  1 2002 Jakub Jelinek <jakub at redhat.com> 0.3.10-12
+-- add a bunch of missing functions to ltrace.conf
+-  (like strlen, ugh)
+-
+-* Fri Jun 21 2002 Tim Powers <timp at redhat.com>
+-- automated rebuild
+-
+-* Tue May 28 2002 Phil Knirsch <pknirsch at redhat.com>
+-- Added the 'official' s390 patch.
+-
+-* Thu May 23 2002 Tim Powers <timp at redhat.com>
+-- automated rebuild
+-
+-* Wed Jan 09 2002 Tim Powers <timp at redhat.com>
+-- automated rebuild
+-
+-* Fri Jul 20 2001 Jakub Jelinek <jakub at redhat.com>
+-- fix stale symlink in documentation directory (#47749)
+-
+-* Sun Jun 24 2001 Elliot Lee <sopwith at redhat.com>
+-- Bump release + rebuild.
+-
+-* Thu Aug  2 2000 Tim Waugh <twaugh at redhat.com>
+-- fix off-by-one problem in checking syscall number
+-
+-* Wed Jul 12 2000 Prospector <bugzilla at redhat.com>
+-- automatic rebuild
+-
+-* Mon Jun 19 2000 Matt Wilson <msw at redhat.com>
+-- rebuilt for next release
+-- patched Makefile.in to take a hint on mandir (patch2)
+-- use %%{_mandir} and %%makeinstall
+-
+-* Wed Feb 02 2000 Cristian Gafton <gafton at redhat.com>
+-- fix description
+-
+-* Fri Jan  7 2000 Jeff Johnson <jbj at redhat.com>
+-- update to 0.3.10.
+-- include (but don't apply) sparc patch from Jakub Jellinek.
+-
+-* Sun Mar 21 1999 Cristian Gafton <gafton at redhat.com> 
+-- auto rebuild in the new build environment (release 2)
+-
+-* Fri Mar 12 1999 Jeff Johnson <jbj at redhat.com>
+-- update to 0.3.6.
+-
+-* Mon Sep 21 1998 Preston Brown <pbrown at redhat.com>
+-- upgraded to 0.3.4
+diff --git a/memstream.c b/memstream.c
+new file mode 100644
+index 0000000..ac3f31a
+--- /dev/null
++++ b/memstream.c
+@@ -0,0 +1,73 @@
++/*
++ * This file is part of ltrace.
++ * Copyright (C) 2012 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
++ */
++
++/* _GNU_SOURCE may be necessary for open_memstream visibility (see
++ * configure.ac), and there's no harm defining it just in case.  */
++#define _GNU_SOURCE
++
++#include <stdio.h>
++#include <stdlib.h>
++
++#include "config.h"
++#include "memstream.h"
++
++int
++memstream_init(struct memstream *memstream)
++{
++#if HAVE_OPEN_MEMSTREAM
++	memstream->stream = open_memstream(&memstream->buf,
++					   &memstream->size);
++#else
++	memstream->stream = tmpfile();
++#endif
++	memstream->buf = NULL;
++	return memstream->stream != NULL ? 0 : -1;
++}
++
++int
++memstream_close(struct memstream *memstream)
++{
++#if !defined(HAVE_OPEN_MEMSTREAM) || !HAVE_OPEN_MEMSTREAM
++	if (fseek(memstream->stream, 0, SEEK_END) < 0) {
++	fail:
++		fclose(memstream->stream);
++		return -1;
++	}
++	memstream->size = ftell(memstream->stream);
++	if (memstream->size == (size_t)-1)
++		goto fail;
++	memstream->buf = malloc(memstream->size);
++	if (memstream->buf == NULL)
++		goto fail;
++
++	rewind(memstream->stream);
++	if (fread(memstream->buf, 1, memstream->size, memstream->stream)
++	    < memstream->size)
++		goto fail;
++#endif
++
++	return fclose(memstream->stream) == 0 ? 0 : -1;
++}
++
++void
++memstream_destroy(struct memstream *memstream)
++{
++	free(memstream->buf);
++}
+diff --git a/memstream.h b/memstream.h
+new file mode 100644
+index 0000000..eb06541
+--- /dev/null
++++ b/memstream.h
+@@ -0,0 +1,35 @@
++/*
++ * This file is part of ltrace.
++ * Copyright (C) 2012 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
++ */
++
++#include <stdio.h>
++
++/* Portability wrapper for platforms that don't have
++ * open_memstream.  */
++
++struct memstream
++{
++	FILE *stream;
++	char *buf;
++	size_t size;
++};
++
++int memstream_init(struct memstream *memstream);
++int memstream_close(struct memstream *memstream);
++void memstream_destroy(struct memstream *memstream);
+diff --git a/options.c b/options.c
+index e8fd2a2..eaf32fa 100644
+--- a/options.c
++++ b/options.c
+@@ -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,1999,2002,2003,2004,2007,2008,2009 Juan Cespedes
+  * Copyright (C) 2006 Ian Wienand
+@@ -86,27 +86,27 @@ usage(void) {
+ 	fprintf(stdout, "Usage: %s [option ...] [command [arg ...]]\n"
+ 		"Trace library calls of a given program.\n\n"
+ 		"  -a, --align=COLUMN  align return values in a secific column.\n"
+-		"  -A ARRAYLEN         maximum number of array elements to print.\n"
++		"  -A MAXELTS          maximum number of array elements to print.\n"
+ 		"  -b, --no-signals    don't print signals.\n"
+ 		"  -c                  count time and calls, and report a summary on exit.\n"
+ # ifdef USE_DEMANGLE
+ 		"  -C, --demangle      decode low-level symbol names into user-level names.\n"
+ # endif
+-		"  -D, --debug=LEVEL   enable debugging (see -Dh or --debug=help).\n"
++		"  -D, --debug=MASK    enable debugging (see -Dh or --debug=help).\n"
+ 		"  -Dh, --debug=help   show help on debugging.\n"
+-		"  -e expr             modify which events to trace.\n"
++		"  -e FILTER           modify which library calls to trace.\n"
+ 		"  -f                  trace children (fork() and clone()).\n"
+ 		"  -F, --config=FILE   load alternate configuration file (may be repeated).\n"
+ 		"  -h, --help          display this help and exit.\n"
+ 		"  -i                  print instruction pointer at time of library call.\n"
+-		"  -l, --library=FILE  only trace symbols implemented by this library.\n"
++		"  -l, --library=LIBRARY_PATTERN only trace symbols implemented by this library.\n"
+ 		"  -L                  do NOT display library calls.\n"
+ 		"  -n, --indent=NR     indent output by NR spaces for each call level nesting.\n"
+-		"  -o, --output=FILE   write the trace output to that file.\n"
++		"  -o, --output=FILENAME write the trace output to file with given name.\n"
+ 		"  -p PID              attach to the process with the process ID pid.\n"
+ 		"  -r                  print relative timestamps.\n"
+-		"  -s STRLEN           specify the maximum string size to print.\n"
+-		"  -S                  display system calls.\n"
++		"  -s STRSIZE          specify the maximum string size to print.\n"
++		"  -S                  trace system calls as well as library calls.\n"
+ 		"  -t, -tt, -ttt       print absolute timestamps.\n"
+ 		"  -T                  show the time spent inside each call.\n"
+ 		"  -u USERNAME         run command with the userid, groupid of username.\n"
+@@ -114,7 +114,7 @@ usage(void) {
+ #if defined(HAVE_LIBUNWIND)
+ 		"  -w, --where=NR      print backtrace showing NR stack frames at most.\n"
+ #endif /* defined(HAVE_LIBUNWIND) */
+-		"  -x NAME             treat the global NAME like a library subroutine.\n"
++		"  -x FILTER           modify which static functions to trace.\n"
+ 		"\nReport bugs to ltrace-devel at lists.alioth.debian.org\n",
+ 		progname);
+ }
+@@ -204,7 +204,7 @@ compile_libname(const char *expr, const char *a_lib, int lib_re_p,
+ 
+ 		regex_t lib_re;
+ 		int status = (lib_re_p ? regcomp : globcomp)(&lib_re, lib, 0);
+-		if (status != REG_NOERROR) {
++		if (status != 0) {
+ 			char buf[100];
+ 			regerror(status, &lib_re, buf, sizeof buf);
+ 			fprintf(stderr, "Rule near '%s' will be ignored: %s.\n",
+@@ -459,6 +459,7 @@ process_options(int argc, char **argv)
+ 	while (1) {
+ 		int c;
+ 		char *p;
++#ifdef HAVE_GETOPT_LONG
+ 		int option_index = 0;
+ 		static struct option long_options[] = {
+ 			{"align", 1, 0, 'a'},
+@@ -466,28 +467,34 @@ process_options(int argc, char **argv)
+ 			{"debug", 1, 0, 'D'},
+ # ifdef USE_DEMANGLE
+ 			{"demangle", 0, 0, 'C'},
+-#endif
++# endif
+ 			{"indent", 1, 0, 'n'},
+ 			{"help", 0, 0, 'h'},
+ 			{"library", 1, 0, 'l'},
+ 			{"output", 1, 0, 'o'},
+ 			{"version", 0, 0, 'V'},
+ 			{"no-signals", 0, 0, 'b'},
+-#if defined(HAVE_LIBUNWIND)
++# if defined(HAVE_LIBUNWIND)
+ 			{"where", 1, 0, 'w'},
+-#endif /* defined(HAVE_LIBUNWIND) */
++# endif /* defined(HAVE_LIBUNWIND) */
+ 			{0, 0, 0, 0}
+ 		};
+-		c = getopt_long(argc, argv, "+cfhiLrStTVb"
+-# ifdef USE_DEMANGLE
+-				"C"
+-# endif
++#endif
++
++		const char *opts = "+"
++#ifdef USE_DEMANGLE
++			"C"
++#endif
+ #if defined(HAVE_LIBUNWIND)
+-				"a:A:D:e:F:l:n:o:p:s:u:x:X:w:", long_options,
+-#else /* !defined(HAVE_LIBUNWIND) */
+-				"a:A:D:e:F:l:n:o:p:s:u:x:X:", long_options,
++			"w:"
++#endif
++			"cfhiLrStTVba:A:D:e:F:l:n:o:p:s:u:x:X:";
++
++#ifdef HAVE_GETOPT_LONG
++		c = getopt_long(argc, argv, opts, long_options, &option_index);
++#else
++		c = getopt(argc, argv, opts);
+ #endif
+-				&option_index);
+ 		if (c == -1) {
+ 			break;
+ 		}
+@@ -610,10 +617,12 @@ process_options(int argc, char **argv)
+ 			options.user = optarg;
+ 			break;
+ 		case 'V':
+-			printf("ltrace version " PACKAGE_VERSION ".\n"
+-					"Copyright (C) 1997-2009 Juan Cespedes <cespedes at debian.org>.\n"
+-					"This is free software; see the GNU General Public Licence\n"
+-					"version 2 or later for copying conditions.  There is NO warranty.\n");
++			printf("ltrace " PACKAGE_VERSION "\n"
++			       "Copyright (C) 2010-2012 Petr Machata, Red Hat Inc.\n"
++			       "Copyright (C) 1997-2009 Juan Cespedes <cespedes at debian.org>.\n"
++			       "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\n"
++			       "This is free software: you are free to change and redistribute it.\n"
++			       "There is NO WARRANTY, to the extent permitted by law.\n");
+ 			exit(0);
+ 			break;
+ #if defined(HAVE_LIBUNWIND)
+diff --git a/output.c b/output.c
+index 1d01d31..fe62bb4 100644
+--- a/output.c
++++ b/output.c
+@@ -22,10 +22,6 @@
+  * 02110-1301 USA
+  */
+ 
+-/* glibc before 2.10, eglibc and uClibc all need _GNU_SOURCE defined
+- * for open_memstream to become visible.  */
+-#define _GNU_SOURCE
+-
+ #include "config.h"
+ 
+ #include <stdio.h>
+@@ -47,25 +43,26 @@
+ #include "param.h"
+ #include "fetch.h"
+ #include "lens_default.h"
++#include "memstream.h"
+ 
+ /* TODO FIXME XXX: include in common.h: */
+ extern struct timeval current_time_spent;
+ 
+ Dict *dict_opt_c = NULL;
+ 
+-static Process *current_proc = 0;
++static struct process *current_proc = 0;
+ static size_t current_depth = 0;
+ static int current_column = 0;
+ 
+ static void
+-output_indent(struct Process *proc)
++output_indent(struct process *proc)
+ {
+ 	int d = options.indent * (proc->callstack_depth - 1);
+ 	current_column += fprintf(options.output, "%*s", d, "");
+ }
+ 
+ static void
+-begin_of_line(Process *proc, int is_func, int indent)
++begin_of_line(struct process *proc, int is_func, int indent)
+ {
+ 	current_column = 0;
+ 	if (!proc) {
+@@ -208,7 +205,7 @@ name2func(char const *name) {
+ }
+ 
+ void
+-output_line(struct Process *proc, const char *fmt, ...)
++output_line(struct process *proc, const char *fmt, ...)
+ {
+ 	if (options.summary)
+ 		return;
+@@ -248,7 +245,8 @@ output_error(FILE *stream)
+ }
+ 
+ static int
+-fetch_simple_param(enum tof type, Process *proc, struct fetch_context *context,
++fetch_simple_param(enum tof type, struct process *proc,
++		   struct fetch_context *context,
+ 		   struct value_dict *arguments,
+ 		   struct arg_type_info *info, int own,
+ 		   struct value *valuep)
+@@ -290,7 +288,8 @@ fetch_param_stop(struct value_dict *arguments, ssize_t *params_leftp)
+ }
+ 
+ static int
+-fetch_param_pack(enum tof type, Process *proc, struct fetch_context *context,
++fetch_param_pack(enum tof type, struct process *proc,
++		 struct fetch_context *context,
+ 		 struct value_dict *arguments, struct param *param,
+ 		 ssize_t *params_leftp)
+ {
+@@ -343,7 +342,8 @@ fetch_param_pack(enum tof type, Process *proc, struct fetch_context *context,
+ }
+ 
+ static int
+-fetch_one_param(enum tof type, Process *proc, struct fetch_context *context,
++fetch_one_param(enum tof type, struct process *proc,
++		struct fetch_context *context,
+ 		struct value_dict *arguments, struct param *param,
+ 		ssize_t *params_leftp)
+ {
+@@ -372,7 +372,8 @@ fetch_one_param(enum tof type, Process *proc, struct fetch_context *context,
+ }
+ 
+ static int
+-fetch_params(enum tof type, Process *proc, struct fetch_context *context,
++fetch_params(enum tof type, struct process *proc,
++	     struct fetch_context *context,
+ 	     struct value_dict *arguments, Function *func, ssize_t *params_leftp)
+ {
+ 	size_t i;
+@@ -424,7 +425,7 @@ output_params(struct value_dict *arguments, size_t start, size_t end,
+ }
+ 
+ void
+-output_left(enum tof type, struct Process *proc,
++output_left(enum tof type, struct process *proc,
+ 	    struct library_symbol *libsym)
+ {
+ 	const char *function_name = libsym->name;
+@@ -499,7 +500,7 @@ output_left(enum tof type, struct Process *proc,
+ }
+ 
+ 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)
+ {
+ 	const char *function_name = libsym->name;
+ 	Function *func = name2func(function_name);
+@@ -640,18 +641,18 @@ delim_output(FILE *stream, int *need_delimp,
+ 		o = writer(stream, data);
+ 
+ 	} else {
+-		char *buf;
+-		size_t bufsz;
+-		FILE *tmp = open_memstream(&buf, &bufsz);
+-		o = writer(tmp, data);
+-		fclose(tmp);
+-
++		struct memstream ms;
++		if (memstream_init(&ms) < 0)
++			return -1;
++		o = writer(ms.stream, data);
++		if (memstream_close(&ms) < 0)
++			o = -1;
+ 		if (o > 0 && ((*need_delimp
+ 			       && account_output(&o, fprintf(stream, ", ")) < 0)
+-			      || fwrite(buf, 1, bufsz, stream) != bufsz))
++			      || fwrite(ms.buf, 1, ms.size, stream) != ms.size))
+ 			o = -1;
+ 
+-		free(buf);
++		memstream_destroy(&ms);
+ 	}
+ 
+ 	if (o < 0)
+diff --git a/output.h b/output.h
+index 0d16657..b9f0518 100644
+--- a/output.h
++++ b/output.h
+@@ -24,10 +24,10 @@
+ #include "fetch.h"
+ #include "forward.h"
+ 
+-void output_line(struct Process *proc, const char *fmt, ...);
+-void output_left(enum tof type, struct Process *proc,
++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,
++void output_right(enum tof type, struct process *proc,
+ 		  struct library_symbol *libsym);
+ 
+ /* This function is for emitting lists of comma-separated strings.
+diff --git a/proc.c b/proc.c
+index 3b4bfdb..db3f645 100644
+--- a/proc.c
++++ b/proc.c
+@@ -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) 2010 Joe Damato
+  * Copyright (C) 1998,2009 Juan Cespedes
+  *
+@@ -43,24 +43,24 @@
+ 
+ #ifndef ARCH_HAVE_PROCESS_DATA
+ int
+-arch_process_init(struct Process *proc)
++arch_process_init(struct process *proc)
+ {
+ 	return 0;
+ }
+ 
+ void
+-arch_process_destroy(struct Process *proc)
++arch_process_destroy(struct process *proc)
+ {
+ }
+ 
+ int
+-arch_process_clone(struct Process *retp, struct Process *proc)
++arch_process_clone(struct process *retp, struct process *proc)
+ {
+ 	return 0;
+ }
+ 
+ int
+-arch_process_exec(struct Process *proc)
++arch_process_exec(struct process *proc)
+ {
+ 	return 0;
+ }
+@@ -68,24 +68,24 @@ arch_process_exec(struct Process *proc)
+ 
+ #ifndef OS_HAVE_PROCESS_DATA
+ int
+-os_process_init(struct Process *proc)
++os_process_init(struct process *proc)
+ {
+ 	return 0;
+ }
+ 
+ void
+-os_process_destroy(struct Process *proc)
++os_process_destroy(struct process *proc)
+ {
+ }
+ 
+ int
+-os_process_clone(struct Process *retp, struct Process *proc)
++os_process_clone(struct process *retp, struct process *proc)
+ {
+ 	return 0;
+ }
+ 
+ int
+-os_process_exec(struct Process *proc)
++os_process_exec(struct process *proc)
+ {
+ 	return 0;
+ }
+@@ -93,16 +93,16 @@ os_process_exec(struct Process *proc)
+ 
+ #ifndef ARCH_HAVE_DYNLINK_DONE
+ void
+-arch_dynlink_done(struct Process *proc)
++arch_dynlink_done(struct process *proc)
+ {
+ }
+ #endif
+ 
+-static void add_process(struct Process *proc, int was_exec);
+-static void unlist_process(struct Process *proc);
++static void add_process(struct process *proc, int was_exec);
++static void unlist_process(struct process *proc);
+ 
+ static void
+-destroy_unwind(struct Process *proc)
++destroy_unwind(struct process *proc)
+ {
+ #if defined(HAVE_LIBUNWIND)
+ 	_UPT_destroy(proc->unwind_priv);
+@@ -111,7 +111,7 @@ destroy_unwind(struct Process *proc)
+ }
+ 
+ static int
+-process_bare_init(struct Process *proc, const char *filename,
++process_bare_init(struct process *proc, const char *filename,
+ 		  pid_t pid, int was_exec)
+ {
+ 	if (!was_exec) {
+@@ -151,7 +151,7 @@ process_bare_init(struct Process *proc, const char *filename,
+ }
+ 
+ static void
+-process_bare_destroy(struct Process *proc, int was_exec)
++process_bare_destroy(struct process *proc, int was_exec)
+ {
+ 	dict_clear(proc->breakpoints);
+ 	if (!was_exec) {
+@@ -162,7 +162,7 @@ process_bare_destroy(struct Process *proc, int was_exec)
+ }
+ 
+ static int
+-process_init_main(struct Process *proc)
++process_init_main(struct process *proc)
+ {
+ 	if (breakpoints_init(proc) < 0) {
+ 		fprintf(stderr, "failed to init breakpoints %d\n",
+@@ -174,7 +174,7 @@ process_init_main(struct Process *proc)
+ }
+ 
+ int
+-process_init(struct Process *proc, const char *filename, pid_t pid)
++process_init(struct process *proc, const char *filename, pid_t pid)
+ {
+ 	if (process_bare_init(proc, filename, pid, 0) < 0) {
+ 	fail:
+@@ -204,7 +204,7 @@ process_init(struct Process *proc, const char *filename, pid_t pid)
+ }
+ 
+ static enum callback_status
+-destroy_breakpoint_cb(struct Process *proc, struct breakpoint *bp, void *data)
++destroy_breakpoint_cb(struct process *proc, struct breakpoint *bp, void *data)
+ {
+ 	breakpoint_destroy(bp);
+ 	free(bp);
+@@ -212,10 +212,10 @@ destroy_breakpoint_cb(struct Process *proc, struct breakpoint *bp, void *data)
+ }
+ 
+ // XXX see comment in handle_event.c
+-void callstack_pop(struct Process *proc);
++void callstack_pop(struct process *proc);
+ 
+ static void
+-private_process_destroy(struct Process *proc, int was_exec)
++private_process_destroy(struct process *proc, int was_exec)
+ {
+ 	/* Pop remaining stack elements.  */
+ 	while (proc->callstack_depth > 0) {
+@@ -257,7 +257,7 @@ private_process_destroy(struct Process *proc, int was_exec)
+ }
+ 
+ void
+-process_destroy(struct Process *proc)
++process_destroy(struct process *proc)
+ {
+ 	arch_process_destroy(proc);
+ 	os_process_destroy(proc);
+@@ -265,7 +265,7 @@ process_destroy(struct Process *proc)
+ }
+ 
+ int
+-process_exec(struct Process *proc)
++process_exec(struct process *proc)
+ {
+ 	/* Call exec handlers first, before we destroy the main
+ 	 * state.  */
+@@ -284,11 +284,11 @@ process_exec(struct Process *proc)
+ 	return 0;
+ }
+ 
+-struct Process *
++struct process *
+ open_program(const char *filename, pid_t pid)
+ {
+ 	assert(pid != 0);
+-	struct Process *proc = malloc(sizeof(*proc));
++	struct process *proc = malloc(sizeof(*proc));
+ 	if (proc == NULL || process_init(proc, filename, pid) < 0) {
+ 		free(proc);
+ 		return NULL;
+@@ -297,8 +297,8 @@ open_program(const char *filename, pid_t pid)
+ }
+ 
+ struct clone_single_bp_data {
+-	struct Process *old_proc;
+-	struct Process *new_proc;
++	struct process *old_proc;
++	struct process *new_proc;
+ 	int error;
+ };
+ 
+@@ -327,7 +327,7 @@ clone_single_bp(void *key, void *value, void *u)
+ }
+ 
+ int
+-process_clone(struct Process *retp, struct Process *proc, pid_t pid)
++process_clone(struct process *retp, struct process *proc, pid_t pid)
+ {
+ 	if (process_bare_init(retp, proc->filename, pid, 0) < 0) {
+ 	fail1:
+@@ -456,20 +456,18 @@ process_clone(struct Process *retp, struct Process *proc, pid_t pid)
+ static int
+ open_one_pid(pid_t pid)
+ {
+-	Process *proc;
+-	char *filename;
+ 	debug(DEBUG_PROCESS, "open_one_pid(pid=%d)", pid);
+ 
+ 	/* Get the filename first.  Should the trace_pid fail, we can
+ 	 * easily free it, untracing is more work.  */
+-	if ((filename = pid2name(pid)) == NULL
+-	    || trace_pid(pid) < 0) {
++	char *filename = pid2name(pid);
++	if (filename == NULL || trace_pid(pid) < 0) {
+ 	fail:
+ 		free(filename);
+ 		return -1;
+ 	}
+ 
+-	proc = open_program(filename, pid);
++	struct process *proc = open_program(filename, pid);
+ 	if (proc == NULL)
+ 		goto fail;
+ 	free(filename);
+@@ -479,7 +477,7 @@ open_one_pid(pid_t pid)
+ }
+ 
+ static enum callback_status
+-start_one_pid(Process * proc, void * data)
++start_one_pid(struct process *proc, void *data)
+ {
+ 	continue_process(proc->pid);
+ 	return CBS_CONT;
+@@ -537,7 +535,7 @@ open_pid(pid_t pid)
+ 		old_ntasks = ntasks;
+ 	}
+ 
+-	struct Process *leader = pid2proc(pid)->leader;
++	struct process *leader = pid2proc(pid)->leader;
+ 
+ 	/* XXX Is there a way to figure out whether _start has
+ 	 * actually already been hit?  */
+@@ -548,29 +546,29 @@ open_pid(pid_t pid)
+ }
+ 
+ static enum callback_status
+-find_proc(Process * proc, void * data)
++find_proc(struct process *proc, void *data)
+ {
+ 	pid_t pid = (pid_t)(uintptr_t)data;
+ 	return proc->pid == pid ? CBS_STOP : CBS_CONT;
+ }
+ 
+-Process *
+-pid2proc(pid_t pid) {
++struct process *
++pid2proc(pid_t pid)
++{
+ 	return each_process(NULL, &find_proc, (void *)(uintptr_t)pid);
+ }
+ 
+-static Process * list_of_processes = NULL;
++static struct process *list_of_processes = NULL;
+ 
+ static void
+-unlist_process(Process * proc)
++unlist_process(struct process *proc)
+ {
+-	Process *tmp;
+-
+ 	if (list_of_processes == proc) {
+ 		list_of_processes = list_of_processes->next;
+ 		return;
+ 	}
+ 
++	struct process *tmp;
+ 	for (tmp = list_of_processes; ; tmp = tmp->next) {
+ 		/* If the following assert fails, the process wasn't
+ 		 * in the list.  */
+@@ -583,17 +581,17 @@ unlist_process(Process * proc)
+ 	}
+ }
+ 
+-struct Process *
+-each_process(struct Process *start_after,
+-	     enum callback_status(*cb)(struct Process *proc, void *data),
++struct process *
++each_process(struct process *start_after,
++	     enum callback_status(*cb)(struct process *proc, void *data),
+ 	     void *data)
+ {
+-	struct Process *it = start_after == NULL ? list_of_processes
++	struct process *it = start_after == NULL ? list_of_processes
+ 		: start_after->next;
+ 
+ 	while (it != NULL) {
+ 		/* Callback might call remove_process.  */
+-		struct Process *next = it->next;
++		struct process *next = it->next;
+ 		switch ((*cb)(it, data)) {
+ 		case CBS_FAIL:
+ 			/* XXX handle me */
+@@ -607,20 +605,20 @@ each_process(struct Process *start_after,
+ 	return NULL;
+ }
+ 
+-Process *
+-each_task(struct Process *proc, struct Process *start_after,
+-	  enum callback_status(*cb)(struct Process *proc, void *data),
++struct process *
++each_task(struct process *proc, struct process *start_after,
++	  enum callback_status(*cb)(struct process *proc, void *data),
+ 	  void *data)
+ {
+ 	assert(proc != NULL);
+-	struct Process *it = start_after == NULL ? proc->leader
++	struct process *it = start_after == NULL ? proc->leader
+ 		: start_after->next;
+ 
+ 	if (it != NULL) {
+-		struct Process *leader = it->leader;
++		struct process *leader = it->leader;
+ 		while (it != NULL && it->leader == leader) {
+ 			/* Callback might call remove_process.  */
+-			struct Process *next = it->next;
++			struct process *next = it->next;
+ 			switch ((*cb)(it, data)) {
+ 			case CBS_FAIL:
+ 				/* XXX handle me */
+@@ -636,19 +634,19 @@ each_task(struct Process *proc, struct Process *start_after,
+ }
+ 
+ static void
+-add_process(struct Process *proc, int was_exec)
++add_process(struct process *proc, int was_exec)
+ {
+-	Process ** leaderp = &list_of_processes;
++	struct process **leaderp = &list_of_processes;
+ 	if (proc->pid) {
+ 		pid_t tgid = process_leader(proc->pid);
+ 		if (tgid == 0)
+ 			/* Must have been terminated before we managed
+ 			 * to fully attach.  */
+ 			return;
+-		if (tgid == proc->pid)
++		if (tgid == proc->pid) {
+ 			proc->leader = proc;
+-		else {
+-			Process * leader = pid2proc(tgid);
++		} else {
++			struct process *leader = pid2proc(tgid);
+ 			proc->leader = leader;
+ 			if (leader != NULL)
+ 				leaderp = &leader->next;
+@@ -662,9 +660,9 @@ add_process(struct Process *proc, int was_exec)
+ }
+ 
+ void
+-change_process_leader(Process * proc, Process * leader)
++change_process_leader(struct process *proc, struct process *leader)
+ {
+-	Process ** leaderp = &list_of_processes;
++	struct process **leaderp = &list_of_processes;
+ 	if (proc->leader == leader)
+ 		return;
+ 
+@@ -679,7 +677,7 @@ change_process_leader(Process * proc, Process * leader)
+ }
+ 
+ static enum callback_status
+-clear_leader(struct Process *proc, void *data)
++clear_leader(struct process *proc, void *data)
+ {
+ 	debug(DEBUG_FUNCTION, "detach_task %d from leader %d",
+ 	      proc->pid, proc->leader->pid);
+@@ -688,7 +686,7 @@ clear_leader(struct Process *proc, void *data)
+ }
+ 
+ void
+-remove_process(Process *proc)
++remove_process(struct process *proc)
+ {
+ 	debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid);
+ 
+@@ -702,7 +700,7 @@ remove_process(Process *proc)
+ }
+ 
+ void
+-install_event_handler(Process *proc, struct event_handler *handler)
++install_event_handler(struct process *proc, struct event_handler *handler)
+ {
+ 	debug(DEBUG_FUNCTION, "install_event_handler(pid=%d, %p)", proc->pid, handler);
+ 	assert(proc->event_handler == NULL);
+@@ -710,7 +708,7 @@ install_event_handler(Process *proc, struct event_handler *handler)
+ }
+ 
+ void
+-destroy_event_handler(Process * proc)
++destroy_event_handler(struct process *proc)
+ {
+ 	struct event_handler *handler = proc->event_handler;
+ 	debug(DEBUG_FUNCTION, "destroy_event_handler(pid=%d, %p)", proc->pid, handler);
+@@ -722,7 +720,7 @@ destroy_event_handler(Process * proc)
+ }
+ 
+ static int
+-breakpoint_for_symbol(struct library_symbol *libsym, struct Process *proc)
++breakpoint_for_symbol(struct library_symbol *libsym, struct process *proc)
+ {
+ 	arch_addr_t bp_addr;
+ 	assert(proc->leader == proc);
+@@ -799,7 +797,7 @@ cb_breakpoint_for_symbol(struct library_symbol *libsym, void *data)
+ }
+ 
+ static int
+-proc_activate_latent_symbol(struct Process *proc,
++proc_activate_latent_symbol(struct process *proc,
+ 			    struct library_symbol *libsym)
+ {
+ 	assert(libsym->latent);
+@@ -809,7 +807,7 @@ proc_activate_latent_symbol(struct Process *proc,
+ }
+ 
+ int
+-proc_activate_delayed_symbol(struct Process *proc,
++proc_activate_delayed_symbol(struct process *proc,
+ 			     struct library_symbol *libsym)
+ {
+ 	assert(libsym->delayed);
+@@ -819,7 +817,7 @@ proc_activate_delayed_symbol(struct Process *proc,
+ }
+ 
+ static enum callback_status
+-activate_latent_in(struct Process *proc, struct library *lib, void *data)
++activate_latent_in(struct process *proc, struct library *lib, void *data)
+ {
+ 	struct library_exported_name *exported;
+ 	for (exported = data; exported != NULL; exported = exported->next) {
+@@ -836,7 +834,7 @@ activate_latent_in(struct Process *proc, struct library *lib, void *data)
+ }
+ 
+ void
+-proc_add_library(struct Process *proc, struct library *lib)
++proc_add_library(struct process *proc, struct library *lib)
+ {
+ 	assert(lib->next == NULL);
+ 	lib->next = proc->libraries;
+@@ -864,7 +862,7 @@ proc_add_library(struct Process *proc, struct library *lib)
+ }
+ 
+ int
+-proc_remove_library(struct Process *proc, struct library *lib)
++proc_remove_library(struct process *proc, struct library *lib)
+ {
+ 	struct library **libp;
+ 	for (libp = &proc->libraries; *libp != NULL; libp = &(*libp)->next)
+@@ -876,8 +874,8 @@ proc_remove_library(struct Process *proc, struct library *lib)
+ }
+ 
+ struct library *
+-proc_each_library(struct Process *proc, struct library *it,
+-		  enum callback_status (*cb)(struct Process *proc,
++proc_each_library(struct process *proc, struct library *it,
++		  enum callback_status (*cb)(struct process *proc,
+ 					     struct library *lib, void *data),
+ 		  void *data)
+ {
+@@ -903,7 +901,7 @@ proc_each_library(struct Process *proc, struct library *it,
+ }
+ 
+ static void
+-check_leader(struct Process *proc)
++check_leader(struct process *proc)
+ {
+ 	/* Only the group leader should be getting the breakpoints and
+ 	 * thus have ->breakpoint initialized.  */
+@@ -913,7 +911,7 @@ check_leader(struct Process *proc)
+ }
+ 
+ int
+-proc_add_breakpoint(struct Process *proc, struct breakpoint *bp)
++proc_add_breakpoint(struct process *proc, struct breakpoint *bp)
+ {
+ 	debug(DEBUG_FUNCTION, "proc_add_breakpoint(pid=%d, %s@%p)",
+ 	      proc->pid, breakpoint_name(bp), bp->addr);
+@@ -935,7 +933,7 @@ proc_add_breakpoint(struct Process *proc, struct breakpoint *bp)
+ }
+ 
+ void
+-proc_remove_breakpoint(struct Process *proc, struct breakpoint *bp)
++proc_remove_breakpoint(struct process *proc, struct breakpoint *bp)
+ {
+ 	debug(DEBUG_FUNCTION, "proc_remove_breakpoint(pid=%d, %s@%p)",
+ 	      proc->pid, breakpoint_name(bp), bp->addr);
+@@ -950,8 +948,8 @@ struct each_breakpoint_data
+ {
+ 	void *start;
+ 	void *end;
+-	struct Process *proc;
+-	enum callback_status (*cb)(struct Process *proc,
++	struct process *proc;
++	enum callback_status (*cb)(struct process *proc,
+ 				   struct breakpoint *bp,
+ 				   void *data);
+ 	void *cb_data;
+@@ -979,8 +977,8 @@ each_breakpoint_cb(void *key, void *value, void *d)
+ }
+ 
+ void *
+-proc_each_breakpoint(struct Process *proc, void *start,
+-		     enum callback_status (*cb)(struct Process *proc,
++proc_each_breakpoint(struct process *proc, void *start,
++		     enum callback_status (*cb)(struct process *proc,
+ 						struct breakpoint *bp,
+ 						void *data), void *data)
+ {
+@@ -995,7 +993,7 @@ proc_each_breakpoint(struct Process *proc, void *start,
+ }
+ 
+ int
+-proc_find_symbol(struct Process *proc, struct library_symbol *sym,
++proc_find_symbol(struct process *proc, struct library_symbol *sym,
+ 		 struct library **retlib, struct library_symbol **retsym)
+ {
+ 	struct library *lib = sym->lib;
+@@ -1021,7 +1019,7 @@ proc_find_symbol(struct Process *proc, struct library_symbol *sym,
+ }
+ 
+ struct library_symbol *
+-proc_each_symbol(struct Process *proc, struct library_symbol *start_after,
++proc_each_symbol(struct process *proc, struct library_symbol *start_after,
+ 		 enum callback_status (*cb)(struct library_symbol *, void *),
+ 		 void *data)
+ {
+@@ -1035,3 +1033,25 @@ proc_each_symbol(struct Process *proc, struct library_symbol *start_after,
+ 
+ 	return NULL;
+ }
++
++#define DEF_READER(NAME, SIZE)						\
++	int								\
++	NAME(struct process *proc, arch_addr_t addr,			\
++	     uint##SIZE##_t *lp)					\
++	{								\
++		union {							\
++			uint##SIZE##_t dst;				\
++			char buf[0];					\
++		} u;							\
++		if (umovebytes(proc, addr, &u.buf, sizeof(u.dst))	\
++		    != sizeof(u.dst))					\
++			return -1;					\
++		*lp = u.dst;						\
++		return 0;						\
++	}
++
++DEF_READER(proc_read_16, 16)
++DEF_READER(proc_read_32, 32)
++DEF_READER(proc_read_64, 64)
++
++#undef DEF_READER
+diff --git a/proc.h b/proc.h
+index a97796c..04c0ef7 100644
+--- a/proc.h
++++ b/proc.h
+@@ -1,6 +1,6 @@
+ /*
+  * This file is part of ltrace.
+- * Copyright (C) 2010,2011,2012 Petr Machata, Red Hat Inc.
++ * Copyright (C) 2010,2011,2012,2013 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2010 Joe Damato
+  * Copyright (C) 1998,2001,2008,2009 Juan Cespedes
+  *
+@@ -26,6 +26,7 @@
+ #include "config.h"
+ 
+ #include <sys/time.h>
++#include <stdint.h>
+ 
+ #if defined(HAVE_LIBUNWIND)
+ # include <libunwind.h>
+@@ -75,13 +76,12 @@ struct callstack_element {
+ #define MAX_CALLDEPTH 64
+ 
+ /* XXX We would rather have this all organized a little differently,
+- * have Process for the whole group and Task for what's there for
+- * per-thread stuff.  But for now this is the less invasive way of
+- * structuring it.  */
+-typedef struct Process Process;
+-struct Process {
++ * have struct process for the whole group and struct task (or struct
++ * lwp, struct thread) for what's there for per-thread stuff.  But for
++ * now this is the less invasive way of structuring it.  */
++struct process {
+ 	enum process_state state;
+-	Process * parent;         /* needed by STATE_BEING_CREATED */
++	struct process *parent;         /* needed by STATE_BEING_CREATED */
+ 	char * filename;
+ 	pid_t pid;
+ 
+@@ -133,15 +133,15 @@ struct Process {
+ 	/**
+ 	 * Process chaining.
+ 	 **/
+-	Process * next;
++	struct process *next;
+ 
+ 	/* LEADER points to the leader thread of the POSIX.1 process.
+ 	   If X->LEADER == X, then X is the leader thread and the
+-	   Process structures chained by NEXT represent other threads,
++	   process structures chained by NEXT represent other threads,
+ 	   up until, but not including, the next leader thread.
+ 	   LEADER may be NULL after the leader has already exited.  In
+ 	   that case this process is waiting to be collected.  */
+-	Process * leader;
++	struct process *leader;
+ 
+ 	struct os_process_data os;
+ 	struct arch_process_data arch;
+@@ -149,12 +149,12 @@ struct Process {
+ 
+ /* Initialize a process given a path to binary FILENAME, with a PID,
+  * and add the process to an internal chain of traced processes.  */
+-int process_init(struct Process *proc, const char *filename, pid_t pid);
++int process_init(struct process *proc, const char *filename, pid_t pid);
+ 
+ /* PROC underwent an exec.  This is a bit like process_destroy
+  * followed by process_init, except that some state is kept and the
+  * process doesn't lose it's place in the list of processes.  */
+-int process_exec(struct Process *proc);
++int process_exec(struct process *proc);
+ 
+ /* Release any memory allocated for PROC (but not PROC itself).  Does
+  * NOT remove PROC from internal chain.
+@@ -162,74 +162,74 @@ int process_exec(struct Process *proc);
+  * XXX clearly this init/destroy pair is different than others and
+  * should be fixed.  process_init should presumably be separate from
+  * process_add.  */
+-void process_destroy(struct Process *proc);
++void process_destroy(struct process *proc);
+ 
+-struct Process *open_program(const char *filename, pid_t pid);
++struct process *open_program(const char *filename, pid_t pid);
+ void open_pid(pid_t pid);
+-Process * pid2proc(pid_t pid);
++struct process *pid2proc(pid_t pid);
+ 
+ /* Clone the contents of PROC into the memory referenced by RETP.
+  * Returns 0 on success or a negative value on failure.  */
+-int process_clone(struct Process *retp, struct Process *proc, pid_t pid);
++int process_clone(struct process *retp, struct process *proc, pid_t pid);
+ 
+ /* Iterate through the processes that ltrace currently traces.  Tasks
+  * are considered to be processes for the purpose of this iterator.
+  * See callback.h for notes on iteration interfaces.  */
+-Process *each_process(Process *start_after,
+-		      enum callback_status (*cb)(struct Process *proc,
+-						 void *data),
+-		      void *data);
++struct process *each_process(struct process *start_after,
++			     enum callback_status (*cb)(struct process *proc,
++							void *data),
++			     void *data);
+ 
+ /* Iterate through list of tasks of given process PROC.  See
+  * callback.h for notes on iteration interfaces.  */
+-Process *each_task(struct Process *proc, struct Process *start_after,
+-		   enum callback_status (*cb)(struct Process *proc,
+-					      void *data),
+-		   void *data);
++struct process *each_task(struct process *proc, struct process *start_after,
++			  enum callback_status (*cb)(struct process *proc,
++						     void *data),
++			  void *data);
+ 
+-void change_process_leader(Process *proc, Process *leader);
++void change_process_leader(struct process *proc, struct process *leader);
+ 
+ /* Remove process from the list of traced processes, drop any events
+  * in the event queue, destroy it and free memory.  */
+-void remove_process(struct Process *proc);
++void remove_process(struct process *proc);
+ 
+-void install_event_handler(Process *proc, struct event_handler *handler);
+-void destroy_event_handler(Process *proc);
++void install_event_handler(struct process *proc, struct event_handler *handler);
++void destroy_event_handler(struct process *proc);
+ 
+ /* Add a library LIB to the list of PROC's libraries.  */
+-void proc_add_library(struct Process *proc, struct library *lib);
++void proc_add_library(struct process *proc, struct library *lib);
+ 
+ /* Remove LIB from list of PROC's libraries.  Returns 0 if the library
+  * was found and unlinked, otherwise returns a negative value.  */
+-int proc_remove_library(struct Process *proc, struct library *lib);
++int proc_remove_library(struct process *proc, struct library *lib);
+ 
+ /* Clear a delayed flag.  If a symbol is neither latent, nor delayed,
+  * a breakpoint is inserted for it.  Returns 0 if the activation was
+  * successful or a negative value if it failed.  Note that if a symbol
+  * is both latent and delayed, this will not enable the corresponding
+  * breakpoint.  */
+-int proc_activate_delayed_symbol(struct Process *proc,
++int proc_activate_delayed_symbol(struct process *proc,
+ 				 struct library_symbol *libsym);
+ 
+ /* Iterate through the libraries of PROC.  See callback.h for notes on
+  * iteration interfaces.  */
+-struct library *proc_each_library(struct Process *proc, struct library *start,
+-				  enum callback_status (*cb)(struct Process *p,
++struct library *proc_each_library(struct process *proc, struct library *start,
++				  enum callback_status (*cb)(struct process *p,
+ 							     struct library *l,
+ 							     void *data),
+ 				  void *data);
+ 
+ /* Insert BP into PROC.  */
+-int proc_add_breakpoint(struct Process *proc, struct breakpoint *bp);
++int proc_add_breakpoint(struct process *proc, struct breakpoint *bp);
+ 
+ /* Remove BP from PROC.  This has no reason to fail in runtime.  If it
+  * does not find BP in PROC, it's hard error guarded by assertion.  */
+-void proc_remove_breakpoint(struct Process *proc, struct breakpoint *bp);
++void proc_remove_breakpoint(struct process *proc, struct breakpoint *bp);
+ 
+ /* Iterate through the breakpoints of PROC.  See callback.h for notes
+  * on iteration interfaces.  */
+-void *proc_each_breakpoint(struct Process *proc, void *start,
+-			   enum callback_status (*cb)(struct Process *proc,
++void *proc_each_breakpoint(struct process *proc, void *start,
++			   enum callback_status (*cb)(struct process *proc,
+ 						      struct breakpoint *bp,
+ 						      void *data),
+ 			   void *data);
+@@ -237,21 +237,29 @@ void *proc_each_breakpoint(struct Process *proc, void *start,
+ /* Iterate through the dynamic section at src_addr looking for D_TAG.
+  * If tag is found, fill it's value in RET and return 0.
+  * If tag is not found, return a negative value.  */
+-int proc_find_dynamic_entry_addr(struct Process *proc, arch_addr_t src_addr,
++int proc_find_dynamic_entry_addr(struct process *proc, arch_addr_t src_addr,
+ 				 int d_tag, arch_addr_t *ret);
+ 
+ /* Finds a symbol corresponding to LIBSYM in a process PROC.  Returns
+  * 0 and sets *RETLIB and *RETSYM if the corresponding pointer is
+  * non-NULL.  Returns a negative value when the symbols couldn't be
+  * found.  */
+-int proc_find_symbol(struct Process *proc, struct library_symbol *sym,
++int proc_find_symbol(struct process *proc, struct library_symbol *sym,
+ 		     struct library **retlib, struct library_symbol **retsym);
+ 
+ /* Iterate through all symbols in all libraries of PROC.  See
+  * callback.h for notes on this interface.  */
+ struct library_symbol *proc_each_symbol
+-	(struct Process *proc, struct library_symbol *start_after,
++	(struct process *proc, struct library_symbol *start_after,
+ 	 enum callback_status (*cb)(struct library_symbol *, void *),
+ 	 void *data);
+ 
++/* Read 16, 32 or 64-bit quantity located at ADDR in PROC.  The
++ * resulting value is stored in *LP.  0 is returned on success or a
++ * negative value on failure.  This uses umovebytes under the hood
++ * (see backend.h).  */
++int proc_read_16(struct process *proc, arch_addr_t addr, uint16_t *lp);
++int proc_read_32(struct process *proc, arch_addr_t addr, uint32_t *lp);
++int proc_read_64(struct process *proc, arch_addr_t addr, uint64_t *lp);
++
+ #endif /* _PROC_H_ */
+diff --git a/read_config_file.c b/read_config_file.c
+index e247436..015be50 100644
+--- a/read_config_file.c
++++ b/read_config_file.c
+@@ -27,7 +27,6 @@
+ #include <stdlib.h>
+ #include <ctype.h>
+ #include <errno.h>
+-#include <error.h>
+ #include <assert.h>
+ 
+ #include "common.h"
+@@ -41,6 +40,19 @@
+ #include "lens_default.h"
+ #include "lens_enum.h"
+ 
++/* Lifted from GCC: The ctype functions are often implemented as
++ * macros which do lookups in arrays using the parameter as the
++ * offset.  If the ctype function parameter is a char, then gcc will
++ * (appropriately) warn that a "subscript has type char".  Using a
++ * (signed) char as a subscript is bad because you may get negative
++ * offsets and thus it is not 8-bit safe.  The CTYPE_CONV macro
++ * ensures that the parameter is cast to an unsigned char when a char
++ * is passed in.  When an int is passed in, the parameter is left
++ * alone so we don't lose EOF.  */
++
++#define CTYPE_CONV(CH) \
++  (sizeof(CH) == sizeof(unsigned char) ? (int)(unsigned char)(CH) : (int)(CH))
++
+ static int line_no;
+ static char *filename;
+ struct typedef_node_t;
+@@ -97,7 +109,7 @@ parse_arg_type(char **name, enum arg_type *ret)
+ #undef KEYWORD
+ 
+ ok:
+-	if (isalnum(*rest))
++	if (isalnum(CTYPE_CONV(*rest)))
+ 		return -1;
+ 
+ 	*name = rest;
+@@ -128,12 +140,12 @@ static char *
+ parse_ident(char **str) {
+ 	char *ident = *str;
+ 
+-	if (!isalpha(**str) && **str != '_') {
++	if (!isalpha(CTYPE_CONV(**str)) && **str != '_') {
+ 		report_error(filename, line_no, "bad identifier");
+ 		return NULL;
+ 	}
+ 
+-	while (**str && (isalnum(**str) || **str == '_')) {
++	while (**str && (isalnum(CTYPE_CONV(**str)) || **str == '_')) {
+ 		++(*str);
+ 	}
+ 
+@@ -280,7 +292,7 @@ parse_argnum(char **str, int *ownp, int zero)
+ 	if (expr == NULL)
+ 		return NULL;
+ 
+-	if (isdigit(**str)) {
++	if (isdigit(CTYPE_CONV(**str))) {
+ 		long l;
+ 		if (parse_int(str, &l) < 0
+ 		    || check_nonnegative(l) < 0
+@@ -381,7 +393,7 @@ static struct arg_type_info *
+ parse_typedef_name(char **str)
+ {
+ 	char *end = *str;
+-	while (*end && (isalnum(*end) || *end == '_'))
++	while (*end && (isalnum(CTYPE_CONV(*end)) || *end == '_'))
+ 		++end;
+ 	if (end == *str)
+ 		return NULL;
+@@ -568,7 +580,7 @@ parse_string(char **str, struct arg_type_info **retp, int *ownp)
+ 	int own_length;
+ 	int with_arg = 0;
+ 
+-	if (isdigit(**str)) {
++	if (isdigit(CTYPE_CONV(**str))) {
+ 		/* string0 is string[retval], length is zero(retval)
+ 		 * stringN is string[argN], length is zero(argN) */
+ 		long l;
+@@ -683,7 +695,7 @@ try_parse_kwd(char **str, const char *kwd)
+ {
+ 	size_t len = strlen(kwd);
+ 	if (strncmp(*str, kwd, len) == 0
+-	    && !isalnum((*str)[len])) {
++	    && !isalnum(CTYPE_CONV((*str)[len]))) {
+ 		(*str) += len;
+ 		return 0;
+ 	}
+@@ -1258,8 +1270,11 @@ void
+ init_global_config(void)
+ {
+ 	struct arg_type_info *info = malloc(2 * sizeof(*info));
+-	if (info == NULL)
+-		error(1, errno, "malloc in init_global_config");
++	if (info == NULL) {
++		fprintf(stderr, "Couldn't init global config: %s\n",
++			strerror(errno));
++		exit(1);
++	}
+ 
+ 	memset(info, 0, 2 * sizeof(*info));
+ 	info[0].type = ARGTYPE_POINTER;
+diff --git a/sysdeps/linux-gnu/alpha/plt.c b/sysdeps/linux-gnu/alpha/plt.c
+index c7ce9fe..1185363 100644
+--- a/sysdeps/linux-gnu/alpha/plt.c
++++ b/sysdeps/linux-gnu/alpha/plt.c
+@@ -23,11 +23,13 @@
+ #include "common.h"
+ 
+ GElf_Addr
+-arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
++arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela)
++{
+ 	return lte->plt_addr + ndx * 12 + 32;
+ }
+ 
+ void *
+-sym2addr(Process *proc, struct library_symbol *sym) {
++sym2addr(struct process *proc, struct library_symbol *sym)
++{
+ 	return sym->enter_addr;
+ }
+diff --git a/sysdeps/linux-gnu/alpha/regs.c b/sysdeps/linux-gnu/alpha/regs.c
+index 0b46afd..c197225 100644
+--- a/sysdeps/linux-gnu/alpha/regs.c
++++ b/sysdeps/linux-gnu/alpha/regs.c
+@@ -36,26 +36,31 @@
+ #endif
+ 
+ void *
+-get_instruction_pointer(Process *proc) {
++get_instruction_pointer(struct process *proc)
++{
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 64 /* REG_PC */ , 0);
+ }
+ 
+ void
+-set_instruction_pointer(Process *proc, void *addr) {
++set_instruction_pointer(struct process *proc, void *addr)
++{
+ 	ptrace(PTRACE_POKEUSER, proc->pid, 64 /* REG_PC */ , addr);
+ }
+ 
+ void *
+-get_stack_pointer(Process *proc) {
++get_stack_pointer(struct process *proc)
++{
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 30 /* REG_FP */ , 0);
+ }
+ 
+ void *
+-get_return_addr(Process *proc, void *stack_pointer) {
++get_return_addr(struct process *proc, void *stack_pointer)
++{
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 26 /* RA */ , 0);
+ }
+ 
+ void
+-set_return_addr(Process *proc, void *addr) {
++set_return_addr(struct process *proc, void *addr)
++{
+ 	ptrace(PTRACE_POKEUSER, proc->pid, 26 /* RA */ , addr);
+ }
+diff --git a/sysdeps/linux-gnu/alpha/trace.c b/sysdeps/linux-gnu/alpha/trace.c
+index a7c5e59..c6f7494 100644
+--- a/sysdeps/linux-gnu/alpha/trace.c
++++ b/sysdeps/linux-gnu/alpha/trace.c
+@@ -40,13 +40,15 @@
+ #endif
+ 
+ void
+-get_arch_dep(Process *proc) {
++get_arch_dep(struct process *proc)
++{
+ }
+ 
+ /* Returns 1 if syscall, 2 if sysret, 0 otherwise.
+  */
+ int
+-syscall_p(Process *proc, int status, int *sysnum) {
++syscall_p(struct process *proc, int status, int *sysnum)
++{
+ 	if (WIFSTOPPED(status)
+ 	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
+ 		char *ip = get_instruction_pointer(proc) - 4;
+@@ -69,7 +71,8 @@ syscall_p(Process *proc, int status, int *sysnum) {
+ }
+ 
+ long
+-gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info)
++gimme_arg(enum tof type, struct process *proc, int arg_num,
++	  struct arg_type_info *info)
+ {
+ 	if (arg_num == -1) {	/* return value */
+ 		return ptrace(PTRACE_PEEKUSER, proc->pid, 0 /* REG_R0 */ , 0);
+diff --git a/sysdeps/linux-gnu/arm/breakpoint.c b/sysdeps/linux-gnu/arm/breakpoint.c
+index 5748401..2fb9578 100644
+--- a/sysdeps/linux-gnu/arm/breakpoint.c
++++ b/sysdeps/linux-gnu/arm/breakpoint.c
+@@ -92,7 +92,7 @@ arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp)
+ }
+ 
+ int
+-arch_breakpoint_init(struct Process *proc, struct breakpoint *sbp)
++arch_breakpoint_init(struct process *proc, struct breakpoint *sbp)
+ {
+ 	/* XXX That uintptr_t cast is there temporarily until
+ 	 * arch_addr_t becomes integral type.  */
+diff --git a/sysdeps/linux-gnu/arm/plt.c b/sysdeps/linux-gnu/arm/plt.c
+index 1b97705..d1bf7ca 100644
+--- a/sysdeps/linux-gnu/arm/plt.c
++++ b/sysdeps/linux-gnu/arm/plt.c
+@@ -43,6 +43,7 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
+ }
+ 
+ void *
+-sym2addr(Process *proc, struct library_symbol *sym) {
++sym2addr(struct process *proc, struct library_symbol *sym)
++{
+ 	return sym->enter_addr;
+ }
+diff --git a/sysdeps/linux-gnu/arm/regs.c b/sysdeps/linux-gnu/arm/regs.c
+index 484de7f..377df62 100644
+--- a/sysdeps/linux-gnu/arm/regs.c
++++ b/sysdeps/linux-gnu/arm/regs.c
+@@ -41,24 +41,28 @@
+ #define off_sp ((void *)52)
+ 
+ void *
+-get_instruction_pointer(Process *proc) {
++get_instruction_pointer(struct process *proc)
++{
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0);
+ }
+ 
+ void
+-set_instruction_pointer(Process *proc, void *addr) {
++set_instruction_pointer(struct process *proc, void *addr)
++{
+ 	ptrace(PTRACE_POKEUSER, proc->pid, off_pc, addr);
+ }
+ 
+ void *
+-get_stack_pointer(Process *proc) {
++get_stack_pointer(struct process *proc)
++{
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_sp, 0);
+ }
+ 
+ /* really, this is given the *stack_pointer expecting
+  * a CISC architecture; in our case, we don't need that */
+ void *
+-get_return_addr(Process *proc, void *stack_pointer) {
++get_return_addr(struct process *proc, void *stack_pointer)
++{
+ 	long addr = ptrace(PTRACE_PEEKUSER, proc->pid, off_lr, 0);
+ 
+ 	/* Remember & unset the thumb mode bit.  XXX This is really a
+@@ -74,7 +78,8 @@ get_return_addr(Process *proc, void *stack_pointer) {
+ }
+ 
+ void
+-set_return_addr(Process *proc, void *addr) {
++set_return_addr(struct process *proc, void *addr)
++{
+ 	long iaddr = (int)addr | proc->thumb_mode;
+ 	ptrace(PTRACE_POKEUSER, proc->pid, off_lr, (void *)iaddr);
+ }
+diff --git a/sysdeps/linux-gnu/arm/trace.c b/sysdeps/linux-gnu/arm/trace.c
+index c528cfb..fbbf676 100644
+--- a/sysdeps/linux-gnu/arm/trace.c
++++ b/sysdeps/linux-gnu/arm/trace.c
+@@ -48,7 +48,8 @@
+ #define off_pc ((void *)60)
+ 
+ void
+-get_arch_dep(Process *proc) {
++get_arch_dep(struct process *proc)
++{
+ 	proc_archdep *a;
+ 
+ 	if (!proc->arch_ptr)
+@@ -63,7 +64,8 @@ get_arch_dep(Process *proc) {
+  *         -1 on error.
+  */
+ int
+-syscall_p(Process *proc, int status, int *sysnum) {
++syscall_p(struct process *proc, int status, int *sysnum)
++{
+ 	if (WIFSTOPPED(status)
+ 	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
+ 		/* get the user's pc (plus 8) */
+@@ -104,7 +106,8 @@ syscall_p(Process *proc, int status, int *sysnum) {
+ }
+ 
+ long
+-gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info)
++gimme_arg(enum tof type, struct process *proc, int arg_num,
++	  struct arg_type_info *info)
+ {
+ 	proc_archdep *a = (proc_archdep *) proc->arch_ptr;
+ 
+diff --git a/sysdeps/linux-gnu/breakpoint.c b/sysdeps/linux-gnu/breakpoint.c
+index fe336b1..c28d745 100644
+--- a/sysdeps/linux-gnu/breakpoint.c
++++ b/sysdeps/linux-gnu/breakpoint.c
+@@ -79,7 +79,7 @@ arch_enable_breakpoint(pid_t pid, struct breakpoint *sbp)
+ #endif				/* ARCH_HAVE_ENABLE_BREAKPOINT */
+ 
+ void
+-enable_breakpoint(Process *proc, struct breakpoint *sbp)
++enable_breakpoint(struct process *proc, struct breakpoint *sbp)
+ {
+ 	debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p, symbol=%s",
+ 	      proc->pid, sbp->addr, breakpoint_name(sbp));
+@@ -127,7 +127,7 @@ arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp)
+ #endif				/* ARCH_HAVE_DISABLE_BREAKPOINT */
+ 
+ void
+-disable_breakpoint(Process *proc, struct breakpoint *sbp)
++disable_breakpoint(struct process *proc, struct breakpoint *sbp)
+ {
+ 	debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p, symbol=%s",
+ 	      proc->pid, sbp->addr, breakpoint_name(sbp));
+diff --git a/sysdeps/linux-gnu/cris/plt.c b/sysdeps/linux-gnu/cris/plt.c
+index 427ae93..fcc18d2 100644
+--- a/sysdeps/linux-gnu/cris/plt.c
++++ b/sysdeps/linux-gnu/cris/plt.c
+@@ -28,7 +28,7 @@ GElf_Addr arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela)
+ 	return lte->plt_addr + 0x20 + (ndx * 26);
+ }
+ 
+-void *sym2addr(Process *proc, struct library_symbol *sym)
++void *sym2addr(struct process *proc, struct library_symbol *sym)
+ {
+ 	return sym->enter_addr;
+ }
+diff --git a/sysdeps/linux-gnu/cris/regs.c b/sysdeps/linux-gnu/cris/regs.c
+index 7028b9e..4cf1fbf 100644
+--- a/sysdeps/linux-gnu/cris/regs.c
++++ b/sysdeps/linux-gnu/cris/regs.c
+@@ -37,22 +37,22 @@
+ # define PTRACE_POKEUSER PTRACE_POKEUSR
+ #endif
+ 
+-void *get_instruction_pointer(Process *proc)
++void *get_instruction_pointer(struct process *proc)
+ {
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_PPC, 0);
+ }
+ 
+-void set_instruction_pointer(Process *proc, void *addr)
++void set_instruction_pointer(struct process *proc, void *addr)
+ {
+ 	ptrace(PTRACE_POKEUSER, proc->pid, 4 * PT_PPC, addr);
+ }
+ 
+-void *get_stack_pointer(Process *proc)
++void *get_stack_pointer(struct process *proc)
+ {
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_USP, 0);
+ }
+ 
+-void *get_return_addr(Process *proc, void *stack_pointer)
++void *get_return_addr(struct process *proc, void *stack_pointer)
+ {
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_SRP, 0);
+ }
+diff --git a/sysdeps/linux-gnu/cris/trace.c b/sysdeps/linux-gnu/cris/trace.c
+index 98cb7d8..7d8cca6 100644
+--- a/sysdeps/linux-gnu/cris/trace.c
++++ b/sysdeps/linux-gnu/cris/trace.c
+@@ -40,14 +40,14 @@
+ # define PTRACE_POKEUSER PTRACE_POKEUSR
+ #endif
+ 
+-void get_arch_dep(Process *proc)
++void get_arch_dep(struct process *proc)
+ {
+ }
+ 
+ /* Returns 1 if syscall, 2 if sysret, 0 otherwise.
+  */
+ #define SYSCALL_INSN   0xe93d
+-int syscall_p(Process *proc, int status, int *sysnum)
++int syscall_p(struct process *proc, int status, int *sysnum)
+ {
+ 	if (WIFSTOPPED(status)
+ 	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
+@@ -71,7 +71,7 @@ int syscall_p(Process *proc, int status, int *sysnum)
+ 	return 0;
+ }
+ 
+-long gimme_arg(enum tof type, Process *proc, int arg_num,
++long gimme_arg(enum tof type, struct process *proc, int arg_num,
+ 	       struct arg_type_info *info)
+ {
+ 	int pid = proc->pid;
+diff --git a/sysdeps/linux-gnu/events.c b/sysdeps/linux-gnu/events.c
+index 077a656..6cda97e 100644
+--- a/sysdeps/linux-gnu/events.c
++++ b/sysdeps/linux-gnu/events.c
+@@ -48,7 +48,7 @@ static Event * delayed_events = NULL;
+ static Event * end_delayed_events = NULL;
+ 
+ static enum callback_status
+-first (Process * proc, void * data)
++first(struct process *proc, void *data)
+ {
+ 	return CBS_STOP;
+ }
+@@ -83,12 +83,12 @@ each_qd_event(enum ecb_status (*pred)(Event *, void *), void * data)
+ 	Event * event;
+ 	for (event = prev; event != NULL; ) {
+ 		switch ((*pred)(event, data)) {
+-		case ecb_cont:
++		case ECB_CONT:
+ 			prev = event;
+ 			event = event->next;
+ 			continue;
+ 
+-		case ecb_deque:
++		case ECB_DEQUE:
+ 			debug(DEBUG_FUNCTION, "dequeuing event %d for %d",
+ 			      event->type,
+ 			      event->proc != NULL ? event->proc->pid : -1);
+@@ -106,7 +106,7 @@ each_qd_event(enum ecb_status (*pred)(Event *, void *), void * data)
+ 				end_delayed_events = NULL;
+ 			/* fall-through */
+ 
+-		case ecb_yield:
++		case ECB_YIELD:
+ 			return event;
+ 		}
+ 	}
+@@ -120,9 +120,9 @@ event_process_not_reenabling(Event * event, void * data)
+ 	if (event->proc == NULL
+ 	    || event->proc->leader == NULL
+ 	    || event->proc->leader->event_handler == NULL)
+-		return ecb_deque;
++		return ECB_DEQUE;
+ 	else
+-		return ecb_cont;
++		return ECB_CONT;
+ }
+ 
+ static Event *
+@@ -188,7 +188,7 @@ next_event(void)
+ 		 * now) the pain of figuring this out all over again.
+ 		 * Petr Machata 2011-11-22.  */
+ 		int i = 0;
+-		for (; i < 100 && process_status(pid) != ps_tracing_stop; ++i) {
++		for (; i < 100 && process_status(pid) != PS_TRACING_STOP; ++i) {
+ 			debug(2, "waiting for %d to stop", pid);
+ 			usleep(10000);
+ 		}
+@@ -199,7 +199,7 @@ next_event(void)
+ 	}
+ 	get_arch_dep(event.proc);
+ 	debug(3, "event from pid %u", pid);
+-	Process *leader = event.proc->leader;
++	struct process *leader = event.proc->leader;
+ 
+ 	/* The process should be stopped after the waitpid call.  But
+ 	 * when the whole thread group is terminated, we see
+@@ -341,13 +341,13 @@ static enum ecb_status
+ event_for_proc(struct Event *event, void *data)
+ {
+ 	if (event->proc == data)
+-		return ecb_deque;
++		return ECB_DEQUE;
+ 	else
+-		return ecb_cont;
++		return ECB_CONT;
+ }
+ 
+ void
+-delete_events_for(struct Process *proc)
++delete_events_for(struct process *proc)
+ {
+ 	struct Event *event;
+ 	while ((event = each_qd_event(&event_for_proc, proc)) != NULL)
+diff --git a/sysdeps/linux-gnu/events.h b/sysdeps/linux-gnu/events.h
+index 3802aff..51ef309 100644
+--- a/sysdeps/linux-gnu/events.h
++++ b/sysdeps/linux-gnu/events.h
+@@ -26,16 +26,16 @@
+ /* Declarations for event que functions.  */
+ 
+ enum ecb_status {
+-	ecb_cont, /* The iteration should continue.  */
+-	ecb_yield, /* The iteration should stop, yielding this
++	ECB_CONT, /* The iteration should continue.  */
++	ECB_YIELD, /* The iteration should stop, yielding this
+ 		    * event.  */
+-	ecb_deque, /* Like ecb_stop, but the event should be removed
++	ECB_DEQUE, /* Like ECB_STOP, but the event should be removed
+ 		    * from the queue.  */
+ };
+ 
+ struct Event *each_qd_event(enum ecb_status (*cb)(struct Event *event,
+ 						  void *data), void *data);
+-void delete_events_for(struct Process * proc);
++void delete_events_for(struct process *proc);
+ void enque_event(struct Event *event);
+ 
+ #endif /* SYSDEPS_LINUX_GNU_EVENTS_H */
+diff --git a/sysdeps/linux-gnu/ia64/fetch.c b/sysdeps/linux-gnu/ia64/fetch.c
+index 54dc5b8..e90dbed 100644
+--- a/sysdeps/linux-gnu/ia64/fetch.c
++++ b/sysdeps/linux-gnu/ia64/fetch.c
+@@ -63,7 +63,7 @@ union cfm_t {
+ };
+ 
+ static int
+-fetch_context_init(struct Process *proc, struct fetch_context *context)
++fetch_context_init(struct process *proc, struct fetch_context *context)
+ {
+ 	context->slot_n = 0;
+ 	context->flt = 8;
+@@ -76,7 +76,7 @@ fetch_context_init(struct Process *proc, struct fetch_context *context)
+ }
+ 
+ struct fetch_context *
+-arch_fetch_arg_init(enum tof type, struct Process *proc,
++arch_fetch_arg_init(enum tof type, struct process *proc,
+ 		    struct arg_type_info *ret_info)
+ {
+ 	struct fetch_context *context = malloc(sizeof(*context));
+@@ -91,7 +91,7 @@ arch_fetch_arg_init(enum tof type, struct Process *proc,
+ }
+ 
+ struct fetch_context *
+-arch_fetch_arg_clone(struct Process *proc,
++arch_fetch_arg_clone(struct process *proc,
+ 		     struct fetch_context *context)
+ {
+ 	struct fetch_context *clone = malloc(sizeof(*context));
+@@ -102,7 +102,7 @@ arch_fetch_arg_clone(struct Process *proc,
+ }
+ 
+ int
+-allocate_stack_slot(struct fetch_context *ctx, struct Process *proc,
++allocate_stack_slot(struct fetch_context *ctx, struct process *proc,
+ 		    struct arg_type_info *info, struct value *valuep)
+ {
+ 	size_t al = type_alignof(proc, info);
+@@ -121,7 +121,7 @@ allocate_stack_slot(struct fetch_context *ctx, struct Process *proc,
+ }
+ 
+ static int
+-allocate_reg(struct fetch_context *ctx, struct Process *proc,
++allocate_reg(struct fetch_context *ctx, struct process *proc,
+ 	     struct arg_type_info *info, struct value *valuep)
+ {
+ 	if (ctx->slot_n >= 8)
+@@ -152,7 +152,7 @@ allocate_reg(struct fetch_context *ctx, struct Process *proc,
+ }
+ 
+ static int
+-copy_aggregate_part(struct fetch_context *ctx, struct Process *proc,
++copy_aggregate_part(struct fetch_context *ctx, struct process *proc,
+ 		    unsigned char *buf, size_t size)
+ {
+ 	size_t slots = (size + 7) / 8;
+@@ -176,7 +176,7 @@ copy_aggregate_part(struct fetch_context *ctx, struct Process *proc,
+ }
+ 
+ static int
+-allocate_arg(struct fetch_context *ctx, struct Process *proc,
++allocate_arg(struct fetch_context *ctx, struct process *proc,
+ 	     struct arg_type_info *info, struct value *valuep)
+ {
+ 	size_t sz = type_sizeof(proc, info);
+@@ -213,7 +213,7 @@ fpreg_to_double (struct ia64_fpreg *fp) {
+ }
+ 
+ static int
+-allocate_float(struct fetch_context *ctx, struct Process *proc,
++allocate_float(struct fetch_context *ctx, struct process *proc,
+ 	       struct arg_type_info *info, struct value *valuep,
+ 	       int take_slot)
+ {
+@@ -281,7 +281,7 @@ get_hfa_type(struct arg_type_info *info, size_t *countp)
+ }
+ 
+ static int
+-allocate_hfa(struct fetch_context *ctx, struct Process *proc,
++allocate_hfa(struct fetch_context *ctx, struct process *proc,
+ 	     struct arg_type_info *info, struct value *valuep,
+ 	     enum arg_type hfa_type, size_t hfa_count)
+ {
+@@ -366,7 +366,7 @@ allocate_hfa(struct fetch_context *ctx, struct Process *proc,
+ }
+ 
+ static int
+-allocate_ret(struct fetch_context *ctx, struct Process *proc,
++allocate_ret(struct fetch_context *ctx, struct process *proc,
+ 	     struct arg_type_info *info, struct value *valuep)
+ {
+ 	size_t sz = type_sizeof(proc, info);
+@@ -405,7 +405,7 @@ allocate_ret(struct fetch_context *ctx, struct Process *proc,
+ 
+ int
+ arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
+-		    struct Process *proc,
++		    struct process *proc,
+ 		    struct arg_type_info *info, struct value *valuep)
+ {
+ 	switch (info->type) {
+@@ -446,7 +446,7 @@ arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
+ 
+ int
+ arch_fetch_retval(struct fetch_context *ctx, enum tof type,
+-		  struct Process *proc, struct arg_type_info *info,
++		  struct process *proc, struct arg_type_info *info,
+ 		  struct value *valuep)
+ {
+ 	if (fetch_context_init(proc, ctx) < 0)
+diff --git a/sysdeps/linux-gnu/ia64/plt.c b/sysdeps/linux-gnu/ia64/plt.c
+index a29488f..f6bc939 100644
+--- a/sysdeps/linux-gnu/ia64/plt.c
++++ b/sysdeps/linux-gnu/ia64/plt.c
+@@ -68,12 +68,13 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela)
+ }
+ 
+ void *
+-sym2addr(Process *proc, struct library_symbol *sym) {
++sym2addr(struct process *proc, struct library_symbol *sym)
++{
+ 	return sym->enter_addr;
+ }
+ 
+ int
+-arch_translate_address_dyn(struct Process *proc,
++arch_translate_address_dyn(struct process *proc,
+ 			   arch_addr_t addr, arch_addr_t *ret)
+ {
+ 	errno = 0;
+diff --git a/sysdeps/linux-gnu/ia64/regs.c b/sysdeps/linux-gnu/ia64/regs.c
+index cbc2744..fb79e8a 100644
+--- a/sysdeps/linux-gnu/ia64/regs.c
++++ b/sysdeps/linux-gnu/ia64/regs.c
+@@ -34,7 +34,8 @@
+ #include "common.h"
+ 
+ void *
+-get_instruction_pointer(Process *proc) {
++get_instruction_pointer(struct process *proc)
++{
+ 	unsigned long ip = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IIP, 0);
+ 	unsigned long slot =
+ 	    (ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IPSR, 0) >> 41) & 3;
+@@ -43,7 +44,8 @@ get_instruction_pointer(Process *proc) {
+ }
+ 
+ void
+-set_instruction_pointer(Process *proc, void *addr) {
++set_instruction_pointer(struct process *proc, void *addr)
++{
+ 
+ 	unsigned long newip = (unsigned long)addr;
+ 	unsigned long slot = (unsigned long)addr & 0xf;
+@@ -59,7 +61,8 @@ set_instruction_pointer(Process *proc, void *addr) {
+ }
+ 
+ void *
+-get_stack_pointer(Process *proc) {
++get_stack_pointer(struct process *proc)
++{
+ 	long l = ptrace(PTRACE_PEEKUSER, proc->pid, PT_R12, 0);
+ 	if (l == -1 && errno)
+ 		return NULL;
+@@ -67,7 +70,8 @@ get_stack_pointer(Process *proc) {
+ }
+ 
+ void *
+-get_return_addr(Process *proc, void *stack_pointer) {
++get_return_addr(struct process *proc, void *stack_pointer)
++{
+ 	long l = ptrace(PTRACE_PEEKUSER, proc->pid, PT_B0, 0);
+ 	if (l == -1 && errno)
+ 		return NULL;
+@@ -75,6 +79,7 @@ get_return_addr(Process *proc, void *stack_pointer) {
+ }
+ 
+ void
+-set_return_addr(Process *proc, void *addr) {
++set_return_addr(struct process *proc, void *addr)
++{
+ 	ptrace(PTRACE_POKEUSER, proc->pid, PT_B0, addr);
+ }
+diff --git a/sysdeps/linux-gnu/ia64/trace.c b/sysdeps/linux-gnu/ia64/trace.c
+index e608275..9e554ef 100644
+--- a/sysdeps/linux-gnu/ia64/trace.c
++++ b/sysdeps/linux-gnu/ia64/trace.c
+@@ -70,7 +70,8 @@ union cfm_t {
+ };
+ 
+ int
+-syscall_p(Process *proc, int status, int *sysnum) {
++syscall_p(struct process *proc, int status, int *sysnum)
++{
+ 	if (WIFSTOPPED(status)
+ 	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
+ 		long l = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IPSR, 0);
+@@ -141,5 +142,6 @@ syscall_p(Process *proc, int status, int *sysnum) {
+ }
+ 
+ void
+-get_arch_dep(Process *proc) {
++get_arch_dep(struct process *proc)
++{
+ }
+diff --git a/sysdeps/linux-gnu/m68k/fetch.c b/sysdeps/linux-gnu/m68k/fetch.c
+index f6d8a0b..24bd8f0 100644
+--- a/sysdeps/linux-gnu/m68k/fetch.c
++++ b/sysdeps/linux-gnu/m68k/fetch.c
+@@ -43,7 +43,7 @@ struct fetch_context
+ };
+ 
+ static int
+-fetch_register_banks(struct Process *proc, struct fetch_context *context,
++fetch_register_banks(struct process *proc, struct fetch_context *context,
+ 		     int floating)
+ {
+ 	if (ptrace(PTRACE_GETREGS, proc->pid, 0, &context->regs) < 0)
+@@ -57,7 +57,7 @@ fetch_register_banks(struct Process *proc, struct fetch_context *context,
+ }
+ 
+ struct fetch_context *
+-arch_fetch_arg_init(enum tof type, struct Process *proc,
++arch_fetch_arg_init(enum tof type, struct process *proc,
+ 		    struct arg_type_info *ret_info)
+ {
+ 	struct fetch_context *context = malloc(sizeof(*context));
+@@ -92,7 +92,7 @@ arch_fetch_arg_init(enum tof type, struct Process *proc,
+ }
+ 
+ struct fetch_context *
+-arch_fetch_arg_clone(struct Process *proc, struct fetch_context *context)
++arch_fetch_arg_clone(struct process *proc, struct fetch_context *context)
+ {
+ 	struct fetch_context *ret = malloc(sizeof(*ret));
+ 	if (ret == NULL)
+@@ -103,7 +103,7 @@ arch_fetch_arg_clone(struct Process *proc, struct fetch_context *context)
+ 
+ int
+ arch_fetch_arg_next(struct fetch_context *context, enum tof type,
+-		    struct Process *proc, struct arg_type_info *info,
++		    struct process *proc, struct arg_type_info *info,
+ 		    struct value *valuep)
+ {
+ 	size_t sz = type_sizeof(proc, info);
+@@ -143,7 +143,7 @@ arch_fetch_arg_next(struct fetch_context *context, enum tof type,
+ 
+ int
+ arch_fetch_retval(struct fetch_context *context, enum tof type,
+-		  struct Process *proc, struct arg_type_info *info,
++		  struct process *proc, struct arg_type_info *info,
+ 		  struct value *valuep)
+ {
+ 	if (fetch_register_banks(proc, context, type == LT_TOF_FUNCTIONR) < 0)
+diff --git a/sysdeps/linux-gnu/m68k/plt.c b/sysdeps/linux-gnu/m68k/plt.c
+index c1b37dd..dcd6878 100644
+--- a/sysdeps/linux-gnu/m68k/plt.c
++++ b/sysdeps/linux-gnu/m68k/plt.c
+@@ -30,6 +30,7 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
+ }
+ 
+ void *
+-sym2addr(Process *proc, struct library_symbol *sym) {
++sym2addr(struct process *proc, struct library_symbol *sym)
++{
+ 	return sym->enter_addr;
+ }
+diff --git a/sysdeps/linux-gnu/m68k/regs.c b/sysdeps/linux-gnu/m68k/regs.c
+index 4afdfbb..c2fafe1 100644
+--- a/sysdeps/linux-gnu/m68k/regs.c
++++ b/sysdeps/linux-gnu/m68k/regs.c
+@@ -36,26 +36,31 @@
+ #endif
+ 
+ void *
+-get_instruction_pointer(Process *proc) {
++get_instruction_pointer(struct process *proc)
++{
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_PC, 0);
+ }
+ 
+ void
+-set_instruction_pointer(Process *proc, void *addr) {
++set_instruction_pointer(struct process *proc, void *addr)
++{
+ 	ptrace(PTRACE_POKEUSER, proc->pid, 4 * PT_PC, addr);
+ }
+ 
+ void *
+-get_stack_pointer(Process *proc) {
++get_stack_pointer(struct process *proc)
++{
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_USP, 0);
+ }
+ 
+ void *
+-get_return_addr(Process *proc, void *stack_pointer) {
++get_return_addr(struct process *proc, void *stack_pointer)
++{
+ 	return (void *)ptrace(PTRACE_PEEKTEXT, proc->pid, stack_pointer, 0);
+ }
+ 
+ void
+-set_return_addr(Process *proc, void *addr) {
++set_return_addr(struct process *proc, void *addr)
++{
+ 	ptrace(PTRACE_POKETEXT, proc->pid, proc->stack_pointer, addr);
+ }
+diff --git a/sysdeps/linux-gnu/m68k/trace.c b/sysdeps/linux-gnu/m68k/trace.c
+index 311ffd5..01b5253 100644
+--- a/sysdeps/linux-gnu/m68k/trace.c
++++ b/sysdeps/linux-gnu/m68k/trace.c
+@@ -40,13 +40,15 @@
+ #endif
+ 
+ void
+-get_arch_dep(Process *proc) {
++get_arch_dep(struct process *proc)
++{
+ }
+ 
+ /* Returns 1 if syscall, 2 if sysret, 0 otherwise.
+  */
+ int
+-syscall_p(Process *proc, int status, int *sysnum) {
++syscall_p(struct process *proc, int status, int *sysnum)
++{
+ 	int depth;
+ 
+ 	if (WIFSTOPPED(status)
+diff --git a/sysdeps/linux-gnu/mipsel/arch.h b/sysdeps/linux-gnu/mipsel/arch.h
+index 684b546..ba1220d 100644
+--- a/sysdeps/linux-gnu/mipsel/arch.h
++++ b/sysdeps/linux-gnu/mipsel/arch.h
+@@ -1,5 +1,6 @@
+ /*
+  * This file is part of ltrace.
++ * Copyright (C) 2013 Petr Machata
+  * Copyright (C) 2006 Eric Vaitl
+  *
+  * This program is free software; you can redistribute it and/or
+@@ -43,7 +44,7 @@ struct arch_ltelf_data {
+ #define ARCH_HAVE_GET_SYMINFO
+ #define ARCH_HAVE_DYNLINK_DONE
+ #define ARCH_HAVE_ADD_PLT_ENTRY
+-#define ARCH_HAVE_ATOMIC_SINGLESTEP
++#define ARCH_HAVE_SW_SINGLESTEP
+ #define ARCH_HAVE_SYMBOL_RET
+ 
+ #define ARCH_HAVE_LIBRARY_SYMBOL_DATA
+diff --git a/sysdeps/linux-gnu/mipsel/plt.c b/sysdeps/linux-gnu/mipsel/plt.c
+index b277fbc..ce33406 100644
+--- a/sysdeps/linux-gnu/mipsel/plt.c
++++ b/sysdeps/linux-gnu/mipsel/plt.c
+@@ -104,7 +104,8 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela)
+    breakpoint changes I just add a new breakpoint for the new address.
+  */
+ void *
+-sym2addr(Process *proc, struct library_symbol *sym) {
++sym2addr(struct process *proc, struct library_symbol *sym)
++{
+     long ret;
+ 
+     if (sym->arch.pltalways
+@@ -125,7 +126,7 @@ sym2addr(Process *proc, struct library_symbol *sym) {
+ /* Address of run time loader map, used for debugging.  */
+ #define DT_MIPS_RLD_MAP         0x70000016
+ int
+-arch_find_dl_debug(struct Process *proc, arch_addr_t dyn_addr,
++arch_find_dl_debug(struct process *proc, arch_addr_t dyn_addr,
+ 		   arch_addr_t *ret)
+ {
+ 	arch_addr_t rld_addr;
+@@ -251,11 +252,11 @@ arch_elf_destroy(struct ltelf *lte)
+ 
+ /* When functions return we check if the symbol needs an updated
+    breakpoint with the resolved address.  */
+-void arch_symbol_ret(struct Process *proc, struct library_symbol *libsym)
++void arch_symbol_ret(struct process *proc, struct library_symbol *libsym)
+ {
+ 	struct breakpoint *bp;
+ 	arch_addr_t resolved_addr;
+-	struct Process *leader = proc->leader;
++	struct process *leader = proc->leader;
+ 
+ 	/* Only deal with unresolved symbols.  */
+ 	if (libsym->arch.type != MIPS_PLT_UNRESOLVED)
+@@ -302,7 +303,7 @@ err:
+ static enum callback_status
+ cb_enable_breakpoint_sym(struct library_symbol *libsym, void *data)
+ {
+-	struct Process *proc = data;
++	struct process *proc = data;
+ 	arch_addr_t bp_addr;
+ 
+ 	if (!libsym->arch.gotonly)
+@@ -329,19 +330,19 @@ cb_enable_breakpoint_sym(struct library_symbol *libsym, void *data)
+ }
+ 
+ static enum callback_status
+-cb_enable_breakpoint_lib(struct Process *proc, struct library *lib, void *data)
++cb_enable_breakpoint_lib(struct process *proc, struct library *lib, void *data)
+ {
+ 	library_each_symbol(lib, NULL, cb_enable_breakpoint_sym, proc);
+ 	return CBS_CONT;
+ }
+ 
+-void arch_dynlink_done(struct Process *proc)
++void arch_dynlink_done(struct process *proc)
+ {
+ 	proc_each_library(proc->leader, NULL, cb_enable_breakpoint_lib, NULL);
+ }
+ 
+ enum plt_status
+-arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
++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)
+ {
+@@ -350,7 +351,7 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
+ 
+ 	struct library_symbol *libsym = malloc(sizeof(*libsym));
+ 	if (libsym == NULL)
+-		return plt_fail;
++		return PLT_FAIL;
+ 
+ 	GElf_Addr addr = arch_plt_sym_val(lte, sym_index, 0);
+ 
+@@ -389,12 +390,12 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
+ 	}
+ 
+ 	*ret = libsym;
+-	return plt_ok;
++	return PLT_OK;
+ 
+ fail:
+ 	free(name);
+ 	free(libsym);
+-	return plt_fail;
++	return PLT_FAIL;
+ }
+ 
+ int
+diff --git a/sysdeps/linux-gnu/mipsel/regs.c b/sysdeps/linux-gnu/mipsel/regs.c
+index 8731ac5..19f97cb 100644
+--- a/sysdeps/linux-gnu/mipsel/regs.c
++++ b/sysdeps/linux-gnu/mipsel/regs.c
+@@ -49,7 +49,8 @@
+    \return The current instruction pointer.
+  */
+ void *
+-get_instruction_pointer(Process *proc) {
++get_instruction_pointer(struct process *proc)
++{
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0);
+ }
+ 
+@@ -63,7 +64,8 @@ get_instruction_pointer(Process *proc) {
+    we \c continue_process() after a breakpoint. Check if this is OK.
+  */
+ void
+-set_instruction_pointer(Process *proc, void *addr) {
++set_instruction_pointer(struct process *proc, void *addr)
++{
+ 	ptrace(PTRACE_POKEUSER, proc->pid, off_pc, addr);
+ }
+ 
+@@ -72,7 +74,8 @@ set_instruction_pointer(Process *proc, void *addr) {
+    \return The current stack pointer.
+  */
+ void *
+-get_stack_pointer(Process *proc) {
++get_stack_pointer(struct process *proc)
++{
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_sp, 0);
+ }
+ 
+@@ -87,11 +90,13 @@ get_stack_pointer(Process *proc) {
+    unused.
+  */
+ void *
+-get_return_addr(Process *proc, void *stack_pointer) {
++get_return_addr(struct process *proc, void *stack_pointer)
++{
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_lr, 0);
+ }
+ 
+ void
+-set_return_addr(Process *proc, void *addr) {
++set_return_addr(struct process *proc, void *addr)
++{
+ 	ptrace(PTRACE_POKEUSER, proc->pid, off_lr, addr);
+ }
+diff --git a/sysdeps/linux-gnu/mipsel/trace.c b/sysdeps/linux-gnu/mipsel/trace.c
+index db9ec21..f553166 100644
+--- a/sysdeps/linux-gnu/mipsel/trace.c
++++ b/sysdeps/linux-gnu/mipsel/trace.c
+@@ -1,5 +1,6 @@
+ /*
+  * This file is part of ltrace.
++ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2012 Edgar E. Iglesias, Axis Communications
+  * Copyright (C) 2010 Arnaud Patard, Mandriva SA
+  * Copyright (C) 2008,2009 Juan Cespedes
+@@ -64,7 +65,8 @@
+    private data area.
+  */
+ void
+-get_arch_dep(Process *proc) {
++get_arch_dep(struct process *proc)
++{
+ }
+ 
+ /**
+@@ -85,7 +87,8 @@ get_arch_dep(Process *proc) {
+    for the system calls is 4000.
+  */
+ int
+-syscall_p(Process *proc, int status, int *sysnum) {
++syscall_p(struct process *proc, int status, int *sysnum)
++{
+ 	if (WIFSTOPPED(status)
+ 			&& WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
+ 		/* get the user's pc (plus 8) */
+@@ -141,7 +144,7 @@ mips32_relative_offset (uint32_t inst)
+   return ((itype_immediate(inst) ^ 0x8000) - 0x8000) << 2;
+ }
+ 
+-int mips_next_pcs(struct Process *proc, uint32_t pc, uint32_t *newpc)
++int mips_next_pcs(struct process *proc, uint32_t pc, uint32_t *newpc)
+ {
+ 	uint32_t inst, rx;
+ 	int op;
+@@ -261,10 +264,10 @@ fail:
+ 	return 0;
+ }
+ 
+-int
+-arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
+-		       int (*add_cb)(void *addr, void *data),
+-		       void *add_cb_data)
++enum sw_singlestep_status
++arch_sw_singlestep(struct process *proc, struct breakpoint *bp,
++		   int (*add_cb)(arch_addr_t, struct sw_singlestep_data *),
++		   struct sw_singlestep_data *add_cb_data)
+ {
+ 	uint32_t pc = (uint32_t) get_instruction_pointer(proc);
+ 	uint32_t newpcs[2];
+@@ -281,11 +284,11 @@ arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
+ 		}
+ 
+ 		if (add_cb(baddr, add_cb_data) < 0)
+-			return -1;
++			return SWS_FAIL;
+ 	}
+ 
+ 	ptrace(PTRACE_SYSCALL, proc->pid, 0, 0);
+-	return 0;
++	return SWS_OK;
+ }
+ 
+ /**
+@@ -317,7 +320,8 @@ I'm not doing any floating point support here.
+ 
+ */
+ long
+-gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info)
++gimme_arg(enum tof type, struct process *proc, int arg_num,
++	  struct arg_type_info *info)
+ {
+ 	long ret;
+ 	long addr;
+diff --git a/sysdeps/linux-gnu/ppc/arch.h b/sysdeps/linux-gnu/ppc/arch.h
+index fb8768a..3b903ee 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 Petr Machata
++ * Copyright (C) 2012,2013 Petr Machata
+  * Copyright (C) 2006 Paul Gilliam
+  * Copyright (C) 2002,2004 Juan Cespedes
+  *
+@@ -37,7 +37,7 @@
+ #define ARCH_SUPPORTS_OPD
+ #endif
+ 
+-#define ARCH_HAVE_ATOMIC_SINGLESTEP
++#define ARCH_HAVE_SW_SINGLESTEP
+ #define ARCH_HAVE_ADD_PLT_ENTRY
+ #define ARCH_HAVE_TRANSLATE_ADDRESS
+ #define ARCH_HAVE_DYNLINK_DONE
+diff --git a/sysdeps/linux-gnu/ppc/fetch.c b/sysdeps/linux-gnu/ppc/fetch.c
+index 9963a1e..ed38336 100644
+--- a/sysdeps/linux-gnu/ppc/fetch.c
++++ b/sysdeps/linux-gnu/ppc/fetch.c
+@@ -31,7 +31,7 @@
+ #include "proc.h"
+ #include "value.h"
+ 
+-static int allocate_gpr(struct fetch_context *ctx, struct Process *proc,
++static int allocate_gpr(struct fetch_context *ctx, struct process *proc,
+ 			struct arg_type_info *info, struct value *valuep);
+ 
+ /* Floating point registers have the same width on 32-bit as well as
+@@ -66,7 +66,7 @@ struct fetch_context {
+ };
+ 
+ static int
+-fetch_context_init(struct Process *proc, struct fetch_context *context)
++fetch_context_init(struct process *proc, struct fetch_context *context)
+ {
+ 	context->greg = 3;
+ 	context->freg = 1;
+@@ -108,7 +108,7 @@ fetch_context_init(struct Process *proc, struct fetch_context *context)
+ }
+ 
+ struct fetch_context *
+-arch_fetch_arg_init(enum tof type, struct Process *proc,
++arch_fetch_arg_init(enum tof type, struct process *proc,
+ 		    struct arg_type_info *ret_info)
+ {
+ 	struct fetch_context *context = malloc(sizeof(*context));
+@@ -132,7 +132,7 @@ arch_fetch_arg_init(enum tof type, struct Process *proc,
+ }
+ 
+ struct fetch_context *
+-arch_fetch_arg_clone(struct Process *proc,
++arch_fetch_arg_clone(struct process *proc,
+ 		     struct fetch_context *context)
+ {
+ 	struct fetch_context *clone = malloc(sizeof(*context));
+@@ -143,7 +143,7 @@ arch_fetch_arg_clone(struct Process *proc,
+ }
+ 
+ static int
+-allocate_stack_slot(struct fetch_context *ctx, struct Process *proc,
++allocate_stack_slot(struct fetch_context *ctx, struct process *proc,
+ 		    struct arg_type_info *info, struct value *valuep)
+ {
+ 	size_t sz = type_sizeof(proc, info);
+@@ -170,7 +170,7 @@ allocate_stack_slot(struct fetch_context *ctx, struct Process *proc,
+ }
+ 
+ static uint64_t
+-read_gpr(struct fetch_context *ctx, struct Process *proc, int reg_num)
++read_gpr(struct fetch_context *ctx, struct process *proc, int reg_num)
+ {
+ 	if (proc->e_machine == EM_PPC)
+ 		return ctx->regs.r32[reg_num];
+@@ -215,7 +215,7 @@ align_small_int(unsigned char *buf, size_t w, size_t sz)
+ }
+ 
+ static int
+-allocate_gpr(struct fetch_context *ctx, struct Process *proc,
++allocate_gpr(struct fetch_context *ctx, struct process *proc,
+ 	     struct arg_type_info *info, struct value *valuep)
+ {
+ 	if (ctx->greg > 10)
+@@ -245,7 +245,7 @@ allocate_gpr(struct fetch_context *ctx, struct Process *proc,
+ }
+ 
+ static int
+-allocate_float(struct fetch_context *ctx, struct Process *proc,
++allocate_float(struct fetch_context *ctx, struct process *proc,
+ 	       struct arg_type_info *info, struct value *valuep)
+ {
+ 	int pool = proc->e_machine == EM_PPC64 ? 13 : 8;
+@@ -276,7 +276,7 @@ allocate_float(struct fetch_context *ctx, struct Process *proc,
+ }
+ 
+ static int
+-allocate_argument(struct fetch_context *ctx, struct Process *proc,
++allocate_argument(struct fetch_context *ctx, struct process *proc,
+ 		  struct arg_type_info *info, struct value *valuep)
+ {
+ 	/* Floating point types and void are handled specially.  */
+@@ -400,7 +400,7 @@ allocate_argument(struct fetch_context *ctx, struct Process *proc,
+ 
+ int
+ arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
+-		    struct Process *proc,
++		    struct process *proc,
+ 		    struct arg_type_info *info, struct value *valuep)
+ {
+ 	return allocate_argument(ctx, proc, info, valuep);
+@@ -408,7 +408,7 @@ arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
+ 
+ int
+ arch_fetch_retval(struct fetch_context *ctx, enum tof type,
+-		  struct Process *proc, struct arg_type_info *info,
++		  struct process *proc, struct arg_type_info *info,
+ 		  struct value *valuep)
+ {
+ 	if (ctx->ret_struct) {
+diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
+index f83f087..439b8e8 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 Petr Machata, Red Hat Inc.
++ * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2004,2008,2009 Juan Cespedes
+  * Copyright (C) 2006 Paul Gilliam
+  *
+@@ -125,51 +125,6 @@ host_powerpc64()
+ #endif
+ }
+ 
+-int
+-read_target_4(struct Process *proc, arch_addr_t addr, uint32_t *lp)
+-{
+-	unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0);
+-	if (l == -1UL && errno)
+-		return -1;
+-#ifdef __powerpc64__
+-	l >>= 32;
+-#endif
+-	*lp = l;
+-	return 0;
+-}
+-
+-static int
+-read_target_8(struct Process *proc, arch_addr_t addr, uint64_t *lp)
+-{
+-	unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0);
+-	if (l == -1UL && errno)
+-		return -1;
+-	if (host_powerpc64()) {
+-		*lp = l;
+-	} else {
+-		unsigned long l2 = ptrace(PTRACE_PEEKTEXT, proc->pid,
+-					  addr + 4, 0);
+-		if (l2 == -1UL && errno)
+-			return -1;
+-		*lp = ((uint64_t)l << 32) | l2;
+-	}
+-	return 0;
+-}
+-
+-int
+-read_target_long(struct Process *proc, arch_addr_t addr, uint64_t *lp)
+-{
+-	if (proc->e_machine == EM_PPC) {
+-		uint32_t w;
+-		int ret = read_target_4(proc, addr, &w);
+-		if (ret >= 0)
+-			*lp = (uint64_t)w;
+-		return ret;
+-	} else {
+-		return read_target_8(proc, addr, lp);
+-	}
+-}
+-
+ static void
+ mark_as_resolved(struct library_symbol *libsym, GElf_Addr value)
+ {
+@@ -178,14 +133,14 @@ mark_as_resolved(struct library_symbol *libsym, GElf_Addr value)
+ }
+ 
+ void
+-arch_dynlink_done(struct Process *proc)
++arch_dynlink_done(struct process *proc)
+ {
+ 	/* On PPC32 with BSS PLT, we need to enable delayed symbols.  */
+ 	struct library_symbol *libsym = NULL;
+ 	while ((libsym = proc_each_symbol(proc, libsym,
+ 					  library_symbol_delayed_cb, NULL))) {
+-		if (read_target_8(proc, libsym->enter_addr,
+-				  &libsym->arch.resolved_value) < 0) {
++		if (proc_read_64(proc, libsym->enter_addr,
++				 &libsym->arch.resolved_value) < 0) {
+ 			fprintf(stderr,
+ 				"couldn't read PLT value for %s(%p): %s\n",
+ 				libsym->name, libsym->enter_addr,
+@@ -258,12 +213,12 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela)
+  * ourselves with bias, as the values in OPD have been resolved
+  * already.  */
+ int
+-arch_translate_address_dyn(struct Process *proc,
++arch_translate_address_dyn(struct process *proc,
+ 			   arch_addr_t addr, arch_addr_t *ret)
+ {
+ 	if (proc->e_machine == EM_PPC64) {
+ 		uint64_t value;
+-		if (read_target_8(proc, addr, &value) < 0) {
++		if (proc_read_64(proc, addr, &value) < 0) {
+ 			fprintf(stderr,
+ 				"dynamic .opd translation of %p: %s\n",
+ 				addr, strerror(errno));
+@@ -324,7 +279,7 @@ load_opd_data(struct ltelf *lte, struct library *lib)
+ }
+ 
+ void *
+-sym2addr(struct Process *proc, struct library_symbol *sym)
++sym2addr(struct process *proc, struct library_symbol *sym)
+ {
+ 	return sym->enter_addr;
+ }
+@@ -560,7 +515,7 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
+ }
+ 
+ static int
+-read_plt_slot_value(struct Process *proc, GElf_Addr addr, GElf_Addr *valp)
++read_plt_slot_value(struct process *proc, GElf_Addr addr, GElf_Addr *valp)
+ {
+ 	/* On PPC64, we read from .plt, which contains 8 byte
+ 	 * addresses.  On PPC32 we read from .plt, which contains 4
+@@ -568,7 +523,7 @@ read_plt_slot_value(struct Process *proc, GElf_Addr addr, GElf_Addr *valp)
+ 	 * either can change.  */
+ 	uint64_t l;
+ 	/* XXX double cast.  */
+-	if (read_target_8(proc, (arch_addr_t)(uintptr_t)addr, &l) < 0) {
++	if (proc_read_64(proc, (arch_addr_t)(uintptr_t)addr, &l) < 0) {
+ 		fprintf(stderr, "ptrace .plt slot value @%#" PRIx64": %s\n",
+ 			addr, strerror(errno));
+ 		return -1;
+@@ -579,7 +534,7 @@ read_plt_slot_value(struct Process *proc, GElf_Addr addr, GElf_Addr *valp)
+ }
+ 
+ static int
+-unresolve_plt_slot(struct Process *proc, GElf_Addr addr, GElf_Addr value)
++unresolve_plt_slot(struct process *proc, GElf_Addr addr, GElf_Addr value)
+ {
+ 	/* We only modify plt_entry[0], which holds the resolved
+ 	 * address of the routine.  We keep the TOC and environment
+@@ -594,18 +549,18 @@ unresolve_plt_slot(struct Process *proc, GElf_Addr addr, GElf_Addr value)
+ }
+ 
+ enum plt_status
+-arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
++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)
+ {
+ 	if (lte->ehdr.e_machine == EM_PPC) {
+ 		if (lte->arch.secure_plt)
+-			return plt_default;
++			return PLT_DEFAULT;
+ 
+ 		struct library_symbol *libsym = NULL;
+ 		if (default_elf_add_plt_entry(proc, lte, a_name, rela, ndx,
+ 					      &libsym) < 0)
+-			return plt_fail;
++			return PLT_FAIL;
+ 
+ 		/* On PPC32 with BSS PLT, delay the symbol until
+ 		 * dynamic linker is done.  */
+@@ -613,7 +568,7 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
+ 		libsym->delayed = 1;
+ 
+ 		*ret = libsym;
+-		return plt_ok;
++		return PLT_OK;
+ 	}
+ 
+ 	/* PPC64.  If we have stubs, we return a chain of breakpoint
+@@ -636,7 +591,7 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
+ 
+ 	if (chain != NULL) {
+ 		*ret = chain;
+-		return plt_ok;
++		return PLT_OK;
+ 	}
+ 
+ 	/* We don't have stub symbols.  Find corresponding .plt slot,
+@@ -653,7 +608,7 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
+ 
+ 	GElf_Addr plt_slot_value;
+ 	if (read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value) < 0)
+-		return plt_fail;
++		return PLT_FAIL;
+ 
+ 	char *name = strdup(a_name);
+ 	struct library_symbol *libsym = malloc(sizeof(*libsym));
+@@ -663,7 +618,7 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
+ 	fail:
+ 		free(name);
+ 		free(libsym);
+-		return plt_fail;
++		return PLT_FAIL;
+ 	}
+ 
+ 	/* XXX The double cast should be removed when
+@@ -696,7 +651,7 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
+ 	}
+ 
+ 	*ret = libsym;
+-	return plt_ok;
++	return PLT_OK;
+ }
+ 
+ void
+@@ -712,7 +667,7 @@ arch_elf_destroy(struct ltelf *lte)
+ }
+ 
+ static void
+-dl_plt_update_bp_on_hit(struct breakpoint *bp, struct Process *proc)
++dl_plt_update_bp_on_hit(struct breakpoint *bp, struct process *proc)
+ {
+ 	debug(DEBUG_PROCESS, "pid=%d dl_plt_update_bp_on_hit %s(%p)",
+ 	      proc->pid, breakpoint_name(bp), bp->addr);
+@@ -752,7 +707,7 @@ cb_on_all_stopped(struct process_stopping_handler *self)
+ static enum callback_status
+ cb_keep_stepping_p(struct process_stopping_handler *self)
+ {
+-	struct Process *proc = self->task_enabling_breakpoint;
++	struct process *proc = self->task_enabling_breakpoint;
+ 	struct library_symbol *libsym = self->breakpoint_being_enabled->libsym;
+ 
+ 	GElf_Addr value;
+@@ -799,7 +754,7 @@ cb_keep_stepping_p(struct process_stopping_handler *self)
+ 	/* Install breakpoint to the address where the change takes
+ 	 * place.  If we fail, then that just means that we'll have to
+ 	 * singlestep the next time around as well.  */
+-	struct Process *leader = proc->leader;
++	struct process *leader = proc->leader;
+ 	if (leader == NULL || leader->arch.dl_plt_update_bp != NULL)
+ 		goto done;
+ 
+@@ -827,7 +782,7 @@ done:
+ }
+ 
+ static void
+-jump_to_entry_point(struct Process *proc, struct breakpoint *bp)
++jump_to_entry_point(struct process *proc, struct breakpoint *bp)
+ {
+ 	/* XXX The double cast should be removed when
+ 	 * arch_addr_t becomes integral type.  */
+@@ -837,10 +792,10 @@ jump_to_entry_point(struct Process *proc, struct breakpoint *bp)
+ }
+ 
+ static void
+-ppc_plt_bp_continue(struct breakpoint *bp, struct Process *proc)
++ppc_plt_bp_continue(struct breakpoint *bp, struct process *proc)
+ {
+ 	switch (bp->libsym->arch.type) {
+-		struct Process *leader;
++		struct process *leader;
+ 		void (*on_all_stopped)(struct process_stopping_handler *);
+ 		enum callback_status (*keep_stepping_p)
+ 			(struct process_stopping_handler *);
+@@ -899,7 +854,7 @@ ppc_plt_bp_continue(struct breakpoint *bp, struct Process *proc)
+  * detect both cases and do any fix-ups necessary to mend this
+  * situation.  */
+ static enum callback_status
+-detach_task_cb(struct Process *task, void *data)
++detach_task_cb(struct process *task, void *data)
+ {
+ 	struct breakpoint *bp = data;
+ 
+@@ -919,7 +874,7 @@ detach_task_cb(struct Process *task, void *data)
+ }
+ 
+ static void
+-ppc_plt_bp_retract(struct breakpoint *bp, struct Process *proc)
++ppc_plt_bp_retract(struct breakpoint *bp, struct process *proc)
+ {
+ 	/* On PPC64, we rewrite .plt with PLT entry addresses.  This
+ 	 * needs to be undone.  Unfortunately, the program may have
+@@ -975,7 +930,7 @@ arch_library_symbol_clone(struct library_symbol *retp,
+  * don't need PROC here, we can store the data in BP if it is of
+  * interest to us.  */
+ int
+-arch_breakpoint_init(struct Process *proc, struct breakpoint *bp)
++arch_breakpoint_init(struct process *proc, struct breakpoint *bp)
+ {
+ 	/* Artificial and entry-point breakpoints are plain.  */
+ 	if (bp->libsym == NULL || bp->libsym->plt_type != LS_TOPLT_EXEC)
+@@ -1012,7 +967,7 @@ arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp)
+ }
+ 
+ int
+-arch_process_init(struct Process *proc)
++arch_process_init(struct process *proc)
+ {
+ 	proc->arch.dl_plt_update_bp = NULL;
+ 	proc->arch.handler = NULL;
+@@ -1020,19 +975,19 @@ arch_process_init(struct Process *proc)
+ }
+ 
+ void
+-arch_process_destroy(struct Process *proc)
++arch_process_destroy(struct process *proc)
+ {
+ }
+ 
+ int
+-arch_process_clone(struct Process *retp, struct Process *proc)
++arch_process_clone(struct process *retp, struct process *proc)
+ {
+ 	retp->arch = proc->arch;
+ 	return 0;
+ }
+ 
+ int
+-arch_process_exec(struct Process *proc)
++arch_process_exec(struct process *proc)
+ {
+ 	return arch_process_init(proc);
+ }
+diff --git a/sysdeps/linux-gnu/ppc/regs.c b/sysdeps/linux-gnu/ppc/regs.c
+index 37f89a4..ed9b398 100644
+--- a/sysdeps/linux-gnu/ppc/regs.c
++++ b/sysdeps/linux-gnu/ppc/regs.c
+@@ -40,35 +40,32 @@
+ #endif
+ 
+ void *
+-get_instruction_pointer(Process *proc) {
++get_instruction_pointer(struct process *proc)
++{
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*PT_NIP, 0);
+ }
+ 
+ void
+-set_instruction_pointer(Process *proc, void *addr)
++set_instruction_pointer(struct process *proc, void *addr)
+ {
+ 	if (ptrace(PTRACE_POKEUSER, proc->pid, sizeof(long)*PT_NIP, addr) != 0)
+ 		error(0, errno, "set_instruction_pointer");
+ }
+ 
+ void *
+-get_stack_pointer(Process *proc) {
++get_stack_pointer(struct process *proc)
++{
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*PT_R1, 0);
+ }
+ 
+ void *
+-get_return_addr(Process *proc, void *stack_pointer) {
++get_return_addr(struct process *proc, void *stack_pointer)
++{
+ 	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*PT_LNK, 0);
+ }
+ 
+ void
+-set_return_addr(Process *proc, void *addr) {
++set_return_addr(struct process *proc, void *addr)
++{
+ 	ptrace(PTRACE_POKEUSER, proc->pid, sizeof(long)*PT_LNK, addr);
+ }
+-
+-/* Grab the value of CTR registers.  */
+-void *
+-get_count_register (Process *proc) {
+-	return (void *) ptrace (PTRACE_PEEKUSER, proc->pid,
+-				sizeof (long) * PT_CTR, 0);
+-}
+diff --git a/sysdeps/linux-gnu/ppc/trace.c b/sysdeps/linux-gnu/ppc/trace.c
+index 4357a1e..ee9a6b5 100644
+--- a/sysdeps/linux-gnu/ppc/trace.c
++++ b/sysdeps/linux-gnu/ppc/trace.c
+@@ -1,6 +1,6 @@
+ /*
+  * This file is part of ltrace.
+- * Copyright (C) 2010,2012 Petr Machata, Red Hat Inc.
++ * Copyright (C) 2010,2012,2013 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2011 Andreas Schwab
+  * Copyright (C) 2002,2004,2008,2009 Juan Cespedes
+  * Copyright (C) 2008 Luis Machado, IBM Corporation
+@@ -49,7 +49,8 @@
+ #endif
+ 
+ void
+-get_arch_dep(Process *proc) {
++get_arch_dep(struct process *proc)
++{
+ #ifdef __powerpc64__
+ 	proc->mask_32bit = (proc->e_machine == EM_PPC);
+ #endif
+@@ -59,7 +60,8 @@ get_arch_dep(Process *proc) {
+ 
+ /* Returns 1 if syscall, 2 if sysret, 0 otherwise. */
+ int
+-syscall_p(Process *proc, int status, int *sysnum) {
++syscall_p(struct process *proc, int status, int *sysnum)
++{
+ 	if (WIFSTOPPED(status)
+ 	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
+ 		long pc = (long)get_instruction_pointer(proc);
+@@ -84,18 +86,15 @@ syscall_p(Process *proc, int status, int *sysnum) {
+ 
+ /* The atomic skip code is mostly taken from GDB.  */
+ 
+-/* In plt.h.  XXX make this official interface.  */
+-int read_target_4(struct Process *proc, arch_addr_t addr, uint32_t *lp);
+-
+-int
+-arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
+-		       int (*add_cb)(void *addr, void *data),
+-		       void *add_cb_data)
++enum sw_singlestep_status
++arch_sw_singlestep(struct process *proc, struct breakpoint *sbp,
++		   int (*add_cb)(arch_addr_t, struct sw_singlestep_data *),
++		   struct sw_singlestep_data *add_cb_data)
+ {
+ 	arch_addr_t ip = get_instruction_pointer(proc);
+ 	struct breakpoint *other = address2bpstruct(proc->leader, ip);
+ 
+-	debug(1, "arch_atomic_singlestep pid=%d addr=%p %s(%p)",
++	debug(1, "arch_sw_singlestep pid=%d addr=%p %s(%p)",
+ 	      proc->pid, ip, breakpoint_name(sbp), sbp->addr);
+ 
+ 	/* If the original instruction was lwarx/ldarx, we can't
+@@ -107,15 +106,15 @@ arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
+ 	} u;
+ 	if (other != NULL) {
+ 		memcpy(u.buf, sbp->orig_value, BREAKPOINT_LENGTH);
+-	} else if (read_target_4(proc, ip, &u.insn) < 0) {
++	} else if (proc_read_32(proc, ip, &u.insn) < 0) {
+ 		fprintf(stderr, "couldn't read instruction at IP %p\n", ip);
+ 		/* Do the normal singlestep.  */
+-		return 1;
++		return SWS_HW;
+ 	}
+ 
+ 	if ((u.insn & LWARX_MASK) != LWARX_INSTRUCTION
+ 	    && (u.insn & LWARX_MASK) != LDARX_INSTRUCTION)
+-		return 1;
++		return SWS_HW;
+ 
+ 	debug(1, "singlestep over atomic block at %p", ip);
+ 
+@@ -125,7 +124,7 @@ arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
+ 		addr += 4;
+ 		unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0);
+ 		if (l == (unsigned long)-1 && errno)
+-			return -1;
++			return SWS_FAIL;
+ 		uint32_t insn;
+ #ifdef __powerpc64__
+ 		insn = l >> 32;
+@@ -140,7 +139,7 @@ arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
+ 			debug(1, "pid=%d, branch in atomic block from %p to %p",
+ 			      proc->pid, addr, branch_addr);
+ 			if (add_cb(branch_addr, add_cb_data) < 0)
+-				return -1;
++				return SWS_FAIL;
+ 		}
+ 
+ 		/* Assume that the atomic sequence ends with a
+@@ -157,22 +156,22 @@ arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
+ 		if (insn_count > 16) {
+ 			fprintf(stderr, "[%d] couldn't find end of atomic block"
+ 				" at %p\n", proc->pid, ip);
+-			return -1;
++			return SWS_FAIL;
+ 		}
+ 	}
+ 
+ 	/* Put the breakpoint to the next instruction.  */
+ 	addr += 4;
+ 	if (add_cb(addr, add_cb_data) < 0)
+-		return -1;
++		return SWS_FAIL;
+ 
+ 	debug(1, "PTRACE_CONT");
+ 	ptrace(PTRACE_CONT, proc->pid, 0, 0);
+-	return 0;
++	return SWS_OK;
+ }
+ 
+ size_t
+-arch_type_sizeof(struct Process *proc, struct arg_type_info *info)
++arch_type_sizeof(struct process *proc, struct arg_type_info *info)
+ {
+ 	if (proc == NULL)
+ 		return (size_t)-2;
+@@ -215,7 +214,7 @@ arch_type_sizeof(struct Process *proc, struct arg_type_info *info)
+ }
+ 
+ size_t
+-arch_type_alignof(struct Process *proc, struct arg_type_info *info)
++arch_type_alignof(struct process *proc, struct arg_type_info *info)
+ {
+ 	if (proc == NULL)
+ 		return (size_t)-2;
+diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c
+index 5adfb16..d69c985 100644
+--- a/sysdeps/linux-gnu/proc.c
++++ b/sysdeps/linux-gnu/proc.c
+@@ -177,44 +177,45 @@ process_status_cb(const char *line, const char *prefix, void *data)
+ 	} while (0)
+ 
+ 	switch (c) {
+-	case 'Z': RETURN(ps_zombie);
+-	case 't': RETURN(ps_tracing_stop);
++	case 'Z': RETURN(PS_ZOMBIE);
++	case 't': RETURN(PS_TRACING_STOP);
+ 	case 'T':
+ 		/* This can be either "T (stopped)" or, for older
+ 		 * kernels, "T (tracing stop)".  */
+ 		if (!strcmp(status, "T (stopped)\n"))
+-			RETURN(ps_stop);
++			RETURN(PS_STOP);
+ 		else if (!strcmp(status, "T (tracing stop)\n"))
+-			RETURN(ps_tracing_stop);
++			RETURN(PS_TRACING_STOP);
+ 		else {
+ 			fprintf(stderr, "Unknown process status: %s",
+ 				status);
+-			RETURN(ps_stop); /* Some sort of stop
++			RETURN(PS_STOP); /* Some sort of stop
+ 					  * anyway.  */
+ 		}
+ 	case 'D':
+-	case 'S': RETURN(ps_sleeping);
++	case 'S': RETURN(PS_SLEEPING);
+ 	}
+ 
+-	RETURN(ps_other);
++	RETURN(PS_OTHER);
+ #undef RETURN
+ }
+ 
+ enum process_status
+ process_status(pid_t pid)
+ {
+-	enum process_status ret = ps_invalid;
++	enum process_status ret = PS_INVALID;
+ 	FILE * file = open_status_file(pid);
+ 	if (file != NULL) {
+ 		each_line_starting(file, "State:\t", &process_status_cb, &ret);
+ 		fclose(file);
+-		if (ret == ps_invalid)
++		if (ret == PS_INVALID)
+ 			fprintf(stderr, "process_status %d: %s", pid,
+ 				strerror(errno));
+-	} else
++	} else {
+ 		/* If the file is not present, the process presumably
+ 		 * exited already.  */
+-		ret = ps_zombie;
++		ret = PS_ZOMBIE;
++	}
+ 
+ 	return ret;
+ }
+@@ -279,7 +280,7 @@ process_tasks(pid_t pid, pid_t **ret_tasks, size_t *ret_n)
+  * ABI object, as theorized about somewhere on pmachata/revamp
+  * branch.  */
+ static void *
+-select_32_64(struct Process *proc, void *p32, void *p64)
++select_32_64(struct process *proc, void *p32, void *p64)
+ {
+ 	if (sizeof(long) == 4 || proc->mask_32bit)
+ 		return p32;
+@@ -288,7 +289,7 @@ select_32_64(struct Process *proc, void *p32, void *p64)
+ }
+ 
+ static int
+-fetch_dyn64(struct Process *proc, arch_addr_t *addr, Elf64_Dyn *ret)
++fetch_dyn64(struct process *proc, arch_addr_t *addr, Elf64_Dyn *ret)
+ {
+ 	if (umovebytes(proc, *addr, ret, sizeof(*ret)) != sizeof(*ret))
+ 		return -1;
+@@ -297,7 +298,7 @@ fetch_dyn64(struct Process *proc, arch_addr_t *addr, Elf64_Dyn *ret)
+ }
+ 
+ static int
+-fetch_dyn32(struct Process *proc, arch_addr_t *addr, Elf64_Dyn *ret)
++fetch_dyn32(struct process *proc, arch_addr_t *addr, Elf64_Dyn *ret)
+ {
+ 	Elf32_Dyn dyn;
+ 	if (umovebytes(proc, *addr, &dyn, sizeof(dyn)) != sizeof(dyn))
+@@ -311,14 +312,14 @@ fetch_dyn32(struct Process *proc, arch_addr_t *addr, Elf64_Dyn *ret)
+ }
+ 
+ static int (*
+-dyn_fetcher(struct Process *proc))(struct Process *,
++dyn_fetcher(struct process *proc))(struct process *,
+ 				   arch_addr_t *, Elf64_Dyn *)
+ {
+ 	return select_32_64(proc, fetch_dyn32, fetch_dyn64);
+ }
+ 
+ int
+-proc_find_dynamic_entry_addr(struct Process *proc, arch_addr_t src_addr,
++proc_find_dynamic_entry_addr(struct process *proc, arch_addr_t src_addr,
+ 			     int d_tag, arch_addr_t *ret)
+ {
+ 	debug(DEBUG_FUNCTION, "find_dynamic_entry()");
+@@ -364,7 +365,7 @@ struct lt_link_map_32 LT_LINK_MAP(32);
+ struct lt_link_map_64 LT_LINK_MAP(64);
+ 
+ static int
+-fetch_lm64(struct Process *proc, arch_addr_t addr,
++fetch_lm64(struct process *proc, arch_addr_t addr,
+ 	   struct lt_link_map_64 *ret)
+ {
+ 	if (umovebytes(proc, addr, ret, sizeof(*ret)) != sizeof(*ret))
+@@ -373,7 +374,7 @@ fetch_lm64(struct Process *proc, arch_addr_t addr,
+ }
+ 
+ static int
+-fetch_lm32(struct Process *proc, arch_addr_t addr,
++fetch_lm32(struct process *proc, arch_addr_t addr,
+ 	   struct lt_link_map_64 *ret)
+ {
+ 	struct lt_link_map_32 lm;
+@@ -390,7 +391,7 @@ fetch_lm32(struct Process *proc, arch_addr_t addr,
+ }
+ 
+ static int (*
+-lm_fetcher(struct Process *proc))(struct Process *,
++lm_fetcher(struct process *proc))(struct process *,
+ 				  arch_addr_t, struct lt_link_map_64 *)
+ {
+ 	return select_32_64(proc, fetch_lm32, fetch_lm64);
+@@ -410,7 +411,7 @@ struct lt_r_debug_32 LT_R_DEBUG(32);
+ struct lt_r_debug_64 LT_R_DEBUG(64);
+ 
+ static int
+-fetch_rd64(struct Process *proc, arch_addr_t addr,
++fetch_rd64(struct process *proc, arch_addr_t addr,
+ 	   struct lt_r_debug_64 *ret)
+ {
+ 	if (umovebytes(proc, addr, ret, sizeof(*ret)) != sizeof(*ret))
+@@ -419,7 +420,7 @@ fetch_rd64(struct Process *proc, arch_addr_t addr,
+ }
+ 
+ static int
+-fetch_rd32(struct Process *proc, arch_addr_t addr,
++fetch_rd32(struct process *proc, arch_addr_t addr,
+ 	   struct lt_r_debug_64 *ret)
+ {
+ 	struct lt_r_debug_32 rd;
+@@ -436,7 +437,7 @@ fetch_rd32(struct Process *proc, arch_addr_t addr,
+ }
+ 
+ static int (*
+-rdebug_fetcher(struct Process *proc))(struct Process *,
++rdebug_fetcher(struct process *proc))(struct process *,
+ 				      arch_addr_t, struct lt_r_debug_64 *)
+ {
+ 	return select_32_64(proc, fetch_rd32, fetch_rd64);
+@@ -463,13 +464,13 @@ fetch_auxv32_entry(int fd, Elf64_auxv_t *ret)
+ }
+ 
+ static int (*
+-auxv_fetcher(struct Process *proc))(int, Elf64_auxv_t *)
++auxv_fetcher(struct process *proc))(int, Elf64_auxv_t *)
+ {
+ 	return select_32_64(proc, fetch_auxv32_entry, fetch_auxv64_entry);
+ }
+ 
+ static void
+-crawl_linkmap(struct Process *proc, struct lt_r_debug_64 *dbg)
++crawl_linkmap(struct process *proc, struct lt_r_debug_64 *dbg)
+ {
+ 	debug (DEBUG_FUNCTION, "crawl_linkmap()");
+ 
+@@ -551,7 +552,7 @@ crawl_linkmap(struct Process *proc, struct lt_r_debug_64 *dbg)
+ }
+ 
+ static int
+-load_debug_struct(struct Process *proc, struct lt_r_debug_64 *ret)
++load_debug_struct(struct process *proc, struct lt_r_debug_64 *ret)
+ {
+ 	debug(DEBUG_FUNCTION, "load_debug_struct");
+ 
+@@ -564,7 +565,7 @@ load_debug_struct(struct Process *proc, struct lt_r_debug_64 *ret)
+ }
+ 
+ static void
+-rdebug_bp_on_hit(struct breakpoint *bp, struct Process *proc)
++rdebug_bp_on_hit(struct breakpoint *bp, struct process *proc)
+ {
+ 	debug(DEBUG_FUNCTION, "arch_check_dbg");
+ 
+@@ -595,7 +596,7 @@ rdebug_bp_on_hit(struct breakpoint *bp, struct Process *proc)
+ 
+ #ifndef ARCH_HAVE_FIND_DL_DEBUG
+ int
+-arch_find_dl_debug(struct Process *proc, arch_addr_t dyn_addr,
++arch_find_dl_debug(struct process *proc, arch_addr_t dyn_addr,
+ 		   arch_addr_t *ret)
+ {
+ 	return proc_find_dynamic_entry_addr(proc, dyn_addr, DT_DEBUG, ret);
+@@ -603,7 +604,7 @@ arch_find_dl_debug(struct Process *proc, arch_addr_t dyn_addr,
+ #endif
+ 
+ int
+-linkmap_init(struct Process *proc, arch_addr_t dyn_addr)
++linkmap_init(struct process *proc, arch_addr_t dyn_addr)
+ {
+ 	debug(DEBUG_FUNCTION, "linkmap_init(%d, dyn_addr=%p)", proc->pid, dyn_addr);
+ 
+@@ -648,13 +649,13 @@ task_kill (pid_t pid, int sig)
+ }
+ 
+ void
+-process_removed(struct Process *proc)
++process_removed(struct process *proc)
+ {
+ 	delete_events_for(proc);
+ }
+ 
+ int
+-process_get_entry(struct Process *proc,
++process_get_entry(struct process *proc,
+ 		  arch_addr_t *entryp,
+ 		  arch_addr_t *interp_biasp)
+ {
+@@ -706,7 +707,7 @@ process_get_entry(struct Process *proc,
+ }
+ 
+ int
+-os_process_init(struct Process *proc)
++os_process_init(struct process *proc)
+ {
+ 	proc->os.debug_addr = 0;
+ 	proc->os.debug_state = 0;
+@@ -714,19 +715,19 @@ os_process_init(struct Process *proc)
+ }
+ 
+ void
+-os_process_destroy(struct Process *proc)
++os_process_destroy(struct process *proc)
+ {
+ }
+ 
+ int
+-os_process_clone(struct Process *retp, struct Process *proc)
++os_process_clone(struct process *retp, struct process *proc)
+ {
+ 	retp->os = proc->os;
+ 	return 0;
+ }
+ 
+ int
+-os_process_exec(struct Process *proc)
++os_process_exec(struct process *proc)
+ {
+ 	return 0;
+ }
+diff --git a/sysdeps/linux-gnu/s390/fetch.c b/sysdeps/linux-gnu/s390/fetch.c
+index fa8f42d..0b68dbc 100644
+--- a/sysdeps/linux-gnu/s390/fetch.c
++++ b/sysdeps/linux-gnu/s390/fetch.c
+@@ -61,7 +61,7 @@ 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)
+ {
+ 	ptrace_area parea;
+ 	parea.len = sizeof(ctx->regs);
+@@ -76,7 +76,7 @@ fetch_register_banks(struct Process *proc, struct fetch_context *ctx)
+ }
+ 
+ static int
+-fetch_context_init(struct Process *proc, struct fetch_context *context)
++fetch_context_init(struct process *proc, struct fetch_context *context)
+ {
+ 	context->greg = 2;
+ 	context->freg = 0;
+@@ -84,7 +84,7 @@ fetch_context_init(struct Process *proc, struct fetch_context *context)
+ }
+ 
+ struct fetch_context *
+-arch_fetch_arg_init(enum tof type, struct Process *proc,
++arch_fetch_arg_init(enum tof type, struct process *proc,
+ 		    struct arg_type_info *ret_info)
+ {
+ 	struct fetch_context *context = malloc(sizeof(*context));
+@@ -105,7 +105,7 @@ arch_fetch_arg_init(enum tof type, struct Process *proc,
+ }
+ 
+ struct fetch_context *
+-arch_fetch_arg_clone(struct Process *proc,
++arch_fetch_arg_clone(struct process *proc,
+ 		     struct fetch_context *context)
+ {
+ 	struct fetch_context *clone = malloc(sizeof(*context));
+@@ -116,7 +116,7 @@ arch_fetch_arg_clone(struct Process *proc,
+ }
+ 
+ static int
+-allocate_stack_slot(struct fetch_context *ctx, struct Process *proc,
++allocate_stack_slot(struct fetch_context *ctx, struct process *proc,
+ 		    struct arg_type_info *info, struct value *valuep,
+ 		    size_t sz)
+ {
+@@ -148,7 +148,7 @@ copy_gpr(struct fetch_context *ctx, struct value *valuep, int regno)
+ }
+ 
+ static int
+-allocate_gpr(struct fetch_context *ctx, struct Process *proc,
++allocate_gpr(struct fetch_context *ctx, struct process *proc,
+ 	     struct arg_type_info *info, struct value *valuep,
+ 	     size_t sz)
+ {
+@@ -160,7 +160,7 @@ allocate_gpr(struct fetch_context *ctx, struct Process *proc,
+ }
+ 
+ static int
+-allocate_gpr_pair(struct fetch_context *ctx, struct Process *proc,
++allocate_gpr_pair(struct fetch_context *ctx, struct process *proc,
+ 		  struct arg_type_info *info, struct value *valuep,
+ 		  size_t sz)
+ {
+@@ -191,7 +191,7 @@ allocate_gpr_pair(struct fetch_context *ctx, struct Process *proc,
+ }
+ 
+ static int
+-allocate_fpr(struct fetch_context *ctx, struct Process *proc,
++allocate_fpr(struct fetch_context *ctx, struct process *proc,
+ 	     struct arg_type_info *info, struct value *valuep,
+ 	     size_t sz)
+ {
+@@ -212,7 +212,7 @@ allocate_fpr(struct fetch_context *ctx, struct Process *proc,
+ 
+ int
+ arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
+-		    struct Process *proc,
++		    struct process *proc,
+ 		    struct arg_type_info *info, struct value *valuep)
+ {
+ 	size_t sz = type_sizeof(proc, info);
+@@ -267,7 +267,7 @@ arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
+ 
+ int
+ arch_fetch_retval(struct fetch_context *ctx, enum tof type,
+-		  struct Process *proc, struct arg_type_info *info,
++		  struct process *proc, struct arg_type_info *info,
+ 		  struct value *valuep)
+ {
+ 	if (info->type == ARGTYPE_STRUCT) {
+diff --git a/sysdeps/linux-gnu/s390/plt.c b/sysdeps/linux-gnu/s390/plt.c
+index 5f612e5..8893d45 100644
+--- a/sysdeps/linux-gnu/s390/plt.c
++++ b/sysdeps/linux-gnu/s390/plt.c
+@@ -29,6 +29,7 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
+ }
+ 
+ void *
+-sym2addr(Process *proc, struct library_symbol *sym) {
++sym2addr(struct process *proc, struct library_symbol *sym)
++{
+ 	return sym->enter_addr;
+ }
+diff --git a/sysdeps/linux-gnu/s390/regs.c b/sysdeps/linux-gnu/s390/regs.c
+index 0592ccd..44e8f67 100644
+--- a/sysdeps/linux-gnu/s390/regs.c
++++ b/sysdeps/linux-gnu/s390/regs.c
+@@ -46,7 +46,8 @@
+ #endif
+ 
+ void *
+-get_instruction_pointer(Process *proc) {
++get_instruction_pointer(struct process *proc)
++{
+ 	long ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_PSWADDR, 0) & PSW_MASK;
+ #ifdef __s390x__
+ 	if (proc->mask_32bit)
+@@ -56,7 +57,8 @@ get_instruction_pointer(Process *proc) {
+ }
+ 
+ void
+-set_instruction_pointer(Process *proc, void *addr) {
++set_instruction_pointer(struct process *proc, void *addr)
++{
+ #ifdef __s390x__
+ 	if (proc->mask_32bit)
+ 		addr = (void *)((long)addr & PSW_MASK31);
+@@ -65,7 +67,8 @@ set_instruction_pointer(Process *proc, void *addr) {
+ }
+ 
+ void *
+-get_stack_pointer(Process *proc) {
++get_stack_pointer(struct process *proc)
++{
+ 	long ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR15, 0) & PSW_MASK;
+ #ifdef __s390x__
+ 	if (proc->mask_32bit)
+@@ -75,7 +78,8 @@ get_stack_pointer(Process *proc) {
+ }
+ 
+ void *
+-get_return_addr(Process *proc, void *stack_pointer) {
++get_return_addr(struct process *proc, void *stack_pointer)
++{
+ 	long ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR14, 0) & PSW_MASK;
+ #ifdef __s390x__
+ 	if (proc->mask_32bit)
+@@ -85,7 +89,8 @@ get_return_addr(Process *proc, void *stack_pointer) {
+ }
+ 
+ void
+-set_return_addr(Process *proc, void *addr) {
++set_return_addr(struct process *proc, void *addr)
++{
+ #ifdef __s390x__
+ 	if (proc->mask_32bit)
+ 		addr = (void *)((long)addr & PSW_MASK31);
+diff --git a/sysdeps/linux-gnu/s390/trace.c b/sysdeps/linux-gnu/s390/trace.c
+index b9e05ff..78b04c3 100644
+--- a/sysdeps/linux-gnu/s390/trace.c
++++ b/sysdeps/linux-gnu/s390/trace.c
+@@ -43,7 +43,8 @@
+ #endif
+ 
+ void
+-get_arch_dep(Process *proc) {
++get_arch_dep(struct process *proc)
++{
+ #ifdef __s390x__
+ 	unsigned long psw;
+ 
+@@ -64,7 +65,8 @@ get_arch_dep(Process *proc) {
+ /* Returns 1 if syscall, 2 if sysret, 0 otherwise.
+  */
+ int
+-syscall_p(Process *proc, int status, int *sysnum) {
++syscall_p(struct process *proc, int status, int *sysnum)
++{
+ 	long pc, opcode, offset_reg, scno, tmp;
+ 	void *svc_addr;
+ 	int gpr_offset[16] = { PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
+@@ -175,7 +177,7 @@ syscall_p(Process *proc, int status, int *sysnum) {
+ }
+ 
+ size_t
+-arch_type_sizeof(struct Process *proc, struct arg_type_info *info)
++arch_type_sizeof(struct process *proc, struct arg_type_info *info)
+ {
+ 	if (proc == NULL)
+ 		return (size_t)-2;
+@@ -217,7 +219,7 @@ arch_type_sizeof(struct Process *proc, struct arg_type_info *info)
+ }
+ 
+ size_t
+-arch_type_alignof(struct Process *proc, struct arg_type_info *info)
++arch_type_alignof(struct process *proc, struct arg_type_info *info)
+ {
+ 	if (proc == NULL)
+ 		return (size_t)-2;
+diff --git a/sysdeps/linux-gnu/sparc/plt.c b/sysdeps/linux-gnu/sparc/plt.c
+index 40bbabc..3d2e589 100644
+--- a/sysdeps/linux-gnu/sparc/plt.c
++++ b/sysdeps/linux-gnu/sparc/plt.c
+@@ -28,6 +28,7 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
+ }
+ 
+ void *
+-sym2addr(Process *proc, struct library_symbol *sym) {
++sym2addr(struct process *proc, struct library_symbol *sym)
++{
+ 	return sym->enter_addr;
+ }
+diff --git a/sysdeps/linux-gnu/sparc/regs.c b/sysdeps/linux-gnu/sparc/regs.c
+index 5e5ad20..8431c9b 100644
+--- a/sysdeps/linux-gnu/sparc/regs.c
++++ b/sysdeps/linux-gnu/sparc/regs.c
+@@ -27,7 +27,8 @@
+ #include "common.h"
+ 
+ void *
+-get_instruction_pointer(Process *proc) {
++get_instruction_pointer(struct process *proc)
++{
+ 	proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
+ 	if (a->valid)
+ 		return (void *)a->regs.pc;
+@@ -35,14 +36,16 @@ get_instruction_pointer(Process *proc) {
+ }
+ 
+ void
+-set_instruction_pointer(Process *proc, void *addr) {
++set_instruction_pointer(struct process *proc, void *addr)
++{
+ 	proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
+ 	if (a->valid)
+ 		a->regs.pc = (long)addr;
+ }
+ 
+ void *
+-get_stack_pointer(Process *proc) {
++get_stack_pointer(struct process *proc)
++{
+ 	proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
+ 	if (a->valid)
+ 		return (void *)a->regs.u_regs[UREG_I5];
+@@ -50,7 +53,8 @@ get_stack_pointer(Process *proc) {
+ }
+ 
+ void *
+-get_return_addr(Process *proc, void *stack_pointer) {
++get_return_addr(struct process *proc, void *stack_pointer)
++{
+ 	proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
+ 	unsigned int t;
+ 	if (!a->valid)
+@@ -63,7 +67,8 @@ get_return_addr(Process *proc, void *stack_pointer) {
+ }
+ 
+ void
+-set_return_addr(Process *proc, void *addr) {
++set_return_addr(struct process *proc, void *addr)
++{
+ 	proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
+ 	if (!a->valid)
+ 		return;
+diff --git a/sysdeps/linux-gnu/sparc/trace.c b/sysdeps/linux-gnu/sparc/trace.c
+index e1725ff..078d406 100644
+--- a/sysdeps/linux-gnu/sparc/trace.c
++++ b/sysdeps/linux-gnu/sparc/trace.c
+@@ -31,7 +31,8 @@
+ #include "common.h"
+ 
+ void
+-get_arch_dep(Process *proc) {
++get_arch_dep(struct process *proc)
++{
+ 	proc_archdep *a;
+ 	if (!proc->arch_ptr)
+ 		proc->arch_ptr = (void *)malloc(sizeof(proc_archdep));
+@@ -43,7 +44,8 @@ get_arch_dep(Process *proc) {
+  * Returns -1 otherwise
+  */
+ int
+-syscall_p(Process *proc, int status, int *sysnum) {
++syscall_p(struct process *proc, int status, int *sysnum)
++{
+ 	if (WIFSTOPPED(status)
+ 	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
+ 		void *ip = get_instruction_pointer(proc);
+@@ -66,7 +68,8 @@ syscall_p(Process *proc, int status, int *sysnum) {
+ }
+ 
+ long
+-gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info)
++gimme_arg(enum tof type, struct process *proc, int arg_num,
++	  struct arg_type_info *info)
+ {
+ 	proc_archdep *a = (proc_archdep *) proc->arch_ptr;
+ 	if (!a->valid) {
+diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
+index e13b761..e57a5ed 100644
+--- a/sysdeps/linux-gnu/trace.c
++++ b/sysdeps/linux-gnu/trace.c
+@@ -1,6 +1,6 @@
+ /*
+  * This file is part of ltrace.
+- * Copyright (C) 2007,2011,2012 Petr Machata, Red Hat Inc.
++ * Copyright (C) 2007,2011,2012,2013 Petr Machata, Red Hat Inc.
+  * Copyright (C) 2010 Joe Damato
+  * Copyright (C) 1998,2002,2003,2004,2008,2009 Juan Cespedes
+  * Copyright (C) 2006 Ian Wienand
+@@ -111,7 +111,7 @@ trace_pid(pid_t pid)
+ }
+ 
+ void
+-trace_set_options(struct Process *proc)
++trace_set_options(struct process *proc)
+ {
+ 	if (proc->tracesysgood & 0x80)
+ 		return;
+@@ -148,8 +148,8 @@ static enum ecb_status
+ event_for_pid(Event *event, void *data)
+ {
+ 	if (event->proc != NULL && event->proc->pid == (pid_t)(uintptr_t)data)
+-		return ecb_yield;
+-	return ecb_cont;
++		return ECB_YIELD;
++	return ECB_CONT;
+ }
+ 
+ static int
+@@ -206,7 +206,7 @@ add_task_info(struct pid_set *pids, pid_t pid)
+ }
+ 
+ static enum callback_status
+-task_stopped(struct Process *task, void *data)
++task_stopped(struct process *task, void *data)
+ {
+ 	enum process_status st = process_status(task->pid);
+ 	if (data != NULL)
+@@ -217,13 +217,13 @@ task_stopped(struct Process *task, void *data)
+ 	 * the meantime.  This can happen when the whole thread group
+ 	 * is terminating.  */
+ 	switch (st) {
+-	case ps_invalid:
+-	case ps_tracing_stop:
+-	case ps_zombie:
++	case PS_INVALID:
++	case PS_TRACING_STOP:
++	case PS_ZOMBIE:
+ 		return CBS_CONT;
+-	case ps_sleeping:
+-	case ps_stop:
+-	case ps_other:
++	case PS_SLEEPING:
++	case PS_STOP:
++	case PS_OTHER:
+ 		return CBS_STOP;
+ 	}
+ 
+@@ -232,7 +232,7 @@ task_stopped(struct Process *task, void *data)
+ 
+ /* Task is blocked if it's stopped, or if it's a vfork parent.  */
+ static enum callback_status
+-task_blocked(struct Process *task, void *data)
++task_blocked(struct process *task, void *data)
+ {
+ 	struct pid_set *pids = data;
+ 	struct pid_task *task_info = get_task_info(pids, task->pid);
+@@ -246,7 +246,7 @@ task_blocked(struct Process *task, void *data)
+ static Event *process_vfork_on_event(struct event_handler *super, Event *event);
+ 
+ static enum callback_status
+-task_vforked(struct Process *task, void *data)
++task_vforked(struct process *task, void *data)
+ {
+ 	if (task->event_handler != NULL
+ 	    && task->event_handler->on_event == &process_vfork_on_event)
+@@ -255,15 +255,15 @@ task_vforked(struct Process *task, void *data)
+ }
+ 
+ static int
+-is_vfork_parent(struct Process *task)
++is_vfork_parent(struct process *task)
+ {
+ 	return each_task(task->leader, NULL, &task_vforked, NULL) != NULL;
+ }
+ 
+ static enum callback_status
+-send_sigstop(struct Process *task, void *data)
++send_sigstop(struct process *task, void *data)
+ {
+-	struct Process *leader = task->leader;
++	struct process *leader = task->leader;
+ 	struct pid_set *pids = data;
+ 
+ 	/* Look for pre-existing task record, or add new.  */
+@@ -299,8 +299,8 @@ send_sigstop(struct Process *task, void *data)
+ 	 * vforked process.  We set up event handler specially to hint
+ 	 * us.  In that case parent is in D state, which we use to
+ 	 * weed out unnecessary looping.  */
+-	if (st == ps_sleeping
+-	    && is_vfork_parent (task)) {
++	if (st == PS_SLEEPING
++	    && is_vfork_parent(task)) {
+ 		task_info->vforked = 1;
+ 		return CBS_CONT;
+ 	}
+@@ -321,7 +321,7 @@ send_sigstop(struct Process *task, void *data)
+    breakpoint where IP points and let the process continue.  After
+    this the breakpoint can be retracted and the process detached.  */
+ static void
+-ugly_workaround(struct Process *proc)
++ugly_workaround(struct process *proc)
+ {
+ 	void *ip = get_instruction_pointer(proc);
+ 	struct breakpoint *sbp = dict_find_entry(proc->leader->breakpoints, ip);
+@@ -334,7 +334,7 @@ ugly_workaround(struct Process *proc)
+ 
+ static void
+ process_stopping_done(struct process_stopping_handler *self,
+-		      struct Process *leader)
++		      struct process *leader)
+ {
+ 	debug(DEBUG_PROCESS, "process stopping done %d",
+ 	      self->task_enabling_breakpoint->pid);
+@@ -351,7 +351,7 @@ process_stopping_done(struct process_stopping_handler *self,
+ 
+ 	if (self->exiting) {
+ 	ugly_workaround:
+-		self->state = psh_ugly_workaround;
++		self->state = PSH_UGLY_WORKAROUND;
+ 		ugly_workaround(self->task_enabling_breakpoint);
+ 	} else {
+ 		switch ((self->ugly_workaround_p)(self)) {
+@@ -377,11 +377,11 @@ undo_breakpoint(Event *event, void *data)
+ 	    && event->proc->leader == data
+ 	    && event->type == EVENT_BREAKPOINT)
+ 		set_instruction_pointer(event->proc, event->e_un.brk_addr);
+-	return ecb_cont;
++	return ECB_CONT;
+ }
+ 
+ static enum callback_status
+-untrace_task(struct Process *task, void *data)
++untrace_task(struct process *task, void *data)
+ {
+ 	if (task != data)
+ 		untrace_pid(task->pid);
+@@ -389,7 +389,7 @@ untrace_task(struct Process *task, void *data)
+ }
+ 
+ static enum callback_status
+-remove_task(struct Process *task, void *data)
++remove_task(struct process *task, void *data)
+ {
+ 	/* Don't untrace leader just yet.  */
+ 	if (task != data)
+@@ -398,14 +398,14 @@ remove_task(struct Process *task, void *data)
+ }
+ 
+ static enum callback_status
+-retract_breakpoint_cb(struct Process *proc, struct breakpoint *bp, void *data)
++retract_breakpoint_cb(struct process *proc, struct breakpoint *bp, void *data)
+ {
+ 	breakpoint_on_retract(bp, proc);
+ 	return CBS_CONT;
+ }
+ 
+ static void
+-detach_process(struct Process *leader)
++detach_process(struct process *leader)
+ {
+ 	each_qd_event(&undo_breakpoint, leader);
+ 	disable_all_breakpoints(leader);
+@@ -414,7 +414,7 @@ detach_process(struct Process *leader)
+ 	/* Now untrace the process, if it was attached to by -p.  */
+ 	struct opt_p_t *it;
+ 	for (it = opt_p; it != NULL; it = it->next) {
+-		struct Process *proc = pid2proc(it->pid);
++		struct process *proc = pid2proc(it->pid);
+ 		if (proc == NULL)
+ 			continue;
+ 		if (proc->leader == leader) {
+@@ -540,19 +540,13 @@ all_stops_accountable(struct pid_set *pids)
+ 	return 1;
+ }
+ 
+-/* The protocol is: 0 for success, negative for failure, positive if
+- * default singlestep is to be used.  */
+-int arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
+-			   int (*add_cb)(void *addr, void *data),
+-			   void *add_cb_data);
+-
+-#ifndef ARCH_HAVE_ATOMIC_SINGLESTEP
+-int
+-arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
+-		       int (*add_cb)(void *addr, void *data),
+-		       void *add_cb_data)
++#ifndef ARCH_HAVE_SW_SINGLESTEP
++enum sw_singlestep_status
++arch_sw_singlestep(struct process *proc, struct breakpoint *bp,
++		   int (*add_cb)(arch_addr_t, struct sw_singlestep_data *),
++		   struct sw_singlestep_data *data)
+ {
+-	return 1;
++	return SWS_HW;
+ }
+ #endif
+ 
+@@ -560,43 +554,46 @@ static Event *process_stopping_on_event(struct event_handler *super,
+ 					Event *event);
+ 
+ static void
+-remove_atomic_breakpoints(struct Process *proc)
++remove_sw_breakpoints(struct process *proc)
+ {
+ 	struct process_stopping_handler *self
+ 		= (void *)proc->leader->event_handler;
+ 	assert(self != NULL);
+ 	assert(self->super.on_event == process_stopping_on_event);
+ 
+-	int ct = sizeof(self->atomic_skip_bp_addrs)
+-		/ sizeof(*self->atomic_skip_bp_addrs);
++	int ct = sizeof(self->sws_bp_addrs) / sizeof(*self->sws_bp_addrs);
+ 	int i;
+ 	for (i = 0; i < ct; ++i)
+-		if (self->atomic_skip_bp_addrs[i] != 0) {
+-			delete_breakpoint(proc, self->atomic_skip_bp_addrs[i]);
+-			self->atomic_skip_bp_addrs[i] = 0;
++		if (self->sws_bp_addrs[i] != 0) {
++			delete_breakpoint(proc, self->sws_bp_addrs[i]);
++			self->sws_bp_addrs[i] = 0;
+ 		}
+ }
+ 
+ static void
+-atomic_singlestep_bp_on_hit(struct breakpoint *bp, struct Process *proc)
++sw_singlestep_bp_on_hit(struct breakpoint *bp, struct process *proc)
+ {
+-	remove_atomic_breakpoints(proc);
++	remove_sw_breakpoints(proc);
+ }
+ 
++struct sw_singlestep_data {
++	struct process_stopping_handler *self;
++};
++
+ static int
+-atomic_singlestep_add_bp(void *addr, void *data)
++sw_singlestep_add_bp(arch_addr_t addr, struct sw_singlestep_data *data)
+ {
+-	struct process_stopping_handler *self = data;
+-	struct Process *proc = self->task_enabling_breakpoint;
++	struct process_stopping_handler *self = data->self;
++	struct process *proc = self->task_enabling_breakpoint;
+ 
+-	int ct = sizeof(self->atomic_skip_bp_addrs)
+-		/ sizeof(*self->atomic_skip_bp_addrs);
++	int ct = sizeof(self->sws_bp_addrs)
++		/ sizeof(*self->sws_bp_addrs);
+ 	int i;
+ 	for (i = 0; i < ct; ++i)
+-		if (self->atomic_skip_bp_addrs[i] == 0) {
+-			self->atomic_skip_bp_addrs[i] = addr;
++		if (self->sws_bp_addrs[i] == 0) {
++			self->sws_bp_addrs[i] = addr;
+ 			static struct bp_callbacks cbs = {
+-				.on_hit = atomic_singlestep_bp_on_hit,
++				.on_hit = sw_singlestep_bp_on_hit,
+ 			};
+ 			struct breakpoint *bp
+ 				= insert_breakpoint(proc, addr, NULL);
+@@ -604,30 +601,35 @@ atomic_singlestep_add_bp(void *addr, void *data)
+ 			return 0;
+ 		}
+ 
+-	assert(!"Too many atomic singlestep breakpoints!");
++	assert(!"Too many sw singlestep breakpoints!");
+ 	abort();
+ }
+ 
+ static int
+ singlestep(struct process_stopping_handler *self)
+ {
+-	struct Process *proc = self->task_enabling_breakpoint;
+-
+-	int status = arch_atomic_singlestep(self->task_enabling_breakpoint,
+-					    self->breakpoint_being_enabled,
+-					    &atomic_singlestep_add_bp, self);
++	struct process *proc = self->task_enabling_breakpoint;
++
++	struct sw_singlestep_data data = { self };
++	switch (arch_sw_singlestep(self->task_enabling_breakpoint,
++				   self->breakpoint_being_enabled,
++				   &sw_singlestep_add_bp, &data)) {
++	case SWS_HW:
++		/* Otherwise do the default action: singlestep.  */
++		debug(1, "PTRACE_SINGLESTEP");
++		if (ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0)) {
++			perror("PTRACE_SINGLESTEP");
++			return -1;
++		}
++		return 0;
+ 
+-	/* Propagate failure and success.  */
+-	if (status <= 0)
+-		return status;
++	case SWS_OK:
++		return 0;
+ 
+-	/* Otherwise do the default action: singlestep.  */
+-	debug(1, "PTRACE_SINGLESTEP");
+-	if (ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0)) {
+-		perror("PTRACE_SINGLESTEP");
++	case SWS_FAIL:
+ 		return -1;
+ 	}
+-	return 0;
++	abort();
+ }
+ 
+ static void
+@@ -639,16 +641,16 @@ post_singlestep(struct process_stopping_handler *self,
+ 	if (*eventp != NULL && (*eventp)->type == EVENT_BREAKPOINT)
+ 		*eventp = NULL; // handled
+ 
+-	struct Process *proc = self->task_enabling_breakpoint;
++	struct process *proc = self->task_enabling_breakpoint;
+ 
+-	remove_atomic_breakpoints(proc);
++	remove_sw_breakpoints(proc);
+ 	self->breakpoint_being_enabled = NULL;
+ }
+ 
+ static void
+ singlestep_error(struct process_stopping_handler *self)
+ {
+-	struct Process *teb = self->task_enabling_breakpoint;
++	struct process *teb = self->task_enabling_breakpoint;
+ 	struct breakpoint *sbp = self->breakpoint_being_enabled;
+ 	fprintf(stderr, "%d couldn't continue when handling %s (%p) at %p\n",
+ 		teb->pid, breakpoint_name(sbp),	sbp->addr,
+@@ -659,7 +661,7 @@ singlestep_error(struct process_stopping_handler *self)
+ static void
+ pt_continue(struct process_stopping_handler *self)
+ {
+-	struct Process *teb = self->task_enabling_breakpoint;
++	struct process *teb = self->task_enabling_breakpoint;
+ 	debug(1, "PTRACE_CONT");
+ 	ptrace(PTRACE_CONT, teb->pid, 0, 0);
+ }
+@@ -675,12 +677,12 @@ static void
+ disable_and(struct process_stopping_handler *self,
+ 	    void (*do_this)(struct process_stopping_handler *self))
+ {
+-	struct Process *teb = self->task_enabling_breakpoint;
++	struct process *teb = self->task_enabling_breakpoint;
+ 	debug(DEBUG_PROCESS, "all stopped, now singlestep/cont %d", teb->pid);
+ 	if (self->breakpoint_being_enabled->enabled)
+ 		disable_breakpoint(teb, self->breakpoint_being_enabled);
+ 	(do_this)(self);
+-	self->state = psh_singlestep;
++	self->state = PSH_SINGLESTEP;
+ }
+ 
+ void
+@@ -705,9 +707,9 @@ static Event *
+ process_stopping_on_event(struct event_handler *super, Event *event)
+ {
+ 	struct process_stopping_handler *self = (void *)super;
+-	struct Process *task = event->proc;
+-	struct Process *leader = task->leader;
+-	struct Process *teb = self->task_enabling_breakpoint;
++	struct process *task = event->proc;
++	struct process *leader = task->leader;
++	struct process *teb = self->task_enabling_breakpoint;
+ 
+ 	debug(DEBUG_PROCESS,
+ 	      "process_stopping_on_event: pid %d; event type %d; state %d",
+@@ -737,7 +739,7 @@ process_stopping_on_event(struct event_handler *super, Event *event)
+ 	}
+ 
+ 	switch (state) {
+-	case psh_stopping:
++	case PSH_STOPPING:
+ 		/* If everyone is stopped, singlestep.  */
+ 		if (each_task(leader, NULL, &task_blocked,
+ 			      &self->pids) == NULL) {
+@@ -746,7 +748,7 @@ process_stopping_on_event(struct event_handler *super, Event *event)
+ 		}
+ 		break;
+ 
+-	case psh_singlestep:
++	case PSH_SINGLESTEP:
+ 		/* In singlestep state, breakpoint signifies that we
+ 		 * have now stepped, and can re-enable the breakpoint.  */
+ 		if (event != NULL && task == teb) {
+@@ -801,13 +803,14 @@ process_stopping_on_event(struct event_handler *super, Event *event)
+ 		break;
+ 
+ 	psh_sinking:
+-		state = self->state = psh_sinking;
+-	case psh_sinking:
++		state = self->state = PSH_SINKING;
++		/* Fall through.  */
++	case PSH_SINKING:
+ 		if (await_sigstop_delivery(&self->pids, task_info, event))
+ 			process_stopping_done(self, leader);
+ 		break;
+ 
+-	case psh_ugly_workaround:
++	case PSH_UGLY_WORKAROUND:
+ 		if (event == NULL)
+ 			break;
+ 		if (event->type == EVENT_BREAKPOINT) {
+@@ -845,7 +848,7 @@ no(struct process_stopping_handler *self)
+ }
+ 
+ int
+-process_install_stopping_handler(struct Process *proc, struct breakpoint *sbp,
++process_install_stopping_handler(struct process *proc, struct breakpoint *sbp,
+ 				 void (*as)(struct process_stopping_handler *),
+ 				 enum callback_status (*ks)
+ 					 (struct process_stopping_handler *),
+@@ -894,7 +897,7 @@ process_install_stopping_handler(struct Process *proc, struct breakpoint *sbp,
+ }
+ 
+ void
+-continue_after_breakpoint(Process *proc, struct breakpoint *sbp)
++continue_after_breakpoint(struct process *proc, struct breakpoint *sbp)
+ {
+ 	debug(DEBUG_PROCESS,
+ 	      "continue_after_breakpoint: pid=%d, addr=%p",
+@@ -937,8 +940,8 @@ static Event *
+ ltrace_exiting_on_event(struct event_handler *super, Event *event)
+ {
+ 	struct ltrace_exiting_handler *self = (void *)super;
+-	struct Process *task = event->proc;
+-	struct Process *leader = task->leader;
++	struct process *task = event->proc;
++	struct process *leader = task->leader;
+ 
+ 	debug(DEBUG_PROCESS,
+ 	      "ltrace_exiting_on_event: pid %d; event type %d",
+@@ -970,7 +973,7 @@ ltrace_exiting_destroy(struct event_handler *super)
+ }
+ 
+ static int
+-ltrace_exiting_install_handler(struct Process *proc)
++ltrace_exiting_install_handler(struct process *proc)
+ {
+ 	/* Only install to leader.  */
+ 	if (proc->leader != proc)
+@@ -1087,7 +1090,7 @@ process_vfork_on_event(struct event_handler *super, Event *event)
+ }
+ 
+ void
+-continue_after_vfork(struct Process *proc)
++continue_after_vfork(struct process *proc)
+ {
+ 	debug(DEBUG_PROCESS, "continue_after_vfork: pid=%d", proc->pid);
+ 	struct process_vfork_handler *handler = calloc(sizeof(*handler), 1);
+@@ -1116,7 +1119,7 @@ continue_after_vfork(struct Process *proc)
+ }
+ 
+ static int
+-is_mid_stopping(Process *proc)
++is_mid_stopping(struct process *proc)
+ {
+ 	return proc != NULL
+ 		&& proc->event_handler != NULL
+@@ -1124,7 +1127,7 @@ is_mid_stopping(Process *proc)
+ }
+ 
+ void
+-continue_after_syscall(struct Process *proc, int sysnum, int ret_p)
++continue_after_syscall(struct process *proc, int sysnum, int ret_p)
+ {
+ 	/* Don't continue if we are mid-stopping.  */
+ 	if (ret_p && (is_mid_stopping(proc) || is_mid_stopping(proc->leader))) {
+@@ -1136,6 +1139,23 @@ continue_after_syscall(struct Process *proc, int sysnum, int ret_p)
+ 	continue_process(proc->pid);
+ }
+ 
++void
++continue_after_exec(struct process *proc)
++{
++	continue_process(proc->pid);
++
++	/* After the exec, we expect to hit the first executable
++	 * instruction.
++	 *
++	 * XXX TODO It would be nice to have this removed, but then we
++	 * need to do that also for initial call to wait_for_proc in
++	 * execute_program.  In that case we could generate a
++	 * EVENT_FIRST event or something, or maybe this could somehow
++	 * be rolled into EVENT_NEW.  */
++	wait_for_proc(proc->pid);
++	continue_process(proc->pid);
++}
++
+ /* If ltrace gets SIGINT, the processes directly or indirectly run by
+  * ltrace get it too.  We just have to wait long enough for the signal
+  * to be delivered and the process terminated, which we notice and
+@@ -1152,7 +1172,7 @@ os_ltrace_exiting(void)
+ {
+ 	struct opt_p_t *it;
+ 	for (it = opt_p; it != NULL; it = it->next) {
+-		struct Process *proc = pid2proc(it->pid);
++		struct process *proc = pid2proc(it->pid);
+ 		if (proc == NULL || proc->leader == NULL)
+ 			continue;
+ 		if (ltrace_exiting_install_handler(proc->leader) < 0)
+@@ -1174,7 +1194,8 @@ os_ltrace_exiting_sighandler(void)
+ }
+ 
+ size_t
+-umovebytes(Process *proc, void *addr, void *laddr, size_t len) {
++umovebytes(struct process *proc, void *addr, void *laddr, size_t len)
++{
+ 
+ 	union {
+ 		long a;
+diff --git a/sysdeps/linux-gnu/trace.h b/sysdeps/linux-gnu/trace.h
+index 88ac33d..e988f70 100644
+--- a/sysdeps/linux-gnu/trace.h
++++ b/sysdeps/linux-gnu/trace.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.
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public License as
+@@ -59,13 +59,13 @@ struct process_stopping_handler
+ 	struct event_handler super;
+ 
+ 	/* The task that is doing the re-enablement.  */
+-	struct Process *task_enabling_breakpoint;
++	struct process *task_enabling_breakpoint;
+ 
+ 	/* The pointer being re-enabled.  */
+ 	struct breakpoint *breakpoint_being_enabled;
+ 
+ 	/* Artificial atomic skip breakpoint, if any needed.  */
+-	void *atomic_skip_bp_addrs[2];
++	arch_addr_t sws_bp_addrs[2];
+ 
+ 	/* When all tasks are stopped, this callback gets called.  */
+ 	void (*on_all_stopped)(struct process_stopping_handler *);
+@@ -84,17 +84,17 @@ struct process_stopping_handler
+ 
+ 	enum {
+ 		/* We are waiting for everyone to land in t/T.  */
+-		psh_stopping = 0,
++		PSH_STOPPING = 0,
+ 
+ 		/* We are doing the PTRACE_SINGLESTEP.  */
+-		psh_singlestep,
++		PSH_SINGLESTEP,
+ 
+ 		/* We are waiting for all the SIGSTOPs to arrive so
+ 		 * that we can sink them.  */
+-		psh_sinking,
++		PSH_SINKING,
+ 
+ 		/* This is for tracking the ugly workaround.  */
+-		psh_ugly_workaround,
++		PSH_UGLY_WORKAROUND,
+ 	} state;
+ 
+ 	int exiting;
+@@ -108,7 +108,7 @@ struct process_stopping_handler
+  * ON_ALL_STOPPED is LINUX_PTRACE_DISABLE_AND_SINGLESTEP, the default
+  * for KEEP_STEPPING_P and UGLY_WORKAROUND_P is "no".  */
+ int process_install_stopping_handler
+-	(struct Process *proc, struct breakpoint *sbp,
++	(struct process *proc, struct breakpoint *sbp,
+ 	 void (*on_all_stopped)(struct process_stopping_handler *),
+ 	 enum callback_status (*keep_stepping_p)
+ 		 (struct process_stopping_handler *),
+diff --git a/sysdeps/linux-gnu/x86/fetch.c b/sysdeps/linux-gnu/x86/fetch.c
+index 4dab4cc..aa02a0a 100644
+--- a/sysdeps/linux-gnu/x86/fetch.c
++++ b/sysdeps/linux-gnu/x86/fetch.c
+@@ -323,13 +323,13 @@ allocate_class(enum arg_class cls, struct fetch_context *context,
+ }
+ 
+ static ssize_t
+-classify(struct Process *proc, struct fetch_context *context,
++classify(struct process *proc, struct fetch_context *context,
+ 	 struct arg_type_info *info, struct value *valuep, enum arg_class classes[],
+ 	 size_t sz, size_t eightbytes);
+ 
+ /* This classifies one eightbyte part of an array or struct.  */
+ static ssize_t
+-classify_eightbyte(struct Process *proc, struct fetch_context *context,
++classify_eightbyte(struct process *proc, struct fetch_context *context,
+ 		   struct arg_type_info *info, struct value *valuep,
+ 		   enum arg_class *classp, size_t start, size_t end,
+ 		   struct arg_type_info *(*getter)(struct arg_type_info *,
+@@ -364,7 +364,7 @@ classify_eightbyte(struct Process *proc, struct fetch_context *context,
+ 
+ /* This classifies small arrays and structs.  */
+ static ssize_t
+-classify_eightbytes(struct Process *proc, struct fetch_context *context,
++classify_eightbytes(struct process *proc, struct fetch_context *context,
+ 		    struct arg_type_info *info, struct value *valuep,
+ 		    enum arg_class classes[], size_t elements,
+ 		    size_t eightbytes,
+@@ -432,7 +432,7 @@ flatten_structure(struct arg_type_info *flattened, struct arg_type_info *info)
+ }
+ 
+ static ssize_t
+-classify(struct Process *proc, struct fetch_context *context,
++classify(struct process *proc, struct fetch_context *context,
+ 	 struct arg_type_info *info, struct value *valuep, enum arg_class classes[],
+ 	 size_t sz, size_t eightbytes)
+ {
+@@ -517,7 +517,7 @@ pass_by_reference(struct value *valuep, enum arg_class classes[])
+ }
+ 
+ static ssize_t
+-classify_argument(struct Process *proc, struct fetch_context *context,
++classify_argument(struct process *proc, struct fetch_context *context,
+ 		  struct arg_type_info *info, struct value *valuep,
+ 		  enum arg_class classes[], size_t *sizep)
+ {
+@@ -545,7 +545,7 @@ classify_argument(struct Process *proc, struct fetch_context *context,
+ }
+ 
+ static int
+-fetch_register_banks(struct Process *proc, struct fetch_context *context,
++fetch_register_banks(struct process *proc, struct fetch_context *context,
+ 		     int floating)
+ {
+ 	if (ptrace(PTRACE_GETREGS, proc->pid, 0, &context->iregs) < 0)
+@@ -566,7 +566,7 @@ fetch_register_banks(struct Process *proc, struct fetch_context *context,
+ 
+ static int
+ arch_fetch_arg_next_32(struct fetch_context *context, enum tof type,
+-		       struct Process *proc, struct arg_type_info *info,
++		       struct process *proc, struct arg_type_info *info,
+ 		       struct value *valuep)
+ {
+ 	size_t sz = type_sizeof(proc, info);
+@@ -580,7 +580,7 @@ arch_fetch_arg_next_32(struct fetch_context *context, enum tof type,
+ 
+ static int
+ arch_fetch_retval_32(struct fetch_context *context, enum tof type,
+-		     struct Process *proc, struct arg_type_info *info,
++		     struct process *proc, struct arg_type_info *info,
+ 		     struct value *valuep)
+ {
+ 	if (fetch_register_banks(proc, context, type == LT_TOF_FUNCTIONR) < 0)
+@@ -646,7 +646,7 @@ fetch_stack_pointer(struct fetch_context *context)
+ 
+ struct fetch_context *
+ arch_fetch_arg_init_32(struct fetch_context *context,
+-		       enum tof type, struct Process *proc,
++		       enum tof type, struct process *proc,
+ 		       struct arg_type_info *ret_info)
+ {
+ 	context->stack_pointer = fetch_stack_pointer(context) + 4;
+@@ -673,7 +673,7 @@ arch_fetch_arg_init_32(struct fetch_context *context,
+ 
+ struct fetch_context *
+ arch_fetch_arg_init_64(struct fetch_context *ctx, enum tof type,
+-		       struct Process *proc, struct arg_type_info *ret_info)
++		       struct process *proc, struct arg_type_info *ret_info)
+ {
+ 	/* The first stack slot holds a return address.  */
+ 	ctx->stack_pointer = fetch_stack_pointer(ctx) + 8;
+@@ -698,7 +698,7 @@ arch_fetch_arg_init_64(struct fetch_context *ctx, enum tof type,
+ }
+ 
+ struct fetch_context *
+-arch_fetch_arg_init(enum tof type, struct Process *proc,
++arch_fetch_arg_init(enum tof type, struct process *proc,
+ 		    struct arg_type_info *ret_info)
+ {
+ 	struct fetch_context *ctx = malloc(sizeof(*ctx));
+@@ -724,7 +724,7 @@ arch_fetch_arg_init(enum tof type, struct Process *proc,
+ }
+ 
+ struct fetch_context *
+-arch_fetch_arg_clone(struct Process *proc, struct fetch_context *context)
++arch_fetch_arg_clone(struct process *proc, struct fetch_context *context)
+ {
+ 	struct fetch_context *ret = malloc(sizeof(*ret));
+ 	if (ret == NULL)
+@@ -734,7 +734,7 @@ arch_fetch_arg_clone(struct Process *proc, struct fetch_context *context)
+ 
+ static int
+ arch_fetch_pool_arg_next(struct fetch_context *context, enum tof type,
+-			 struct Process *proc, struct arg_type_info *info,
++			 struct process *proc, struct arg_type_info *info,
+ 			 struct value *valuep, enum reg_pool pool)
+ {
+ 	enum arg_class classes[2];
+@@ -776,7 +776,7 @@ arch_fetch_pool_arg_next(struct fetch_context *context, enum tof type,
+ 
+ int
+ arch_fetch_fun_retval(struct fetch_context *context, enum tof type,
+-		      struct Process *proc, struct arg_type_info *info,
++		      struct process *proc, struct arg_type_info *info,
+ 		      struct value *valuep)
+ {
+ 	assert(type != LT_TOF_FUNCTION
+@@ -808,7 +808,7 @@ arch_fetch_fun_retval(struct fetch_context *context, enum tof type,
+ 
+ int
+ arch_fetch_arg_next(struct fetch_context *context, enum tof type,
+-		    struct Process *proc, struct arg_type_info *info,
++		    struct process *proc, struct arg_type_info *info,
+ 		    struct value *valuep)
+ {
+ 	if (proc->e_machine == EM_386)
+@@ -832,7 +832,7 @@ arch_fetch_arg_next(struct fetch_context *context, enum tof type,
+ 
+ int
+ arch_fetch_retval(struct fetch_context *context, enum tof type,
+-		  struct Process *proc, struct arg_type_info *info,
++		  struct process *proc, struct arg_type_info *info,
+ 		  struct value *valuep)
+ {
+ 	if (proc->e_machine == EM_386)
+diff --git a/sysdeps/linux-gnu/x86/plt.c b/sysdeps/linux-gnu/x86/plt.c
+index dc6f183..c2a4151 100644
+--- a/sysdeps/linux-gnu/x86/plt.c
++++ b/sysdeps/linux-gnu/x86/plt.c
+@@ -24,11 +24,13 @@
+ #include "library.h"
+ 
+ GElf_Addr
+-arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
++arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela)
++{
+ 	return lte->plt_addr + (ndx + 1) * 16;
+ }
+ 
+ void *
+-sym2addr(Process *proc, struct library_symbol *sym) {
++sym2addr(struct process *proc, struct library_symbol *sym)
++{
+ 	return sym->enter_addr;
+ }
+diff --git a/sysdeps/linux-gnu/x86/regs.c b/sysdeps/linux-gnu/x86/regs.c
+index ca6470b..3886e84 100644
+--- a/sysdeps/linux-gnu/x86/regs.c
++++ b/sysdeps/linux-gnu/x86/regs.c
+@@ -56,7 +56,7 @@ conv_32(arch_addr_t val)
+ }
+ 
+ void *
+-get_instruction_pointer(struct Process *proc)
++get_instruction_pointer(struct process *proc)
+ {
+ 	long int ret = ptrace(PTRACE_PEEKUSER, proc->pid, XIP, 0);
+ 	if (proc->e_machine == EM_386)
+@@ -65,7 +65,7 @@ get_instruction_pointer(struct Process *proc)
+ }
+ 
+ void
+-set_instruction_pointer(struct Process *proc, arch_addr_t addr)
++set_instruction_pointer(struct process *proc, arch_addr_t addr)
+ {
+ 	if (proc->e_machine == EM_386)
+ 		addr = conv_32(addr);
+@@ -73,7 +73,7 @@ set_instruction_pointer(struct Process *proc, arch_addr_t addr)
+ }
+ 
+ void *
+-get_stack_pointer(struct Process *proc)
++get_stack_pointer(struct process *proc)
+ {
+ 	long sp = ptrace(PTRACE_PEEKUSER, proc->pid, XSP, 0);
+ 	if (sp == -1 && errno) {
+@@ -91,7 +91,7 @@ get_stack_pointer(struct Process *proc)
+ }
+ 
+ void *
+-get_return_addr(struct Process *proc, void *sp)
++get_return_addr(struct process *proc, void *sp)
+ {
+ 	long a = ptrace(PTRACE_PEEKTEXT, proc->pid, sp, 0);
+ 	if (a == -1 && errno) {
+@@ -109,7 +109,8 @@ get_return_addr(struct Process *proc, void *sp)
+ }
+ 
+ void
+-set_return_addr(Process *proc, void *addr) {
++set_return_addr(struct process *proc, void *addr)
++{
+ 	if (proc->e_machine == EM_386)
+ 		addr = (void *)((long int)addr & 0xffffffff);
+ 	ptrace(PTRACE_POKETEXT, proc->pid, proc->stack_pointer, addr);
+diff --git a/sysdeps/linux-gnu/x86/trace.c b/sysdeps/linux-gnu/x86/trace.c
+index ed8bdb4..6a1a6a5 100644
+--- a/sysdeps/linux-gnu/x86/trace.c
++++ b/sysdeps/linux-gnu/x86/trace.c
+@@ -55,7 +55,7 @@ static const int x86_64 = 0;
+ #endif
+ 
+ void
+-get_arch_dep(struct Process *proc)
++get_arch_dep(struct process *proc)
+ {
+ 	/* Unfortunately there are still remnants of mask_32bit uses
+ 	 * around.  */
+@@ -75,7 +75,7 @@ get_arch_dep(struct Process *proc)
+ /* Returns 1 if syscall, 2 if sysret, 0 otherwise.
+  */
+ int
+-syscall_p(struct Process *proc, int status, int *sysnum)
++syscall_p(struct process *proc, int status, int *sysnum)
+ {
+ 	if (WIFSTOPPED(status)
+ 	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
+@@ -109,7 +109,7 @@ syscall_p(struct Process *proc, int status, int *sysnum)
+ }
+ 
+ size_t
+-arch_type_sizeof(struct Process *proc, struct arg_type_info *info)
++arch_type_sizeof(struct process *proc, struct arg_type_info *info)
+ {
+ 	if (proc == NULL)
+ 		return (size_t)-2;
+@@ -151,7 +151,7 @@ arch_type_sizeof(struct Process *proc, struct arg_type_info *info)
+ }
+ 
+ size_t
+-arch_type_alignof(struct Process *proc, struct arg_type_info *info)
++arch_type_alignof(struct process *proc, struct arg_type_info *info)
+ {
+ 	if (proc == NULL)
+ 		return (size_t)-2;
+diff --git a/type.c b/type.c
+index 3ce8563..d80550b 100644
+--- a/type.c
++++ b/type.c
+@@ -123,7 +123,7 @@ type_struct_destroy(struct arg_type_info *info)
+ }
+ 
+ static int
+-layout_struct(struct Process *proc, struct arg_type_info *info,
++layout_struct(struct process *proc, struct arg_type_info *info,
+ 	      size_t *sizep, size_t *alignmentp, size_t *offsetofp)
+ {
+ 	size_t sz = 0;
+@@ -254,10 +254,10 @@ type_destroy(struct arg_type_info *info)
+ }
+ 
+ #ifdef ARCH_HAVE_SIZEOF
+-size_t arch_type_sizeof(struct Process *proc, struct arg_type_info * arg);
++size_t arch_type_sizeof(struct process *proc, struct arg_type_info *arg);
+ #else
+ size_t
+-arch_type_sizeof(struct Process *proc, struct arg_type_info * arg)
++arch_type_sizeof(struct process *proc, struct arg_type_info *arg)
+ {
+ 	/* Use default value.  */
+ 	return (size_t)-2;
+@@ -265,10 +265,10 @@ arch_type_sizeof(struct Process *proc, struct arg_type_info * arg)
+ #endif
+ 
+ #ifdef ARCH_HAVE_ALIGNOF
+-size_t arch_type_alignof(struct Process *proc, struct arg_type_info * arg);
++size_t arch_type_alignof(struct process *proc, struct arg_type_info *arg);
+ #else
+ size_t
+-arch_type_alignof(struct Process *proc, struct arg_type_info * arg)
++arch_type_alignof(struct process *proc, struct arg_type_info *arg)
+ {
+ 	/* Use default value.  */
+ 	return (size_t)-2;
+@@ -289,7 +289,7 @@ align(size_t sz, size_t alignment)
+ }
+ 
+ size_t
+-type_sizeof(struct Process *proc, struct arg_type_info *type)
++type_sizeof(struct process *proc, struct arg_type_info *type)
+ {
+ 	size_t arch_size = arch_type_sizeof(proc, type);
+ 	if (arch_size != (size_t)-2)
+@@ -359,7 +359,7 @@ type_sizeof(struct Process *proc, struct arg_type_info *type)
+ #define alignof(field,st) ((size_t) ((char*) &st.field - (char*) &st))
+ 
+ size_t
+-type_alignof(struct Process *proc, struct arg_type_info *type)
++type_alignof(struct process *proc, struct arg_type_info *type)
+ {
+ 	size_t arch_alignment = arch_type_alignof(proc, type);
+ 	if (arch_alignment != (size_t)-2)
+@@ -412,7 +412,7 @@ type_alignof(struct Process *proc, struct arg_type_info *type)
+ }
+ 
+ size_t
+-type_offsetof(struct Process *proc, struct arg_type_info *type, size_t emt)
++type_offsetof(struct process *proc, struct arg_type_info *type, size_t emt)
+ {
+ 	assert(type->type == ARGTYPE_STRUCT
+ 	       || type->type == ARGTYPE_ARRAY);
+diff --git a/type.h b/type.h
+index e8dec71..b92c1af 100644
+--- a/type.h
++++ b/type.h
+@@ -111,11 +111,11 @@ void type_init_pointer(struct arg_type_info *info,
+ void type_destroy(struct arg_type_info *info);
+ 
+ /* Compute a size of given type.  Return (size_t)-1 for error.  */
+-size_t type_sizeof(struct Process *proc, struct arg_type_info *type);
++size_t type_sizeof(struct process *proc, struct arg_type_info *type);
+ 
+ /* Compute an alignment necessary for elements of this type.  Return
+  * (size_t)-1 for error.  */
+-size_t type_alignof(struct Process *proc, struct arg_type_info *type);
++size_t type_alignof(struct process *proc, struct arg_type_info *type);
+ 
+ /* Align value SZ to ALIGNMENT and return the result.  */
+ size_t align(size_t sz, size_t alignment);
+@@ -126,7 +126,7 @@ struct arg_type_info *type_element(struct arg_type_info *type, size_t elt);
+ 
+ /* Compute an offset of EMT-th element of type TYPE.  This works for
+  * arrays and structures.  Return (size_t)-1 for error.  */
+-size_t type_offsetof(struct Process *proc,
++size_t type_offsetof(struct process *proc,
+ 		     struct arg_type_info *type, size_t elt);
+ 
+ /* Whether TYPE is an integral type as defined by the C standard.  */
+diff --git a/value.c b/value.c
+index f7950da..d18db17 100644
+--- a/value.c
++++ b/value.c
+@@ -29,7 +29,7 @@
+ #include "backend.h"
+ 
+ static void
+-value_common_init(struct value *valp, struct Process *inferior,
++value_common_init(struct value *valp, struct process *inferior,
+ 		  struct value *parent, struct arg_type_info *type,
+ 		  int own_type)
+ {
+@@ -43,7 +43,7 @@ value_common_init(struct value *valp, struct Process *inferior,
+ }
+ 
+ void
+-value_init(struct value *valp, struct Process *inferior, struct value *parent,
++value_init(struct value *valp, struct process *inferior, struct value *parent,
+ 	   struct arg_type_info *type, int own_type)
+ {
+ 	assert(inferior != NULL);
+diff --git a/value.h b/value.h
+index 795573c..f501254 100644
+--- a/value.h
++++ b/value.h
+@@ -46,7 +46,7 @@ enum value_location_t {
+ 
+ struct value {
+ 	struct arg_type_info *type;
+-	struct Process *inferior;
++	struct process *inferior;
+ 	struct value *parent;
+ 	size_t size;
+ 	union {
+@@ -63,7 +63,7 @@ struct value {
+  * value, in case of compound types.  It may be NULL.  TYPE is a type
+  * of the value.  It may be NULL if the type is not yet known.  If
+  * OWN_TYPE, the passed-in type is owned and released by value.  */
+-void value_init(struct value *value, struct Process *inferior,
++void value_init(struct value *value, struct process *inferior,
+ 		struct value *parent, struct arg_type_info *type,
+ 		int own_type);
+ 
+diff --git a/zero.c b/zero.c
+index bc119ee..5757943 100644
+--- a/zero.c
++++ b/zero.c
+@@ -18,7 +18,6 @@
+  * 02110-1301 USA
+  */
+ 
+-#include <error.h>
+ #include <errno.h>
+ 
+ #include "zero.h"
+@@ -93,13 +92,12 @@ build_zero_w_arg(struct expr_node *expr, int own)
+ struct expr_node *
+ expr_node_zero(void)
+ {
+-	static struct expr_node *node = NULL;
+-	if (node == NULL) {
+-		node = malloc(sizeof(*node));
+-		if (node == NULL)
+-			error(1, errno, "malloc expr_node_zero");
+-		expr_init_cb1(node, &zero1_callback,
++	static struct expr_node *nodep = NULL;
++	if (nodep == NULL) {
++		static struct expr_node node;
++		expr_init_cb1(&node, &zero1_callback,
+ 			      expr_self(), 0, (void *)-1);
++		nodep = &node;
+ 	}
+-	return node;
++	return nodep;
+ }
diff --git a/ltrace.spec b/ltrace.spec
index a3e0c3c..70b043d 100644
--- a/ltrace.spec
+++ b/ltrace.spec
@@ -1,21 +1,27 @@
 Summary: Tracks runtime library calls from dynamically linked executables
 Name: ltrace
 Version: 0.7.2
-Release: 2%{?dist}
+Release: 3%{?dist}
 URL: http://ltrace.alioth.debian.org/
 License: GPLv2+
 Group: Development/Debuggers
 
 BuildRequires: elfutils-libelf-devel dejagnu
 BuildRequires: libselinux-devel
+BuildRequires: autoconf automake libtool
 
 # Note: this URL needs to be updated for each release, as the file
 # number changes for each file.  Full list of released files is at:
 #  https://alioth.debian.org/frs/?group_id=30892
 Source: http://alioth.debian.org/frs/download.php/3848/ltrace-0.7.2.tar.bz2
 
-# Upstream patch for fixes in man page and --help.
-Patch0: ltrace-0.7.2-man.patch
+# Many small fixes brought from master branch.
+Patch0: ltrace-0.7.2-bits.patch
+
+# Upstream patch which introduces singlestepping support on ARM.  This
+# makes ltrace essentially work on ARM, except for parameter passing
+# conventions.
+Patch1: ltrace-0.7.2-arm.patch
 
 %description
 Ltrace is a debugging program which runs a specified command until the
@@ -30,8 +36,10 @@ execution of processes.
 %prep
 %setup -q
 %patch0 -p1
+%patch1 -p1
 
 %build
+autoreconf -i
 %configure
 make %{?_smp_mflags}
 
@@ -54,6 +62,13 @@ echo ====================TESTING END=====================
 %config(noreplace) %{_sysconfdir}/ltrace.conf
 
 %changelog
+* Thu Jan 31 2013 Petr Machata <pmachata at redhat.com> - 0.7.2-3
+- Bring small fixes from master branch
+  (ltrace-0.7.2-bits.patch; drop ltrace-0.7.2-man.patch)
+- Add a patch that implements ARM sofware singlestepping.  This mostly
+  fixes test suite on ARM, though parameter passing conventions are
+  still not implemented.  (ltrace-0.7.2-arm.patch)
+
 * Fri Jan 11 2013 Petr Machata <pmachata at redhat.com> - 0.7.2-2
 - Improve documentation: better correlation between ltrace(1) and
   --help, other minor improvements in ltrace(1).


More information about the scm-commits mailing list