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 ++ ++/* 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 + #include + ++#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 + #include + #include ++#include + + #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 + #include + +-#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 , BLX */ ++ 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 + + 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@lists.alioth.debian.org]) ++AC_INIT([ltrace],[0.7.90-git],[ltrace-devel@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 ]], ++ [[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 + + #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 +-#include +-#include +-#include +-#include +- +-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 + #include + #include +-#include + #include + + #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 + #include + #include + #include +@@ -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 ++ + #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 + #include + #include ++#include + #include + + #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 + #include +-#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 + .\" + .\" 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 - 0.3.36-4.2 +-- bump again for double-long bug on ppc(64) +- +-* Tue Feb 07 2006 Jesse Keating - 0.3.36-4.1 +-- rebuilt for new gcc4.1 snapshot and glibc changes +- +-* Mon Jan 9 2006 Jakub Jelinek 0.3.36-4 +-- added ppc64 and s390x support (IBM) +-- added ia64 support (Ian Wienand) +- +-* Sat Mar 5 2005 Jakub Jelinek 0.3.36-3 +-- rebuilt with GCC 4 +- +-* Tue Dec 14 2004 Jakub Jelinek 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 0.3.36-1 +-- update to 0.3.36 +- +-* Mon Oct 11 2004 Jakub Jelinek 0.3.35-1 +-- update to 0.3.35 +-- update syscall tables from latest kernel source +- +-* Tue Jun 15 2004 Elliot Lee +-- rebuilt +- +-* Tue Jun 8 2004 Jakub Jelinek 0.3.32-3 +-- buildreq elfutils-libelf-devel (#124921) +- +-* Thu Apr 22 2004 Jakub Jelinek 0.3.32-2 +-- fix demangling +- +-* Thu Apr 22 2004 Jakub Jelinek 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 +-- rebuilt +- +-* Mon Feb 3 2003 Jakub Jelinek 0.3.29-1 +-- update to 0.3.29 +- +-* Wed Jan 22 2003 Tim Powers +-- rebuilt +- +-* Sun Sep 1 2002 Jakub Jelinek 0.3.10-12 +-- add a bunch of missing functions to ltrace.conf +- (like strlen, ugh) +- +-* Fri Jun 21 2002 Tim Powers +-- automated rebuild +- +-* Tue May 28 2002 Phil Knirsch +-- Added the 'official' s390 patch. +- +-* Thu May 23 2002 Tim Powers +-- automated rebuild +- +-* Wed Jan 09 2002 Tim Powers +-- automated rebuild +- +-* Fri Jul 20 2001 Jakub Jelinek +-- fix stale symlink in documentation directory (#47749) +- +-* Sun Jun 24 2001 Elliot Lee +-- Bump release + rebuild. +- +-* Thu Aug 2 2000 Tim Waugh +-- fix off-by-one problem in checking syscall number +- +-* Wed Jul 12 2000 Prospector +-- automatic rebuild +- +-* Mon Jun 19 2000 Matt Wilson +-- rebuilt for next release +-- patched Makefile.in to take a hint on mandir (patch2) +-- use %%{_mandir} and %%makeinstall +- +-* Wed Feb 02 2000 Cristian Gafton +-- fix description +- +-* Fri Jan 7 2000 Jeff Johnson +-- update to 0.3.10. +-- include (but don't apply) sparc patch from Jakub Jellinek. +- +-* Sun Mar 21 1999 Cristian Gafton +-- auto rebuild in the new build environment (release 2) +- +-* Fri Mar 12 1999 Jeff Johnson +-- update to 0.3.6. +- +-* Mon Sep 21 1998 Preston Brown +-- 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 ++#include ++ ++#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 ++ ++/* 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@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 .\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 .\n" ++ "License GPLv2+: GNU GPL version 2 or later \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 +@@ -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 ++#include + + #if defined(HAVE_LIBUNWIND) + # include +@@ -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 + #include + #include +-#include + #include + + #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 + #include + + #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-0.7.2-man.patch b/ltrace-0.7.2-man.patch deleted file mode 100644 index 4f89adf..0000000 --- a/ltrace-0.7.2-man.patch +++ /dev/null @@ -1,364 +0,0 @@ -From b340bd5fc0448da0079e02d4ede8c123d14a1620 Mon Sep 17 00:00:00 2001 -From: Petr Machata -Date: Fri, 11 Jan 2013 23:32:17 +0100 -Subject: [PATCH] Update documentation - -- Add several missing options to synopsis in ltrace.1 -- Synchronize naming of arguments between ltrace.1 and --help -- Fix formatting in ltrace.1 -- argument names should be in emphasis, - only the argument metavariables should. ---- - ltrace.1 | 207 ++++++++++++++++++++++++++++++++----------------------------- - options.c | 18 +++--- - 2 files changed, 118 insertions(+), 107 deletions(-) - -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 - .\" - .\" 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/options.c b/options.c -index e8fd2a2..0aa893a 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@lists.alioth.debian.org\n", - progname); - } --- -1.7.6.5 - 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 - 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 - 0.7.2-2 - Improve documentation: better correlation between ltrace(1) and --help, other minor improvements in ltrace(1).