import gcc-toolset-11-ltrace-0.7.91-1.el8

c8 imports/c8/gcc-toolset-11-ltrace-0.7.91-1.el8
CentOS Sources 3 years ago committed by MSVSphere Packaging Team
commit 94f5f88da6

@ -0,0 +1 @@
74029042af10b0e9fca6acccb016ce096460a176 SOURCES/ltrace-0.7.91.tar.bz2

1
.gitignore vendored

@ -0,0 +1 @@
SOURCES/ltrace-0.7.91.tar.bz2

@ -0,0 +1,20 @@
diff -up ltrace-0.7.2/proc.c\~ ltrace-0.7.2/proc.c
--- ltrace-0.7.2/proc.c~ 2014-02-13 12:16:33.000000000 +0100
+++ ltrace-0.7.2/proc.c 2014-02-13 15:44:25.000000000 +0100
@@ -194,9 +197,11 @@ process_init(struct process *proc, const
goto fail;
}
- if (proc->leader != proc)
- return 0;
- if (process_init_main(proc) < 0) {
+ if (proc->leader != proc) {
+ proc->e_machine = proc->leader->e_machine;
+ proc->e_class = proc->leader->e_class;
+ get_arch_dep(proc);
+ } else if (process_init_main(proc) < 0) {
process_bare_destroy(proc, 0);
goto fail;
}
Diff finished. Thu Feb 13 15:50:21 2014

@ -0,0 +1,151 @@
diff -rupN a/options.c b/options.c
--- a/options.c 2019-06-28 17:15:31.515626363 -0400
+++ b/options.c 2019-06-28 17:18:59.490632337 -0400
@@ -440,7 +440,8 @@ parse_int(const char *optarg, char opt,
}
int
-parse_colon_separated_list(const char *paths, struct vect *vec)
+parse_colon_separated_list(const char *paths, struct vect *vec,
+ enum opt_F_origin origin)
{
/* PATHS contains a colon-separated list of directories and
* files to load. It's modeled after shell PATH variable,
@@ -467,6 +468,7 @@ parse_colon_separated_list(const char *p
struct opt_F_t arg = {
.pathname = tok,
.own_pathname = tok == clone,
+ .origin = origin,
};
if (VECT_PUSHBACK(vec, &arg) < 0)
/* Presumably this is not a deal-breaker. */
@@ -494,16 +496,18 @@ opt_F_get_kind(struct opt_F_t *entry)
if (entry->kind == OPT_F_UNKNOWN) {
struct stat st;
if (lstat(entry->pathname, &st) < 0) {
- fprintf(stderr, "Couldn't stat %s: %s\n",
- entry->pathname, strerror(errno));
+ if (entry->origin == OPT_F_CMDLINE)
+ fprintf(stderr, "Couldn't stat %s: %s\n",
+ entry->pathname, strerror(errno));
entry->kind = OPT_F_BROKEN;
} else if (S_ISDIR(st.st_mode)) {
entry->kind = OPT_F_DIR;
} else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
entry->kind = OPT_F_FILE;
} else {
- fprintf(stderr, "%s is neither a regular file, "
- "nor a directory.\n", entry->pathname);
+ if (entry->origin == OPT_F_CMDLINE)
+ fprintf(stderr, "%s is neither a regular file, "
+ "nor a directory.\n", entry->pathname);
entry->kind = OPT_F_BROKEN;
}
}
@@ -607,7 +611,8 @@ process_options(int argc, char **argv)
options.follow = 1;
break;
case 'F':
- parse_colon_separated_list(optarg, &opt_F);
+ parse_colon_separated_list(optarg, &opt_F,
+ OPT_F_CMDLINE);
break;
case 'h':
usage();
diff -rupN a/options.h b/options.h
--- a/options.h 2019-06-28 17:15:31.515626363 -0400
+++ b/options.h 2019-06-28 17:18:55.984632238 -0400
@@ -1,6 +1,6 @@
/*
* This file is part of ltrace.
- * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
+ * Copyright (C) 2012, 2013, 2015 Petr Machata, Red Hat Inc.
* Copyright (C) 2009,2010 Joe Damato
* Copyright (C) 1998,2002,2008 Juan Cespedes
* Copyright (C) 2006 Ian Wienand
@@ -77,10 +77,16 @@ enum opt_F_kind {
OPT_F_DIR,
};
+enum opt_F_origin {
+ OPT_F_CMDLINE = 0,
+ OPT_F_ENVIRON,
+};
+
struct opt_F_t {
char *pathname;
int own_pathname : 1;
enum opt_F_kind kind : 2;
+ enum opt_F_origin origin : 1;
};
/* If entry->kind is OPT_F_UNKNOWN, figure out whether it should be
@@ -98,7 +104,8 @@ void opt_F_destroy(struct opt_F_t *entry
* The list is split and added to VEC, which shall be a vector
* initialized like VECT_INIT(VEC, struct opt_F_t); Returns 0 on
* success or a negative value on failure. */
-int parse_colon_separated_list(const char *paths, struct vect *vec);
+int parse_colon_separated_list(const char *paths, struct vect *vec,
+ enum opt_F_origin origin);
/* Vector of struct opt_F_t. */
extern struct vect opt_F;
diff -rupN a/sysdeps/linux-gnu/hooks.c b/sysdeps/linux-gnu/hooks.c
--- a/sysdeps/linux-gnu/hooks.c 2013-11-04 20:08:03.000000000 -0500
+++ b/sysdeps/linux-gnu/hooks.c 2019-06-28 17:18:55.989632238 -0400
@@ -1,6 +1,6 @@
/*
* This file is part of ltrace.
- * Copyright (C) 2012, 2013 Petr Machata
+ * Copyright (C) 2012, 2013, 2015 Petr Machata
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -153,7 +153,7 @@ again:
if (xdg_sys != NULL) {
struct vect v;
VECT_INIT(&v, struct opt_F_t);
- if (parse_colon_separated_list(xdg_sys, &v) < 0
+ if (parse_colon_separated_list(xdg_sys, &v, OPT_F_ENVIRON) < 0
|| VECT_EACH(&v, struct opt_F_t, NULL,
add_dir_component_cb, &dirs) != NULL)
fprintf(stderr,
diff -rupN a/testsuite/ltrace.main/XDG_CONFIG_DIRS.exp b/testsuite/ltrace.main/XDG_CONFIG_DIRS.exp
--- a/testsuite/ltrace.main/XDG_CONFIG_DIRS.exp 1969-12-31 19:00:00.000000000 -0500
+++ b/testsuite/ltrace.main/XDG_CONFIG_DIRS.exp 2019-06-28 17:18:55.989632238 -0400
@@ -0,0 +1,35 @@
+# This file is part of ltrace.
+# Copyright (C) 2015 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 bin [ltraceCompile {} [ltraceSource c {
+ int main() { return 0; }
+}]]
+
+setenv XDG_CONFIG_DIRS "blah"
+ltraceRun -L -- $bin
+unsetenv XDG_CONFIG_DIRS
+
+if {[catch "exec $LTRACE -L -F blah -- $bin" output]} {
+ ltraceMatch [ltraceSource ltrace "$output"] {
+ {blah == 1}
+ }
+} else {
+ fail "expected error message regarding `blah`"
+}
+
+ltraceDone

@ -0,0 +1,24 @@
Index: ltrace-0.7.91/sysdeps/linux-gnu/aarch64/regs.c
===================================================================
--- ltrace-0.7.91.orig/sysdeps/linux-gnu/aarch64/regs.c
+++ ltrace-0.7.91/sysdeps/linux-gnu/aarch64/regs.c
@@ -23,6 +23,7 @@
#include <linux/uio.h>
#include <assert.h>
#include <stdlib.h>
+#include <stdio.h>
#include "backend.h"
#include "proc.h"
Index: ltrace-0.7.91/sysdeps/linux-gnu/aarch64/trace.c
===================================================================
--- ltrace-0.7.91.orig/sysdeps/linux-gnu/aarch64/trace.c
+++ ltrace-0.7.91/sysdeps/linux-gnu/aarch64/trace.c
@@ -24,6 +24,7 @@
#include <asm/ptrace.h>
#include <string.h>
#include <errno.h>
+#include <stdio.h>
#include "backend.h"
#include "proc.h"

@ -0,0 +1,37 @@
diff -rup a/sysdeps/linux-gnu/aarch64/fetch.c b/sysdeps/linux-gnu/aarch64/fetch.c
--- a/sysdeps/linux-gnu/aarch64/fetch.c 2018-07-05 16:06:10.066626252 -0400
+++ b/sysdeps/linux-gnu/aarch64/fetch.c 2018-07-05 16:17:17.659748481 -0400
@@ -308,12 +308,9 @@ arch_fetch_arg_init(enum tof type, struc
struct fetch_script how = pass_arg(context, proc, ret_info);
if (how.c == CVT_ERR)
goto fail;
- if (how.c == CVT_NOP && how.f == FETCH_STACK) {
+ if (how.c == CVT_BYREF && how.f == FETCH_GPR) {
/* XXX double cast. */
context->x8 = (arch_addr_t) (uintptr_t) context->gregs.regs[8];
- /* See the comment above about the assert. */
- assert(! "Unexpected: first argument passed on stack.");
- abort();
}
return context;
diff -rup a/testsuite/ltrace.main/system_call_params.exp b/testsuite/ltrace.main/system_call_params.exp
--- a/testsuite/ltrace.main/system_call_params.exp 2018-07-05 16:06:10.516624926 -0400
+++ b/testsuite/ltrace.main/system_call_params.exp 2018-07-05 16:58:01.549830643 -0400
@@ -61,13 +61,13 @@ set conf [ltraceNamedSource "$dir/syscal
# doesn't list readdir, that would be taken from somelib.conf with a
# wrong prototype.
-ltraceMatch1 [ltraceRun -L -S -F $conf -- $bin] {^open@SYS\("/some/path"} == 0
+ltraceMatch1 [ltraceRun -L -S -F $conf -- $bin] {^open@SYS\("/some/path", 0\)} == 0
# On the other hand, if -F somedir/ is given, we want to accept
# syscalls.conf found there.
ltraceMatch [ltraceRun -L -S -F $dir -- $bin] {
- {{^open@SYS\("/some/path"} == 1}
+ {{^open@SYS\("/some/path", 0\)} == 1}
{{^write@SYS\(1, "something", 10\)} == 1}
{{^mount@SYS\("source", "target", "filesystemtype"} == 1}
}
Only in b/testsuite/ltrace.main: system_call_params.exp~

File diff suppressed because it is too large Load Diff

@ -0,0 +1,834 @@
From 0cf4ab66e9927e101a51dd9fa9adc6c8dc56b5e7 Mon Sep 17 00:00:00 2001
From: Petr Machata <pmachata@redhat.com>
Date: Thu, 21 Nov 2013 20:25:53 +0100
Subject: [PATCH] Consider exec and exit events an end of outstanding calls
- This cleans up a lot of stuff. The actual substance is addition of
account_current_callstack in handle_event.c (which however uses
those cleaned-up interfaces).
- trace-exec.exp was extended to check that the exec syscall can be
seen in -c output. That's one of the symptoms of what this fixes.
---
Makefile.am | 8 +-
common.h | 2 -
forward.h | 1 +
handle_event.c | 225 ++++++++++++++++++++-------------
libltrace.c | 5 +-
options.h | 8 +-
output.c | 86 +++----------
output.h | 5 +-
proc.h | 2 +-
summary.c | 89 +++++++++++++-
summary.h | 35 +++++
testsuite/ltrace.minor/trace-exec.exp | 16 ++-
12 files changed, 299 insertions(+), 183 deletions(-)
create mode 100644 summary.h
diff --git a/Makefile.am b/Makefile.am
index d711aec..efcf18a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -54,10 +54,10 @@ ltrace_LDADD = \
noinst_HEADERS = bits.h backend.h breakpoint.h common.h debug.h \
defs.h demangle.h dict.h forward.h ltrace-elf.h ltrace.h \
- options.h output.h proc.h read_config_file.h library.h \
- filter.h glob.h vect.h type.h value.h value_dict.h callback.h \
- expr.h fetch.h vect.h param.h printf.h zero.h lens.h \
- lens_default.h lens_enum.h memstream.h prototype.h
+ options.h output.h proc.h read_config_file.h summary.h \
+ library.h filter.h glob.h vect.h type.h value.h value_dict.h \
+ callback.h expr.h fetch.h vect.h param.h printf.h zero.h \
+ lens.h lens_default.h lens_enum.h memstream.h prototype.h
dist_man1_MANS = ltrace.1
dist_man5_MANS = ltrace.conf.5
diff --git a/common.h b/common.h
index a53c5db..7259ba4 100644
--- a/common.h
+++ b/common.h
@@ -54,8 +54,6 @@ extern void handle_event(Event * event);
extern pid_t execute_program(const char * command, char ** argv);
-extern void show_summary(void);
-
struct breakpoint;
struct library_symbol;
diff --git a/forward.h b/forward.h
index 8641213..58d8f05 100644
--- a/forward.h
+++ b/forward.h
@@ -34,6 +34,7 @@ struct param_enum;
struct process;
struct protolib;
struct prototype;
+struct timedelta;
struct value;
struct value_dict;
struct vect;
diff --git a/handle_event.c b/handle_event.c
index 9ed62a2..6fa7e98 100644
--- a/handle_event.c
+++ b/handle_event.c
@@ -32,7 +32,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/time.h>
#include <stdbool.h>
#include "backend.h"
@@ -41,8 +40,9 @@
#include "fetch.h"
#include "library.h"
#include "proc.h"
-#include "value_dict.h"
#include "prototype.h"
+#include "summary.h"
+#include "value_dict.h"
static void handle_signal(Event *event);
static void handle_exit(Event *event);
@@ -419,32 +419,11 @@ handle_signal(Event *event) {
continue_after_signal(event->proc->pid, event->e_un.signum);
}
-static void
-handle_exit(Event *event) {
- debug(DEBUG_FUNCTION, "handle_exit(pid=%d, status=%d)", event->proc->pid, event->e_un.ret_val);
- if (event->proc->state != STATE_IGNORED) {
- output_line(event->proc, "+++ exited (status %d) +++",
- event->e_un.ret_val);
- }
- remove_process(event->proc);
-}
-
-static void
-handle_exit_signal(Event *event) {
- debug(DEBUG_FUNCTION, "handle_exit_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
- if (event->proc->state != STATE_IGNORED) {
- output_line(event->proc, "+++ killed by %s +++",
- shortsignal(event->proc, event->e_un.signum));
- }
- remove_process(event->proc);
-}
-
-static void
-output_syscall(struct process *proc, const char *name, enum tof tof,
- void (*output)(enum tof, struct process *,
- struct library_symbol *))
+static int
+init_syscall_symbol(struct library_symbol *libsym, const char *name)
{
static struct library syscall_lib;
+
if (syscall_lib.protolib == NULL) {
struct protolib *protolib
= protolib_cache_load(&g_protocache, "syscalls", 0, 1);
@@ -475,10 +454,91 @@ output_syscall(struct process *proc, const char *name, enum tof tof,
syscall_lib.protolib = protolib;
}
+ if (library_symbol_init(libsym, 0, name, 0, LS_TOPLT_NONE) < 0)
+ return -1;
+
+ libsym->lib = &syscall_lib;
+ return 0;
+}
+
+/* Account the unfinished functions on the call stack. */
+static void
+account_current_callstack(struct process *proc)
+{
+ if (! options.summary)
+ return;
+
+ struct timedelta spent[proc->callstack_depth];
+
+ size_t i;
+ for (i = 0; i < proc->callstack_depth; ++i) {
+ struct callstack_element *elem = &proc->callstack[i];
+ spent[i] = calc_time_spent(elem->enter_time);
+ }
+
+ for (i = 0; i < proc->callstack_depth; ++i) {
+ struct callstack_element *elem = &proc->callstack[i];
+ struct library_symbol syscall, *libsym = NULL;
+ if (elem->is_syscall) {
+ const char *name = sysname(proc, elem->c_un.syscall);
+ if (init_syscall_symbol(&syscall, name) >= 0)
+ libsym = &syscall;
+
+ } else {
+ libsym = elem->c_un.libfunc;
+ }
+
+ if (libsym != NULL) {
+ summary_account_call(libsym, spent[i]);
+
+ if (elem->is_syscall)
+ library_symbol_destroy(&syscall);
+ }
+ }
+}
+
+static void
+handle_exit(Event *event) {
+ debug(DEBUG_FUNCTION, "handle_exit(pid=%d, status=%d)", event->proc->pid, event->e_un.ret_val);
+ if (event->proc->state != STATE_IGNORED) {
+ output_line(event->proc, "+++ exited (status %d) +++",
+ event->e_un.ret_val);
+ }
+
+ account_current_callstack(event->proc);
+ remove_process(event->proc);
+}
+
+static void
+handle_exit_signal(Event *event) {
+ debug(DEBUG_FUNCTION, "handle_exit_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
+ if (event->proc->state != STATE_IGNORED) {
+ output_line(event->proc, "+++ killed by %s +++",
+ shortsignal(event->proc, event->e_un.signum));
+ }
+
+ account_current_callstack(event->proc);
+ remove_process(event->proc);
+}
+
+static void
+output_syscall(struct process *proc, const char *name, enum tof tof,
+ bool left, struct timedelta *spent)
+{
+ if (left)
+ assert(spent == NULL);
+
struct library_symbol syscall;
- if (library_symbol_init(&syscall, 0, name, 0, LS_TOPLT_NONE) >= 0) {
- syscall.lib = &syscall_lib;
- (*output)(tof, proc, &syscall);
+ if (init_syscall_symbol(&syscall, name) >= 0) {
+ if (left) {
+ if (! options.summary)
+ output_left(tof, proc, &syscall);
+ } else if (options.summary) {
+ summary_account_call(&syscall, *spent);
+ } else {
+ output_right(tof, proc, &syscall, spent);
+ }
+
library_symbol_destroy(&syscall);
}
}
@@ -486,17 +546,19 @@ output_syscall(struct process *proc, const char *name, enum tof tof,
static void
output_syscall_left(struct process *proc, const char *name)
{
- output_syscall(proc, name, LT_TOF_SYSCALL, &output_left);
+ output_syscall(proc, name, LT_TOF_SYSCALL, true, NULL);
}
static void
-output_syscall_right(struct process *proc, const char *name)
+output_syscall_right(struct process *proc, const char *name,
+ struct timedelta *spent)
{
- output_syscall(proc, name, LT_TOF_SYSCALLR, &output_right);
+ output_syscall(proc, name, LT_TOF_SYSCALLR, false, spent);
}
static void
-handle_syscall(Event *event) {
+handle_syscall(Event *event)
+{
debug(DEBUG_FUNCTION, "handle_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
if (event->proc->state != STATE_IGNORED) {
callstack_push_syscall(event->proc, event->e_un.sysnum);
@@ -526,6 +588,8 @@ handle_exec(Event *event)
}
output_line(proc, "--- Called exec() ---");
+ account_current_callstack(proc);
+
if (process_exec(proc) < 0) {
fprintf(stderr,
"couldn't reinitialize process %d after exec\n", pid);
@@ -549,74 +613,58 @@ handle_arch_syscall(Event *event) {
continue_process(event->proc->pid);
}
-struct timeval current_time_spent;
-
static void
-calc_time_spent(struct process *proc)
+handle_x_sysret(Event *event, char *(*name_cb)(struct process *, int))
{
- struct timeval tv;
- struct timezone tz;
- struct timeval diff;
- struct callstack_element *elem;
-
- debug(DEBUG_FUNCTION, "calc_time_spent(pid=%d)", proc->pid);
- elem = &proc->callstack[proc->callstack_depth - 1];
-
- gettimeofday(&tv, &tz);
+ debug(DEBUG_FUNCTION, "handle_x_sysret(pid=%d, sysnum=%d)",
+ event->proc->pid, event->e_un.sysnum);
- diff.tv_sec = tv.tv_sec - elem->time_spent.tv_sec;
- if (tv.tv_usec >= elem->time_spent.tv_usec) {
- diff.tv_usec = tv.tv_usec - elem->time_spent.tv_usec;
- } else {
- diff.tv_sec--;
- diff.tv_usec = 1000000 + tv.tv_usec - elem->time_spent.tv_usec;
- }
- current_time_spent = diff;
-}
+ unsigned d = event->proc->callstack_depth;
+ assert(d > 0);
+ struct callstack_element *elem = &event->proc->callstack[d - 1];
+ assert(elem->is_syscall);
-static void
-handle_sysret(Event *event) {
- debug(DEBUG_FUNCTION, "handle_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
if (event->proc->state != STATE_IGNORED) {
- if (opt_T || options.summary) {
- calc_time_spent(event->proc);
- }
+ struct timedelta spent = calc_time_spent(elem->enter_time);
if (options.syscalls)
output_syscall_right(event->proc,
- sysname(event->proc,
- event->e_un.sysnum));
+ name_cb(event->proc,
+ event->e_un.sysnum),
+ &spent);
- assert(event->proc->callstack_depth > 0);
- unsigned d = event->proc->callstack_depth - 1;
- assert(event->proc->callstack[d].is_syscall);
callstack_pop(event->proc);
}
continue_after_syscall(event->proc, event->e_un.sysnum, 1);
}
static void
-handle_arch_sysret(Event *event) {
- debug(DEBUG_FUNCTION, "handle_arch_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
- if (event->proc->state != STATE_IGNORED) {
- if (opt_T || options.summary) {
- calc_time_spent(event->proc);
- }
- if (options.syscalls)
- output_syscall_right(event->proc,
- arch_sysname(event->proc,
- event->e_un.sysnum));
- callstack_pop(event->proc);
- }
- continue_process(event->proc->pid);
+handle_sysret(Event *event)
+{
+ handle_x_sysret(event, &sysname);
+}
+
+static void
+handle_arch_sysret(Event *event)
+{
+ handle_x_sysret(event, &arch_sysname);
}
static void
output_right_tos(struct process *proc)
{
size_t d = proc->callstack_depth;
+ assert(d > 0);
struct callstack_element *elem = &proc->callstack[d - 1];
- if (proc->state != STATE_IGNORED)
- output_right(LT_TOF_FUNCTIONR, proc, elem->c_un.libfunc);
+ assert(! elem->is_syscall);
+
+ if (proc->state != STATE_IGNORED) {
+ struct timedelta spent = calc_time_spent(elem->enter_time);
+ if (options.summary)
+ summary_account_call(elem->c_un.libfunc, spent);
+ else
+ output_right(LT_TOF_FUNCTIONR, proc, elem->c_un.libfunc,
+ &spent);
+ }
}
#ifndef ARCH_HAVE_SYMBOL_RET
@@ -645,14 +693,8 @@ handle_breakpoint(Event *event)
for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
if (brk_addr == event->proc->callstack[i].return_addr) {
- for (j = event->proc->callstack_depth - 1; j > i; j--) {
+ for (j = event->proc->callstack_depth - 1; j > i; j--)
callstack_pop(event->proc);
- }
- if (event->proc->state != STATE_IGNORED) {
- if (opt_T || options.summary) {
- calc_time_spent(event->proc);
- }
- }
struct library_symbol *libsym =
event->proc->callstack[i].c_un.libfunc;
@@ -705,11 +747,14 @@ handle_breakpoint(Event *event)
/* breakpoint_on_hit may delete its own breakpoint, so we have
* to look it up again. */
if ((sbp = address2bpstruct(leader, brk_addr)) != NULL) {
+
if (event->proc->state != STATE_IGNORED
&& sbp->libsym != NULL) {
event->proc->stack_pointer = get_stack_pointer(event->proc);
callstack_push_symfunc(event->proc, sbp);
- output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym);
+ if (! options.summary)
+ output_left(LT_TOF_FUNCTION, event->proc,
+ sbp->libsym);
}
breakpoint_on_continue(sbp, event->proc);
@@ -743,7 +788,7 @@ callstack_push_syscall(struct process *proc, int sysnum)
proc->callstack_depth++;
if (opt_T || options.summary) {
struct timezone tz;
- gettimeofday(&elem->time_spent, &tz);
+ gettimeofday(&elem->enter_time, &tz);
}
}
@@ -781,7 +826,7 @@ callstack_push_symfunc(struct process *proc, struct breakpoint *bp)
if (opt_T || options.summary) {
struct timezone tz;
- gettimeofday(&elem->time_spent, &tz);
+ gettimeofday(&elem->enter_time, &tz);
}
}
diff --git a/libltrace.c b/libltrace.c
index 2d910a1..0112c9f 100644
--- a/libltrace.c
+++ b/libltrace.c
@@ -32,11 +32,12 @@
#include <string.h>
#include <unistd.h>
+#include "backend.h"
#include "common.h"
#include "proc.h"
-#include "read_config_file.h"
-#include "backend.h"
#include "prototype.h"
+#include "read_config_file.h"
+#include "summary.h"
char *command = NULL;
diff --git a/options.h b/options.h
index 6c28ed9..d0df3a7 100644
--- a/options.h
+++ b/options.h
@@ -1,6 +1,6 @@
/*
* This file is part of ltrace.
- * Copyright (C) 2012 Petr Machata, Red Hat Inc.
+ * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
* Copyright (C) 2009,2010 Joe Damato
* Copyright (C) 1998,2002,2008 Juan Cespedes
* Copyright (C) 2006 Ian Wienand
@@ -103,12 +103,6 @@ int parse_colon_separated_list(const char *paths, struct vect *vec);
/* Vector of struct opt_F_t. */
extern struct vect opt_F;
-struct opt_c_struct {
- int count;
- struct timeval tv;
-};
-extern struct dict *dict_opt_c;
-
extern char **process_options(int argc, char **argv);
#endif /* _OPTIONS_H_ */
diff --git a/output.c b/output.c
index edf4522..82b6a5e 100644
--- a/output.c
+++ b/output.c
@@ -44,16 +44,12 @@
#include "param.h"
#include "proc.h"
#include "prototype.h"
+#include "summary.h"
#include "type.h"
#include "value.h"
#include "value_dict.h"
-/* TODO FIXME XXX: include in common.h: */
-extern struct timeval current_time_spent;
-
-struct dict *dict_opt_c = NULL;
-
-static struct process *current_proc = 0;
+static struct process *current_proc = NULL;
static size_t current_depth = 0;
static int current_column = 0;
@@ -498,9 +494,8 @@ void
output_left(enum tof type, struct process *proc,
struct library_symbol *libsym)
{
- if (options.summary) {
- return;
- }
+ assert(! options.summary);
+
if (current_proc) {
fprintf(options.output, " <unfinished ...>\n");
current_column = 0;
@@ -572,70 +567,21 @@ output_left(enum tof type, struct process *proc,
stel->out.need_delim = need_delim;
}
-static void
-free_stringp_cb(const char **stringp, void *data)
-{
- free((char *)*stringp);
-}
-
void
-output_right(enum tof type, struct process *proc, struct library_symbol *libsym)
+output_right(enum tof type, struct process *proc, struct library_symbol *libsym,
+ struct timedelta *spent)
{
+ assert(! options.summary);
+
struct prototype *func = lookup_symbol_prototype(proc, libsym);
if (func == NULL)
return;
-again:
- if (options.summary) {
- if (dict_opt_c == NULL) {
- dict_opt_c = malloc(sizeof(*dict_opt_c));
- if (dict_opt_c == NULL) {
- oom:
- fprintf(stderr,
- "Can't allocate memory for "
- "keeping track of -c.\n");
- free(dict_opt_c);
- options.summary = 0;
- goto again;
- }
- DICT_INIT(dict_opt_c, char *, struct opt_c_struct,
- dict_hash_string, dict_eq_string, NULL);
- }
-
- struct opt_c_struct *st
- = DICT_FIND_REF(dict_opt_c, &libsym->name,
- struct opt_c_struct);
- if (st == NULL) {
- const char *na = strdup(libsym->name);
- struct opt_c_struct new_st = {.count = 0, .tv = {0, 0}};
- if (na == NULL
- || DICT_INSERT(dict_opt_c, &na, &new_st) < 0) {
- free((char *)na);
- DICT_DESTROY(dict_opt_c, const char *,
- struct opt_c_struct,
- free_stringp_cb, NULL, NULL);
- goto oom;
- }
- st = DICT_FIND_REF(dict_opt_c, &libsym->name,
- struct opt_c_struct);
- assert(st != NULL);
- }
-
- if (st->tv.tv_usec + current_time_spent.tv_usec > 1000000) {
- st->tv.tv_usec += current_time_spent.tv_usec - 1000000;
- st->tv.tv_sec++;
- } else {
- st->tv.tv_usec += current_time_spent.tv_usec;
- }
- st->count++;
- st->tv.tv_sec += current_time_spent.tv_sec;
- return;
- }
-
- if (current_proc && (current_proc != proc ||
- current_depth != proc->callstack_depth)) {
+ if (current_proc != NULL
+ && (current_proc != proc
+ || current_depth != proc->callstack_depth)) {
fprintf(options.output, " <unfinished ...>\n");
- current_proc = 0;
+ current_proc = NULL;
}
if (current_proc != proc) {
begin_of_line(proc, type == LT_TOF_FUNCTIONR, 1);
@@ -689,10 +635,12 @@ again:
value_destroy(&retval);
if (opt_T) {
+ assert(spent != NULL);
fprintf(options.output, " <%lu.%06d>",
- (unsigned long)current_time_spent.tv_sec,
- (int)current_time_spent.tv_usec);
+ (unsigned long) spent->tm.tv_sec,
+ (int) spent->tm.tv_usec);
}
+
fprintf(options.output, "\n");
#if defined(HAVE_LIBUNWIND)
@@ -746,7 +694,7 @@ again:
}
#endif /* defined(HAVE_LIBUNWIND) */
- current_proc = 0;
+ current_proc = NULL;
current_column = 0;
}
diff --git a/output.h b/output.h
index b9f0518..2e74d61 100644
--- a/output.h
+++ b/output.h
@@ -1,6 +1,6 @@
/*
* This file is part of ltrace.
- * Copyright (C) 2011, 2012 Petr Machata, Red Hat Inc.
+ * Copyright (C) 2011, 2012, 2013 Petr Machata, Red Hat Inc.
* Copyright (C) 2009 Juan Cespedes
*
* This program is free software; you can redistribute it and/or
@@ -28,7 +28,8 @@ void output_line(struct process *proc, const char *fmt, ...);
void output_left(enum tof type, struct process *proc,
struct library_symbol *libsym);
void output_right(enum tof type, struct process *proc,
- struct library_symbol *libsym);
+ struct library_symbol *libsym,
+ struct timedelta *spent);
/* This function is for emitting lists of comma-separated strings.
*
diff --git a/proc.h b/proc.h
index e8032fa..64f8fe2 100644
--- a/proc.h
+++ b/proc.h
@@ -66,7 +66,7 @@ struct callstack_element {
} c_un;
int is_syscall;
arch_addr_t return_addr;
- struct timeval time_spent;
+ struct timeval enter_time;
struct fetch_context *fetch_context;
struct value_dict *arguments;
struct output_state out;
diff --git a/summary.c b/summary.c
index 9e22086..9103f71 100644
--- a/summary.c
+++ b/summary.c
@@ -22,11 +22,15 @@
#include "config.h"
+#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
-#include <sys/time.h>
+#include <string.h>
-#include "common.h"
+#include "summary.h"
+#include "dict.h"
+#include "library.h"
+#include "options.h"
struct entry_st {
const char *name;
@@ -40,6 +44,32 @@ struct fill_struct_data {
unsigned long tot_usecs;
};
+struct opt_c_struct {
+ int count;
+ struct timeval tv;
+};
+
+static struct dict *dict_opt_c;
+
+struct timedelta
+calc_time_spent(struct timeval start)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ struct timeval diff;
+ diff.tv_sec = tv.tv_sec - start.tv_sec;
+ if (tv.tv_usec >= start.tv_usec) {
+ diff.tv_usec = tv.tv_usec - start.tv_usec;
+ } else {
+ diff.tv_sec--;
+ diff.tv_usec = 1000000 + tv.tv_usec - start.tv_usec;
+ }
+
+ struct timedelta ret = { diff };
+ return ret;
+}
+
static enum callback_status
fill_struct(const char **namep, struct opt_c_struct *st, void *u)
{
@@ -114,3 +144,58 @@ show_summary(void)
vect_destroy(&cdata.entries, NULL, NULL);
}
+
+static void
+free_stringp_cb(const char **stringp, void *data)
+{
+ free((char *)*stringp);
+}
+
+void
+summary_account_call(struct library_symbol *libsym, struct timedelta spent)
+{
+ assert(options.summary);
+
+ if (dict_opt_c == NULL) {
+ dict_opt_c = malloc(sizeof(*dict_opt_c));
+ if (dict_opt_c == NULL) {
+ oom:
+ fprintf(stderr,
+ "Can't allocate memory for "
+ "keeping track of -c.\n");
+ free(dict_opt_c);
+ options.summary = 0;
+ return;
+ }
+ DICT_INIT(dict_opt_c, char *, struct opt_c_struct,
+ dict_hash_string, dict_eq_string, NULL);
+ }
+
+ struct opt_c_struct *st = DICT_FIND_REF(dict_opt_c, &libsym->name,
+ struct opt_c_struct);
+ if (st == NULL) {
+ const char *na = strdup(libsym->name);
+ struct opt_c_struct new_st = {.count = 0, .tv = {0, 0}};
+ if (na == NULL
+ || DICT_INSERT(dict_opt_c, &na, &new_st) < 0) {
+ free((char *) na);
+ DICT_DESTROY(dict_opt_c, const char *,
+ struct opt_c_struct,
+ free_stringp_cb, NULL, NULL);
+ goto oom;
+ }
+ st = DICT_FIND_REF(dict_opt_c, &libsym->name,
+ struct opt_c_struct);
+ assert(st != NULL);
+ }
+
+ if (st->tv.tv_usec + spent.tm.tv_usec > 1000000) {
+ st->tv.tv_usec += spent.tm.tv_usec - 1000000;
+ st->tv.tv_sec++;
+ } else {
+ st->tv.tv_usec += spent.tm.tv_usec;
+ }
+ st->count++;
+ st->tv.tv_sec += spent.tm.tv_sec;
+ return;
+}
diff --git a/summary.h b/summary.h
new file mode 100644
index 0000000..f680ef9
--- /dev/null
+++ b/summary.h
@@ -0,0 +1,35 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef _SUMMARY_H_
+#define _SUMMARY_H_
+
+#include "forward.h"
+
+struct timedelta {
+ struct timeval tm;
+};
+
+struct timedelta calc_time_spent(struct timeval start);
+void summary_account_call(struct library_symbol *libsym,
+ struct timedelta spent);
+void show_summary(void);
+
+#endif /* _SUMMARY_H_ */
diff --git a/testsuite/ltrace.minor/trace-exec.exp b/testsuite/ltrace.minor/trace-exec.exp
index 7a953de..57260f8 100644
--- a/testsuite/ltrace.minor/trace-exec.exp
+++ b/testsuite/ltrace.minor/trace-exec.exp
@@ -1,5 +1,5 @@
# This file is part of ltrace.
-# Copyright (C) 2012 Petr Machata, Red Hat Inc.
+# Copyright (C) 2012, 2013 Petr Machata, Red Hat Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
@@ -16,22 +16,30 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
# 02110-1301 USA
-ltraceMatch [ltraceRun -xmain -- [ltraceCompile {} [ltraceSource c {
+set bin1 [ltraceCompile {} [ltraceSource c {
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char ** argv) {
execl(argv[1], argv[1], NULL);
abort();
}
-}]] [ltraceCompile {} [ltraceSource c {
+}]]
+
+set bin2 [ltraceCompile {} [ltraceSource c {
#include <stdio.h>
int main(void) {
return puts("Hello, World.");
}
-}]]] {
+}]]
+
+ltraceMatch [ltraceRun -xmain -- $bin1 $bin2] {
{{^execl\(} == 1}
{{^puts\(.*\) .*= 14} == 1}
{{^main\(} == 2}
}
+ltraceMatch [ltraceRun -c -- $bin1 $bin2] {
+ {{exec} > 0}
+}
+
ltraceDone
--
1.7.6.5

@ -0,0 +1,610 @@
diff --git a/ltrace-elf.c b/ltrace-elf.c
index 92b642b..6f86d56 100644
--- a/ltrace-elf.c
+++ b/ltrace-elf.c
@@ -531,6 +531,38 @@ elf_read_relocs(struct ltelf *lte, Elf_Scn *scn, GElf_Shdr *shdr,
return 0;
}
+int
+elf_load_dynamic_entry(struct ltelf *lte, int tag, GElf_Addr *valuep)
+{
+ Elf_Scn *scn;
+ GElf_Shdr shdr;
+ if (elf_get_section_type(lte, SHT_DYNAMIC, &scn, &shdr) < 0
+ || scn == NULL) {
+ fail:
+ fprintf(stderr, "Couldn't get SHT_DYNAMIC: %s\n",
+ elf_errmsg(-1));
+ return -1;
+ }
+
+ Elf_Data *data = elf_loaddata(scn, &shdr);
+ if (data == NULL)
+ goto fail;
+
+ size_t j;
+ for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) {
+ GElf_Dyn dyn;
+ if (gelf_getdyn(data, j, &dyn) == NULL)
+ goto fail;
+
+ if(dyn.d_tag == tag) {
+ *valuep = dyn.d_un.d_ptr;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
static int
ltelf_read_elf(struct ltelf *lte, const char *filename)
{
diff --git a/ltrace-elf.h b/ltrace-elf.h
index ea14512..db4ffe9 100644
--- a/ltrace-elf.h
+++ b/ltrace-elf.h
@@ -139,6 +139,10 @@ struct elf_each_symbol_t {
int elf_read_relocs(struct ltelf *lte, Elf_Scn *scn, GElf_Shdr *shdr,
struct vect *rela_vec);
+/* Read a given DT_ TAG from LTE. Value is returned in *VALUEP.
+ * Returns 0 on success or a negative value on failure. */
+int elf_load_dynamic_entry(struct ltelf *lte, int tag, GElf_Addr *valuep);
+
/* Read, respectively, 1, 2, 4, or 8 bytes from Elf data at given
* OFFSET, and store it in *RETP. Returns 0 on success or a negative
* value if there's not enough data. */
diff --git a/sysdeps/linux-gnu/arm/arch.h b/sysdeps/linux-gnu/arm/arch.h
index 58a7fdf..6d0d902 100644
--- a/sysdeps/linux-gnu/arm/arch.h
+++ b/sysdeps/linux-gnu/arm/arch.h
@@ -22,6 +22,8 @@
#ifndef LTRACE_ARM_ARCH_H
#define LTRACE_ARM_ARCH_H
+#include <libelf.h>
+
#define ARCH_HAVE_ENABLE_BREAKPOINT 1
#define ARCH_HAVE_DISABLE_BREAKPOINT 1
@@ -47,7 +49,7 @@ struct arch_breakpoint_data {
#define ARCH_HAVE_LTELF_DATA
struct arch_ltelf_data {
- /* We have this only for the hooks. */
+ Elf_Data *jmprel_data;
};
#define ARCH_HAVE_LIBRARY_DATA
diff --git a/sysdeps/linux-gnu/arm/fetch.c b/sysdeps/linux-gnu/arm/fetch.c
index 5081d78..b500448 100644
--- a/sysdeps/linux-gnu/arm/fetch.c
+++ b/sysdeps/linux-gnu/arm/fetch.c
@@ -32,200 +32,12 @@
#include "backend.h"
#include "fetch.h"
#include "library.h"
-#include "ltrace-elf.h"
#include "proc.h"
#include "ptrace.h"
#include "regs.h"
#include "type.h"
#include "value.h"
-static int
-get_hardfp(uint64_t abi_vfp_args)
-{
- if (abi_vfp_args == 2)
- fprintf(stderr,
- "Tag_ABI_VFP_args value 2 (tool chain-specific "
- "conventions) not supported.\n");
- return abi_vfp_args == 1;
-}
-
-int
-arch_elf_init(struct ltelf *lte, struct library *lib)
-{
- /* Nothing in this section is strictly critical. It's not
- * that much of a deal if we fail to guess right whether the
- * ABI is softfp or hardfp. */
- unsigned hardfp = 0;
-
- Elf_Scn *scn;
- Elf_Data *data;
- GElf_Shdr shdr;
- if (elf_get_section_type(lte, SHT_ARM_ATTRIBUTES, &scn, &shdr) < 0
- || (scn != NULL && (data = elf_loaddata(scn, &shdr)) == NULL)) {
- fprintf(stderr,
- "Error when obtaining ARM attribute section: %s\n",
- elf_errmsg(-1));
- goto done;
-
- } else if (scn != NULL && data != NULL) {
- GElf_Xword offset = 0;
- uint8_t version;
- if (elf_read_next_u8(data, &offset, &version) < 0) {
- goto done;
- } else if (version != 'A') {
- fprintf(stderr, "Unsupported ARM attribute section "
- "version %d ('%c').\n", version, version);
- goto done;
- }
-
- do {
- const char signature[] = "aeabi";
- /* N.B. LEN is including the length field
- * itself. */
- uint32_t sec_len;
- if (elf_read_u32(data, offset, &sec_len) < 0
- || !elf_can_read_next(data, offset, sec_len)) {
- goto done;
- }
- const GElf_Xword next_offset = offset + sec_len;
- offset += 4;
-
- if (sec_len < 4 + sizeof signature
- || strcmp(signature, data->d_buf + offset) != 0)
- goto skip;
- offset += sizeof signature;
-
- const GElf_Xword offset0 = offset;
- uint64_t tag;
- uint32_t sub_len;
- if (elf_read_next_uleb128(data, &offset, &tag) < 0
- || elf_read_next_u32(data, &offset, &sub_len) < 0
- || !elf_can_read_next(data, offset0, sub_len))
- goto done;
-
- if (tag != 1)
- /* IHI0045D_ABI_addenda: "section and
- * symbol attributes are deprecated
- * [...] consumers are permitted to
- * ignore them." */
- goto skip;
-
- while (offset < offset0 + sub_len) {
- if (elf_read_next_uleb128(data,
- &offset, &tag) < 0)
- goto done;
-
- switch (tag) {
- uint64_t v;
- case 6: /* Tag_CPU_arch */
- case 7: /* Tag_CPU_arch_profile */
- case 8: /* Tag_ARM_ISA_use */
- case 9: /* Tag_THUMB_ISA_use */
- case 10: /* Tag_FP_arch */
- case 11: /* Tag_WMMX_arch */
- case 12: /* Tag_Advanced_SIMD_arch */
- case 13: /* Tag_PCS_config */
- case 14: /* Tag_ABI_PCS_R9_use */
- case 15: /* Tag_ABI_PCS_RW_data */
- case 16: /* Tag_ABI_PCS_RO_data */
- case 17: /* Tag_ABI_PCS_GOT_use */
- case 18: /* Tag_ABI_PCS_wchar_t */
- case 19: /* Tag_ABI_FP_rounding */
- case 20: /* Tag_ABI_FP_denormal */
- case 21: /* Tag_ABI_FP_exceptions */
- case 22: /* Tag_ABI_FP_user_exceptions */
- case 23: /* Tag_ABI_FP_number_model */
- case 24: /* Tag_ABI_align_needed */
- case 25: /* Tag_ABI_align_preserved */
- case 26: /* Tag_ABI_enum_size */
- case 27: /* Tag_ABI_HardFP_use */
- case 28: /* Tag_ABI_VFP_args */
- case 29: /* Tag_ABI_WMMX_args */
- case 30: /* Tag_ABI_optimization_goals */
- case 31: /* Tag_ABI_FP_optimization_goals */
- case 32: /* Tag_compatibility */
- case 34: /* Tag_CPU_unaligned_access */
- case 36: /* Tag_FP_HP_extension */
- case 38: /* Tag_ABI_FP_16bit_format */
- case 42: /* Tag_MPextension_use */
- case 70: /* Tag_MPextension_use as well */
- case 44: /* Tag_DIV_use */
- case 64: /* Tag_nodefaults */
- case 66: /* Tag_T2EE_use */
- case 68: /* Tag_Virtualization_use */
- uleb128:
- if (elf_read_next_uleb128
- (data, &offset, &v) < 0)
- goto done;
- if (tag == 28)
- hardfp = get_hardfp(v);
- if (tag != 32)
- continue;
-
- /* Tag 32 has two arguments,
- * fall through. */
-
- case 4: /* Tag_CPU_raw_name */
- case 5: /* Tag_CPU_name */
- case 65: /* Tag_also_compatible_with */
- case 67: /* Tag_conformance */
- ntbs:
- offset += strlen(data->d_buf
- + offset) + 1;
- continue;
- }
-
- /* Handle unknown tags in a generic
- * manner, if possible. */
- if (tag <= 32) {
- fprintf(stderr,
- "Unknown tag %lld "
- "at offset %#llx "
- "of ARM attribute section.",
- tag, offset);
- goto skip;
- } else if (tag % 2 == 0) {
- goto uleb128;
- } else {
- goto ntbs;
- }
- }
-
- skip:
- offset = next_offset;
-
- } while (elf_can_read_next(data, offset, 1));
-
- }
-
-done:
- lib->arch.hardfp = hardfp;
- return 0;
-}
-
-void
-arch_elf_destroy(struct ltelf *lte)
-{
-}
-
-int
-arch_library_init(struct library *lib)
-{
- return 0;
-}
-
-void
-arch_library_destroy(struct library *lib)
-{
-}
-
-int
-arch_library_clone(struct library *retp, struct library *lib)
-{
- retp->arch = lib->arch;
- return 0;
-}
-
enum {
/* How many (double) VFP registers the AAPCS uses for
* parameter passing. */
diff --git a/sysdeps/linux-gnu/arm/plt.c b/sysdeps/linux-gnu/arm/plt.c
index d1bf7ca..9e9e37f 100644
--- a/sysdeps/linux-gnu/arm/plt.c
+++ b/sysdeps/linux-gnu/arm/plt.c
@@ -1,5 +1,6 @@
/*
* This file is part of ltrace.
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
* Copyright (C) 2010 Zach Welch, CodeSourcery
* Copyright (C) 2004,2008,2009 Juan Cespedes
*
@@ -20,20 +21,205 @@
*/
#include <gelf.h>
+#include <stdio.h>
+#include <string.h>
#include "proc.h"
#include "library.h"
#include "ltrace-elf.h"
static int
+get_hardfp(uint64_t abi_vfp_args)
+{
+ if (abi_vfp_args == 2)
+ fprintf(stderr,
+ "Tag_ABI_VFP_args value 2 (tool chain-specific "
+ "conventions) not supported.\n");
+ return abi_vfp_args == 1;
+}
+
+int
+arch_elf_init(struct ltelf *lte, struct library *lib)
+{
+ GElf_Addr jmprel_addr;
+ Elf_Scn *jmprel_sec;
+ GElf_Shdr jmprel_shdr;
+ if (elf_load_dynamic_entry(lte, DT_JMPREL, &jmprel_addr) < 0
+ || elf_get_section_covering(lte, jmprel_addr,
+ &jmprel_sec, &jmprel_shdr) < 0
+ || jmprel_sec == NULL)
+ return -1;
+
+ lte->arch.jmprel_data = elf_loaddata(jmprel_sec, &jmprel_shdr);
+ if (lte->arch.jmprel_data == NULL)
+ return -1;
+
+ /* Nothing in this section is strictly critical. It's not
+ * that much of a deal if we fail to guess right whether the
+ * ABI is softfp or hardfp. */
+ unsigned hardfp = 0;
+
+ Elf_Scn *scn;
+ Elf_Data *data;
+ GElf_Shdr shdr;
+ if (elf_get_section_type(lte, SHT_ARM_ATTRIBUTES, &scn, &shdr) < 0
+ || (scn != NULL && (data = elf_loaddata(scn, &shdr)) == NULL)) {
+ fprintf(stderr,
+ "Error when obtaining ARM attribute section: %s\n",
+ elf_errmsg(-1));
+ goto done;
+
+ } else if (scn != NULL && data != NULL) {
+ GElf_Xword offset = 0;
+ uint8_t version;
+ if (elf_read_next_u8(data, &offset, &version) < 0) {
+ goto done;
+ } else if (version != 'A') {
+ fprintf(stderr, "Unsupported ARM attribute section "
+ "version %d ('%c').\n", version, version);
+ goto done;
+ }
+
+ do {
+ const char signature[] = "aeabi";
+ /* N.B. LEN is including the length field
+ * itself. */
+ uint32_t sec_len;
+ if (elf_read_u32(data, offset, &sec_len) < 0
+ || !elf_can_read_next(data, offset, sec_len)) {
+ goto done;
+ }
+ const GElf_Xword next_offset = offset + sec_len;
+ offset += 4;
+
+ if (sec_len < 4 + sizeof signature
+ || strcmp(signature, data->d_buf + offset) != 0)
+ goto skip;
+ offset += sizeof signature;
+
+ const GElf_Xword offset0 = offset;
+ uint64_t tag;
+ uint32_t sub_len;
+ if (elf_read_next_uleb128(data, &offset, &tag) < 0
+ || elf_read_next_u32(data, &offset, &sub_len) < 0
+ || !elf_can_read_next(data, offset0, sub_len))
+ goto done;
+
+ if (tag != 1)
+ /* IHI0045D_ABI_addenda: "section and
+ * symbol attributes are deprecated
+ * [...] consumers are permitted to
+ * ignore them." */
+ goto skip;
+
+ while (offset < offset0 + sub_len) {
+ if (elf_read_next_uleb128(data,
+ &offset, &tag) < 0)
+ goto done;
+
+ switch (tag) {
+ uint64_t v;
+ case 6: /* Tag_CPU_arch */
+ case 7: /* Tag_CPU_arch_profile */
+ case 8: /* Tag_ARM_ISA_use */
+ case 9: /* Tag_THUMB_ISA_use */
+ case 10: /* Tag_FP_arch */
+ case 11: /* Tag_WMMX_arch */
+ case 12: /* Tag_Advanced_SIMD_arch */
+ case 13: /* Tag_PCS_config */
+ case 14: /* Tag_ABI_PCS_R9_use */
+ case 15: /* Tag_ABI_PCS_RW_data */
+ case 16: /* Tag_ABI_PCS_RO_data */
+ case 17: /* Tag_ABI_PCS_GOT_use */
+ case 18: /* Tag_ABI_PCS_wchar_t */
+ case 19: /* Tag_ABI_FP_rounding */
+ case 20: /* Tag_ABI_FP_denormal */
+ case 21: /* Tag_ABI_FP_exceptions */
+ case 22: /* Tag_ABI_FP_user_exceptions */
+ case 23: /* Tag_ABI_FP_number_model */
+ case 24: /* Tag_ABI_align_needed */
+ case 25: /* Tag_ABI_align_preserved */
+ case 26: /* Tag_ABI_enum_size */
+ case 27: /* Tag_ABI_HardFP_use */
+ case 28: /* Tag_ABI_VFP_args */
+ case 29: /* Tag_ABI_WMMX_args */
+ case 30: /* Tag_ABI_optimization_goals */
+ case 31: /* Tag_ABI_FP_optimization_goals */
+ case 32: /* Tag_compatibility */
+ case 34: /* Tag_CPU_unaligned_access */
+ case 36: /* Tag_FP_HP_extension */
+ case 38: /* Tag_ABI_FP_16bit_format */
+ case 42: /* Tag_MPextension_use */
+ case 70: /* Tag_MPextension_use as well */
+ case 44: /* Tag_DIV_use */
+ case 64: /* Tag_nodefaults */
+ case 66: /* Tag_T2EE_use */
+ case 68: /* Tag_Virtualization_use */
+ uleb128:
+ if (elf_read_next_uleb128
+ (data, &offset, &v) < 0)
+ goto done;
+ if (tag == 28)
+ hardfp = get_hardfp(v);
+ if (tag != 32)
+ continue;
+
+ /* Tag 32 has two arguments,
+ * fall through. */
+
+ case 4: /* Tag_CPU_raw_name */
+ case 5: /* Tag_CPU_name */
+ case 65: /* Tag_also_compatible_with */
+ case 67: /* Tag_conformance */
+ ntbs:
+ offset += strlen(data->d_buf
+ + offset) + 1;
+ continue;
+ }
+
+ /* Handle unknown tags in a generic
+ * manner, if possible. */
+ if (tag <= 32) {
+ fprintf(stderr,
+ "Unknown tag %lld "
+ "at offset %#llx "
+ "of ARM attribute section.",
+ tag, offset);
+ goto skip;
+ } else if (tag % 2 == 0) {
+ goto uleb128;
+ } else {
+ goto ntbs;
+ }
+ }
+
+ skip:
+ offset = next_offset;
+
+ } while (elf_can_read_next(data, offset, 1));
+
+ }
+
+done:
+ lib->arch.hardfp = hardfp;
+ return 0;
+}
+
+void
+arch_elf_destroy(struct ltelf *lte)
+{
+}
+
+static int
arch_plt_entry_has_stub(struct ltelf *lte, size_t off) {
- uint16_t op = *(uint16_t *)((char *)lte->relplt->d_buf + off);
+ char *buf = (char *) lte->arch.jmprel_data->d_buf;
+ uint16_t op = *(uint16_t *) (buf + off);
return op == 0x4778;
}
GElf_Addr
arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
- size_t start = lte->relplt->d_size + 12;
+ size_t start = lte->arch.jmprel_data->d_size + 12;
size_t off = start + 20, i;
for (i = 0; i < ndx; i++)
off += arch_plt_entry_has_stub(lte, off) ? 16 : 12;
@@ -47,3 +233,21 @@ sym2addr(struct process *proc, struct library_symbol *sym)
{
return sym->enter_addr;
}
+
+int
+arch_library_init(struct library *lib)
+{
+ return 0;
+}
+
+void
+arch_library_destroy(struct library *lib)
+{
+}
+
+int
+arch_library_clone(struct library *retp, struct library *lib)
+{
+ retp->arch = lib->arch;
+ return 0;
+}
diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
index 5e3ffe1..3ec1397 100644
--- a/sysdeps/linux-gnu/ppc/plt.c
+++ b/sysdeps/linux-gnu/ppc/plt.c
@@ -402,38 +402,6 @@ get_glink_vma(struct ltelf *lte, GElf_Addr ppcgot, Elf_Data *plt_data)
}
static int
-load_dynamic_entry(struct ltelf *lte, int tag, GElf_Addr *valuep)
-{
- Elf_Scn *scn;
- GElf_Shdr shdr;
- if (elf_get_section_type(lte, SHT_DYNAMIC, &scn, &shdr) < 0
- || scn == NULL) {
- fail:
- fprintf(stderr, "Couldn't get SHT_DYNAMIC: %s\n",
- elf_errmsg(-1));
- return -1;
- }
-
- Elf_Data *data = elf_loaddata(scn, &shdr);
- if (data == NULL)
- goto fail;
-
- size_t j;
- for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) {
- GElf_Dyn dyn;
- if (gelf_getdyn(data, j, &dyn) == NULL)
- goto fail;
-
- if(dyn.d_tag == tag) {
- *valuep = dyn.d_un.d_ptr;
- return 0;
- }
- }
-
- return -1;
-}
-
-static int
nonzero_data(Elf_Data *data)
{
/* We are not supposed to get here if there's no PLT. */
@@ -488,8 +456,8 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
Elf_Scn *rela_sec;
GElf_Shdr rela_shdr;
if ((lte->ehdr.e_machine == EM_PPC64 || lte->arch.secure_plt)
- && load_dynamic_entry(lte, DT_RELA, &rela) == 0
- && load_dynamic_entry(lte, DT_RELASZ, &relasz) == 0
+ && elf_load_dynamic_entry(lte, DT_RELA, &rela) == 0
+ && elf_load_dynamic_entry(lte, DT_RELASZ, &relasz) == 0
&& elf_get_section_covering(lte, rela, &rela_sec, &rela_shdr) == 0
&& rela_sec != NULL) {
@@ -509,7 +477,7 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
if (lte->ehdr.e_machine == EM_PPC && lte->arch.secure_plt) {
GElf_Addr ppcgot;
- if (load_dynamic_entry(lte, DT_PPC_GOT, &ppcgot) < 0) {
+ if (elf_load_dynamic_entry(lte, DT_PPC_GOT, &ppcgot) < 0) {
fprintf(stderr, "couldn't find DT_PPC_GOT\n");
return -1;
}
@@ -522,7 +490,8 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
} else if (lte->ehdr.e_machine == EM_PPC64) {
GElf_Addr glink_vma;
- if (load_dynamic_entry(lte, DT_PPC64_GLINK, &glink_vma) < 0) {
+ if (elf_load_dynamic_entry(lte, DT_PPC64_GLINK,
+ &glink_vma) < 0) {
fprintf(stderr, "couldn't find DT_PPC64_GLINK\n");
return -1;
}
@@ -532,8 +501,8 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
} else {
/* By exhaustion--PPC32 BSS. */
- if (load_dynamic_entry(lte, DT_PLTGOT,
- &lib->arch.pltgot_addr) < 0) {
+ if (elf_load_dynamic_entry(lte, DT_PLTGOT,
+ &lib->arch.pltgot_addr) < 0) {
fprintf(stderr, "couldn't find DT_PLTGOT\n");
return -1;
}

@ -0,0 +1,81 @@
From 56134ff5442bee4e128b189bb86cfc97dcb6f60a Mon Sep 17 00:00:00 2001
From: Petr Machata <pmachata@redhat.com>
Date: Fri, 10 Jan 2014 20:05:15 +0100
Subject: [PATCH 1/2] Add a new per-breakpoint callback on_install
---
breakpoint.h | 9 ++++++++-
breakpoints.c | 11 ++++++++++-
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/breakpoint.h b/breakpoint.h
index 95964a8..c36f673 100644
--- a/breakpoint.h
+++ b/breakpoint.h
@@ -1,6 +1,6 @@
/*
* This file is part of ltrace.
- * Copyright (C) 2012, 2013 Petr Machata, Red Hat Inc.
+ * Copyright (C) 2012,2013,2014 Petr Machata, Red Hat Inc.
* Copyright (C) 2009 Juan Cespedes
*
* This program is free software; you can redistribute it and/or
@@ -46,6 +46,7 @@
struct bp_callbacks {
void (*on_hit)(struct breakpoint *bp, struct process *proc);
void (*on_continue)(struct breakpoint *bp, struct process *proc);
+ void (*on_install)(struct breakpoint *bp, struct process *proc);
void (*on_retract)(struct breakpoint *bp, struct process *proc);
/* Create a new breakpoint that should handle return from the
@@ -84,6 +85,12 @@ void breakpoint_on_continue(struct breakpoint *bp, struct process *proc);
* the instruction underneath it). */
void breakpoint_on_retract(struct breakpoint *bp, struct process *proc);
+/* Call ON_INSTALL handler of BP, if any is set. This should be
+ * called after the breakpoint is enabled for the first time, not
+ * every time it's enabled (such as after stepping over a site of a
+ * temporarily disabled breakpoint). */
+void breakpoint_on_install(struct breakpoint *bp, struct process *proc);
+
/* Call GET_RETURN_BP handler of BP, if any is set. If none is set,
* call CREATE_DEFAULT_RETURN_BP to obtain one. */
int breakpoint_get_return_bp(struct breakpoint **ret,
diff --git a/breakpoints.c b/breakpoints.c
index 947cb71..c3fa275 100644
--- a/breakpoints.c
+++ b/breakpoints.c
@@ -1,6 +1,6 @@
/*
* This file is part of ltrace.
- * Copyright (C) 2006,2007,2011,2012,2013 Petr Machata, Red Hat Inc.
+ * Copyright (C) 2006,2007,2011,2012,2013,2014 Petr Machata, Red Hat Inc.
* Copyright (C) 2009 Juan Cespedes
* Copyright (C) 1998,2001,2002,2003,2007,2008,2009 Juan Cespedes
* Copyright (C) 2006 Ian Wienand
@@ -85,6 +85,14 @@ breakpoint_on_retract(struct breakpoint *bp, struct process *proc)
(bp->cbs->on_retract)(bp, proc);
}
+void
+breakpoint_on_install(struct breakpoint *bp, struct process *proc)
+{
+ assert(bp != NULL);
+ if (bp->cbs != NULL && bp->cbs->on_install != NULL)
+ (bp->cbs->on_install)(bp, proc);
+}
+
int
breakpoint_get_return_bp(struct breakpoint **ret,
struct breakpoint *bp, struct process *proc)
@@ -229,6 +237,7 @@ breakpoint_turn_on(struct breakpoint *bp, struct process *proc)
if (bp->enabled == 1) {
assert(proc->pid != 0);
enable_breakpoint(proc, bp);
+ breakpoint_on_install(bp, proc);
}
return 0;
}
--
1.7.6.5

@ -0,0 +1,36 @@
diff -urp ltrace-0.7.91/libltrace.c master/libltrace.c
--- ltrace-0.7.91/libltrace.c 2014-01-14 16:31:37.696174464 +0100
+++ master/libltrace.c 2013-11-21 14:06:38.623701688 +0100
@@ -113,9 +117,13 @@ ltrace_init(int argc, char **argv) {
if (command) {
/* Check that the binary ABI is supported before
* calling execute_program. */
- struct ltelf lte;
- ltelf_init(&lte, command);
- ltelf_destroy(&lte);
+ {
+ struct ltelf lte;
+ if (ltelf_init(&lte, command) == 0)
+ ltelf_destroy(&lte);
+ else
+ exit(EXIT_FAILURE);
+ }
pid_t pid = execute_program(command, argv);
struct process *proc = open_program(command, pid);
diff -urp ltrace-0.7.91/ltrace-elf.c master/ltrace-elf.c
--- ltrace-0.7.91/ltrace-elf.c 2014-01-14 16:31:37.688174420 +0100
+++ master/ltrace-elf.c 2013-11-22 18:17:11.767721609 +0100
@@ -361,8 +361,11 @@ ltelf_init(struct ltelf *lte, const char
{
memset(lte, 0, sizeof *lte);
lte->fd = open(filename, O_RDONLY);
- if (lte->fd == -1)
+ if (lte->fd == -1) {
+ fprintf(stderr, "Can't open %s: %s\n", filename,
+ strerror(errno));
return 1;
+ }
elf_version(EV_CURRENT);

@ -0,0 +1,121 @@
diff -rup a/ltrace-elf.c b/ltrace-elf.c
--- a/ltrace-elf.c 2019-02-28 17:32:49.873659818 -0500
+++ b/ltrace-elf.c 2019-02-28 17:36:32.426779439 -0500
@@ -639,7 +639,21 @@ ltelf_read_elf(struct ltelf *lte, const
}
} else if (shdr.sh_type == SHT_PROGBITS
|| shdr.sh_type == SHT_NOBITS) {
- if (strcmp(name, ".plt") == 0) {
+ if (strcmp(name, ".plt") == 0
+ && lte->second_plt_seen == 0) {
+ lte->plt_addr = shdr.sh_addr;
+ lte->plt_size = shdr.sh_size;
+ lte->plt_data = elf_loaddata(scn, &shdr);
+ if (lte->plt_data == NULL)
+ fprintf(stderr,
+ "Can't load .plt data\n");
+ lte->plt_flags = shdr.sh_flags;
+ }
+ /* An Intel CET binary has two PLTs; the
+ initial PLTGOT points to the second
+ one. */
+ else if (strcmp(name, ".plt.sec") == 0) {
+ lte->second_plt_seen = 1;
lte->plt_addr = shdr.sh_addr;
lte->plt_size = shdr.sh_size;
lte->plt_data = elf_loaddata(scn, &shdr);
diff -rup a/ltrace-elf.h b/ltrace-elf.h
--- a/ltrace-elf.h 2019-02-28 17:32:49.874660328 -0500
+++ b/ltrace-elf.h 2019-02-28 17:36:32.428779868 -0500
@@ -45,6 +45,7 @@ struct ltelf {
Elf_Data *dynsym;
size_t dynsym_count;
const char *dynstr;
+ int second_plt_seen;
GElf_Addr plt_addr;
GElf_Word plt_flags;
size_t plt_size;
diff -rup a/sysdeps/linux-gnu/x86/plt.c b/sysdeps/linux-gnu/x86/plt.c
--- a/sysdeps/linux-gnu/x86/plt.c 2019-02-28 17:32:49.991720041 -0500
+++ b/sysdeps/linux-gnu/x86/plt.c 2019-02-28 17:36:32.429780083 -0500
@@ -28,18 +28,18 @@
#include "trace.h"
static GElf_Addr
-x86_plt_offset(uint32_t i)
+x86_plt_offset(struct ltelf *lte, uint32_t i)
{
/* Skip the first PLT entry, which contains a stub to call the
* resolver. */
- return (i + 1) * 16;
+ return (i + (lte->second_plt_seen ? 0 : 1)) * 16;
}
GElf_Addr
arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela)
{
uint32_t i = *VECT_ELEMENT(&lte->arch.plt_map, uint32_t, ndx);
- return x86_plt_offset(i) + lte->plt_addr;
+ return x86_plt_offset(lte, i) + lte->plt_addr;
}
void *
@@ -116,6 +116,13 @@ arch_elf_init(struct ltelf *lte, struct
* 400426: 68 00 00 00 00 pushq $0x0
* 40042b: e9 e0 ff ff ff jmpq 400410 <_init+0x18>
*
+ * For CET binaries it is the following:
+ *
+ * 13d0: f3 0f 1e fa endbr64
+ * 13d4: 68 27 00 00 00 pushq $0x27 <-- index
+ * 13d9: f2 e9 71 fd ff ff bnd jmpq 1150 <.plt>
+ * 13df: 90 nop
+ *
* On i386, the argument to push is an offset of relocation to
* use. The first PLT slot has an offset of 0x0, the second
* 0x8, etc. On x86_64, it's directly the index that we are
@@ -128,11 +135,33 @@ arch_elf_init(struct ltelf *lte, struct
unsigned int i, sz = vect_size(&lte->plt_relocs);
for (i = 0; i < sz; ++i) {
- GElf_Addr offset = x86_plt_offset(i);
+ GElf_Addr offset = x86_plt_offset(lte, i);
+ uint32_t reloc_arg;
uint8_t byte;
- if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
- || byte != 0xff
+ if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0)
+ continue;
+
+
+ if (byte == 0xf3
+ && elf_read_next_u8(lte->plt_data, &offset, &byte) >= 0
+ && byte == 0x0f
+ && elf_read_next_u8(lte->plt_data, &offset, &byte) >= 0
+ && byte == 0x1e
+ && elf_read_next_u8(lte->plt_data, &offset, &byte) >= 0
+ && byte == 0xfa
+ && elf_read_next_u8(lte->plt_data, &offset, &byte) >= 0
+ && byte == 0x68
+ && elf_read_next_u32(lte->plt_data,
+ &offset, &reloc_arg) >= 0)
+ {
+ /* CET */
+ fprintf(stderr, "%d: reloc_arg is %lx\n", i, (long)reloc_arg);
+ *VECT_ELEMENT(&lte->arch.plt_map, unsigned int, reloc_arg) = i;
+ continue;
+ }
+
+ if (byte != 0xff
|| elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
|| (byte != 0xa3 && byte != 0x25))
continue;
@@ -140,7 +169,6 @@ arch_elf_init(struct ltelf *lte, struct
/* Skip immediate argument in the instruction. */
offset += 4;
- uint32_t reloc_arg;
if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
|| byte != 0x68
|| elf_read_next_u32(lte->plt_data,

@ -0,0 +1,45 @@
diff -up ltrace-0.7.91/options.c\~ ltrace-0.7.91/options.c
--- ltrace-0.7.91/options.c~ 2013-10-22 11:54:21.000000000 +0200
+++ ltrace-0.7.91/options.c 2014-01-13 15:38:51.362221740 +0100
@@ -128,6 +128,8 @@ usage_debug(void) {
"\n"
"Debugging options are mixed using bitwise-or.\n"
"Note that the meanings and values are subject to change.\n"
+ "Also note that these values are used inconsistently in ltrace, and the\n"
+ "only debuglevel that you can rely on is -D77 that will show everything.\n"
);
}
diff -up ltrace-0.7.91/ltrace.1\~ ltrace-0.7.91/ltrace.1
--- ltrace-0.7.91/ltrace.1~ 2013-10-23 17:44:13.000000000 +0200
+++ ltrace-0.7.91/ltrace.1 2014-01-13 15:51:24.236730677 +0100
@@ -1,5 +1,5 @@
.\" -*-nroff-*-
-.\" Copyright (c) 2012, 2013 Petr Machata, Red Hat Inc.
+.\" Copyright (c) 2012,2013,2014 Petr Machata, Red Hat Inc.
.\" Copyright (c) 1997-2005 Juan Cespedes <cespedes@debian.org>
.\"
.\" This program is free software; you can redistribute it and/or
@@ -118,9 +118,9 @@ Besides removing any initial underscore
this makes C++ function names readable.
.IP "\-D, \-\-debug \fRmask\fI"
Show debugging output of \fBltrace\fR itself. \fImask\fR is a number
-with internal meaning that's not really well defined at all.
-\fImask\fR of 77 shows all debug messages, which is what you usually
-need.
+describing which debug messages should be displayed. Use the option
+\-Dh to see what can be used, but note that currently the only
+reliable debugmask is 77, which shows all debug messages.
.IP "\-e \fIfilter"
A qualifying expression which modifies which library calls to trace.
The format of the filter expression is described in the section
@@ -156,7 +156,8 @@ dependency ordering. If you want to mak
library are actually called, use \fB-x @\fIlibrary_pattern\fR instead.
.IP \-L
When no -e option is given, don't assume the default action of
-\fB@MAIN\fR.
+\fB@MAIN\fR. In practice this means that library calls will not be
+traced.
.IP "\-n, \-\-indent \fInr"
Indent trace output by \fInr\fR spaces for each level of call
nesting. Using this option makes the program flow visualization easy

@ -0,0 +1,175 @@
From 4724bd5a4a19db117a1d280b9d1a3508fd4e03fa Mon Sep 17 00:00:00 2001
From: Petr Machata <pmachata@redhat.com>
Date: Wed, 8 Apr 2015 07:11:52 -0400
Subject: [PATCH 1/2] Convert main-threaded test case to new style
---
testsuite/ltrace.main/Makefile.am | 4 +-
testsuite/ltrace.main/main-threaded.c | 30 ----------
testsuite/ltrace.main/main-threaded.exp | 103 ++++++++++++++++++++------------
3 files changed, 66 insertions(+), 71 deletions(-)
delete mode 100644 testsuite/ltrace.main/main-threaded.c
diff --git a/testsuite/ltrace.main/Makefile.am b/testsuite/ltrace.main/Makefile.am
index 23ab8ab..06ad613 100644
--- a/testsuite/ltrace.main/Makefile.am
+++ b/testsuite/ltrace.main/Makefile.am
@@ -1,4 +1,4 @@
-# Copyright (C) 1992 - 2001, 2012, 2013 Free Software Foundation, Inc.
+# Copyright (C) 1992 - 2001, 2012, 2013, 2015 Free Software Foundation, 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
@@ -17,7 +17,7 @@
EXTRA_DIST = branch_func.c branch_func.exp filters.exp hello-vfork.c \
hello-vfork.exp main.c main.exp main-internal.exp main-lib.c \
- main-threaded.c main-threaded.exp main-vfork.c main-vfork.exp \
+ main-threaded.exp main-vfork.c main-vfork.exp \
parameters.c parameters.conf parameters.exp parameters-lib.c \
parameters2.exp parameters3.exp signals.c signals.exp \
system_calls.c system_calls.exp system_call_params.exp
diff --git a/testsuite/ltrace.main/main-threaded.c b/testsuite/ltrace.main/main-threaded.c
deleted file mode 100644
index 2992d1e..0000000
--- a/testsuite/ltrace.main/main-threaded.c
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <pthread.h>
-
-extern void print (char *);
-
-#define PRINT_LOOP 10
-
-void *
-th_main (void *arg)
-{
- int i;
- for (i=0; i<PRINT_LOOP; i++)
- print (arg);
-}
-
-int
-main ()
-{
- pthread_t thread1;
- pthread_t thread2;
- pthread_t thread3;
- pthread_create (&thread1, NULL, th_main, "aaa");
- pthread_create (&thread2, NULL, th_main, "bbb");
- pthread_create (&thread3, NULL, th_main, "ccc");
- pthread_join (thread1, NULL);
- pthread_join (thread2, NULL);
- pthread_join (thread3, NULL);
- return 0;
-}
-
diff --git a/testsuite/ltrace.main/main-threaded.exp b/testsuite/ltrace.main/main-threaded.exp
index 4d5f478..cead82d 100644
--- a/testsuite/ltrace.main/main-threaded.exp
+++ b/testsuite/ltrace.main/main-threaded.exp
@@ -1,39 +1,64 @@
-# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+# This file is part of ltrace.
+# Copyright (C) 2011, 2015 Petr Machata, Red Hat Inc.
+# Copyright (C) 2006 Yao Qi <qiyao@cn.ibm.com>.
+#
+# 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 libprint [ltraceCompile libprint.so [ltraceSource c {
+ #include<stdio.h>
+
+ void
+ print(char* s)
+ {
+ printf("%s\n",s);
+ }
+}]]
+
+set bin [ltraceCompile {} $libprint -lpthread [ltraceSource c {
+ #include <pthread.h>
+
+ extern void print (char *);
+
+ #define PRINT_LOOP 10
+
+ void *
+ th_main (void *arg)
+ {
+ int i;
+ for (i=0; i<PRINT_LOOP; i++)
+ print (arg);
+ return NULL;
+ }
+
+ int
+ main (void)
+ {
+ pthread_t thread1;
+ pthread_t thread2;
+ pthread_t thread3;
+ pthread_create (&thread1, NULL, th_main, "aaa");
+ pthread_create (&thread2, NULL, th_main, "bbb");
+ pthread_create (&thread3, NULL, th_main, "ccc");
+ pthread_join (thread1, NULL);
+ pthread_join (thread2, NULL);
+ pthread_join (thread3, NULL);
+ return 0;
+ }
+}]]
-set testfile "main-threaded"
-set srcfile ${testfile}.c
-set binfile ${testfile}
-set libfile "main-lib"
-set libsrc $srcdir/$subdir/$libfile.c
-set lib_sl $objdir/$subdir/lib$testfile.so
-
-
-if [get_compiler_info $binfile] {
- return -1
-}
-
-verbose "compiling source file now....."
-if { [ltrace_compile_shlib $libsrc $lib_sl debug ] != ""
- || [ltrace_compile $srcdir/$subdir/$srcfile $objdir/$subdir/$binfile executable [list debug shlib=$lib_sl ldflags=-pthread] ] != ""} {
- send_user "Testcase compile failed, so all tests in this file will automatically fail.\n"
-}
-
-# set options for ltrace.
-ltrace_options "-l" "lib$testfile.so" "-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-threaded.ltrace.
-set pattern "print"
-ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 30
+ltraceMatch1 [ltraceRun -f -l libprint.so -- $bin] {print\(} == 30
+
+ltraceDone
Only in ltrace.main: main-threaded.exp~
Only in ltrace.main: .main-threaded.exp.~undo-tree~

@ -0,0 +1,50 @@
From 72ee29639c55b5942bc07c8ed0013005f8fc5a97 Mon Sep 17 00:00:00 2001
From: Petr Machata <pmachata@redhat.com>
Date: Wed, 8 Apr 2015 07:14:10 -0400
Subject: [PATCH 2/2] Fix tracing multi-threaded processes without -f
- In handle_syscall, we avoid touching stack of ignored processes.
But in handle_sysret, we require a sysret-like stack entry even
for ignored processes, even though we then go ahead to not act
on that stack entry. Instead, for ignored processes, avoid looking
at stack trace at all.
---
handle_event.c | 10 +++++-----
testsuite/ltrace.main/main-threaded.exp | 1 +
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/handle_event.c b/handle_event.c
index 6fa7e98..c2550ad 100644
--- a/handle_event.c
+++ b/handle_event.c
@@ -619,12 +619,12 @@ handle_x_sysret(Event *event, char *(*name_cb)(struct process *, int))
debug(DEBUG_FUNCTION, "handle_x_sysret(pid=%d, sysnum=%d)",
event->proc->pid, event->e_un.sysnum);
- unsigned d = event->proc->callstack_depth;
- assert(d > 0);
- struct callstack_element *elem = &event->proc->callstack[d - 1];
- assert(elem->is_syscall);
-
if (event->proc->state != STATE_IGNORED) {
+ unsigned d = event->proc->callstack_depth;
+ assert(d > 0);
+ struct callstack_element *elem = &event->proc->callstack[d - 1];
+ assert(elem->is_syscall);
+
struct timedelta spent = calc_time_spent(elem->enter_time);
if (options.syscalls)
output_syscall_right(event->proc,
diff --git a/testsuite/ltrace.main/main-threaded.exp b/testsuite/ltrace.main/main-threaded.exp
index cead82d..aca7afd 100644
--- a/testsuite/ltrace.main/main-threaded.exp
+++ b/testsuite/ltrace.main/main-threaded.exp
@@ -60,5 +60,6 @@ set bin [ltraceCompile {} $libprint -lpthread [ltraceSource c {
}]]
ltraceMatch1 [ltraceRun -f -l libprint.so -- $bin] {print\(} == 30
+ltraceMatch1 [ltraceRun -L -- $bin] exited == 1
ltraceDone
--
2.1.0

@ -0,0 +1,14 @@
diff --git a/output.c b/output.c
index 7cab383..18f9cf0 100644
--- a/output.c
+++ b/output.c
@@ -598,6 +598,9 @@ frame_callback (Dwfl_Frame *state, void *arg)
NULL, NULL, NULL);
symname = dwfl_module_addrinfo(mod, pc, &off, &sym,
NULL, NULL, NULL);
+ } else {
+ modname = "unknown";
+ symname = "unknown";
}
/* This mimics the output produced by libunwind below. */

@ -0,0 +1,144 @@
From 2e9f9f1f5d0fb223b109429b9c904504b7f638e2 Mon Sep 17 00:00:00 2001
From: Petr Machata <pmachata@redhat.com>
Date: Fri, 8 Aug 2014 16:53:41 +0200
Subject: [PATCH] In config files, allow whitespace between identifier and
opening paren
---
read_config_file.c | 61 ++++++--------------------------
testsuite/ltrace.main/parameters2.exp | 14 +++++++-
2 files changed, 25 insertions(+), 50 deletions(-)
diff --git a/read_config_file.c b/read_config_file.c
index ea3ab88..05ff283 100644
--- a/read_config_file.c
+++ b/read_config_file.c
@@ -1,6 +1,6 @@
/*
* This file is part of ltrace.
- * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
+ * Copyright (C) 2011,2012,2013,2014 Petr Machata, Red Hat Inc.
* Copyright (C) 1998,1999,2003,2007,2008,2009 Juan Cespedes
* Copyright (C) 2006 Ian Wienand
* Copyright (C) 2006 Steve Fink
@@ -168,38 +168,6 @@ parse_ident(struct locus *loc, char **str)
return xstrndup(ident, *str - ident);
}
-/*
- Returns position in string at the left parenthesis which starts the
- function's argument signature. Returns NULL on error.
-*/
-static char *
-start_of_arg_sig(char *str) {
- char *pos;
- int stacked = 0;
-
- if (!strlen(str))
- return NULL;
-
- pos = &str[strlen(str)];
- do {
- pos--;
- if (pos < str)
- return NULL;
- while ((pos > str) && (*pos != ')') && (*pos != '('))
- pos--;
-
- if (*pos == ')')
- stacked++;
- else if (*pos == '(')
- stacked--;
- else
- return NULL;
-
- } while (stacked > 0);
-
- return (stacked == 0) ? pos : NULL;
-}
-
static int
parse_int(struct locus *loc, char **str, long *ret)
{
@@ -1110,7 +1078,6 @@ static int
process_line(struct protolib *plib, struct locus *loc, char *buf)
{
char *str = buf;
- char *tmp;
debug(3, "Reading line %d of `%s'", loc->line_no, loc->filename);
eat_spaces(&str);
@@ -1148,22 +1115,13 @@ process_line(struct protolib *plib, struct locus *loc, char *buf)
debug(4, " return_type = %d", fun.return_info->type);
eat_spaces(&str);
- tmp = start_of_arg_sig(str);
- if (tmp == NULL) {
- report_error(loc->filename, loc->line_no, "syntax error");
+ proto_name = parse_ident(loc, &str);
+ if (proto_name == NULL)
goto err;
- }
- *tmp = '\0';
- proto_name = strdup(str);
- if (proto_name == NULL) {
- oom:
- report_error(loc->filename, loc->line_no,
- "%s", strerror(errno));
+ eat_spaces(&str);
+ if (parse_char(loc, &str, '(') < 0)
goto err;
- }
-
- str = tmp + 1;
debug(3, " name = %s", proto_name);
struct param *extra_param = NULL;
@@ -1177,8 +1135,13 @@ process_line(struct protolib *plib, struct locus *loc, char *buf)
if (have_stop == 0) {
struct param param;
param_init_stop(&param);
- if (prototype_push_param(&fun, &param) < 0)
- goto oom;
+ if (prototype_push_param(&fun, &param) < 0) {
+ oom:
+ report_error(loc->filename,
+ loc->line_no,
+ "%s", strerror(errno));
+ goto err;
+ }
have_stop = 1;
}
str++;
diff --git a/testsuite/ltrace.main/parameters2.exp b/testsuite/ltrace.main/parameters2.exp
index 6318fc5..9850079 100644
--- a/testsuite/ltrace.main/parameters2.exp
+++ b/testsuite/ltrace.main/parameters2.exp
@@ -1,5 +1,5 @@
# This file is part of ltrace.
-# Copyright (C) 2012, 2013 Petr Machata, Red Hat Inc.
+# Copyright (C) 2012, 2013, 2014 Petr Machata, Red Hat Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
@@ -259,4 +259,16 @@ ltraceMatch1 [ltraceLibTest {
somefunc();
}] {somefunc\(\) *= nil} == 1
+# Test that spaces in function name make no difference.
+
+ltraceMatch1 [ltraceLibTest {
+ void somefunc ();
+} {
+ void somefunc(void);
+} {
+ void somefunc(void) {}
+} {
+ somefunc();
+}] {somefunc\(\)} == 1
+
ltraceDone
--
1.7.6.5

@ -0,0 +1,91 @@
diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
index 45ed7fb..5f81889 100644
--- a/sysdeps/linux-gnu/ppc/plt.c
+++ b/sysdeps/linux-gnu/ppc/plt.c
@@ -274,14 +274,15 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela)
assert(rela->r_addend != 0);
/* XXX double cast */
- arch_addr_t res_addr = (arch_addr_t) (uintptr_t) rela->r_addend;
+ arch_addr_t res_addr
+ = (arch_addr_t) (uintptr_t) (rela->r_addend + lte->bias);
if (arch_translate_address(lte, res_addr, &res_addr) < 0) {
fprintf(stderr, "Couldn't OPD-translate IRELATIVE "
"resolver address.\n");
return 0;
}
/* XXX double cast */
- return (GElf_Addr) (uintptr_t) res_addr;
+ return (GElf_Addr) (uintptr_t) (res_addr - lte->bias);
} else {
/* We put brakpoints to PLT entries the same as the
@@ -453,7 +454,7 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
#ifndef EF_PPC64_ABI
assert (! (lte->ehdr.e_flags & 3 ) == 2)
#else
- lte->arch.elfv2_abi=((lte->ehdr.e_flags & EF_PPC64_ABI) == 2) ;
+ lte->arch.elfv2_abi = ((lte->ehdr.e_flags & EF_PPC64_ABI) == 2);
#endif
if (lte->ehdr.e_machine == EM_PPC64
@@ -827,15 +828,15 @@ arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
assert(plt_slot_addr >= lte->plt_addr
|| plt_slot_addr < lte->plt_addr + lte->plt_size);
+ plt_entry_addr += lte->bias;
+ plt_slot_addr += lte->bias;
+
/* Should avoid to do read if dynamic linker hasn't run yet
* or allow -1 a valid return code. */
GElf_Addr plt_slot_value;
- if (read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value) < 0) {
- if (!lte->arch.elfv2_abi)
- goto fail;
- else
- return PPC_PLT_UNRESOLVED;
- }
+ int rc = read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value);
+ if (rc < 0 && !lte->arch.elfv2_abi)
+ goto fail;
struct library_symbol *libsym = malloc(sizeof(*libsym));
if (libsym == NULL) {
@@ -854,8 +855,9 @@ arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
goto fail2;
libsym->arch.plt_slot_addr = plt_slot_addr;
- if (! is_irelative
- && (plt_slot_value == plt_entry_addr || plt_slot_value == 0)) {
+ if (rc < 0 || (! is_irelative
+ && (plt_slot_value == plt_entry_addr
+ || plt_slot_value == 0))) {
libsym->arch.type = PPC_PLT_UNRESOLVED;
libsym->arch.resolved_value = plt_entry_addr;
} else {
@@ -1166,8 +1168,8 @@ ppc_plt_bp_install(struct breakpoint *bp, struct process *proc)
libsym->arch.resolved_value = plt_entry_addr;
}
} else {
- fprintf(stderr, "Couldn't unresolve %s@%p. Not tracing"
- " this symbol.\n",
+ fprintf(stderr, "Couldn't unresolve %s@%p. Will not"
+ " trace this symbol.\n",
breakpoint_name(bp), bp->addr);
proc_remove_breakpoint(proc, bp);
}
@@ -1222,6 +1224,14 @@ arch_library_symbol_clone(struct library_symbol *retp,
struct library_symbol *libsym)
{
retp->arch = libsym->arch;
+ if (libsym->arch.type == PPC_PLT_NEED_UNRESOLVE) {
+ assert(libsym->arch.data->self == libsym->arch.data);
+ retp->arch.data = malloc(sizeof *retp->arch.data);
+ if (retp->arch.data == NULL)
+ return -1;
+ *retp->arch.data = *libsym->arch.data;
+ retp->arch.data->self = retp->arch.data;
+ }
return 0;
}

@ -0,0 +1,52 @@
From 35742523e3daa0e59de0c1c3fdd8e5ff52891967 Mon Sep 17 00:00:00 2001
From: Petr Machata <pmachata@redhat.com>
Date: Thu, 9 Jan 2014 23:41:50 +0100
Subject: [PATCH] Fix a problem in tracing across fork on PPC64
In order to avoid single-stepping through large portions of the
dynamic linker, ltrace remembers at which address the instruction that
resolved a PLT slot is. It then puts a breakpoint to this address so
that it can fast-forward to that address next time it needs to catch a
PLT slot being resolved.
When a process is cloned, the pointer to this breakpoint is simply
copied over to the new process, instead of being looked up in the new
process structures. This patches fixes this.
---
sysdeps/linux-gnu/ppc/plt.c | 14 +++++++++++++-
1 files changed, 13 insertions(+), 1 deletions(-)
diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
index 3ec1397..8715da6 100644
--- a/sysdeps/linux-gnu/ppc/plt.c
+++ b/sysdeps/linux-gnu/ppc/plt.c
@@ -1,6 +1,6 @@
/*
* This file is part of ltrace.
- * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
+ * Copyright (C) 2012,2013,2014 Petr Machata, Red Hat Inc.
* Copyright (C) 2004,2008,2009 Juan Cespedes
* Copyright (C) 2006 Paul Gilliam
*
@@ -1157,6 +1157,18 @@ int
arch_process_clone(struct process *retp, struct process *proc)
{
retp->arch = proc->arch;
+
+ if (retp->arch.dl_plt_update_bp != NULL) {
+ /* Point it to the corresponding breakpoint in RETP.
+ * It must be there, this part of PROC has already
+ * been cloned to RETP. */
+ retp->arch.dl_plt_update_bp
+ = address2bpstruct(retp,
+ retp->arch.dl_plt_update_bp->addr);
+
+ assert(retp->arch.dl_plt_update_bp != NULL);
+ }
+
return 0;
}
--
1.7.6.5

@ -0,0 +1,221 @@
From a0093ca43cf40d7e5f6cebeb64156062d2de46d9 Mon Sep 17 00:00:00 2001
From: Petr Machata <pmachata@redhat.com>
Date: Fri, 10 Jan 2014 20:06:51 +0100
Subject: [PATCH 2/2] Don't crash untraced calls via PLT in prelinked PPC64
binaries
In prelinked binaries, ltrace has to unprelinks PLT slots in order to
catch calls done through PLT. This makes the calls done through these
slots invalid, because the special first PLT slot is not initialized,
and dynamic linker SIGSEGVs because of this. Ltrace relies on
arranging breakpoints such that the dynamic linker is not actually
entered, and moves PC around itself to simulate the effects of a call
through PLT.
Originally, arch_elf_add_plt_entry was called only for symbols that
were actually traced. Later this was changed and it's now called for
all PLT entries, and the resulting candidate list is filtered
afterwards. This gives backends a chance to rename the symbol, as is
useful with IRELATIVE PLT calls, where symbol name may not be
available at all. But the PPC backend was never updated to reflect
this, and unresolved all symbols for which arch_elf_add_plt_entry was
called, thus rendering _all_ PLT slots invalid, even those that
weren't later procted by breakpoints. Thus calls done through any
untraced slots failed.
This patch fixes this problem by deferring the unprelinking of PLT
slots into the on_install hook of breakpoints.
---
sysdeps/linux-gnu/ppc/arch.h | 21 ++++++++-
sysdeps/linux-gnu/ppc/plt.c | 94 +++++++++++++++++++++++++++++++++--------
2 files changed, 94 insertions(+), 21 deletions(-)
diff --git a/sysdeps/linux-gnu/ppc/arch.h b/sysdeps/linux-gnu/ppc/arch.h
index 2add3b8..bf9b5dc 100644
--- a/sysdeps/linux-gnu/ppc/arch.h
+++ b/sysdeps/linux-gnu/ppc/arch.h
@@ -1,6 +1,6 @@
/*
* This file is part of ltrace.
- * Copyright (C) 2012,2013 Petr Machata
+ * Copyright (C) 2012,2013,2014 Petr Machata
* Copyright (C) 2006 Paul Gilliam
* Copyright (C) 2002,2004 Juan Cespedes
*
@@ -87,12 +87,29 @@ enum ppc64_plt_type {
/* Very similar to PPC_PLT_UNRESOLVED, but for JMP_IREL
* slots. */
PPC_PLT_IRELATIVE,
+
+ /* Transitional state before the breakpoint is enabled. */
+ PPC_PLT_NEED_UNRESOLVE,
};
#define ARCH_HAVE_LIBRARY_SYMBOL_DATA
+struct ppc_unresolve_data;
struct arch_library_symbol_data {
enum ppc64_plt_type type;
- GElf_Addr resolved_value;
+
+ /* State Contents
+ *
+ * PPC_DEFAULT N/A
+ * PPC64_PLT_STUB N/A
+ * PPC_PLT_UNRESOLVED PLT entry address.
+ * PPC_PLT_IRELATIVE Likewise.
+ * PPC_PLT_RESOLVED The original value the slot was resolved to.
+ * PPC_PLT_NEED_UNRESOLVE DATA.
+ */
+ union {
+ GElf_Addr resolved_value;
+ struct ppc_unresolve_data *data;
+ };
/* Address of corresponding slot in .plt. */
GElf_Addr plt_slot_addr;
diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
index 8715da6..332daa8 100644
--- a/sysdeps/linux-gnu/ppc/plt.c
+++ b/sysdeps/linux-gnu/ppc/plt.c
@@ -679,6 +679,14 @@ arch_elf_add_func_entry(struct process *proc, struct ltelf *lte,
return PLT_OK;
}
+struct ppc_unresolve_data {
+ struct ppc_unresolve_data *self; /* A canary. */
+ GElf_Addr plt_entry_addr;
+ GElf_Addr plt_slot_addr;
+ GElf_Addr plt_slot_value;
+ bool is_irelative;
+};
+
enum plt_status
arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
const char *a_name, GElf_Rela *rela, size_t ndx,
@@ -778,28 +786,23 @@ arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
&& (plt_slot_value == plt_entry_addr || plt_slot_value == 0)) {
libsym->arch.type = PPC_PLT_UNRESOLVED;
libsym->arch.resolved_value = plt_entry_addr;
-
} else {
- /* Unresolve the .plt slot. If the binary was
- * prelinked, this makes the code invalid, because in
- * case of prelinked binary, the dynamic linker
- * doesn't update .plt[0] and .plt[1] with addresses
- * of the resover. But we don't care, we will never
- * need to enter the resolver. That just means that
- * we have to un-un-resolve this back before we
- * detach. */
-
- if (unresolve_plt_slot(proc, plt_slot_addr, plt_entry_addr) < 0) {
- library_symbol_destroy(libsym);
+ /* Mark the symbol for later unresolving. We may not
+ * do this right away, as this is called by ltrace
+ * core for all symbols, and only later filtered. We
+ * only unresolve the symbol before the breakpoint is
+ * enabled. */
+
+ libsym->arch.type = PPC_PLT_NEED_UNRESOLVE;
+ libsym->arch.data = malloc(sizeof *libsym->arch.data);
+ if (libsym->arch.data == NULL)
goto fail2;
- }
- if (! is_irelative) {
- mark_as_resolved(libsym, plt_slot_value);
- } else {
- libsym->arch.type = PPC_PLT_IRELATIVE;
- libsym->arch.resolved_value = plt_entry_addr;
- }
+ libsym->arch.data->self = libsym->arch.data;
+ libsym->arch.data->plt_entry_addr = plt_entry_addr;
+ libsym->arch.data->plt_slot_addr = plt_slot_addr;
+ libsym->arch.data->plt_slot_value = plt_slot_value;
+ libsym->arch.data->is_irelative = is_irelative;
}
*ret = libsym;
@@ -999,6 +1002,7 @@ ppc_plt_bp_continue(struct breakpoint *bp, struct process *proc)
return;
case PPC64_PLT_STUB:
+ case PPC_PLT_NEED_UNRESOLVE:
/* These should never hit here. */
break;
}
@@ -1050,6 +1054,52 @@ ppc_plt_bp_retract(struct breakpoint *bp, struct process *proc)
}
}
+static void
+ppc_plt_bp_install(struct breakpoint *bp, struct process *proc)
+{
+ /* This should not be an artificial breakpoint. */
+ struct library_symbol *libsym = bp->libsym;
+ if (libsym == NULL)
+ libsym = bp->arch.irel_libsym;
+ assert(libsym != NULL);
+
+ if (libsym->arch.type == PPC_PLT_NEED_UNRESOLVE) {
+ /* Unresolve the .plt slot. If the binary was
+ * prelinked, this makes the code invalid, because in
+ * case of prelinked binary, the dynamic linker
+ * doesn't update .plt[0] and .plt[1] with addresses
+ * of the resover. But we don't care, we will never
+ * need to enter the resolver. That just means that
+ * we have to un-un-resolve this back before we
+ * detach. */
+
+ struct ppc_unresolve_data *data = libsym->arch.data;
+ libsym->arch.data = NULL;
+ assert(data->self == data);
+
+ GElf_Addr plt_slot_addr = data->plt_slot_addr;
+ GElf_Addr plt_slot_value = data->plt_slot_value;
+ GElf_Addr plt_entry_addr = data->plt_entry_addr;
+
+ if (unresolve_plt_slot(proc, plt_slot_addr,
+ plt_entry_addr) == 0) {
+ if (! data->is_irelative) {
+ mark_as_resolved(libsym, plt_slot_value);
+ } else {
+ libsym->arch.type = PPC_PLT_IRELATIVE;
+ libsym->arch.resolved_value = plt_entry_addr;
+ }
+ } else {
+ fprintf(stderr, "Couldn't unresolve %s@%p. Not tracing"
+ " this symbol.\n",
+ breakpoint_name(bp), bp->addr);
+ proc_remove_breakpoint(proc, bp);
+ }
+
+ free(data);
+ }
+}
+
int
arch_library_init(struct library *lib)
{
@@ -1080,6 +1130,11 @@ arch_library_symbol_init(struct library_symbol *libsym)
void
arch_library_symbol_destroy(struct library_symbol *libsym)
{
+ if (libsym->arch.type == PPC_PLT_NEED_UNRESOLVE) {
+ assert(libsym->arch.data->self == libsym->arch.data);
+ free(libsym->arch.data);
+ libsym->arch.data = NULL;
+ }
}
int
@@ -1115,6 +1170,7 @@ arch_breakpoint_init(struct process *proc, struct breakpoint *bp)
static struct bp_callbacks cbs = {
.on_continue = ppc_plt_bp_continue,
.on_retract = ppc_plt_bp_retract,
+ .on_install = ppc_plt_bp_install,
};
breakpoint_set_callbacks(bp, &cbs);
--
1.7.6.5

@ -0,0 +1,44 @@
From eea6091f8672b01f7f022b0fc367e0f568225ffc Mon Sep 17 00:00:00 2001
From: Petr Machata <pmachata@redhat.com>
Date: Fri, 8 Aug 2014 17:09:58 +0200
Subject: [PATCH] Recognize powerpc64le in configure
---
configure.ac | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/configure.ac b/configure.ac
index 4f360c8..6fe5e3b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -43,7 +43,7 @@ case "${host_cpu}" in
arm*|sa110) HOST_CPU="arm" ;;
cris*) HOST_CPU="cris" ;;
mips*) HOST_CPU="mips" ;;
- powerpc|powerpc64) HOST_CPU="ppc" ;;
+ powerpc|powerpc64|powerpc64le) HOST_CPU="ppc" ;;
sun4u|sparc64) HOST_CPU="sparc" ;;
s390x) HOST_CPU="s390" ;;
i?86|x86_64) HOST_CPU="x86" ;;
@@ -210,12 +210,12 @@ AC_MSG_RESULT([$enable_libunwind])
if test x"$enable_libunwind" = xyes; then
case "${host_cpu}" in
- arm*|sa110) UNWIND_ARCH="arm" ;;
- i?86) UNWIND_ARCH="x86" ;;
- powerpc) UNWIND_ARCH="ppc32" ;;
- powerpc64) UNWIND_ARCH="ppc64" ;;
- mips*) UNWIND_ARCH="mips" ;;
- *) UNWIND_ARCH="${host_cpu}" ;;
+ arm*|sa110) UNWIND_ARCH="arm" ;;
+ i?86) UNWIND_ARCH="x86" ;;
+ powerpc) UNWIND_ARCH="ppc32" ;;
+ powerpc64|powerpc64le) UNWIND_ARCH="ppc64" ;;
+ mips*) UNWIND_ARCH="mips" ;;
+ *) UNWIND_ARCH="${host_cpu}" ;;
esac
saved_LDFLAGS="${LDFLAGS}"
--
2.1.0

@ -0,0 +1,421 @@
diff --git a/sysdeps/linux-gnu/ppc/arch.h b/sysdeps/linux-gnu/ppc/arch.h
index d5ad759..a8b67bb 100644
--- a/sysdeps/linux-gnu/ppc/arch.h
+++ b/sysdeps/linux-gnu/ppc/arch.h
@@ -32,36 +32,45 @@
#define LT_ELF_MACHINE EM_PPC
#ifdef __powerpc64__ // Says 'ltrace' is 64 bits, says nothing about target.
-#define LT_ELFCLASS2 ELFCLASS64
-#define LT_ELF_MACHINE2 EM_PPC64
+# define LT_ELFCLASS2 ELFCLASS64
+# define LT_ELF_MACHINE2 EM_PPC64
# ifdef __LITTLE_ENDIAN__
-# define BREAKPOINT_VALUE { 0x08, 0x00, 0xe0, 0x7f }
-# define ARCH_ENDIAN_LITTLE
+# define BREAKPOINT_VALUE { 0x08, 0x00, 0xe0, 0x7f }
+# define ARCH_ENDIAN_LITTLE
# else
-# define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
-# define ARCH_SUPPORTS_OPD
-# define ARCH_ENDIAN_BIG
+# define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
+# define ARCH_SUPPORTS_OPD
+# define ARCH_ENDIAN_BIG
# endif
-# if _CALL_ELF != 2
-# define ARCH_SUPPORTS_OPD
-# define STACK_FRAME_OVERHEAD 112
+# if !defined(_CALL_ELF) || _CALL_ELF < 2
+# define ARCH_SUPPORTS_OPD
+# define STACK_FRAME_OVERHEAD 112
# ifndef EF_PPC64_ABI
-# define EF_PPC64_ABI 3
+# define EF_PPC64_ABI 3
# endif
-# else /* _CALL_ELF == 2 ABIv2 */
-# define STACK_FRAME_OVERHEAD 32
+# elif _CALL_ELF == 2 /* ELFv2 ABI */
+# define STACK_FRAME_OVERHEAD 32
+# else
+# error Unsupported PowerPC64 ABI.
# endif /* CALL_ELF */
#else
-#define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
-#define ARCH_ENDIAN_BIG
+# define STACK_FRAME_OVERHEAD 112
+# define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
+# define ARCH_ENDIAN_BIG
# ifndef EF_PPC64_ABI
-# define EF_PPC64_ABI 3
+# define EF_PPC64_ABI 3
# endif
#endif /* __powerpc64__ */
+#ifdef _CALL_ELF
+enum { ppc64_call_elf_abi = _CALL_ELF };
+#else
+enum { ppc64_call_elf_abi = 0 };
+#endif
+
#define ARCH_HAVE_SW_SINGLESTEP
#define ARCH_HAVE_ADD_PLT_ENTRY
#define ARCH_HAVE_ADD_FUNC_ENTRY
diff --git a/sysdeps/linux-gnu/ppc/fetch.c b/sysdeps/linux-gnu/ppc/fetch.c
index c9381c3..c6cbd71 100644
--- a/sysdeps/linux-gnu/ppc/fetch.c
+++ b/sysdeps/linux-gnu/ppc/fetch.c
@@ -1,6 +1,6 @@
/*
* This file is part of ltrace.
- * Copyright (C) 2012 Petr Machata, Red Hat Inc.
+ * Copyright (C) 2012, 2014 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
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/ucontext.h>
+#include <stdio.h>
#include "backend.h"
#include "fetch.h"
@@ -57,7 +58,7 @@ struct fetch_context {
arch_addr_t stack_pointer;
int greg;
int freg;
- int ret_struct;
+ bool ret_struct;
union {
gregs32_t r32;
@@ -65,11 +66,29 @@ struct fetch_context {
} regs;
struct fpregs_t fpregs;
int vgreg;
- int struct_size;
- int struct_hfa_size;
- int struct_hfa_count;
};
+static bool
+is_eligible_hfa(struct arg_type_info *info,
+ struct arg_type_info **hfa_infop, size_t *hfa_countp)
+{
+ size_t hfa_count;
+ struct arg_type_info *hfa_info = type_get_hfa_type(info, &hfa_count);
+
+ if (hfa_info != NULL && hfa_count <= 8
+ && (hfa_info->type == ARGTYPE_FLOAT
+ || hfa_info->type == ARGTYPE_DOUBLE)) {
+
+ if (hfa_infop != NULL)
+ *hfa_infop = hfa_info;
+ if (hfa_countp != NULL)
+ *hfa_countp = hfa_count;
+ return true;
+ }
+
+ return false;
+}
+
static int
fetch_context_init(struct process *proc, struct fetch_context *context)
{
@@ -125,30 +144,37 @@ arch_fetch_arg_init(enum tof type, struct process *proc,
}
context->vgreg = context->greg;
- context->struct_size = 0;
- context->struct_hfa_size = 0;
- context->struct_hfa_count = 0;
/* Aggregates or unions of any length, and character strings
* of length longer than 8 bytes, will be returned in a
* storage buffer allocated by the caller. The caller will
* pass the address of this buffer as a hidden first argument
* in r3, causing the first explicit argument to be passed in
- * r4. */
- context->ret_struct = ret_info->type == ARGTYPE_STRUCT;
- if (context->ret_struct) {
-#if _CALL_ELF == 2
- /* if R3 points to stack, parameters will be in R4. */
- uint64_t pstack_end = ptrace(PTRACE_PEEKTEXT, proc->pid,
- proc->stack_pointer, 0);
- if (((arch_addr_t)context->regs.r64[3] > proc->stack_pointer)
- && (context->regs.r64[3] < pstack_end)) {
+ * r4.
+ */
+
+ context->ret_struct = false;
+
+ if (ppc64_call_elf_abi == 2) {
+ /* With ELFv2 ABI, aggregates that consist
+ * (recursively) only of members of the same
+ * floating-point or vector type, are passed in a
+ * series of floating-point resp. vector registers.
+ * Additionally, when returning any aggregate of up to
+ * 16 bytes, general-purpose registers are used. */
+
+ if (ret_info->type == ARGTYPE_STRUCT
+ && ! is_eligible_hfa(ret_info, NULL, NULL)
+ && type_sizeof(proc, ret_info) > 16) {
+
+ context->ret_struct = true;
context->greg++;
context->stack_pointer += 8;
}
-#else
+
+ } else if (ret_info->type == ARGTYPE_STRUCT) {
+ context->ret_struct = true;
context->greg++;
-#endif
}
return context;
@@ -176,17 +202,16 @@ allocate_stack_slot(struct fetch_context *ctx, struct process *proc,
size_t a = type_alignof(proc, info);
size_t off = 0;
- if (proc->e_machine == EM_PPC && a < 4)
- a = 4;
-#if _CALL_ELF == 2
- else if (proc->e_machine == EM_PPC64 && sz == 4 && is_hfa_type)
+ if (proc->e_machine == EM_PPC && a < 4) {
a = 4;
- else
- a = 8;
-#else
- else if (proc->e_machine == EM_PPC64 && a < 8)
-#endif
+ } else if (ppc64_call_elf_abi == 2) {
+ if (proc->e_machine == EM_PPC64 && sz == 4 && is_hfa_type) {
+ a = 4;
+ } else
+ a = 8;
+ } else if (proc->e_machine == EM_PPC64 && a < 8) {
a = 8;
+ }
/* XXX Remove the two double casts when arch_addr_t
* becomes integral type. */
@@ -259,18 +284,19 @@ allocate_gpr(struct fetch_context *ctx, struct process *proc,
if (sz == (size_t)-1)
return -1;
assert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
-#if _CALL_ELF == 2
- /* Consume the stack slot corresponding to this arg. */
- if ((sz + off) >= 8)
- ctx->greg++;
- if (is_hfa_type)
- ctx->stack_pointer += sz;
- else
- ctx->stack_pointer += 8;
-#else
- ctx->greg++;
-#endif
+ if (ppc64_call_elf_abi == 2) {
+ /* Consume the stack slot corresponding to this arg. */
+ if ((sz + off) >= 8)
+ ctx->greg++;
+
+ if (is_hfa_type)
+ ctx->stack_pointer += sz;
+ else
+ ctx->stack_pointer += 8;
+ } else {
+ ctx->greg++;
+ }
if (valuep == NULL)
return 0;
@@ -326,7 +352,6 @@ allocate_float(struct fetch_context *ctx, struct process *proc,
return allocate_stack_slot(ctx, proc, info, valuep, is_hfa_type);
}
-#if _CALL_ELF == 2
static int
allocate_hfa(struct fetch_context *ctx, struct process *proc,
struct arg_type_info *info, struct value *valuep,
@@ -336,27 +361,27 @@ allocate_hfa(struct fetch_context *ctx, struct process *proc,
if (sz == (size_t)-1)
return -1;
- ctx->struct_hfa_size += sz;
-
/* There are two changes regarding structure return types:
- * * heterogeneous float/vector structs are returned
- * in (multiple) FP/vector registers,
- * instead of via implicit reference.
- * * small structs (up to 16 bytes) are return
- * in one or two GPRs, instead of via implicit reference.
+ * * heterogeneous float/vector structs are returned in
+ * (multiple) FP/vector registers, instead of via implicit
+ * reference.
+ * * small structs (up to 16 bytes) are return in one or two
+ * GPRs, instead of via implicit reference.
*
* Other structures (larger than 16 bytes, not heterogeneous)
* are still returned via implicit reference (i.e. a pointer
* to memory where to return the struct being passed in r3).
- * Of course, whether or not an implicit reference pointer
- * is present will shift the remaining arguments,
- * so you need to get this right for ELFv2 in order
- * to get the arguments correct.
+ * Of course, whether or not an implicit reference pointer is
+ * present will shift the remaining arguments, so you need to
+ * get this right for ELFv2 in order to get the arguments
+ * correct.
+ *
* If an actual parameter is known to correspond to an HFA
* formal parameter, each element is passed in the next
* available floating-point argument register starting at fp1
* until the fp13. The remaining elements of the aggregate are
- * passed on the stack. */
+ * passed on the stack.
+ */
size_t slot_off = 0;
unsigned char *buf = value_reserve(valuep, sz);
@@ -366,26 +391,17 @@ allocate_hfa(struct fetch_context *ctx, struct process *proc,
struct arg_type_info *hfa_info = type_get_simple(hfa_type);
size_t hfa_sz = type_sizeof(proc, hfa_info);
- if (hfa_count > 8)
- ctx->struct_hfa_count += hfa_count;
-
while (hfa_count > 0 && ctx->freg <= 13) {
- int rc;
struct value tmp;
-
value_init(&tmp, proc, NULL, hfa_info, 0);
+ int rc = allocate_float(ctx, proc, hfa_info,
+ &tmp, slot_off, true);
+ if (rc == 0)
+ memcpy(buf, value_get_data(&tmp, NULL), hfa_sz);
+ value_destroy(&tmp);
- /* Hetereogeneous struct - get value on GPR or stack. */
- if (((hfa_type == ARGTYPE_FLOAT
- || hfa_type == ARGTYPE_DOUBLE)
- && hfa_count <= 8))
- rc = allocate_float(ctx, proc, hfa_info, &tmp,
- slot_off, true);
- else
- rc = allocate_gpr(ctx, proc, hfa_info, &tmp,
- slot_off, true);
-
- memcpy(buf, value_get_data(&tmp, NULL), hfa_sz);
+ if (rc < 0)
+ return -1;
slot_off += hfa_sz;
buf += hfa_sz;
@@ -394,17 +410,13 @@ allocate_hfa(struct fetch_context *ctx, struct process *proc,
slot_off = 0;
ctx->vgreg++;
}
-
- value_destroy(&tmp);
- if (rc < 0)
- return -1;
}
if (hfa_count == 0)
return 0;
/* if no remaining FP, GPR corresponding to slot is used
- * Mostly it is in part of r10. */
- if (ctx->struct_hfa_size <= 64 && ctx->vgreg == 10) {
+ * Mostly it is in part of r10. */
+ if (ctx->vgreg == 10) {
while (ctx->vgreg <= 10) {
struct value tmp;
value_init(&tmp, proc, NULL, hfa_info, 0);
@@ -428,11 +440,8 @@ allocate_hfa(struct fetch_context *ctx, struct process *proc,
}
}
- if (hfa_count == 0)
- return 0;
-
/* Remaining values are on stack */
- while (hfa_count) {
+ while (hfa_count > 0) {
struct value tmp;
value_init(&tmp, proc, NULL, hfa_info, 0);
@@ -444,7 +453,6 @@ allocate_hfa(struct fetch_context *ctx, struct process *proc,
}
return 0;
}
-#endif
static int
allocate_argument(struct fetch_context *ctx, struct process *proc,
@@ -459,24 +467,20 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
case ARGTYPE_FLOAT:
case ARGTYPE_DOUBLE:
return allocate_float(ctx, proc, info, valuep,
- 8 - type_sizeof(proc,info), false);
+ 8 - type_sizeof(proc,info), false);
case ARGTYPE_STRUCT:
if (proc->e_machine == EM_PPC) {
if (value_pass_by_reference(valuep) < 0)
return -1;
- } else {
-#if _CALL_ELF == 2
+ } else if (ppc64_call_elf_abi == 2) {
struct arg_type_info *hfa_info;
- size_t hfa_size;
- hfa_info = type_get_hfa_type(info, &hfa_size);
- if (hfa_info != NULL ) {
- size_t sz = type_sizeof(proc, info);
- ctx->struct_size += sz;
+ size_t hfa_count;
+ if (is_eligible_hfa(info, &hfa_info, &hfa_count)) {
return allocate_hfa(ctx, proc, info, valuep,
- hfa_info->type, hfa_size);
+ hfa_info->type, hfa_count);
}
-#endif
+ } else {
/* PPC64: Fixed size aggregates and unions passed by
* value are mapped to as many doublewords of the
* parameter save area as the value uses in memory.
@@ -510,9 +514,6 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
if (sz == (size_t)-1)
return -1;
- if (ctx->ret_struct)
- ctx->struct_size += sz;
-
size_t slots = (sz + width - 1) / width; /* Round up. */
unsigned char *buf = value_reserve(valuep, slots * width);
if (buf == NULL)
@@ -605,19 +606,7 @@ arch_fetch_retval(struct fetch_context *ctx, enum tof type,
if (fetch_context_init(proc, ctx) < 0)
return -1;
-#if _CALL_ELF == 2
- void *ptr = (void *)(ctx->regs.r64[1]+32);
- uint64_t val = ptrace(PTRACE_PEEKTEXT, proc->pid, ptr, 0);
-
- if (ctx->ret_struct
- && ((ctx->struct_size > 64
- || ctx->struct_hfa_count > 8
- || (ctx->struct_hfa_size == 0 && ctx->struct_size > 56)
- || (ctx->regs.r64[3] == ctx->regs.r64[1]+32)
- || (ctx->regs.r64[3] == val )))) {
-#else
if (ctx->ret_struct) {
-#endif
assert(info->type == ARGTYPE_STRUCT);
uint64_t addr = read_gpr(ctx, proc, 3);

@ -0,0 +1,20 @@
diff -rup a/sysdeps/linux-gnu/ppc/trace.c b/sysdeps/linux-gnu/ppc/trace.c
--- a/sysdeps/linux-gnu/ppc/trace.c 2021-02-08 14:35:16.876494095 -0500
+++ b/sysdeps/linux-gnu/ppc/trace.c 2021-02-08 15:05:59.468107311 -0500
@@ -57,6 +57,7 @@ get_arch_dep(struct process *proc)
}
#define SYSCALL_INSN 0x44000002
+#define SYSCALL2_INSN 0x44000001
/* Returns 1 if syscall, 2 if sysret, 0 otherwise. */
int
@@ -75,7 +76,7 @@ syscall_p(struct process *proc, int stat
0);
#endif
- if (insn == SYSCALL_INSN) {
+ if (insn == SYSCALL_INSN || insn == SYSCALL2_INSN) {
*sysnum =
(int)ptrace(PTRACE_PEEKUSER, proc->pid,
sizeof(long) * PT_R0, 0);

@ -0,0 +1,786 @@
From eea4ad2cce289753aaa35b4e0258a76d8f8f367c Mon Sep 17 00:00:00 2001
From: Thierry Fauck <thierry@linux.vnet.ibm.com>
Date: Tue, 13 May 2014 07:48:24 -0400
Subject: [PATCH] Support for powerpc64 arch ppc64el
Signed-off-by: Thierry Fauck <thierry@linux.vnet.ibm.com>
Add support for ppc64le proc and ELF ABIv2.
Provides support for irelative and wchar
---
ltrace-elf.c | 2 +-
ltrace-elf.h | 1 +
sysdeps/linux-gnu/ppc/arch.h | 35 ++++-
sysdeps/linux-gnu/ppc/fetch.c | 244 +++++++++++++++++++++++++++++---
sysdeps/linux-gnu/ppc/plt.c | 98 ++++++++++++--
sysdeps/linux-gnu/ppc/trace.c | 10 ++
testsuite/ltrace.main/system_calls.exp | 2 +-
7 files changed, 356 insertions(+), 36 deletions(-)
diff --git a/ltrace-elf.c b/ltrace-elf.c
index 8997518..f638342 100644
--- a/ltrace-elf.c
+++ b/ltrace-elf.c
@@ -859,7 +859,7 @@ populate_plt(struct process *proc, const char *filename,
return 0;
}
-static void
+void
delete_symbol_chain(struct library_symbol *libsym)
{
while (libsym != NULL) {
diff --git a/ltrace-elf.h b/ltrace-elf.h
index db4ffe9..4a824c4 100644
--- a/ltrace-elf.h
+++ b/ltrace-elf.h
@@ -166,6 +166,7 @@ int elf_read_next_uleb128(Elf_Data *data, GElf_Xword *offset, uint64_t *retp);
/* Return whether there's AMOUNT more bytes after OFFSET in DATA. */
int elf_can_read_next(Elf_Data *data, GElf_Xword offset, GElf_Xword amount);
+void delete_symbol_chain(struct library_symbol *);
#if __WORDSIZE == 32
#define PRI_ELF_ADDR PRIx32
#define GELF_ADDR_CAST(x) (void *)(uint32_t)(x)
diff --git a/sysdeps/linux-gnu/ppc/arch.h b/sysdeps/linux-gnu/ppc/arch.h
index bf9b5dc..7918a13 100644
--- a/sysdeps/linux-gnu/ppc/arch.h
+++ b/sysdeps/linux-gnu/ppc/arch.h
@@ -23,8 +23,8 @@
#define LTRACE_PPC_ARCH_H
#include <gelf.h>
+#include <stdbool.h>
-#define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
#define BREAKPOINT_LENGTH 4
#define DECR_PC_AFTER_BREAK 0
@@ -34,8 +34,33 @@
#ifdef __powerpc64__ // Says 'ltrace' is 64 bits, says nothing about target.
#define LT_ELFCLASS2 ELFCLASS64
#define LT_ELF_MACHINE2 EM_PPC64
-#define ARCH_SUPPORTS_OPD
-#endif
+
+# ifdef __LITTLE_ENDIAN__
+# define BREAKPOINT_VALUE { 0x08, 0x00, 0xe0, 0x7f }
+# define ARCH_ENDIAN_LITTLE
+# else
+# define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
+# define ARCH_SUPPORTS_OPD
+# define ARCH_ENDIAN_BIG
+# endif
+
+# if _CALL_ELF != 2
+# define ARCH_SUPPORTS_OPD
+# define STACK_FRAME_OVERHEAD 112
+# ifndef EF_PPC64_ABI
+# define EF_PPC64_ABI 3
+# endif
+# else /* _CALL_ELF == 2 ABIv2 */
+# define STACK_FRAME_OVERHEAD 32
+# endif /* CALL_ELF */
+
+#else
+#define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
+#define ARCH_ENDIAN_BIG
+# ifndef EF_PPC64_ABI
+# define EF_PPC64_ABI 3
+# endif
+#endif /* __powerpc64__ */
#define ARCH_HAVE_SW_SINGLESTEP
#define ARCH_HAVE_ADD_PLT_ENTRY
@@ -43,7 +68,6 @@
#define ARCH_HAVE_TRANSLATE_ADDRESS
#define ARCH_HAVE_DYNLINK_DONE
#define ARCH_HAVE_FETCH_ARG
-#define ARCH_ENDIAN_BIG
#define ARCH_HAVE_SIZEOF
#define ARCH_HAVE_ALIGNOF
@@ -56,7 +80,8 @@ struct arch_ltelf_data {
Elf_Data *opd_data;
GElf_Addr opd_base;
GElf_Xword opd_size;
- int secure_plt;
+ bool secure_plt : 1;
+ bool elfv2_abi : 1;
Elf_Data *reladyn;
size_t reladyn_count;
diff --git a/sysdeps/linux-gnu/ppc/fetch.c b/sysdeps/linux-gnu/ppc/fetch.c
index ed38336..c9381c3 100644
--- a/sysdeps/linux-gnu/ppc/fetch.c
+++ b/sysdeps/linux-gnu/ppc/fetch.c
@@ -30,9 +30,11 @@
#include "ptrace.h"
#include "proc.h"
#include "value.h"
+#include "ltrace-elf.h"
static int allocate_gpr(struct fetch_context *ctx, struct process *proc,
- struct arg_type_info *info, struct value *valuep);
+ struct arg_type_info *info, struct value *valuep,
+ size_t off, bool is_hfa_type);
/* Floating point registers have the same width on 32-bit as well as
* 64-bit PPC, but <ucontext.h> presents a different API depending on
@@ -62,7 +64,10 @@ struct fetch_context {
gregs64_t r64;
} regs;
struct fpregs_t fpregs;
-
+ int vgreg;
+ int struct_size;
+ int struct_hfa_size;
+ int struct_hfa_count;
};
static int
@@ -74,7 +79,8 @@ fetch_context_init(struct process *proc, struct fetch_context *context)
if (proc->e_machine == EM_PPC)
context->stack_pointer = proc->stack_pointer + 8;
else
- context->stack_pointer = proc->stack_pointer + 112;
+ context->stack_pointer = proc->stack_pointer
+ + STACK_FRAME_OVERHEAD;
/* When ltrace is 64-bit, we might use PTRACE_GETREGS to
* obtain 64-bit as well as 32-bit registers. But if we do it
@@ -118,6 +124,11 @@ arch_fetch_arg_init(enum tof type, struct process *proc,
return NULL;
}
+ context->vgreg = context->greg;
+ context->struct_size = 0;
+ context->struct_hfa_size = 0;
+ context->struct_hfa_count = 0;
+
/* Aggregates or unions of any length, and character strings
* of length longer than 8 bytes, will be returned in a
* storage buffer allocated by the caller. The caller will
@@ -125,8 +136,20 @@ arch_fetch_arg_init(enum tof type, struct process *proc,
* in r3, causing the first explicit argument to be passed in
* r4. */
context->ret_struct = ret_info->type == ARGTYPE_STRUCT;
- if (context->ret_struct)
+ if (context->ret_struct) {
+#if _CALL_ELF == 2
+ /* if R3 points to stack, parameters will be in R4. */
+ uint64_t pstack_end = ptrace(PTRACE_PEEKTEXT, proc->pid,
+ proc->stack_pointer, 0);
+ if (((arch_addr_t)context->regs.r64[3] > proc->stack_pointer)
+ && (context->regs.r64[3] < pstack_end)) {
+ context->greg++;
+ context->stack_pointer += 8;
+ }
+#else
context->greg++;
+#endif
+ }
return context;
}
@@ -144,7 +167,8 @@ arch_fetch_arg_clone(struct process *proc,
static int
allocate_stack_slot(struct fetch_context *ctx, struct process *proc,
- struct arg_type_info *info, struct value *valuep)
+ struct arg_type_info *info, struct value *valuep,
+ bool is_hfa_type)
{
size_t sz = type_sizeof(proc, info);
if (sz == (size_t)-1)
@@ -154,7 +178,14 @@ allocate_stack_slot(struct fetch_context *ctx, struct process *proc,
size_t off = 0;
if (proc->e_machine == EM_PPC && a < 4)
a = 4;
+#if _CALL_ELF == 2
+ else if (proc->e_machine == EM_PPC64 && sz == 4 && is_hfa_type)
+ a = 4;
+ else
+ a = 8;
+#else
else if (proc->e_machine == EM_PPC64 && a < 8)
+#endif
a = 8;
/* XXX Remove the two double casts when arch_addr_t
@@ -164,7 +195,7 @@ allocate_stack_slot(struct fetch_context *ctx, struct process *proc,
if (valuep != NULL)
value_in_inferior(valuep, ctx->stack_pointer + off);
- ctx->stack_pointer += sz;
+ ctx->stack_pointer += a;
return 0;
}
@@ -216,19 +247,34 @@ align_small_int(unsigned char *buf, size_t w, size_t sz)
static int
allocate_gpr(struct fetch_context *ctx, struct process *proc,
- struct arg_type_info *info, struct value *valuep)
+ struct arg_type_info *info, struct value *valuep,
+ size_t off, bool is_hfa_type)
{
if (ctx->greg > 10)
- return allocate_stack_slot(ctx, proc, info, valuep);
+ return allocate_stack_slot(ctx, proc, info, valuep, is_hfa_type);
- int reg_num = ctx->greg++;
- if (valuep == NULL)
- return 0;
+ int reg_num = ctx->greg;
size_t sz = type_sizeof(proc, info);
if (sz == (size_t)-1)
return -1;
assert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
+#if _CALL_ELF == 2
+ /* Consume the stack slot corresponding to this arg. */
+ if ((sz + off) >= 8)
+ ctx->greg++;
+
+ if (is_hfa_type)
+ ctx->stack_pointer += sz;
+ else
+ ctx->stack_pointer += 8;
+#else
+ ctx->greg++;
+#endif
+
+ if (valuep == NULL)
+ return 0;
+
if (value_reserve(valuep, sz) == NULL)
return -1;
@@ -240,13 +286,14 @@ allocate_gpr(struct fetch_context *ctx, struct process *proc,
u.i64 = read_gpr(ctx, proc, reg_num);
if (proc->e_machine == EM_PPC)
align_small_int(u.buf, 8, sz);
- memcpy(value_get_raw_data(valuep), u.buf, sz);
+ memcpy(value_get_raw_data(valuep), u.buf + off, sz);
return 0;
}
static int
allocate_float(struct fetch_context *ctx, struct process *proc,
- struct arg_type_info *info, struct value *valuep)
+ struct arg_type_info *info, struct value *valuep,
+ size_t off, bool is_hfa_type)
{
int pool = proc->e_machine == EM_PPC64 ? 13 : 8;
if (ctx->freg <= pool) {
@@ -257,8 +304,12 @@ allocate_float(struct fetch_context *ctx, struct process *proc,
} u = { .d = ctx->fpregs.fpregs[ctx->freg] };
ctx->freg++;
+
+ if (!is_hfa_type)
+ ctx->vgreg++;
+
if (proc->e_machine == EM_PPC64)
- allocate_gpr(ctx, proc, info, NULL);
+ allocate_gpr(ctx, proc, info, NULL, off, is_hfa_type);
size_t sz = sizeof(double);
if (info->type == ARGTYPE_FLOAT) {
@@ -272,8 +323,128 @@ allocate_float(struct fetch_context *ctx, struct process *proc,
memcpy(value_get_raw_data(valuep), u.buf, sz);
return 0;
}
- return allocate_stack_slot(ctx, proc, info, valuep);
+ return allocate_stack_slot(ctx, proc, info, valuep, is_hfa_type);
+}
+
+#if _CALL_ELF == 2
+static int
+allocate_hfa(struct fetch_context *ctx, struct process *proc,
+ struct arg_type_info *info, struct value *valuep,
+ enum arg_type hfa_type, size_t hfa_count)
+{
+ size_t sz = type_sizeof(proc, info);
+ if (sz == (size_t)-1)
+ return -1;
+
+ ctx->struct_hfa_size += sz;
+
+ /* There are two changes regarding structure return types:
+ * * heterogeneous float/vector structs are returned
+ * in (multiple) FP/vector registers,
+ * instead of via implicit reference.
+ * * small structs (up to 16 bytes) are return
+ * in one or two GPRs, instead of via implicit reference.
+ *
+ * Other structures (larger than 16 bytes, not heterogeneous)
+ * are still returned via implicit reference (i.e. a pointer
+ * to memory where to return the struct being passed in r3).
+ * Of course, whether or not an implicit reference pointer
+ * is present will shift the remaining arguments,
+ * so you need to get this right for ELFv2 in order
+ * to get the arguments correct.
+ * If an actual parameter is known to correspond to an HFA
+ * formal parameter, each element is passed in the next
+ * available floating-point argument register starting at fp1
+ * until the fp13. The remaining elements of the aggregate are
+ * passed on the stack. */
+ size_t slot_off = 0;
+
+ unsigned char *buf = value_reserve(valuep, sz);
+ if (buf == NULL)
+ return -1;
+
+ struct arg_type_info *hfa_info = type_get_simple(hfa_type);
+ size_t hfa_sz = type_sizeof(proc, hfa_info);
+
+ if (hfa_count > 8)
+ ctx->struct_hfa_count += hfa_count;
+
+ while (hfa_count > 0 && ctx->freg <= 13) {
+ int rc;
+ struct value tmp;
+
+ value_init(&tmp, proc, NULL, hfa_info, 0);
+
+ /* Hetereogeneous struct - get value on GPR or stack. */
+ if (((hfa_type == ARGTYPE_FLOAT
+ || hfa_type == ARGTYPE_DOUBLE)
+ && hfa_count <= 8))
+ rc = allocate_float(ctx, proc, hfa_info, &tmp,
+ slot_off, true);
+ else
+ rc = allocate_gpr(ctx, proc, hfa_info, &tmp,
+ slot_off, true);
+
+ memcpy(buf, value_get_data(&tmp, NULL), hfa_sz);
+
+ slot_off += hfa_sz;
+ buf += hfa_sz;
+ hfa_count--;
+ if (slot_off == 8) {
+ slot_off = 0;
+ ctx->vgreg++;
+ }
+
+ value_destroy(&tmp);
+ if (rc < 0)
+ return -1;
+ }
+ if (hfa_count == 0)
+ return 0;
+
+ /* if no remaining FP, GPR corresponding to slot is used
+ * Mostly it is in part of r10. */
+ if (ctx->struct_hfa_size <= 64 && ctx->vgreg == 10) {
+ while (ctx->vgreg <= 10) {
+ struct value tmp;
+ value_init(&tmp, proc, NULL, hfa_info, 0);
+ union {
+ uint64_t i64;
+ unsigned char buf[0];
+ } u;
+
+ u.i64 = read_gpr(ctx, proc, ctx->vgreg);
+
+ memcpy(buf, u.buf + slot_off, hfa_sz);
+ slot_off += hfa_sz;
+ buf += hfa_sz;
+ hfa_count--;
+ ctx->stack_pointer += hfa_sz;
+ if (slot_off >= 8 ) {
+ slot_off = 0;
+ ctx->vgreg++;
+ }
+ value_destroy(&tmp);
+ }
+ }
+
+ if (hfa_count == 0)
+ return 0;
+
+ /* Remaining values are on stack */
+ while (hfa_count) {
+ struct value tmp;
+ value_init(&tmp, proc, NULL, hfa_info, 0);
+
+ value_in_inferior(&tmp, ctx->stack_pointer);
+ memcpy(buf, value_get_data(&tmp, NULL), hfa_sz);
+ ctx->stack_pointer += hfa_sz;
+ buf += hfa_sz;
+ hfa_count--;
+ }
+ return 0;
}
+#endif
static int
allocate_argument(struct fetch_context *ctx, struct process *proc,
@@ -287,13 +458,25 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
case ARGTYPE_FLOAT:
case ARGTYPE_DOUBLE:
- return allocate_float(ctx, proc, info, valuep);
+ return allocate_float(ctx, proc, info, valuep,
+ 8 - type_sizeof(proc,info), false);
case ARGTYPE_STRUCT:
if (proc->e_machine == EM_PPC) {
if (value_pass_by_reference(valuep) < 0)
return -1;
} else {
+#if _CALL_ELF == 2
+ struct arg_type_info *hfa_info;
+ size_t hfa_size;
+ hfa_info = type_get_hfa_type(info, &hfa_size);
+ if (hfa_info != NULL ) {
+ size_t sz = type_sizeof(proc, info);
+ ctx->struct_size += sz;
+ return allocate_hfa(ctx, proc, info, valuep,
+ hfa_info->type, hfa_size);
+ }
+#endif
/* PPC64: Fixed size aggregates and unions passed by
* value are mapped to as many doublewords of the
* parameter save area as the value uses in memory.
@@ -326,6 +509,10 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
size_t sz = type_sizeof(proc, valuep->type);
if (sz == (size_t)-1)
return -1;
+
+ if (ctx->ret_struct)
+ ctx->struct_size += sz;
+
size_t slots = (sz + width - 1) / width; /* Round up. */
unsigned char *buf = value_reserve(valuep, slots * width);
if (buf == NULL)
@@ -346,9 +533,11 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
struct arg_type_info *fp_info
= type_get_fp_equivalent(valuep->type);
if (fp_info != NULL)
- rc = allocate_float(ctx, proc, fp_info, &val);
+ rc = allocate_float(ctx, proc, fp_info, &val,
+ 8-type_sizeof(proc,info), false);
else
- rc = allocate_gpr(ctx, proc, long_info, &val);
+ rc = allocate_gpr(ctx, proc, long_info, &val,
+ 0, false);
if (rc >= 0) {
memcpy(ptr, value_get_data(&val, NULL), width);
@@ -363,6 +552,7 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
return rc;
}
+#ifndef __LITTLE_ENDIAN__
/* Small values need post-processing. */
if (sz < width) {
switch (info->type) {
@@ -394,6 +584,7 @@ allocate_argument(struct fetch_context *ctx, struct process *proc,
break;
}
}
+#endif
return 0;
}
@@ -411,7 +602,22 @@ arch_fetch_retval(struct fetch_context *ctx, enum tof type,
struct process *proc, struct arg_type_info *info,
struct value *valuep)
{
+ if (fetch_context_init(proc, ctx) < 0)
+ return -1;
+
+#if _CALL_ELF == 2
+ void *ptr = (void *)(ctx->regs.r64[1]+32);
+ uint64_t val = ptrace(PTRACE_PEEKTEXT, proc->pid, ptr, 0);
+
+ if (ctx->ret_struct
+ && ((ctx->struct_size > 64
+ || ctx->struct_hfa_count > 8
+ || (ctx->struct_hfa_size == 0 && ctx->struct_size > 56)
+ || (ctx->regs.r64[3] == ctx->regs.r64[1]+32)
+ || (ctx->regs.r64[3] == val )))) {
+#else
if (ctx->ret_struct) {
+#endif
assert(info->type == ARGTYPE_STRUCT);
uint64_t addr = read_gpr(ctx, proc, 3);
@@ -424,8 +630,6 @@ arch_fetch_retval(struct fetch_context *ctx, enum tof type,
return 0;
}
- if (fetch_context_init(proc, ctx) < 0)
- return -1;
return allocate_argument(ctx, proc, info, valuep);
}
diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
index 332daa8..45ed7fb 100644
--- a/sysdeps/linux-gnu/ppc/plt.c
+++ b/sysdeps/linux-gnu/ppc/plt.c
@@ -136,7 +136,11 @@
*/
#define PPC_PLT_STUB_SIZE 16
-#define PPC64_PLT_STUB_SIZE 8 //xxx
+#if _CALL_ELF != 2
+#define PPC64_PLT_STUB_SIZE 8
+#else
+#define PPC64_PLT_STUB_SIZE 4
+#endif
static inline int
host_powerpc64()
@@ -186,8 +190,13 @@ ppc32_delayed_symbol(struct library_symbol *libsym)
if ((insn1 & BRANCH_MASK) == B_INSN
|| ((insn2 & BRANCH_MASK) == B_INSN
/* XXX double cast */
+#ifdef __LITTLE_ENDIAN__
+ && (ppc_branch_dest(libsym->enter_addr + 4, insn1)
+ == (arch_addr_t) (long) libsym->lib->arch.pltgot_addr)))
+#else
&& (ppc_branch_dest(libsym->enter_addr + 4, insn2)
== (arch_addr_t) (long) libsym->lib->arch.pltgot_addr)))
+#endif
{
mark_as_resolved(libsym, libsym->arch.resolved_value);
}
@@ -206,7 +215,7 @@ arch_dynlink_done(struct process *proc)
"couldn't read PLT value for %s(%p): %s\n",
libsym->name, libsym->enter_addr,
strerror(errno));
- return;
+ return;
}
if (proc->e_machine == EM_PPC)
@@ -227,8 +236,14 @@ reloc_is_irelative(int machine, GElf_Rela *rela)
{
bool irelative = false;
if (machine == EM_PPC64) {
-#ifdef R_PPC64_JMP_IREL
+#ifdef __LITTLE_ENDIAN__
+# ifdef R_PPC64_IRELATIVE
+ irelative = GELF_R_TYPE(rela->r_info) == R_PPC64_IRELATIVE;
+# endif
+#else
+# ifdef R_PPC64_JMP_IREL
irelative = GELF_R_TYPE(rela->r_info) == R_PPC64_JMP_IREL;
+# endif
#endif
} else {
assert(machine == EM_PPC);
@@ -285,6 +300,7 @@ arch_translate_address_dyn(struct process *proc,
arch_addr_t addr, arch_addr_t *ret)
{
if (proc->e_machine == EM_PPC64) {
+#if _CALL_ELF != 2
uint64_t value;
if (proc_read_64(proc, addr, &value) < 0) {
fprintf(stderr,
@@ -296,6 +312,7 @@ arch_translate_address_dyn(struct process *proc,
* arch_addr_t becomes integral type. */
*ret = (arch_addr_t)(uintptr_t)value;
return 0;
+#endif
}
*ret = addr;
@@ -306,7 +323,8 @@ int
arch_translate_address(struct ltelf *lte,
arch_addr_t addr, arch_addr_t *ret)
{
- if (lte->ehdr.e_machine == EM_PPC64) {
+ if (lte->ehdr.e_machine == EM_PPC64
+ && !lte->arch.elfv2_abi) {
/* XXX The double cast should be removed when
* arch_addr_t becomes integral type. */
GElf_Xword offset
@@ -430,7 +448,16 @@ reloc_copy_if_irelative(GElf_Rela *rela, void *data)
int
arch_elf_init(struct ltelf *lte, struct library *lib)
{
+
+ /* Check for ABIv2 in ELF header processor specific flag. */
+#ifndef EF_PPC64_ABI
+ assert (! (lte->ehdr.e_flags & 3 ) == 2)
+#else
+ lte->arch.elfv2_abi=((lte->ehdr.e_flags & EF_PPC64_ABI) == 2) ;
+#endif
+
if (lte->ehdr.e_machine == EM_PPC64
+ && !lte->arch.elfv2_abi
&& load_opd_data(lte, lib) < 0)
return -1;
@@ -599,7 +626,7 @@ read_plt_slot_value(struct process *proc, GElf_Addr addr, GElf_Addr *valp)
uint64_t l;
/* XXX double cast. */
if (proc_read_64(proc, (arch_addr_t)(uintptr_t)addr, &l) < 0) {
- fprintf(stderr, "ptrace .plt slot value @%#" PRIx64": %s\n",
+ debug(DEBUG_EVENT, "ptrace .plt slot value @%#" PRIx64": %s",
addr, strerror(errno));
return -1;
}
@@ -616,7 +643,7 @@ unresolve_plt_slot(struct process *proc, GElf_Addr addr, GElf_Addr value)
* pointers intact. Hence the only adjustment that we need to
* do is to IP. */
if (ptrace(PTRACE_POKETEXT, proc->pid, addr, value) < 0) {
- fprintf(stderr, "failed to unresolve .plt slot: %s\n",
+ debug(DEBUG_EVENT, "failed to unresolve .plt slot: %s",
strerror(errno));
return -1;
}
@@ -629,9 +656,48 @@ arch_elf_add_func_entry(struct process *proc, struct ltelf *lte,
arch_addr_t addr, const char *name,
struct library_symbol **ret)
{
- if (lte->ehdr.e_machine != EM_PPC || lte->ehdr.e_type == ET_DYN)
+#ifndef PPC64_LOCAL_ENTRY_OFFSET
+ assert(! lte->arch.elfv2_abi);
+#else
+ /* With ABIv2 st_other field contains an offset. */
+ if (lte->arch.elfv2_abi)
+ addr += PPC64_LOCAL_ENTRY_OFFSET(sym->st_other);
+#endif
+
+ int st_info = GELF_ST_TYPE(sym->st_info);
+
+ if ((lte->ehdr.e_machine != EM_PPC && sym->st_other == 0)
+ || lte->ehdr.e_type == ET_DYN
+ || (st_info == STT_FUNC && ! sym->st_other))
return PLT_DEFAULT;
+ if (st_info == STT_FUNC) {
+ /* Put the default symbol to the chain.
+ * The addr has already been updated with
+ * symbol offset */
+ char *full_name = strdup(name);
+ if (full_name == NULL) {
+ fprintf(stderr, "couldn't copy name of %s: %s\n",
+ name, strerror(errno));
+ free(full_name);
+ return PLT_FAIL;
+ }
+ struct library_symbol *libsym = malloc(sizeof *libsym);
+ if (libsym == NULL
+ || library_symbol_init(libsym, addr, full_name, 1,
+ LS_TOPLT_NONE) < 0) {
+ free(libsym);
+ delete_symbol_chain(libsym);
+ libsym = NULL;
+ fprintf(stderr, "Couldn't add symbol %s"
+ "for tracing.\n", name);
+ }
+ full_name = NULL;
+ libsym->next = *ret;
+ *ret = libsym;
+ return PLT_OK;
+ }
+
bool ifunc = false;
#ifdef STT_GNU_IFUNC
ifunc = GELF_ST_TYPE(sym->st_info) == STT_GNU_IFUNC;
@@ -761,9 +827,15 @@ arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
assert(plt_slot_addr >= lte->plt_addr
|| plt_slot_addr < lte->plt_addr + lte->plt_size);
+ /* Should avoid to do read if dynamic linker hasn't run yet
+ * or allow -1 a valid return code. */
GElf_Addr plt_slot_value;
- if (read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value) < 0)
- goto fail;
+ if (read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value) < 0) {
+ if (!lte->arch.elfv2_abi)
+ goto fail;
+ else
+ return PPC_PLT_UNRESOLVED;
+ }
struct library_symbol *libsym = malloc(sizeof(*libsym));
if (libsym == NULL) {
@@ -997,8 +1069,12 @@ ppc_plt_bp_continue(struct breakpoint *bp, struct process *proc)
return;
}
+#if _CALL_ELF == 2
+ continue_after_breakpoint(proc, bp);
+#else
jump_to_entry_point(proc, bp);
continue_process(proc->pid);
+#endif
return;
case PPC64_PLT_STUB:
@@ -1123,7 +1199,11 @@ arch_library_symbol_init(struct library_symbol *libsym)
/* We set type explicitly in the code above, where we have the
* necessary context. This is for calls from ltrace-elf.c and
* such. */
+#if _CALL_ELF == 2
+ libsym->arch.type = PPC_PLT_UNRESOLVED;
+#else
libsym->arch.type = PPC_DEFAULT;
+#endif
return 0;
}
diff --git a/sysdeps/linux-gnu/ppc/trace.c b/sysdeps/linux-gnu/ppc/trace.c
index ee9a6b5..5aab538 100644
--- a/sysdeps/linux-gnu/ppc/trace.c
+++ b/sysdeps/linux-gnu/ppc/trace.c
@@ -65,9 +65,15 @@ syscall_p(struct process *proc, int status, int *sysnum)
if (WIFSTOPPED(status)
&& WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
long pc = (long)get_instruction_pointer(proc);
+#ifndef __LITTLE_ENDIAN__
int insn =
(int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(long),
0);
+#else
+ int insn =
+ (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(int),
+ 0);
+#endif
if (insn == SYSCALL_INSN) {
*sysnum =
diff -up ltrace-0.7.91/sysdeps/linux-gnu/ppc/trace.c\~ ltrace-0.7.91/sysdeps/linux-gnu/ppc/trace.c
--- ltrace-0.7.91/sysdeps/linux-gnu/ppc/trace.c~ 2014-08-08 14:05:58.000000000 +0200
+++ ltrace-0.7.91/sysdeps/linux-gnu/ppc/trace.c 2014-08-08 14:07:55.000000000 +0200
@@ -133,7 +133,11 @@ arch_sw_singlestep(struct process *proc,
return SWS_FAIL;
uint32_t insn;
#ifdef __powerpc64__
+# ifdef __LITTLE_ENDIAN__
+ insn = (uint32_t) l;
+# else
insn = l >> 32;
+# endif
#else
insn = l;
#endif
diff -up ltrace-0.7.91/configure\~ ltrace-0.7.91/configure
--- ltrace-0.7.91/configure~ 2014-08-08 14:09:12.000000000 +0200
+++ ltrace-0.7.91/configure 2014-08-08 14:18:30.000000000 +0200
@@ -2555,7 +2555,7 @@ case "${host_cpu}" in
arm*|sa110) HOST_CPU="arm" ;;
cris*) HOST_CPU="cris" ;;
mips*) HOST_CPU="mips" ;;
- powerpc|powerpc64) HOST_CPU="ppc" ;;
+ powerpc|powerpc64|powerpc64le) HOST_CPU="ppc" ;;
sun4u|sparc64) HOST_CPU="sparc" ;;
s390x) HOST_CPU="s390" ;;
i?86|x86_64) HOST_CPU="x86" ;;
@@ -12094,7 +12094,7 @@ if test x"$enable_libunwind" = xyes; the
arm*|sa110) UNWIND_ARCH="arm" ;;
i?86) UNWIND_ARCH="x86" ;;
powerpc) UNWIND_ARCH="ppc32" ;;
- powerpc64) UNWIND_ARCH="ppc64" ;;
+ powerpc64|powerpc64le) UNWIND_ARCH="ppc64" ;;
mips*) UNWIND_ARCH="mips" ;;
*) UNWIND_ARCH="${host_cpu}" ;;
esac

@ -0,0 +1,16 @@
diff -rup a/expr.c b/expr.c
--- a/expr.c 2013-10-10 08:43:55.000000000 -0400
+++ b/expr.c 2020-02-06 17:05:40.658679755 -0500
@@ -189,10 +189,10 @@ int
expr_clone(struct expr_node *retp, const struct expr_node *node)
{
*retp = *node;
+ struct expr_node *nlhs;
+ struct expr_node *nrhs = NULL;
switch (node->kind) {
- struct expr_node *nlhs;
- struct expr_node *nrhs;
case EXPR_OP_ARGNO:
case EXPR_OP_SELF:

@ -0,0 +1,69 @@
@@ -, +, @@
exe->mount("source", "target", "filesystemtype", 0, nil <unfinished ...>
mount@SYS("", "target", "filesystemtype", 0, nil) = -2
<... mount resumed> = -1
---
sysdeps/linux-gnu/s390/fetch.c | 17 ++++++++++++-----
1 files changed, 12 insertions(+), 5 deletions(-)
--- a/sysdeps/linux-gnu/s390/fetch.c
+++ a/sysdeps/linux-gnu/s390/fetch.c
@@ -23,6 +23,7 @@
#include <sys/ucontext.h>
#include <assert.h>
#include <errno.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -61,7 +62,8 @@ s390x(struct fetch_context *ctx)
}
static int
-fetch_register_banks(struct process *proc, struct fetch_context *ctx)
+fetch_register_banks(struct process *proc, struct fetch_context *ctx,
+ bool syscall_enter)
{
ptrace_area parea;
parea.len = sizeof(ctx->regs);
@@ -72,15 +74,20 @@ fetch_register_banks(struct process *proc, struct fetch_context *ctx)
strerror(errno));
return -1;
}
+
+ if (syscall_enter)
+ ctx->regs.gprs[2] = ctx->regs.orig_gpr2;
+
return 0;
}
static int
-fetch_context_init(struct process *proc, struct fetch_context *context)
+fetch_context_init(struct process *proc, struct fetch_context *context,
+ bool syscall_enter)
{
context->greg = 2;
context->freg = 0;
- return fetch_register_banks(proc, context);
+ return fetch_register_banks(proc, context, syscall_enter);
}
struct fetch_context *
@@ -89,7 +96,7 @@ arch_fetch_arg_init(enum tof type, struct process *proc,
{
struct fetch_context *context = malloc(sizeof(*context));
if (context == NULL
- || fetch_context_init(proc, context) < 0) {
+ || fetch_context_init(proc, context, type == LT_TOF_SYSCALL) < 0) {
fprintf(stderr, "arch_fetch_arg_init: %s\n",
strerror(errno));
free(context);
@@ -277,7 +284,7 @@ arch_fetch_retval(struct fetch_context *ctx, enum tof type,
return 0;
}
- if (fetch_context_init(proc, ctx) < 0)
+ if (fetch_context_init(proc, ctx, false) < 0)
return -1;
return arch_fetch_arg_next(ctx, type, proc, info, valuep);
}
--

@ -0,0 +1,67 @@
@@ -, +, @@
---
sysdeps/linux-gnu/s390/arch.h | 2 ++
sysdeps/linux-gnu/s390/plt.c | 22 ++++++++++++++++++++++
2 files changed, 24 insertions(+)
--- a/sysdeps/linux-gnu/s390/arch.h
+++ a/sysdeps/linux-gnu/s390/arch.h
@@ -1,5 +1,6 @@
/*
* This file is part of ltrace.
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
* Copyright (C) 2001 IBM Poughkeepsie, IBM Corporation
*
* This program is free software; you can redistribute it and/or
@@ -25,6 +26,7 @@
#define ARCH_HAVE_FETCH_ARG
#define ARCH_HAVE_SIZEOF
#define ARCH_HAVE_ALIGNOF
+#define ARCH_HAVE_ADD_PLT_ENTRY
#define LT_ELFCLASS ELFCLASS32
#define LT_ELF_MACHINE EM_S390
--- a/sysdeps/linux-gnu/s390/plt.c
+++ a/sysdeps/linux-gnu/s390/plt.c
@@ -1,5 +1,6 @@
/*
* This file is part of ltrace.
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
* Copyright (C) 2004,2008,2009 Juan Cespedes
*
* This program is free software; you can redistribute it and/or
@@ -19,9 +20,12 @@
*/
#include <gelf.h>
+#include <stdbool.h>
+
#include "proc.h"
#include "common.h"
#include "library.h"
+#include "trace.h"
GElf_Addr
arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
@@ -33,3 +37,21 @@ sym2addr(struct process *proc, struct library_symbol *sym)
{
return sym->enter_addr;
}
+
+enum plt_status
+arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
+ const char *a_name, GElf_Rela *rela, size_t ndx,
+ struct library_symbol **ret)
+{
+#ifdef R_390_IRELATIVE
+ bool irelative = GELF_R_TYPE(rela->r_info) == R_390_IRELATIVE;
+#else
+ bool irelative = false;
+#endif
+
+ if (irelative)
+ return linux_elf_add_plt_entry_irelative(proc, lte, rela,
+ ndx, ret);
+
+ return PLT_DEFAULT;
+}
--

@ -0,0 +1,96 @@
diff -r -U3 -p ltrace-0.7.91.orig/filter.c ltrace-0.7.91.dj/filter.c
--- ltrace-0.7.91.orig/filter.c 2012-12-16 20:53:44.000000000 -0500
+++ ltrace-0.7.91.dj/filter.c 2016-06-17 19:07:23.678490985 -0400
@@ -79,7 +79,7 @@ filter_lib_matcher_name_init(struct filt
{
switch (type) {
case FLM_MAIN:
- assert(type != type);
+ //assert(type != type);
abort();
case FLM_SONAME:
@@ -137,7 +137,7 @@ matcher_matches_library(struct filter_li
case FLM_MAIN:
return lib->type == LT_LIBTYPE_MAIN;
}
- assert(matcher->type != matcher->type);
+ //assert(matcher->type != matcher->type);
abort();
}
Only in ltrace-0.7.91.dj/: filter.c~
diff -r -U3 -p ltrace-0.7.91.orig/sysdeps/linux-gnu/proc.c ltrace-0.7.91.dj/sysdeps/linux-gnu/proc.c
--- ltrace-0.7.91.orig/sysdeps/linux-gnu/proc.c 2013-10-11 15:27:11.000000000 -0400
+++ ltrace-0.7.91.dj/sysdeps/linux-gnu/proc.c 2016-06-17 18:59:42.333774042 -0400
@@ -242,9 +242,10 @@ process_tasks(pid_t pid, pid_t **ret_tas
size_t alloc = 0;
while (1) {
- struct dirent entry;
struct dirent *result;
- if (readdir_r(d, &entry, &result) != 0) {
+ errno = 0;
+ result = readdir(d);
+ if (result == NULL && errno != 0) {
fail:
free(tasks);
closedir(d);
Only in ltrace-0.7.91.dj/sysdeps/linux-gnu: proc.c~
diff -r -U3 -p ltrace-0.7.91.orig/sysdeps/linux-gnu/x86/fetch.c ltrace-0.7.91.dj/sysdeps/linux-gnu/x86/fetch.c
--- ltrace-0.7.91.orig/sysdeps/linux-gnu/x86/fetch.c 2013-10-24 08:33:35.000000000 -0400
+++ ltrace-0.7.91.dj/sysdeps/linux-gnu/x86/fetch.c 2016-06-17 18:52:33.962842191 -0400
@@ -523,7 +523,7 @@ classify(struct process *proc, struct fe
default:
/* Unsupported type. */
- assert(info->type != info->type);
+ //assert(info->type != info->type);
abort();
}
abort();
Only in ltrace-0.7.91.dj/sysdeps/linux-gnu/x86: fetch.c~
diff -r -U3 -p ltrace-0.7.91.orig/sysdeps/linux-gnu/x86/trace.c ltrace-0.7.91.dj/sysdeps/linux-gnu/x86/trace.c
--- ltrace-0.7.91.orig/sysdeps/linux-gnu/x86/trace.c 2012-12-16 20:53:45.000000000 -0500
+++ ltrace-0.7.91.dj/sysdeps/linux-gnu/x86/trace.c 2016-06-17 18:52:16.699844065 -0400
@@ -145,7 +145,7 @@ arch_type_sizeof(struct process *proc, s
return (size_t)-2;
default:
- assert(info->type != info->type);
+ //assert(info->type != info->type);
abort();
}
}
@@ -158,7 +158,7 @@ arch_type_alignof(struct process *proc,
switch (info->type) {
default:
- assert(info->type != info->type);
+ //assert(info->type != info->type);
abort();
break;
Only in ltrace-0.7.91.dj/sysdeps/linux-gnu/x86: trace.c~
diff -r -U3 -p ltrace-0.7.91.orig/value.c ltrace-0.7.91.dj/value.c
--- ltrace-0.7.91.orig/value.c 2013-10-10 08:43:55.000000000 -0400
+++ ltrace-0.7.91.dj/value.c 2016-06-17 19:11:43.441047589 -0400
@@ -363,7 +363,7 @@ value_set_word(struct value *value, long
u.u64 = word;
break;
default:
- assert(sz != sz);
+ //assert(sz != sz);
abort();
}
@@ -414,7 +414,7 @@ value_extract_word(struct value *value,
*retp = (long)u.u64;
return 0;
default:
- assert(sz != sz);
+ //assert(sz != sz);
abort();
}
}
Only in ltrace-0.7.91.dj/: value.c~

@ -0,0 +1,48 @@
From 57dbe34ea7aa54b97e11406e1cfb2e427a68779e Mon Sep 17 00:00:00 2001
From: Petr Machata <pmachata@redhat.com>
Date: Wed, 8 Apr 2015 16:04:13 +0200
Subject: [PATCH] Fix warnings in compilation of test-suite cases
---
testsuite/ltrace.main/signals.c | 5 +++--
testsuite/ltrace.minor/wchar.exp | 3 ++-
testsuite/ltrace.torture/signals.c | 5 +++--
3 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/testsuite/ltrace.main/signals.c b/testsuite/ltrace.main/signals.c
index a02e795..ab23fc7 100644
--- a/testsuite/ltrace.main/signals.c
+++ b/testsuite/ltrace.main/signals.c
@@ -2,9 +2,10 @@
Objectives : Verify that ltrace can trace user defined signal.
This file was written by Yao Qi <qiyao@cn.ibm.com>. */
-#include<stdio.h>
-#include<signal.h>
+#include <stdio.h>
+#include <signal.h>
#include <sys/types.h>
+#include <unistd.h>
#define LOOP 7
diff --git a/testsuite/ltrace.torture/signals.c b/testsuite/ltrace.torture/signals.c
index b786c81..c66416e 100644
--- a/testsuite/ltrace.torture/signals.c
+++ b/testsuite/ltrace.torture/signals.c
@@ -2,9 +2,10 @@
Objectives : Verify that ltrace can trace user defined signal.
This file was written by Yao Qi <qiyao@cn.ibm.com>. */
-#include<stdio.h>
-#include<signal.h>
+#include <stdio.h>
+#include <signal.h>
#include <sys/types.h>
+#include <unistd.h>
#define LOOP 20
--
2.3.5

@ -0,0 +1,216 @@
From 694d19ff14017926454771cbb63a22355b72f1bf Mon Sep 17 00:00:00 2001
From: Faraz Shahbazker <faraz.shahbazker@imgtec.com>
Date: Tue, 3 Feb 2015 13:07:55 -0800
Subject: [PATCH] Fix missing includes and return statements in test sources
Fix warnings while compiling test cases by adding missing #includes and
return statements. Missing arguments provided for functions wait()/wcswidth()
---
testsuite/ltrace.main/filters.exp | 1 +
testsuite/ltrace.main/main-internal.exp | 4 +++-
testsuite/ltrace.main/main-threaded.c | 1 +
testsuite/ltrace.main/parameters.c | 1 +
testsuite/ltrace.main/parameters2.exp | 2 +-
testsuite/ltrace.main/parameters3.exp | 2 ++
testsuite/ltrace.main/system_call_params.exp | 4 ++++
testsuite/ltrace.minor/attach-process.exp | 1 +
testsuite/ltrace.minor/libdl-simple.c | 2 ++
testsuite/ltrace.minor/time-record.c | 1 +
testsuite/ltrace.minor/trace-clone.c | 2 ++
testsuite/ltrace.minor/trace-fork.c | 4 +++-
testsuite/ltrace.minor/wchar.exp | 3 ++-
testsuite/ltrace.torture/vfork-thread.c | 1 +
14 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/testsuite/ltrace.main/filters.exp b/testsuite/ltrace.main/filters.exp
index 988346f..f7f4140 100644
--- a/testsuite/ltrace.main/filters.exp
+++ b/testsuite/ltrace.main/filters.exp
@@ -22,6 +22,7 @@ set libfilt1 [ltraceCompile libfilt1.so [ltraceSource c {
}]]
set libfilt2 [ltraceCompile libfilt2.so [ltraceSource c {
+ #include <stdio.h>
void func2(void) { puts("func2"); }
}]]
diff --git a/testsuite/ltrace.main/main-internal.exp b/testsuite/ltrace.main/main-internal.exp
index 0ca5e14..112c69b 100644
--- a/testsuite/ltrace.main/main-internal.exp
+++ b/testsuite/ltrace.main/main-internal.exp
@@ -19,11 +19,13 @@
set bin [ltraceCompile {} [ltraceSource c {
__attribute__((noinline)) void this(void) {}
__attribute__((noinline)) void that(void) {}
- int main(int i) {
+ int main() {
+ int i;
for (i = 0; i < 12; ++i) {
this();
that();
}
+ return 0;
}
}]]
diff --git a/testsuite/ltrace.main/parameters.c b/testsuite/ltrace.main/parameters.c
index a3d8bb5..aa862b9 100644
--- a/testsuite/ltrace.main/parameters.c
+++ b/testsuite/ltrace.main/parameters.c
@@ -17,6 +17,7 @@ void func_intptr_ret(int *i);
int func_strlen(char*);
void func_strfixed(char*);
void func_ppp(int***);
+void func_string(char*);
void func_stringp(char**);
void func_short(short, short);
void func_ushort(unsigned short, unsigned short);
diff --git a/testsuite/ltrace.main/parameters2.exp b/testsuite/ltrace.main/parameters2.exp
index 9850079..1c7b3b4 100644
--- a/testsuite/ltrace.main/parameters2.exp
+++ b/testsuite/ltrace.main/parameters2.exp
@@ -17,7 +17,7 @@
# 02110-1301 USA
set trivial [ltraceCompile {} [ltraceSource c {
- int main(void) {}
+ int main(void) {return 0;}
}]]
ltraceMatch1 [ltraceRun -L -F [ltraceSource conf {
diff --git a/testsuite/ltrace.main/parameters3.exp b/testsuite/ltrace.main/parameters3.exp
index 693c219..f6d9116 100644
--- a/testsuite/ltrace.main/parameters3.exp
+++ b/testsuite/ltrace.main/parameters3.exp
@@ -29,8 +29,10 @@ set liba [ltraceCompile liba.so [ltraceSource c {
}]]
set bin [ltraceCompile {} $liba [ltraceSource c {
+ extern void fun(void);
int main(void) {
fun();
+ return 0;
}
}]]
diff --git a/testsuite/ltrace.main/system_call_params.exp b/testsuite/ltrace.main/system_call_params.exp
index 2ccf840..f3a55d2 100644
--- a/testsuite/ltrace.main/system_call_params.exp
+++ b/testsuite/ltrace.main/system_call_params.exp
@@ -17,12 +17,15 @@
# 02110-1301 USA
set bin [ltraceCompile {} [ltraceSource c {
+ #ifndef _GNU_SOURCE
#define _GNU_SOURCE
+ #endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/syscall.h> /* For SYS_xxx definitions */
+ #include <sys/mount.h>
#ifndef SYS_open
# if defined(__aarch64__)
@@ -38,6 +41,7 @@ set bin [ltraceCompile {} [ltraceSource c {
syscall(SYS_open, "/some/path", O_RDONLY);
write(1, "something", 10);
mount("source", "target", "filesystemtype", 0, 0);
+ return 0;
}
}]]
diff --git a/testsuite/ltrace.minor/attach-process.exp b/testsuite/ltrace.minor/attach-process.exp
index 2c7d20c..c050f21 100644
--- a/testsuite/ltrace.minor/attach-process.exp
+++ b/testsuite/ltrace.minor/attach-process.exp
@@ -21,6 +21,7 @@ set bin [ltraceCompile {} [ltraceSource c {
int main(void) {
sleep(5);
sleep(1);
+ return 0;
}
}]]
diff --git a/testsuite/ltrace.minor/libdl-simple.c b/testsuite/ltrace.minor/libdl-simple.c
index 0bef5cf..b1be002 100644
--- a/testsuite/ltrace.minor/libdl-simple.c
+++ b/testsuite/ltrace.minor/libdl-simple.c
@@ -1,6 +1,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
+#include <string.h>
int main(int argc, char **argv) {
void *handle;
@@ -21,4 +22,5 @@ int main(int argc, char **argv) {
printf("%d\n", test(5));
dlclose(handle);
+ return 0;
}
diff --git a/testsuite/ltrace.minor/time-record.c b/testsuite/ltrace.minor/time-record.c
index a66b838..7d5e5e3 100644
--- a/testsuite/ltrace.minor/time-record.c
+++ b/testsuite/ltrace.minor/time-record.c
@@ -5,6 +5,7 @@
This file was written by Yao Qi <qiyao@cn.ibm.com>. */
#include <stdio.h>
#include <time.h>
+#include <unistd.h>
#define SLEEP_COUNT 2
#define NANOSLEEP_COUNT 50
diff --git a/testsuite/ltrace.minor/trace-clone.c b/testsuite/ltrace.minor/trace-clone.c
index ded930c..6aab235 100644
--- a/testsuite/ltrace.minor/trace-clone.c
+++ b/testsuite/ltrace.minor/trace-clone.c
@@ -3,7 +3,9 @@
clone called.
This file was written by Yao Qi <qiyao@cn.ibm.com>. */
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
diff --git a/testsuite/ltrace.minor/trace-fork.c b/testsuite/ltrace.minor/trace-fork.c
index c5f0c71..9611184 100644
--- a/testsuite/ltrace.minor/trace-fork.c
+++ b/testsuite/ltrace.minor/trace-fork.c
@@ -6,6 +6,8 @@
#include <stdio.h>
#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
void
child ()
@@ -27,7 +29,7 @@ main ()
else
{
printf("My child pid is %d\n",pid);
- wait();
+ wait(NULL);
}
return 0;
}
diff --git a/testsuite/ltrace.torture/vfork-thread.c b/testsuite/ltrace.torture/vfork-thread.c
index f909bd3..4c118a6 100644
--- a/testsuite/ltrace.torture/vfork-thread.c
+++ b/testsuite/ltrace.torture/vfork-thread.c
@@ -13,6 +13,7 @@ routine (void *data)
puts ("bleble");
sleep (1);
}
+ return NULL;
}
--
2.1.0

@ -0,0 +1,68 @@
diff -rup a/testsuite/Makefile.am b/testsuite/Makefile.am
--- a/testsuite/Makefile.am 2012-12-16 20:53:45.000000000 -0500
+++ b/testsuite/Makefile.am 2019-06-28 16:59:19.935602953 -0400
@@ -39,6 +39,7 @@ env.exp: Makefile
rm -f env.exp
echo set libelf_LD_LIBRARY_PATH '"$(libelf_LD_LIBRARY_PATH)"' >> $@
echo set libunwind_LD_LIBRARY_PATH '"$(libunwind_LD_LIBRARY_PATH)"' >> $@
+ echo set PREFIX '"$(prefix)"' >> $@
CLEANFILES = *.o *.so *.log *.sum *.ltrace site.bak setval.tmp site.exp env.exp
diff -rup a/testsuite/Makefile.in b/testsuite/Makefile.in
--- a/testsuite/Makefile.in 2013-11-04 20:22:47.000000000 -0500
+++ b/testsuite/Makefile.in 2019-06-28 16:59:12.075602806 -0400
@@ -648,6 +648,7 @@ env.exp: Makefile
rm -f env.exp
echo set libelf_LD_LIBRARY_PATH '"$(libelf_LD_LIBRARY_PATH)"' >> $@
echo set libunwind_LD_LIBRARY_PATH '"$(libunwind_LD_LIBRARY_PATH)"' >> $@
+ echo set PREFIX '"$(prefix)"' >> $@
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff -rup a/testsuite/ltrace.main/system_call_params.exp b/testsuite/ltrace.main/system_call_params.exp
--- a/testsuite/ltrace.main/system_call_params.exp 2019-06-28 16:44:07.542584754 -0400
+++ b/testsuite/ltrace.main/system_call_params.exp 2019-06-28 17:00:35.811604355 -0400
@@ -1,5 +1,5 @@
# This file is part of ltrace.
-# Copyright (C) 2013, 2014 Petr Machata, Red Hat Inc.
+# Copyright (C) 2013, 2014, 2015 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
@@ -60,8 +60,35 @@ set conf [ltraceNamedSource "$dir/syscal
# somelib.conf is passed, and syscalls.conf is not available, or
# doesn't list readdir, that would be taken from somelib.conf with a
# wrong prototype.
+#
+# This test relies on the fact that there is no global config file
+# that would provide legitimate system call prototypes. But that
+# doesn't have to be true, maybe ltrace is already installed on the
+# system with the right prefix. So first compile a wrapper that we
+# use to redirect fopen calls.
+
+set libfopen_so [ltraceCompile libfopen.so -ldl \
+ [ltraceSource c [string map [list "@PREFIX@" "$PREFIX"] {
+ #define _GNU_SOURCE
+ #include <dlfcn.h>
+ #include <stdio.h>
+ #include <string.h>
+
+ FILE *
+ fopen(const char *path, const char *mode)
+ {
+ #define PATH "@PREFIX@/share"
+ if (strncmp(path, PATH, sizeof(PATH) - 1) == 0)
+ path = "/dev/null";
+ return ((FILE *(*)(const char *, const char *))
+ dlsym(RTLD_NEXT, "fopen")) (path, mode);
+ }
+}]]]
+
+setenv LD_PRELOAD $libfopen_so
ltraceMatch1 [ltraceRun -L -S -F $conf -- $bin] {^open@SYS\("/some/path", 0\)} == 0
+unsetenv LD_PRELOAD
# On the other hand, if -F somedir/ is given, we want to accept
# syscalls.conf found there.

@ -0,0 +1,422 @@
Common subdirectories: ltrace-0.7.91/config and ltrace-0.7.91-pm/config
diff -u ltrace-0.7.91/configure.ac ltrace-0.7.91-pm/configure.ac
--- ltrace-0.7.91/configure.ac 2015-01-09 00:38:17.977190726 +0100
+++ ltrace-0.7.91-pm/configure.ac 2015-01-09 00:37:40.261910548 +0100
@@ -128,6 +128,51 @@
AC_CHECK_HEADERS(selinux/selinux.h)
AC_CHECK_LIB(selinux, security_get_boolean_active)
+dnl Whether (and which) elfutils libdw.so to use for unwinding.
+AC_ARG_WITH(elfutils,
+ AS_HELP_STRING([--with-elfutils], [Use elfutils libdwfl unwinding support]),
+ [case "${withval}" in
+ (yes|no) enable_elfutils=$withval;;
+ (*) enable_elfutils=yes
+ AM_CPPFLAGS="${AM_CPPFLAGS} -I${withval}/include"
+ AM_LDFLAGS="${AM_LDFLAGS} -L${withval}/lib"
+ elfutils_LD_LIBRARY_PATH="${withval}/lib:${withval}/lib/elfutils"
+ ;;
+esac],[enable_elfutils=maybe])
+
+dnl Check whether we have the elfutils libdwfl.h header installed.
+saved_CPPFLAGS="${CPPFLAGS}"
+CPPFLAGS="${CPPFLAGS} ${AM_CPPFLAGS}"
+AC_CHECK_HEADERS([elfutils/libdwfl.h],[have_libdwfl_h=yes])
+CPPFLAGS="${saved_CPPFLAGS}"
+
+dnl And whether libdw.so provides the unwinding functions.
+saved_LDFLAGS="${LDFLAGS}"
+LDFLAGS="${LDFLAGS} ${AM_LDFLAGS}"
+AC_CHECK_LIB([dw], [dwfl_getthread_frames], [have_libdw_dwfl_frames=yes])
+LDFLAGS="${saved_LDFLAGS}"
+
+AC_MSG_CHECKING([whether to use elfutils libdwfl unwinding support])
+case "${enable_elfutils}" in
+(yes|maybe)
+ if test x$have_libdwfl_h = xyes -a x$have_libdw_dwfl_frames = xyes; then
+ enable_elfutils=yes
+ elif test $enable_elfutils = maybe; then
+ enable_elfutils=no
+ else
+ AC_MSG_RESULT([$enable_elfutils])
+ AC_MSG_ERROR([Missing elfutils/libdwfl.h or dwfl_getthread_frames not in libdw.so])
+ fi
+ ;;
+(*) ;;
+esac
+AC_MSG_RESULT([$enable_elfutils])
+
+if test x"$enable_elfutils" = xyes; then
+ libdw_LIBS=-ldw
+ AC_SUBST(libdw_LIBS)
+ AC_DEFINE([HAVE_LIBDW], [1], [we have elfutils libdw])
+fi
# HAVE_LIBUNWIND
AC_ARG_WITH(libunwind,
@@ -193,6 +238,13 @@
LDFLAGS="${saved_LDFLAGS}"
fi
+if test x"$enable_elfutils" = xyes -a x"$enable_libunwind" = xyes; then
+ AC_MSG_ERROR([Cannot enable both --with-libunwind and --with-elfutils])
+fi
+
+if test x"$enable_elfutils" = xyes -o x"$enable_libunwind" = xyes; then
+ AC_DEFINE([HAVE_UNWINDER], [1], [we have an unwinder available])
+fi
saved_CPPFLAGS="${CPPFLAGS}"
saved_LDFLAGS="${LDFLAGS}"
@@ -340,6 +392,7 @@
AC_SUBST(AM_CFLAGS)
AC_SUBST(AM_LDFLAGS)
AC_SUBST(libelf_LD_LIBRARY_PATH)
+AC_SUBST(elfutils_LD_LIBRARY_PATH)
AC_SUBST(libunwind_LD_LIBRARY_PATH)
AC_CONFIG_FILES([
Common subdirectories: ltrace-0.7.91/debian and ltrace-0.7.91-pm/debian
Common subdirectories: ltrace-0.7.91/etc and ltrace-0.7.91-pm/etc
diff -u ltrace-0.7.91/ltrace.1 ltrace-0.7.91-pm/ltrace.1
--- ltrace-0.7.91/ltrace.1 2015-01-09 00:38:17.975190764 +0100
+++ ltrace-0.7.91-pm/ltrace.1 2015-01-09 00:37:40.261910548 +0100
@@ -196,7 +196,8 @@
correct execution of setuid and/or setgid binaries.
.IP "\-w, --where \fInr"
Show backtrace of \fInr\fR stack frames for each traced function. This
-option enabled only if libunwind support was enabled at compile time.
+option enabled only if elfutils or libunwind support was enabled at compile
+time.
.IP "\-x \fIfilter"
A qualifying expression which modifies which symbol table entry points
to trace. The format of the filter expression is described in the
Only in ltrace-0.7.91-pm/: ltrace.1.orig
diff -u ltrace-0.7.91/Makefile.am ltrace-0.7.91-pm/Makefile.am
--- ltrace-0.7.91/Makefile.am 2015-01-09 00:38:17.965190955 +0100
+++ ltrace-0.7.91-pm/Makefile.am 2015-01-09 00:37:40.260910568 +0100
@@ -40,6 +40,7 @@
$(liberty_LIBS) \
$(libsupcxx_LIBS) \
$(libstdcxx_LIBS) \
+ $(libdw_LIBS) \
$(libunwind_LIBS) \
sysdeps/libos.la
diff -u ltrace-0.7.91/options.c ltrace-0.7.91-pm/options.c
--- ltrace-0.7.91/options.c 2015-01-09 00:38:17.974190783 +0100
+++ ltrace-0.7.91-pm/options.c 2015-01-09 00:37:40.261910548 +0100
@@ -107,9 +107,9 @@
" -T show the time spent inside each call.\n"
" -u USERNAME run command with the userid, groupid of username.\n"
" -V, --version output version information and exit.\n"
-#if defined(HAVE_LIBUNWIND)
+#if defined(HAVE_UNWINDER)
" -w, --where=NR print backtrace showing NR stack frames at most.\n"
-#endif /* defined(HAVE_LIBUNWIND) */
+#endif /* defined(HAVE_UNWINDER) */
" -x FILTER modify which static functions to trace.\n"
"\nReport bugs to ltrace-devel@lists.alioth.debian.org\n",
progname);
@@ -519,9 +519,9 @@
progname = argv[0];
options.output = stderr;
options.no_signals = 0;
-#if defined(HAVE_LIBUNWIND)
+#if defined(HAVE_UNWINDER)
options.bt_depth = -1;
-#endif /* defined(HAVE_LIBUNWIND) */
+#endif /* defined(HAVE_UNWINDER) */
guess_cols();
@@ -545,9 +545,9 @@
{"output", 1, 0, 'o'},
{"version", 0, 0, 'V'},
{"no-signals", 0, 0, 'b'},
-# if defined(HAVE_LIBUNWIND)
+# if defined(HAVE_UNWINDER)
{"where", 1, 0, 'w'},
-# endif /* defined(HAVE_LIBUNWIND) */
+# endif /* defined(HAVE_UNWINDER) */
{0, 0, 0, 0}
};
#endif
@@ -556,7 +556,7 @@
#ifdef USE_DEMANGLE
"C"
#endif
-#if defined(HAVE_LIBUNWIND)
+#if defined(HAVE_UNWINDER)
"w:"
#endif
"cfhiLrStTVba:A:D:e:F:l:n:o:p:s:u:x:X:";
@@ -681,11 +681,11 @@
"There is NO WARRANTY, to the extent permitted by law.\n");
exit(0);
break;
-#if defined(HAVE_LIBUNWIND)
+#if defined(HAVE_UNWINDER)
case 'w':
options.bt_depth = parse_int(optarg, 'w', 1, 0);
break;
-#endif /* defined(HAVE_LIBUNWIND) */
+#endif /* defined(HAVE_UNWINDER) */
case 'x':
parse_filter_chain(optarg, &options.static_filter);
Only in ltrace-0.7.91-pm/: options.c.orig
diff -u ltrace-0.7.91/options.h ltrace-0.7.91-pm/options.h
--- ltrace-0.7.91/options.h 2015-01-09 00:38:17.966190936 +0100
+++ ltrace-0.7.91-pm/options.h 2015-01-09 00:37:40.261910548 +0100
@@ -44,9 +44,9 @@
size_t strlen; /* default maximum # of bytes printed in strings */
int follow; /* trace child processes */
int no_signals; /* don't print signals */
-#if defined(HAVE_LIBUNWIND)
+#if defined(HAVE_UNWINDER)
int bt_depth; /* how may levels of stack frames to show */
-#endif /* defined(HAVE_LIBUNWIND) */
+#endif /* defined(HAVE_UNWINDER) */
struct filter *plt_filter;
struct filter *static_filter;
diff -u ltrace-0.7.91/output.c ltrace-0.7.91-pm/output.c
--- ltrace-0.7.91/output.c 2015-01-09 00:38:17.966190936 +0100
+++ ltrace-0.7.91-pm/output.c 2015-01-09 00:37:40.261910548 +0100
@@ -33,6 +33,7 @@
#include <unistd.h>
#include <errno.h>
#include <assert.h>
+#include <inttypes.h>
#include "output.h"
#include "demangle.h"
@@ -567,6 +568,73 @@
stel->out.need_delim = need_delim;
}
+#if defined(HAVE_LIBDW)
+/* Prints information about one frame of a thread. Called by
+ dwfl_getthread_frames in output_right. Returns 1 when done (max
+ number of frames reached). Returns -1 on error. Returns 0 on
+ success (if there are more frames in the thread, call us again). */
+static int
+frame_callback (Dwfl_Frame *state, void *arg)
+{
+ Dwarf_Addr pc;
+ bool isactivation;
+
+ int *frames = (int *) arg;
+
+ if (!dwfl_frame_pc(state, &pc, &isactivation))
+ return -1;
+
+ if (!isactivation)
+ pc--;
+
+ Dwfl *dwfl = dwfl_thread_dwfl(dwfl_frame_thread(state));
+ Dwfl_Module *mod = dwfl_addrmodule(dwfl, pc);
+ const char *modname = NULL;
+ const char *symname = NULL;
+ GElf_Off off = 0;
+ if (mod != NULL) {
+ GElf_Sym sym;
+ modname = dwfl_module_info(mod, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ symname = dwfl_module_addrinfo(mod, pc, &off, &sym,
+ NULL, NULL, NULL);
+ }
+
+ /* This mimics the output produced by libunwind below. */
+ fprintf(options.output, " > %s(%s+0x%" PRIx64 ") [%" PRIx64 "]\n",
+ modname, symname, off, pc);
+
+ /* See if we can extract the source line too and print it on
+ the next line if we can find it. */
+ if (mod != NULL) {
+ Dwfl_Line *l = dwfl_module_getsrc(mod, pc);
+ if (l != NULL) {
+ int line, col;
+ line = col = -1;
+ const char *src = dwfl_lineinfo(l, NULL, &line, &col,
+ NULL, NULL);
+ if (src != NULL) {
+ fprintf(options.output, "\t%s", src);
+ if (line > 0) {
+ fprintf(options.output, ":%d", line);
+ if (col > 0)
+ fprintf(options.output,
+ ":%d", col);
+ }
+ fprintf(options.output, "\n");
+ }
+
+ }
+ }
+
+ /* Max number of frames to print reached? */
+ if ((*frames)-- == 0)
+ return 1;
+
+ return 0;
+}
+#endif /* defined(HAVE_LIBDW) */
+
void
output_right(enum tof type, struct process *proc, struct library_symbol *libsym,
struct timedelta *spent)
@@ -694,6 +762,24 @@
}
#endif /* defined(HAVE_LIBUNWIND) */
+#if defined(HAVE_LIBDW)
+ if (options.bt_depth > 0 && proc->leader->dwfl != NULL) {
+ int frames = options.bt_depth;
+ if (dwfl_getthread_frames(proc->leader->dwfl, proc->pid,
+ frame_callback, &frames) < 0) {
+ // Only print an error if we couldn't show anything.
+ // Otherwise just show there might be more...
+ if (frames == options.bt_depth)
+ fprintf(stderr,
+ "dwfl_getthread_frames tid %d: %s\n",
+ proc->pid, dwfl_errmsg(-1));
+ else
+ fprintf(options.output, " > [...]\n");
+ }
+ fprintf(options.output, "\n");
+ }
+#endif /* defined(HAVE_LIBDW) */
+
current_proc = NULL;
current_column = 0;
}
Only in ltrace-0.7.91-pm/: output.c.orig
diff -u ltrace-0.7.91/proc.c ltrace-0.7.91-pm/proc.c
--- ltrace-0.7.91/proc.c 2015-01-09 00:38:17.981190650 +0100
+++ ltrace-0.7.91-pm/proc.c 2015-01-09 00:37:40.261910548 +0100
@@ -111,6 +111,11 @@
if (proc->unwind_as != NULL)
unw_destroy_addr_space(proc->unwind_as);
#endif /* defined(HAVE_LIBUNWIND) */
+
+#if defined(HAVE_LIBDW)
+ if (proc->dwfl != NULL)
+ dwfl_end(proc->dwfl);
+#endif /* defined(HAVE_LIBDW) */
}
static int
@@ -172,6 +177,10 @@
}
#endif /* defined(HAVE_LIBUNWIND) */
+#if defined(HAVE_LIBDW)
+ proc->dwfl = NULL; /* Initialize for leader only on first library. */
+#endif /* defined(HAVE_LIBDW) */
+
return 0;
}
@@ -887,6 +896,59 @@
debug(DEBUG_PROCESS, "added library %s@%p (%s) to %d",
lib->soname, lib->base, lib->pathname, proc->pid);
+#if defined(HAVE_LIBDW)
+ if (options.bt_depth > 0) {
+ /* Setup module tracking for libdwfl unwinding. */
+ struct process *leader = proc->leader;
+ Dwfl *dwfl = leader->dwfl;
+ if (dwfl == NULL) {
+ static const Dwfl_Callbacks proc_callbacks = {
+ .find_elf = dwfl_linux_proc_find_elf,
+ .find_debuginfo = dwfl_standard_find_debuginfo
+ };
+ dwfl = dwfl_begin(&proc_callbacks);
+ if (dwfl == NULL)
+ fprintf(stderr,
+ "Couldn't initialize libdwfl unwinding "
+ "for process %d: %s\n", leader->pid,
+ dwfl_errmsg (-1));
+ }
+
+ if (dwfl != NULL) {
+ dwfl_report_begin_add(dwfl);
+ if (dwfl_report_elf(dwfl, lib->soname,
+ lib->pathname, -1,
+ (GElf_Addr) lib->base,
+ false) == NULL)
+ fprintf(stderr,
+ "dwfl_report_elf %s@%p (%s) %d: %s\n",
+ lib->soname, lib->base, lib->pathname,
+ proc->pid, dwfl_errmsg (-1));
+ dwfl_report_end(dwfl, NULL, NULL);
+
+ if (leader->dwfl == NULL) {
+ int r = dwfl_linux_proc_attach(dwfl,
+ leader->pid,
+ true);
+ if (r == 0)
+ leader->dwfl = dwfl;
+ else {
+ const char *msg;
+ dwfl_end(dwfl);
+ if (r < 0)
+ msg = dwfl_errmsg(-1);
+ else
+ msg = strerror(r);
+ fprintf(stderr, "Couldn't initialize "
+ "libdwfl unwinding for "
+ "process %d: %s\n",
+ leader->pid, msg);
+ }
+ }
+ }
+ }
+#endif /* defined(HAVE_LIBDW) */
+
/* Insert breakpoints for all active (non-latent) symbols. */
struct library_symbol *libsym = NULL;
while ((libsym = library_each_symbol(lib, libsym,
diff -u ltrace-0.7.91/proc.c.orig ltrace-0.7.91-pm/proc.c.orig
--- ltrace-0.7.91/proc.h 2015-01-09 00:38:17.966190936 +0100
+++ ltrace-0.7.91-pm/proc.h 2015-01-09 00:37:40.261910548 +0100
@@ -28,6 +28,10 @@
#include <sys/time.h>
#include <stdint.h>
+#if defined(HAVE_LIBDW)
+# include <elfutils/libdwfl.h>
+#endif
+
#if defined(HAVE_LIBUNWIND)
# include <libunwind.h>
#endif /* defined(HAVE_LIBUNWIND) */
@@ -113,6 +117,11 @@
short e_machine;
char e_class;
+#if defined(HAVE_LIBDW)
+ /* Unwind info for leader, NULL for non-leader procs. */
+ Dwfl *dwfl;
+#endif /* defined(HAVE_LIBDW) */
+
#if defined(HAVE_LIBUNWIND)
/* libunwind address space */
unw_addr_space_t unwind_as;
Only in ltrace-0.7.91-pm/: proc.h.orig
Common subdirectories: ltrace-0.7.91/sysdeps and ltrace-0.7.91-pm/sysdeps
Common subdirectories: ltrace-0.7.91/testsuite and ltrace-0.7.91-pm/testsuite
diff -up ltrace-0.7.91/proc.c\~ ltrace-0.7.91/proc.c
--- ltrace-0.7.91/proc.c~ 2015-01-09 01:55:38.289864078 +0100
+++ ltrace-0.7.91/proc.c 2015-01-09 01:56:29.818881935 +0100
@@ -918,7 +918,8 @@ proc_add_library(struct process *proc, s
dwfl_report_begin_add(dwfl);
if (dwfl_report_elf(dwfl, lib->soname,
lib->pathname, -1,
- (GElf_Addr) lib->base,
+ /* XXX double cast */
+ (GElf_Addr) (uintptr_t) lib->base,
false) == NULL)
fprintf(stderr,
"dwfl_report_elf %s@%p (%s) %d: %s\n",

@ -0,0 +1,101 @@
From fba95ad936f1d8c1052259bae811f1fc07f9a215 Mon Sep 17 00:00:00 2001
From: Petr Machata <pmachata@redhat.com>
Date: Thu, 30 Oct 2014 01:48:17 +0100
Subject: [PATCH] Initialize the PLT slot map correctly on x86 and x86_64
The PLT slot map translates relocation numbers to PLT slot numbers,
but was actually initialized in the opposite direction. Fix the way
it's initialized. This bug can be seen on glibc in particular:
$ ltrace -e free ls
libc.so.6->free(0x5) = <void>
libc.so.6->free(0x78) = <void>
libc.so.6->free(0xc) = <void>
libc.so.6->free(0x308) = <void>
Note the nonsense values passed to free. The problem is that these
are not free calls at all, but malloc calls that are assigned to wrong
PLT slots due to above bug.
---
sysdeps/linux-gnu/x86/plt.c | 38 +++++++++++++++++++++-----------------
1 file changed, 21 insertions(+), 17 deletions(-)
diff --git a/sysdeps/linux-gnu/x86/plt.c b/sysdeps/linux-gnu/x86/plt.c
index c860af6..97f6c3e 100644
--- a/sysdeps/linux-gnu/x86/plt.c
+++ b/sysdeps/linux-gnu/x86/plt.c
@@ -77,6 +77,18 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
{
VECT_INIT(&lte->arch.plt_map, unsigned int);
+ if (vect_reserve(&lte->arch.plt_map, vect_size(&lte->plt_relocs)) < 0) {
+ fail:
+ arch_elf_destroy(lte);
+ return -1;
+ }
+
+ {
+ unsigned int i, sz = vect_size(&lte->plt_relocs);
+ for (i = 0; i < sz; ++i)
+ vect_pushback (&lte->arch.plt_map, &i);
+ }
+
/* IRELATIVE slots may make the whole situation a fair deal
* more complex. On x86{,_64}, the PLT slots are not
* presented in the order of the corresponding relocations,
@@ -114,43 +126,35 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
/* Here we scan the PLT table and initialize a map of
* relocation->slot number in lte->arch.plt_map. */
- size_t i;
- for (i = 0; i < vect_size(&lte->plt_relocs); ++i) {
+ unsigned int i, sz = vect_size(&lte->plt_relocs);
+ for (i = 0; i < sz; ++i) {
GElf_Addr offset = x86_plt_offset(i);
- uint32_t reloc_arg = 0;
uint8_t byte;
if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
|| byte != 0xff
|| elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
|| (byte != 0xa3 && byte != 0x25))
- goto next;
+ continue;
/* Skip immediate argument in the instruction. */
offset += 4;
+ uint32_t reloc_arg;
if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
|| byte != 0x68
|| elf_read_next_u32(lte->plt_data,
- &offset, &reloc_arg) < 0) {
- reloc_arg = 0;
- goto next;
- }
+ &offset, &reloc_arg) < 0)
+ continue;
if (lte->ehdr.e_machine == EM_386) {
- if (reloc_arg % 8 != 0) {
- reloc_arg = 0;
- goto next;
- }
+ if (reloc_arg % 8 != 0)
+ continue;
reloc_arg /= 8;
}
- next:
- if (VECT_PUSHBACK(&lte->arch.plt_map, &reloc_arg) < 0) {
- arch_elf_destroy(lte);
- return -1;
- }
+ *VECT_ELEMENT(&lte->arch.plt_map, unsigned int, reloc_arg) = i;
}
return 0;
--
2.1.0

@ -0,0 +1,32 @@
From e16a28f1b6e5a15368f8ed98dc29a6da714dc5fa Mon Sep 17 00:00:00 2001
From: Petr Machata <pmachata@redhat.com>
Date: Tue, 9 Dec 2014 17:44:30 +0100
Subject: [PATCH] Drop unused label in x86 backend
---
sysdeps/linux-gnu/x86/plt.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/sysdeps/linux-gnu/x86/plt.c b/sysdeps/linux-gnu/x86/plt.c
index 97f6c3e..44ea260 100644
--- a/sysdeps/linux-gnu/x86/plt.c
+++ b/sysdeps/linux-gnu/x86/plt.c
@@ -1,6 +1,6 @@
/*
* This file is part of ltrace.
- * Copyright (C) 2013 Petr Machata, Red Hat Inc.
+ * Copyright (C) 2013,2014 Petr Machata, Red Hat Inc.
* Copyright (C) 2004,2008,2009 Juan Cespedes
*
* This program is free software; you can redistribute it and/or
@@ -78,7 +78,6 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
VECT_INIT(&lte->arch.plt_map, unsigned int);
if (vect_reserve(&lte->arch.plt_map, vect_size(&lte->plt_relocs)) < 0) {
- fail:
arch_elf_destroy(lte);
return -1;
}
--
2.1.0

@ -0,0 +1,156 @@
@@ -, +, @@
relocation
- In general they are. But IRELATIVE relocations are sorted to come
last, and PLT entries are not sorted accordingly.
---
sysdeps/linux-gnu/x86/arch.h | 11 +++++
sysdeps/linux-gnu/x86/plt.c | 101 +++++++++++++++++++++++++++++++++++++++++-
2 files changed, 111 insertions(+), 1 deletions(-)
--- a/sysdeps/linux-gnu/x86/arch.h
+++ a/sysdeps/linux-gnu/x86/arch.h
@@ -19,6 +19,10 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
+#ifndef LTRACE_X86_ARCH_H
+#define LTRACE_X86_ARCH_H
+
+#include "vect.h"
#define BREAKPOINT_VALUE {0xcc}
#define BREAKPOINT_LENGTH 1
@@ -30,9 +34,16 @@
#define ARCH_HAVE_ADD_PLT_ENTRY
+#define ARCH_HAVE_LTELF_DATA
+struct arch_ltelf_data {
+ struct vect plt_map;
+};
+
#ifdef __x86_64__
#define LT_ELFCLASS ELFCLASS64
#define LT_ELF_MACHINE EM_X86_64
#endif
#define LT_ELFCLASS2 ELFCLASS32
#define LT_ELF_MACHINE2 EM_386
+
+#endif /* LTRACE_X86_ARCH_H */
--- a/sysdeps/linux-gnu/x86/plt.c
+++ a/sysdeps/linux-gnu/x86/plt.c
@@ -27,10 +27,19 @@
#include "library.h"
#include "trace.h"
+static GElf_Addr
+x86_plt_offset(uint32_t i)
+{
+ /* Skip the first PLT entry, which contains a stub to call the
+ * resolver. */
+ return (i + 1) * 16;
+}
+
GElf_Addr
arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela)
{
- return lte->plt_addr + (ndx + 1) * 16;
+ uint32_t i = *VECT_ELEMENT(&lte->arch.plt_map, uint32_t, ndx);
+ return x86_plt_offset(i) + lte->plt_addr;
}
void *
@@ -62,3 +71,93 @@ arch_elf_add_plt_entry(struct process *proc, struct ltelf *lte,
return PLT_DEFAULT;
}
+
+int
+arch_elf_init(struct ltelf *lte, struct library *lib)
+{
+ VECT_INIT(&lte->arch.plt_map, unsigned int);
+
+ /* IRELATIVE slots may make the whole situation a fair deal
+ * more complex. On x86{,_64}, the PLT slots are not
+ * presented in the order of the corresponding relocations,
+ * but in the order it which these symbols are in the symbol
+ * table. That's static symbol table, which may be stripped
+ * off, not dynsym--that doesn't contain IFUNC symbols at all.
+ * So we have to decode each PLT entry to figure out what
+ * entry it corresponds to. We need to interpret the PLT
+ * table to figure this out.
+ *
+ * On i386, the PLT entry format is as follows:
+ *
+ * 8048300: ff 25 0c a0 04 08 jmp *0x804a00c
+ * 8048306: 68 20 00 00 00 push $0x20
+ * 804830b: e9 e0 ff ff ff jmp 80482f0 <_init+0x30>
+ *
+ * For PIE binaries it is the following:
+ *
+ * 410: ff a3 10 00 00 00 jmp *0x10(%ebx)
+ * 416: 68 00 00 00 00 push $0x0
+ * 41b: e9 d0 ff ff ff jmp 3f0 <_init+0x30>
+ *
+ * On x86_64, it is:
+ *
+ * 400420: ff 25 f2 0b 20 00 jmpq *0x200bf2(%rip) # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
+ * 400426: 68 00 00 00 00 pushq $0x0
+ * 40042b: e9 e0 ff ff ff jmpq 400410 <_init+0x18>
+ *
+ * On i386, the argument to push is an offset of relocation to
+ * use. The first PLT slot has an offset of 0x0, the second
+ * 0x8, etc. On x86_64, it's directly the index that we are
+ * looking for.
+ */
+
+ /* Here we scan the PLT table and initialize a map of
+ * relocation->slot number in lte->arch.plt_map. */
+
+ size_t i;
+ for (i = 0; i < vect_size(&lte->plt_relocs); ++i) {
+
+ GElf_Addr offset = x86_plt_offset(i);
+ uint32_t reloc_arg = 0;
+
+ uint8_t byte;
+ if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
+ || byte != 0xff
+ || elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
+ || (byte != 0xa3 && byte != 0x25))
+ goto next;
+
+ /* Skip immediate argument in the instruction. */
+ offset += 4;
+
+ if (elf_read_next_u8(lte->plt_data, &offset, &byte) < 0
+ || byte != 0x68
+ || elf_read_next_u32(lte->plt_data,
+ &offset, &reloc_arg) < 0) {
+ reloc_arg = 0;
+ goto next;
+ }
+
+ if (lte->ehdr.e_machine == EM_386) {
+ if (reloc_arg % 8 != 0) {
+ reloc_arg = 0;
+ goto next;
+ }
+ reloc_arg /= 8;
+ }
+
+ next:
+ if (VECT_PUSHBACK(&lte->arch.plt_map, &reloc_arg) < 0) {
+ arch_elf_destroy(lte);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+void
+arch_elf_destroy(struct ltelf *lte)
+{
+ VECT_DESTROY(&lte->arch.plt_map, uint32_t, NULL, NULL);
+}
--

@ -0,0 +1,12 @@
diff -Nrup a/testsuite/ltrace.minor/trace-irelative.exp b/testsuite/ltrace.minor/trace-irelative.exp
--- a/testsuite/ltrace.minor/trace-irelative.exp 2013-11-04 18:08:03.000000000 -0700
+++ b/testsuite/ltrace.minor/trace-irelative.exp 2015-06-01 12:30:59.737371166 -0600
@@ -54,6 +54,8 @@ set src [ltraceSource c {
}]
foreach ext {{} .pie} {
+ # ltrace does not yet support AARCH64's ifuncs
+ setup_xfail aarch64*-*-*
set bin1 [ltraceCompile $ext $src]
do_tests $bin1 ""
}

@ -0,0 +1,12 @@
diff -Nrup a/testsuite/ltrace.main/system_calls.exp b/testsuite/ltrace.main/system_calls.exp
--- a/testsuite/ltrace.main/system_calls.exp 2016-02-17 19:39:51.433134376 -0700
+++ b/testsuite/ltrace.main/system_calls.exp 2016-02-17 19:40:26.220402747 -0700
@@ -133,7 +133,7 @@ Match [Diff [Calls [ltraceRun -L -S -- $
{ {^write$} == 1 }
{ {^unlink(at)?$} >= 2 }
{ {^open(at)?$} == 1 }
- { {^(new|f)?stat(64)?$} == 1 }
+ { {^(new|f)?stat(64)?$} >= 1 }
{ {^close$} == 1 }
{ {^getcwd$} == 1 }
{ {^chdir$} == 1 }

@ -0,0 +1,20 @@
diff -Nrup a/sysdeps/linux-gnu/arm/trace.c b/sysdeps/linux-gnu/arm/trace.c
--- a/sysdeps/linux-gnu/arm/trace.c 2013-03-11 17:23:39.000000000 -0600
+++ b/sysdeps/linux-gnu/arm/trace.c 2017-02-17 09:39:42.233547101 -0700
@@ -155,6 +155,8 @@ arm_get_next_pcs(struct process *proc,
const unsigned cond = BITS(this_instr, 28, 31);
const unsigned opcode = BITS(this_instr, 24, 27);
+ uint32_t operand1, operand2, result = 0;
+
if (cond == COND_NV)
switch (opcode) {
arch_addr_t addr;
@@ -170,7 +172,6 @@ arm_get_next_pcs(struct process *proc,
}
else
switch (opcode) {
- uint32_t operand1, operand2, result = 0;
case 0x0:
case 0x1: /* data processing */
case 0x2:

@ -0,0 +1,210 @@
%global __python /usr/bin/python3
%{?scl:%{?scl_package:%scl_package ltrace}}
Summary: Tracks runtime library calls from dynamically linked executables
Name: %{?scl_prefix}ltrace
Version: 0.7.91
Release: 1%{?dist}
URL: http://ltrace.alioth.debian.org/
License: GPLv2+
BuildRequires: elfutils-devel dejagnu
BuildRequires: libselinux-devel
BuildRequires: autoconf automake libtool
BuildRequires: gcc-c++
BuildRequires: make
# Note: this URL needs to be updated for each release, as the file
# number changes for each file. Full list of released files is at:
# https://alioth.debian.org/frs/?group_id=30892
Source: ltrace-%{version}.tar.bz2
# Merge of several upstream commits that fixes compilation on ARM.
Patch0: ltrace-0.7.91-arm.patch
# Upstream patch that fixes accounting of exec, __libc_start_main and
# others in -c output.
Patch1: ltrace-0.7.91-account_execl.patch
# Upstream patch that fixes interpretation of PLT on x86_64 when
# IRELATIVE slots are present.
Patch2: ltrace-0.7.91-x86_64-irelative.patch
# Upstream patch that fixes fetching of system call arguments on s390.
Patch3: ltrace-0.7.91-s390-fetch-syscall.patch
# Upstream patch that enables tracing of IRELATIVE PLT slots on s390.
Patch4: ltrace-0.7.91-s390-irelative.patch
# Fix for a regression in tracing across fork. Upstream patch.
Patch5: ltrace-0.7.91-ppc64-fork.patch
# Fix crashing a prelinked PPC64 binary which makes PLT calls through
# slots that ltrace doesn't trace.
# https://bugzilla.redhat.com/show_bug.cgi?id=1051221
Patch6: ltrace-0.7.91-breakpoint-on_install.patch
Patch7: ltrace-0.7.91-ppc64-unprelink.patch
# Man page nits. Backport of an upstream patch.
Patch8: ltrace-0.7.91-man.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1044766
Patch9: ltrace-0.7.91-cant_open.patch
# Support Aarch64 architecture.
Patch10: ltrace-0.7.91-aarch64.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1064406
Patch11: ltrace-0.7.2-e_machine.patch
# Support for ppc64le, backported from upstream.
# http://anonscm.debian.org/gitweb/?p=collab-maint/ltrace.git;a=commit;h=eea4ad2cce289753aaa35b4e0258a76d8f8f367c
# https://bugzilla.redhat.com/show_bug.cgi?id=1131956
Patch13: ltrace-0.7.91-ppc64le-support.patch
# 35a9677dc9dcb7909ebd28f30200474d7e8b660f,
# 437d2377119036346f4dbd93039c847b4cc9d0be,
# eb3993420734f091cde9a6053ca6b4edcf9ae334
Patch14: ltrace-0.7.91-ppc64le-fixes.patch
# http://anonscm.debian.org/gitweb/?p=collab-maint/ltrace.git;a=commit;h=2e9f9f1f5d0fb223b109429b9c904504b7f638e2
# http://anonscm.debian.org/gitweb/?p=collab-maint/ltrace.git;a=commit;h=f96635a03b3868057db5c2d7972d5533e2068345
Patch15: ltrace-0.7.91-parser-ws_after_id.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1171165
# http://anonscm.debian.org/cgit/collab-maint/ltrace.git/commit/?id=d8f1287b85e2c2b2ae0235809e956f4365e53c45
# http://anonscm.debian.org/cgit/collab-maint/ltrace.git/commit/?id=d80c5371454383e3f9978622e5578cf02af8c44c
# http://anonscm.debian.org/cgit/collab-maint/ltrace.git/commit/?id=bf82100966deda9c7d26ad085d97c08126a8ae88
Patch16: ltrace-0.7.91-ppc-bias.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1158714
Patch17: ltrace-0.7.91-x86-plt_map.patch
Patch18: ltrace-0.7.91-x86-unused_label.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1170315
Patch19: ltrace-0.7.91-unwind-elfutils.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1208351
# http://anonscm.debian.org/cgit/collab-maint/ltrace.git/commit/?id=4724bd5a4a19db117a1d280b9d1a3508fd4e03fa
# http://anonscm.debian.org/cgit/collab-maint/ltrace.git/commit/?id=72ee29639c55b5942bc07c8ed0013005f8fc5a97
Patch20: ltrace-0.7.91-multithread-no-f-1.patch
Patch21: ltrace-0.7.91-multithread-no-f-2.patch
# Fix problems with building a number of test cases.
# http://anonscm.debian.org/cgit/collab-maint/ltrace.git/commit/?id=694d19ff14017926454771cbb63a22355b72f1bf
# http://anonscm.debian.org/cgit/collab-maint/ltrace.git/commit/?id=a3a03622fb4ca9772dca13eae724a94ba1e728f4
Patch22: ltrace-0.7.91-testsuite-includes.patch
Patch23: ltrace-0.7.91-testsuite-includes-2.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1210653
# http://anonscm.debian.org/cgit/collab-maint/ltrace.git/commit/?id=eea6091f8672b01f7f022b0fc367e0f568225ffc
Patch24: ltrace-0.7.91-ppc64le-configure.patch
Patch25: ltrace-rh1307754.patch
# GCC now warns (errors) on "tautological compares", and readdir_r is deprecated.
Patch26: ltrace-0.7.91-tautology.patch
# ARM code has unreachable code after switch statement, move initialization
Patch27: ltrace-rh1423913.patch
# AARCH64 large parameters and syscall testsuite fixes.
Patch28: ltrace-0.7.91-aarch64-params.patch
# gcc-9 fix. Avoid passing NULL as argument to %s
Patch29: ltrace-0.7.91-null.patch
# Adds support for CET PLTs via second-plt lookups.
Patch30: ltrace-0.7.91-cet.patch
# Extra #includes for gcc 9
Patch31: ltrace-0.7.91-aarch64-headers.patch
# Testsuite: AARCH64 ifuncs not supported yet yet.
Patch32: ltrace-rh1225568.patch
# testsuite fixes for pre-installed config files
Patch33: ltrace-0.7.91-testsuite-system_call_params.patch
# Ignore bogus files from the environment
Patch34: ltrace-0.7.91-XDG_CONFIG_DIRS.patch
# GCC erroneously warns about uninitialized values
Patch35: ltrace-0.7.91-rh1799619.patch
# Support for both SC and SCV sycall insns
Patch36: ltrace-0.7.91-ppc64le-scv.patch
%description
Ltrace is a debugging program which runs a specified command until the
command exits. While the command is executing, ltrace intercepts and
records both the dynamic library calls called by the executed process
and the signals received by the executed process. Ltrace can also
intercept and print system calls executed by the process.
You should install ltrace if you need a sysadmin tool for tracking the
execution of processes.
%prep
%setup -q -n ltrace-%{version}
%patch0 -p1
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%patch11 -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
%patch30 -p1
%patch31 -p1
%patch32 -p1
%patch33 -p1
%patch34 -p1
%patch35 -p1
%patch36 -p1
%build
autoreconf -i
%configure --docdir=%{?_pkgdocdir}%{!?_pkgdocdir:%{_docdir}/%{name}-%{version}}
make %{?_smp_mflags}
%install
make DESTDIR=$RPM_BUILD_ROOT bindir=%{_bindir} install
# The testsuite is useful for development in real world, but fails in
# koji for some reason. Disable it, but have it handy.
%check
echo ====================TESTING=========================
timeout 180 make -k check ||:
echo ====================TESTING END=====================
%files
%defattr(-,root,root)
%doc NEWS COPYING CREDITS INSTALL README TODO
%{_bindir}/ltrace
%{_mandir}/man1/ltrace.1*
%{_mandir}/man5/ltrace.conf.5*
%{_datadir}/ltrace
%changelog
* Fri Jun 11 2021 DJ Delorie <dj@redhat.com> - 0.7.91-1
- Initial sources (#1954828) for GTS-11
Loading…
Cancel
Save