commit 4b23d2c6b77a8025bdc5a24231e17329518e70a2
Author: Petr Machata <pmachata(a)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, ®) < 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, ®) < 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(a)lists.alioth.debian.org])
++AC_INIT([ltrace],[0.7.90-git],[ltrace-devel(a)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, ®ex);
+- 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(<e);
+
+ 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(a)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@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@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(a)redhat.com> - 0.3.36-4.2
+-- bump again for double-long bug on ppc(64)
+-
+-* Tue Feb 07 2006 Jesse Keating <jkeating(a)redhat.com> - 0.3.36-4.1
+-- rebuilt for new gcc4.1 snapshot and glibc changes
+-
+-* Mon Jan 9 2006 Jakub Jelinek <jakub(a)redhat.com> 0.3.36-4
+-- added ppc64 and s390x support (IBM)
+-- added ia64 support (Ian Wienand)
+-
+-* Sat Mar 5 2005 Jakub Jelinek <jakub(a)redhat.com> 0.3.36-3
+-- rebuilt with GCC 4
+-
+-* Tue Dec 14 2004 Jakub Jelinek <jakub(a)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(a)redhat.com> 0.3.36-1
+-- update to 0.3.36
+-
+-* Mon Oct 11 2004 Jakub Jelinek <jakub(a)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(a)redhat.com>
+-- rebuilt
+-
+-* Tue Jun 8 2004 Jakub Jelinek <jakub(a)redhat.com> 0.3.32-3
+-- buildreq elfutils-libelf-devel (#124921)
+-
+-* Thu Apr 22 2004 Jakub Jelinek <jakub(a)redhat.com> 0.3.32-2
+-- fix demangling
+-
+-* Thu Apr 22 2004 Jakub Jelinek <jakub(a)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(a)redhat.com>
+-- rebuilt
+-
+-* Mon Feb 3 2003 Jakub Jelinek <jakub(a)redhat.com> 0.3.29-1
+-- update to 0.3.29
+-
+-* Wed Jan 22 2003 Tim Powers <timp(a)redhat.com>
+-- rebuilt
+-
+-* Sun Sep 1 2002 Jakub Jelinek <jakub(a)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(a)redhat.com>
+-- automated rebuild
+-
+-* Tue May 28 2002 Phil Knirsch <pknirsch(a)redhat.com>
+-- Added the 'official' s390 patch.
+-
+-* Thu May 23 2002 Tim Powers <timp(a)redhat.com>
+-- automated rebuild
+-
+-* Wed Jan 09 2002 Tim Powers <timp(a)redhat.com>
+-- automated rebuild
+-
+-* Fri Jul 20 2001 Jakub Jelinek <jakub(a)redhat.com>
+-- fix stale symlink in documentation directory (#47749)
+-
+-* Sun Jun 24 2001 Elliot Lee <sopwith(a)redhat.com>
+-- Bump release + rebuild.
+-
+-* Thu Aug 2 2000 Tim Waugh <twaugh(a)redhat.com>
+-- fix off-by-one problem in checking syscall number
+-
+-* Wed Jul 12 2000 Prospector <bugzilla(a)redhat.com>
+-- automatic rebuild
+-
+-* Mon Jun 19 2000 Matt Wilson <msw(a)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(a)redhat.com>
+-- fix description
+-
+-* Fri Jan 7 2000 Jeff Johnson <jbj(a)redhat.com>
+-- update to 0.3.10.
+-- include (but don't apply) sparc patch from Jakub Jellinek.
+-
+-* Sun Mar 21 1999 Cristian Gafton <gafton(a)redhat.com>
+-- auto rebuild in the new build environment (release 2)
+-
+-* Fri Mar 12 1999 Jeff Johnson <jbj(a)redhat.com>
+-- update to 0.3.6.
+-
+-* Mon Sep 21 1998 Preston Brown <pbrown(a)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(a)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(a)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(a)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(a)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(a)redhat.com> - 0.7.2-2
- Improve documentation: better correlation between ltrace(1) and
--help, other minor improvements in ltrace(1).