Compare commits

...

No commits in common. "c8-beta" and "c10s" have entirely different histories.

42 changed files with 5 additions and 5168 deletions

View File

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

1
.gitignore vendored
View File

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

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# Package Not Available
This package is not available on CentOS Stream 10.
It may be available on another branch.

View File

@ -1,20 +0,0 @@
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

View File

@ -1,151 +0,0 @@
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

View File

@ -1,24 +0,0 @@
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"

View File

@ -1,37 +0,0 @@
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

View File

@ -1,834 +0,0 @@
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

View File

@ -1,610 +0,0 @@
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;
}

View File

@ -1,81 +0,0 @@
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

View File

@ -1,36 +0,0 @@
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);

View File

@ -1,121 +0,0 @@
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,

View File

@ -1,45 +0,0 @@
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

View File

@ -1,175 +0,0 @@
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~

View File

@ -1,50 +0,0 @@
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

View File

@ -1,14 +0,0 @@
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. */

View File

@ -1,144 +0,0 @@
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

View File

@ -1,91 +0,0 @@
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;
}

View File

@ -1,52 +0,0 @@
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

View File

@ -1,221 +0,0 @@
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

View File

@ -1,44 +0,0 @@
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

1
dead.package Normal file
View File

@ -0,0 +1 @@
gcc-toolset-11-ltrace package is retired on branch c10s for CS-2551

1
sources Normal file
View File

@ -0,0 +1 @@
SHA512 (ltrace-0.7.91.tar.bz2) = c663ac4dc4c317e296e87b2ae42c8c3716ec34e75c50c49eb97613a82273e40ee81fca773643972b9441dae26c26130a669ff6f630c3236c7797fd7c6a480a94