Upstream 0.7.0

This commit is contained in:
Petr Machata 2012-11-10 15:14:00 +01:00
parent f09484d326
commit 85e550411c
32 changed files with 240 additions and 36273 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
ltrace-0.5-svn45.tar.gz
ltrace-*/
/ltrace-0.6.0.tar.bz2
/ltrace-0.7.0.tar.bz2

View File

@ -1,13 +0,0 @@
diff -up ltrace-0.5/etc/ltrace.conf\~ ltrace-0.5/etc/ltrace.conf
--- ltrace-0.5/etc/ltrace.conf~ 2006-02-20 22:55:47.000000000 +0100
+++ ltrace-0.5/etc/ltrace.conf 2010-12-09 12:24:31.000000000 +0100
@@ -237,6 +237,7 @@ string basename(string);
string index(string,char);
addr memchr(string,char,ulong);
addr memcpy(addr,string3,ulong);
+addr memmove(addr,string3,ulong);
addr memset(addr,char,long);
string rindex(string,char);
addr stpcpy(addr,string);
Diff finished. Thu Dec 9 12:24:37 2010

View File

@ -1,84 +0,0 @@
diff -Nurp ltrace-0.5-orig/testsuite/ltrace.torture/ia64-sigill.exp ltrace-0.5/testsuite/ltrace.torture/ia64-sigill.exp
--- ltrace-0.5-orig/testsuite/ltrace.torture/ia64-sigill.exp 1969-12-31 19:00:00.000000000 -0500
+++ ltrace-0.5/testsuite/ltrace.torture/ia64-sigill.exp 2007-05-04 13:29:43.000000000 -0400
@@ -0,0 +1,33 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+set testfile "ia64-sigill"
+set srcfile ${testfile}.s
+set binfile ${testfile}
+
+if { [istarget ia64-*] } then {
+ verbose "compiling source file now....."
+ # Build the shared libraries this test case needs.
+ if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}.s" "${srcdir}/${subdir}/${binfile}" executable {debug} ] != "" } {
+ send_user "Testcase compile failed, so all tests in this file will automatically fail\n."
+ }
+
+ # Run PUT for ltarce.
+ set exec_output [ltrace_runtest $srcdir/$subdir $srcdir/$subdir/$binfile]
+
+ # Check the output of this program.
+ verbose "ltrace runtest output: $exec_output\n"
+ if [regexp {ELF from incompatible architecture} $exec_output] {
+ fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!"
+ return
+ } elseif [ regexp {Couldn't get .hash data} $exec_output ] {
+ fail "Couldn't get .hash data!"
+ return
+ }
+
+ catch "exec sh -c {grep SIGILL ${srcdir}/${subdir}/${testfile}.ltrace | wc -l ;exit}" output
+ if { $output == 0 } then {
+ pass "ltrace did interpret SIGILL as breakpoint."
+ } else {
+ fail "ltrace failed to interpret SIGILL as breakpoint."
+ }
+}
diff -Nurp ltrace-0.5-orig/testsuite/ltrace.torture/ia64-sigill.s ltrace-0.5/testsuite/ltrace.torture/ia64-sigill.s
--- ltrace-0.5-orig/testsuite/ltrace.torture/ia64-sigill.s 1969-12-31 19:00:00.000000000 -0500
+++ ltrace-0.5/testsuite/ltrace.torture/ia64-sigill.s 2007-05-04 12:51:14.000000000 -0400
@@ -0,0 +1,43 @@
+ .file "pokus.c"
+ .pred.safe_across_calls p1-p5,p16-p63
+ .section .rodata
+ .align 8
+.LC0:
+ stringz ""
+ .text
+ .align 16
+ .global main#
+ .proc main#
+main:
+ .prologue 14, 32
+ .save ar.pfs, r33
+ alloc r33 = ar.pfs, 0, 4, 1, 0
+ .vframe r34
+ mov r34 = r12
+ mov r35 = r1
+ .save rp, r32
+ mov r32 = b0
+ .body
+ addl r36 = @ltoffx(.LC0), r1
+ ;;
+ ld8.mov r36 = [r36], .LC0
+ br.call.sptk.many b0 = printf#
+ nop.b 0x0
+ nop.b 0x1
+ nop.b 0x2
+ nop.b 0x0
+ nop.b 0x1
+ nop.b 0x2
+ mov r1 = r35
+ addl r14 = 234, r0
+ ;;
+ mov r8 = r14
+ mov ar.pfs = r33
+ mov b0 = r32
+ .restore sp
+ mov r12 = r34
+ br.ret.sptk.many b0
+ ;;
+ .endp main#
+ .section .note.GNU-stack,"",@progbits
+ .ident "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-3)"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,652 +0,0 @@
diff --git a/lens_default.c b/lens_default.c
index f59d328..81025b1 100644
--- a/lens_default.c
+++ b/lens_default.c
@@ -63,7 +63,7 @@ READER(read_double, double)
int##BITS##_t i = l; \
switch (format) { \
case INT_FMT_unknown: \
- if (i < -10000 || i > 10000) \
+ if (l < -10000 || l > 10000) \
case INT_FMT_x: \
return fprintf(stream, "%#"PRIx##BITS, i); \
case INT_FMT_i: \
diff --git a/sysdeps/linux-gnu/ia64/breakpoint.c b/sysdeps/linux-gnu/ia64/breakpoint.c
index a0bfaf9..a5071b8 100644
--- a/sysdeps/linux-gnu/ia64/breakpoint.c
+++ b/sysdeps/linux-gnu/ia64/breakpoint.c
@@ -2,11 +2,12 @@
* -Ian Wienand <ianw@gelato.unsw.edu.au> 10/3/2005
*/
-#include "config.h"
-
#include <sys/ptrace.h>
#include <string.h>
-#include "common.h"
+#include <assert.h>
+
+#include "breakpoint.h"
+#include "debug.h"
static long long
extract_bit_field(char *bundle, int from, int len) {
@@ -161,9 +162,7 @@ arch_enable_breakpoint(pid_t pid, struct breakpoint *sbp)
debug(1, "Enable Breakpoint at %p)", sbp->addr);
- if (slotnum > 2)
- printf
- ("Can't insert breakpoint for slot numbers greater than 2.");
+ assert(slotnum <= 2);
addr &= ~0x0f;
bundle.ubundle[0] = ptrace(PTRACE_PEEKTEXT, pid, addr, 0);
diff --git a/sysdeps/linux-gnu/ia64/plt.c b/sysdeps/linux-gnu/ia64/plt.c
index 323df65..76a4aac 100644
--- a/sysdeps/linux-gnu/ia64/plt.c
+++ b/sysdeps/linux-gnu/ia64/plt.c
@@ -1,6 +1,8 @@
#include <gelf.h>
+
#include "proc.h"
#include "common.h"
+#include "library.h"
/* A bundle is 128 bits */
#define BUNDLE_SIZE 16
@@ -36,7 +38,7 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
unsigned long addr =
lte->plt_addr + (4 * BUNDLE_SIZE) + (BUNDLE_SIZE * entries) +
(2 * ndx * BUNDLE_SIZE);
- debug(3, "Found PLT %d entry at %lx\n", ndx, addr);
+ debug(3, "Found PLT %zd entry at %lx\n", ndx, addr);
return addr;
}
diff --git a/breakpoints.c b/breakpoints.c
index e7120ee..3eee38b 100644
--- a/breakpoints.c
+++ b/breakpoints.c
@@ -302,35 +302,6 @@ enable_all_breakpoints(Process *proc)
dict_apply_to_all(proc->breakpoints, enable_bp_cb,
proc);
}
-#ifdef __mips__
- {
- /*
- * I'm sure there is a nicer way to do this. We need to
- * insert breakpoints _after_ the child has been started.
- */
- struct library_symbol *sym;
- struct library_symbol *new_sym;
- sym=proc->list_of_symbols;
- while(sym){
- void *addr= sym2addr(proc,sym);
- if(!addr){
- sym=sym->next;
- continue;
- }
- if(dict_find_entry(proc->breakpoints,addr)){
- sym=sym->next;
- continue;
- }
- debug(2,"inserting bp %p %s",addr,sym->name);
- new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1);
- memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1);
- new_sym->next=proc->list_of_symbols;
- proc->list_of_symbols=new_sym;
- insert_breakpoint(proc, addr, new_sym);
- sym=sym->next;
- }
- }
-#endif
}
static void
diff --git a/handle_event.c b/handle_event.c
index 5b6cc40..1720cb3 100644
--- a/handle_event.c
+++ b/handle_event.c
@@ -232,6 +232,7 @@ pending_new_remove(pid_t pid) {
debug(DEBUG_FUNCTION, "pending_new_remove(%d)", pid);
p = pending_news;
+ pred = NULL;
if (p->pid == pid) {
pending_news = p->next;
free(p);
@@ -592,25 +593,6 @@ handle_breakpoint(Event *event)
for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
if (brk_addr == event->proc->callstack[i].return_addr) {
-#if defined(__mips__)
- void *addr = NULL;
- struct library_symbol *sym= event->proc->callstack[i].c_un.libfunc;
- struct library_symbol *new_sym;
- assert(sym);
- addr = sym2addr(event->proc, sym);
- sbp = dict_find_entry(leader->breakpoints, addr);
- if (sbp) {
- if (addr != sbp->addr) {
- insert_breakpoint(event->proc, addr, sym);
- }
- } else {
- new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1);
- memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1);
- new_sym->next = leader->list_of_symbols;
- leader->list_of_symbols = new_sym;
- insert_breakpoint(event->proc, addr, new_sym);
- }
-#endif
for (j = event->proc->callstack_depth - 1; j > i; j--) {
callstack_pop(event->proc);
}
diff --git a/ltrace-elf.c b/ltrace-elf.c
index c8667a7..bc99c6a 100644
--- a/ltrace-elf.c
+++ b/ltrace-elf.c
@@ -50,10 +50,6 @@
#include "debug.h"
#include "options.h"
-#ifdef PLT_REINITALISATION_BP
-extern char *PLTs_initialized_by_here;
-#endif
-
#ifndef ARCH_HAVE_LTELF_DATA
int
arch_elf_init(struct ltelf *lte, struct library *lib)
diff --git a/ltrace.1 b/ltrace.1
index 604f4da..fb64289 100644
--- a/ltrace.1
+++ b/ltrace.1
@@ -7,7 +7,7 @@ ltrace \- A library call tracer
.SH SYNOPSIS
.B ltrace
-.I "[-bCfghiLrStttV] [-a column] [-A maxelts] [-D level] [-e expr] [-l filename] [-n nr] [-o filename] [-p pid] ... [-s strsize] [-u username] [-w count] [-X extern] [-x extern] ... [--align=column] [--debug=level] [--demangle] [--help] [--indent=nr] [--library=filename] [--no-signals] [--output=filename] [--version] [--where=NR] [command [arg ...]]"
+.I "[-bCfghiLrStttV] [-a column] [-A maxelts] [-D level] [-e expr] [-l filename] [-n nr] [-o filename] [-p pid] ... [-s strsize] [-u username] [-w count] [-x extern] ... [--align=column] [--debug=level] [--demangle] [--help] [--indent=nr] [--library=filename] [--no-signals] [--output=filename] [--version] [--where=NR] [command [arg ...]]"
.SH DESCRIPTION
.B ltrace
@@ -158,14 +158,6 @@ correct execution of setuid and/or setgid binaries.
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 extern
-Some architectures need to know where to set a breakpoint that will be hit
-after the dynamic linker has run. If this flag is used, then the breakpoint
-is set at
-.IR extern ,
-which must be an external function. By default, '_start' is used.
-NOTE: this flag is only available on the architectures that need it.
-.TP
.I \-x filter
A qualifying expression which modifies which symbol table entry points
to trace. The format of the filter expression is described in the
diff --git a/options.c b/options.c
index 8dce7f8..b9472a8 100644
--- a/options.c
+++ b/options.c
@@ -50,12 +50,6 @@ struct opt_p_t *opt_p = NULL; /* attach to process with a given pid */
/* List of filenames give to option -F: */
struct opt_F_t *opt_F = NULL; /* alternate configuration file(s) */
-#ifdef PLT_REINITALISATION_BP
-/* Set a break on the routine named here in order to re-initialize breakpoints
- after all the PLTs have been initialzed */
-char *PLTs_initialized_by_here = PLT_REINITALISATION_BP;
-#endif
-
static void
err_usage(void) {
fprintf(stderr, "Try `%s --help' for more information\n", progname);
@@ -78,7 +72,6 @@ usage(void) {
" -e expr modify which events to trace.\n"
" -f trace children (fork() and clone()).\n"
" -F, --config=FILE load alternate configuration file (may be repeated).\n"
- " -g, --no-plt disable breakpoints on PLT entries.\n"
" -h, --help display this help and exit.\n"
" -i print instruction pointer at time of library call.\n"
" -l, --library=FILE print library calls from this library only.\n"
@@ -97,9 +90,6 @@ usage(void) {
" -w=NR, --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"
-#ifdef PLT_REINITALISATION_BP
- " -X NAME same as -x; and PLT's will be initialized by here.\n"
-#endif
"\nReport bugs to ltrace-devel@lists.alioth.debian.org\n",
progname);
}
@@ -560,14 +550,6 @@ process_options(int argc, char **argv)
options.bt_depth = atoi(optarg);
break;
#endif /* defined(HAVE_LIBUNWIND) */
- case 'X':
-#ifdef PLT_REINITALISATION_BP
- PLTs_initialized_by_here = optarg;
-#else
- fprintf(stderr, "WARNING: \"-X\" not used for this "
- "architecture: assuming you meant \"-x\"\n");
-#endif
- /* Fall Thru */
case 'x':
parse_filter_chain(optarg, &options.static_filter);
diff --git a/sysdeps/linux-gnu/ppc/arch.h b/sysdeps/linux-gnu/ppc/arch.h
index 846961e..2d0ad65 100644
--- a/sysdeps/linux-gnu/ppc/arch.h
+++ b/sysdeps/linux-gnu/ppc/arch.h
@@ -37,8 +37,6 @@
#define ARCH_SUPPORTS_OPD
#endif
-#define PLT_REINITALISATION_BP "_start"
-
#define ARCH_ENDIAN_BIG
#define ARCH_HAVE_ATOMIC_SINGLESTEP
#define ARCH_HAVE_ADD_PLT_ENTRY
diff --git a/Makefile.am b/Makefile.am
index 177a498..47161f8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -85,6 +85,7 @@ noinst_HEADERS = \
type.h \
value.h \
value_dict.h \
+ callback.h \
expr.h \
fetch.h \
vect.h \
diff --git a/callback.h b/callback.h
new file mode 100644
index 0000000..31e5c8f
--- /dev/null
+++ b/callback.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 2011,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
+ */
+
+#ifndef _CALLBACK_H_
+#define _CALLBACK_H_
+
+/* Notes on the iteration interface used across ltrace. Typically the
+ * iteration function looks something like this:
+ *
+ * foo *each_foo(foo *start_after,
+ * enum callback_status (*cb)(foo *f, void *data),
+ * void *data);
+ *
+ * The iteration starts after the element designated by START_AFTER,
+ * or at the first element if START_AFTER is NULL. CB is then called
+ * for each element of the collection. DATA is passed verbatim to CB.
+ * If CB returns CBS_STOP, the iteration stops and the current element
+ * is returned. That element can then be passed as START_AFTER to
+ * restart the iteration. NULL is returned when iteration ends.
+ *
+ * CBS_FAIL is not currently handled, and essentially means the same
+ * thing as CBS_STOP. There's no provision for returning error
+ * states. Errors need to be signaled to the caller via DATA,
+ * together with any other data that the callback needs.
+ */
+enum callback_status {
+ CBS_STOP, /* The iteration should stop. */
+ CBS_CONT, /* The iteration should continue. */
+ CBS_FAIL, /* There was an error. The iteration should stop
+ * and return error. */
+};
+
+#endif /* _CALLBACK_H_ */
diff --git a/filter.c b/filter.c
index 003010d..bf77b76 100644
--- a/filter.c
+++ b/filter.c
@@ -25,6 +25,7 @@
#include "filter.h"
#include "library.h"
+#include "callback.h"
void
filter_init(struct filter *filt)
diff --git a/forward.h b/forward.h
index e4233e5..8c03319 100644
--- a/forward.h
+++ b/forward.h
@@ -12,3 +12,4 @@ struct param;
struct param_enum;
struct value;
struct value_dict;
+struct filter;
diff --git a/library.c b/library.c
index 2ce3427..cbd4a35 100644
--- a/library.c
+++ b/library.c
@@ -25,8 +25,9 @@
#include <assert.h>
#include "library.h"
-#include "proc.h" // for enum callback_status
+#include "callback.h"
#include "debug.h"
+#include "dict.h"
#include "backend.h" // for arch_library_symbol_init, arch_library_init
#ifndef ARCH_HAVE_LIBRARY_DATA
diff --git a/library.h b/library.h
index 876a533..f207502 100644
--- a/library.h
+++ b/library.h
@@ -23,6 +23,7 @@
#define _LIBRARY_H_
#include <stdint.h>
+#include "callback.h"
#include "sysdep.h"
struct Process;
@@ -144,9 +145,8 @@ void library_set_soname(struct library *lib,
void library_set_pathname(struct library *lib,
const char *new_name, int own_name);
-/* Iterate through list of symbols of library LIB. Restarts are
- * supported via START_AFTER (see each_process for details of
- * iteration interface). */
+/* Iterate through list of symbols of library LIB. See callback.h for
+ * notes on this interface. */
struct library_symbol *library_each_symbol
(struct library *lib, struct library_symbol *start_after,
enum callback_status (*cb)(struct library_symbol *, void *),
diff --git a/options.c b/options.c
index b9472a8..87dddb0 100644
--- a/options.c
+++ b/options.c
@@ -52,7 +52,7 @@ struct opt_F_t *opt_F = NULL; /* alternate configuration file(s) */
static void
err_usage(void) {
- fprintf(stderr, "Try `%s --help' for more information\n", progname);
+ fprintf(stderr, "Try `%s --help' for more information.\n", progname);
exit(1);
}
@@ -127,7 +127,7 @@ search_for_command(char *filename) {
m = n = strlen(path);
}
if (n + strlen(filename) + 1 >= PATH_MAX) {
- fprintf(stderr, "Error: filename too long\n");
+ fprintf(stderr, "Error: filename too long.\n");
exit(1);
}
strncpy(pathname, path, n);
@@ -173,7 +173,7 @@ add_filter_rule(struct filter *filt, const char *expr,
struct filter_lib_matcher *matcher = malloc(sizeof(*matcher));
if (rule == NULL || matcher == NULL) {
- fprintf(stderr, "rule near '%s' will be ignored: %s\n",
+ fprintf(stderr, "Rule near '%s' will be ignored: %s.\n",
expr, strerror(errno));
fail:
free(rule);
@@ -193,7 +193,7 @@ add_filter_rule(struct filter *filt, const char *expr,
if (status != 0) {
char buf[100];
regerror(status, &symbol_re, buf, sizeof buf);
- fprintf(stderr, "rule near '%s' will be ignored: %s\n",
+ fprintf(stderr, "Rule near '%s' will be ignored: %s.\n",
expr, buf);
goto fail;
}
@@ -301,8 +301,8 @@ parse_filter(struct filter *filt, char *expr)
/* /XXX@YYY/ is the same as
* /XXX/@/YYY/. */
if (libend[0] != '/')
- fprintf(stderr, "unmatched '/'"
- " in symbol name\n");
+ fprintf(stderr, "Unmatched '/'"
+ " in symbol name.\n");
else
*libend-- = 0;
}
@@ -339,7 +339,7 @@ recursive_parse_chain(char *expr)
{
struct filter *filt = malloc(sizeof(*filt));
if (filt == NULL) {
- fprintf(stderr, "(part of) filter will be ignored: '%s': %s\n",
+ fprintf(stderr, "(Part of) filter will be ignored: '%s': %s.\n",
expr, strerror(errno));
return NULL;
}
@@ -359,7 +359,7 @@ parse_filter_chain(const char *expr, struct filter **retp)
{
char *str = strdup(expr);
if (str == NULL) {
- fprintf(stderr, "filter '%s' will be ignored: %s\n",
+ fprintf(stderr, "Filter '%s' will be ignored: %s.\n",
expr, strerror(errno));
return;
}
@@ -598,7 +598,8 @@ process_options(int argc, char **argv)
err_usage();
}
if (opt_r && opt_t) {
- fprintf(stderr, "%s: Incompatible options -r and -t\n",
+ fprintf(stderr,
+ "%s: Options -r and -t can't be used together\n",
progname);
err_usage();
}
diff --git a/options.h b/options.h
index 3ffee71..0806928 100644
--- a/options.h
+++ b/options.h
@@ -1,7 +1,7 @@
#include <stdio.h>
#include <sys/types.h>
-struct filter;
+#include "forward.h"
struct options_t {
int align; /* -a: default alignment column for results */
diff --git a/proc.h b/proc.h
index 64c37a9..b61e420 100644
--- a/proc.h
+++ b/proc.h
@@ -34,20 +34,11 @@
#include "ltrace.h"
#include "dict.h"
#include "sysdep.h"
+#include "callback.h"
struct library;
struct breakpoint;
-/* XXX Move this somewhere where it makes sense. When the mess in
- * common.h is disentangled, that would actually be a good place for
- * this. */
-enum callback_status {
- CBS_STOP, /* The iteration should stop. */
- CBS_CONT, /* The iteration should continue. */
- CBS_FAIL, /* There was an error. The iteration should stop
- * and return error. */
-};
-
struct event_handler {
/* Event handler that overrides the default one. Should
* return NULL if the event was handled, otherwise the
@@ -184,28 +175,16 @@ Process * pid2proc(pid_t pid);
* Returns 0 on success or a negative value on failure. */
int process_clone(struct Process *retp, struct Process *proc, pid_t pid);
-/* Iterate through the processes that ltrace currently traces. CB is
- * called for each process. Tasks are considered to be processes for
- * the purpose of this iterator.
- *
- * Notes on this iteration interface: The iteration starts after the
- * process designated by START_AFTER, or at the first process if
- * START_AFTER is NULL. DATA is passed verbatim to CB. If CB returns
- * CBS_STOP, the iteration stops and the current iterator is returned.
- * That iterator can then be used to restart the iteration. NULL is
- * returned when iteration ends.
- *
- * There's no provision for returning error states. Errors need to be
- * signaled to the caller via DATA, together with any other data that
- * the callback needs. */
+/* 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);
-/* Iterate through list of tasks of given process PROC. Restarts are
- * supported via START_AFTER (see each_process for details of
- * iteration interface). */
+/* 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),
@@ -227,8 +206,8 @@ void proc_add_library(struct Process *proc, struct library *lib);
* was found and unlinked, otherwise returns a negative value. */
int proc_remove_library(struct Process *proc, struct library *lib);
-/* Iterate through the libraries of PROC. See each_process for
- * detailed description of the iteration interface. */
+/* 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 *l,
@@ -242,8 +221,8 @@ int proc_add_breakpoint(struct Process *proc, struct breakpoint *bp);
* does not find BP in PROC, it's hard error guarded by assertion. */
void proc_remove_breakpoint(struct Process *proc, struct breakpoint *bp);
-/* Iterate through the libraries of PROC. See each_process for
- * detailed description of the iteration interface. */
+/* 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,
struct breakpoint *bp,
diff --git a/sysdeps/linux-gnu/x86/arch.h b/sysdeps/linux-gnu/x86/arch.h
index 77a09d7..329cfba 100644
--- a/sysdeps/linux-gnu/x86/arch.h
+++ b/sysdeps/linux-gnu/x86/arch.h
@@ -1,6 +1,6 @@
/*
* This file is part of ltrace.
- * Copyright (C) 2011 Petr Machata
+ * Copyright (C) 2011, 2012 Petr Machata
* Copyright (C) 2006 Ian Wienand
* Copyright (C) 2004 Juan Cespedes
*
@@ -34,7 +34,3 @@
#endif
#define LT_ELFCLASS2 ELFCLASS32
#define LT_ELF_MACHINE2 EM_386
-
-/* __NR_fork, __NR_clone, __NR_clone2, __NR_vfork and __NR_execve
- from asm-i386/unistd.h. */
-#define FORK_EXEC_SYSCALLS , { 2, 120, -1, 190, 11 }
diff --git a/testsuite/ltrace.main/parameters.c b/testsuite/ltrace.main/parameters.c
index 158fdd7..44d54b2 100644
--- a/testsuite/ltrace.main/parameters.c
+++ b/testsuite/ltrace.main/parameters.c
@@ -190,7 +190,7 @@ main ()
"%c %d %g %d %g %c %d "
"%hd %d %c %g %g %g "
"%ld %g %g %g %g",
- 1, 2, 3, 4.0, '5', 6, 7.0,
+ 1, 2, 3L, 4.0, '5', 6, 7.0,
'8', 9, 10.0, 11, 12.0, 'A', 14,
(short)15, 16, 'B', 18.0, 19.0, 20.0,
21L, 22.0, 23.0, 24.0, 25.0);
diff --git a/vect.c b/vect.c
index f2e58b2..7dae847 100644
--- a/vect.c
+++ b/vect.c
@@ -134,3 +134,25 @@ vect_destroy(struct vect *vec, void (*dtor)(void *emt, void *data), void *data)
}
free(vec->data);
}
+
+void *
+vect_each(struct vect *vec, void *start_after,
+ enum callback_status (*cb)(void *, void *), void *data)
+{
+ size_t i = start_after == NULL ? 0
+ : ((start_after - vec->data) / vec->elt_size) + 1;
+
+ for (; i < vec->size; ++i) {
+ void *slt = slot(vec, i);
+ switch ((*cb)(slt, data)) {
+ case CBS_FAIL:
+ /* XXX handle me */
+ case CBS_STOP:
+ return slt;
+ case CBS_CONT:
+ break;
+ }
+ }
+
+ return NULL;
+}
diff --git a/vect.h b/vect.h
index 50401bb..c07235f 100644
--- a/vect.h
+++ b/vect.h
@@ -22,6 +22,9 @@
#define VECT_H
#include <stddef.h>
+#include <assert.h>
+
+#include "callback.h"
/* Vector is an array that can grow as needed to accommodate the data
* that it needs to hold. ELT_SIZE is also used as an elementary
@@ -122,4 +125,22 @@ void vect_destroy(struct vect *vec,
DATA); \
} while (0)
+/* Iterate through vector VEC. See callback.h for notes on iteration
+ * interfaces. */
+void *vect_each(struct vect *vec, void *start_after,
+ enum callback_status (*cb)(void *, void *), void *data);
+
+#define VECT_EACH(VECP, ELT_TYPE, START_AFTER, CB, DATA) \
+ /* xxx GCC-ism necessary to get in the safety latches. */ \
+ ({ \
+ assert((VECP)->elt_size == sizeof(ELT_TYPE)); \
+ /* Check that CB is typed properly. */ \
+ enum callback_status (*_cb)(ELT_TYPE *, void *) = CB; \
+ ELT_TYPE *start_after = (START_AFTER); \
+ (ELT_TYPE *)vect_each((VECP), start_after, \
+ (enum callback_status \
+ (*)(void *, void *))_cb, \
+ DATA); \
+ })
+
#endif /* VECT_H */

View File

@ -1,12 +0,0 @@
diff --git a/testsuite/ltrace.minor/trace-clone.c b/testsuite/ltrace.minor/trace-clone.c
index a1ccb22..6e1c809 100644
--- a/testsuite/ltrace.minor/trace-clone.c
+++ b/testsuite/ltrace.minor/trace-clone.c
@@ -4,6 +4,7 @@
This file was written by Yao Qi <qiyao@cn.ibm.com>. */
+#define _GNU_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +0,0 @@
diff --git a/options.c b/options.c
index d5edc1a..8dce7f8 100644
--- a/options.c
+++ b/options.c
@@ -494,9 +494,19 @@ process_options(int argc, char **argv)
case 'L':
libcalls = 0;
break;
- case 'n':
- options.indent = atoi(optarg);
+ case 'n': {
+ char *endptr;
+ long int l = strtol(optarg, &endptr, 0);
+ /* Arbitrary cut-off. Nobody needs to indent
+ * more than, say, 8, anyway. */
+ if (l < 0 || l > 20 || *optarg == 0 || *endptr != 0) {
+ fprintf(stderr, "Invalid argument to -n: '%s'."
+ " Use integer 0..20.\n", optarg);
+ exit(1);
+ }
+ options.indent = (int)l;
break;
+ }
case 'o':
options.output = fopen(optarg, "w");
if (!options.output) {

View File

@ -1,86 +0,0 @@
diff --git a/Makefile.am b/Makefile.am
index 256c940..593e943 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,6 +35,7 @@ libltrace_la_LIBADD = \
$(libelf_LIBS) \
$(liberty_LIBS) \
$(libsupcxx_LIBS) \
+ $(libstdcxx_LIBS) \
$(libunwind_LIBS) \
$(libunwind_ptrace_LIBS) \
$(libunwind_arch_LIBS) \
diff --git a/common.h b/common.h
index 7fffa76..b84a5d1 100644
--- a/common.h
+++ b/common.h
@@ -16,7 +16,10 @@
#include "read_config_file.h"
#include "proc.h"
-#if defined HAVE_LIBIBERTY || defined HAVE_LIBSUPC__
+#if defined HAVE_LIBSUPC__ || defined HAVE_LIBSTDC__
+# define USE_CXA_DEMANGLE
+#endif
+#if defined HAVE_LIBIBERTY || defined USE_CXA_DEMANGLE
# define USE_DEMANGLE
#endif
diff --git a/configure.ac b/configure.ac
index 707f8c5..1ec7242 100644
--- a/configure.ac
+++ b/configure.ac
@@ -82,6 +82,14 @@ AC_CHECK_LIB([supc++], [__cxa_demangle], [
AC_SUBST(libsupcxx_LIBS)
+# HAVE_LIBSTDC__
+AC_CHECK_LIB([stdc++], [__cxa_demangle], [
+ AC_DEFINE([HAVE_LIBSTDC__], [1], [we have libstdc++])
+ libstdcxx_LIBS="-lstdc++"], [
+ libstdcxx_LIBS=""])
+AC_SUBST(libstdcxx_LIBS)
+
+
dnl Check security_get_boolean_active availability.
AC_CHECK_HEADERS(selinux/selinux.h)
AC_CHECK_LIB(selinux, security_get_boolean_active)
diff --git a/demangle.c b/demangle.c
index 5825e28..26a5c7a 100644
--- a/demangle.c
+++ b/demangle.c
@@ -15,9 +15,8 @@ static Dict *d = NULL;
const char *
my_demangle(const char *function_name) {
const char *tmp, *fn_copy;
-#if !defined HAVE_LIBIBERTY && defined HAVE_LIBSUPC__
+#ifdef USE_CXA_DEMANGLE
extern char *__cxa_demangle(const char *, char *, size_t *, int *);
- int status = 0;
#endif
debug(DEBUG_FUNCTION, "my_demangle(name=%s)", function_name);
@@ -30,7 +29,8 @@ my_demangle(const char *function_name) {
fn_copy = strdup(function_name);
#ifdef HAVE_LIBIBERTY
tmp = cplus_demangle(function_name, DMGL_ANSI | DMGL_PARAMS);
-#elif defined HAVE_LIBSUPC__
+#elif defined USE_CXA_DEMANGLE
+ int status = 0;
tmp = __cxa_demangle(function_name, NULL, NULL, &status);
#endif
if (!tmp)
diff --git a/testsuite/ltrace.minor/demangle.exp b/testsuite/ltrace.minor/demangle.exp
index c2d3aeb..9dd7694 100644
--- a/testsuite/ltrace.minor/demangle.exp
+++ b/testsuite/ltrace.minor/demangle.exp
@@ -32,6 +32,9 @@ if [regexp {ELF from incompatible architecture} $exec_output] {
} elseif [ regexp {Couldn't get .hash data} $exec_output ] {
fail "Couldn't get .hash data!"
return
+} elseif [ regexp {invalid option} $exec_output ] {
+ unsupported "Demangle support not compiled in."
+ return
}
# read function declarations from demangle.cpp and verify them in demangle.ltrace.

View File

@ -1,141 +0,0 @@
diff --git a/common.h b/common.h
index 2399e29..b6e10f2 100644
--- a/common.h
+++ b/common.h
@@ -347,7 +347,6 @@ extern void continue_after_signal(pid_t pid, int signum);
extern void continue_after_syscall(Process *proc, int sysnum, int ret_p);
extern void continue_after_breakpoint(Process * proc, struct breakpoint *sbp);
extern void continue_after_vfork(Process * proc);
-extern void ltrace_exiting(void);
extern long gimme_arg(enum tof type, Process * proc, int arg_num, arg_type_info * info);
extern void save_register_args(enum tof type, Process * proc);
extern int umovestr(Process * proc, void * addr, int len, void * laddr);
@@ -363,5 +362,21 @@ extern int task_kill (pid_t pid, int sig);
* any platform-specific knowledge of why it could be so. */
void trace_fail_warning(pid_t pid);
+/* A pair of functions called to initiate a detachment request when
+ * ltrace is about to exit. Their job is to undo any effects that
+ * tracing had and eventually detach process, perhaps by way of
+ * installing a process handler.
+ *
+ * OS_LTRACE_EXITING_SIGHANDLER is called from a signal handler
+ * context right after the signal was captured. It returns 1 if the
+ * request was handled or 0 if it wasn't.
+ *
+ * If the call to OS_LTRACE_EXITING_SIGHANDLER didn't handle the
+ * request, OS_LTRACE_EXITING is called when the next event is
+ * generated. Therefore it's called in "safe" context, without
+ * re-entrancy concerns, but it's only called after an even is
+ * generated. */
+int os_ltrace_exiting_sighandler(void);
+void os_ltrace_exiting(void);
extern struct ltelf main_lte;
diff --git a/handle_event.c b/handle_event.c
index e3d3d0a..725f50d 100644
--- a/handle_event.c
+++ b/handle_event.c
@@ -49,11 +49,12 @@ call_handler(Process * proc, Event * event)
}
void
-handle_event(Event *event) {
+handle_event(Event *event)
+{
if (exiting == 1) {
- exiting = 2;
debug(1, "ltrace about to exit");
- ltrace_exiting();
+ os_ltrace_exiting();
+ exiting = 2;
}
debug(DEBUG_FUNCTION, "handle_event(pid=%d, type=%d)",
event->proc ? event->proc->pid : -1, event->type);
diff --git a/libltrace.c b/libltrace.c
index 19bfafd..777ad1b 100644
--- a/libltrace.c
+++ b/libltrace.c
@@ -48,9 +48,14 @@ signal_alarm(int sig) {
}
static void
-signal_exit(int sig) {
- exiting = 1;
+signal_exit(int sig)
+{
debug(1, "Received interrupt signal; exiting...");
+ if (exiting != 0)
+ return;
+
+ exiting = 1 + !!os_ltrace_exiting_sighandler();
+
signal(SIGINT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGALRM, signal_alarm);
diff --git a/sysdeps/linux-gnu/events.c b/sysdeps/linux-gnu/events.c
index 021192f..b6c12ef 100644
--- a/sysdeps/linux-gnu/events.c
+++ b/sysdeps/linux-gnu/events.c
@@ -104,6 +104,8 @@ next_qd_event(void)
return each_qd_event(&event_process_not_reenabling, NULL);
}
+int linux_in_waitpid = 0;
+
Event *
next_event(void)
{
@@ -124,7 +126,11 @@ next_event(void)
debug(DEBUG_EVENT, "event: No more traced programs: exiting");
exit(0);
}
+
+ linux_in_waitpid = 1;
pid = waitpid(-1, &status, __WALL);
+ linux_in_waitpid = 0;
+
if (pid == -1) {
if (errno == ECHILD) {
debug(DEBUG_EVENT, "event: No more traced programs: exiting");
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
index 82a4154..9ecea1e 100644
--- a/sysdeps/linux-gnu/trace.c
+++ b/sysdeps/linux-gnu/trace.c
@@ -314,8 +314,8 @@ task_stopped(Process * task, void * data)
case ps_invalid:
case ps_tracing_stop:
case ps_zombie:
- case ps_sleeping:
return pcb_cont;
+ case ps_sleeping:
case ps_stop:
case ps_other:
return pcb_stop;
@@ -1005,7 +1005,7 @@ continue_after_syscall(Process * proc, int sysnum, int ret_p)
* detaches.
*/
void
-ltrace_exiting(void)
+os_ltrace_exiting(void)
{
struct opt_p_t * it;
for (it = opt_p; it != NULL; it = it->next) {
@@ -1019,6 +1019,17 @@ ltrace_exiting(void)
}
}
+int
+os_ltrace_exiting_sighandler(void)
+{
+ extern int linux_in_waitpid;
+ if (linux_in_waitpid) {
+ os_ltrace_exiting();
+ return 1;
+ }
+ return 0;
+}
+
size_t
umovebytes(Process *proc, void *addr, void *laddr, size_t len) {

View File

@ -1,203 +0,0 @@
diff --git a/sysdeps/linux-gnu/alpha/arch.h b/sysdeps/linux-gnu/alpha/arch.h
index 1107b5f..2dfeec7 100644
--- a/sysdeps/linux-gnu/alpha/arch.h
+++ b/sysdeps/linux-gnu/alpha/arch.h
@@ -1,6 +1,7 @@
#define BREAKPOINT_VALUE { 0x80, 0x00, 0x00, 0x00 }
#define BREAKPOINT_LENGTH 4
#define DECR_PC_AFTER_BREAK 4
+#define ARCH_ENDIAN_LITTLE
#define LT_ELFCLASS ELFCLASS64
#define LT_ELF_MACHINE EM_ALPHA
diff --git a/sysdeps/linux-gnu/arm/arch.h b/sysdeps/linux-gnu/arm/arch.h
index 8f2dfb3..e2a62ab 100644
--- a/sysdeps/linux-gnu/arm/arch.h
+++ b/sysdeps/linux-gnu/arm/arch.h
@@ -6,6 +6,7 @@
#define THUMB_BREAKPOINT_VALUE { 0x01, 0xde }
#define THUMB_BREAKPOINT_LENGTH 2
#define DECR_PC_AFTER_BREAK 0
+#define ARCH_ENDIAN_LITTLE
#define LT_ELFCLASS ELFCLASS32
#define LT_ELF_MACHINE EM_ARM
diff --git a/sysdeps/linux-gnu/i386/arch.h b/sysdeps/linux-gnu/i386/arch.h
index dc7383f..15f0d78 100644
--- a/sysdeps/linux-gnu/i386/arch.h
+++ b/sysdeps/linux-gnu/i386/arch.h
@@ -1,6 +1,7 @@
#define BREAKPOINT_VALUE {0xcc}
#define BREAKPOINT_LENGTH 1
#define DECR_PC_AFTER_BREAK 1
+#define ARCH_ENDIAN_LITTLE
#define LT_ELFCLASS ELFCLASS32
#define LT_ELF_MACHINE EM_386
diff --git a/sysdeps/linux-gnu/ia64/arch.h b/sysdeps/linux-gnu/ia64/arch.h
index 673047c..d7e0d23 100644
--- a/sysdeps/linux-gnu/ia64/arch.h
+++ b/sysdeps/linux-gnu/ia64/arch.h
@@ -4,6 +4,7 @@
#define BREAKPOINT_LENGTH 16
#define BREAKPOINT_VALUE {0}
#define DECR_PC_AFTER_BREAK 0
+#define ARCH_ENDIAN_LITTLE
#define LT_ELFCLASS ELFCLASS64
#define LT_ELF_MACHINE EM_IA_64
diff --git a/sysdeps/linux-gnu/m68k/arch.h b/sysdeps/linux-gnu/m68k/arch.h
index 1790d09..44fad89 100644
--- a/sysdeps/linux-gnu/m68k/arch.h
+++ b/sysdeps/linux-gnu/m68k/arch.h
@@ -1,6 +1,7 @@
#define BREAKPOINT_VALUE { 0x4e, 0x4f }
#define BREAKPOINT_LENGTH 2
#define DECR_PC_AFTER_BREAK 2
+#define ARCH_ENDIAN_BIG
#define LT_ELFCLASS ELFCLASS32
#define LT_ELF_MACHINE EM_68K
diff --git a/sysdeps/linux-gnu/mipsel/arch.h b/sysdeps/linux-gnu/mipsel/arch.h
index dd0ca35..45c4598 100644
--- a/sysdeps/linux-gnu/mipsel/arch.h
+++ b/sysdeps/linux-gnu/mipsel/arch.h
@@ -1,6 +1,7 @@
#define BREAKPOINT_VALUE { 0x0d, 0x00, 0x00, 0x00 }
#define BREAKPOINT_LENGTH 4
#define DECR_PC_AFTER_BREAK 0
+#define ARCH_ENDIAN_LITTLE
#define LT_ELFCLASS ELFCLASS32
#define LT_ELF_MACHINE EM_MIPS
diff --git a/sysdeps/linux-gnu/ppc/arch.h b/sysdeps/linux-gnu/ppc/arch.h
index 711b4a3..8b955e8 100644
--- a/sysdeps/linux-gnu/ppc/arch.h
+++ b/sysdeps/linux-gnu/ppc/arch.h
@@ -14,7 +14,7 @@
#define PLT_REINITALISATION_BP "_start"
/* Start of arch-specific functions. */
-#define ARCH_HAVE_UMOVELONG
+#define ARCH_ENDIAN_BIG
#define PPC_NOP { 0x60, 0x00, 0x00, 0x00 }
#define PPC_NOP_LENGTH 4
diff -up ltrace-0.6.0/sysdeps/linux-gnu/ppc/trace.c\~ ltrace-0.6.0/sysdeps/linux-gnu/ppc/trace.c
--- ltrace-0.6.0/sysdeps/linux-gnu/ppc/trace.c~ 2011-02-14 16:48:25.000000000 +0100
+++ ltrace-0.6.0/sysdeps/linux-gnu/ppc/trace.c 2011-09-03 00:18:14.518317665 +0200
@@ -156,34 +156,3 @@ save_register_args(enum tof type, Proces
memcpy(&arch->regs_copy, &arch->regs, sizeof(arch->regs));
memcpy(&arch->fpregs_copy, &arch->fpregs, sizeof(arch->fpregs));
}
-
-/* Read a single long from the process's memory address 'addr'. */
-int
-arch_umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
- long pointed_to;
-
- errno = 0;
-
- pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0);
-
- if (pointed_to == -1 && errno)
- return -errno;
-
- /* Since int's are 4-bytes (long is 8-bytes) in length for ppc64, we
- need to shift the long values returned by ptrace to end up with
- the correct value. */
-
- if (info) {
- if (info->type == ARGTYPE_INT || (proc->mask_32bit && (info->type == ARGTYPE_POINTER
- || info->type == ARGTYPE_STRING))) {
- pointed_to = pointed_to >> 32;
-
- /* Make sure we have nothing in the upper word so we can
- do a explicit cast from long to int later in the code. */
- pointed_to &= 0x00000000ffffffff;
- }
- }
-
- *result = pointed_to;
- return 0;
-}
diff --git a/sysdeps/linux-gnu/s390/arch.h b/sysdeps/linux-gnu/s390/arch.h
index 5cf168c..c6fed74 100644
--- a/sysdeps/linux-gnu/s390/arch.h
+++ b/sysdeps/linux-gnu/s390/arch.h
@@ -6,6 +6,7 @@
#define BREAKPOINT_VALUE { 0x00, 0x01 }
#define BREAKPOINT_LENGTH 2
#define DECR_PC_AFTER_BREAK 2
+#define ARCH_ENDIAN_BIG
#ifdef __s390x__
#define LT_ELFCLASS ELFCLASS64
diff --git a/sysdeps/linux-gnu/sparc/arch.h b/sysdeps/linux-gnu/sparc/arch.h
index 75251b8..bec22ce 100644
--- a/sysdeps/linux-gnu/sparc/arch.h
+++ b/sysdeps/linux-gnu/sparc/arch.h
@@ -1,6 +1,7 @@
#define BREAKPOINT_VALUE {0x91, 0xd0, 0x20, 0x01}
#define BREAKPOINT_LENGTH 4
#define DECR_PC_AFTER_BREAK 0
+#define ARCH_ENDIAN_BIG
#define LT_ELFCLASS ELFCLASS32
#define LT_ELF_MACHINE EM_SPARC
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
index e4be465..9b0b980 100644
--- a/sysdeps/linux-gnu/trace.c
+++ b/sysdeps/linux-gnu/trace.c
@@ -10,6 +10,7 @@
#include <assert.h>
#include "common.h"
+#include "config.h"
/* If the system headers did not provide the constants, hard-code the normal
values. */
@@ -54,15 +55,23 @@ umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
if (pointed_to == -1 && errno)
return -errno;
- *result = pointed_to;
- if (info) {
- switch(info->type) {
- case ARGTYPE_INT:
- *result &= 0x00000000ffffffffUL;
- default:
- break;
- };
+#if SIZEOF_LONG == 8
+ if (info != NULL
+ && (info->type == ARGTYPE_INT
+ || (proc->mask_32bit
+ && (info->type == ARGTYPE_POINTER
+ || info->type == ARGTYPE_STRING)))) {
+#if defined (ARCH_ENDIAN_LITTLE)
+ pointed_to &= 0x00000000ffffffffUL;
+#elif defined (ARCH_ENDIAN_BIG)
+ pointed_to = (long)(((unsigned long)pointed_to) >> 32);
+#else
+# error arch.h has to define endianness
+#endif
}
+#endif
+
+ *result = pointed_to;
return 0;
}
#endif
diff --git a/sysdeps/linux-gnu/x86_64/arch.h b/sysdeps/linux-gnu/x86_64/arch.h
index 255395c..34376c4 100644
--- a/sysdeps/linux-gnu/x86_64/arch.h
+++ b/sysdeps/linux-gnu/x86_64/arch.h
@@ -1,6 +1,7 @@
#define BREAKPOINT_VALUE {0xcc}
#define BREAKPOINT_LENGTH 1
#define DECR_PC_AFTER_BREAK 1
+#define ARCH_ENDIAN_LITTLE
#define LT_ELFCLASS ELFCLASS64
#define LT_ELF_MACHINE EM_X86_64

View File

@ -1,63 +0,0 @@
diff -up ltrace-0.6.0/ltrace-elf.c\~ ltrace-0.6.0/ltrace-elf.c
--- ltrace-0.6.0/ltrace-elf.c~ 2011-02-14 16:48:25.000000000 +0100
+++ ltrace-0.6.0/ltrace-elf.c 2011-02-14 18:13:03.000000000 +0100
@@ -609,6 +609,7 @@ read_elf(Process *proc) {
struct ltelf lte[MAX_LIBRARIES + 1];
size_t i;
struct opt_x_t *xptr;
+ struct opt_x_t *opt_x_loc = opt_x;
struct library_symbol **lib_tail = NULL;
int exit_out = 0;
int count = 0;
@@ -722,11 +723,11 @@ read_elf(Process *proc) {
main_cheat = (struct opt_x_t *)malloc(sizeof(struct opt_x_t));
if (main_cheat == NULL)
error(EXIT_FAILURE, 0, "Couldn't allocate memory");
- main_cheat->next = opt_x;
+ main_cheat->next = opt_x_loc;
main_cheat->found = 0;
main_cheat->name = PLTs_initialized_by_here;
- for (xptr = opt_x; xptr; xptr = xptr->next)
+ for (xptr = opt_x_loc; xptr; xptr = xptr->next)
if (strcmp(xptr->name, PLTs_initialized_by_here) == 0
&& main_cheat) {
free(main_cheat);
@@ -734,7 +735,7 @@ read_elf(Process *proc) {
break;
}
if (main_cheat)
- opt_x = main_cheat;
+ opt_x_loc = main_cheat;
}
#endif
} else {
@@ -756,7 +757,7 @@ read_elf(Process *proc) {
if (!addr)
continue;
- for (xptr = opt_x; xptr; xptr = xptr->next)
+ for (xptr = opt_x_loc; xptr; xptr = xptr->next)
if (xptr->name && strcmp(xptr->name, name) == 0) {
/* FIXME: Should be able to use &library_symbols as above. But
when you do, none of the real library symbols cause breaks. */
@@ -769,7 +770,7 @@ read_elf(Process *proc) {
unsigned found_count = 0;
- for (xptr = opt_x; xptr; xptr = xptr->next) {
+ for (xptr = opt_x_loc; xptr; xptr = xptr->next) {
if (xptr->found)
continue;
@@ -791,7 +792,7 @@ read_elf(Process *proc) {
}
}
- for (xptr = opt_x; xptr; xptr = xptr->next)
+ for (xptr = opt_x_loc; xptr; xptr = xptr->next)
if ( ! xptr->found) {
char *badthing = "WARNING";
#ifdef PLT_REINITALISATION_BP
Diff finished. Mon Feb 14 18:13:11 2011

View File

@ -1,39 +0,0 @@
diff --git a/output.c b/output.c
index ac8c9d0..db6e93e 100644
--- a/output.c
+++ b/output.c
@@ -22,9 +22,10 @@ static int current_depth = 0;
static int current_column = 0;
static void
-output_indent(Process *proc) {
- current_column +=
- fprintf(options.output, "%*s", options.indent * proc->callstack_depth, "");
+output_indent(struct Process *proc)
+{
+ int d = options.indent * (proc->callstack_depth - 1);
+ current_column += fprintf(options.output, "%*s", d, "");
}
static void
diff --git a/proc.c b/proc.c
index 51833fe..54afbe0 100644
--- a/proc.c
+++ b/proc.c
@@ -49,6 +49,7 @@ 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 int
process_bare_init(struct Process *proc, const char *filename,
@@ -96,7 +97,7 @@ process_bare_destroy(struct Process *proc, int was_exec)
dict_clear(proc->breakpoints);
if (!was_exec) {
free(proc->filename);
- remove_process(proc);
+ unlist_process(proc);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,30 +0,0 @@
diff --git a/sysdeps/linux-gnu/ppc/trace.c b/sysdeps/linux-gnu/ppc/trace.c
index 20b3f5d..321e6ec 100644
--- a/sysdeps/linux-gnu/ppc/trace.c
+++ b/sysdeps/linux-gnu/ppc/trace.c
@@ -87,10 +87,22 @@ gimme_arg_regset(enum tof type, Process *proc, int arg_num, arg_type_info *info,
}
else if (greg <= 10)
return (*regs)[greg++];
- else
+ else {
+#ifdef __powerpc64__
+ if (proc->mask_32bit)
+ return ptrace (PTRACE_PEEKDATA, proc->pid,
+ proc->stack_pointer + 8 +
+ sizeof (int) * (arg_num - 8), 0) >> 32;
+ else
+ return ptrace (PTRACE_PEEKDATA, proc->pid,
+ proc->stack_pointer + 112 +
+ sizeof (long) * (arg_num - 8), 0);
+#else
return ptrace (PTRACE_PEEKDATA, proc->pid,
- proc->stack_pointer + sizeof (long) *
- (arg_num - 8), 0);
+ proc->stack_pointer + 8 +
+ sizeof (long) * (arg_num - 8), 0);
+#endif
+ }
return 0;
}

View File

@ -1,162 +0,0 @@
From fcf256ceeab4b0b74cf1e18122e894aafce94fdc Mon Sep 17 00:00:00 2001
From: Petr Machata <pmachata@redhat.com>
Date: Thu, 30 Aug 2012 01:37:23 +0200
Subject: [PATCH] PPC64 passes floating point equivalent structures in
registers as well
Extract the structure unpacking code from s390 back end into the generic
type module. Call this from both s390 and ppc back ends.
---
sysdeps/linux-gnu/ppc/fetch.c | 21 +++++++++++++++++++--
sysdeps/linux-gnu/s390/fetch.c | 31 +------------------------------
type.c | 34 ++++++++++++++++++++++++++++++++++
type.h | 7 +++++++
4 files changed, 61 insertions(+), 32 deletions(-)
diff --git a/sysdeps/linux-gnu/ppc/fetch.c b/sysdeps/linux-gnu/ppc/fetch.c
index 44cd056..40c91d9 100644
--- a/sysdeps/linux-gnu/ppc/fetch.c
+++ b/sysdeps/linux-gnu/ppc/fetch.c
@@ -340,13 +340,30 @@ allocate_argument(struct fetch_context *ctx, struct Process *proc,
while (slots-- > 0) {
struct value val;
value_init(&val, proc, NULL, long_info, 0);
- int rc = allocate_gpr(ctx, proc, long_info, &val);
+
+ /* Floating point registers [...] are used [...] to
+ pass [...] one member aggregates passed by value
+ containing a floating point value[.] Note that for
+ one member aggregates, "containing" extends to
+ aggregates within aggregates ad infinitum. */
+ int rc;
+ struct arg_type_info *fp_info
+ = type_get_fp_equivalent(valuep->type);
+ if (fp_info != NULL)
+ rc = allocate_float(ctx, proc, fp_info, &val);
+ else
+ rc = allocate_gpr(ctx, proc, long_info, &val);
+
if (rc >= 0) {
memcpy(ptr, value_get_data(&val, NULL), width);
ptr += width;
}
value_destroy(&val);
- if (rc < 0)
+
+ /* Bail out if we failed or if we are dealing with
+ * FP-equivalent. Those don't need the adjustments
+ * made below. */
+ if (rc < 0 || fp_info != NULL)
return rc;
}
diff --git a/sysdeps/linux-gnu/s390/fetch.c b/sysdeps/linux-gnu/s390/fetch.c
index 5d26b35..c46ef7c 100644
--- a/sysdeps/linux-gnu/s390/fetch.c
+++ b/sysdeps/linux-gnu/s390/fetch.c
@@ -61,35 +61,6 @@ s390x(struct fetch_context *ctx)
}
static int
-fp_equivalent(struct arg_type_info *info)
-{
- switch (info->type) {
- case ARGTYPE_VOID:
- case ARGTYPE_INT:
- case ARGTYPE_UINT:
- case ARGTYPE_LONG:
- case ARGTYPE_ULONG:
- case ARGTYPE_CHAR:
- case ARGTYPE_SHORT:
- case ARGTYPE_USHORT:
- case ARGTYPE_ARRAY:
- case ARGTYPE_POINTER:
- return 0;
-
- case ARGTYPE_FLOAT:
- case ARGTYPE_DOUBLE:
- return 1;
-
- case ARGTYPE_STRUCT:
- if (type_struct_size(info) != 1)
- return 0;
- return fp_equivalent(type_element(info, 0));
- }
- assert(info->type != info->type);
- abort();
-}
-
-static int
fetch_register_banks(struct Process *proc, struct fetch_context *ctx)
{
ptrace_area parea;
@@ -256,7 +227,7 @@ arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
return 0;
case ARGTYPE_STRUCT:
- if (fp_equivalent(info))
+ if (type_get_fp_equivalent(info) != NULL)
/* fall through */
case ARGTYPE_FLOAT:
case ARGTYPE_DOUBLE:
diff --git a/type.c b/type.c
index 6341042..4b9a645 100644
--- a/type.c
+++ b/type.c
@@ -513,3 +513,37 @@ type_is_signed(enum arg_type type)
}
abort();
}
+
+struct arg_type_info *
+type_get_fp_equivalent(struct arg_type_info *info)
+{
+ /* Extract innermost structure. Give up early if any
+ * component has more than one element. */
+ while (info->type == ARGTYPE_STRUCT) {
+ if (type_struct_size(info) != 1)
+ return NULL;
+ info = type_element(info, 0);
+ }
+
+ switch (info->type) {
+ case ARGTYPE_CHAR:
+ case ARGTYPE_SHORT:
+ case ARGTYPE_INT:
+ case ARGTYPE_LONG:
+ case ARGTYPE_UINT:
+ case ARGTYPE_ULONG:
+ case ARGTYPE_USHORT:
+ case ARGTYPE_VOID:
+ case ARGTYPE_ARRAY:
+ case ARGTYPE_POINTER:
+ return NULL;
+
+ case ARGTYPE_FLOAT:
+ case ARGTYPE_DOUBLE:
+ return info;
+
+ case ARGTYPE_STRUCT:
+ abort();
+ }
+ abort();
+}
diff --git a/type.h b/type.h
index 545173c..53123b8 100644
--- a/type.h
+++ b/type.h
@@ -130,4 +130,11 @@ int type_is_integral(enum arg_type type);
/* Whether TYPE, which shall be integral, is a signed type. */
int type_is_signed(enum arg_type type);
+/* If INFO is floating point equivalent type, return the corresponding
+ * floating point type. Otherwise return NULL. Floating point
+ * equivalent types are either ARGTYPE_FLOAT, or ARGTYPE_DOUBLE, or
+ * ARGTYPE_STRUCT whose sole member is a floating point equivalent
+ * type. */
+struct arg_type_info *type_get_fp_equivalent(struct arg_type_info *info);
+
#endif /* TYPE_H */
--
1.7.6.5

View File

@ -1,373 +0,0 @@
diff --git a/sysdeps/linux-gnu/ppc/arch.h b/sysdeps/linux-gnu/ppc/arch.h
index 711b4a3..64c1821 100644
--- a/sysdeps/linux-gnu/ppc/arch.h
+++ b/sysdeps/linux-gnu/ppc/arch.h
@@ -15,6 +15,7 @@
/* Start of arch-specific functions. */
#define ARCH_ENDIAN_BIG
+#define ARCH_HAVE_ATOMIC_SINGLESTEP
#define PPC_NOP { 0x60, 0x00, 0x00, 0x00 }
#define PPC_NOP_LENGTH 4
diff --git a/sysdeps/linux-gnu/ppc/trace.c b/sysdeps/linux-gnu/ppc/trace.c
index 8642157..05993de 100644
--- a/sysdeps/linux-gnu/ppc/trace.c
+++ b/sysdeps/linux-gnu/ppc/trace.c
@@ -11,6 +11,7 @@
#include "common.h"
#include "ptrace.h"
+#include "breakpoint.h"
#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
# define PTRACE_PEEKUSER PTRACE_PEEKUSR
@@ -197,3 +197,85 @@ arch_umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
memcpy(&arch->regs_copy, &arch->regs, sizeof(arch->regs));
memcpy(&arch->fpregs_copy, &arch->fpregs, sizeof(arch->fpregs));
}
+
+/* The atomic skip code is mostly taken from GDB. */
+
+/* Instruction masks used during single-stepping of atomic
+ * sequences. This was lifted from GDB. */
+#define LWARX_MASK 0xfc0007fe
+#define LWARX_INSTRUCTION 0x7c000028
+#define LDARX_INSTRUCTION 0x7c0000A8
+#define STWCX_MASK 0xfc0007ff
+#define STWCX_INSTRUCTION 0x7c00012d
+#define STDCX_INSTRUCTION 0x7c0001ad
+#define BC_MASK 0xfc000000
+#define BC_INSTRUCTION 0x40000000
+
+int
+arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
+ int (*add_cb)(void *addr, void *data),
+ void *add_cb_data)
+{
+ void *addr = sbp->addr;
+ debug(1, "pid=%d addr=%p", proc->pid, addr);
+
+ /* If the original instruction was lwarx/ldarx, we can't
+ * single-step over it, instead we have to execute the whole
+ * atomic block at once. */
+ union {
+ uint32_t insn;
+ char buf[4];
+ } u;
+ memcpy(u.buf, sbp->orig_value, BREAKPOINT_LENGTH);
+
+ if ((u.insn & LWARX_MASK) != LWARX_INSTRUCTION
+ && (u.insn & LWARX_MASK) != LDARX_INSTRUCTION)
+ return 1;
+
+ int insn_count;
+ for (insn_count = 0; ; ++insn_count) {
+ addr += 4;
+ unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0);
+ if (l == (unsigned long)-1 && errno)
+ return -1;
+ uint32_t insn;
+#ifdef __powerpc64__
+ insn = l >> 32;
+#else
+ insn = l;
+#endif
+
+ /* If we hit a branch instruction, give up. The
+ * computation could escape that way and we'd have to
+ * treat that case specially. */
+ if ((insn & BC_MASK) == BC_INSTRUCTION) {
+ debug(1, "pid=%d, found branch at %p, giving up",
+ proc->pid, addr);
+ return -1;
+ }
+
+ if ((insn & STWCX_MASK) == STWCX_INSTRUCTION
+ || (insn & STWCX_MASK) == STDCX_INSTRUCTION) {
+ debug(1, "pid=%d, found end of atomic block at %p",
+ proc->pid, addr);
+ break;
+ }
+
+ /* Arbitrary cut-off. If we didn't find the
+ * terminating instruction by now, just give up. */
+ if (insn_count > 16) {
+ debug(1, "pid=%d, couldn't find end of atomic block",
+ proc->pid);
+ return -1;
+ }
+ }
+
+ /* Put the breakpoint to the next instruction. */
+ addr += 4;
+ if (add_cb(addr, add_cb_data) < 0)
+ return -1;
+
+ debug(1, "PTRACE_CONT");
+ ptrace(PTRACE_CONT, proc->pid, 0, 0);
+ return 0;
+}
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
index 9ecea1e..d962048 100644
--- a/sysdeps/linux-gnu/trace.c
+++ b/sysdeps/linux-gnu/trace.c
@@ -249,6 +249,9 @@ struct process_stopping_handler
/* The pointer being re-enabled. */
struct breakpoint *breakpoint_being_enabled;
+ /* Artificial atomic skip breakpoint, if any needed. */
+ void *atomic_skip_bp_addr;
+
enum {
/* We are waiting for everyone to land in t/T. */
psh_stopping = 0,
@@ -612,12 +615,84 @@ all_stops_accountable(struct pid_set * pids)
return 1;
}
-static void
-singlestep(Process * proc)
+/* 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)
+{
+ return 1;
+}
+#endif
+
+static int
+atomic_singlestep_add_bp(void *addr, void *data)
+{
+ struct process_stopping_handler *self = data;
+ struct Process *proc = self->task_enabling_breakpoint;
+
+ /* Only support single address as of now. */
+ assert(self->atomic_skip_bp_addr == NULL);
+
+ self->atomic_skip_bp_addr = addr + 4;
+ insert_breakpoint(proc->leader, self->atomic_skip_bp_addr, NULL, 1);
+
+ return 0;
+}
+
+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);
+
+ /* Propagate failure and success. */
+ if (status <= 0)
+ return status;
+
+ /* Otherwise do the default action: singlestep. */
debug(1, "PTRACE_SINGLESTEP");
- if (ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0))
+ if (ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0)) {
perror("PTRACE_SINGLESTEP");
+ return -1;
+ }
+ return 0;
+}
+
+static void
+post_singlestep(struct process_stopping_handler *self, Event **eventp)
+{
+ continue_for_sigstop_delivery(&self->pids);
+
+ if ((*eventp)->type == EVENT_BREAKPOINT)
+ *eventp = NULL; // handled
+
+ if (self->atomic_skip_bp_addr != 0)
+ delete_breakpoint(self->task_enabling_breakpoint->leader,
+ self->atomic_skip_bp_addr);
+
+ self->breakpoint_being_enabled = NULL;
+}
+
+static void
+singlestep_error(struct process_stopping_handler *self, Event **eventp)
+{
+ struct Process *teb = self->task_enabling_breakpoint;
+ struct breakpoint *sbp = self->breakpoint_being_enabled;
+ fprintf(stderr, "%d couldn't singlestep over %s (%p)\n",
+ teb->pid, sbp->libsym != NULL ? sbp->libsym->name : NULL,
+ sbp->addr);
+ delete_breakpoint(teb->leader, sbp->addr);
+ post_singlestep(self, eventp);
}
/* This event handler is installed when we are in the process of
@@ -670,7 +745,11 @@ process_stopping_on_event(Event_Handler * super, Event * event)
teb->pid);
if (sbp->enabled)
disable_breakpoint(teb, sbp);
- singlestep(teb);
+ if (singlestep(self) < 0) {
+ singlestep_error(self, &event);
+ goto psh_sinking;
+ }
+
self->state = state = psh_singlestep;
}
break;
@@ -682,7 +761,10 @@ process_stopping_on_event(Event_Handler * super, Event * event)
/* This is not the singlestep that we are waiting for. */
if (event->type == EVENT_SIGNAL) {
- singlestep(task);
+ if (singlestep(self) < 0) {
+ singlestep_error(self, &event);
+ goto psh_sinking;
+ }
break;
}
@@ -692,18 +774,13 @@ process_stopping_on_event(Event_Handler * super, Event * event)
if (sbp->enabled)
enable_breakpoint(teb, sbp);
- continue_for_sigstop_delivery(&self->pids);
-
- self->breakpoint_being_enabled = NULL;
- self->state = state = psh_sinking;
-
- if (event->type == EVENT_BREAKPOINT)
- event = NULL; // handled
- } else
- break;
-
- /* fall-through */
+ post_singlestep(self, &event);
+ goto psh_sinking;
+ }
+ break;
+ psh_sinking:
+ state = self->state = psh_sinking;
case psh_sinking:
if (await_sigstop_delivery(&self->pids, task_info, event))
process_stopping_done(self, leader);
diff --git a/testsuite/ltrace.torture/ppc-lwarx.c b/testsuite/ltrace.torture/ppc-lwarx.c
new file mode 100644
index 0000000..0716407
--- /dev/null
+++ b/testsuite/ltrace.torture/ppc-lwarx.c
@@ -0,0 +1,44 @@
+/*
+ * 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 <stdint.h>
+
+__attribute__((noinline, optimize(3))) void
+atomic_add(uint32_t *a, uint32_t b)
+{
+ __asm__ volatile("lwarx 9,0,%0\n"
+ "add 9,9,%2\n"
+ "stwcx. 9,0,%0\n"
+ "bne- atomic_add\n"
+ : "=r"(a)
+ : "0"(a), "r"(b)
+ : "%r9");
+}
+
+uint32_t a = 0;
+
+__attribute__((optimize(0))) int
+main(int argc, char **argv)
+{
+ atomic_add(&a, 5);
+ atomic_add(&a, 10);
+ atomic_add(&a, 15);
+ return a;
+}
diff --git a/testsuite/ltrace.torture/ppc-lwarx.exp b/testsuite/ltrace.torture/ppc-lwarx.exp
new file mode 100644
index 0000000..bc2eba4
--- /dev/null
+++ b/testsuite/ltrace.torture/ppc-lwarx.exp
@@ -0,0 +1,55 @@
+# 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
+
+set testfile "ppc-lwarx"
+set srcfile ${testfile}.c
+set binfile ${testfile}
+
+if [get_compiler_info $binfile] {
+ return -1
+}
+
+if { [istarget powerpc*-*] } then {
+ verbose "compiling source file now....."
+ if { [ltrace_compile $srcdir/$subdir/$srcfile $objdir/$subdir/$binfile executable {debug} ] != "" } {
+ send_user "Testcase compile failed, so all tests in this file will automatically fail\n."
+ }
+
+ # set options for ltrace.
+ ltrace_options "-x" "atomic_add" "-e" "!atoi"
+
+ # Run PUT for ltarce.
+ set exec_output [ltrace_runtest $objdir/$subdir $objdir/$subdir/$binfile]
+
+ # Check the output of this program.
+ verbose "ltrace runtest output: $exec_output\n"
+ if [regexp {ELF from incompatible architecture} $exec_output] {
+ fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!"
+ return
+ } elseif [ regexp {Couldn't get .hash data} $exec_output ] {
+ fail "Couldn't get .hash data!"
+ return
+ }
+
+ set pattern "atomic_add(.*, 5,.*)"
+ ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1
+ set pattern "atomic_add(.*, 10,.*)"
+ ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1
+ set pattern "atomic_add(.*, 15,.*)"
+ ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 1
+}

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +0,0 @@
diff -up ltrace-0.6.0/output.c\~ ltrace-0.6.0/output.c
--- ltrace-0.6.0/output.c~ 2011-02-14 16:48:25.000000000 +0100
+++ ltrace-0.6.0/output.c 2011-02-15 00:35:39.000000000 +0100
@@ -202,7 +204,9 @@ output_left(enum tof type, Process *proc
current_column += fprintf(options.output, ", ");
}
}
- if (func->params_right) {
+ if (func->params_right
+ || func->return_info->type == ARGTYPE_STRING_N
+ || func->return_info->type == ARGTYPE_ARRAY) {
save_register_args(type, proc);
}
}
Diff finished. Tue Feb 15 00:35:44 2011

View File

@ -1,212 +0,0 @@
From cec06ec8282c538a40bde968ae36fe8356daffaa Mon Sep 17 00:00:00 2001
From: Petr Machata <pmachata@redhat.com>
Date: Tue, 10 Apr 2012 13:31:55 +0200
Subject: [PATCH] Warn when we fail to trace and SELinux boolean deny_ptrace
is in effect
---
ChangeLog | 7 ++++++
common.h | 4 +++
configure.ac | 5 ++++
proc.c | 1 +
sysdeps/linux-gnu/trace.c | 51 ++++++++++++++++++++++++++++++++++++--------
5 files changed, 58 insertions(+), 10 deletions(-)
diff --git a/common.h b/common.h
index fa80076..2399e29 100644
--- a/common.h
+++ b/common.h
@@ -359,2 +359,6 @@ extern int linkmap_init(Process *, struct ltelf *);
+/* Called when trace_me or primary trace_pid fail. This may plug in
+ * any platform-specific knowledge of why it could be so. */
+void trace_fail_warning(pid_t pid);
+
diff --git a/configure.ac b/configure.ac
index 7fcfda5..42d6158 100644
--- a/configure.ac
+++ b/configure.ac
@@ -82,6 +82,11 @@ AC_CHECK_LIB([supc++], [__cxa_demangle], [
AC_SUBST(libsupcxx_LIBS)
+dnl Check security_get_boolean_active availability.
+AC_CHECK_HEADERS(selinux/selinux.h)
+AC_CHECK_LIB(selinux, security_get_boolean_active)
+
+
# HAVE_LIBUNWIND
AC_ARG_WITH(libunwind,
AS_HELP_STRING([--with-libunwind], [Use libunwind frame unwinding support]),
diff -up ltrace-0.6.0/configure\~ ltrace-0.6.0/configure
--- ltrace-0.6.0/configure~ 2012-04-11 12:56:00.688263027 +0200
+++ ltrace-0.6.0/configure 2012-04-11 12:55:49.787935890 +0200
@@ -11029,6 +11689,65 @@ fi
+for ac_header in selinux/selinux.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "selinux/selinux.h" "ac_cv_header_selinux_selinux_h" "$ac_includes_default"
+if test "x$ac_cv_header_selinux_selinux_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_SELINUX_SELINUX_H 1
+_ACEOF
+
+fi
+
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for security_get_boolean_active in -lselinux" >&5
+$as_echo_n "checking for security_get_boolean_active in -lselinux... " >&6; }
+if ${ac_cv_lib_selinux_security_get_boolean_active+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lselinux $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char security_get_boolean_active ();
+int
+main ()
+{
+return security_get_boolean_active ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_selinux_security_get_boolean_active=yes
+else
+ ac_cv_lib_selinux_security_get_boolean_active=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_selinux_security_get_boolean_active" >&5
+$as_echo "$ac_cv_lib_selinux_security_get_boolean_active" >&6; }
+if test "x$ac_cv_lib_selinux_security_get_boolean_active" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSELINUX 1
+_ACEOF
+
+ LIBS="-lselinux $LIBS"
+
+fi
+
+
+
# HAVE_LIBUNWIND
# Check whether --with-libunwind was given.
diff --git a/proc.c b/proc.c
index 106b6a0..ded0c95 100644
--- a/proc.c
+++ b/proc.c
@@ -94,6 +94,7 @@ open_pid(pid_t pid)
if (open_one_pid(pid)) {
fprintf(stderr, "Cannot attach to pid %u: %s\n",
pid, strerror(errno));
+ trace_fail_warning(pid);
return;
}
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
index 67e1f93..82a4154 100644
--- a/sysdeps/linux-gnu/trace.c
+++ b/sysdeps/linux-gnu/trace.c
@@ -10,2 +10,7 @@
+#include "config.h"
+#ifdef HAVE_LIBSELINUX
+# include <selinux/selinux.h>
+#endif
+
/* If the system headers did not provide the constants, hard-code the normal
@@ -69,10 +75,32 @@ umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
#endif
void
-trace_me(void) {
+trace_fail_warning(pid_t pid)
+{
+ /* This was adapted from GDB. */
+#ifdef HAVE_LIBSELINUX
+ static int checked = 0;
+ if (checked)
+ return;
+ checked = 1;
+
+ /* -1 is returned for errors, 0 if it has no effect, 1 if
+ * PTRACE_ATTACH is forbidden. */
+ if (security_get_boolean_active("deny_ptrace") == 1)
+ fprintf(stderr,
+"The SELinux boolean 'deny_ptrace' is enabled, which may prevent ltrace from\n"
+"tracing other processes. You can disable this process attach protection by\n"
+"issuing 'setsebool deny_ptrace=0' in the superuser context.\n");
+#endif /* HAVE_LIBSELINUX */
+}
+
+void
+trace_me(void)
+{
debug(DEBUG_PROCESS, "trace_me: pid=%d", getpid());
if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
perror("PTRACE_TRACEME");
+ trace_fail_warning(getpid());
exit(1);
}
}
@@ -101,11 +129,14 @@ I'll now try to proceed with tracing, but this shouldn't be happening.\n");
}
int
-trace_pid(pid_t pid) {
+trace_pid(pid_t pid)
+{
debug(DEBUG_PROCESS, "trace_pid: pid=%d", pid);
- if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) {
+ /* This shouldn't emit error messages, as there are legitimate
+ * reasons that the PID can't be attached: like it may have
+ * already ended. */
+ if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0)
return -1;
- }
/* man ptrace: PTRACE_ATTACH attaches to the process specified
in pid. The child is sent a SIGSTOP, but will not
--
1.7.7.6
diff -up ./config.h.in~ ./config.h.in
--- ./config.h.in~ 2011-02-14 17:01:18.000000000 +0100
+++ ./config.h.in 2012-04-11 13:19:10.000000000 +0200
@@ -45,6 +45,9 @@
/* we have libiberty */
#undef HAVE_LIBIBERTY
+/* Define to 1 if you have the `selinux' library (-lselinux). */
+#undef HAVE_LIBSELINUX
+
/* we have libsupc++ */
#undef HAVE_LIBSUPC__
@@ -72,6 +75,9 @@
/* Define to 1 if you have the `rmdir' function. */
#undef HAVE_RMDIR
+/* Define to 1 if you have the <selinux/selinux.h> header file. */
+#undef HAVE_SELINUX_SELINUX_H
+
/* Define to 1 if you have the <stddef.h> header file. */
#undef HAVE_STDDEF_H

View File

@ -1,30 +0,0 @@
From 6aa01523f249f9763ccd71db9f46969a6e5d8cfd Mon Sep 17 00:00:00 2001
From: Paul Buerger <pbuerger@avetec.org>
Date: Wed, 12 Sep 2012 10:58:52 -0400
Subject: [PATCH] reported time in system call was too large
when -S and -T are specified and if the system call spans
a second boundary, the reported time in the system call
was too large by precisely 2 seconds
Signed-off-by: Paul Buerger <pbuerger@avetec.org>
---
handle_event.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/handle_event.c b/handle_event.c
index 1720cb3..384e868 100644
--- a/handle_event.c
+++ b/handle_event.c
@@ -522,7 +522,7 @@ calc_time_spent(Process *proc) {
if (tv.tv_usec >= elem->time_spent.tv_usec) {
diff.tv_usec = tv.tv_usec - elem->time_spent.tv_usec;
} else {
- diff.tv_sec++;
+ diff.tv_sec--;
diff.tv_usec = 1000000 + tv.tv_usec - elem->time_spent.tv_usec;
}
current_time_spent = diff;
--
1.7.6.5

View File

@ -1,256 +0,0 @@
diff --git a/handle_event.c b/handle_event.c
index 725f50d..8c3c7ce 100644
--- a/handle_event.c
+++ b/handle_event.c
@@ -565,11 +565,21 @@ void *get_count_register (Process *proc);
}
static void
+output_right_tos(struct Process *proc)
+{
+ size_t d = proc->callstack_depth;
+ struct callstack_element *elem = &proc->callstack[d - 1];
+ if (proc->state != STATE_IGNORED)
+ output_right(LT_TOF_FUNCTIONR, proc, elem->c_un.libfunc->name);
+}
+
+static void
handle_breakpoint(Event *event)
{
int i, j;
struct breakpoint *sbp;
Process *leader = event->proc->leader;
+ void *brk_addr = event->e_un.brk_addr;
/* The leader has terminated. */
if (leader == NULL) {
@@ -577,12 +587,14 @@ handle_breakpoint(Event *event)
return;
}
- debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)", event->proc->pid, event->e_un.brk_addr);
- debug(2, "event: breakpoint (%p)", event->e_un.brk_addr);
+ debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)",
+ event->proc->pid, brk_addr);
+ debug(2, "event: breakpoint (%p)", brk_addr);
for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
- if (event->e_un.brk_addr ==
- event->proc->callstack[i].return_addr) {
+ if (brk_addr == event->proc->callstack[i].return_addr) {
+ struct library_symbol *libsym =
+ event->proc->callstack[i].c_un.libfunc;
#ifdef __powerpc__
/*
* PPC HACK! (XXX FIXME TODO)
@@ -623,8 +625,6 @@ handle_breakpoint(Event *event)
* so be sure to re-enable the breakpoint.
*/
unsigned long a;
- struct library_symbol *libsym =
- event->proc->callstack[i].c_un.libfunc;
void *addr = sym2addr(event->proc, libsym);
if (libsym->plt_type != LS_TOPLT_POINT) {
@@ -668,19 +679,37 @@ handle_breakpoint(Event *event)
calc_time_spent(event->proc);
}
}
- event->proc->return_addr = event->e_un.brk_addr;
- if (event->proc->state != STATE_IGNORED) {
- output_right(LT_TOF_FUNCTIONR, event->proc,
- event->proc->callstack[i].c_un.libfunc->name);
- }
+ event->proc->return_addr = brk_addr;
+
+ output_right_tos(event->proc);
callstack_pop(event->proc);
- sbp = address2bpstruct(leader, event->e_un.brk_addr);
+
+ /* Pop also any other entries that seem like
+ * they are linked to the current one: they
+ * have the same return address, but were made
+ * for different symbols. This should only
+ * happen for entry point tracing, i.e. for -x
+ * everywhere, or -x and -e on PPC64. */
+ while (event->proc->callstack_depth > 0) {
+ struct callstack_element *prev;
+ size_t d = event->proc->callstack_depth;
+ prev = &event->proc->callstack[d - 1];
+
+ if (prev->c_un.libfunc == libsym
+ || prev->return_addr != brk_addr)
+ break;
+
+ output_right_tos(event->proc);
+ callstack_pop(event->proc);
+ }
+
+ sbp = address2bpstruct(leader, brk_addr);
continue_after_breakpoint(event->proc, sbp);
return;
}
}
- if ((sbp = address2bpstruct(leader, event->e_un.brk_addr))) {
+ if ((sbp = address2bpstruct(leader, brk_addr))) {
breakpoint_on_hit(sbp, event->proc);
if (sbp->libsym == NULL) {
@@ -711,7 +740,7 @@ handle_breakpoint(Event *event)
if (event->proc->state != STATE_IGNORED && !options.no_plt) {
output_line(event->proc, "unexpected breakpoint at %p",
- (void *)event->e_un.brk_addr);
+ brk_addr);
}
continue_process(event->proc->pid);
}
@@ -742,7 +771,7 @@ callstack_push_syscall(Process *proc, int sysnum) {
static void
callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
- struct callstack_element *elem, *prev;
+ struct callstack_element *elem;
debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name);
/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
@@ -752,8 +781,7 @@ callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
return;
}
- prev = &proc->callstack[proc->callstack_depth-1];
- elem = &proc->callstack[proc->callstack_depth];
+ elem = &proc->callstack[proc->callstack_depth++];
elem->is_syscall = 0;
elem->c_un.libfunc = sym;
@@ -763,8 +791,6 @@ callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
}
/* handle functions like atexit() on mips which have no return */
- if (elem->return_addr != prev->return_addr)
- proc->callstack_depth++;
if (opt_T || options.summary) {
struct timezone tz;
gettimeofday(&elem->time_spent, &tz);
diff --git a/testsuite/ltrace.main/branch_func.c b/testsuite/ltrace.main/branch_func.c
new file mode 100644
index 0000000..0ce311d
--- /dev/null
+++ b/testsuite/ltrace.main/branch_func.c
@@ -0,0 +1,51 @@
+/*
+ * 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
+ */
+
+/* This is specially made to produce tail calls. We then trace them
+ * and see if ltrace handles it well, or whether its internal stack
+ * overflows. */
+
+__attribute__((noinline, optimize(3))) int
+func3(int i)
+{
+ return i + 1;
+}
+
+__attribute__((noinline, optimize(3))) int
+func2(int i)
+{
+ return func3(i * 3);
+}
+
+__attribute__((noinline, optimize(3))) int
+func1(int i)
+{
+ return func2(i + 2);
+}
+
+__attribute__((optimize(0))) int
+main(int argc, char **argv)
+{
+ int counter = 0;
+ int i;
+ for (i = 0; i < 100; ++i)
+ counter += func1(i);
+ return counter;
+}
diff --git a/testsuite/ltrace.main/branch_func.exp b/testsuite/ltrace.main/branch_func.exp
new file mode 100644
index 0000000..fec5700
--- /dev/null
+++ b/testsuite/ltrace.main/branch_func.exp
@@ -0,0 +1,57 @@
+# 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
+
+set testfile "branch_func"
+set srcfile ${testfile}.c
+set binfile ${testfile}
+
+if [get_compiler_info $binfile] {
+ return -1
+}
+
+verbose "compiling source file now....."
+if { [ltrace_compile $srcdir/$subdir/$srcfile $objdir/$subdir/$binfile executable {debug} ] != "" } {
+ send_user "Testcase compile failed, so all tests in this file will automatically fail\n."
+}
+
+# set options for ltrace.
+ltrace_options "-x" "func1" "-x" "func2" "-x" "func3"
+
+# Run PUT for ltarce.
+set exec_output [ltrace_runtest $objdir/$subdir $objdir/$subdir/$binfile]
+
+# Check the output of this program.
+verbose "ltrace runtest output: $exec_output\n"
+if [regexp {ELF from incompatible architecture} $exec_output] {
+ fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!"
+ return
+} elseif [ regexp {Couldn't get .hash data} $exec_output ] {
+ fail "Couldn't get .hash data!"
+ return
+}
+
+set pattern "func1(.*unfinished"
+ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100
+set pattern "func2(.*unfinished"
+ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100
+set pattern "func3(.*)"
+ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100
+set pattern "func2.resumed"
+ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100
+set pattern "func1.resumed"
+ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100

View File

@ -1,406 +0,0 @@
diff --git a/common.h b/common.h
index 2fff8dd..715898d 100644
--- a/common.h
+++ b/common.h
@@ -343,6 +343,7 @@ extern void disable_breakpoint(Process * proc, Breakpoint * sbp);
extern int syscall_p(Process * proc, int status, int * sysnum);
extern void continue_process(pid_t pid);
extern void continue_after_signal(pid_t pid, int signum);
+extern void continue_after_syscall(Process *proc, int sysnum, int ret_p);
extern void continue_after_breakpoint(Process * proc, Breakpoint * sbp);
extern void continue_after_vfork(Process * proc);
extern void ltrace_exiting(void);
diff --git a/handle_event.c b/handle_event.c
index f56c537..203459c 100644
--- a/handle_event.c
+++ b/handle_event.c
@@ -70,7 +70,9 @@ handle_event(Event *event) {
/* Note: the previous handler has a chance to alter
* the event. */
- if (event->proc->leader != NULL) {
+ if (event->proc != NULL
+ && event->proc->leader != NULL
+ && event->proc != event->proc->leader) {
event = call_handler(event->proc->leader, event);
if (event == NULL)
return;
@@ -454,7 +456,7 @@ handle_syscall(Event *event) {
enable_all_breakpoints(event->proc);
}
}
- continue_process(event->proc->pid);
+ continue_after_syscall(event->proc, event->e_un.sysnum, 0);
}
static void
@@ -533,9 +535,12 @@ handle_sysret(Event *event) {
output_right(LT_TOF_SYSCALLR, event->proc,
sysname(event->proc, event->e_un.sysnum));
}
+ assert(event->proc->callstack_depth > 0);
+ unsigned d = event->proc->callstack_depth - 1;
+ assert(event->proc->callstack[d].is_syscall);
callstack_pop(event->proc);
}
- continue_process(event->proc->pid);
+ continue_after_syscall(event->proc, event->e_un.sysnum, 1);
}
static void
@@ -639,7 +644,7 @@ handle_breakpoint(Event *event) {
struct library_symbol *sym= event->proc->callstack[i].c_un.libfunc;
struct library_symbol *new_sym;
assert(sym);
- addr = sym2addr(leader, sym);
+ addr = sym2addr(event->proc, sym);
sbp = dict_find_entry(leader->breakpoints, addr);
if (sbp) {
if (addr != sbp->addr) {
diff --git a/sysdeps/linux-gnu/events.c b/sysdeps/linux-gnu/events.c
index 0685342..021192f 100644
--- a/sysdeps/linux-gnu/events.c
+++ b/sysdeps/linux-gnu/events.c
@@ -9,6 +9,7 @@
#include <string.h>
#include <sys/ptrace.h>
#include <assert.h>
+#include <unistd.h>
#include "common.h"
@@ -138,6 +139,26 @@ next_event(void)
}
event.proc = pid2proc(pid);
if (!event.proc || event.proc->state == STATE_BEING_CREATED) {
+ /* Work around (presumably) a bug on some kernels,
+ * where we are seeing a waitpid event even though the
+ * process is still reported to be running. Wait for
+ * the tracing stop to propagate. But don't get stuck
+ * here forever.
+ *
+ * We need the process in T, because there's a lot of
+ * ptracing going on all over the place, and these
+ * calls fail when the process is not in T.
+ *
+ * N.B. This was observed on RHEL 5 Itanium, but I'm
+ * turning this on globally, to save some poor soul
+ * down the road (which could well be me a year from
+ * 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) {
+ debug(2, "waiting for %d to stop", pid);
+ usleep(10000);
+ }
event.type = EVENT_NEW;
event.e_un.newpid = pid;
debug(DEBUG_EVENT, "event: NEW: pid=%d", pid);
diff --git a/sysdeps/linux-gnu/ia64/regs.c b/sysdeps/linux-gnu/ia64/regs.c
index 00df572..3f5d951 100644
--- a/sysdeps/linux-gnu/ia64/regs.c
+++ b/sysdeps/linux-gnu/ia64/regs.c
@@ -2,6 +2,7 @@
#include <sys/types.h>
#include <sys/ptrace.h>
+#include <errno.h>
#include <asm/ptrace_offsets.h>
#include <asm/rse.h>
@@ -36,12 +37,18 @@ set_instruction_pointer(Process *proc, void *addr) {
void *
get_stack_pointer(Process *proc) {
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, PT_R12, 0);
+ long l = ptrace(PTRACE_PEEKUSER, proc->pid, PT_R12, 0);
+ if (l == -1 && errno)
+ return NULL;
+ return (void *)l;
}
void *
get_return_addr(Process *proc, void *stack_pointer) {
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, PT_B0, 0);
+ long l = ptrace(PTRACE_PEEKUSER, proc->pid, PT_B0, 0);
+ if (l == -1 && errno)
+ return NULL;
+ return (void *)l;
}
void
diff --git a/sysdeps/linux-gnu/ia64/trace.c b/sysdeps/linux-gnu/ia64/trace.c
index 799e0ff..079ed55 100644
--- a/sysdeps/linux-gnu/ia64/trace.c
+++ b/sysdeps/linux-gnu/ia64/trace.c
@@ -9,6 +9,7 @@
#include <string.h>
#include <asm/ptrace_offsets.h>
#include <asm/rse.h>
+#include <errno.h>
#include "common.h"
@@ -48,9 +49,10 @@ int
syscall_p(Process *proc, int status, int *sysnum) {
if (WIFSTOPPED(status)
&& WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
- unsigned long slot =
- (ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IPSR, 0) >> 41) &
- 0x3;
+ long l = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IPSR, 0);
+ if (l == -1 && errno)
+ return -1;
+ unsigned long slot = ((unsigned long)l >> 41) & 0x3;
unsigned long ip =
ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IIP, 0);
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
index ba3806d..db18df0 100644
--- a/sysdeps/linux-gnu/trace.c
+++ b/sysdeps/linux-gnu/trace.c
@@ -146,8 +146,8 @@ continue_process(pid_t pid)
debug(DEBUG_PROCESS, "continue_process: pid=%d", pid);
/* Only really continue the process if there are no events in
- the queue for this process. Otherwise just for the other
- events to arrive. */
+ the queue for this process. Otherwise just wait for the
+ other events to arrive. */
if (!have_events_for(pid))
/* We always trace syscalls to control fork(),
* clone(), execve()... */
@@ -168,6 +168,7 @@ struct pid_task {
int got_event : 1;
int delivered : 1;
int vforked : 1;
+ int sysret : 1;
} * pids;
struct pid_set {
@@ -259,10 +260,14 @@ task_stopped(Process * task, void * data)
case ps_invalid:
case ps_tracing_stop:
case ps_zombie:
+ case ps_sleeping:
return pcb_cont;
- default:
+ case ps_stop:
+ case ps_other:
return pcb_stop;
}
+
+ abort ();
}
/* Task is blocked if it's stopped, or if it's a vfork parent. */
@@ -376,7 +381,8 @@ process_stopping_done(struct process_stopping_handler * self, Process * leader)
if (!self->exiting) {
for (i = 0; i < self->pids.count; ++i)
if (self->pids.tasks[i].pid != 0
- && self->pids.tasks[i].delivered)
+ && (self->pids.tasks[i].delivered
+ || self->pids.tasks[i].sysret))
continue_process(self->pids.tasks[i].pid);
continue_process(self->task_enabling_breakpoint->pid);
destroy_event_handler(leader);
@@ -469,7 +475,10 @@ handle_stopping_event(struct pid_task * task_info, Event ** eventp)
/* Some SIGSTOPs may have not been delivered to their respective tasks
* yet. They are still in the queue. If we have seen an event for
* that process, continue it, so that the SIGSTOP can be delivered and
- * caught by ltrace. */
+ * caught by ltrace. We don't mind that the process is after
+ * breakpoint (and therefore potentially doesn't have aligned IP),
+ * because the signal will be delivered without the process actually
+ * starting. */
static void
continue_for_sigstop_delivery(struct pid_set * pids)
{
@@ -549,6 +558,14 @@ all_stops_accountable(struct pid_set * pids)
return 1;
}
+static void
+singlestep(Process * proc)
+{
+ debug(1, "PTRACE_SINGLESTEP");
+ if (ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0))
+ perror("PTRACE_SINGLESTEP");
+}
+
/* This event handler is installed when we are in the process of
* stopping the whole thread group to do the pointer re-enablement for
* one of the threads. We pump all events to the queue for later
@@ -580,6 +597,17 @@ process_stopping_on_event(Event_Handler * super, Event * event)
if (event_exit_p(event) && task_info != NULL)
task_info->pid = 0;
+ /* Always handle sysrets. Whether sysret occurred and what
+ * sys it rets from may need to be determined based on process
+ * stack, so we need to keep that in sync with reality. Note
+ * that we don't continue the process after the sysret is
+ * handled. See continue_after_syscall. */
+ if (event != NULL && event->type == EVENT_SYSRET) {
+ debug(1, "%d LT_EV_SYSRET", event->proc->pid);
+ event_to_queue = 0;
+ task_info->sysret = 1;
+ }
+
switch (state) {
case psh_stopping:
/* If everyone is stopped, singlestep. */
@@ -588,16 +616,22 @@ process_stopping_on_event(Event_Handler * super, Event * event)
teb->pid);
if (sbp->enabled)
disable_breakpoint(teb, sbp);
- if (ptrace(PTRACE_SINGLESTEP, teb->pid, 0, 0))
- perror("PTRACE_SINGLESTEP");
+ singlestep(teb);
self->state = state = psh_singlestep;
}
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) {
+
+ /* This is not the singlestep that we are waiting for. */
+ if (event->type == EVENT_SIGNAL) {
+ singlestep(task);
+ break;
+ }
+
/* Essentially we don't care what event caused
* the thread to stop. We can do the
* re-enablement now. */
@@ -613,7 +647,6 @@ process_stopping_on_event(Event_Handler * super, Event * event)
event = NULL; // handled
} else
break;
- }
/* fall-through */
@@ -806,9 +839,6 @@ ltrace_exiting_install_handler(Process * proc)
* with its parent, and handle it as a multi-threaded case, with the
* exception that we know that the parent is blocked, and don't
* attempt to stop it. When the child execs, we undo the setup.
- *
- * XXX The parent process could be un-suspended before ltrace gets
- * child exec/exit event. Make sure this is taken care of.
*/
struct process_vfork_handler
@@ -840,9 +870,9 @@ process_vfork_on_event(Event_Handler * super, Event * event)
sbp = dict_find_entry(event->proc->leader->breakpoints,
self->bp_addr);
if (sbp != NULL)
- insert_breakpoint(event->proc->leader,
- self->bp_addr, sbp->libsym,
- 1);
+ insert_breakpoint(event->proc->parent,
+ self->bp_addr,
+ sbp->libsym, 1);
}
continue_process(event->proc->parent->pid);
@@ -852,11 +882,6 @@ process_vfork_on_event(Event_Handler * super, Event * event)
change_process_leader(event->proc, event->proc);
destroy_event_handler(event->proc);
- /* XXXXX this could happen in the middle of handling
- * multi-threaded breakpoint. We must be careful to
- * undo the effects that we introduced above (vforked
- * = 1 et.al.). */
-
default:
;
}
@@ -893,6 +918,27 @@ continue_after_vfork(Process * proc)
change_process_leader(proc, proc->parent->leader);
}
+static int
+is_mid_stopping(Process *proc)
+{
+ return proc != NULL
+ && proc->event_handler != NULL
+ && proc->event_handler->on_event == &process_stopping_on_event;
+}
+
+void
+continue_after_syscall(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))) {
+ debug(DEBUG_PROCESS,
+ "continue_after_syscall: don't continue %d",
+ proc->pid);
+ return;
+ }
+ 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
diff --git a/testsuite/ltrace.main/hello-vfork.c b/testsuite/ltrace.main/hello-vfork.c
new file mode 100644
index 0000000..228c052
--- /dev/null
+++ b/testsuite/ltrace.main/hello-vfork.c
@@ -0,0 +1,11 @@
+/* Copyright (C) 2008, Red Hat, Inc.
+ * Written by Denys Vlasenko */
+#include <stdio.h>
+#include <unistd.h>
+
+int main() {
+ int r = vfork();
+ fprintf(stderr, "vfork():%d\n", r);
+ _exit(0);
+}
+
diff --git a/testsuite/ltrace.main/hello-vfork.exp b/testsuite/ltrace.main/hello-vfork.exp
new file mode 100644
index 0000000..12c9ca3
--- /dev/null
+++ b/testsuite/ltrace.main/hello-vfork.exp
@@ -0,0 +1,35 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+set testfile "hello-vfork"
+set srcfile ${testfile}.c
+set binfile ${testfile}
+
+
+if [get_compiler_info $binfile] {
+ return -1
+}
+
+verbose "compiling source file now....."
+if { [ltrace_compile $srcdir/$subdir/$srcfile $objdir/$subdir/$binfile executable debug ] != ""} {
+ send_user "Testcase compile failed, so all tests in this file will automatically fail.\n"
+}
+
+# set options for ltrace.
+ltrace_options "-f"
+
+# Run PUT for ltarce.
+set exec_output [ltrace_runtest $objdir/$subdir $objdir/$subdir/$binfile]
+
+# Check the output of this program.
+verbose "ltrace runtest output: $exec_output\n"
+if [regexp {ELF from incompatible architecture} $exec_output] {
+ fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!"
+ return
+} elseif [ regexp {Couldn't get .hash data} $exec_output ] {
+ fail "Couldn't get .hash data!"
+ return
+}
+
+# Verify the output by checking numbers of print in main-vfork.ltrace.
+ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace "_exit" 2
+ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace "vfork resumed" 2

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,88 +0,0 @@
From 78ed40f161c102a10c6033c28ad9a80e5ffe9550 Mon Sep 17 00:00:00 2001
From: Petr Machata <pmachata@redhat.com>
Date: Sat, 22 Sep 2012 18:19:24 +0200
Subject: [PATCH] Fix passing struct(float,struct(float,float)) on x86_64
The problem was that we assumed that structure elements never overlap
eightbyte boundary. This assumption is violated by the above layout,
where the first two floats should be passed in %xmm0 together.
This case is covered by the Itanium HFA tests func_hfa_f3 and func_hfa_f4.
---
ChangeLog | 4 +++
sysdeps/linux-gnu/x86/fetch.c | 46 ++++++++++++++++++++++++++++++++++++----
2 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/sysdeps/linux-gnu/x86/fetch.c b/sysdeps/linux-gnu/x86/fetch.c
index 8df900e..cca1638 100644
--- a/sysdeps/linux-gnu/x86/fetch.c
+++ b/sysdeps/linux-gnu/x86/fetch.c
@@ -411,12 +411,34 @@ get_array_field(struct arg_type_info *info, size_t emt)
return info->u.array_info.elt_type;
}
+static int
+flatten_structure(struct arg_type_info *flattened, struct arg_type_info *info)
+{
+ size_t i;
+ for (i = 0; i < type_struct_size(info); ++i) {
+ struct arg_type_info *field = type_struct_get(info, i);
+ assert(field != NULL);
+ switch (field->type) {
+ case ARGTYPE_STRUCT:
+ if (flatten_structure(flattened, field) < 0)
+ return -1;
+ break;
+
+ default:
+ if (type_struct_add(flattened, field, 0) < 0)
+ return -1;
+ }
+ }
+ return 0;
+}
+
static ssize_t
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)
{
switch (info->type) {
+ struct arg_type_info flattened;
case ARGTYPE_VOID:
return 0;
@@ -458,11 +480,25 @@ classify(struct Process *proc, struct fetch_context *context,
get_array_field);
case ARGTYPE_STRUCT:
- /* N.B. "big" structs are dealt with in the
- * caller. */
- return classify_eightbytes(proc, context, info, valuep, classes,
- type_struct_size(info),
- eightbytes, type_struct_get);
+ /* N.B. "big" structs are dealt with in the caller.
+ *
+ * First, we need to flatten the structure. In
+ * struct(float,struct(float,float)), first two floats
+ * both belong to the same eightbyte. */
+ type_init_struct(&flattened);
+
+ ssize_t ret;
+ if (flatten_structure(&flattened, info) < 0) {
+ ret = -1;
+ goto done;
+ }
+ ret = classify_eightbytes(proc, context, &flattened,
+ valuep, classes,
+ type_struct_size(&flattened),
+ eightbytes, type_struct_get);
+ done:
+ type_destroy(&flattened);
+ return ret;
}
abort();
}
--
1.7.6.5

150
ltrace-0.7.0-man5.patch Normal file
View File

@ -0,0 +1,150 @@
diff -urp ltrace-0.7.0/Makefile.am ltrace-0.7.0/Makefile.am
--- ltrace-0.7.0/Makefile.am 2012-11-10 13:43:55.000000000 +0100
+++ ltrace-0.7.0/Makefile.am 2012-11-10 14:57:39.141288149 +0100
@@ -116,7 +116,8 @@ noinst_HEADERS = \
lens_default.h \
lens_enum.h
-dist_man1_MANS = ltrace.1 ltrace.conf.5
+dist_man1_MANS = ltrace.1
+dist_man5_MANS = ltrace.conf.5
dist_doc_DATA = COPYING CREDITS INSTALL README TODO
diff -urp ltrace-0.7.0/Makefile.in ltrace-0.7.0/Makefile.in
--- ltrace-0.7.0/Makefile.in 2012-11-10 13:46:03.000000000 +0100
+++ ltrace-0.7.0/Makefile.in 2012-11-10 15:00:05.854225673 +0100
@@ -60,8 +60,8 @@ host_triplet = @host@
bin_PROGRAMS = ltrace$(EXEEXT)
subdir = .
DIST_COMMON = README $(am__configure_deps) $(dist_doc_DATA) \
- $(dist_man1_MANS) $(dist_sysconf_DATA) $(noinst_HEADERS) \
- $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(dist_man1_MANS) $(dist_man5_MANS) $(dist_sysconf_DATA) \
+ $(noinst_HEADERS) $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
$(srcdir)/config.h.in $(top_srcdir)/configure COPYING INSTALL \
NEWS TODO config/autoconf/config.guess \
config/autoconf/config.sub config/autoconf/depcomp \
@@ -96,7 +96,8 @@ am_libltrace_la_OBJECTS = breakpoints.lo
lens_default.lo lens_enum.lo
libltrace_la_OBJECTS = $(am_libltrace_la_OBJECTS)
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" \
- "$(DESTDIR)$(docdir)" "$(DESTDIR)$(sysconfdir)"
+ "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(docdir)" \
+ "$(DESTDIR)$(sysconfdir)"
PROGRAMS = $(bin_PROGRAMS)
am_ltrace_OBJECTS = main.$(OBJEXT)
ltrace_OBJECTS = $(am_ltrace_OBJECTS)
@@ -145,8 +146,9 @@ am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
man1dir = $(mandir)/man1
+man5dir = $(mandir)/man5
NROFF = nroff
-MANS = $(dist_man1_MANS)
+MANS = $(dist_man1_MANS) $(dist_man5_MANS)
DATA = $(dist_doc_DATA) $(dist_sysconf_DATA)
HEADERS = $(noinst_HEADERS)
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
@@ -410,7 +412,8 @@ noinst_HEADERS = \
lens_default.h \
lens_enum.h
-dist_man1_MANS = ltrace.1 ltrace.conf.5
+dist_man1_MANS = ltrace.1
+dist_man5_MANS = ltrace.conf.5
dist_doc_DATA = COPYING CREDITS INSTALL README TODO
dist_sysconf_DATA = \
etc/ltrace.conf
@@ -658,6 +661,40 @@ uninstall-man1:
test -z "$$files" || { \
echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(man1dir)" && rm -f $$files; }
+install-man5: $(dist_man5_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man5dir)" || $(MKDIR_P) "$(DESTDIR)$(man5dir)"
+ @list='$(dist_man5_MANS)'; test -n "$(man5dir)" || exit 0; \
+ { for i in $$list; do echo "$$i"; done; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man5:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_man5_MANS)'; test -n "$(man5dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ test -z "$$files" || { \
+ echo " ( cd '$(DESTDIR)$(man5dir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(man5dir)" && rm -f $$files; }
install-dist_docDATA: $(dist_doc_DATA)
@$(NORMAL_INSTALL)
test -z "$(docdir)" || $(MKDIR_P) "$(DESTDIR)$(docdir)"
@@ -1028,7 +1065,7 @@ all-am: Makefile $(LTLIBRARIES) $(PROGRA
config.h
installdirs: installdirs-recursive
installdirs-am:
- for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(sysconfdir)"; do \
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(sysconfdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-recursive
@@ -1097,7 +1134,7 @@ install-info: install-info-recursive
install-info-am:
-install-man: install-man1
+install-man: install-man1 install-man5
install-pdf: install-pdf-recursive
@@ -1133,7 +1170,7 @@ ps-am:
uninstall-am: uninstall-binPROGRAMS uninstall-dist_docDATA \
uninstall-dist_sysconfDATA uninstall-man
-uninstall-man: uninstall-man1
+uninstall-man: uninstall-man1 uninstall-man5
.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \
ctags-recursive install-am install-strip tags-recursive
@@ -1150,14 +1187,16 @@ uninstall-man: uninstall-man1
install-data-am install-dist_docDATA install-dist_sysconfDATA \
install-dvi install-dvi-am install-exec install-exec-am \
install-html install-html-am install-info install-info-am \
- install-man install-man1 install-pdf install-pdf-am install-ps \
- install-ps-am install-strip installcheck installcheck-am \
- installdirs installdirs-am maintainer-clean \
- maintainer-clean-generic maintainer-clean-local mostlyclean \
- mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
- pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \
+ install-man install-man1 install-man5 install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs installdirs-am \
+ maintainer-clean maintainer-clean-generic \
+ maintainer-clean-local mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-recursive uninstall uninstall-am \
uninstall-binPROGRAMS uninstall-dist_docDATA \
- uninstall-dist_sysconfDATA uninstall-man uninstall-man1
+ uninstall-dist_sysconfDATA uninstall-man uninstall-man1 \
+ uninstall-man5
maintainer-clean-local:

View File

@ -0,0 +1,70 @@
diff -urp ltrace-0.7.0/sysdeps/linux-gnu/ppc/Makefile.am ltrace-0.7.0/sysdeps/linux-gnu/ppc/Makefile.am
--- ltrace-0.7.0/sysdeps/linux-gnu/ppc/Makefile.am 2012-11-09 23:45:23.192038441 +0100
+++ ltrace-0.7.0/sysdeps/linux-gnu/ppc/Makefile.am 2012-11-10 13:43:55.000000000 +0100
@@ -27,6 +27,7 @@ ___libcpu_la_SOURCES = \
noinst_HEADERS = \
arch.h \
+ insn.h \
ptrace.h \
signalent.h \
syscallent.h
diff -urp ltrace-0.7.0/sysdeps/linux-gnu/ppc/Makefile.in ltrace-0.7.0/sysdeps/linux-gnu/ppc/Makefile.in
--- ltrace-0.7.0/sysdeps/linux-gnu/ppc/Makefile.in 2012-11-10 14:41:22.453856321 +0100
+++ ltrace-0.7.0/sysdeps/linux-gnu/ppc/Makefile.in 2012-11-10 13:46:03.000000000 +0100
@@ -232,6 +232,7 @@ ___libcpu_la_SOURCES = \
noinst_HEADERS = \
arch.h \
+ insn.h \
ptrace.h \
signalent.h \
syscallent.h
--- ltrace-0.7.0/sysdeps/linux-gnu/ppc/insn.h 1970-01-01 01:00:00.000000000 +0100
+++ ltrace-0.7.0/sysdeps/linux-gnu/ppc/insn.h 2012-11-07 17:09:31.784520698 +0100
@@ -0,0 +1,45 @@
+/*
+ * 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
+ */
+
+/* Instruction masks used during single-stepping of atomic
+ * sequences. This was lifted from GDB. */
+#define LWARX_MASK 0xfc0007fe
+#define LWARX_INSTRUCTION 0x7c000028
+#define LDARX_INSTRUCTION 0x7c0000A8
+#define STWCX_MASK 0xfc0007ff
+#define STWCX_INSTRUCTION 0x7c00012d
+#define STDCX_INSTRUCTION 0x7c0001ad
+#define BRANCH_MASK 0xfc000000
+#define BC_MASK 0xfc000000
+#define BC_INSN 0x40000000
+#define B_INSN 0x48000000
+
+static inline arch_addr_t
+ppc_branch_dest(arch_addr_t addr, uint32_t insn)
+{
+ int immediate = ((insn & 0xfffc) ^ 0x8000) - 0x8000;
+ int absolute = insn & 2;
+
+ /* XXX drop the following double casts. */
+ if (absolute)
+ return (arch_addr_t)(uintptr_t)immediate;
+ else
+ return addr + (uintptr_t)immediate;
+}

View File

@ -1,47 +1,20 @@
Summary: Tracks runtime library calls from dynamically linked executables
Name: ltrace
Version: 0.6.0
Release: 19%{?dist}
Version: 0.7.0
Release: 1%{?dist}
URL: http://ltrace.alioth.debian.org/
License: GPLv2+
Group: Development/Debuggers
BuildRequires: elfutils-libelf-devel dejagnu
BuildRequires: autoconf automake libtool
BuildRequires: libselinux-devel
# Tarball generated from git checkout. To regenerate:
# git clone http://github.com/ice799/ltrace.git
# cd ltrace && ./autogen.sh && ./configure && make dist
Source: %{name}-%{version}.tar.bz2
Source: http://alioth.debian.org/frs/download.php/3822/%{name}-%{version}.tar.bz2
Patch1: ltrace-0.5-ia64-sigill.patch
Patch2: ltrace-0.6.0-exec-stripped.patch
Patch4: ltrace-0.5-etc-memmove.patch
Patch5: ltrace-0.6.0-return-string-n.patch
Patch6: ltrace-0.6.0-threads.patch
Patch7: ltrace-0.6.0-endian.patch
Patch8: ltrace-0.6.0-clone-test.patch
Patch9: ltrace-0.6.0-ppc-args.patch
Patch11: ltrace-0.6.0-vfork.patch
Patch12: ltrace-0.6.0-thread-races.patch
Patch13: ltrace-0.6.0-process-start.patch
Patch14: ltrace-0.6.0-selinux.patch
Patch15: ltrace-0.6.0-detach-sleeping.patch
Patch16: ltrace-0.6.0-tail-return.patch
Patch17: ltrace-0.6.0-ppc-lwarx.patch
Patch18: ltrace-0.6.0-libs.patch
Patch19: ltrace-0.6.0-libs-fixes-1.patch
Patch20: ltrace-0.6.0-dash-n.patch
Patch21: ltrace-0.6.0-demangle.patch
Patch22: ltrace-0.6.0-abi.patch
Patch23: ltrace-0.6.0-abi-s390.patch
Patch24: ltrace-0.6.0-ppc-flteqv.patch
Patch25: ltrace-0.6.0-cleanups.patch
Patch26: ltrace-0.6.0-syscall-time.patch
Patch27: ltrace-0.6.0-abi-ia64.patch
Patch28: ltrace-0.6.0-x86_64-flatten.patch
Patch29: ltrace-0.6.0-dash-l.patch
# Upstream ccbdb91f
Patch0: ltrace-0.7.0-ppc-insn.h.patch
# Upstream 808d64b9
Patch1: ltrace-0.7.0-man5.patch
%description
Ltrace is a debugging program which runs a specified command until the
@ -55,39 +28,13 @@ execution of processes.
%prep
%setup -q
%patch0 -p1
%patch1 -p1
%patch2 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch11 -p1
%patch12 -p1
%patch13 -p1
%patch14 -p1
%patch15 -p1
%patch16 -p1
%patch17 -p1
%patch18 -p1
%patch19 -p1
%patch20 -p1
%patch21 -p1
%patch22 -p1
%patch23 -p1
%patch24 -p1
%patch25 -p1
%patch26 -p1
%patch27 -p1
%patch28 -p1
%patch29 -p1
%build
# This ugly hack is necessary to build and link files for correct
# architecture. It makes a difference on ppc.
export CC="gcc`echo $RPM_OPT_FLAGS | sed -n 's/^.*\(-m[36][124]\).*$/ \1/p'` -D_LARGEFILE64_SOURCE"
autoreconf -i
%configure CC="$CC"
make %{?_smp_mflags}
@ -103,12 +50,21 @@ echo ====================TESTING END=====================
%files
%defattr(-,root,root)
%doc COPYING README TODO BUGS ChangeLog
%doc COPYING README NEWS
%{_bindir}/ltrace
%{_mandir}/man1/ltrace.1*
%{_mandir}/man5/ltrace.conf.5*
%config(noreplace) %{_sysconfdir}/ltrace.conf
%changelog
* Sat Nov 10 2012 Petr Machata <pmachata@redhat.com> - 0.7.0-1
- Upstream 0.7.0
- Drop all the patches
- Upstream patch for missing sysdeps/linux-gnu/ppc/insn.h
(ltrace-0.7.0-ppc-insn.h.patch)
- Upstream patch for installing ltrace.conf.5 to man5
(ltrace-0.7.0-man5.patch)
* Mon Oct 1 2012 Petr Machata <pmachata@redhat.com> - 0.6.0-19
- Upstream patch for ia64 parameter passing
(ltrace-0.6.0-abi-ia64.patch)

View File

@ -1 +1 @@
eca4ffd76293b2cae871b890b1cd4ddf ltrace-0.6.0.tar.bz2
68ad1cdf594fc6819e55519f36092916 ltrace-0.7.0.tar.bz2