aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog61
-rw-r--r--Makefile.in32
-rw-r--r--README13
-rw-r--r--aclocal.m4833
-rw-r--r--breakpoints.c115
-rwxr-xr-xconfig.guess43
-rwxr-xr-xconfig.sub45
-rw-r--r--configure.ac43
-rw-r--r--debian/copyright2
-rw-r--r--debug.c139
-rw-r--r--debug.h12
-rw-r--r--demangle.c22
-rw-r--r--dict.c87
-rw-r--r--display_args.c299
-rw-r--r--elf.c703
-rw-r--r--elf.h8
-rw-r--r--etc/ltrace.conf2
-rw-r--r--execute_program.c16
-rwxr-xr-xinstall-sh495
-rw-r--r--ltrace.1114
-rw-r--r--ltrace.c88
-rw-r--r--ltrace.h50
-rw-r--r--ltrace.spec164
-rw-r--r--options.c374
-rw-r--r--options.h2
-rw-r--r--output.c161
-rw-r--r--proc.c35
-rw-r--r--process_event.c339
-rw-r--r--read_config_file.c139
-rw-r--r--summary.c54
-rw-r--r--sysdeps/linux-gnu/Makefile21
-rw-r--r--sysdeps/linux-gnu/alpha/arch.h4
-rw-r--r--sysdeps/linux-gnu/alpha/plt.c10
-rw-r--r--sysdeps/linux-gnu/alpha/regs.c24
-rw-r--r--sysdeps/linux-gnu/alpha/trace.c46
-rw-r--r--sysdeps/linux-gnu/arm/arch.h3
-rw-r--r--sysdeps/linux-gnu/arm/plt.c10
-rw-r--r--sysdeps/linux-gnu/arm/regs.c16
-rw-r--r--sysdeps/linux-gnu/arm/trace.c51
-rw-r--r--sysdeps/linux-gnu/breakpoint.c55
-rw-r--r--sysdeps/linux-gnu/i386/arch.h3
-rw-r--r--sysdeps/linux-gnu/i386/plt.c10
-rw-r--r--sysdeps/linux-gnu/i386/regs.c22
-rw-r--r--sysdeps/linux-gnu/i386/syscallent.h9
-rw-r--r--sysdeps/linux-gnu/i386/trace.c61
-rw-r--r--sysdeps/linux-gnu/ia64/arch.h4
-rw-r--r--sysdeps/linux-gnu/ia64/plt.c5
-rw-r--r--sysdeps/linux-gnu/ia64/syscallent.h21
-rw-r--r--sysdeps/linux-gnu/ia64/trace.c3
-rw-r--r--sysdeps/linux-gnu/m68k/arch.h3
-rw-r--r--sysdeps/linux-gnu/m68k/plt.c12
-rw-r--r--sysdeps/linux-gnu/m68k/regs.c22
-rw-r--r--sysdeps/linux-gnu/m68k/trace.c69
-rw-r--r--sysdeps/linux-gnu/ppc/arch.h12
-rw-r--r--sysdeps/linux-gnu/ppc/plt.c38
-rw-r--r--sysdeps/linux-gnu/ppc/regs.c24
-rw-r--r--sysdeps/linux-gnu/ppc/syscallent.h9
-rw-r--r--sysdeps/linux-gnu/ppc/trace.c44
-rw-r--r--sysdeps/linux-gnu/proc.c10
-rw-r--r--sysdeps/linux-gnu/s390/arch.h10
-rw-r--r--sysdeps/linux-gnu/s390/plt.c11
-rw-r--r--sysdeps/linux-gnu/s390/regs.c50
-rw-r--r--sysdeps/linux-gnu/s390/signalent.h3
-rw-r--r--sysdeps/linux-gnu/s390/signalent1.h1
-rw-r--r--sysdeps/linux-gnu/s390/syscallent.h282
-rw-r--r--sysdeps/linux-gnu/s390/syscallent1.h1
-rw-r--r--sysdeps/linux-gnu/s390/syscalls31.h287
-rw-r--r--sysdeps/linux-gnu/s390/syscalls64.h287
-rw-r--r--sysdeps/linux-gnu/s390/trace.c191
-rw-r--r--sysdeps/linux-gnu/sparc/arch.h4
-rw-r--r--sysdeps/linux-gnu/sparc/plt.c10
-rw-r--r--sysdeps/linux-gnu/sparc/regs.c24
-rw-r--r--sysdeps/linux-gnu/sparc/syscallent.h14
-rw-r--r--sysdeps/linux-gnu/sparc/trace.c36
-rw-r--r--sysdeps/linux-gnu/trace.c156
-rw-r--r--sysdeps/linux-gnu/x86_64/arch.h9
-rw-r--r--sysdeps/linux-gnu/x86_64/plt.c10
-rw-r--r--sysdeps/linux-gnu/x86_64/regs.c36
-rw-r--r--sysdeps/linux-gnu/x86_64/signalent1.h1
-rw-r--r--sysdeps/linux-gnu/x86_64/syscallent.h8
-rw-r--r--sysdeps/linux-gnu/x86_64/syscallent1.h1
-rw-r--r--sysdeps/linux-gnu/x86_64/trace.c120
-rw-r--r--wait_for_something.c49
83 files changed, 4214 insertions, 2498 deletions
diff --git a/ChangeLog b/ChangeLog
deleted file mode 100644
index 9247339..0000000
--- a/ChangeLog
+++ /dev/null
@@ -1,61 +0,0 @@
-2006-02-17 Ian Wienand <ianw@ieee.org>
-
- * sysdeps/linux-gnu/ia64/arch.h: add ia64 support
- * sysdeps/linux-gnu/ia64/breakpoint.c: add
- * sysdeps/linux-gnu/ia64/Makefile: add
- * sysdeps/linux-gnu/ia64/plt.c: add
- * sysdeps/linux-gnu/ia64/ptrace.h: add
- * sysdeps/linux-gnu/ia64/regs.c: add
- * sysdeps/linux-gnu/ia64/signalent.h: add
- * sysdeps/linux-gnu/ia64/syscallent.h: add
- * sysdeps/linux-gnu/ia64/trace.c: add
- * elf.h: add extra field for PLT size
- * elf.c: put in PLT size
- * sysdeps/linux-gnu/breakpoint.c: add arch breakpoint override
- * sysdeps/linux-gnu/trace.c: don't single step after breakpoin for
- ia64
-
- * configure.ac: add version to AC_INIT, bump version to 0.3.38
- * options.c: use PACKAGE_VERSION
-
-2006-02-16 Ian Wienand <ianw@ieee.org>
-
- * Makefile.in: install documentation into share/doc, make dist
- target export latest version from CVS.
-
-2006-02-16 Rajeev V. Pillai <rajeevvp@yahoo.com>
-
- * Makefile.in: pass through CPP and LD FLAGS
-
-2006-02-16 Ian Wienand <ianw@ieee.org>
-
- * read_config_file.c: initialise pt stack argument to stop warning
- * summary.c: make show_summary() obey -C for demangaling function names
-
-2006-02-16 Richard Kettlewell <rjk@nchiper.com>
-
- * display_args.c: update to handle variable length strings
- arguments
- * ltrace.h: likewise
- * output.c: likewise
- * read_config_file.c: likewise
-
-2006-02-16 Bernd Zeimetz <bernd@zeimetz.de>
-
- * ltrace.1: reference reportbug
-
-2006-02-16 Colin S. Miller <csmiller@iname.com>
-
- * ltrace.1: fix debug typo
-
-2006-02-16 Andrew Stribblehill <ads@debian.org>
-
- * etc/ltrace.conf: fix putenv typo
-
-2006-02-16 Ian Wienand <ianw@ieee.org>
-
- * README: update
- * Makefile.in: remove obsolete -I- for -iquote, add TAGS target
- * debug.c, debug.h: __PRETTY_FUNCTION__ is const; change specifier
- to stop warnings.
- * ltrace.1: add a note about not tracing dlopen()ed libraries
diff --git a/Makefile.in b/Makefile.in
index 9e2f525..2191584 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -2,8 +2,6 @@
# ltrace's Makefile.in
#
-VERSION := 0.3.37
-
#OS := $(shell uname -s)
OS := @HOST_OS@
@@ -13,12 +11,12 @@ prefix = @prefix@
sysconfdir = @sysconfdir@
bindir = $(prefix)/bin
mandir = @mandir@
-docdir = $(prefix)/share/doc/ltrace
+docdir = $(prefix)/doc/ltrace
CC = @CC@
-CPPFLAGS = -iquote $(TOPDIR) -I$(TOPDIR)/sysdeps/$(OS) @CPPFLAGS@ @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)\"
CFLAGS = -Wall @CFLAGS@
-LDFLAGS = @LDFLAGS@
+CPPFLAGS = @iquote@$(TOPDIR) @iquote@$(TOPDIR)/sysdeps/$(OS) @iquoteend@ @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)\" @CPPFLAGS@
+LDFLAGS =
LIBS = @LIBS@
INSTALL = @INSTALL@
@@ -32,9 +30,6 @@ OBJ = ltrace.o options.o elf.o output.o read_config_file.o \
display_args.o breakpoints.o proc.o demangle.o dict.o \
debug.o summary.o
-DIST_DIR = $(shell basename `pwd`)
-
-
all: ltrace
ltrace: sysdeps/sysdep.o $(OBJ)
@@ -55,22 +50,8 @@ distclean: clean
realclean: distclean
$(RM) configure config.h.in
-# This goes to the debian CVS server to export the latest version and put it in a tarball.
-# It does NOT make a dist of your current directory
dist: clean
- ( rm -rf dist ; mkdir dist ; cd dist \
- cvs -d:pserver:anonymous@cvs.alioth.debian.org:/cvsroot/ltrace login; \
- cvs -d:pserver:anonymous@cvs.alioth.debian.org:/cvsroot/ltrace export -d ltrace-$(VERSION) -D tomorrow ltrace; \
- cd ltrace-$(VERSION); \
- rm -rf debian; \
- ./autogen.sh; \
- rm autogen.sh; \
- cd ..; \
- tar cfz ltrace-$(VERSION).tar.gz ./ltrace-$(VERSION); \
- mv ltrace-$(VERSION).tar.gz ../; \
- cd ..; \
- rm -rf dist; \
- echo "ALL DONE!" )
+ ( cd .. ; tar zcvf ltrace-`date +%y%m%d`.tgz ltrace )
install: ltrace
$(INSTALL_DIR) $(DESTDIR)$(bindir) $(DESTDIR)$(docdir) $(DESTDIR)$(mandir)/man1
@@ -82,9 +63,6 @@ install: ltrace
dummy:
-TAGS:
- find -name '*.c' -o -name '*.h' | xargs etags -a
-
-.PHONY: all clean distclean dist install dummy TAGS
+.PHONY: all clean distclean dist install dummy
.EXPORT_ALL_VARIABLES:
diff --git a/README b/README
index 02b1c91..4ddbbcd 100644
--- a/README
+++ b/README
@@ -2,7 +2,7 @@
A Dynamic Library Tracer
- Copyright 1997-2006 Juan Cespedes <cespedes@debian.org>
+ Copyright 1997-2005 Juan Cespedes <cespedes@debian.org>
Contents
@@ -31,7 +31,7 @@ people have contributed significantly to this project:
* Jakub Jelinek <jakub@redhat.com> (SPARC port, support for libelf, many fixes)
* Jakub Bogusz <qboosh@pld-linux.org> (alpha port)
* SuSE (amd64 port)
-* Ian Wienand <ianw@gelato.unsw.edu.au> (ia64 port)
+* Ian Wienand <ianw@gelato.unsw.edu.au> (IA64 port)
1. Introduction
---------------
@@ -49,10 +49,6 @@ You may find it at:
Alternatively, you may find it in any Debian mirror. For more info,
see ftp://ftp.debian.org/debian/README.mirrors
-You can also retreive the source via CVS, see
-
-http://ltrace.alioth.debian.org
-
3. How does it work
-------------------
Using software breakpoints, just like gdb.
@@ -68,13 +64,14 @@ It is part of at least Debian GNU/Linux, RedHat, SuSE and Mandrake.
5. Bugs
-------
Too many to list here :). If you like to submit a bug report, or a
-feature request, plase do that against the Debian `ltrace' package
+feature request, either do that against the Debian `ltrace' package,
+or mail ``Juan Cespedes <cespedes@debian.org>''.
This file is very incomplete and out-of-date.
6. License
----------
- Copyright (C) 1997-2006 Juan Cespedes <cespedes@debian.org>
+ Copyright (C) 1997-2005 Juan Cespedes <cespedes@debian.org>
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
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..abe07e0
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,833 @@
+dnl aclocal.m4t generated automatically by aclocal 1.4-p6
+
+dnl Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+# lib-prefix.m4 serial 3 (gettext-0.13)
+dnl Copyright (C) 2001-2003 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License. As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl From Bruno Haible.
+
+dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and
+dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't
+dnl require excessive bracketing.
+ifdef([AC_HELP_STRING],
+[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])],
+[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])])
+
+dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed
+dnl to access previously installed libraries. The basic assumption is that
+dnl a user will want packages to use other packages he previously installed
+dnl with the same --prefix option.
+dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate
+dnl libraries, but is otherwise very convenient.
+AC_DEFUN([AC_LIB_PREFIX],
+[
+ AC_BEFORE([$0], [AC_LIB_LINKFLAGS])
+ AC_REQUIRE([AC_PROG_CC])
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ dnl By default, look in $includedir and $libdir.
+ use_additional=yes
+ AC_LIB_WITH_FINAL_PREFIX([
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+ ])
+ AC_LIB_ARG_WITH([lib-prefix],
+[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib
+ --without-lib-prefix don't search for libraries in includedir and libdir],
+[
+ if test "X$withval" = "Xno"; then
+ use_additional=no
+ else
+ if test "X$withval" = "X"; then
+ AC_LIB_WITH_FINAL_PREFIX([
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+ ])
+ else
+ additional_includedir="$withval/include"
+ additional_libdir="$withval/lib"
+ fi
+ fi
+])
+ if test $use_additional = yes; then
+ dnl Potentially add $additional_includedir to $CPPFLAGS.
+ dnl But don't add it
+ dnl 1. if it's the standard /usr/include,
+ dnl 2. if it's already present in $CPPFLAGS,
+ dnl 3. if it's /usr/local/include and we are using GCC on Linux,
+ dnl 4. if it doesn't exist as a directory.
+ if test "X$additional_includedir" != "X/usr/include"; then
+ haveit=
+ for x in $CPPFLAGS; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-I$additional_includedir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test "X$additional_includedir" = "X/usr/local/include"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ if test -d "$additional_includedir"; then
+ dnl Really add $additional_includedir to $CPPFLAGS.
+ CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir"
+ fi
+ fi
+ fi
+ fi
+ dnl Potentially add $additional_libdir to $LDFLAGS.
+ dnl But don't add it
+ dnl 1. if it's the standard /usr/lib,
+ dnl 2. if it's already present in $LDFLAGS,
+ dnl 3. if it's /usr/local/lib and we are using GCC on Linux,
+ dnl 4. if it doesn't exist as a directory.
+ if test "X$additional_libdir" != "X/usr/lib"; then
+ haveit=
+ for x in $LDFLAGS; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test "X$additional_libdir" = "X/usr/local/lib"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ dnl Really add $additional_libdir to $LDFLAGS.
+ LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir"
+ fi
+ fi
+ fi
+ fi
+ fi
+])
+
+dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix,
+dnl acl_final_exec_prefix, containing the values to which $prefix and
+dnl $exec_prefix will expand at the end of the configure script.
+AC_DEFUN([AC_LIB_PREPARE_PREFIX],
+[
+ dnl Unfortunately, prefix and exec_prefix get only finally determined
+ dnl at the end of configure.
+ if test "X$prefix" = "XNONE"; then
+ acl_final_prefix="$ac_default_prefix"
+ else
+ acl_final_prefix="$prefix"
+ fi
+ if test "X$exec_prefix" = "XNONE"; then
+ acl_final_exec_prefix='${prefix}'
+ else
+ acl_final_exec_prefix="$exec_prefix"
+ fi
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ eval acl_final_exec_prefix=\"$acl_final_exec_prefix\"
+ prefix="$acl_save_prefix"
+])
+
+dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the
+dnl variables prefix and exec_prefix bound to the values they will have
+dnl at the end of the configure script.
+AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX],
+[
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ $1
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+])
+
+# lib-link.m4 serial 4 (gettext-0.12)
+dnl Copyright (C) 2001-2003 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License. As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl From Bruno Haible.
+
+dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and
+dnl augments the CPPFLAGS variable.
+AC_DEFUN([AC_LIB_LINKFLAGS],
+[
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ AC_REQUIRE([AC_LIB_RPATH])
+ define([Name],[translit([$1],[./-], [___])])
+ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+ [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+ AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [
+ AC_LIB_LINKFLAGS_BODY([$1], [$2])
+ ac_cv_lib[]Name[]_libs="$LIB[]NAME"
+ ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME"
+ ac_cv_lib[]Name[]_cppflags="$INC[]NAME"
+ ])
+ LIB[]NAME="$ac_cv_lib[]Name[]_libs"
+ LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs"
+ INC[]NAME="$ac_cv_lib[]Name[]_cppflags"
+ AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+ AC_SUBST([LIB]NAME)
+ AC_SUBST([LTLIB]NAME)
+ dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the
+ dnl results of this search when this library appears as a dependency.
+ HAVE_LIB[]NAME=yes
+ undefine([Name])
+ undefine([NAME])
+])
+
+dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode)
+dnl searches for libname and the libraries corresponding to explicit and
+dnl implicit dependencies, together with the specified include files and
+dnl the ability to compile and link the specified testcode. If found, it
+dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and
+dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and
+dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs
+dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty.
+AC_DEFUN([AC_LIB_HAVE_LINKFLAGS],
+[
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ AC_REQUIRE([AC_LIB_RPATH])
+ define([Name],[translit([$1],[./-], [___])])
+ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+ [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+
+ dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME
+ dnl accordingly.
+ AC_LIB_LINKFLAGS_BODY([$1], [$2])
+
+ dnl Add $INC[]NAME to CPPFLAGS before performing the following checks,
+ dnl because if the user has installed lib[]Name and not disabled its use
+ dnl via --without-lib[]Name-prefix, he wants to use it.
+ ac_save_CPPFLAGS="$CPPFLAGS"
+ AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+
+ AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [
+ ac_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIB[]NAME"
+ AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no])
+ LIBS="$ac_save_LIBS"
+ ])
+ if test "$ac_cv_lib[]Name" = yes; then
+ HAVE_LIB[]NAME=yes
+ AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.])
+ AC_MSG_CHECKING([how to link with lib[]$1])
+ AC_MSG_RESULT([$LIB[]NAME])
+ else
+ HAVE_LIB[]NAME=no
+ dnl If $LIB[]NAME didn't lead to a usable library, we don't need
+ dnl $INC[]NAME either.
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIB[]NAME=
+ LTLIB[]NAME=
+ fi
+ AC_SUBST([HAVE_LIB]NAME)
+ AC_SUBST([LIB]NAME)
+ AC_SUBST([LTLIB]NAME)
+ undefine([Name])
+ undefine([NAME])
+])
+
+dnl Determine the platform dependent parameters needed to use rpath:
+dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator,
+dnl hardcode_direct, hardcode_minus_L.
+AC_DEFUN([AC_LIB_RPATH],
+[
+ AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS
+ AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld
+ AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host
+ AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir
+ AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [
+ CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \
+ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh
+ . ./conftest.sh
+ rm -f ./conftest.sh
+ acl_cv_rpath=done
+ ])
+ wl="$acl_cv_wl"
+ libext="$acl_cv_libext"
+ shlibext="$acl_cv_shlibext"
+ hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec"
+ hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator"
+ hardcode_direct="$acl_cv_hardcode_direct"
+ hardcode_minus_L="$acl_cv_hardcode_minus_L"
+ dnl Determine whether the user wants rpath handling at all.
+ AC_ARG_ENABLE(rpath,
+ [ --disable-rpath do not hardcode runtime library paths],
+ :, enable_rpath=yes)
+])
+
+dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables.
+AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
+[
+ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+ [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+ dnl By default, look in $includedir and $libdir.
+ use_additional=yes
+ AC_LIB_WITH_FINAL_PREFIX([
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+ ])
+ AC_LIB_ARG_WITH([lib$1-prefix],
+[ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib
+ --without-lib$1-prefix don't search for lib$1 in includedir and libdir],
+[
+ if test "X$withval" = "Xno"; then
+ use_additional=no
+ else
+ if test "X$withval" = "X"; then
+ AC_LIB_WITH_FINAL_PREFIX([
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+ ])
+ else
+ additional_includedir="$withval/include"
+ additional_libdir="$withval/lib"
+ fi
+ fi
+])
+ dnl Search the library and its dependencies in $additional_libdir and
+ dnl $LDFLAGS. Using breadth-first-seach.
+ LIB[]NAME=
+ LTLIB[]NAME=
+ INC[]NAME=
+ rpathdirs=
+ ltrpathdirs=
+ names_already_handled=
+ names_next_round='$1 $2'
+ while test -n "$names_next_round"; do
+ names_this_round="$names_next_round"
+ names_next_round=
+ for name in $names_this_round; do
+ already_handled=
+ for n in $names_already_handled; do
+ if test "$n" = "$name"; then
+ already_handled=yes
+ break
+ fi
+ done
+ if test -z "$already_handled"; then
+ names_already_handled="$names_already_handled $name"
+ dnl See if it was already located by an earlier AC_LIB_LINKFLAGS
+ dnl or AC_LIB_HAVE_LINKFLAGS call.
+ uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+ eval value=\"\$HAVE_LIB$uppername\"
+ if test -n "$value"; then
+ if test "$value" = yes; then
+ eval value=\"\$LIB$uppername\"
+ test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value"
+ eval value=\"\$LTLIB$uppername\"
+ test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value"
+ else
+ dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined
+ dnl that this library doesn't exist. So just drop it.
+ :
+ fi
+ else
+ dnl Search the library lib$name in $additional_libdir and $LDFLAGS
+ dnl and the already constructed $LIBNAME/$LTLIBNAME.
+ found_dir=
+ found_la=
+ found_so=
+ found_a=
+ if test $use_additional = yes; then
+ if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then
+ found_dir="$additional_libdir"
+ found_so="$additional_libdir/lib$name.$shlibext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ else
+ if test -f "$additional_libdir/lib$name.$libext"; then
+ found_dir="$additional_libdir"
+ found_a="$additional_libdir/lib$name.$libext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ fi
+ fi
+ fi
+ if test "X$found_dir" = "X"; then
+ for x in $LDFLAGS $LTLIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ case "$x" in
+ -L*)
+ dir=`echo "X$x" | sed -e 's/^X-L//'`
+ if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then
+ found_dir="$dir"
+ found_so="$dir/lib$name.$shlibext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ else
+ if test -f "$dir/lib$name.$libext"; then
+ found_dir="$dir"
+ found_a="$dir/lib$name.$libext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ if test "X$found_dir" != "X"; then
+ break
+ fi
+ done
+ fi
+ if test "X$found_dir" != "X"; then
+ dnl Found the library.
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name"
+ if test "X$found_so" != "X"; then
+ dnl Linking with a shared library. We attempt to hardcode its
+ dnl directory into the executable's runpath, unless it's the
+ dnl standard /usr/lib.
+ if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then
+ dnl No hardcoding is needed.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ else
+ dnl Use an explicit option to hardcode DIR into the resulting
+ dnl binary.
+ dnl Potentially add DIR to ltrpathdirs.
+ dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $found_dir"
+ fi
+ dnl The hardcoding into $LIBNAME is system dependent.
+ if test "$hardcode_direct" = yes; then
+ dnl Using DIR/libNAME.so during linking hardcodes DIR into the
+ dnl resulting binary.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ else
+ if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+ dnl Use an explicit option to hardcode DIR into the resulting
+ dnl binary.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ dnl Potentially add DIR to rpathdirs.
+ dnl The rpathdirs will be appended to $LIBNAME at the end.
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $found_dir"
+ fi
+ else
+ dnl Rely on "-L$found_dir".
+ dnl But don't add it if it's already contained in the LDFLAGS
+ dnl or the already constructed $LIBNAME
+ haveit=
+ for x in $LDFLAGS $LIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir"
+ fi
+ if test "$hardcode_minus_L" != no; then
+ dnl FIXME: Not sure whether we should use
+ dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+ dnl here.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ else
+ dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH
+ dnl here, because this doesn't fit in flags passed to the
+ dnl compiler. So give up. No hardcoding. This affects only
+ dnl very old systems.
+ dnl FIXME: Not sure whether we should use
+ dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+ dnl here.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+ fi
+ fi
+ fi
+ fi
+ else
+ if test "X$found_a" != "X"; then
+ dnl Linking with a static library.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a"
+ else
+ dnl We shouldn't come here, but anyway it's good to have a
+ dnl fallback.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name"
+ fi
+ fi
+ dnl Assume the include files are nearby.
+ additional_includedir=
+ case "$found_dir" in
+ */lib | */lib/)
+ basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'`
+ additional_includedir="$basedir/include"
+ ;;
+ esac
+ if test "X$additional_includedir" != "X"; then
+ dnl Potentially add $additional_includedir to $INCNAME.
+ dnl But don't add it
+ dnl 1. if it's the standard /usr/include,
+ dnl 2. if it's /usr/local/include and we are using GCC on Linux,
+ dnl 3. if it's already present in $CPPFLAGS or the already
+ dnl constructed $INCNAME,
+ dnl 4. if it doesn't exist as a directory.
+ if test "X$additional_includedir" != "X/usr/include"; then
+ haveit=
+ if test "X$additional_includedir" = "X/usr/local/include"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ for x in $CPPFLAGS $INC[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-I$additional_includedir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_includedir"; then
+ dnl Really add $additional_includedir to $INCNAME.
+ INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir"
+ fi
+ fi
+ fi
+ fi
+ fi
+ dnl Look for dependencies.
+ if test -n "$found_la"; then
+ dnl Read the .la file. It defines the variables
+ dnl dlname, library_names, old_library, dependency_libs, current,
+ dnl age, revision, installed, dlopen, dlpreopen, libdir.
+ save_libdir="$libdir"
+ case "$found_la" in
+ */* | *\\*) . "$found_la" ;;
+ *) . "./$found_la" ;;
+ esac
+ libdir="$save_libdir"
+ dnl We use only dependency_libs.
+ for dep in $dependency_libs; do
+ case "$dep" in
+ -L*)
+ additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+ dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME.
+ dnl But don't add it
+ dnl 1. if it's the standard /usr/lib,
+ dnl 2. if it's /usr/local/lib and we are using GCC on Linux,
+ dnl 3. if it's already present in $LDFLAGS or the already
+ dnl constructed $LIBNAME,
+ dnl 4. if it doesn't exist as a directory.
+ if test "X$additional_libdir" != "X/usr/lib"; then
+ haveit=
+ if test "X$additional_libdir" = "X/usr/local/lib"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ haveit=
+ for x in $LDFLAGS $LIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ dnl Really add $additional_libdir to $LIBNAME.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir"
+ fi
+ fi
+ haveit=
+ for x in $LDFLAGS $LTLIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ dnl Really add $additional_libdir to $LTLIBNAME.
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir"
+ fi
+ fi
+ fi
+ fi
+ ;;
+ -R*)
+ dir=`echo "X$dep" | sed -e 's/^X-R//'`
+ if test "$enable_rpath" != no; then
+ dnl Potentially add DIR to rpathdirs.
+ dnl The rpathdirs will be appended to $LIBNAME at the end.
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $dir"
+ fi
+ dnl Potentially add DIR to ltrpathdirs.
+ dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $dir"
+ fi
+ fi
+ ;;
+ -l*)
+ dnl Handle this in the next round.
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+ ;;
+ *.la)
+ dnl Handle this in the next round. Throw away the .la's
+ dnl directory; it is already contained in a preceding -L
+ dnl option.
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+ ;;
+ *)
+ dnl Most likely an immediate library name.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep"
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep"
+ ;;
+ esac
+ done
+ fi
+ else
+ dnl Didn't find the library; assume it is in the system directories
+ dnl known to the linker and runtime loader. (All the system
+ dnl directories known to the linker should also be known to the
+ dnl runtime loader, otherwise the system is severely misconfigured.)
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name"
+ fi
+ fi
+ fi
+ done
+ done
+ if test "X$rpathdirs" != "X"; then
+ if test -n "$hardcode_libdir_separator"; then
+ dnl Weird platform: only the last -rpath option counts, the user must
+ dnl pass all path elements in one option. We can arrange that for a
+ dnl single library, but not when more than one $LIBNAMEs are used.
+ alldirs=
+ for found_dir in $rpathdirs; do
+ alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+ done
+ dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl.
+ acl_save_libdir="$libdir"
+ libdir="$alldirs"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+ else
+ dnl The -rpath options are cumulative.
+ for found_dir in $rpathdirs; do
+ acl_save_libdir="$libdir"
+ libdir="$found_dir"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+ done
+ fi
+ fi
+ if test "X$ltrpathdirs" != "X"; then
+ dnl When using libtool, the option that works for both libraries and
+ dnl executables is -R. The -R options are cumulative.
+ for found_dir in $ltrpathdirs; do
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir"
+ done
+ fi
+])
+
+dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR,
+dnl unless already present in VAR.
+dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes
+dnl contains two or three consecutive elements that belong together.
+AC_DEFUN([AC_LIB_APPENDTOVAR],
+[
+ for element in [$2]; do
+ haveit=
+ for x in $[$1]; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X$element"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ [$1]="${[$1]}${[$1]:+ }$element"
+ fi
+ done
+])
+
+# lib-ld.m4 serial 3 (gettext-0.13)
+dnl Copyright (C) 1996-2003 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License. As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl Subroutines of libtool.m4,
+dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision
+dnl with libtool.m4.
+
+dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no.
+AC_DEFUN([AC_LIB_PROG_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ acl_cv_prog_gnu_ld=yes ;;
+*)
+ acl_cv_prog_gnu_ld=no ;;
+esac])
+with_gnu_ld=$acl_cv_prog_gnu_ld
+])
+
+dnl From libtool-1.4. Sets the variable LD.
+AC_DEFUN([AC_LIB_PROG_LD],
+[AC_ARG_WITH(gnu-ld,
+[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]],
+test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by GCC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]* | [A-Za-z]:[\\/]*)]
+ [re_direlt='/[^/][^/]*/\.\./']
+ # Canonicalize the path of ld
+ ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
+ while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(acl_cv_path_LD,
+[if test -z "$LD"; then
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ acl_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some GNU ld's only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break ;;
+ *)
+ test "$with_gnu_ld" != yes && break ;;
+ esac
+ fi
+ done
+ IFS="$ac_save_ifs"
+else
+ acl_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$acl_cv_path_LD"
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_LIB_PROG_LD_GNU
+])
+
diff --git a/breakpoints.c b/breakpoints.c
index fbeac81..d9ea6e9 100644
--- a/breakpoints.c
+++ b/breakpoints.c
@@ -18,58 +18,63 @@
/*****************************************************************************/
-struct breakpoint *address2bpstruct(struct process *proc, void *addr)
-{
+struct breakpoint *
+address2bpstruct(struct process * proc, void * addr) {
return dict_find_entry(proc->breakpoints, addr);
}
-void insert_breakpoint(struct process *proc, void *addr)
-{
- struct breakpoint *sbp;
+void
+insert_breakpoint(struct process * proc, void * addr, struct library_symbol * libsym) {
+ struct breakpoint * sbp;
if (!proc->breakpoints) {
- proc->breakpoints =
- dict_init(dict_key2hash_int, dict_key_cmp_int);
- /* atexit(brk_dict_clear); *//* why bother to do this on exit? */
+ proc->breakpoints = dict_init(dict_key2hash_int, dict_key_cmp_int);
+ /* atexit(brk_dict_clear); */ /* why bother to do this on exit? */
}
+
+ if (!addr)
+ return;
+
+ if (libsym)
+ libsym->needs_init = 0;
+
sbp = dict_find_entry(proc->breakpoints, addr);
if (!sbp) {
- sbp = malloc(sizeof(struct breakpoint));
+ sbp = calloc(1, sizeof(struct breakpoint));
if (!sbp) {
- return; /* TODO FIXME XXX: error_mem */
+ return; /* TODO FIXME XXX: error_mem */
}
dict_enter(proc->breakpoints, addr, sbp);
sbp->addr = addr;
- sbp->enabled = 0;
+ sbp->libsym = libsym;
+ if (libsym)
+ libsym->brkpnt = sbp;
}
sbp->enabled++;
- if (sbp->enabled == 1 && proc->pid)
- enable_breakpoint(proc->pid, sbp);
+ if (sbp->enabled==1 && proc->pid) enable_breakpoint(proc->pid, sbp);
}
-void delete_breakpoint(struct process *proc, void *addr)
-{
- struct breakpoint *sbp = dict_find_entry(proc->breakpoints, addr);
- assert(sbp); /* FIXME: remove after debugging has been done. */
+void
+delete_breakpoint(struct process * proc, void * addr) {
+ struct breakpoint * sbp = dict_find_entry(proc->breakpoints, addr);
+ assert(sbp); /* FIXME: remove after debugging has been done. */
/* This should only happen on out-of-memory conditions. */
- if (sbp == NULL)
- return;
+ if (sbp == NULL) return;
sbp->enabled--;
- if (sbp->enabled == 0)
- disable_breakpoint(proc->pid, sbp);
+ if (sbp->enabled == 0) disable_breakpoint(proc->pid, sbp);
assert(sbp->enabled >= 0);
}
-static void enable_bp_cb(void *addr, void *sbp, void *proc)
-{
+static void
+enable_bp_cb(void * addr, void * sbp, void * proc) {
if (((struct breakpoint *)sbp)->enabled) {
enable_breakpoint(((struct process *)proc)->pid, sbp);
}
}
-void enable_all_breakpoints(struct process *proc)
-{
+void
+enable_all_breakpoints(struct process * proc) {
if (proc->breakpoints_enabled <= 0) {
#ifdef __powerpc__
unsigned long a;
@@ -80,8 +85,7 @@ void enable_all_breakpoints(struct process *proc)
* dont enable the breakpoints
*/
if (opt_L) {
- a = ptrace(PTRACE_PEEKTEXT, proc->pid,
- proc->list_of_symbols->enter_addr, 0);
+ a = ptrace(PTRACE_PEEKTEXT, proc->pid, plt2addr(proc, proc->list_of_symbols->enter_addr), 0);
if (a == 0x0)
return;
}
@@ -89,22 +93,21 @@ void enable_all_breakpoints(struct process *proc)
debug(1, "Enabling breakpoints for pid %u...", proc->pid);
if (proc->breakpoints) {
- dict_apply_to_all(proc->breakpoints, enable_bp_cb,
- proc);
+ dict_apply_to_all(proc->breakpoints, enable_bp_cb, proc);
}
}
proc->breakpoints_enabled = 1;
}
-static void disable_bp_cb(void *addr, void *sbp, void *proc)
-{
+static void
+disable_bp_cb(void * addr, void * sbp, void * proc) {
if (((struct breakpoint *)sbp)->enabled) {
disable_breakpoint(((struct process *)proc)->pid, sbp);
}
}
-void disable_all_breakpoints(struct process *proc)
-{
+void
+disable_all_breakpoints(struct process * proc) {
if (proc->breakpoints_enabled) {
debug(1, "Disabling breakpoints for pid %u...", proc->pid);
dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc);
@@ -112,17 +115,17 @@ void disable_all_breakpoints(struct process *proc)
proc->breakpoints_enabled = 0;
}
-static void free_bp_cb(void *addr, void *sbp, void *data)
-{
+static void
+free_bp_cb(void * addr, void * sbp, void * data) {
assert(sbp);
free(sbp);
}
-void breakpoints_init(struct process *proc)
-{
- struct library_symbol *sym;
+void
+breakpoints_init(struct process * proc) {
+ struct library_symbol * sym;
- if (proc->breakpoints) { /* let's remove that struct */
+ if (proc->breakpoints) { /* let's remove that struct */
/* TODO FIXME XXX: free() all "struct breakpoint"s */
dict_apply_to_all(proc->breakpoints, free_bp_cb, NULL);
dict_clear(proc->breakpoints);
@@ -130,14 +133,14 @@ void breakpoints_init(struct process *proc)
}
if (opt_L && proc->filename) {
- proc->list_of_symbols = read_elf(proc->filename);
+ proc->list_of_symbols = read_elf(proc);
if (opt_e) {
- struct library_symbol **tmp1 = &(proc->list_of_symbols);
- while (*tmp1) {
- struct opt_e_t *tmp2 = opt_e;
+ struct library_symbol ** tmp1 = &(proc->list_of_symbols);
+ while(*tmp1) {
+ struct opt_e_t * tmp2 = opt_e;
int keep = !opt_e_enable;
- while (tmp2) {
+ while(tmp2) {
if (!strcmp((*tmp1)->name, tmp2->name)) {
keep = opt_e_enable;
}
@@ -155,9 +158,31 @@ void breakpoints_init(struct process *proc)
}
sym = proc->list_of_symbols;
while (sym) {
- insert_breakpoint(proc, sym->enter_addr); /* proc->pid==0 delays enabling. */
+ /* proc->pid==0 delays enabling. */
+ if (sym->static_plt2addr) {
+ insert_breakpoint(proc, sym->enter_addr, sym);
+ } else {
+ insert_breakpoint(proc, plt2addr(proc, sym->enter_addr), sym); /* proc->pid==0 delays enabling. */
+ }
sym = sym->next;
}
proc->callstack_depth = 0;
proc->breakpoints_enabled = -1;
}
+
+void
+reinitialize_breakpoints (struct process * proc) {
+ struct library_symbol * sym = proc->list_of_symbols;
+
+ while (sym) {
+ if (sym->needs_init) {
+ insert_breakpoint(proc, plt2addr(proc, sym->enter_addr), sym);
+ if (sym->needs_init && !sym->is_weak) {
+ fprintf(stderr, "could not re-initialize breakpoint for \"%s\" in file \"%s\"\n", sym->name, proc->filename);
+ exit(1);
+ }
+ }
+ sym = sym->next;
+ }
+}
+
diff --git a/config.guess b/config.guess
index fb25fa4..ad5281e 100755
--- a/config.guess
+++ b/config.guess
@@ -3,7 +3,7 @@
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
-timestamp='2006-01-30'
+timestamp='2005-08-03'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -106,7 +106,7 @@ set_cc_for_build='
trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
: ${TMPDIR=/tmp} ;
- { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
{ test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
{ echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
@@ -206,9 +206,6 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:ekkoBSD:*:*)
echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
exit ;;
- *:SolidBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
- exit ;;
macppc:MirBSD:*:*)
echo powerppc-unknown-mirbsd${UNAME_RELEASE}
exit ;;
@@ -767,12 +764,7 @@ EOF
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
exit ;;
*:FreeBSD:*:*)
- case ${UNAME_MACHINE} in
- pc98)
- echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
- *)
- echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
- esac
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
exit ;;
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
@@ -787,7 +779,7 @@ EOF
i*:PW*:*)
echo ${UNAME_MACHINE}-pc-pw32
exit ;;
- x86:Interix*:[345]*)
+ x86:Interix*:[34]*)
echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
exit ;;
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
@@ -859,11 +851,7 @@ EOF
#endif
#endif
EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^CPU/{
- s: ::g
- p
- }'`"
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
;;
mips64:Linux:*:*)
@@ -882,11 +870,7 @@ EOF
#endif
#endif
EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^CPU/{
- s: ::g
- p
- }'`"
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
;;
or32:Linux:*:*)
@@ -935,9 +919,6 @@ EOF
sparc:Linux:*:* | sparc64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
- vax:Linux:*:*)
- echo ${UNAME_MACHINE}-dec-linux-gnu
- exit ;;
x86_64:Linux:*:*)
echo x86_64-unknown-linux-gnu
exit ;;
@@ -983,7 +964,7 @@ EOF
LIBC=gnulibc1
# endif
#else
- #if defined(__INTEL_COMPILER) || defined(__PGI)
+ #ifdef __INTEL_COMPILER
LIBC=gnu
#else
LIBC=gnuaout
@@ -993,11 +974,7 @@ EOF
LIBC=dietlibc
#endif
EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^LIBC/{
- s: ::g
- p
- }'`"
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
test x"${LIBC}" != x && {
echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
exit
@@ -1208,6 +1185,7 @@ EOF
*:Darwin:*:*)
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
case $UNAME_PROCESSOR in
+ *86) UNAME_PROCESSOR=i686 ;;
unknown) UNAME_PROCESSOR=powerpc ;;
esac
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
@@ -1286,9 +1264,6 @@ EOF
i*86:skyos:*:*)
echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
exit ;;
- i*86:rdos:*:*)
- echo ${UNAME_MACHINE}-pc-rdos
- exit ;;
esac
#echo '(No uname command or uname output not recognized.)' 1>&2
diff --git a/config.sub b/config.sub
index a4e8a94..1c366df 100755
--- a/config.sub
+++ b/config.sub
@@ -3,7 +3,7 @@
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
-timestamp='2006-01-02'
+timestamp='2005-07-08'
# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
@@ -119,9 +119,8 @@ esac
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
- nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
- uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
- storm-chaos* | os2-emx* | rtmk-nova*)
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \
+ kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
@@ -172,10 +171,6 @@ case $os in
-hiux*)
os=-hiuxwe2
;;
- -sco6)
- os=-sco5v6
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
-sco5)
os=-sco3.2v5
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
@@ -192,10 +187,6 @@ case $os in
# Don't forget version if it is 3.2v4 or newer.
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
- -sco5v6*)
- # Don't forget version if it is 3.2v4 or newer.
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
-sco*)
os=-sco3.2v2
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
@@ -248,7 +239,7 @@ case $basic_machine in
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| i370 | i860 | i960 | ia64 \
| ip2k | iq2000 \
- | m32r | m32rle | m68000 | m68k | m88k | maxq | mb | microblaze | mcore \
+ | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \
| mips | mipsbe | mipseb | mipsel | mipsle \
| mips16 \
| mips64 | mips64el \
@@ -266,7 +257,7 @@ case $basic_machine in
| mipsisa64sr71k | mipsisa64sr71kel \
| mipstx39 | mipstx39el \
| mn10200 | mn10300 \
- | mt \
+ | ms1 \
| msp430 \
| ns16k | ns32k \
| or32 \
@@ -295,9 +286,6 @@ case $basic_machine in
;;
m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
;;
- ms1)
- basic_machine=mt-unknown
- ;;
# We use `pc' rather than `unknown'
# because (1) that's what they normally are, and
@@ -348,7 +336,7 @@ case $basic_machine in
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
| mipstx39-* | mipstx39el-* \
| mmix-* \
- | mt-* \
+ | ms1-* \
| msp430-* \
| none-* | np1-* | ns16k-* | ns32k-* \
| orion-* \
@@ -708,9 +696,6 @@ case $basic_machine in
basic_machine=i386-pc
os=-msdos
;;
- ms1-*)
- basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
- ;;
mvs)
basic_machine=i370-ibm
os=-mvs
@@ -818,12 +803,6 @@ case $basic_machine in
pc532 | pc532-*)
basic_machine=ns32k-pc532
;;
- pc98)
- basic_machine=i386-pc
- ;;
- pc98-*)
- basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
pentium | p5 | k5 | k6 | nexgen | viac3)
basic_machine=i586-pc
;;
@@ -880,10 +859,6 @@ case $basic_machine in
basic_machine=i586-unknown
os=-pw32
;;
- rdos)
- basic_machine=i386-pc
- os=-rdos
- ;;
rom68k)
basic_machine=m68k-rom68k
os=-coff
@@ -1199,23 +1174,21 @@ case $os in
| -aos* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
- | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
- | -openbsd* | -solidbsd* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
- | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
- | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
- | -skyos* | -haiku* | -rdos*)
+ | -skyos* | -haiku*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
diff --git a/configure.ac b/configure.ac
index 9f987ab..1087240 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,8 @@
dnl Process this file with autoconf to produce a configure script.
-AC_INIT(ltrace.c, 0.3.38)
+AC_PREREQ(2.57)
+AC_INIT(ltrace,0.3.36,[Juan Cespedes <cespedes@debian.org>])
+AC_CONFIG_SRCDIR(ltrace.c)
AC_CONFIG_HEADER(config.h)
-AC_PREREQ(2.50)
dnl Check host system type
AC_CANONICAL_HOST
@@ -40,20 +41,34 @@ dnl AC_FUNC_VPRINTF
dnl AC_CHECK_FUNCS(gettimeofday strdup strerror strspn)
AC_CHECK_FUNCS(getopt getopt_long)
-AC_CHECK_HEADER(gelf.h,,[
- if test -f /usr/include/elfutils/gelf.h; then
- CPPFLAGS="$CPPFLAGS -I /usr/include/elfutils"
- elif test -f /usr/local/include/elfutils/gelf.h; then
- CPPFLAGS="$CPPFLAGS -I /usr/local/include/elfutils"
- elif test -f /usr/include/libelf/gelf.h; then
- CPPFLAGS="$CPPFLAGS -I /usr/include/libelf"
- elif test -f /usr/local/include/libelf/gelf.h; then
- CPPFLAGS="$CPPFLAGS -I /usr/local/include/libelf"
- else
- AC_MSG_ERROR(gelf.h not found)
- fi])
+for path in /usr/include/elfutils /usr/local/include/elfutils \
+ /usr/include/libelf /usr/local/include/libelf; do
+ if test -f ${path}/gelf.h; then
+ CPPFLAGS="$CPPFLAGS -I ${path}"
+ fi
+done
+
+AC_CHECK_HEADER(gelf.h,,AC_MSG_ERROR([***** gelf.h not found *****]))
+
AC_CHECK_LIB(elf,gelf_getdyn)
+ac_cv_have_iquote=no
+AC_MSG_CHECKING(compiler accepts -iquote dir)
+save_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS -iquote ."
+AC_TRY_COMPILE(,,[ac_cv_have_iquote=yes])
+CPPFLAGS="$save_CPPFLAGS"
+AC_MSG_RESULT($ac_cv_have_iquote)
+if test $ac_cv_have_iquote = yes; then
+ iquote="-iquote "
+ iquoteend=""
+else
+ iquote="-I "
+ iquoteend="-I-"
+fi
+AC_SUBST(iquote)
+AC_SUBST(iquoteend)
+
ac_cv_have_elf_c_read_mmap=no
AC_MSG_CHECKING(elf_begin accepts ELF_C_READ_MMAP)
AC_TRY_COMPILE([#include <gelf.h>],
diff --git a/debian/copyright b/debian/copyright
index 2b15ef6..c37158f 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -13,7 +13,7 @@ s390 port: Copyright (C) 2001 IBM Poughkeepsie, IBM Cororation <slate@us.ibm.com
ELF hacking: Copyright (C) 1999 Silvio Cesare <silvio@big.net.au>
PowerPC port: Copyright (C) 2001-2002 Anton Blanchard <anton@samba.org>
SPARC port: Copyright (C) 1999 Jakub Jelinek <jakub@redhat.com>
-IA64 port: Copyright (C) 2006 Ian Wienand <ianw@gelato.unsw.edu.au>
+
Autoconf stuff: Copyright 1992-1996 Free Software Foundation, Inc.
install-sh: Copyright 1991 by the Massachusetts Institute of Technology
diff --git a/debug.c b/debug.c
index 6b5bb8e..198581b 100644
--- a/debug.c
+++ b/debug.c
@@ -5,8 +5,8 @@
#include "options.h"
#include "output.h"
-void debug_(int level, char *file, int line, const char *func, char *fmt, ...)
-{
+void
+debug_(int level, const char *file, int line, const char *func, const char *fmt, ...) {
char buf[1024];
va_list args;
@@ -19,3 +19,138 @@ void debug_(int level, char *file, int line, const char *func, char *fmt, ...)
output_line(NULL, "DEBUG: %s:%d: %s(): %s", file, line, func, buf);
}
+
+// The following section provides a way to print things, like hex dumps,
+// with out using buffered output. This was written by Steve Munroe of IBM.
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/ptrace.h>
+
+int xwrite(const char *string, size_t len)
+{
+ int rc = 0;
+ rc = write (1, string, len);
+ return rc;
+}
+
+int xwrites(const char *string)
+{
+ size_t len = 0;
+ int rc = 0;
+ const char *tstring = string;
+
+ while (*tstring++ != '\0')
+ {
+ len++;
+ }
+
+ if (len >0)
+ {
+ rc = xwrite( string, len );
+ }
+
+ return rc;
+}
+
+int xwritehexi(int i)
+{
+ int rc = 0;
+ char text[9];
+ int j;
+ unsigned int temp = (unsigned int)i;
+
+ for ( j = 7; j >= 0; j--)
+ {
+ char c;
+ c = (char)((temp & 0x0f ) + '0');
+ if ( c > '9' )
+ {
+ c = (char)(c + ('a' - '9' - 1));
+ }
+ text[j] = c;
+ temp = temp>>4;
+ }
+
+ rc = write (1, text, 8);
+ return rc;
+}
+
+int xwritehexl(long i)
+{
+ int rc = 0;
+ char text[17];
+ int j;
+ unsigned long temp = (unsigned long)i;
+
+ for ( j = 15; j >= 0; j--)
+ {
+ char c;
+ c = (char)((temp & 0x0f ) + '0');
+ if ( c > '9' )
+ {
+ c = (char)(c + ('a' - '9' - 1));
+ }
+ text[j] = c;
+ temp = temp>>4;
+ }
+
+ rc = write (1, text, 16);
+ return rc;
+}
+
+int xwritec(char c)
+{
+ char temp = c;
+ char *text = &temp;
+ int rc = 0;
+ rc = write (1, text, 1);
+ return rc;
+}
+
+int xwritecr(void)
+{
+ return xwritec('\n');
+}
+
+int xwritedump(void *ptr, long addr, int len)
+{
+ int rc = 0;
+ long *tprt = (long*)ptr;
+ int i;
+
+ for ( i = 0; i < len ; i+=8 )
+ {
+ xwritehexl( addr);
+ xwritec('-');
+ xwritec('>');
+ xwritehexl( *tprt++);
+ xwritecr();
+ addr += sizeof(long);
+ }
+
+ return rc;
+}
+
+int xinfdump(long pid, void *ptr, int len)
+{
+ int rc;
+ int i;
+ long wrdcnt = len / sizeof(long) + 1;
+ long *infwords = malloc(wrdcnt*sizeof(long));
+ long addr = (long)ptr;
+
+ addr = ((addr + sizeof(long) - 1) / sizeof(long)) * sizeof(long);
+
+ for (i=0; i<wrdcnt; ++i) {
+ infwords[i] = ptrace(PTRACE_PEEKTEXT, pid, addr);
+ addr += sizeof(long);
+ }
+
+ rc = xwritedump(infwords, (long)ptr, len);
+
+ free(infwords);
+ return rc;
+}
diff --git a/debug.h b/debug.h
index f42dd73..53626ef 100644
--- a/debug.h
+++ b/debug.h
@@ -1,6 +1,16 @@
#include <features.h>
-void debug_(int level, char *file, int line, const char *func, char *fmt, ...);
+void debug_(int level, const char *file, int line, const char *func, const char *fmt, ...);
+
+int xwrite(const char *, size_t);
+int xwrites(const char *);
+int xwritehexi(int);
+int xwritehexl(long);
+int xwritec(char);
+int xwritecr(void);
+int xwritedump(void *, long, int);
+int xinfdump(long, void *, int);
+
# define debug(level, expr...) debug_(level, __FILE__, __LINE__, DEBUG_FUNCTION, expr)
diff --git a/demangle.c b/demangle.c
index 0d86888..63b7da6 100644
--- a/demangle.c
+++ b/demangle.c
@@ -16,19 +16,19 @@
/*****************************************************************************/
-static struct dict *d = NULL;
+static struct dict * d = NULL;
-static void my_demangle_dict_clear(void)
-{
+static void
+my_demangle_dict_clear(void) {
/* FIXME TODO XXX: I should also free all (key,value) pairs */
dict_clear(d);
}
-const char *my_demangle(const char *function_name)
-{
- const char *tmp, *fn_copy;
+const char *
+my_demangle(const char * function_name) {
+ const char * tmp, * fn_copy;
#if !defined HAVE_LIBIBERTY && defined HAVE_LIBSUPC__
- extern char *__cxa_demangle(const char *, char *, size_t *, int *);
+ extern char *__cxa_demangle (const char *, char *, size_t *, int *);
int status = 0;
#endif
@@ -36,7 +36,7 @@ const char *my_demangle(const char *function_name)
d = dict_init(dict_key2hash_string, dict_key_cmp_string);
atexit(my_demangle_dict_clear);
}
-
+
tmp = dict_find_entry(d, (void *)function_name);
if (!tmp) {
fn_copy = strdup(function_name);
@@ -45,10 +45,8 @@ const char *my_demangle(const char *function_name)
#elif defined HAVE_LIBSUPC__
tmp = __cxa_demangle(function_name, NULL, NULL, &status);
#endif
- if (!tmp)
- tmp = fn_copy;
- if (tmp)
- dict_enter(d, (void *)fn_copy, (void *)tmp);
+ if (!tmp) tmp = fn_copy;
+ if (tmp) dict_enter(d, (void *)fn_copy, (void *)tmp);
}
return tmp;
}
diff --git a/dict.c b/dict.c
index a1ec8c1..8d97220 100644
--- a/dict.c
+++ b/dict.c
@@ -13,27 +13,26 @@
struct dict_entry {
unsigned int hash;
- void *key;
- void *value;
- struct dict_entry *next;
+ void * key;
+ void * value;
+ struct dict_entry * next;
};
/* #define DICTTABLESIZE 97 */
-#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */
+#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */
/* #define DICTTABLESIZE 9973 */
/* #define DICTTABLESIZE 99991 */
/* #define DICTTABLESIZE 999983 */
struct dict {
- struct dict_entry *buckets[DICTTABLESIZE];
- unsigned int (*key2hash) (void *);
- int (*key_cmp) (void *, void *);
+ struct dict_entry * buckets[DICTTABLESIZE];
+ unsigned int (*key2hash)(void *);
+ int (*key_cmp)(void *, void *);
};
-struct dict *dict_init(unsigned int (*key2hash) (void *),
- int (*key_cmp) (void *, void *))
-{
- struct dict *d;
+struct dict *
+dict_init(unsigned int (*key2hash)(void *), int (*key_cmp)(void *, void *)) {
+ struct dict * d;
int i;
d = malloc(sizeof(struct dict));
@@ -41,7 +40,7 @@ struct dict *dict_init(unsigned int (*key2hash) (void *),
perror("malloc()");
exit(1);
}
- for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
+ for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
d->buckets[i] = NULL;
}
d->key2hash = key2hash;
@@ -49,10 +48,10 @@ struct dict *dict_init(unsigned int (*key2hash) (void *),
return d;
}
-void dict_clear(struct dict *d)
-{
+void
+dict_clear(struct dict * d) {
int i;
- struct dict_entry *entry, *nextentry;
+ struct dict_entry * entry, * nextentry;
assert(d);
for (i = 0; i < DICTTABLESIZE; i++) {
@@ -65,9 +64,9 @@ void dict_clear(struct dict *d)
free(d);
}
-int dict_enter(struct dict *d, void *key, void *value)
-{
- struct dict_entry *entry, *newentry;
+int
+dict_enter(struct dict * d, void * key, void * value) {
+ struct dict_entry * entry, * newentry;
unsigned int hash = d->key2hash(key);
unsigned int bucketpos = hash % DICTTABLESIZE;
@@ -78,30 +77,26 @@ int dict_enter(struct dict *d, void *key, void *value)
exit(1);
}
- newentry->hash = hash;
- newentry->key = key;
+ newentry->hash = hash;
+ newentry->key = key;
newentry->value = value;
- newentry->next = NULL;
+ newentry->next = NULL;
entry = d->buckets[bucketpos];
- while (entry && entry->next)
- entry = entry->next;
+ while (entry && entry->next) entry = entry->next;
- if (entry)
- entry->next = newentry;
- else
- d->buckets[bucketpos] = newentry;
+ if (entry) entry->next = newentry;
+ else d->buckets[bucketpos] = newentry;
- debug(3, "new dict entry at %p[%d]: (%p,%p)\n", d, bucketpos, key,
- value);
+ debug(3, "new dict entry at %p[%d]: (%p,%p)", d, bucketpos, key, value);
return 0;
}
-void *dict_find_entry(struct dict *d, void *key)
-{
+void *
+dict_find_entry(struct dict * d, void * key) {
unsigned int hash = d->key2hash(key);
unsigned int bucketpos = hash % DICTTABLESIZE;
- struct dict_entry *entry;
+ struct dict_entry * entry;
assert(d);
for (entry = d->buckets[bucketpos]; entry; entry = entry->next) {
@@ -116,16 +111,14 @@ void *dict_find_entry(struct dict *d, void *key)
}
void
-dict_apply_to_all(struct dict *d,
- void (*func) (void *key, void *value, void *data), void *data)
-{
+dict_apply_to_all(struct dict * d, void (*func)(void *key, void *value, void *data), void *data) {
int i;
if (!d) {
return;
}
for (i = 0; i < DICTTABLESIZE; i++) {
- struct dict_entry *entry = d->buckets[i];
+ struct dict_entry * entry = d->buckets[i];
while (entry) {
func(entry->key, entry->value, data);
entry = entry->next;
@@ -135,35 +128,35 @@ dict_apply_to_all(struct dict *d,
/*****************************************************************************/
-unsigned int dict_key2hash_string(void *key)
-{
- const char *s = (const char *)key;
+unsigned int
+dict_key2hash_string(void * key) {
+ const char * s = (const char *)key;
unsigned int total = 0, shift = 0;
assert(key);
while (*s) {
total = total ^ ((*s) << shift);
shift += 5;
- if (shift > 24)
- shift -= 24;
+ if (shift > 24) shift -= 24;
s++;
}
return total;
}
-int dict_key_cmp_string(void *key1, void *key2)
-{
+int
+dict_key_cmp_string(void * key1, void * key2) {
assert(key1);
assert(key2);
return strcmp((const char *)key1, (const char *)key2);
}
-unsigned int dict_key2hash_int(void *key)
-{
+unsigned int
+dict_key2hash_int(void * key) {
return (unsigned long)key;
}
-int dict_key_cmp_int(void *key1, void *key2)
-{
+int
+dict_key_cmp_int(void * key1, void * key2) {
return key1 - key2;
}
+
diff --git a/display_args.c b/display_args.c
index b8dc0f6..e922d4b 100644
--- a/display_args.c
+++ b/display_args.c
@@ -11,110 +11,109 @@
#include "options.h"
static int display_char(int what);
-static int display_string(enum tof type, struct process *proc, int arg_num);
-static int display_stringN(int arg2, enum tof type, struct process *proc,
- int arg_num);
-static int display_unknown(enum tof type, struct process *proc, int arg_num);
-static int display_format(enum tof type, struct process *proc, int arg_num);
+static int display_string(enum tof type, struct process * proc, int arg_num);
+static int display_stringN(int arg2, enum tof type, struct process * proc, int arg_num);
+static int display_unknown(enum tof type, struct process * proc, int arg_num);
+static int display_format(enum tof type, struct process * proc, int arg_num);
int
-display_arg(enum tof type, struct process *proc, int arg_num,
- const struct complete_arg_type *at)
-{
+display_arg(enum tof type, struct process * proc, int arg_num, enum arg_type at) {
int tmp;
long arg;
- if (!at)
- return display_unknown(type, proc, arg_num);
- switch (at->at) {
- case ARGTYPE_VOID:
- return 0;
- case ARGTYPE_INT:
- return fprintf(output, "%d",
- (int)gimme_arg(type, proc, arg_num));
- case ARGTYPE_UINT:
- return fprintf(output, "%u",
- (unsigned)gimme_arg(type, proc, arg_num));
- case ARGTYPE_LONG:
- return fprintf(output, "%ld", gimme_arg(type, proc, arg_num));
- case ARGTYPE_ULONG:
- return fprintf(output, "%lu",
- (unsigned long)gimme_arg(type, proc, arg_num));
- case ARGTYPE_OCTAL:
- return fprintf(output, "0%o",
- (unsigned)gimme_arg(type, proc, arg_num));
- case ARGTYPE_CHAR:
- tmp = fprintf(output, "'");
- tmp += display_char((int)gimme_arg(type, proc, arg_num));
- tmp += fprintf(output, "'");
- return tmp;
- case ARGTYPE_ADDR:
- arg = gimme_arg(type, proc, arg_num);
- if (!arg) {
- return fprintf(output, "NULL");
- } else {
- return fprintf(output, "%p", (void *)arg);
- }
- case ARGTYPE_FORMAT:
- return display_format(type, proc, arg_num);
- case ARGTYPE_STRING:
- return display_string(type, proc, arg_num);
- case ARGTYPE_STRINGN:
- return display_stringN(at->argno, type, proc, arg_num);
- case ARGTYPE_UNKNOWN:
- default:
- return display_unknown(type, proc, arg_num);
+ switch(at) {
+ case ARGTYPE_VOID:
+ return 0;
+ case ARGTYPE_INT:
+ return fprintf(output, "%d", (int)gimme_arg(type, proc, arg_num));
+ case ARGTYPE_UINT:
+ return fprintf(output, "%u", (unsigned)gimme_arg(type, proc, arg_num));
+ case ARGTYPE_LONG:
+ if (proc->mask_32bit)
+ return fprintf(output, "%d", (int)gimme_arg(type, proc, arg_num));
+ return fprintf(output, "%ld", gimme_arg(type, proc, arg_num));
+ case ARGTYPE_ULONG:
+ if (proc->mask_32bit)
+ return fprintf(output, "%u", (unsigned)gimme_arg(type, proc, arg_num));
+ return fprintf(output, "%lu", (unsigned long)gimme_arg(type, proc, arg_num));
+ case ARGTYPE_OCTAL:
+ return fprintf(output, "0%o", (unsigned)gimme_arg(type, proc, arg_num));
+ case ARGTYPE_CHAR:
+ tmp = fprintf(output, "'");
+ tmp += display_char((int)gimme_arg(type, proc, arg_num));
+ tmp += fprintf(output, "'");
+ return tmp;
+ case ARGTYPE_ADDR:
+ arg = gimme_arg(type, proc, arg_num);
+ if (!arg) {
+ return fprintf(output, "NULL");
+ } else {
+ return fprintf(output, "%p", (void *)arg);
+ }
+ case ARGTYPE_FORMAT:
+ return display_format(type, proc, arg_num);
+ case ARGTYPE_STRING:
+ return display_string(type, proc, arg_num);
+ case ARGTYPE_STRING0:
+ return display_stringN(0, type, proc, arg_num);
+ case ARGTYPE_STRING1:
+ return display_stringN(1, type, proc, arg_num);
+ case ARGTYPE_STRING2:
+ return display_stringN(2, type, proc, arg_num);
+ case ARGTYPE_STRING3:
+ return display_stringN(3, type, proc, arg_num);
+ case ARGTYPE_STRING4:
+ return display_stringN(4, type, proc, arg_num);
+ case ARGTYPE_STRING5:
+ return display_stringN(5, type, proc, arg_num);
+ case ARGTYPE_UNKNOWN:
+ default:
+ return display_unknown(type, proc, arg_num);
}
return fprintf(output, "?");
}
-static int display_char(int what)
-{
- switch (what) {
- case -1:
- return fprintf(output, "EOF");
- case '\r':
- return fprintf(output, "\\r");
- case '\n':
- return fprintf(output, "\\n");
- case '\t':
- return fprintf(output, "\\t");
- case '\b':
- return fprintf(output, "\\b");
- case '\\':
- return fprintf(output, "\\\\");
- default:
- if ((what < 32) || (what > 126)) {
- return fprintf(output, "\\%03o", (unsigned char)what);
- } else {
- return fprintf(output, "%c", what);
- }
+static int
+display_char(int what) {
+ switch(what) {
+ case -1: return fprintf(output, "EOF");
+ case '\r': return fprintf(output, "\\r");
+ case '\n': return fprintf(output, "\\n");
+ case '\t': return fprintf(output, "\\t");
+ case '\b': return fprintf(output, "\\b");
+ case '\\': return fprintf(output, "\\\\");
+ default:
+ if ((what<32) || (what>126)) {
+ return fprintf(output, "\\%03o", (unsigned char)what);
+ } else {
+ return fprintf(output, "%c", what);
+ }
}
}
-static int string_maxlength = INT_MAX;
+static int string_maxlength=INT_MAX;
#define MIN(a,b) (((a)<(b)) ? (a) : (b))
-static int display_string(enum tof type, struct process *proc, int arg_num)
-{
- void *addr;
- unsigned char *str1;
+static int
+display_string(enum tof type, struct process * proc, int arg_num) {
+ void * addr;
+ unsigned char * str1;
int i;
- int len = 0;
+ int len=0;
addr = (void *)gimme_arg(type, proc, arg_num);
if (!addr) {
return fprintf(output, "NULL");
}
- str1 = malloc(MIN(opt_s, string_maxlength) + 3);
+ str1 = malloc(MIN(opt_s,string_maxlength)+3);
if (!str1) {
return fprintf(output, "???");
}
- umovestr(proc, addr, MIN(opt_s, string_maxlength) + 1, str1);
+ umovestr(proc, addr, MIN(opt_s,string_maxlength)+1, str1);
len = fprintf(output, "\"");
- for (i = 0; i < MIN(opt_s, string_maxlength); i++) {
+ for(i=0; i<MIN(opt_s,string_maxlength); i++) {
if (str1[i]) {
len += display_char(str1[i]);
} else {
@@ -130,48 +129,52 @@ static int display_string(enum tof type, struct process *proc, int arg_num)
}
static int
-display_stringN(int arg2, enum tof type, struct process *proc, int arg_num)
-{
+display_stringN(int arg2, enum tof type, struct process * proc, int arg_num) {
int a;
- string_maxlength = gimme_arg(type, proc, arg2 - 1);
+ string_maxlength=gimme_arg(type, proc, arg2-1);
a = display_string(type, proc, arg_num);
- string_maxlength = INT_MAX;
+ string_maxlength=INT_MAX;
return a;
}
-static int display_unknown(enum tof type, struct process *proc, int arg_num)
-{
+static int
+display_unknown(enum tof type, struct process * proc, int arg_num) {
long tmp;
tmp = gimme_arg(type, proc, arg_num);
- if (tmp < 1000000 && tmp > -1000000) {
+ if (proc->mask_32bit) {
+ if ((int)tmp<1000000 && (int)tmp>-1000000)
+ return fprintf(output, "%d", (int)tmp);
+ else
+ return fprintf(output, "%p", (void *)tmp);
+ } else if (tmp<1000000 && tmp>-1000000) {
return fprintf(output, "%ld", tmp);
} else {
return fprintf(output, "%p", (void *)tmp);
}
}
-static int display_format(enum tof type, struct process *proc, int arg_num)
-{
- void *addr;
- unsigned char *str1;
+static int
+display_format(enum tof type, struct process * proc, int arg_num) {
+ void * addr;
+ unsigned char * str1;
int i;
- int len = 0;
+ int len=0;
addr = (void *)gimme_arg(type, proc, arg_num);
if (!addr) {
return fprintf(output, "NULL");
}
- str1 = malloc(MIN(opt_s, string_maxlength) + 3);
+ str1 = malloc(MIN(opt_s,string_maxlength)+3);
if (!str1) {
return fprintf(output, "???");
}
- umovestr(proc, addr, MIN(opt_s, string_maxlength) + 1, str1);
+ umovestr(proc, addr, MIN(opt_s,string_maxlength)+1, str1);
len = fprintf(output, "\"");
- for (i = 0; len < MIN(opt_s, string_maxlength) + 1; i++) {
+ for(i=0; len<MIN(opt_s,string_maxlength)+1; i++) {
if (str1[i]) {
len += display_char(str1[i]);
} else {
@@ -182,114 +185,68 @@ static int display_format(enum tof type, struct process *proc, int arg_num)
if (str1[i] && (opt_s <= string_maxlength)) {
len += fprintf(output, "...");
}
- for (i = 0; str1[i]; i++) {
- if (str1[i] == '%') {
+ for(i=0; str1[i]; i++) {
+ if (str1[i]=='%') {
int is_long = 0;
- while (1) {
+ while(1) {
unsigned char c = str1[++i];
if (c == '%') {
break;
} else if (!c) {
break;
- } else if (strchr("lzZtj", c)) {
+ } else if (strchr ("lzZtj", c)) {
is_long++;
if (c == 'j')
is_long++;
if (is_long > 1
- && sizeof(long) <
- sizeof(long long)) {
+ && (sizeof (long) < sizeof (long long) || proc->mask_32bit)) {
len += fprintf(output, ", ...");
- str1[i + 1] = '\0';
+ str1[i+1]='\0';
break;
}
- } else if (c == 'd' || c == 'i') {
- if (is_long)
- len +=
- fprintf(output, ", %d",
- (int)gimme_arg(type,
- proc,
- ++arg_num));
+ } else if (c=='d' || c=='i') {
+ if (!is_long || proc->mask_32bit)
+ len += fprintf(output, ", %d", (int)gimme_arg(type, proc, ++arg_num));
else
- len +=
- fprintf(output, ", %ld",
- gimme_arg(type,
- proc,
- ++arg_num));
+ len += fprintf(output, ", %ld", gimme_arg(type, proc, ++arg_num));
break;
- } else if (c == 'u') {
- if (is_long)
- len +=
- fprintf(output, ", %u",
- (int)gimme_arg(type,
- proc,
- ++arg_num));
+ } else if (c=='u') {
+ if (!is_long || proc->mask_32bit)
+ len += fprintf(output, ", %u", (int)gimme_arg(type, proc, ++arg_num));
else
- len +=
- fprintf(output, ", %lu",
- gimme_arg(type,
- proc,
- ++arg_num));
+ len += fprintf(output, ", %lu", gimme_arg(type, proc, ++arg_num));
break;
- } else if (c == 'o') {
- if (is_long)
- len +=
- fprintf(output, ", 0%o",
- (int)gimme_arg(type,
- proc,
- ++arg_num));
+ } else if (c=='o') {
+ if (!is_long || proc->mask_32bit)
+ len += fprintf(output, ", 0%o", (int)gimme_arg(type, proc, ++arg_num));
else
- len +=
- fprintf(output, ", 0%lo",
- gimme_arg(type,
- proc,
- ++arg_num));
+ len += fprintf(output, ", 0%lo", gimme_arg(type, proc, ++arg_num));
break;
- } else if (c == 'x' || c == 'X') {
- if (is_long)
- len +=
- fprintf(output, ", %#x",
- (int)gimme_arg(type,
- proc,
- ++arg_num));
+ } else if (c=='x' || c=='X') {
+ if (!is_long || proc->mask_32bit)
+ len += fprintf(output, ", %#x", (int)gimme_arg(type, proc, ++arg_num));
else
- len +=
- fprintf(output, ", %#lx",
- gimme_arg(type,
- proc,
- ++arg_num));
+ len += fprintf(output, ", %#lx", gimme_arg(type, proc, ++arg_num));
break;
} else if (strchr("eEfFgGaACS", c)
- || (is_long
- && (c == 'c' || c == 's'))) {
+ || (is_long && (c=='c' || c=='s'))) {
len += fprintf(output, ", ...");
- str1[i + 1] = '\0';
+ str1[i+1]='\0';
break;
- } else if (c == 'c') {
+ } else if (c=='c') {
len += fprintf(output, ", '");
- len += display_char((int)
- gimme_arg(type,
- proc,
- ++arg_num));
+ len += display_char((int)gimme_arg(type, proc, ++arg_num));
len += fprintf(output, "'");
break;
- } else if (c == 's') {
+ } else if (c=='s') {
len += fprintf(output, ", ");
- len +=
- display_string(type, proc,
- ++arg_num);
+ len += display_string(type, proc, ++arg_num);
break;
- } else if (c == 'p' || c == 'n') {
- len +=
- fprintf(output, ", %p",
- (void *)gimme_arg(type,
- proc,
- ++arg_num));
+ } else if (c=='p' || c=='n') {
+ len += fprintf(output, ", %p", (void *)gimme_arg(type, proc, ++arg_num));
break;
- } else if (c == '*') {
- len +=
- fprintf(output, ", %d",
- (int)gimme_arg(type, proc,
- ++arg_num));
+ } else if (c=='*') {
+ len += fprintf(output, ", %d", (int)gimme_arg(type, proc, ++arg_num));
}
}
}
diff --git a/elf.c b/elf.c
index db5378c..c7ef400 100644
--- a/elf.c
+++ b/elf.c
@@ -15,324 +15,455 @@
#include "ltrace.h"
#include "elf.h"
#include "debug.h"
+#include "options.h"
-static void do_init_elf(struct ltelf *lte, const char *filename);
-static void do_close_elf(struct ltelf *lte);
-static void add_library_symbol(GElf_Addr addr, const char *name,
- struct library_symbol **library_symbolspp);
-static int in_load_libraries(const char *name, struct ltelf *lte);
+static void do_init_elf (struct ltelf *lte, const char *filename);
+static void do_close_elf (struct ltelf *lte);
+static void add_library_symbol (GElf_Addr addr, const char *name,
+ struct library_symbol **library_symbolspp,
+ int use_elf_plt2addr, int is_weak);
+static int in_load_libraries (const char *name, struct ltelf *lte);
+static GElf_Addr elf_plt2addr (struct ltelf *ltc, void *addr);
-static void do_init_elf(struct ltelf *lte, const char *filename)
+
+extern char * PLTs_initialized_by_here;
+
+static void
+do_init_elf (struct ltelf *lte, const char *filename)
{
- int i;
- GElf_Addr relplt_addr = 0;
- size_t relplt_size = 0;
+ int i;
+ GElf_Addr relplt_addr = 0;
+ size_t relplt_size = 0;
- debug(1, "Reading ELF from %s...", filename);
+ debug (1, "Reading ELF from %s...", filename);
- memset(lte, 0, sizeof(*lte));
- lte->fd = open(filename, O_RDONLY);
- if (lte->fd == -1)
- error(EXIT_FAILURE, errno, "Can't open \"%s\"", filename);
+ memset (lte, 0, sizeof (*lte));
+ lte->fd = open (filename, O_RDONLY);
+ if (lte->fd == -1)
+ error (EXIT_FAILURE, errno, "Can't open \"%s\"", filename);
#ifdef HAVE_ELF_C_READ_MMAP
- lte->elf = elf_begin(lte->fd, ELF_C_READ_MMAP, NULL);
+ lte->elf = elf_begin (lte->fd, ELF_C_READ_MMAP, NULL);
#else
- lte->elf = elf_begin(lte->fd, ELF_C_READ, NULL);
+ lte->elf = elf_begin (lte->fd, ELF_C_READ, NULL);
#endif
- if (lte->elf == NULL || elf_kind(lte->elf) != ELF_K_ELF)
- error(EXIT_FAILURE, 0, "Can't open ELF file \"%s\"", filename);
+ if (lte->elf == NULL || elf_kind (lte->elf) != ELF_K_ELF)
+ error (EXIT_FAILURE, 0, "Can't open ELF file \"%s\"", filename);
- if (gelf_getehdr(lte->elf, &lte->ehdr) == NULL)
- error(EXIT_FAILURE, 0, "Can't read ELF header of \"%s\"",
- filename);
+ if (gelf_getehdr (lte->elf, &lte->ehdr) == NULL)
+ error (EXIT_FAILURE, 0, "Can't read ELF header of \"%s\"", filename);
- if (lte->ehdr.e_type != ET_EXEC && lte->ehdr.e_type != ET_DYN)
- error(EXIT_FAILURE, 0,
- "\"%s\" is not an ELF executable nor shared library",
- filename);
+ if (lte->ehdr.e_type != ET_EXEC && lte->ehdr.e_type != ET_DYN)
+ error (EXIT_FAILURE, 0, "\"%s\" is not an ELF executable nor shared library",
+ filename);
- if (lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS
- || (lte->ehdr.e_machine != LT_ELF_MACHINE
+ if ((lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS
+ || lte->ehdr.e_machine != LT_ELF_MACHINE)
#ifdef LT_ELF_MACHINE2
- && lte->ehdr.e_machine != LT_ELF_MACHINE2
+ && (lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS2
+ || lte->ehdr.e_machine != LT_ELF_MACHINE2)
#endif
#ifdef LT_ELF_MACHINE3
- && lte->ehdr.e_machine != LT_ELF_MACHINE3
+ && (lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS3
+ || lte->ehdr.e_machine != LT_ELF_MACHINE3)
#endif
- ))
- error(EXIT_FAILURE, 0,
- "\"%s\" is ELF from incompatible architecture", filename);
-
- for (i = 1; i < lte->ehdr.e_shnum; ++i) {
- Elf_Scn *scn;
- GElf_Shdr shdr;
- const char *name;
-
- scn = elf_getscn(lte->elf, i);
- if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
- error(EXIT_FAILURE, 0,
- "Couldn't get section header from \"%s\"",
- filename);
-
- name = elf_strptr(lte->elf, lte->ehdr.e_shstrndx, shdr.sh_name);
- if (name == NULL)
- error(EXIT_FAILURE, 0,
- "Couldn't get section header from \"%s\"",
- filename);
-
- if (shdr.sh_type == SHT_DYNSYM) {
- Elf_Data *data;
-
- lte->dynsym = elf_getdata(scn, NULL);
- lte->dynsym_count = shdr.sh_size / shdr.sh_entsize;
- if (lte->dynsym == NULL
- || elf_getdata(scn, lte->dynsym) != NULL)
- error(EXIT_FAILURE, 0,
- "Couldn't get .dynsym data from \"%s\"",
- filename);
-
- scn = elf_getscn(lte->elf, shdr.sh_link);
- if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
- error(EXIT_FAILURE, 0,
- "Couldn't get section header from \"%s\"",
- filename);
-
- data = elf_getdata(scn, NULL);
- if (data == NULL || elf_getdata(scn, data) != NULL
- || shdr.sh_size != data->d_size || data->d_off)
- error(EXIT_FAILURE, 0,
- "Couldn't get .dynstr data from \"%s\"",
- filename);
-
- lte->dynstr = data->d_buf;
- } else if (shdr.sh_type == SHT_DYNAMIC) {
- Elf_Data *data;
- size_t j;
-
- data = elf_getdata(scn, NULL);
- if (data == NULL || elf_getdata(scn, data) != NULL)
- error(EXIT_FAILURE, 0,
- "Couldn't get .dynamic data from \"%s\"",
- filename);
-
- for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) {
- GElf_Dyn dyn;
-
- if (gelf_getdyn(data, j, &dyn) == NULL)
- error(EXIT_FAILURE, 0,
- "Couldn't get .dynamic data from \"%s\"",
- filename);
-
- if (dyn.d_tag == DT_JMPREL)
- relplt_addr = dyn.d_un.d_ptr;
- else if (dyn.d_tag == DT_PLTRELSZ)
- relplt_size = dyn.d_un.d_val;
- }
- } else if (shdr.sh_type == SHT_HASH) {
- Elf_Data *data;
- size_t j;
-
- data = elf_getdata(scn, NULL);
- if (data == NULL || elf_getdata(scn, data) != NULL
- || data->d_off || data->d_size != shdr.sh_size)
- error(EXIT_FAILURE, 0,
- "Couldn't get .hash data from \"%s\"",
- filename);
-
- if (shdr.sh_entsize == 4) {
- /* Standard conforming ELF. */
- if (data->d_type != ELF_T_WORD)
- error(EXIT_FAILURE, 0,
- "Couldn't get .hash data from \"%s\"",
- filename);
- lte->hash = (Elf32_Word *) data->d_buf;
- } else if (shdr.sh_entsize == 8) {
- /* Alpha or s390x. */
- Elf32_Word *dst, *src;
- size_t hash_count = data->d_size / 8;
-
- lte->hash = (Elf32_Word *)
- malloc(hash_count * sizeof(Elf32_Word));
- if (lte->hash == NULL)
- error(EXIT_FAILURE, 0,
- "Couldn't convert .hash section from \"%s\"",
- filename);
- lte->hash_malloced = 1;
- dst = lte->hash;
- src = (Elf32_Word *) data->d_buf;
- if ((data->d_type == ELF_T_WORD
- && __BYTE_ORDER == __BIG_ENDIAN)
- || (data->d_type == ELF_T_XWORD
- && lte->ehdr.e_ident[EI_DATA] ==
- ELFDATA2MSB))
- ++src;
- for (j = 0; j < hash_count; ++j, src += 2)
- *dst++ = *src;
- } else
- error(EXIT_FAILURE, 0,
- "Unknown .hash sh_entsize in \"%s\"",
- filename);
- } else
- if ((shdr.sh_type == SHT_PROGBITS
- || shdr.sh_type == SHT_NOBITS)
- && strcmp(name, ".plt") == 0)
- {
- lte->plt_addr = shdr.sh_addr;
- lte->plt_size = shdr.sh_size;
- }
+ )
+ error (EXIT_FAILURE, 0, "\"%s\" is ELF from incompatible architecture",
+ filename);
+
+ for (i = 1; i < lte->ehdr.e_shnum; ++i)
+ {
+ Elf_Scn *scn;
+ GElf_Shdr shdr;
+ const char *name;
+
+ scn = elf_getscn (lte->elf, i);
+ if (scn == NULL || gelf_getshdr (scn, &shdr) == NULL)
+ error (EXIT_FAILURE, 0, "Couldn't get section header from \"%s\"",
+ filename);
+
+ name = elf_strptr (lte->elf, lte->ehdr.e_shstrndx, shdr.sh_name);
+ if (name == NULL)
+ error (EXIT_FAILURE, 0, "Couldn't get section header from \"%s\"",
+ filename);
+
+ if (shdr.sh_type == SHT_SYMTAB)
+ {
+ Elf_Data *data;
+
+ lte->symtab = elf_getdata (scn,NULL);
+ lte->symtab_count = shdr.sh_size / shdr.sh_entsize;
+ if ((lte->symtab == NULL || elf_getdata(scn, lte->symtab) != NULL)
+ && opt_x != NULL)
+ error (EXIT_FAILURE, 0, "Couldn't get .symtab data from \"%s\"",
+ filename);
+
+ scn = elf_getscn (lte->elf, shdr.sh_link);
+ if (scn == NULL || gelf_getshdr (scn, &shdr) == NULL)
+ error (EXIT_FAILURE, 0, "Couldn't get section header from \"%s\"",
+ filename);
+
+ data = elf_getdata (scn, NULL);
+ if (data == NULL || elf_getdata (scn, data) != NULL
+ || shdr.sh_size != data->d_size || data->d_off)
+ error (EXIT_FAILURE, 0, "Couldn't get .strtab data from \"%s\"",
+ filename);
+
+ lte->strtab = data->d_buf;
}
-
- if (lte->dynsym == NULL || lte->dynstr == NULL)
- error(EXIT_FAILURE, 0,
- "Couldn't find .dynsym or .dynstr in \"%s\"", filename);
-
- if (!relplt_addr || !lte->plt_addr) {
- debug(1, "%s has no PLT relocations", filename);
- lte->relplt = NULL;
- lte->relplt_count = 0;
- } else {
- for (i = 1; i < lte->ehdr.e_shnum; ++i) {
- Elf_Scn *scn;
- GElf_Shdr shdr;
-
- scn = elf_getscn(lte->elf, i);
- if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
- error(EXIT_FAILURE, 0,
- "Couldn't get section header from \"%s\"",
- filename);
- if (shdr.sh_addr == relplt_addr
- && shdr.sh_size == relplt_size) {
- lte->relplt = elf_getdata(scn, NULL);
- lte->relplt_count =
- shdr.sh_size / shdr.sh_entsize;
- if (lte->relplt == NULL
- || elf_getdata(scn, lte->relplt) != NULL)
- error(EXIT_FAILURE, 0,
- "Couldn't get .rel*.plt data from \"%s\"",
- filename);
- break;
- }
- }
-
- if (i == lte->ehdr.e_shnum)
- error(EXIT_FAILURE, 0,
- "Couldn't find .rel*.plt section in \"%s\"",
- filename);
-
- debug(1, "%s %zd PLT relocations", filename, lte->relplt_count);
+ else if (shdr.sh_type == SHT_DYNSYM)
+ {
+ Elf_Data *data;
+
+ lte->dynsym = elf_getdata (scn, NULL);
+ lte->dynsym_count = shdr.sh_size / shdr.sh_entsize;
+ if (lte->dynsym == NULL || elf_getdata (scn, lte->dynsym) != NULL)
+ error (EXIT_FAILURE, 0, "Couldn't get .dynsym data from \"%s\"",
+ filename);
+
+ scn = elf_getscn (lte->elf, shdr.sh_link);
+ if (scn == NULL || gelf_getshdr (scn, &shdr) == NULL)
+ error (EXIT_FAILURE, 0, "Couldn't get section header from \"%s\"",
+ filename);
+
+ data = elf_getdata (scn, NULL);
+ if (data == NULL || elf_getdata (scn, data) != NULL
+ || shdr.sh_size != data->d_size || data->d_off)
+ error (EXIT_FAILURE, 0, "Couldn't get .dynstr data from \"%s\"",
+ filename);
+
+ lte->dynstr = data->d_buf;
}
+ else if (shdr.sh_type == SHT_DYNAMIC)
+ {
+ Elf_Data *data;
+ size_t j;
+
+ data = elf_getdata (scn, NULL);
+ if (data == NULL || elf_getdata (scn, data) != NULL)
+ error (EXIT_FAILURE, 0, "Couldn't get .dynamic data from \"%s\"",
+ filename);
+
+ for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j)
+ {
+ GElf_Dyn dyn;
+
+ if (gelf_getdyn (data, j, &dyn) == NULL)
+ error (EXIT_FAILURE, 0, "Couldn't get .dynamic data from \"%s\"",
+ filename);
+
+ if (dyn.d_tag == DT_JMPREL)
+ relplt_addr = dyn.d_un.d_ptr;
+ else if (dyn.d_tag == DT_PLTRELSZ)
+ relplt_size = dyn.d_un.d_val;
+ }
+ }
+ else if (shdr.sh_type == SHT_HASH)
+ {
+ Elf_Data *data;
+ size_t j;
+
+ data = elf_getdata (scn, NULL);
+ if (data == NULL || elf_getdata (scn, data) != NULL
+ || data->d_off || data->d_size != shdr.sh_size)
+ error (EXIT_FAILURE, 0, "Couldn't get .hash data from \"%s\"",
+ filename);
+
+ if (shdr.sh_entsize == 4)
+ {
+ /* Standard conforming ELF. */
+ if (data->d_type != ELF_T_WORD)
+ error (EXIT_FAILURE, 0, "Couldn't get .hash data from \"%s\"",
+ filename);
+ lte->hash = (Elf32_Word *) data->d_buf;
+ }
+ else if (shdr.sh_entsize == 8)
+ {
+ /* Alpha or s390x. */
+ Elf32_Word *dst, *src;
+ size_t hash_count = data->d_size / 8;
+
+ lte->hash = (Elf32_Word *)
+ malloc (hash_count * sizeof (Elf32_Word));
+ if (lte->hash == NULL)
+ error (EXIT_FAILURE, 0, "Couldn't convert .hash section from \"%s\"",
+ filename);
+ lte->hash_malloced = 1;
+ dst = lte->hash;
+ src = (Elf32_Word *) data->d_buf;
+ if ((data->d_type == ELF_T_WORD && __BYTE_ORDER == __BIG_ENDIAN)
+ || (data->d_type == ELF_T_XWORD
+ && lte->ehdr.e_ident[EI_DATA] == ELFDATA2MSB))
+ ++src;
+ for (j = 0; j < hash_count; ++j, src += 2)
+ *dst++ = *src;
+ }
+ else
+ error (EXIT_FAILURE, 0, "Unknown .hash sh_entsize in \"%s\"",
+ filename);
+ }
+ else if (shdr.sh_type == SHT_PROGBITS || shdr.sh_type == SHT_NOBITS)
+ {
+ if (strcmp (name, ".plt") == 0)
+ {
+ lte->plt_addr = shdr.sh_addr;
+ lte->plt_size = shdr.sh_size;
+ }
+ else if (strcmp (name, ".opd") == 0)
+ {
+ lte->opd_addr = (GElf_Addr *)shdr.sh_addr;
+ lte->opd_size = shdr.sh_size;
+ lte->opd = elf_rawdata (scn, NULL);
+ }
+ }
+ }
+
+ if (lte->dynsym == NULL || lte->dynstr == NULL)
+ error (EXIT_FAILURE, 0, "Couldn't find .dynsym or .dynstr in \"%s\"",
+ filename);
+
+ if (!relplt_addr || !lte->plt_addr)
+ {
+ debug (1, "%s has no PLT relocations", filename);
+ lte->relplt = NULL;
+ lte->relplt_count = 0;
+ }
+ else
+ {
+ for (i = 1; i < lte->ehdr.e_shnum; ++i)
+ {
+ Elf_Scn *scn;
+ GElf_Shdr shdr;
+
+ scn = elf_getscn (lte->elf, i);
+ if (scn == NULL || gelf_getshdr (scn, &shdr) == NULL)
+ error (EXIT_FAILURE, 0, "Couldn't get section header from \"%s\"",
+ filename);
+ if (shdr.sh_addr == relplt_addr && shdr.sh_size == relplt_size)
+ {
+ lte->relplt = elf_getdata (scn, NULL);
+ lte->relplt_count = shdr.sh_size / shdr.sh_entsize;
+ if (lte->relplt == NULL
+ || elf_getdata (scn, lte->relplt) != NULL)
+ error (EXIT_FAILURE, 0, "Couldn't get .rel*.plt data from \"%s\"",
+ filename);
+ break;
+ }
+ }
+
+ if (i == lte->ehdr.e_shnum)
+ error (EXIT_FAILURE, 0, "Couldn't find .rel*.plt section in \"%s\"",
+ filename);
+
+ debug (1, "%s %zd PLT relocations", filename, lte->relplt_count);
+ }
}
-static void do_close_elf(struct ltelf *lte)
+static void
+do_close_elf (struct ltelf *lte)
{
- if (lte->hash_malloced)
- free((char *)lte->hash);
- elf_end(lte->elf);
- close(lte->fd);
+ if (lte->hash_malloced)
+ free ((char *) lte->hash);
+ elf_end (lte->elf);
+ close (lte->fd);
}
static void
-add_library_symbol(GElf_Addr addr, const char *name,
- struct library_symbol **library_symbolspp)
+add_library_symbol (GElf_Addr addr, const char *name,
+ struct library_symbol **library_symbolspp,
+ int use_elf_plt2addr, int is_weak)
{
- struct library_symbol *s;
- s = malloc(sizeof(struct library_symbol) + strlen(name) + 1);
- if (s == NULL)
- error(EXIT_FAILURE, errno, "add_library_symbol failed");
-
- s->next = *library_symbolspp;
- s->enter_addr = (void *)(uintptr_t) addr;
- s->name = (char *)(s + 1);
- strcpy(s->name, name);
- *library_symbolspp = s;
-
- debug(2, "addr: %p, symbol: \"%s\"", (void *)(uintptr_t) addr, name);
+ struct library_symbol *s;
+ s = malloc (sizeof (struct library_symbol) + strlen (name) + 1);
+ if (s == NULL)
+ error (EXIT_FAILURE, errno, "add_library_symbol failed");
+
+ s->needs_init = 1;
+ s->is_weak = is_weak;
+ s->static_plt2addr = use_elf_plt2addr;
+ s->next = *library_symbolspp;
+ s->enter_addr = (void *) (uintptr_t) addr;
+ s->brkpnt = NULL;
+ s->name = (char *) (s + 1);
+ strcpy (s->name, name);
+ *library_symbolspp = s;
+
+ debug (2, "addr: %p, symbol: \"%s\"", (void *) (uintptr_t) addr, name);
}
-static int in_load_libraries(const char *name, struct ltelf *lte)
+static int
+in_load_libraries (const char *name, struct ltelf *lte)
{
- size_t i;
- unsigned long hash;
-
- if (!library_num)
- return 1;
-
- hash = elf_hash(name);
- for (i = 1; i <= library_num; ++i) {
- Elf32_Word nbuckets, symndx;
- Elf32_Word *buckets, *chain;
-
- if (lte[i].hash == NULL)
- continue;
-
- nbuckets = lte[i].hash[0];
- buckets = &lte[i].hash[2];
- chain = &lte[i].hash[2 + nbuckets];
- for (symndx = buckets[hash % nbuckets];
- symndx != STN_UNDEF; symndx = chain[symndx]) {
- GElf_Sym sym;
-
- if (gelf_getsym(lte[i].dynsym, symndx, &sym) == NULL)
- error(EXIT_FAILURE, 0,
- "Couldn't get symbol from .dynsym");
-
- if (sym.st_value != 0
- && sym.st_shndx != SHN_UNDEF
- && strcmp(name, lte[i].dynstr + sym.st_name) == 0)
- return 1;
- }
+ size_t i;
+ unsigned long hash;
+
+ if (!library_num)
+ return 1;
+
+ hash = elf_hash (name);
+ for (i = 1; i <= library_num; ++i)
+ {
+ Elf32_Word nbuckets, symndx;
+ Elf32_Word *buckets, *chain;
+
+ if (lte[i].hash == NULL)
+ continue;
+
+ nbuckets = lte[i].hash[0];
+ buckets = &lte[i].hash[2];
+ chain = &lte[i].hash[2 + nbuckets];
+ for (symndx = buckets[hash % nbuckets];
+ symndx != STN_UNDEF;
+ symndx = chain[symndx])
+ {
+ GElf_Sym sym;
+
+ if (gelf_getsym (lte[i].dynsym, symndx, &sym) == NULL)
+ error (EXIT_FAILURE, 0, "Couldn't get symbol from .dynsym");
+
+ if (sym.st_value != 0
+ && sym.st_shndx != SHN_UNDEF
+ && strcmp (name, lte[i].dynstr + sym.st_name) == 0)
+ return 1;
}
- return 0;
+ }
+ return 0;
}
-struct library_symbol *read_elf(const char *filename)
+static GElf_Addr
+elf_plt2addr (struct ltelf *lte, void *addr)
{
- struct library_symbol *library_symbols = NULL;
- struct ltelf lte[MAX_LIBRARY + 1];
- size_t i;
-
- elf_version(EV_CURRENT);
-
- do_init_elf(lte, filename);
- for (i = 0; i < library_num; ++i)
- do_init_elf(&lte[i + 1], library[i]);
-
- for (i = 0; i < lte->relplt_count; ++i) {
- GElf_Rel rel;
- GElf_Rela rela;
- GElf_Sym sym;
- GElf_Addr addr;
- void *ret;
- const char *name;
-
- if (lte->relplt->d_type == ELF_T_REL) {
- ret = gelf_getrel(lte->relplt, i, &rel);
- rela.r_offset = rel.r_offset;
- rela.r_info = rel.r_info;
- rela.r_addend = 0;
- } else
- ret = gelf_getrela(lte->relplt, i, &rela);
-
- if (ret == NULL
- || ELF64_R_SYM(rela.r_info) >= lte->dynsym_count
- || gelf_getsym(lte->dynsym, ELF64_R_SYM(rela.r_info),
- &sym) == NULL)
- error(EXIT_FAILURE, 0,
- "Couldn't get relocation from \"%s\"", filename);
-
- name = lte->dynstr + sym.st_name;
- if (in_load_libraries(name, lte)) {
- addr = arch_plt_sym_val(lte, i, &rela);
- if (addr != 0)
- add_library_symbol(addr, name,
- &library_symbols);
- }
- }
-
- for (i = 0; i < library_num + 1; ++i)
- do_close_elf(&lte[i]);
+ long base;
+ long offset;
+ GElf_Addr ret_val;
+
+ if (!lte->opd)
+ return (GElf_Addr)addr;
+
+ base = (long)lte->opd->d_buf;
+ offset = (long)addr - (long)lte->opd_addr;
+ if (offset > lte->opd_size)
+ error (EXIT_FAILURE, 0, "static plt not in .opd");
+
+ ret_val = (GElf_Addr) *(long*)(base + offset);
+ return ret_val;
+}
- return library_symbols;
+struct library_symbol *
+read_elf (struct process * proc)
+{
+ struct library_symbol *library_symbols = NULL;
+ struct ltelf lte[MAX_LIBRARY + 1];
+ size_t i;
+ struct opt_e_t * xptr;
+ struct library_symbol **lib_tail = NULL;
+ struct opt_e_t *main_cheat;
+
+ elf_version (EV_CURRENT);
+
+ do_init_elf (lte, proc->filename);
+ proc->e_machine = lte->ehdr.e_machine;
+ for (i = 0; i < library_num; ++i)
+ do_init_elf (&lte[i + 1], library[i]);
+
+ for (i = 0; i < lte->relplt_count; ++i)
+ {
+ GElf_Rel rel;
+ GElf_Rela rela;
+ GElf_Sym sym;
+ GElf_Addr addr;
+ void *ret;
+ const char *name;
+
+ if (lte->relplt->d_type == ELF_T_REL)
+ {
+ ret = gelf_getrel (lte->relplt, i, &rel);
+ rela.r_offset = rel.r_offset;
+ rela.r_info = rel.r_info;
+ rela.r_addend = 0;
+ }
+ else
+ ret = gelf_getrela (lte->relplt, i, &rela);
+
+ if (ret == NULL
+ || ELF64_R_SYM (rela.r_info) >= lte->dynsym_count
+ || gelf_getsym (lte->dynsym, ELF64_R_SYM (rela.r_info), &sym) == NULL)
+ error (EXIT_FAILURE, 0, "Couldn't get relocation from \"%s\"",
+ proc->filename);
+
+ if ( ! sym.st_value && PLTs_initialized_by_here)
+ proc->need_to_reinitialize_breakpoints = 1;
+
+ name = lte->dynstr + sym.st_name;
+ if (in_load_libraries (name, lte))
+ {
+ addr = arch_plt_sym_val (lte, i, &rela);
+ add_library_symbol (addr, name, &library_symbols, 0,
+ ELF64_ST_BIND (sym.st_info) != 0);
+ if (!lib_tail)
+ lib_tail = &(library_symbols->next);
+ }
+ }
+
+ if (proc->need_to_reinitialize_breakpoints)
+ {
+ /* Add "PLTs_initialized_by_here" to opt_x list, if not already there. */
+ main_cheat = (struct opt_e_t *)malloc(sizeof(struct opt_e_t));
+ if (main_cheat == NULL)
+ error (EXIT_FAILURE, 0, "Couldn allocate memory");
+ main_cheat->next = opt_x;
+ main_cheat->name = PLTs_initialized_by_here;
+
+ for (xptr=opt_x; xptr; xptr=xptr->next)
+ if (strcmp(xptr->name, PLTs_initialized_by_here) == 0 && main_cheat)
+ {
+ free(main_cheat);
+ main_cheat = NULL;
+ break;
+ }
+ if (main_cheat)
+ opt_x = main_cheat;
+ }
+
+ for (i = 0; i < lte->symtab_count; ++i)
+ {
+ GElf_Sym sym;
+ GElf_Addr addr;
+ const char *name;
+
+ if (gelf_getsym (lte->symtab, i, &sym) == NULL)
+ error (EXIT_FAILURE, 0, "Couldn't get symbol from \"%s\"", proc->filename);
+
+ name = lte->strtab + sym.st_name;
+ addr = sym.st_value;
+ if ( ! addr)
+ continue;
+
+ for (xptr=opt_x; xptr; xptr=xptr->next)
+ if (xptr->name && strcmp (xptr->name, name) == 0)
+ {
+ /* FIXME: Should be able to use &library_symbols as above. But
+ when you do, none of the real library symbols cause breaks. */
+ add_library_symbol (elf_plt2addr(lte, (void *)addr), name,
+ lib_tail, 1, 0);
+ break;
+ }
+ }
+ for (xptr=opt_x; xptr; xptr=xptr->next)
+ if (xptr->name)
+ {
+ if (strcmp(xptr->name, E_ENTRY_NAME) == 0)
+ add_library_symbol (elf_plt2addr(lte, (void*)lte->ehdr.e_entry),
+ "_start", lib_tail, 1, 0);
+ else
+ fprintf (stderr, "Warning: Couldn't get symbol \"%s\" "
+ "from \"%s\" or it's a duplicate",
+ xptr->name, proc->filename);
+ }
+
+ for (i = 0; i < library_num + 1; ++i)
+ do_close_elf (&lte[i]);
+
+ return library_symbols;
}
diff --git a/elf.h b/elf.h
index 6f0bf6e..1a318c6 100644
--- a/elf.h
+++ b/elf.h
@@ -18,6 +18,12 @@ struct ltelf
size_t plt_size;
Elf_Data *relplt;
size_t relplt_count;
+ Elf_Data *symtab;
+ const char *strtab;
+ size_t symtab_count;
+ Elf_Data *opd;
+ GElf_Addr *opd_addr;
+ size_t opd_size;
Elf32_Word *hash;
int hash_malloced;
};
@@ -25,7 +31,7 @@ struct ltelf
extern int library_num;
extern char *library[MAX_LIBRARY];
-extern struct library_symbol *read_elf (const char *);
+extern struct library_symbol *read_elf (struct process *);
extern GElf_Addr arch_plt_sym_val (struct ltelf *, size_t, GElf_Rela *);
diff --git a/etc/ltrace.conf b/etc/ltrace.conf
index 14cb7e8..7ecce4d 100644
--- a/etc/ltrace.conf
+++ b/etc/ltrace.conf
@@ -220,7 +220,7 @@ addr calloc(ulong, ulong);
void exit(int);
void free(addr);
string getenv(string);
-int putenv(string);
+int putsenv(string);
int setenv(string,string,int);
void unsetenv(string);
addr malloc(ulong);
diff --git a/execute_program.c b/execute_program.c
index 6697386..09db44a 100644
--- a/execute_program.c
+++ b/execute_program.c
@@ -17,8 +17,8 @@
#include "debug.h"
#include "sysdep.h"
-static void change_uid(struct process *proc)
-{
+static void
+change_uid(struct process * proc) {
uid_t run_uid, run_euid;
gid_t run_gid, run_egid;
@@ -26,8 +26,7 @@ static void change_uid(struct process *proc)
struct passwd *pent;
if (getuid() != 0 || geteuid() != 0) {
- fprintf(stderr,
- "you must be root to use the -u option\n");
+ fprintf(stderr, "you must be root to use the -u option\n");
exit(1);
}
if ((pent = getpwnam(opt_u)) == NULL) {
@@ -69,22 +68,21 @@ static void change_uid(struct process *proc)
}
}
-void execute_program(struct process *sp, char **argv)
-{
+void
+execute_program(struct process * sp, char **argv) {
pid_t pid;
debug(1, "Executing `%s'...", sp->filename);
pid = fork();
- if (pid < 0) {
+ if (pid<0) {
perror("ltrace: fork");
exit(1);
} else if (!pid) { /* child */
change_uid(sp);
trace_me();
execvp(sp->filename, argv);
- fprintf(stderr, "Can't execute `%s': %s\n", sp->filename,
- strerror(errno));
+ fprintf(stderr, "Can't execute `%s': %s\n", sp->filename, strerror(errno));
exit(1);
}
diff --git a/install-sh b/install-sh
index 4d4a951..e843669 100755
--- a/install-sh
+++ b/install-sh
@@ -1,38 +1,19 @@
#!/bin/sh
-# install - install a program, script, or datafile
-
-scriptversion=2005-05-14.22
-
-# This originates from X11R5 (mit/util/scripts/install.sh), which was
-# later released in X11R6 (xc/config/util/install.sh) with the
-# following copyright and license.
-#
-# Copyright (C) 1994 X Consortium
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to
-# deal in the Software without restriction, including without limitation the
-# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-# sell copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
-# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-# Except as contained in this notice, the name of the X Consortium shall not
-# be used in advertising or otherwise to promote the sale, use or other deal-
-# ings in this Software without prior written authorization from the X Consor-
-# tium.
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
#
+# Copyright 1991 by the Massachusetts Institute of Technology
#
-# FSF changes to this file are in the public domain.
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
@@ -42,11 +23,13 @@ scriptversion=2005-05-14.22
# from scratch. It can only install one file at a time, a restriction
# shared with many OS's install programs.
+
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
+
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
@@ -58,266 +41,210 @@ stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
-chowncmd=
-chgrpcmd=
-stripcmd=
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
-src=
-dst=
-dir_arg=
-dstarg=
-no_target_directory=
-
-usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
- or: $0 [OPTION]... SRCFILES... DIRECTORY
- or: $0 [OPTION]... -t DIRECTORY SRCFILES...
- or: $0 [OPTION]... -d DIRECTORIES...
-
-In the 1st form, copy SRCFILE to DSTFILE.
-In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
-In the 4th, create DIRECTORIES.
-
-Options:
--c (ignored)
--d create directories instead of installing files.
--g GROUP $chgrpprog installed files to GROUP.
--m MODE $chmodprog installed files to MODE.
--o USER $chownprog installed files to USER.
--s $stripprog installed files.
--t DIRECTORY install into DIRECTORY.
--T report an error if DSTFILE is a directory.
---help display this help and exit.
---version display version info and exit.
-
-Environment variables override the default commands:
- CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
-"
-
-while test -n "$1"; do
- case $1 in
- -c) shift
- continue;;
-
- -d) dir_arg=true
- shift
- continue;;
-
- -g) chgrpcmd="$chgrpprog $2"
- shift
- shift
- continue;;
-
- --help) echo "$usage"; exit $?;;
-
- -m) chmodcmd="$chmodprog $2"
- shift
- shift
- continue;;
-
- -o) chowncmd="$chownprog $2"
- shift
- shift
- continue;;
-
- -s) stripcmd=$stripprog
- shift
- continue;;
-
- -t) dstarg=$2
- shift
- shift
- continue;;
-
- -T) no_target_directory=true
- shift
- continue;;
-
- --version) echo "$0 $scriptversion"; exit $?;;
-
- *) # When -d is used, all remaining arguments are directories to create.
- # When -t is used, the destination is already specified.
- test -n "$dir_arg$dstarg" && break
- # Otherwise, the last argument is the destination. Remove it from $@.
- for arg
- do
- if test -n "$dstarg"; then
- # $@ is not empty: it contains at least $arg.
- set fnord "$@" "$dstarg"
- shift # fnord
- fi
- shift # arg
- dstarg=$arg
- done
- break;;
- esac
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
done
-if test -z "$1"; then
- if test -z "$dir_arg"; then
- echo "$0: no input file specified." >&2
- exit 1
- fi
- # It's OK to call `install-sh -d' without argument.
- # This can happen when creating conditional directories.
- exit 0
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
fi
-for src
-do
- # Protect names starting with `-'.
- case $src in
- -*) src=./$src ;;
- esac
-
- if test -n "$dir_arg"; then
- dst=$src
- src=
-
- if test -d "$dst"; then
- mkdircmd=:
- chmodcmd=
- else
- mkdircmd=$mkdirprog
- fi
- else
- # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
- # might cause directories to be created, which would be especially bad
- # if $src (and thus $dsttmp) contains '*'.
- if test ! -f "$src" && test ! -d "$src"; then
- echo "$0: $src does not exist." >&2
- exit 1
- fi
-
- if test -z "$dstarg"; then
- echo "$0: no destination specified." >&2
- exit 1
- fi
-
- dst=$dstarg
- # Protect names starting with `-'.
- case $dst in
- -*) dst=./$dst ;;
- esac
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
- # If destination is a directory, append the input filename; won't work
- # if double slashes aren't ignored.
- if test -d "$dst"; then
- if test -n "$no_target_directory"; then
- echo "$0: $dstarg: Is a directory" >&2
- exit 1
- fi
- dst=$dst/`basename "$src"`
- fi
- fi
-
- # This sed command emulates the dirname command.
- dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'`
-
- # Make sure that the destination directory exists.
-
- # Skip lots of stat calls in the usual case.
- if test ! -d "$dstdir"; then
- defaultIFS='
- '
- IFS="${IFS-$defaultIFS}"
-
- oIFS=$IFS
- # Some sh's can't handle IFS=/ for some reason.
- IFS='%'
- set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
- shift
- IFS=$oIFS
-
- pathcomp=
-
- while test $# -ne 0 ; do
- pathcomp=$pathcomp$1
- shift
- if test ! -d "$pathcomp"; then
- $mkdirprog "$pathcomp"
- # mkdir can fail with a `File exist' error in case several
- # install-sh are creating the directory concurrently. This
- # is OK.
- test -d "$pathcomp" || exit
- fi
- pathcomp=$pathcomp/
- done
- fi
-
- if test -n "$dir_arg"; then
- $doit $mkdircmd "$dst" \
- && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
- && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
- && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
- && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
-
- else
- dstfile=`basename "$dst"`
-
- # Make a couple of temp file names in the proper directory.
- dsttmp=$dstdir/_inst.$$_
- rmtmp=$dstdir/_rm.$$_
-
- # Trap to clean up those temp files at exit.
- trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
- trap '(exit $?); exit' 1 2 13 15
-
- # Copy the file name to the temp name.
- $doit $cpprog "$src" "$dsttmp" &&
-
- # and set any options; do chmod last to preserve setuid bits.
- #
- # If any of these fail, we abort the whole thing. If we want to
- # ignore errors from any of these, just make sure not to ignore
- # errors from the above "$doit $cpprog $src $dsttmp" command.
- #
- { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
- && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
- && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
- && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
-
- # Now rename the file to the real destination.
- { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \
- || {
- # The rename failed, perhaps because mv can't rename something else
- # to itself, or perhaps because mv is so ancient that it does not
- # support -f.
-
- # Now remove or move aside any old file at destination location.
- # We try this two ways since rm can't unlink itself on some
- # systems and the destination file might be busy for other
- # reasons. In this case, the final cleanup might fail but the new
- # file should still install successfully.
- {
- if test -f "$dstdir/$dstfile"; then
- $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
- || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
- || {
- echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
- (exit 1); exit 1
- }
- else
- :
- fi
- } &&
-
- # Now rename the file to the real destination.
- $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
- }
- }
- fi || { (exit 1); exit 1; }
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
-# The final little trick to "correctly" pass the exit status to the exit trap.
-{
- (exit 0); exit 0
-}
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-end: "$"
-# End:
+exit 0
diff --git a/ltrace.1 b/ltrace.1
index 93ba0bb..4780825 100644
--- a/ltrace.1
+++ b/ltrace.1
@@ -1,14 +1,14 @@
-.\" Copyright (c) 1997-2004 Juan Cespedes <cespedes@debian.org>
+.\" Copyright (c) 1997-2005 Juan Cespedes <cespedes@debian.org>
.\" This file is covered by the GNU GPL
-.TH "ltrace" "1" "" "" ""
-.SH "NAME"
+.TH ltrace 1
+.SH NAME
ltrace \- A library call tracer
-.SH "SYNOPSIS"
+.SH SYNOPSIS
.B ltrace
-.I "[\-CdfhiLrStttV] [\-a column] [\-e expr] [\-l filename] [\-n nr] [\-o filename] [\-p pid] ... [\-s strsize] [\-u username] [\-\-align=column] [\-\-debug] [\-\-demangle] [\-\-help] [\-\-indent=nr] [\-\-library=filename] [\-\-output=filename] [\-\-version] [command [arg ...]]"
+.I "[-CdfhiLrStttV] [-a column] [-e expr] [-l filename] [-n nr] [-o filename] [-p pid] ... [-s strsize] [-u username] [-X extern] [-x extern] ... [--align=column] [--debug] [--demangle] [--help] [--indent=nr] [--library=filename] [--output=filename] [--version] [command [arg ...]]"
-.SH "DESCRIPTION"
+.SH DESCRIPTION
.B ltrace
is a program that simply runs the specified
.I command
@@ -16,148 +16,158 @@ until it exits. It intercepts and records the dynamic library calls
which are called by the executed process and the signals which are
received by that process.
It can also intercept and print the system calls executed by the program.
-.PP
+.PP
Its use is very similar to
.BR strace(1) .
-.SH "OPTIONS"
-.TP
+.SH OPTIONS
+.TP
.I \-a, \-\-align column
Align return values in a secific column (default column is 5/8 of screen width).
-.TP
+.TP
.I \-c
Count time and calls for each library call and report a summary on program exit.
-.TP
+.TP
.I \-C, \-\-demangle
-Decode (demangle) low\-level symbol names into user\-level names.
+Decode (demangle) low-level symbol names into user-level names.
Besides removing any initial underscore prepended by the system,
this makes C++ function names readable.
-.TP
+.TP
.I \-d, \-\-debug
Increase the debugging level.
Use more (ie.
-.I \-dd
+.I \=dd
) for greater debugging information.
-.TP
+.TP
.I \-e expr
A qualifying expression which modifies which events to trace.
The format of the expression is:
-.br
+.br
[!]value1[,value2]...
-.br
+.br
where the values are the functions to trace. Using an exclamation
mark negates the set of values. For example
.I \-e printf
means to trace only the printf library call. By contrast,
.I \-e !printf
means to trace every library call except printf.
-.IP
+.IP
Note that some shells use the exclamation point for history
expansion; even inside quoted arguments. If so, you must escape
the exclamation point with a backslash.
-.TP
+.TP
.I \-f
Trace child processes as they are created by
currently traced processes as a result of the fork(2)
or clone(2) system calls.
The new process is attached as soon as its pid is known.
-.TP
+.TP
.I \-h, \-\-help
Show a summary of the options to ltrace and exit.
-.TP
+.TP
.I \-i
Print the instruction pointer at the time of the library call.
-.TP
+.TP
.I \-l, \-\-library filename
Display only the symbols included in the library
.I filename.
Up to 20 library names can be specified with several instances
of this option.
-.TP
+.TP
.I \-L
DON'T display library calls (use it with the
.I \-S
option).
-.TP
+.TP
.I \-n, \-\-indent nr
Indent trace output by
.I nr
number of spaces for each new nested call. Using this option makes
the program flow visualization easy to follow.
-.TP
+.TP
.I \-o, \-\-output filename
Write the trace output to the file
.I filename
rather than to stderr.
-.TP
+.TP
.I \-p pid
Attach to the process with the process ID
.I pid
and begin tracing.
-.TP
+.TP
.I \-r
Print a relative timestamp with each line of the trace.
This records the time difference between the beginning of
successive lines.
-.TP
+.TP
.I \-s strsize
Specify the maximum string size to print (the default is 32).
-.TP
+.TP
.I \-S
Display system calls as well as library calls
-.TP
+.TP
.I \-t
Prefix each line of the trace with the time of day.
-.TP
+.TP
.I \-tt
If given twice, the time printed will include the microseconds.
-.TP
+.TP
.I \-ttt
If given thrice, the time printed will include the microseconds and
the leading portion will be printed as the number of seconds since the
epoch.
-.TP
+.TP
.I \-T
Show the time spent inside each call. This records the time difference
between the beginning and the end of each call.
-.TP
+.TP
.I \-u username
Run command with the userid, groupid and supplementary groups of
-.I R username .
+.IR username .
This option is only useful when running as root and enables the
correct execution of setuid and/or setgid binaries.
-.TP
+.TP
+.I \-X extern
+Some architectures need to know where to set a breakpoint that will be hit
+after the dynamic linker has run. If this flag is used, then the breakpoint
+is set at
+.IR extern ,
+which must be an external function. By default, 'main' is used.
+.TP
+.I \-x extern
+Trace the external function
+.IR extern .
+This option may be repeated.
+.TP
.I \-V, \-\-version
Show the version number of ltrace and exit.
-.SH "BUGS"
+.SH BUGS
It has most of the bugs stated in
.BR strace(1) .
-.LP
-Manual page and documentation are not very up\-to\-date.
-.LP
-Option \-f sometimes fails to trace some children.
-.LP
+.LP
+Manual page and documentation are not very up-to-date.
+.LP
+Option -f sometimes fails to trace some children.
+.LP
It only works on Linux and in a small subset of architectures.
-.LP
+.LP
Only ELF32 binaries are supported.
-.LP
-Calls to dlopen()ed libraries will not be traced
-.PP
-If you would like to report a bug, send a notice to the author, or use the
-.BR reportbug(1)
+.PP
+If you like to report a bug, send a notice to the author, or use the
+.BR bug(1)
program if you are under the Debian GNU/Linux distribution.
-.SH "FILES"
-.TP
+.SH FILES
+.TP
.I /etc/ltrace.conf
System configuration file
-.TP
+.TP
.I ~/.ltrace.conf
Personal config file, overrides
.I /etc/ltrace.conf
-.SH "AUTHOR"
+.SH AUTHOR
Juan Cespedes <cespedes@debian.org>
.SH "SEE ALSO"
diff --git a/ltrace.c b/ltrace.c
index 0e60839..d31a981 100644
--- a/ltrace.c
+++ b/ltrace.c
@@ -22,19 +22,19 @@
#define SYSCONFDIR "/etc"
#endif
-char *command = NULL;
-struct process *list_of_processes = NULL;
+char * command = NULL;
+struct process * list_of_processes = NULL;
-int exiting = 0; /* =1 if a SIGINT or SIGTERM has been received */
+int exiting=0; /* =1 if a SIGINT or SIGTERM has been received */
-static void signal_alarm(int sig)
-{
- struct process *tmp = list_of_processes;
+static void
+signal_alarm(int sig) {
+ struct process * tmp = list_of_processes;
- signal(SIGALRM, SIG_DFL);
- while (tmp) {
- struct opt_p_t *tmp2 = opt_p;
- while (tmp2) {
+ signal(SIGALRM,SIG_DFL);
+ while(tmp) {
+ struct opt_p_t * tmp2 = opt_p;
+ while(tmp2) {
if (tmp->pid == tmp2->pid) {
tmp = tmp->next;
if (!tmp) {
@@ -44,23 +44,23 @@ static void signal_alarm(int sig)
}
tmp2 = tmp2->next;
}
- debug(2, "Sending SIGSTOP to process %u\n", tmp->pid);
+ debug(2,"Sending SIGSTOP to process %u\n",tmp->pid);
kill(tmp->pid, SIGSTOP);
tmp = tmp->next;
}
}
-static void signal_exit(int sig)
-{
- exiting = 1;
- debug(1, "Received interrupt signal; exiting...");
- signal(SIGINT, SIG_IGN);
- signal(SIGTERM, SIG_IGN);
- signal(SIGALRM, signal_alarm);
+static void
+signal_exit(int sig) {
+ exiting=1;
+ debug(1,"Received interrupt signal; exiting...");
+ signal(SIGINT,SIG_IGN);
+ signal(SIGTERM,SIG_IGN);
+ signal(SIGALRM,signal_alarm);
if (opt_p) {
- struct opt_p_t *tmp = opt_p;
- while (tmp) {
- debug(2, "Sending SIGSTOP to process %u\n", tmp->pid);
+ struct opt_p_t * tmp = opt_p;
+ while(tmp) {
+ debug(2,"Sending SIGSTOP to process %u\n",tmp->pid);
kill(tmp->pid, SIGSTOP);
tmp = tmp->next;
}
@@ -68,41 +68,41 @@ static void signal_exit(int sig)
alarm(1);
}
-static void normal_exit(void)
-{
- output_line(0, 0);
+static void
+normal_exit(void) {
+ output_line(0,0);
if (opt_c) {
show_summary();
}
}
-static void guess_cols(void)
-{
+static void
+guess_cols(void) {
struct winsize ws;
- char *c;
+ char * c;
opt_a = DEFAULT_ACOLUMN;
c = getenv("COLUMNS");
if (c && *c) {
- char *endptr;
+ char * endptr;
int cols;
cols = strtol(c, &endptr, 0);
- if (cols > 0 && !*endptr) {
- opt_a = cols * 5 / 8;
+ if (cols>0 && !*endptr) {
+ opt_a = cols * 5/8;
}
- } else if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 0) {
- opt_a = ws.ws_col * 5 / 8;
+ } else if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col>0) {
+ opt_a = ws.ws_col * 5/8;
}
}
-int main(int argc, char **argv)
-{
- struct opt_p_t *opt_p_tmp;
- char *home;
+int
+main(int argc, char **argv) {
+ struct opt_p_t * opt_p_tmp;
+ char * home;
atexit(normal_exit);
- signal(SIGINT, signal_exit); /* Detach processes when interrupted */
- signal(SIGTERM, signal_exit); /* ... or killed */
+ signal(SIGINT,signal_exit); /* Detach processes when interrupted */
+ signal(SIGTERM,signal_exit); /* ... or killed */
guess_cols();
argv = process_options(argc, argv);
@@ -110,7 +110,7 @@ int main(int argc, char **argv)
home = getenv("HOME");
if (home) {
char path[PATH_MAX];
- if (strlen(home) > PATH_MAX - 15) {
+ if (strlen(home) > PATH_MAX-15) {
fprintf(stderr, "Error: $HOME too long\n");
exit(1);
}
@@ -119,21 +119,21 @@ int main(int argc, char **argv)
read_config_file(path);
}
if (opt_e) {
- struct opt_e_t *tmp = opt_e;
- while (tmp) {
- debug(1, "Option -e: %s\n", tmp->name);
+ struct opt_e_t * tmp = opt_e;
+ while(tmp) {
+ debug(1,"Option -e: %s\n", tmp->name);
tmp = tmp->next;
}
}
if (command) {
- execute_program(open_program(command), argv);
+ execute_program(open_program(command,0), argv);
}
opt_p_tmp = opt_p;
while (opt_p_tmp) {
open_pid(opt_p_tmp->pid, 1);
opt_p_tmp = opt_p_tmp->next;
}
- while (1) {
+ while(1) {
process_event(wait_for_something());
}
}
diff --git a/ltrace.h b/ltrace.h
index 98586cf..08cf626 100644
--- a/ltrace.h
+++ b/ltrace.h
@@ -25,6 +25,7 @@ struct breakpoint {
void * addr;
unsigned char orig_value[BREAKPOINT_LENGTH];
int enabled;
+ struct library_symbol * libsym;
};
enum arg_type {
@@ -40,12 +41,12 @@ enum arg_type {
ARGTYPE_FILE,
ARGTYPE_FORMAT, /* printf-like format */
ARGTYPE_STRING,
- ARGTYPE_STRINGN,
-};
-
-struct complete_arg_type {
- enum arg_type at;
- int argno; /* for STRINGN */
+ ARGTYPE_STRING0, /* stringN: string up to (arg N) bytes */
+ ARGTYPE_STRING1,
+ ARGTYPE_STRING2,
+ ARGTYPE_STRING3,
+ ARGTYPE_STRING4,
+ ARGTYPE_STRING5
};
enum tof {
@@ -58,20 +59,25 @@ enum tof {
struct function {
const char * name;
- struct complete_arg_type return_type;
+ enum arg_type return_type;
int num_params;
- struct complete_arg_type arg_types[MAX_ARGS];
+ enum arg_type arg_types[MAX_ARGS];
int params_right;
struct function * next;
};
extern struct function * list_of_functions;
+extern char * PLTs_initialized_by_here;
struct library_symbol {
- char * name;
- void * enter_addr;
-
- struct library_symbol * next;
+ char * name;
+ void * enter_addr;
+ struct breakpoint *brkpnt;
+ char needs_init;
+ char static_plt2addr;
+ char is_weak;
+
+ struct library_symbol * next;
};
struct callstack_element {
@@ -91,6 +97,9 @@ struct process {
pid_t pid;
struct dict * breakpoints;
int breakpoints_enabled; /* -1:not enabled yet, 0:disabled, 1:enabled */
+ int mask_32bit; /* 1 if 64-bit ltrace is tracing 32-bit process. */
+ int personality;
+ int tracesysgood; /* signal indicating a PTRACE_SYSCALL trap */
int callstack_depth;
struct callstack_element callstack[MAX_CALLDEPTH];
@@ -102,6 +111,8 @@ struct process {
void * return_addr;
struct breakpoint * breakpoint_being_enabled;
void * arch_ptr;
+ short e_machine;
+ short need_to_reinitialize_breakpoints;
/* output: */
enum tof type_being_displayed;
@@ -142,20 +153,23 @@ extern void * instruction_pointer;
extern struct event * wait_for_something(void);
extern void process_event(struct event * event);
extern void execute_program(struct process *, char **);
-extern int display_arg(enum tof type, struct process * proc, int arg_num, const struct complete_arg_type *at);
+extern int display_arg(enum tof type, struct process * proc, int arg_num, enum arg_type at);
extern struct breakpoint * address2bpstruct(struct process * proc, void * addr);
extern void breakpoints_init(struct process * proc);
-extern void insert_breakpoint(struct process * proc, void * addr);
+extern void insert_breakpoint(struct process * proc, void * addr, struct library_symbol * libsym);
extern void delete_breakpoint(struct process * proc, void * addr);
extern void enable_all_breakpoints(struct process * proc);
extern void disable_all_breakpoints(struct process * proc);
-extern struct process * open_program(char * filename);
+extern void reinitialize_breakpoints (struct process *);
+
+extern struct process * open_program(char * filename, pid_t pid);
extern void open_pid(pid_t pid, int verbose);
extern void show_summary(void);
/* Arch-dependent stuff: */
extern char * pid2name(pid_t pid);
+extern void trace_set_options(struct process * proc, pid_t pid);
extern void trace_me(void);
extern int trace_pid(pid_t pid);
extern void untrace_pid(pid_t pid);
@@ -166,8 +180,8 @@ extern void * get_stack_pointer(struct process * proc);
extern void * get_return_addr(struct process * proc, void * stack_pointer);
extern void enable_breakpoint(pid_t pid, struct breakpoint * sbp);
extern void disable_breakpoint(pid_t pid, const struct breakpoint * sbp);
-extern int fork_p(int sysnum);
-extern int exec_p(int sysnum);
+extern int fork_p(struct process * proc, int sysnum);
+extern int exec_p(struct process * proc, int sysnum);
extern int syscall_p(struct process * proc, int status, int * sysnum);
extern void continue_process(pid_t pid);
extern void continue_after_signal(pid_t pid, int signum);
@@ -177,6 +191,8 @@ extern long gimme_arg(enum tof type, struct process * proc, int arg_num);
extern void save_register_args(enum tof type, struct process * proc);
extern int umovestr(struct process * proc, void * addr, int len, void * laddr);
extern int ffcheck(void *maddr);
+extern void * plt2addr(struct process *, void **);
+
#if 0 /* not yet */
extern int umoven(struct process * proc, void * addr, int len, void * laddr);
#endif
diff --git a/ltrace.spec b/ltrace.spec
new file mode 100644
index 0000000..3740190
--- /dev/null
+++ b/ltrace.spec
@@ -0,0 +1,164 @@
+Summary: Tracks runtime library calls from dynamically linked executables.
+Name: ltrace
+Version: 0.3.36
+Release: 4.2
+Source: ftp://ftp.debian.org/debian/pool/main/l/ltrace/ltrace_%{version}.orig.tar.gz
+Patch1: ftp://ftp.debian.org/debian/pool/main/l/ltrace/ltrace_0.3.36-2.diff.gz
+Patch2: ltrace-ppc64.patch
+Patch3: ltrace-ppc64-2.patch
+Patch4: ltrace-s390x.patch
+Patch5: ltrace-syscallent-update.patch
+Patch6: ltrace-fixes.patch
+Patch7: ltrace-ia64.patch
+License: GPL
+Group: Development/Debuggers
+ExclusiveArch: i386 x86_64 ia64 ppc ppc64 s390 s390x alpha sparc
+Prefix: %{_prefix}
+BuildRoot: /var/tmp/%{name}-root
+BuildRequires: elfutils-libelf-devel
+
+%description
+Ltrace is a debugging program which runs a specified command until the
+command exits. While the command is executing, ltrace intercepts and
+records both the dynamic library calls called by the executed process
+and the signals received by the executed process. Ltrace can also
+intercept and print system calls executed by the process.
+
+You should install ltrace if you need a sysadmin tool for tracking the
+execution of processes.
+
+%prep
+%setup -q
+%patch1 -p1
+%patch2 -p1
+%patch3 -p1
+%patch4 -p1
+%patch5 -p1
+%patch6 -p1
+%patch7 -p1
+sed -i -e 's/-o root -g root//' Makefile.in
+
+%build
+export CC="gcc`echo $RPM_OPT_FLAGS | sed -n 's/^.*\(-m[36][124]\).*$/ \1/p'`"
+%configure CC="$CC"
+make
+
+%install
+make DESTDIR=$RPM_BUILD_ROOT mandir=%{_mandir} install
+rm -f ChangeLog; mv -f debian/changelog ChangeLog
+rm -rf $RPM_BUILD_ROOT/%{_prefix}/doc
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%doc COPYING README TODO BUGS ChangeLog
+%{_prefix}/bin/ltrace
+%{_mandir}/man1/ltrace.1*
+%config /etc/ltrace.conf
+
+%changelog
+* Fri Feb 10 2006 Jesse Keating <jkeating@redhat.com> - 0.3.36-4.2
+- bump again for double-long bug on ppc(64)
+
+* Tue Feb 07 2006 Jesse Keating <jkeating@redhat.com> - 0.3.36-4.1
+- rebuilt for new gcc4.1 snapshot and glibc changes
+
+* Mon Jan 9 2006 Jakub Jelinek <jakub@redhat.com> 0.3.36-4
+- added ppc64 and s390x support (IBM)
+- added ia64 support (Ian Wienand)
+
+* Sat Mar 5 2005 Jakub Jelinek <jakub@redhat.com> 0.3.36-3
+- rebuilt with GCC 4
+
+* Tue Dec 14 2004 Jakub Jelinek <jakub@redhat.com> 0.3.36-2
+- make x86_64 ltrace trace both 32-bit and 64-bit binaries (#141955,
+ IT#55600)
+- fix tracing across execve
+- fix printf-style format handling on 64-bit arches
+
+* Thu Nov 18 2004 Jakub Jelinek <jakub@redhat.com> 0.3.36-1
+- update to 0.3.36
+
+* Mon Oct 11 2004 Jakub Jelinek <jakub@redhat.com> 0.3.35-1
+- update to 0.3.35
+- update syscall tables from latest kernel source
+
+* Tue Jun 15 2004 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Tue Jun 8 2004 Jakub Jelinek <jakub@redhat.com> 0.3.32-3
+- buildreq elfutils-libelf-devel (#124921)
+
+* Thu Apr 22 2004 Jakub Jelinek <jakub@redhat.com> 0.3.32-2
+- fix demangling
+
+* Thu Apr 22 2004 Jakub Jelinek <jakub@redhat.com> 0.3.32-1
+- update to 0.3.32
+ - fix dict.c assertion (#114359)
+ - x86_64 support
+- rewrite elf.[ch] using libelf
+- don't rely on st_value of SHN_UNDEF symbols in binaries,
+ instead walk .rel{,a}.plt and compute the addresses (#115299)
+- fix x86-64 support
+- some ltrace.conf additions
+- some format string printing fixes
+
+* Fri Feb 13 2004 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Mon Feb 3 2003 Jakub Jelinek <jakub@redhat.com> 0.3.29-1
+- update to 0.3.29
+
+* Wed Jan 22 2003 Tim Powers <timp@redhat.com>
+- rebuilt
+
+* Sun Sep 1 2002 Jakub Jelinek <jakub@redhat.com> 0.3.10-12
+- add a bunch of missing functions to ltrace.conf
+ (like strlen, ugh)
+
+* Fri Jun 21 2002 Tim Powers <timp@redhat.com>
+- automated rebuild
+
+* Tue May 28 2002 Phil Knirsch <pknirsch@redhat.com>
+- Added the 'official' s390 patch.
+
+* Thu May 23 2002 Tim Powers <timp@redhat.com>
+- automated rebuild
+
+* Wed Jan 09 2002 Tim Powers <timp@redhat.com>
+- automated rebuild
+
+* Fri Jul 20 2001 Jakub Jelinek <jakub@redhat.com>
+- fix stale symlink in documentation directory (#47749)
+
+* Sun Jun 24 2001 Elliot Lee <sopwith@redhat.com>
+- Bump release + rebuild.
+
+* Thu Aug 2 2000 Tim Waugh <twaugh@redhat.com>
+- fix off-by-one problem in checking syscall number
+
+* Wed Jul 12 2000 Prospector <bugzilla@redhat.com>
+- automatic rebuild
+
+* Mon Jun 19 2000 Matt Wilson <msw@redhat.com>
+- rebuilt for next release
+- patched Makefile.in to take a hint on mandir (patch2)
+- use %%{_mandir} and %%makeinstall
+
+* Wed Feb 02 2000 Cristian Gafton <gafton@redhat.com>
+- fix description
+
+* Fri Jan 7 2000 Jeff Johnson <jbj@redhat.com>
+- update to 0.3.10.
+- include (but don't apply) sparc patch from Jakub Jellinek.
+
+* Sun Mar 21 1999 Cristian Gafton <gafton@redhat.com>
+- auto rebuild in the new build environment (release 2)
+
+* Fri Mar 12 1999 Jeff Johnson <jbj@redhat.com>
+- update to 0.3.6.
+
+* Mon Sep 21 1998 Preston Brown <pbrown@redhat.com>
+- upgraded to 0.3.4
diff --git a/options.c b/options.c
index 4f02a06..63f2ff3 100644
--- a/options.c
+++ b/options.c
@@ -2,6 +2,10 @@
#include "config.h"
#endif
+#ifndef PACKAGE_VERSION
+# define PACKAGE_VERSION "0.3.32"
+#endif
+
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
@@ -21,7 +25,7 @@
char *library[MAX_LIBRARY];
int library_num = 0;
static char *progname; /* Program name (`ltrace') */
-FILE *output;
+FILE * output;
int opt_a = DEFAULT_ACOLUMN; /* default alignment column for results */
int opt_c = 0; /* Count time, calls, and report a summary on program exit */
int opt_d = 0; /* debug */
@@ -30,7 +34,7 @@ int opt_s = DEFAULT_STRLEN; /* default maximum # of bytes printed in strings */
int opt_S = 0; /* display syscalls */
int opt_L = 1; /* display library calls */
int opt_f = 0; /* trace child processes as they are created */
-char *opt_u = NULL; /* username to run command as */
+char * opt_u = NULL; /* username to run command as */
int opt_r = 0; /* print relative timestamp */
int opt_t = 0; /* print absolute timestamp */
#ifdef USE_DEMANGLE
@@ -40,81 +44,91 @@ int opt_n = 0; /* indent trace output according to program flow */
int opt_T = 0; /* show the time spent inside each call */
/* List of pids given to option -p: */
-struct opt_p_t *opt_p = NULL; /* attach to process with a given pid */
+struct opt_p_t * opt_p = NULL; /* attach to process with a given pid */
/* List of function names given to option -e: */
-struct opt_e_t *opt_e = NULL;
-int opt_e_enable = 1;
+struct opt_e_t * opt_e = NULL;
+int opt_e_enable=1;
+
+/* List of global function names given to -x: */
+struct opt_e_t * opt_x = NULL;
+
+/* Set a break on the routine named here in order to re-initialize breakpoints
+ after all the PLTs have been initialzed */
+char * PLTs_initialized_by_here = PLTs_INIT_BY_HERE;
-static void usage(void)
-{
+static void
+usage(void) {
#if !(HAVE_GETOPT || HAVE_GETOPT_LONG)
fprintf(stdout, "Usage: %s [command [arg ...]]\n"
- "Trace library calls of a given program.\n\n", progname);
+"Trace library calls of a given program.\n\n", progname);
#else
fprintf(stdout, "Usage: %s [option ...] [command [arg ...]]\n"
- "Trace library calls of a given program.\n\n"
+"Trace library calls of a given program.\n\n"
+
# if HAVE_GETOPT_LONG
- " -a, --align=COLUMN align return values in a secific column.\n"
+" -a, --align=COLUMN align return values in a secific column.\n"
# else
- " -a COLUMN align return values in a secific column.\n"
+" -a COLUMN align return values in a secific column.\n"
# endif
- " -c count time and calls, and report a summary on exit.\n"
+" -c count time and calls, and report a summary on exit.\n"
# ifdef USE_DEMANGLE
# if HAVE_GETOPT_LONG
- " -C, --demangle decode low-level symbol names into user-level names.\n"
+" -C, --demangle decode low-level symbol names into user-level names.\n"
# else
- " -C decode low-level symbol names into user-level names.\n"
+" -C decode low-level symbol names into user-level names.\n"
# endif
# endif
# if HAVE_GETOPT_LONG
- " -d, --debug print debugging info.\n"
+" -d, --debug print debugging info.\n"
# else
- " -d print debugging info.\n"
+" -d print debugging info.\n"
# endif
- " -e expr modify which events to trace.\n"
- " -f follow forks.\n"
+" -e expr modify which events to trace.\n"
+" -f follow forks.\n"
# if HAVE_GETOPT_LONG
- " -h, --help display this help and exit.\n"
+" -h, --help display this help and exit.\n"
# else
- " -h display this help and exit.\n"
+" -h display this help and exit.\n"
# endif
- " -i print instruction pointer at time of library call.\n"
+" -i print instruction pointer at time of library call.\n"
# if HAVE_GETOPT_LONG
- " -l, --library=FILE print library calls from this library only.\n"
+" -l, --library=FILE print library calls from this library only.\n"
# else
- " -l FILE print library calls from this library only.\n"
+" -l FILE print library calls from this library only.\n"
# endif
- " -L do NOT display library calls.\n"
+" -L do NOT display library calls.\n"
# if HAVE_GETOPT_LONG
- " -n, --indent=NR indent output by NR spaces for each call level nesting.\n"
+" -n, --indent=NR indent output by NR spaces for each call level nesting.\n"
# else
- " -n NR indent output by NR spaces for each call level nesting.\n"
+" -n NR indent output by NR spaces for each call level nesting.\n"
# endif
# if HAVE_GETOPT_LONG
- " -o, --output=FILE write the trace output to that file.\n"
+" -o, --output=FILE write the trace output to that file.\n"
# else
- " -o FILE write the trace output to that file.\n"
+" -o FILE write the trace output to that file.\n"
# endif
- " -p PID attach to the process with the process ID pid.\n"
- " -r print relative timestamps.\n"
- " -s STRLEN specify the maximum string size to print.\n"
- " -S display system calls.\n"
- " -t, -tt, -ttt print absolute timestamps.\n"
- " -T show the time spent inside each call.\n"
- " -u USERNAME run command with the userid, groupid of username.\n"
+" -p PID attach to the process with the process ID pid.\n"
+" -r print relative timestamps.\n"
+" -s STRLEN specify the maximum string size to print.\n"
+" -S display system calls.\n"
+" -t, -tt, -ttt print absolute timestamps.\n"
+" -T show the time spent inside each call.\n"
+" -u USERNAME run command with the userid, groupid of username.\n"
# if HAVE_GETOPT_LONG
- " -V, --version output version information and exit.\n"
+" -V, --version output version information and exit.\n"
# else
- " -V output version information and exit.\n"
+" -V output version information and exit.\n"
# endif
- "\nReport bugs to Juan Cespedes <cespedes@debian.org>\n",
- progname);
+" -x NAME treat the global NAME like a library subroutine.\n"
+" -X NAME same as -x; and PLT's will be initialized by here.\n"
+"\nReport bugs to Juan Cespedes <cespedes@debian.org>\n"
+ , progname);
#endif
}
-static char *search_for_command(char *filename)
-{
+static char *
+search_for_command(char * filename) {
static char pathname[PATH_MAX];
char *path;
int m, n;
@@ -145,193 +159,189 @@ static char *search_for_command(char *filename)
return filename;
}
-char **process_options(int argc, char **argv)
-{
+char **
+process_options(int argc, char **argv) {
progname = argv[0];
output = stderr;
#if HAVE_GETOPT || HAVE_GETOPT_LONG
- while (1) {
+ while(1) {
int c;
#if HAVE_GETOPT_LONG
int option_index = 0;
static struct option long_options[] = {
- {"align", 1, 0, 'a'},
- {"debug", 0, 0, 'd'},
+ { "align", 1, 0, 'a'},
+ { "debug", 0, 0, 'd'},
# ifdef USE_DEMANGLE
- {"demangle", 0, 0, 'C'},
+ { "demangle", 0, 0, 'C'},
#endif
- {"indent", 1, 0, 'n'},
- {"help", 0, 0, 'h'},
- {"library", 1, 0, 'l'},
- {"output", 1, 0, 'o'},
- {"version", 0, 0, 'V'},
- {0, 0, 0, 0}
+ { "indent", 1, 0, 'n'},
+ { "help", 0, 0, 'h'},
+ { "library", 1, 0, 'l'},
+ { "output", 1, 0, 'o'},
+ { "version", 0, 0, 'V'},
+ { 0, 0, 0, 0}
};
c = getopt_long(argc, argv, "+cdfhiLrStTV"
# ifdef USE_DEMANGLE
- "C"
+ "C"
# endif
- "a:e:l:n:o:p:s:u:", long_options,
- &option_index);
+ "a:e:l:n:o:p:s:u:x:X:", long_options, &option_index);
#else
c = getopt(argc, argv, "+cdfhiLrStTV"
# ifdef USE_DEMANGLE
- "C"
+ "C"
# endif
- "a:e:l:n:o:p:s:u:");
+ "a:e:l:n:o:p:s:u:x:X:");
#endif
- if (c == -1) {
+ if (c==-1) {
break;
}
- switch (c) {
- case 'a':
- opt_a = atoi(optarg);
- break;
- case 'c':
- opt_c++;
- break;
+ switch(c) {
+ case 'a': opt_a = atoi(optarg);
+ break;
+ case 'c': opt_c++;
+ break;
#ifdef USE_DEMANGLE
- case 'C':
- opt_C++;
- break;
+ case 'C': opt_C++;
+ break;
#endif
- case 'd':
- opt_d++;
- break;
- case 'e':
- {
- char *str_e = strdup(optarg);
- if (!str_e) {
- perror("ltrace: strdup");
- exit(1);
- }
- if (str_e[0] == '!') {
- opt_e_enable = 0;
- str_e++;
- }
- while (*str_e) {
- struct opt_e_t *tmp;
- char *str2 = strchr(str_e, ',');
- if (str2) {
- *str2 = '\0';
+ case 'd': opt_d++;
+ break;
+ case 'e':
+ {
+ char * str_e = strdup(optarg);
+ if (!str_e) {
+ perror("ltrace: strdup");
+ exit(1);
+ }
+ if (str_e[0]=='!') {
+ opt_e_enable=0;
+ str_e++;
}
- tmp = malloc(sizeof(struct opt_e_t));
+ while(*str_e) {
+ struct opt_e_t * tmp;
+ char *str2 = strchr(str_e,',');
+ if (str2) {
+ *str2 = '\0';
+ }
+ tmp = malloc(sizeof(struct opt_e_t));
+ if (!tmp) {
+ perror("ltrace: malloc");
+ exit(1);
+ }
+ tmp->name = str_e;
+ tmp->next = opt_e;
+ opt_e = tmp;
+ if (str2) {
+ str_e = str2+1;
+ } else {
+ break;
+ }
+ }
+ break;
+ }
+ case 'f': opt_f = 1;
+ break;
+ case 'h': usage();
+ exit(0);
+ case 'i': opt_i++;
+ break;
+ case 'l': if (library_num == MAX_LIBRARY) {
+ fprintf(stderr, "Too many libraries. Maximum is %i.\n", MAX_LIBRARY);
+ exit(1);
+ }
+ library[library_num++] = optarg;
+ break;
+ case 'L': opt_L = 0;
+ break;
+ case 'n': opt_n = atoi(optarg);
+ break;
+ case 'o': output = fopen(optarg, "w");
+ if (!output) {
+ fprintf(stderr, "Can't open %s for output: %s\n", optarg, strerror(errno));
+ exit(1);
+ }
+ setvbuf(output, (char *)NULL, _IOLBF, 0);
+ fcntl(fileno(output), F_SETFD, FD_CLOEXEC);
+ break;
+ case 'p':
+ {
+ struct opt_p_t * tmp = malloc(sizeof(struct opt_p_t));
if (!tmp) {
perror("ltrace: malloc");
exit(1);
}
- tmp->name = str_e;
- tmp->next = opt_e;
- opt_e = tmp;
- if (str2) {
- str_e = str2 + 1;
- } else {
+ tmp->pid = atoi(optarg);
+ tmp->next = opt_p;
+ opt_p = tmp;
+ break;
+ }
+ case 'r': opt_r++;
break;
+ case 's': opt_s = atoi(optarg);
+ break;
+ case 'S': opt_S = 1;
+ break;
+ case 't': opt_t++;
+ break;
+ case 'T': opt_T++;
+ break;
+ case 'u': opt_u = optarg;
+ break;
+ case 'V': printf("ltrace version " PACKAGE_VERSION ".\n"
+"Copyright (C) 1997-2006 Juan Cespedes <cespedes@debian.org>.\n"
+"This is free software; see the GNU General Public Licence\n"
+"version 2 or later for copying conditions. There is NO warranty.\n");
+ exit(0);
+ case 'X': PLTs_initialized_by_here = optarg;
+ /* Fall Thru */
+
+ case 'x':
+ {
+ struct opt_e_t * p = opt_x;
+
+ /* First, check for duplicate. */
+ while (p && strcmp(p->name, optarg)) {
+ p = p->next;
}
+ if (p) { break; }
+
+ /* If not duplicate, add to list. */
+ p = malloc(sizeof(struct opt_e_t));
+ if (!p) {
+ perror("ltrace: malloc");
+ exit(1);
+ }
+ p->name = optarg;
+ p->next = opt_x;
+ opt_x = p;
+ break;
}
- break;
- }
- case 'f':
- opt_f = 1;
- break;
- case 'h':
- usage();
- exit(0);
- case 'i':
- opt_i++;
- break;
- case 'l':
- if (library_num == MAX_LIBRARY) {
- fprintf(stderr,
- "Too many libraries. Maximum is %i.\n",
- MAX_LIBRARY);
- exit(1);
- }
- library[library_num++] = optarg;
- break;
- case 'L':
- opt_L = 0;
- break;
- case 'n':
- opt_n = atoi(optarg);
- break;
- case 'o':
- output = fopen(optarg, "w");
- if (!output) {
- fprintf(stderr,
- "Can't open %s for output: %s\n",
- optarg, strerror(errno));
- exit(1);
- }
- setvbuf(output, (char *)NULL, _IOLBF, 0);
- fcntl(fileno(output), F_SETFD, FD_CLOEXEC);
- break;
- case 'p':
- {
- struct opt_p_t *tmp =
- malloc(sizeof(struct opt_p_t));
- if (!tmp) {
- perror("ltrace: malloc");
- exit(1);
- }
- tmp->pid = atoi(optarg);
- tmp->next = opt_p;
- opt_p = tmp;
- break;
- }
- case 'r':
- opt_r++;
- break;
- case 's':
- opt_s = atoi(optarg);
- break;
- case 'S':
- opt_S = 1;
- break;
- case 't':
- opt_t++;
- break;
- case 'T':
- opt_T++;
- break;
- case 'u':
- opt_u = optarg;
- break;
- case 'V':
- printf("ltrace version " PACKAGE_VERSION ".\n"
- "Copyright (C) 1997-2006 Juan Cespedes <cespedes@debian.org>.\n"
- "This is free software; see the GNU General Public Licence\n"
- "version 2 or later for copying conditions. There is NO warranty.\n");
- exit(0);
- default:
+
+ default:
#if HAVE_GETOPT_LONG
- fprintf(stderr,
- "Try `%s --help' for more information\n",
- progname);
+ fprintf(stderr, "Try `%s --help' for more information\n", progname);
#else
- fprintf(stderr, "Try `%s -h' for more information\n",
- progname);
+ fprintf(stderr, "Try `%s -h' for more information\n", progname);
#endif
- exit(1);
+ exit(1);
}
}
- argc -= optind;
- argv += optind;
+ argc -= optind; argv += optind;
#endif
- if (!opt_p && argc < 1) {
+ if (!opt_p && argc<1) {
fprintf(stderr, "%s: too few arguments\n", progname);
usage();
exit(1);
}
if (opt_r && opt_t) {
- fprintf(stderr, "%s: Incompatible options -r and -t\n",
- progname);
+ fprintf(stderr, "%s: Incompatible options -r and -t\n", progname);
exit(1);
}
- if (argc > 0) {
+ if (argc>0) {
command = search_for_command(argv[0]);
}
return &argv[0];
diff --git a/options.h b/options.h
index 0fbb427..2b63bbc 100644
--- a/options.h
+++ b/options.h
@@ -36,4 +36,6 @@ extern struct opt_p_t * opt_p; /* attach to process with a given pid */
extern struct opt_e_t * opt_e; /* list of function names to display */
extern int opt_e_enable; /* 0 if '!' is used, 1 otherwise */
+extern struct opt_e_t * opt_x; /* list of functions to break at */
+
extern char ** process_options(int argc, char **argv);
diff --git a/output.c b/output.c
index b7759a6..109a201 100644
--- a/output.c
+++ b/output.c
@@ -22,25 +22,24 @@
/* TODO FIXME XXX: include in ltrace.h: */
extern struct timeval current_time_spent;
-struct dict *dict_opt_c = NULL;
+struct dict * dict_opt_c = NULL;
static pid_t current_pid = 0;
static int current_depth = 0;
static int current_column = 0;
-static void output_indent(struct process *proc)
-{
- current_column +=
- fprintf(output, "%*s", opt_n * proc->callstack_depth, "");
+static void
+output_indent(struct process * proc) {
+ current_column += fprintf(output, "%*s", opt_n * proc->callstack_depth, "");
}
-static void begin_of_line(enum tof type, struct process *proc)
-{
+static void
+begin_of_line(enum tof type, struct process * proc) {
current_column = 0;
if (!proc) {
return;
}
- if ((output != stderr) && (opt_p || opt_f)) {
+ if ((output!=stderr) && (opt_p || opt_f)) {
current_column += fprintf(output, "%u ", proc->pid);
} else if (list_of_processes->next) {
current_column += fprintf(output, "[pid %u] ", proc->pid);
@@ -48,14 +47,14 @@ static void begin_of_line(enum tof type, struct process *proc)
if (opt_r) {
struct timeval tv;
struct timezone tz;
- static struct timeval old_tv = { 0, 0 };
+ static struct timeval old_tv={0,0};
struct timeval diff;
gettimeofday(&tv, &tz);
- if (old_tv.tv_sec == 0 && old_tv.tv_usec == 0) {
- old_tv.tv_sec = tv.tv_sec;
- old_tv.tv_usec = tv.tv_usec;
+ if (old_tv.tv_sec==0 && old_tv.tv_usec==0) {
+ old_tv.tv_sec=tv.tv_sec;
+ old_tv.tv_usec=tv.tv_usec;
}
diff.tv_sec = tv.tv_sec - old_tv.tv_sec;
if (tv.tv_usec >= old_tv.tv_usec) {
@@ -67,50 +66,47 @@ static void begin_of_line(enum tof type, struct process *proc)
old_tv.tv_sec = tv.tv_sec;
old_tv.tv_usec = tv.tv_usec;
current_column += fprintf(output, "%3lu.%06d ",
- diff.tv_sec, (int)diff.tv_usec);
+ diff.tv_sec, (int)diff.tv_usec);
}
if (opt_t) {
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
- if (opt_t > 2) {
+ if (opt_t>2) {
current_column += fprintf(output, "%lu.%06d ",
- tv.tv_sec, (int)tv.tv_usec);
- } else if (opt_t > 1) {
- struct tm *tmp = localtime(&tv.tv_sec);
- current_column +=
- fprintf(output, "%02d:%02d:%02d.%06d ",
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
- (int)tv.tv_usec);
+ tv.tv_sec, (int)tv.tv_usec);
+ } else if (opt_t>1) {
+ struct tm * tmp = localtime(&tv.tv_sec);
+ current_column += fprintf(output, "%02d:%02d:%02d.%06d ",
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec, (int)tv.tv_usec);
} else {
- struct tm *tmp = localtime(&tv.tv_sec);
+ struct tm * tmp = localtime(&tv.tv_sec);
current_column += fprintf(output, "%02d:%02d:%02d ",
- tmp->tm_hour, tmp->tm_min,
- tmp->tm_sec);
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
}
}
if (opt_i) {
- if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) {
+ if (type==LT_TOF_FUNCTION || type==LT_TOF_FUNCTIONR) {
current_column += fprintf(output, "[%p] ",
- proc->return_addr);
+ proc->return_addr);
} else {
current_column += fprintf(output, "[%p] ",
- proc->instruction_pointer);
+ proc->instruction_pointer);
}
}
- if (opt_n > 0 && type != LT_TOF_NONE) {
+ if (opt_n > 0 && type!=LT_TOF_NONE) {
output_indent(proc);
}
}
-static struct function *name2func(char *name)
-{
- struct function *tmp;
- const char *str1, *str2;
+static struct function *
+name2func(char * name) {
+ struct function * tmp;
+ const char * str1, * str2;
tmp = list_of_functions;
- while (tmp) {
+ while(tmp) {
#ifdef USE_DEMANGLE
str1 = opt_C ? my_demangle(tmp->name) : tmp->name;
str2 = opt_C ? my_demangle(name) : name;
@@ -127,8 +123,8 @@ static struct function *name2func(char *name)
return NULL;
}
-void output_line(struct process *proc, char *fmt, ...)
-{
+void
+output_line(struct process * proc, char *fmt, ...) {
va_list args;
if (opt_c) {
@@ -137,7 +133,7 @@ void output_line(struct process *proc, char *fmt, ...)
if (current_pid) {
fprintf(output, " <unfinished ...>\n");
}
- current_pid = 0;
+ current_pid=0;
if (!fmt) {
return;
}
@@ -147,36 +143,34 @@ void output_line(struct process *proc, char *fmt, ...)
vfprintf(output, fmt, args);
fprintf(output, "\n");
va_end(args);
- current_column = 0;
+ current_column=0;
}
-static void tabto(int col)
-{
+static void
+tabto(int col) {
if (current_column < col) {
- fprintf(output, "%*s", col - current_column, "");
+ fprintf(output, "%*s", col-current_column, "");
}
}
-void output_left(enum tof type, struct process *proc, char *function_name)
-{
- struct function *func;
+void
+output_left(enum tof type, struct process * proc, char * function_name) {
+ struct function * func;
if (opt_c) {
return;
}
if (current_pid) {
fprintf(output, " <unfinished ...>\n");
- current_pid = 0;
- current_column = 0;
+ current_pid=0;
+ current_column=0;
}
current_pid = proc->pid;
current_depth = proc->callstack_depth;
proc->type_being_displayed = type;
begin_of_line(type, proc);
#ifdef USE_DEMANGLE
- current_column +=
- fprintf(output, "%s(",
- opt_C ? my_demangle(function_name) : function_name);
+ current_column += fprintf(output, "%s(", opt_C ? my_demangle(function_name): function_name);
#else
current_column += fprintf(output, "%s(", function_name);
#endif
@@ -184,22 +178,20 @@ void output_left(enum tof type, struct process *proc, char *function_name)
func = name2func(function_name);
if (!func) {
int i;
- for (i = 0; i < 4; i++) {
- current_column += display_arg(type, proc, i, 0);
+ for(i=0; i<4; i++) {
+ current_column += display_arg(type, proc, i, ARGTYPE_UNKNOWN);
current_column += fprintf(output, ", ");
}
- current_column += display_arg(type, proc, 4, 0);
+ current_column += display_arg(type, proc, 4, ARGTYPE_UNKNOWN);
return;
} else {
int i;
- for (i = 0; i < func->num_params - func->params_right - 1; i++) {
- current_column +=
- display_arg(type, proc, i, &func->arg_types[i]);
+ for(i=0; i< func->num_params - func->params_right - 1; i++) {
+ current_column += display_arg(type, proc, i, func->arg_types[i]);
current_column += fprintf(output, ", ");
}
- if (func->num_params > func->params_right) {
- current_column +=
- display_arg(type, proc, i, &func->arg_types[i]);
+ if (func->num_params>func->params_right) {
+ current_column += display_arg(type, proc, i, func->arg_types[i]);
if (func->params_right) {
current_column += fprintf(output, ", ");
}
@@ -210,16 +202,14 @@ void output_left(enum tof type, struct process *proc, char *function_name)
}
}
-void output_right(enum tof type, struct process *proc, char *function_name)
-{
- struct function *func = name2func(function_name);
+void
+output_right(enum tof type, struct process * proc, char * function_name) {
+ struct function * func = name2func(function_name);
if (opt_c) {
- struct opt_c_struct *st;
+ struct opt_c_struct * st;
if (!dict_opt_c) {
- dict_opt_c =
- dict_init(dict_key2hash_string,
- dict_key_cmp_string);
+ dict_opt_c = dict_init(dict_key2hash_string, dict_key_cmp_string);
}
st = dict_find_entry(dict_opt_c, function_name);
if (!st) {
@@ -243,59 +233,52 @@ void output_right(enum tof type, struct process *proc, char *function_name)
st->count++;
st->tv.tv_sec += current_time_spent.tv_sec;
-// fprintf(output, "%s <%lu.%06d>\n", function_name,
-// current_time_spent.tv_sec, (int)current_time_spent.tv_usec);
+// fprintf(output, "%s <%lu.%06d>\n", function_name,
+// current_time_spent.tv_sec, (int)current_time_spent.tv_usec);
return;
}
- if (current_pid && (current_pid != proc->pid ||
- current_depth != proc->callstack_depth)) {
+ if (current_pid && (current_pid!=proc->pid ||
+ current_depth != proc->callstack_depth)) {
fprintf(output, " <unfinished ...>\n");
current_pid = 0;
}
if (current_pid != proc->pid) {
begin_of_line(type, proc);
#ifdef USE_DEMANGLE
- current_column +=
- fprintf(output, "<... %s resumed> ",
- opt_C ? my_demangle(function_name) : function_name);
+ current_column += fprintf(output, "<... %s resumed> ", opt_C ? my_demangle(function_name) : function_name);
#else
- current_column +=
- fprintf(output, "<... %s resumed> ", function_name);
+ current_column += fprintf(output, "<... %s resumed> ", function_name);
#endif
}
if (!func) {
current_column += fprintf(output, ") ");
- tabto(opt_a - 1);
+ tabto(opt_a-1);
fprintf(output, "= ");
- display_arg(type, proc, -1, 0);
+ display_arg(type, proc, -1, ARGTYPE_UNKNOWN);
} else {
int i;
- for (i = func->num_params - func->params_right;
- i < func->num_params - 1; i++) {
- current_column +=
- display_arg(type, proc, i, &func->arg_types[i]);
+ for(i=func->num_params-func->params_right; i<func->num_params-1; i++) {
+ current_column += display_arg(type, proc, i, func->arg_types[i]);
current_column += fprintf(output, ", ");
}
if (func->params_right) {
- current_column +=
- display_arg(type, proc, i, &func->arg_types[i]);
+ current_column += display_arg(type, proc, i, func->arg_types[i]);
}
current_column += fprintf(output, ") ");
- tabto(opt_a - 1);
- fprintf(output, "= ");
- if (func->return_type.at == ARGTYPE_VOID) {
+ tabto(opt_a-1);
+ fprintf(output, "= ");
+ if (func->return_type == ARGTYPE_VOID) {
fprintf(output, "<void>");
} else {
- display_arg(type, proc, -1, &func->return_type);
+ display_arg(type, proc, -1, func->return_type);
}
}
if (opt_T) {
fprintf(output, " <%lu.%06d>",
- current_time_spent.tv_sec,
- (int)current_time_spent.tv_usec);
+ current_time_spent.tv_sec, (int)current_time_spent.tv_usec);
}
fprintf(output, "\n");
- current_pid = 0;
- current_column = 0;
+ current_pid=0;
+ current_column=0;
}
diff --git a/proc.c b/proc.c
index 083f6a9..aae4478 100644
--- a/proc.c
+++ b/proc.c
@@ -12,37 +12,31 @@
#include "options.h"
#include "elf.h"
-struct process *open_program(char *filename)
-{
- struct process *proc;
- proc = malloc(sizeof(struct process));
+struct process *
+open_program(char * filename, pid_t pid) {
+ struct process * proc;
+ proc = calloc(sizeof(struct process), 1);
if (!proc) {
perror("malloc");
exit(1);
}
- memset(proc, 0, sizeof(struct process));
proc->filename = filename;
- proc->pid = 0;
- proc->breakpoints = NULL;
proc->breakpoints_enabled = -1;
- proc->callstack_depth = 0;
- proc->breakpoint_being_enabled = NULL;
+ if (pid) { proc->pid = pid; }
breakpoints_init(proc);
- proc->next = NULL;
proc->next = list_of_processes;
list_of_processes = proc;
return proc;
}
-void open_pid(pid_t pid, int verbose)
-{
- struct process *proc;
- char *filename;
+void
+open_pid(pid_t pid, int verbose) {
+ struct process * proc;
+ char * filename;
- if (trace_pid(pid) < 0) {
- fprintf(stderr, "Cannot attach to pid %u: %s\n", pid,
- strerror(errno));
+ if (trace_pid(pid)<0) {
+ fprintf(stderr, "Cannot attach to pid %u: %s\n", pid, strerror(errno));
return;
}
@@ -51,13 +45,12 @@ void open_pid(pid_t pid, int verbose)
#if 0
if (!filename) {
if (verbose) {
- fprintf(stderr, "Cannot trace pid %u: %s\n", pid,
- strerror(errno));
+ fprintf(stderr, "Cannot trace pid %u: %s\n", pid, strerror(errno));
}
return;
}
#endif
- proc = open_program(filename);
- proc->pid = pid;
+ proc = open_program(filename, pid);
+ proc->breakpoints_enabled = 1;
}
diff --git a/process_event.c b/process_event.c
index 1323d39..9263184 100644
--- a/process_event.c
+++ b/process_event.c
@@ -20,92 +20,101 @@
#include <sys/ptrace.h>
#endif
-static void process_signal(struct event *event);
-static void process_exit(struct event *event);
-static void process_exit_signal(struct event *event);
-static void process_syscall(struct event *event);
-static void process_sysret(struct event *event);
-static void process_breakpoint(struct event *event);
-static void remove_proc(struct process *proc);
-
-static void callstack_push_syscall(struct process *proc, int sysnum);
-static void callstack_push_symfunc(struct process *proc,
- struct library_symbol *sym);
-static void callstack_pop(struct process *proc);
-
-static char *shortsignal(int signum)
-{
- static char *signalent0[] = {
-#include "signalent.h"
+static void process_signal(struct event * event);
+static void process_exit(struct event * event);
+static void process_exit_signal(struct event * event);
+static void process_syscall(struct event * event);
+static void process_sysret(struct event * event);
+static void process_breakpoint(struct event * event);
+static void remove_proc(struct process * proc);
+
+static void callstack_push_syscall(struct process * proc, int sysnum);
+static void callstack_push_symfunc(struct process * proc, struct library_symbol * sym);
+static void callstack_pop(struct process * proc);
+
+static char *
+shortsignal(struct process *proc, int signum) {
+ static char * signalent0[] = {
+ #include "signalent.h"
};
- int nsignals0 = sizeof signalent0 / sizeof signalent0[0];
+ static char * signalent1[] = {
+ #include "signalent1.h"
+ };
+ static char **signalents[] = { signalent0, signalent1 };
+ int nsignals[] = { sizeof signalent0 / sizeof signalent0[0],
+ sizeof signalent1 / sizeof signalent1[0] };
- if (signum < 0 || signum >= nsignals0) {
+ if (proc->personality > sizeof signalents / sizeof signalents[0])
+ abort ();
+ if (signum < 0 || signum >= nsignals[proc->personality]) {
return "UNKNOWN_SIGNAL";
} else {
- return signalent0[signum];
+ return signalents[proc->personality][signum];
}
}
-static char *sysname(int sysnum)
-{
+static char *
+sysname(struct process *proc, int sysnum) {
static char result[128];
- static char *syscalent0[] = {
-#include "syscallent.h"
+ static char * syscalent0[] = {
+ #include "syscallent.h"
+ };
+ static char * syscalent1[] = {
+ #include "syscallent1.h"
};
- int nsyscals0 = sizeof syscalent0 / sizeof syscalent0[0];
+ static char **syscalents[] = { syscalent0, syscalent1 };
+ int nsyscals[] = { sizeof syscalent0 / sizeof syscalent0[0],
+ sizeof syscalent1 / sizeof syscalent1[0] };
- if (sysnum < 0 || sysnum >= nsyscals0) {
+ if (proc->personality > sizeof syscalents / sizeof syscalents[0])
+ abort ();
+ if (sysnum < 0 || sysnum >= nsyscals[proc->personality]) {
sprintf(result, "SYS_%d", sysnum);
return result;
} else {
- sprintf(result, "SYS_%s", syscalent0[sysnum]);
+ sprintf(result, "SYS_%s", syscalents[proc->personality][sysnum]);
return result;
}
}
-void process_event(struct event *event)
-{
+void
+process_event(struct event * event) {
switch (event->thing) {
- case LT_EV_NONE:
- debug(1, "event: none");
- return;
- case LT_EV_SIGNAL:
- debug(1, "event: signal (%s [%d])",
- shortsignal(event->e_un.signum), event->e_un.signum);
- process_signal(event);
- return;
- case LT_EV_EXIT:
- debug(1, "event: exit (%d)", event->e_un.ret_val);
- process_exit(event);
- return;
- case LT_EV_EXIT_SIGNAL:
- debug(1, "event: exit signal (%s [%d])",
- shortsignal(event->e_un.signum), event->e_un.signum);
- process_exit_signal(event);
- return;
- case LT_EV_SYSCALL:
- debug(1, "event: syscall (%s [%d])",
- sysname(event->e_un.sysnum), event->e_un.sysnum);
- process_syscall(event);
- return;
- case LT_EV_SYSRET:
- debug(1, "event: sysret (%s [%d])", sysname(event->e_un.sysnum),
- event->e_un.sysnum);
- process_sysret(event);
- return;
- case LT_EV_BREAKPOINT:
- debug(1, "event: breakpoint");
- process_breakpoint(event);
- return;
- default:
- fprintf(stderr, "Error! unknown event?\n");
- exit(1);
+ case LT_EV_NONE:
+ debug(1, "event: none");
+ return;
+ case LT_EV_SIGNAL:
+ debug(1, "event: signal (%s [%d])", shortsignal(event->proc, event->e_un.signum), event->e_un.signum);
+ process_signal(event);
+ return;
+ case LT_EV_EXIT:
+ debug(1, "event: exit (%d)", event->e_un.ret_val);
+ process_exit(event);
+ return;
+ case LT_EV_EXIT_SIGNAL:
+ debug(1, "event: exit signal (%s [%d])", shortsignal(event->proc, event->e_un.signum), event->e_un.signum);
+ process_exit_signal(event);
+ return;
+ case LT_EV_SYSCALL:
+ debug(1, "event: syscall (%s [%d])", sysname (event->proc, event->e_un.sysnum), event->e_un.sysnum);
+ process_syscall(event);
+ return;
+ case LT_EV_SYSRET:
+ debug(1, "event: sysret (%s [%d])", sysname (event->proc, event->e_un.sysnum), event->e_un.sysnum);
+ process_sysret(event);
+ return;
+ case LT_EV_BREAKPOINT:
+ debug(1, "event: breakpoint");
+ process_breakpoint(event);
+ return;
+ default:
+ fprintf(stderr, "Error! unknown event?\n");
+ exit(1);
}
}
-static void process_signal(struct event *event)
-{
+static void
+process_signal(struct event * event) {
if (exiting && event->e_un.signum == SIGSTOP) {
pid_t pid = event->proc->pid;
disable_all_breakpoints(event->proc);
@@ -115,27 +124,26 @@ static void process_signal(struct event *event)
return;
}
output_line(event->proc, "--- %s (%s) ---",
- shortsignal(event->e_un.signum),
- strsignal(event->e_un.signum));
+ shortsignal(event->proc, event->e_un.signum), strsignal(event->e_un.signum));
continue_after_signal(event->proc->pid, event->e_un.signum);
}
-static void process_exit(struct event *event)
-{
+static void
+process_exit(struct event * event) {
output_line(event->proc, "+++ exited (status %d) +++",
- event->e_un.ret_val);
+ event->e_un.ret_val);
remove_proc(event->proc);
}
-static void process_exit_signal(struct event *event)
-{
+static void
+process_exit_signal(struct event * event) {
output_line(event->proc, "+++ killed by %s +++",
- shortsignal(event->e_un.signum));
+ shortsignal(event->proc, event->e_un.signum));
remove_proc(event->proc);
}
-static void remove_proc(struct process *proc)
-{
+static void
+remove_proc(struct process * proc) {
struct process *tmp, *tmp2;
debug(1, "Removing pid %u\n", proc->pid);
@@ -147,8 +155,8 @@ static void remove_proc(struct process *proc)
return;
}
tmp = list_of_processes;
- while (tmp->next) {
- if (tmp->next == proc) {
+ while(tmp->next) {
+ if (tmp->next==proc) {
tmp2 = tmp->next;
tmp->next = tmp->next->next;
free(tmp2);
@@ -158,15 +166,15 @@ static void remove_proc(struct process *proc)
}
}
-static void process_syscall(struct event *event)
-{
+static void
+process_syscall(struct event * event) {
if (opt_S) {
- output_left(LT_TOF_SYSCALL, event->proc,
- sysname(event->e_un.sysnum));
+ output_left(LT_TOF_SYSCALL, event->proc, sysname(event->proc, event->e_un.sysnum));
}
- if (fork_p(event->e_un.sysnum)) {
+ if (fork_p(event->proc, event->e_un.sysnum)
+ || exec_p(event->proc, event->e_un.sysnum)) {
disable_all_breakpoints(event->proc);
- } else if (!event->proc->breakpoints_enabled) {
+ } else if (event->proc->breakpoints_enabled == 0) {
enable_all_breakpoints(event->proc);
}
callstack_push_syscall(event->proc, event->e_un.sysnum);
@@ -175,14 +183,14 @@ static void process_syscall(struct event *event)
struct timeval current_time_spent;
-static void calc_time_spent(struct process *proc)
-{
+static void
+calc_time_spent(struct process * proc) {
struct timeval tv;
struct timezone tz;
struct timeval diff;
- struct callstack_element *elem;
+ struct callstack_element * elem;
- elem = &proc->callstack[proc->callstack_depth - 1];
+ elem = & proc->callstack[proc->callstack_depth-1];
gettimeofday(&tv, &tz);
@@ -196,16 +204,15 @@ static void calc_time_spent(struct process *proc)
current_time_spent = diff;
}
-static void process_sysret(struct event *event)
-{
+static void
+process_sysret(struct event * event) {
if (opt_T || opt_c) {
calc_time_spent(event->proc);
}
- if (fork_p(event->e_un.sysnum)) {
+ if (fork_p(event->proc, event->e_un.sysnum)) {
if (opt_f) {
- pid_t child =
- gimme_arg(LT_TOF_SYSCALLR, event->proc, -1);
- if (child > 0) {
+ pid_t child = gimme_arg(LT_TOF_SYSCALLR,event->proc,-1);
+ if (child>0) {
open_pid(child, 0);
}
}
@@ -213,57 +220,72 @@ static void process_sysret(struct event *event)
}
callstack_pop(event->proc);
if (opt_S) {
- output_right(LT_TOF_SYSCALLR, event->proc,
- sysname(event->e_un.sysnum));
+ output_right(LT_TOF_SYSCALLR, event->proc, sysname(event->proc, event->e_un.sysnum));
}
- if (exec_p(event->e_un.sysnum)) {
- if (gimme_arg(LT_TOF_SYSCALLR, event->proc, -1) == 0) {
+ if (exec_p(event->proc, event->e_un.sysnum)) {
+ if (gimme_arg(LT_TOF_SYSCALLR,event->proc,-1)==0) {
+ pid_t saved_pid;
+ event->proc->mask_32bit = 0;
+ event->proc->personality = 0;
+ /* FIXME: Leak, should have arch_dep_free.
+ But we are leaking here much more than that. */
+ event->proc->arch_ptr = NULL;
event->proc->filename = pid2name(event->proc->pid);
+ saved_pid = event->proc->pid;
+ event->proc->pid = 0;
breakpoints_init(event->proc);
- }
+ event->proc->pid = saved_pid;
+ } else
+ enable_all_breakpoints(event->proc);
}
continue_process(event->proc->pid);
}
-static void process_breakpoint(struct event *event)
-{
- struct library_symbol *tmp;
- int i, j;
+static void
+process_breakpoint(struct event * event) {
+ int i,j;
+ struct breakpoint *sbp;
debug(2, "event: breakpoint (%p)", event->e_un.brk_addr);
if (event->proc->breakpoint_being_enabled) {
/* Reinsert breakpoint */
- continue_enabling_breakpoint(event->proc->pid,
- event->proc->
- breakpoint_being_enabled);
+ continue_enabling_breakpoint(event->proc->pid, event->proc->breakpoint_being_enabled);
event->proc->breakpoint_being_enabled = NULL;
return;
}
- for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
- if (event->e_un.brk_addr ==
- event->proc->callstack[i].return_addr) {
+ for(i=event->proc->callstack_depth-1; i>=0; i--) {
+ if (event->e_un.brk_addr == event->proc->callstack[i].return_addr) {
#ifdef __powerpc__
- unsigned long a;
- unsigned long addr =
- event->proc->callstack[i].c_un.libfunc->enter_addr;
- struct breakpoint *sbp =
- address2bpstruct(event->proc, addr);
- unsigned char break_insn[] = BREAKPOINT_VALUE;
-
/*
* PPC HACK! (XXX FIXME TODO)
* The PLT gets modified during the first call,
* so be sure to re-enable the breakpoint.
- */
- a = ptrace(PTRACE_PEEKTEXT, event->proc->pid, addr);
-
- if (memcmp(&a, break_insn, 4)) {
- sbp->enabled--;
- insert_breakpoint(event->proc, addr);
+ */
+ unsigned long a;
+ struct library_symbol *libsym =
+ event->proc->callstack[i].c_un.libfunc;
+ void *addr = plt2addr(event->proc, libsym->enter_addr);
+
+ if (event->proc->e_machine == EM_PPC) {
+ unsigned char break_insn[] = BREAKPOINT_VALUE;
+
+ sbp = address2bpstruct(event->proc, addr);
+ assert(sbp);
+ a = ptrace(PTRACE_PEEKTEXT, event->proc->pid, addr);
+
+ if (memcmp(&a, break_insn, 4)) {
+ sbp->enabled--;
+ insert_breakpoint(event->proc, addr, libsym);
+ }
+ } else {
+ sbp = libsym->brkpnt;
+ assert(sbp);
+ if (addr != sbp->addr)
+ insert_breakpoint(event->proc, addr, libsym);
}
#endif
- 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 (opt_T || opt_c) {
@@ -272,50 +294,44 @@ static void process_breakpoint(struct event *event)
callstack_pop(event->proc);
event->proc->return_addr = event->e_un.brk_addr;
output_right(LT_TOF_FUNCTIONR, event->proc,
- event->proc->callstack[i].c_un.libfunc->
- name);
+ event->proc->callstack[i].c_un.libfunc->name);
continue_after_breakpoint(event->proc,
- address2bpstruct(event->proc,
- event->e_un.
- brk_addr));
+ address2bpstruct(event->proc, event->e_un.brk_addr));
return;
}
}
- tmp = event->proc->list_of_symbols;
- while (tmp) {
- if (event->e_un.brk_addr == tmp->enter_addr) {
- event->proc->stack_pointer =
- get_stack_pointer(event->proc);
- event->proc->return_addr =
- get_return_addr(event->proc,
- event->proc->stack_pointer);
- output_left(LT_TOF_FUNCTION, event->proc, tmp->name);
- callstack_push_symfunc(event->proc, tmp);
- continue_after_breakpoint(event->proc,
- address2bpstruct(event->proc,
- tmp->
- enter_addr));
- return;
- }
- tmp = tmp->next;
- }
- output_line(event->proc, "breakpointed at %p (?)",
- (void *)event->e_un.brk_addr);
+ if ((sbp = address2bpstruct(event->proc, event->e_un.brk_addr)))
+ {
+ event->proc->stack_pointer = get_stack_pointer(event->proc);
+ event->proc->return_addr = get_return_addr(event->proc, event->proc->stack_pointer);
+ output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name);
+ callstack_push_symfunc(event->proc, sbp->libsym);
+ if (PLTs_initialized_by_here
+ && event->proc->need_to_reinitialize_breakpoints
+ && (strcmp(sbp->libsym->name, PLTs_initialized_by_here) == 0))
+ reinitialize_breakpoints(event->proc);
+
+ continue_after_breakpoint(event->proc, sbp);
+ return;
+ }
+
+ output_line(event->proc, "unexpected breakpoint at %p",
+ (void *)event->e_un.brk_addr);
continue_process(event->proc->pid);
}
-static void callstack_push_syscall(struct process *proc, int sysnum)
-{
- struct callstack_element *elem;
+static void
+callstack_push_syscall(struct process * proc, int sysnum) {
+ struct callstack_element * elem;
/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
- if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
+ if (proc->callstack_depth == MAX_CALLDEPTH-1) {
fprintf(stderr, "Error: call nesting too deep!\n");
return;
}
- elem = &proc->callstack[proc->callstack_depth];
+ elem = & proc->callstack[proc->callstack_depth];
elem->is_syscall = 1;
elem->c_un.syscall = sysnum;
elem->return_addr = NULL;
@@ -328,22 +344,21 @@ static void callstack_push_syscall(struct process *proc, int sysnum)
}
static void
-callstack_push_symfunc(struct process *proc, struct library_symbol *sym)
-{
- struct callstack_element *elem;
+callstack_push_symfunc(struct process * proc, struct library_symbol * sym) {
+ struct callstack_element * elem;
/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
- if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
+ if (proc->callstack_depth == MAX_CALLDEPTH-1) {
fprintf(stderr, "Error: call nesting too deep!\n");
return;
}
- elem = &proc->callstack[proc->callstack_depth];
+ elem = & proc->callstack[proc->callstack_depth];
elem->is_syscall = 0;
elem->c_un.libfunc = sym;
elem->return_addr = proc->return_addr;
- insert_breakpoint(proc, elem->return_addr);
+ insert_breakpoint(proc, elem->return_addr, 0);
proc->callstack_depth++;
if (opt_T || opt_c) {
@@ -352,12 +367,12 @@ callstack_push_symfunc(struct process *proc, struct library_symbol *sym)
}
}
-static void callstack_pop(struct process *proc)
-{
- struct callstack_element *elem;
+static void
+callstack_pop(struct process * proc) {
+ struct callstack_element * elem;
assert(proc->callstack_depth > 0);
- elem = &proc->callstack[proc->callstack_depth - 1];
+ elem = & proc->callstack[proc->callstack_depth-1];
if (!elem->is_syscall) {
delete_breakpoint(proc, elem->return_addr);
}
diff --git a/read_config_file.c b/read_config_file.c
index e5c3f6b..bdceef5 100644
--- a/read_config_file.c
+++ b/read_config_file.c
@@ -24,56 +24,50 @@
* "addr" ARGTYPE_ADDR
*/
-struct function *list_of_functions = NULL;
+struct function * list_of_functions = NULL;
static struct list_of_pt_t {
- char *name;
+ char * name;
enum arg_type pt;
} list_of_pt[] = {
- {
- "void", ARGTYPE_VOID}, {
- "int", ARGTYPE_INT}, {
- "uint", ARGTYPE_UINT}, {
- "long", ARGTYPE_LONG}, {
- "ulong", ARGTYPE_ULONG}, {
- "octal", ARGTYPE_OCTAL}, {
- "char", ARGTYPE_CHAR}, {
- "addr", ARGTYPE_ADDR}, {
- "file", ARGTYPE_FILE}, {
- "format", ARGTYPE_FORMAT}, {
- "string", ARGTYPE_STRING}, {
- NULL, ARGTYPE_UNKNOWN} /* Must finish with NULL */
+ { "void", ARGTYPE_VOID },
+ { "int", ARGTYPE_INT },
+ { "uint", ARGTYPE_UINT },
+ { "long", ARGTYPE_LONG },
+ { "ulong", ARGTYPE_ULONG },
+ { "octal", ARGTYPE_OCTAL },
+ { "char", ARGTYPE_CHAR },
+ { "addr", ARGTYPE_ADDR },
+ { "file", ARGTYPE_FILE },
+ { "format", ARGTYPE_FORMAT },
+ { "string", ARGTYPE_STRING },
+ { "string0",ARGTYPE_STRING0 },
+ { "string1",ARGTYPE_STRING1 },
+ { "string2",ARGTYPE_STRING2 },
+ { "string3",ARGTYPE_STRING3 },
+ { "string4",ARGTYPE_STRING4 },
+ { "string5",ARGTYPE_STRING5 },
+ { NULL, ARGTYPE_UNKNOWN } /* Must finish with NULL */
};
-static struct complete_arg_type str2type(char **str)
-{
- struct list_of_pt_t *tmp = &list_of_pt[0];
- struct complete_arg_type pt = { 0, 0 };
-
- if (!strncmp(*str, "string", 6)
- && isdigit((unsigned char)(*str)[6])) {
- pt.at = ARGTYPE_STRINGN;
- pt.argno = atoi(*str + 6);
- *str += strspn(*str, "string0123456789");
- return pt;
- }
+static enum arg_type
+str2type(char ** str) {
+ struct list_of_pt_t * tmp = &list_of_pt[0];
- while (tmp->name) {
+ while(tmp->name) {
if (!strncmp(*str, tmp->name, strlen(tmp->name))
- && index(" ,)#", *(*str + strlen(tmp->name)))) {
- *str += strlen(tmp->name);
- pt.at = tmp->pt;
- return pt;
+ && index(" ,)#", *(*str+strlen(tmp->name)))) {
+ *str += strlen(tmp->name);
+ return tmp->pt;
}
tmp++;
}
- pt.at = ARGTYPE_UNKNOWN;
- return pt;
+ return ARGTYPE_UNKNOWN;
}
-static void eat_spaces(char **str)
-{
- while (**str == ' ') {
+static void
+eat_spaces(char ** str) {
+ while(**str==' ') {
(*str)++;
}
}
@@ -82,28 +76,22 @@ static void eat_spaces(char **str)
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;
+static char *
+start_of_arg_sig(char * str) {
+ char * pos;
int stacked = 0;
- if (!strlen(str))
- return NULL;
+ 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;
+ if (pos < str) return NULL;
+ while ((pos > str) && (*pos != ')') && (*pos != '(')) pos--;
+
+ if (*pos == ')') stacked++;
+ else if (*pos == '(') stacked--;
+ else return NULL;
} while (stacked > 0);
@@ -111,21 +99,21 @@ static char *start_of_arg_sig(char *str)
}
static int line_no;
-static char *filename;
+static char * filename;
-static struct function *process_line(char *buf)
-{
+static struct function *
+process_line (char * buf) {
struct function fun;
- struct function *fun_p;
- char *str = buf;
- char *tmp;
+ struct function * fun_p;
+ char * str = buf;
+ char * tmp;
int i;
line_no++;
debug(3, "Reading line %d of `%s'", line_no, filename);
eat_spaces(&str);
fun.return_type = str2type(&str);
- if (fun.return_type.at == ARGTYPE_UNKNOWN) {
+ if (fun.return_type==ARGTYPE_UNKNOWN) {
debug(3, " Skipping line %d", line_no);
return NULL;
}
@@ -133,41 +121,38 @@ static struct function *process_line(char *buf)
eat_spaces(&str);
tmp = start_of_arg_sig(str);
if (!tmp) {
- output_line(0, "Syntax error in `%s', line %d", filename,
- line_no);
+ output_line(0, "Syntax error in `%s', line %d", filename, line_no);
return NULL;
}
*tmp = '\0';
fun.name = strdup(str);
- str = tmp + 1;
+ str = tmp+1;
debug(3, " name = %s", fun.name);
fun.params_right = 0;
- for (i = 0; i < MAX_ARGS; i++) {
+ for(i=0; i<MAX_ARGS; i++) {
eat_spaces(&str);
if (*str == ')') {
break;
}
- if (str[0] == '+') {
+ if (str[0]=='+') {
fun.params_right++;
str++;
} else if (fun.params_right) {
fun.params_right++;
}
fun.arg_types[i] = str2type(&str);
- if (fun.return_type.at == ARGTYPE_UNKNOWN) {
- output_line(0, "Syntax error in `%s', line %d",
- filename, line_no);
+ if (fun.return_type==ARGTYPE_UNKNOWN) {
+ output_line(0, "Syntax error in `%s', line %d", filename, line_no);
return NULL;
}
eat_spaces(&str);
- if (*str == ',') {
+ if (*str==',') {
str++;
continue;
- } else if (*str == ')') {
+ } else if (*str==')') {
continue;
} else {
- output_line(0, "Syntax error in `%s', line %d",
- filename, line_no);
+ output_line(0, "Syntax error in `%s', line %d", filename, line_no);
return NULL;
}
}
@@ -177,9 +162,9 @@ static struct function *process_line(char *buf)
return fun_p;
}
-void read_config_file(char *file)
-{
- FILE *stream;
+void
+read_config_file(char * file) {
+ FILE * stream;
char buf[1024];
filename = file;
@@ -190,9 +175,9 @@ void read_config_file(char *file)
if (!stream) {
return;
}
- line_no = 0;
+ line_no=0;
while (fgets(buf, 1024, stream)) {
- struct function *tmp = process_line(buf);
+ struct function * tmp = process_line(buf);
if (tmp) {
debug(2, "New function: `%s'", tmp->name);
diff --git a/summary.c b/summary.c
index 7dc2c07..2cfe4d6 100644
--- a/summary.c
+++ b/summary.c
@@ -1,33 +1,24 @@
-#if HAVE_CONFIG_H
-#include "config.h"
-#endif
-
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include "ltrace.h"
-#include "options.h"
-
-#ifdef USE_DEMANGLE
-#include "demangle.h"
-#endif
static int num_entries = 0;
static struct entry_st {
char *name;
int count;
struct timeval tv;
-} *entries = NULL;
+} * entries = NULL;
static int tot_count = 0;
static unsigned long int tot_usecs = 0;
-static void fill_struct(void *key, void *value, void *data)
-{
- struct opt_c_struct *st = (struct opt_c_struct *)value;
+static void
+fill_struct(void * key, void * value, void * data) {
+ struct opt_c_struct * st = (struct opt_c_struct *)value;
- entries = realloc(entries, (num_entries + 1) * sizeof(struct entry_st));
+ entries = realloc(entries, (num_entries+1)*sizeof(struct entry_st));
if (!entries) {
perror("realloc()");
exit(1);
@@ -37,14 +28,14 @@ static void fill_struct(void *key, void *value, void *data)
entries[num_entries].tv = st->tv;
tot_count += st->count;
- tot_usecs += 1000000 * st->tv.tv_sec;
+ tot_usecs += 1000000*st->tv.tv_sec;
tot_usecs += st->tv.tv_usec;
num_entries++;
}
-static int compar(const void *a, const void *b)
-{
+static int
+compar(const void *a, const void *b) {
struct entry_st *en1, *en2;
en1 = (struct entry_st *)a;
@@ -57,8 +48,8 @@ static int compar(const void *a, const void *b)
}
}
-void show_summary(void)
-{
+void
+show_summary(void) {
int i;
num_entries = 0;
@@ -69,23 +60,20 @@ void show_summary(void)
qsort(entries, num_entries, sizeof(*entries), compar);
printf("%% time seconds usecs/call calls function\n");
- printf
- ("------ ----------- ----------- --------- --------------------\n");
- for (i = 0; i < num_entries; i++) {
+ printf( "------ ----------- ----------- --------- --------------------\n");
+ for(i=0; i<num_entries; i++) {
unsigned long long int c;
unsigned long long int p;
- c = 1000000 * (int)entries[i].tv.tv_sec +
- (int)entries[i].tv.tv_usec;
+ c = 1000000 * (int)entries[i].tv.tv_sec + (int)entries[i].tv.tv_usec;
p = 100000 * c / tot_usecs + 5;
printf("%3lu.%02lu %4d.%06d %11lu %9d %s\n",
- (unsigned long int)(p / 1000),
- (unsigned long int)((p / 10) % 100),
- (int)entries[i].tv.tv_sec, (int)entries[i].tv.tv_usec,
- (unsigned long int)(c / entries[i].count),
- entries[i].count, opt_C ? my_demangle(entries[i].name) : entries[i].name);
+ (unsigned long int)(p / 1000),
+ (unsigned long int)((p / 10) % 100),
+ (int)entries[i].tv.tv_sec, (int)entries[i].tv.tv_usec,
+ (unsigned long int)(c / entries[i].count),
+ entries[i].count, entries[i].name);
}
- printf
- ("------ ----------- ----------- --------- --------------------\n");
- printf("100.00 %4lu.%06lu %9d total\n", tot_usecs / 1000000,
- tot_usecs % 1000000, tot_count);
+ printf("------ ----------- ----------- --------- --------------------\n");
+ printf("100.00 %4lu.%06lu %9d total\n",
+ tot_usecs / 1000000, tot_usecs % 1000000, tot_count);
}
diff --git a/sysdeps/linux-gnu/Makefile b/sysdeps/linux-gnu/Makefile
index 7163709..6cbff83 100644
--- a/sysdeps/linux-gnu/Makefile
+++ b/sysdeps/linux-gnu/Makefile
@@ -1,20 +1,34 @@
-ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
+ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
+ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/ppc64/ppc/ -e s/s390x/s390/)
CPPFLAGS += -I$(TOPDIR)/sysdeps/linux-gnu/$(ARCH)
OBJ = trace.o proc.o breakpoint.o
-all: sysdep.h signalent.h syscallent.h ../sysdep.o
+all: sysdep.h signalent.h syscallent.h signalent1.h syscallent1.h ../sysdep.o
sysdep.h: $(ARCH)/arch.h
cat $(ARCH)/arch.h > sysdep.h
signalent.h:
cp $(ARCH)/signalent.h signalent.h
+signalent1.h:
+ if [ -f $(ARCH)/signalent1.h ]; then \
+ cp $(ARCH)/signalent1.h signalent1.h; \
+ else \
+ > signalent1.h; \
+ fi
syscallent.h:
cp $(ARCH)/syscallent.h syscallent.h
+syscallent1.h:
+ if [ -f $(ARCH)/syscallent1.h ]; then \
+ cp $(ARCH)/syscallent1.h syscallent1.h; \
+ else \
+ > syscallent1.h; \
+ fi
+
../sysdep.o: os.o $(ARCH)/arch.o
$(CC) -nostdlib -r -o ../sysdep.o os.o $(ARCH)/arch.o
@@ -26,6 +40,7 @@ $(ARCH)/arch.o: dummy
clean:
$(MAKE) -C $(ARCH) clean
- rm -f $(OBJ) sysdep.h signalent.h syscallent.h os.o sysdep.o ../sysdep.o
+ rm -f $(OBJ) sysdep.h signalent.h signalent1.h syscallent.h
+ rm -f syscallent1.h os.o sysdep.o ../sysdep.o
dummy:
diff --git a/sysdeps/linux-gnu/alpha/arch.h b/sysdeps/linux-gnu/alpha/arch.h
index cdeeb52..930b6f1 100644
--- a/sysdeps/linux-gnu/alpha/arch.h
+++ b/sysdeps/linux-gnu/alpha/arch.h
@@ -4,4 +4,8 @@
#define LT_ELFCLASS ELFCLASS64
#define LT_ELF_MACHINE EM_ALPHA
+#define LT_ELFCLASS2 ELFCLASS64
#define LT_ELF_MACHINE2 EM_FAKE_ALPHA
+
+#define PLTs_INIT_BY_HERE NULL
+#define E_ENTRY_NAME "_start"
diff --git a/sysdeps/linux-gnu/alpha/plt.c b/sysdeps/linux-gnu/alpha/plt.c
index 32dfafb..16ec3d0 100644
--- a/sysdeps/linux-gnu/alpha/plt.c
+++ b/sysdeps/linux-gnu/alpha/plt.c
@@ -2,7 +2,13 @@
#include "ltrace.h"
#include "elf.h"
-GElf_Addr arch_plt_sym_val(struct ltelf * lte, size_t ndx, GElf_Rela * rela)
+GElf_Addr
+arch_plt_sym_val (struct ltelf *lte, size_t ndx, GElf_Rela *rela)
{
- return lte->plt_addr + ndx * 12 + 32;
+ return lte->plt_addr + ndx * 12 + 32;
+}
+
+void * plt2addr(struct process *proc, void ** plt)
+{
+ return (void *) plt;
}
diff --git a/sysdeps/linux-gnu/alpha/regs.c b/sysdeps/linux-gnu/alpha/regs.c
index fcba535..c59eee9 100644
--- a/sysdeps/linux-gnu/alpha/regs.c
+++ b/sysdeps/linux-gnu/alpha/regs.c
@@ -16,22 +16,22 @@
# define PTRACE_POKEUSER PTRACE_POKEUSR
#endif
-void *get_instruction_pointer(struct process *proc)
-{
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 64 /* REG_PC */ , 0);
+void *
+get_instruction_pointer(struct process * proc) {
+ return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 64 /* REG_PC */, 0);
}
-void set_instruction_pointer(struct process *proc, void *addr)
-{
- ptrace(PTRACE_POKEUSER, proc->pid, 64 /* REG_PC */ , addr);
+void
+set_instruction_pointer(struct process * proc, void * addr) {
+ ptrace(PTRACE_POKEUSER, proc->pid, 64 /* REG_PC */, addr);
}
-void *get_stack_pointer(struct process *proc)
-{
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 30 /* REG_FP */ , 0);
+void *
+get_stack_pointer(struct process * proc) {
+ return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 30 /* REG_FP */, 0);
}
-void *get_return_addr(struct process *proc, void *stack_pointer)
-{
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 26 /* RA */ , 0);
+void *
+get_return_addr(struct process * proc, void * stack_pointer) {
+ return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 26 /* RA */, 0);
}
diff --git a/sysdeps/linux-gnu/alpha/trace.c b/sysdeps/linux-gnu/alpha/trace.c
index 3d35cf2..3d6237c 100644
--- a/sysdeps/linux-gnu/alpha/trace.c
+++ b/sysdeps/linux-gnu/alpha/trace.c
@@ -25,51 +25,45 @@ void get_arch_dep(struct process *proc)
/* Returns 1 if syscall, 2 if sysret, 0 otherwise.
*/
-int syscall_p(struct process *proc, int status, int *sysnum)
-{
- if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
- char *ip = get_instruction_pointer(proc) - 4;
+int
+syscall_p(struct process * proc, int status, int * sysnum) {
+ if (WIFSTOPPED(status) && WSTOPSIG(status)==(SIGTRAP | proc->tracesysgood)) {
+ char *ip=get_instruction_pointer(proc) - 4;
long x = ptrace(PTRACE_PEEKTEXT, proc->pid, ip, 0);
debug(2, "instr: %016lx", x);
- if ((x & 0xffffffff) != 0x00000083)
+ if((x & 0xffffffff) != 0x00000083)
return 0;
- *sysnum =
- ptrace(PTRACE_PEEKUSER, proc->pid, 0 /* REG_R0 */ , 0);
- if (proc->callstack_depth > 0
- && proc->callstack[proc->callstack_depth - 1].is_syscall) {
+ *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, 0 /* REG_R0 */, 0);
+ if (proc->callstack_depth > 0 && proc->callstack[proc->callstack_depth-1].is_syscall) {
return 2;
}
- if (*sysnum >= 0 && *sysnum < 500) {
+ if (*sysnum>=0 && *sysnum<500) {
return 1;
}
}
return 0;
}
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
-{
- if (arg_num == -1) { /* return value */
- return ptrace(PTRACE_PEEKUSER, proc->pid, 0 /* REG_R0 */ , 0);
+long
+gimme_arg(enum tof type, struct process * proc, int arg_num) {
+ if (arg_num==-1) { /* return value */
+ return ptrace(PTRACE_PEEKUSER, proc->pid, 0 /* REG_R0 */, 0);
}
- if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) {
- if (arg_num <= 5)
- return ptrace(PTRACE_PEEKUSER, proc->pid,
- arg_num + 16 /* REG_A0 */ , 0);
+ if (type==LT_TOF_FUNCTION || type==LT_TOF_FUNCTIONR) {
+ if(arg_num <= 5)
+ return ptrace(PTRACE_PEEKUSER, proc->pid, arg_num + 16 /* REG_A0 */, 0);
else
- return ptrace(PTRACE_PEEKTEXT, proc->pid,
- proc->stack_pointer + 8 * (arg_num - 6),
- 0);
- } else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) {
- return ptrace(PTRACE_PEEKUSER, proc->pid,
- arg_num + 16 /* REG_A0 */ , 0);
+ return ptrace(PTRACE_PEEKTEXT, proc->pid, proc->stack_pointer+8*(arg_num-6), 0);
+ } else if (type==LT_TOF_SYSCALL || type==LT_TOF_SYSCALLR) {
+ return ptrace(PTRACE_PEEKUSER, proc->pid, arg_num + 16 /* REG_A0 */, 0);
} else {
fprintf(stderr, "gimme_arg called with wrong arguments\n");
exit(1);
}
return 0;
}
-
-void save_register_args(enum tof type, struct process *proc)
+
+void save_register_args(enum tof type, struct process * proc)
{
}
diff --git a/sysdeps/linux-gnu/arm/arch.h b/sysdeps/linux-gnu/arm/arch.h
index e8a8b66..315238d 100644
--- a/sysdeps/linux-gnu/arm/arch.h
+++ b/sysdeps/linux-gnu/arm/arch.h
@@ -4,3 +4,6 @@
#define LT_ELFCLASS ELFCLASS32
#define LT_ELF_MACHINE EM_ARM
+
+#define PLTs_INIT_BY_HERE NULL
+#define E_ENTRY_NAME "_start"
diff --git a/sysdeps/linux-gnu/arm/plt.c b/sysdeps/linux-gnu/arm/plt.c
index 1dae91f..51463c5 100644
--- a/sysdeps/linux-gnu/arm/plt.c
+++ b/sysdeps/linux-gnu/arm/plt.c
@@ -2,7 +2,13 @@
#include "ltrace.h"
#include "elf.h"
-GElf_Addr arch_plt_sym_val(struct ltelf * lte, size_t ndx, GElf_Rela * rela)
+GElf_Addr
+arch_plt_sym_val (struct ltelf *lte, size_t ndx, GElf_Rela *rela)
{
- return lte->plt_addr + 20 + ndx * 12;
+ return lte->plt_addr + 20 + ndx * 12;
+}
+
+void * plt2addr(struct process *proc, void ** plt)
+{
+ return (void *) plt;
}
diff --git a/sysdeps/linux-gnu/arm/regs.c b/sysdeps/linux-gnu/arm/regs.c
index 819754f..70ead10 100644
--- a/sysdeps/linux-gnu/arm/regs.c
+++ b/sysdeps/linux-gnu/arm/regs.c
@@ -20,24 +20,24 @@
#define off_lr 56
#define off_sp 52
-void *get_instruction_pointer(struct process *proc)
-{
+void *
+get_instruction_pointer(struct process * proc) {
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0);
}
-void set_instruction_pointer(struct process *proc, void *addr)
-{
+void
+set_instruction_pointer(struct process * proc, void * addr) {
ptrace(PTRACE_POKEUSER, proc->pid, off_pc, addr);
}
-void *get_stack_pointer(struct process *proc)
-{
+void *
+get_stack_pointer(struct process * proc) {
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_sp, 0);
}
/* really, this is given the *stack_pointer expecting
* a CISC architecture; in our case, we don't need that */
-void *get_return_addr(struct process *proc, void *stack_pointer)
-{
+void *
+get_return_addr(struct process * proc, void * stack_pointer) {
return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_lr, 0);
}
diff --git a/sysdeps/linux-gnu/arm/trace.c b/sysdeps/linux-gnu/arm/trace.c
index 0d68ae0..485f0ad 100644
--- a/sysdeps/linux-gnu/arm/trace.c
+++ b/sysdeps/linux-gnu/arm/trace.c
@@ -26,54 +26,47 @@
#define off_ip 48
#define off_pc 60
-void get_arch_dep(struct process *proc)
-{
+void
+get_arch_dep(struct process * proc) {
}
/* Returns 1 if syscall, 2 if sysret, 0 otherwise.
*/
-int syscall_p(struct process *proc, int status, int *sysnum)
-{
- if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
+int
+syscall_p(struct process * proc, int status, int * sysnum) {
+ if (WIFSTOPPED(status) && WSTOPSIG(status)==(SIGTRAP | proc->tracesysgood)) {
/* get the user's pc (plus 8) */
int pc = ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0);
/* fetch the SWI instruction */
- int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 4, 0);
-
+ int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc-4, 0) ;
+
*sysnum = insn & 0xFFFF;
/* if it is a syscall, return 1 or 2 */
if ((insn & 0xFFFF0000) == 0xef900000) {
- return ptrace(PTRACE_PEEKUSER, proc->pid, off_ip,
- 0) ? 2 : 1;
+ return ptrace(PTRACE_PEEKUSER, proc->pid, off_ip, 0) ? 2 : 1;
}
}
return 0;
}
-
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
-{
- if (arg_num == -1) { /* return value */
+
+long
+gimme_arg(enum tof type, struct process * proc, int arg_num) {
+ if (arg_num==-1) { /* return value */
return ptrace(PTRACE_PEEKUSER, proc->pid, off_r0, 0);
}
/* deal with the ARM calling conventions */
- if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) {
- if (arg_num < 4) {
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num,
- 0);
+ if (type==LT_TOF_FUNCTION || type==LT_TOF_FUNCTIONR) {
+ if (arg_num<4) {
+ return ptrace(PTRACE_PEEKUSER, proc->pid, 4*arg_num, 0);
} else {
- return ptrace(PTRACE_PEEKDATA, proc->pid,
- proc->stack_pointer + 4 * (arg_num - 4),
- 0);
+ return ptrace(PTRACE_PEEKDATA, proc->pid, proc->stack_pointer+4*(arg_num-4), 0);
}
- } else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) {
- if (arg_num < 5) {
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num,
- 0);
+ } else if (type==LT_TOF_SYSCALL || type==LT_TOF_SYSCALLR) {
+ if (arg_num<5) {
+ return ptrace(PTRACE_PEEKUSER, proc->pid, 4*arg_num, 0);
} else {
- return ptrace(PTRACE_PEEKDATA, proc->pid,
- proc->stack_pointer + 4 * (arg_num - 5),
- 0);
+ return ptrace(PTRACE_PEEKDATA, proc->pid, proc->stack_pointer+4*(arg_num-5), 0);
}
} else {
fprintf(stderr, "gimme_arg called with wrong arguments\n");
@@ -83,6 +76,6 @@ long gimme_arg(enum tof type, struct process *proc, int arg_num)
return 0;
}
-void save_register_args(enum tof type, struct process *proc)
-{
+void
+save_register_args(enum tof type, struct process * proc) {
}
diff --git a/sysdeps/linux-gnu/breakpoint.c b/sysdeps/linux-gnu/breakpoint.c
index fe6ac69..712f1a5 100644
--- a/sysdeps/linux-gnu/breakpoint.c
+++ b/sysdeps/linux-gnu/breakpoint.c
@@ -7,6 +7,7 @@
#include "arch.h"
#include "options.h"
#include "output.h"
+#include "debug.h"
static unsigned char break_insn[] = BREAKPOINT_VALUE;
@@ -14,30 +15,24 @@ static unsigned char break_insn[] = BREAKPOINT_VALUE;
extern void arch_enable_breakpoint(pid_t, struct breakpoint*);
void enable_breakpoint(pid_t pid, struct breakpoint *sbp)
{
- arch_enable_breakpoint(pid, sbp);
+ arch_enable_breakpoint(pid, sbp);
}
#else
-void enable_breakpoint(pid_t pid, struct breakpoint *sbp)
-{
- int i, j;
+void
+enable_breakpoint(pid_t pid, struct breakpoint * sbp) {
+ int i,j;
- if (opt_d > 1) {
- output_line(0, "enable_breakpoint(%d,%p)", pid, sbp->addr);
- }
+ debug(1, "enable_breakpoint(%d,%p)", pid, sbp->addr);
- for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) {
- long a =
- ptrace(PTRACE_PEEKTEXT, pid, sbp->addr + i * sizeof(long),
- 0);
- for (j = 0;
- j < sizeof(long)
- && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) {
- unsigned char *bytes = (unsigned char *)&a;
+ for(i=0; i < 1+((BREAKPOINT_LENGTH-1)/sizeof(long)); i++) {
+ long a = ptrace(PTRACE_PEEKTEXT, pid, sbp->addr + i*sizeof(long), 0);
+ for(j=0; j<sizeof(long) && i*sizeof(long)+j < BREAKPOINT_LENGTH; j++) {
+ unsigned char * bytes = (unsigned char *)&a;
- sbp->orig_value[i * sizeof(long) + j] = bytes[+j];
- bytes[j] = break_insn[i * sizeof(long) + j];
+ sbp->orig_value[i*sizeof(long)+j] = bytes[+j];
+ bytes[j] = break_insn[i*sizeof(long)+j];
}
- ptrace(PTRACE_POKETEXT, pid, sbp->addr + i * sizeof(long), a);
+ ptrace(PTRACE_POKETEXT, pid, sbp->addr + i*sizeof(long), a);
}
}
#endif /* ARCH_HAVE_ENABLE_BREAKPOINT */
@@ -49,26 +44,22 @@ disable_breakpoint(pid_t pid, const struct breakpoint * sbp) {
arch_disable_breakpoint(pid, sbp);
}
#else
-void disable_breakpoint(pid_t pid, const struct breakpoint *sbp)
-{
- int i, j;
+void
+disable_breakpoint(pid_t pid, const struct breakpoint * sbp) {
+ int i,j;
- if (opt_d > 1) {
+ if (opt_d>1) {
output_line(0, "disable_breakpoint(%d,%p)", pid, sbp->addr);
}
- for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) {
- long a =
- ptrace(PTRACE_PEEKTEXT, pid, sbp->addr + i * sizeof(long),
- 0);
- for (j = 0;
- j < sizeof(long)
- && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) {
- unsigned char *bytes = (unsigned char *)&a;
+ for(i=0; i < 1+((BREAKPOINT_LENGTH-1)/sizeof(long)); i++) {
+ long a = ptrace(PTRACE_PEEKTEXT, pid, sbp->addr + i*sizeof(long), 0);
+ for(j=0; j<sizeof(long) && i*sizeof(long)+j < BREAKPOINT_LENGTH; j++) {
+ unsigned char * bytes = (unsigned char *)&a;
- bytes[j] = sbp->orig_value[i * sizeof(long) + j];
+ bytes[j] = sbp->orig_value[i*sizeof(long)+j];
}
- ptrace(PTRACE_POKETEXT, pid, sbp->addr + i * sizeof(long), a);
+ ptrace(PTRACE_POKETEXT, pid, sbp->addr + i*sizeof(long), a);
}
}
#endif /* ARCH_HAVE_DISABLE_BREAKPOINT */
diff --git a/sysdeps/linux-gnu/i386/arch.h b/sysdeps/linux-gnu/i386/arch.h
index dc7383f..c624a8a 100644
--- a/sysdeps/linux-gnu/i386/arch.h
+++ b/sysdeps/linux-gnu/i386/arch.h
@@ -4,3 +4,6 @@
#define LT_ELFCLASS ELFCLASS32
#define LT_ELF_MACHINE EM_386
+
+#define PLTs_INIT_BY_HERE NULL
+#define E_ENTRY_NAME "_start"
diff --git a/sysdeps/linux-gnu/i386/plt.c b/sysdeps/linux-gnu/i386/plt.c
index 939bc4e..36d0ecd 100644
--- a/sysdeps/linux-gnu/i386/plt.c
+++ b/sysdeps/linux-gnu/i386/plt.c
@@ -2,7 +2,13 @@
#include "ltrace.h"
#include "elf.h"
-GElf_Addr arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela)
+GElf_Addr
+arch_plt_sym_val (struct ltelf *lte, size_t ndx, GElf_Rela *rela)
{
- return lte->plt_addr + (ndx + 1) * 16;
+ return lte->plt_addr + (ndx + 1) * 16;
+}
+
+void * plt2addr(struct process *proc, void ** plt)
+{
+ return (void *) plt;
}
diff --git a/sysdeps/linux-gnu/i386/regs.c b/sysdeps/linux-gnu/i386/regs.c
index 158fa24..75268e9 100644
--- a/sysdeps/linux-gnu/i386/regs.c
+++ b/sysdeps/linux-gnu/i386/regs.c
@@ -16,22 +16,22 @@
# define PTRACE_POKEUSER PTRACE_POKEUSR
#endif
-void *get_instruction_pointer(struct process *proc)
-{
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * EIP, 0);
+void *
+get_instruction_pointer(struct process * proc) {
+ return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4*EIP, 0);
}
-void set_instruction_pointer(struct process *proc, void *addr)
-{
- ptrace(PTRACE_POKEUSER, proc->pid, 4 * EIP, (long)addr);
+void
+set_instruction_pointer(struct process * proc, void * addr) {
+ ptrace(PTRACE_POKEUSER, proc->pid, 4*EIP, (long)addr);
}
-void *get_stack_pointer(struct process *proc)
-{
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * UESP, 0);
+void *
+get_stack_pointer(struct process * proc) {
+ return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4*UESP, 0);
}
-void *get_return_addr(struct process *proc, void *stack_pointer)
-{
+void *
+get_return_addr(struct process * proc, void * stack_pointer) {
return (void *)ptrace(PTRACE_PEEKTEXT, proc->pid, stack_pointer, 0);
}
diff --git a/sysdeps/linux-gnu/i386/syscallent.h b/sysdeps/linux-gnu/i386/syscallent.h
index b6eb2a8..c4bdae5 100644
--- a/sysdeps/linux-gnu/i386/syscallent.h
+++ b/sysdeps/linux-gnu/i386/syscallent.h
@@ -283,3 +283,12 @@
"mq_getsetattr", /* 282 */
"kexec_load", /* 283 */
"waitid", /* 284 */
+ "285", /* 285 */
+ "add_key", /* 286 */
+ "request_key", /* 287 */
+ "keyctl", /* 288 */
+ "ioprio_set", /* 289 */
+ "ioprio_get", /* 290 */
+ "inotify_init", /* 291 */
+ "inotify_add_watch", /* 292 */
+ "inotify_rm_watch", /* 293 */
diff --git a/sysdeps/linux-gnu/i386/trace.c b/sysdeps/linux-gnu/i386/trace.c
index fe9d8a4..b8eff3d 100644
--- a/sysdeps/linux-gnu/i386/trace.c
+++ b/sysdeps/linux-gnu/i386/trace.c
@@ -19,58 +19,51 @@
# define PTRACE_POKEUSER PTRACE_POKEUSR
#endif
-void get_arch_dep(struct process *proc)
-{
+void
+get_arch_dep(struct process * proc) {
}
/* Returns 1 if syscall, 2 if sysret, 0 otherwise.
*/
-int syscall_p(struct process *proc, int status, int *sysnum)
-{
- if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
- *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, 4 * ORIG_EAX, 0);
+int
+syscall_p(struct process * proc, int status, int * sysnum) {
+ if (WIFSTOPPED(status) && WSTOPSIG(status)==(SIGTRAP | proc->tracesysgood)) {
+ *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, 4*ORIG_EAX, 0);
if (proc->callstack_depth > 0 &&
- proc->callstack[proc->callstack_depth - 1].is_syscall) {
+ proc->callstack[proc->callstack_depth-1].is_syscall) {
return 2;
}
- if (*sysnum >= 0) {
+ if (*sysnum>=0) {
return 1;
}
}
return 0;
}
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
-{
- if (arg_num == -1) { /* return value */
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * EAX, 0);
+long
+gimme_arg(enum tof type, struct process * proc, int arg_num) {
+ if (arg_num==-1) { /* return value */
+ return ptrace(PTRACE_PEEKUSER, proc->pid, 4*EAX, 0);
}
- if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) {
- return ptrace(PTRACE_PEEKTEXT, proc->pid,
- proc->stack_pointer + 4 * (arg_num + 1), 0);
- } else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) {
+ if (type==LT_TOF_FUNCTION || type==LT_TOF_FUNCTIONR) {
+ return ptrace(PTRACE_PEEKTEXT, proc->pid, proc->stack_pointer+4*(arg_num+1), 0);
+ } else if (type==LT_TOF_SYSCALL || type==LT_TOF_SYSCALLR) {
#if 0
- switch (arg_num) {
- case 0:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * EBX, 0);
- case 1:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * ECX, 0);
- case 2:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * EDX, 0);
- case 3:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * ESI, 0);
- case 4:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * EDI, 0);
- default:
- fprintf(stderr,
- "gimme_arg called with wrong arguments\n");
- exit(2);
+ switch(arg_num) {
+ case 0: return ptrace(PTRACE_PEEKUSER, proc->pid, 4*EBX, 0);
+ case 1: return ptrace(PTRACE_PEEKUSER, proc->pid, 4*ECX, 0);
+ case 2: return ptrace(PTRACE_PEEKUSER, proc->pid, 4*EDX, 0);
+ case 3: return ptrace(PTRACE_PEEKUSER, proc->pid, 4*ESI, 0);
+ case 4: return ptrace(PTRACE_PEEKUSER, proc->pid, 4*EDI, 0);
+ default:
+ fprintf(stderr, "gimme_arg called with wrong arguments\n");
+ exit(2);
}
#else
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, 0);
+ return ptrace(PTRACE_PEEKUSER, proc->pid, 4*arg_num, 0);
#endif
} else {
fprintf(stderr, "gimme_arg called with wrong arguments\n");
@@ -80,6 +73,6 @@ long gimme_arg(enum tof type, struct process *proc, int arg_num)
return 0;
}
-void save_register_args(enum tof type, struct process *proc)
-{
+void
+save_register_args(enum tof type, struct process * proc) {
}
diff --git a/sysdeps/linux-gnu/ia64/arch.h b/sysdeps/linux-gnu/ia64/arch.h
index b5f141f..6efef3d 100644
--- a/sysdeps/linux-gnu/ia64/arch.h
+++ b/sysdeps/linux-gnu/ia64/arch.h
@@ -1,10 +1,12 @@
#define ARCH_HAVE_DISABLE_BREAKPOINT 1
#define ARCH_HAVE_ENABLE_BREAKPOINT 1
-
#define BREAKPOINT_LENGTH 16
#define BREAKPOINT_VALUE {0}
#define DECR_PC_AFTER_BREAK 0
#define LT_ELFCLASS ELFCLASS64
#define LT_ELF_MACHINE EM_IA_64
+
+#define PLTs_INIT_BY_HERE NULL
+#define E_ENTRY_NAME "_start"
diff --git a/sysdeps/linux-gnu/ia64/plt.c b/sysdeps/linux-gnu/ia64/plt.c
index 05a1a24..b4ee017 100644
--- a/sysdeps/linux-gnu/ia64/plt.c
+++ b/sysdeps/linux-gnu/ia64/plt.c
@@ -40,3 +40,8 @@ arch_plt_sym_val (struct ltelf *lte, size_t ndx, GElf_Rela *rela)
return addr;
}
+
+void * plt2addr(struct process *proc, void ** plt)
+{
+ return (void *) plt;
+}
diff --git a/sysdeps/linux-gnu/ia64/syscallent.h b/sysdeps/linux-gnu/ia64/syscallent.h
index 1a5b505..88545d4 100644
--- a/sysdeps/linux-gnu/ia64/syscallent.h
+++ b/sysdeps/linux-gnu/ia64/syscallent.h
@@ -1257,3 +1257,24 @@
"clock_nanosleep", /* 1256 */
"fstatfs64", /* 1257 */
"statfs64", /* 1258 */
+ "mbind", /* 1259 */
+ "get_mempolicy", /* 1260 */
+ "set_mempolicy", /* 1261 */
+ "mq_open", /* 1262 */
+ "mq_unlink", /* 1263 */
+ "mq_timedsend", /* 1264 */
+ "mq_timedreceive", /* 1265 */
+ "mq_notify", /* 1266 */
+ "mq_getsetattr", /* 1267 */
+ "kexec_load", /* 1268 */
+ "vserver", /* 1269 */
+ "waitid", /* 1270 */
+ "add_key", /* 1271 */
+ "request_key", /* 1272 */
+ "keyctl", /* 1273 */
+ "ioprio_set", /* 1274 */
+ "ioprio_get", /* 1275 */
+ "set_zone_reclaim", /* 1276 */
+ "inotify_init", /* 1277 */
+ "inotify_add_watch", /* 1278 */
+ "inotify_rm_watch", /* 1279 */
diff --git a/sysdeps/linux-gnu/ia64/trace.c b/sysdeps/linux-gnu/ia64/trace.c
index 46e8771..7fa6c1e 100644
--- a/sysdeps/linux-gnu/ia64/trace.c
+++ b/sysdeps/linux-gnu/ia64/trace.c
@@ -37,8 +37,7 @@ union bundle_t {
int
syscall_p(struct process * proc, int status, int * sysnum) {
- if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP)
- {
+ if (WIFSTOPPED(status) && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
unsigned long slot = (ptrace (PTRACE_PEEKUSER, proc->pid, PT_CR_IPSR, 0) >> 41) & 0x3;
unsigned long ip = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IIP, 0);
diff --git a/sysdeps/linux-gnu/m68k/arch.h b/sysdeps/linux-gnu/m68k/arch.h
index 1790d09..438545f 100644
--- a/sysdeps/linux-gnu/m68k/arch.h
+++ b/sysdeps/linux-gnu/m68k/arch.h
@@ -4,3 +4,6 @@
#define LT_ELFCLASS ELFCLASS32
#define LT_ELF_MACHINE EM_68K
+
+#define PLTs_INIT_BY_HERE NULL
+#define E_ENTRY_NAME "_start"
diff --git a/sysdeps/linux-gnu/m68k/plt.c b/sysdeps/linux-gnu/m68k/plt.c
index 09168e9..54cc920 100644
--- a/sysdeps/linux-gnu/m68k/plt.c
+++ b/sysdeps/linux-gnu/m68k/plt.c
@@ -2,8 +2,14 @@
#include "ltrace.h"
#include "elf.h"
-GElf_Addr arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela)
+GElf_Addr
+arch_plt_sym_val (struct ltelf *lte, size_t ndx, GElf_Rela *rela)
{
- return lte->plt_addr + (ndx + 1)
- * ((lte->ehdr.e_flags & EF_CPU32) ? 24 : 12);
+ return lte->plt_addr + (ndx + 1)
+ * ((lte->ehdr.e_flags & EF_CPU32) ? 24 : 12);
+}
+
+void * plt2addr(struct process *proc, void ** plt)
+{
+ return (void *) plt;
}
diff --git a/sysdeps/linux-gnu/m68k/regs.c b/sysdeps/linux-gnu/m68k/regs.c
index d953d28..187cef5 100644
--- a/sysdeps/linux-gnu/m68k/regs.c
+++ b/sysdeps/linux-gnu/m68k/regs.c
@@ -16,22 +16,22 @@
# define PTRACE_POKEUSER PTRACE_POKEUSR
#endif
-void *get_instruction_pointer(struct process *proc)
-{
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_PC, 0);
+void *
+get_instruction_pointer(struct process * proc) {
+ return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4*PT_PC, 0);
}
-void set_instruction_pointer(struct process *proc, void *addr)
-{
- ptrace(PTRACE_POKEUSER, proc->pid, 4 * PT_PC, addr);
+void
+set_instruction_pointer(struct process * proc, void * addr) {
+ ptrace(PTRACE_POKEUSER, proc->pid, 4*PT_PC, addr);
}
-void *get_stack_pointer(struct process *proc)
-{
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_USP, 0);
+void *
+get_stack_pointer(struct process * proc) {
+ return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4*PT_USP, 0);
}
-void *get_return_addr(struct process *proc, void *stack_pointer)
-{
+void *
+get_return_addr(struct process * proc, void * stack_pointer) {
return (void *)ptrace(PTRACE_PEEKTEXT, proc->pid, stack_pointer, 0);
}
diff --git a/sysdeps/linux-gnu/m68k/trace.c b/sysdeps/linux-gnu/m68k/trace.c
index b4e1b88..fac5fbe 100644
--- a/sysdeps/linux-gnu/m68k/trace.c
+++ b/sysdeps/linux-gnu/m68k/trace.c
@@ -18,26 +18,24 @@
# define PTRACE_POKEUSER PTRACE_POKEUSR
#endif
-void get_arch_dep(struct process *proc)
-{
+void
+get_arch_dep(struct process * proc) {
}
/* Returns 1 if syscall, 2 if sysret, 0 otherwise.
*/
-int syscall_p(struct process *proc, int status, int *sysnum)
-{
+int
+syscall_p(struct process * proc, int status, int * sysnum) {
int depth;
- if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
- *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_ORIG_D0, 0);
- if (*sysnum == -1)
- return 0;
- if (*sysnum >= 0) {
+ if (WIFSTOPPED(status) && WSTOPSIG(status)==(SIGTRAP | proc->tracesysgood)) {
+ *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, 4*PT_ORIG_D0, 0);
+ if (*sysnum == -1) return 0;
+ if (*sysnum>=0) {
depth = proc->callstack_depth;
- if (depth > 0 &&
- proc->callstack[depth - 1].is_syscall &&
- proc->callstack[depth - 1].c_un.syscall ==
- *sysnum) {
+ if (depth>0 &&
+ proc->callstack[depth-1].is_syscall &&
+ proc->callstack[depth-1].c_un.syscall==*sysnum) {
return 2;
} else {
return 1;
@@ -47,36 +45,29 @@ int syscall_p(struct process *proc, int status, int *sysnum)
return 0;
}
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
-{
- if (arg_num == -1) { /* return value */
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D0, 0);
+long
+gimme_arg(enum tof type, struct process * proc, int arg_num) {
+ if (arg_num==-1) { /* return value */
+ return ptrace(PTRACE_PEEKUSER, proc->pid, 4*PT_D0, 0);
}
- if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) {
- return ptrace(PTRACE_PEEKTEXT, proc->pid,
- proc->stack_pointer + 4 * (arg_num + 1), 0);
- } else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) {
+ if (type==LT_TOF_FUNCTION || type==LT_TOF_FUNCTIONR) {
+ return ptrace(PTRACE_PEEKTEXT, proc->pid, proc->stack_pointer+4*(arg_num+1), 0);
+ } else if (type==LT_TOF_SYSCALL || type==LT_TOF_SYSCALLR) {
#if 0
- switch (arg_num) {
- case 0:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D1, 0);
- case 1:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D2, 0);
- case 2:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D3, 0);
- case 3:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D4, 0);
- case 4:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D5, 0);
- default:
- fprintf(stderr,
- "gimme_arg called with wrong arguments\n");
- exit(2);
+ switch(arg_num) {
+ case 0: return ptrace(PTRACE_PEEKUSER, proc->pid, 4*PT_D1, 0);
+ case 1: return ptrace(PTRACE_PEEKUSER, proc->pid, 4*PT_D2, 0);
+ case 2: return ptrace(PTRACE_PEEKUSER, proc->pid, 4*PT_D3, 0);
+ case 3: return ptrace(PTRACE_PEEKUSER, proc->pid, 4*PT_D4, 0);
+ case 4: return ptrace(PTRACE_PEEKUSER, proc->pid, 4*PT_D5, 0);
+ default:
+ fprintf(stderr, "gimme_arg called with wrong arguments\n");
+ exit(2);
}
#else
/* That hack works on m68k, too */
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, 0);
+ return ptrace(PTRACE_PEEKUSER, proc->pid, 4*arg_num, 0);
#endif
} else {
fprintf(stderr, "gimme_arg called with wrong arguments\n");
@@ -86,6 +77,6 @@ long gimme_arg(enum tof type, struct process *proc, int arg_num)
return 0;
}
-void save_register_args(enum tof type, struct process *proc)
-{
+void
+save_register_args(enum tof type, struct process * proc) {
}
diff --git a/sysdeps/linux-gnu/ppc/arch.h b/sysdeps/linux-gnu/ppc/arch.h
index e04e885..37634bf 100644
--- a/sysdeps/linux-gnu/ppc/arch.h
+++ b/sysdeps/linux-gnu/ppc/arch.h
@@ -1,6 +1,18 @@
#define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
#define BREAKPOINT_LENGTH 4
#define DECR_PC_AFTER_BREAK 0
+#define E_ENTRY_NAME "_start"
#define LT_ELFCLASS ELFCLASS32
#define LT_ELF_MACHINE EM_PPC
+#ifdef __powerpc64__
+#define LT_ELFCLASS2 ELFCLASS64
+#define LT_ELF_MACHINE2 EM_PPC64
+
+#define PLTs_INIT_BY_HERE E_ENTRY_NAME
+
+#else
+
+#define PLTs_INIT_BY_HERE NULL
+
+#endif
diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
index 19991b5..c85ea92 100644
--- a/sysdeps/linux-gnu/ppc/plt.c
+++ b/sysdeps/linux-gnu/ppc/plt.c
@@ -1,8 +1,42 @@
#include <gelf.h>
#include "ltrace.h"
#include "elf.h"
+#include "debug.h"
+#include "ptrace.h"
+#include "options.h"
-GElf_Addr arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela)
+GElf_Addr
+arch_plt_sym_val (struct ltelf *lte, size_t ndx, GElf_Rela *rela)
{
- return rela->r_offset;
+ return rela->r_offset;
}
+
+void * plt2addr(struct process *proc, void ** plt)
+{
+ long addr;
+
+ debug(3, 0);
+
+ if (proc->e_machine == EM_PPC || plt == 0)
+ return (void *)plt;
+
+ if (proc->pid == 0)
+ return (void *)0;
+
+ // On a PowerPC-64 system, a plt is three 64-bit words: the first is the
+ // 64-bit address of the routine. Before the PLT has been initialized, this
+ // will be 0x0. In fact, the symbol table won't have the plt's address even.
+ // Ater the PLT has been initialized, but before it has been resolved, the
+ // first word will be the address of the function in the dynamic linker that
+ // will reslove the PLT. After the PLT is resolved, this will will be the
+ // address of the routine whose symbol is in the symbol table.
+
+ addr = ptrace(PTRACE_PEEKTEXT, proc->pid, plt);
+
+ if (opt_d >= 3) {
+ xinfdump(proc->pid, plt, sizeof(void*)*3);
+ }
+
+ return (void *)addr;
+}
+
diff --git a/sysdeps/linux-gnu/ppc/regs.c b/sysdeps/linux-gnu/ppc/regs.c
index d0d51e3..a14e8d6 100644
--- a/sysdeps/linux-gnu/ppc/regs.c
+++ b/sysdeps/linux-gnu/ppc/regs.c
@@ -16,22 +16,22 @@
# define PTRACE_POKEUSER PTRACE_POKEUSR
#endif
-void *get_instruction_pointer(struct process *proc)
-{
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_NIP, 0);
+void *
+get_instruction_pointer(struct process * proc) {
+ return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*PT_NIP, 0);
}
-void set_instruction_pointer(struct process *proc, void *addr)
-{
- ptrace(PTRACE_POKEUSER, proc->pid, 4 * PT_NIP, addr);
+void
+set_instruction_pointer(struct process * proc, void * addr) {
+ ptrace(PTRACE_POKEUSER, proc->pid, sizeof(long)*PT_NIP, addr);
}
-void *get_stack_pointer(struct process *proc)
-{
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_R1, 0);
+void *
+get_stack_pointer(struct process * proc) {
+ return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*PT_R1, 0);
}
-void *get_return_addr(struct process *proc, void *stack_pointer)
-{
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_LNK, 0);
+void *
+get_return_addr(struct process * proc, void * stack_pointer) {
+ return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*PT_LNK, 0);
}
diff --git a/sysdeps/linux-gnu/ppc/syscallent.h b/sysdeps/linux-gnu/ppc/syscallent.h
index 2bbba38..205fc4a 100644
--- a/sysdeps/linux-gnu/ppc/syscallent.h
+++ b/sysdeps/linux-gnu/ppc/syscallent.h
@@ -261,3 +261,12 @@
"mq_notify", /* 266 */
"mq_getsetattr", /* 267 */
"kexec_load", /* 268 */
+ "add_key", /* 269 */
+ "request_key", /* 270 */
+ "keyctl", /* 271 */
+ "waitid", /* 272 */
+ "ioprio_set", /* 273 */
+ "ioprio_get", /* 274 */
+ "inotify_init", /* 275 */
+ "inotify_add_watch", /* 276 */
+ "inotify_rm_watch", /* 277 */
diff --git a/sysdeps/linux-gnu/ppc/trace.c b/sysdeps/linux-gnu/ppc/trace.c
index 6670be1..f31fb35 100644
--- a/sysdeps/linux-gnu/ppc/trace.c
+++ b/sysdeps/linux-gnu/ppc/trace.c
@@ -7,6 +7,7 @@
#include <signal.h>
#include <sys/ptrace.h>
#include <asm/ptrace.h>
+#include <elf.h>
#include "ltrace.h"
@@ -20,23 +21,28 @@
void get_arch_dep(struct process *proc)
{
+#ifdef __powerpc64__
+ if (proc->arch_ptr)
+ return;
+ proc->mask_32bit = (proc->e_machine == EM_PPC);
+ proc->arch_ptr = (void *) 1;
+#endif
}
+
/* Returns 1 if syscall, 2 if sysret, 0 otherwise.
*/
#define SYSCALL_INSN 0x44000002
-int syscall_p(struct process *proc, int status, int *sysnum)
-{
- if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
- int pc = ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_NIP, 0);
- int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 4, 0);
+int
+syscall_p(struct process * proc, int status, int * sysnum) {
+ if (WIFSTOPPED(status) && WSTOPSIG(status)==(SIGTRAP | proc->tracesysgood)) {
+ long pc = (long)get_instruction_pointer(proc);
+ int insn = (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc-sizeof(long), 0);
if (insn == SYSCALL_INSN) {
- *sysnum =
- ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_R0, 0);
- if (proc->callstack_depth > 0
- && proc->callstack[proc->callstack_depth -
- 1].is_syscall) {
+ *sysnum = (int)ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*PT_R0, 0);
+ if (proc->callstack_depth > 0 &&
+ proc->callstack[proc->callstack_depth-1].is_syscall) {
return 2;
}
return 1;
@@ -45,20 +51,18 @@ int syscall_p(struct process *proc, int status, int *sysnum)
return 0;
}
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
-{
- if (arg_num == -1) { /* return value */
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_R3, 0);
+long
+gimme_arg(enum tof type, struct process * proc, int arg_num) {
+ if (arg_num==-1) { /* return value */
+ return ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*PT_R3, 0);
} else if (arg_num < 8) {
- return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * (arg_num + PT_R3),
- 0);
+ return ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*(arg_num+PT_R3), 0);
} else {
- return ptrace(PTRACE_PEEKDATA, proc->pid,
- proc->stack_pointer + 8 * (arg_num - 8), 0);
+ return ptrace(PTRACE_PEEKDATA, proc->pid, proc->stack_pointer+8*(arg_num-8), 0);
}
return 0;
}
-void save_register_args(enum tof type, struct process *proc)
-{
+void
+save_register_args(enum tof type, struct process * proc) {
}
diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c
index 201fb6d..a5c18f6 100644
--- a/sysdeps/linux-gnu/proc.c
+++ b/sysdeps/linux-gnu/proc.c
@@ -13,21 +13,21 @@
* have a bit delay
*/
-#define MAX_DELAY 100000 /* 100000 microseconds = 0.1 seconds */
+#define MAX_DELAY 100000 /* 100000 microseconds = 0.1 seconds */
/*
* Returns a file name corresponding to a running pid
*/
-char *pid2name(pid_t pid)
-{
+char *
+pid2name(pid_t pid) {
char proc_exe[1024];
if (!kill(pid, 0)) {
- int delay = 0;
+ int delay=0;
sprintf(proc_exe, "/proc/%d/exe", pid);
- while (delay < MAX_DELAY) {
+ while(delay<MAX_DELAY) {
if (!access(proc_exe, F_OK)) {
return strdup(proc_exe);
}
diff --git a/sysdeps/linux-gnu/s390/arch.h b/sysdeps/linux-gnu/s390/arch.h
index bb61ca7..18a1c89 100644
--- a/sysdeps/linux-gnu/s390/arch.h
+++ b/sysdeps/linux-gnu/s390/arch.h
@@ -7,5 +7,15 @@
#define BREAKPOINT_LENGTH 2
#define DECR_PC_AFTER_BREAK 2
+#ifdef __s390x__
+#define LT_ELFCLASS ELFCLASS64
+#define LT_ELF_MACHINE EM_S390
+#define LT_ELFCLASS2 ELFCLASS32
+#define LT_ELF_MACHINE2 EM_S390
+#else
#define LT_ELFCLASS ELFCLASS32
#define LT_ELF_MACHINE EM_S390
+#endif
+
+#define PLTs_INIT_BY_HERE NULL
+#define E_ENTRY_NAME "_start"
diff --git a/sysdeps/linux-gnu/s390/plt.c b/sysdeps/linux-gnu/s390/plt.c
index deb612e..99c524d 100644
--- a/sysdeps/linux-gnu/s390/plt.c
+++ b/sysdeps/linux-gnu/s390/plt.c
@@ -2,7 +2,14 @@
#include "ltrace.h"
#include "elf.h"
-GElf_Addr arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela)
+GElf_Addr
+arch_plt_sym_val (struct ltelf *lte, size_t ndx, GElf_Rela *rela)
{
- return lte->plt_addr + (ndx + 1) * 32;
+ return lte->plt_addr + (ndx + 1) * 32;
+}
+
+
+void * plt2addr(struct process *proc, void ** plt)
+{
+ return (void *) plt;
}
diff --git a/sysdeps/linux-gnu/s390/regs.c b/sysdeps/linux-gnu/s390/regs.c
index efba7f8..3f14115 100644
--- a/sysdeps/linux-gnu/s390/regs.c
+++ b/sysdeps/linux-gnu/s390/regs.c
@@ -21,24 +21,48 @@
# define PTRACE_POKEUSER PTRACE_POKEUSR
#endif
-void *get_instruction_pointer(struct process *proc)
-{
- return (void *)(ptrace(PTRACE_PEEKUSER, proc->pid, PT_PSWADDR, 0) &
- 0x7fffffff);
+#ifdef __s390x__
+#define PSW_MASK 0xffffffffffffffff
+#define PSW_MASK31 0x7fffffff
+#else
+#define PSW_MASK 0x7fffffff
+#endif
+
+void *
+get_instruction_pointer(struct process * proc) {
+ long ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_PSWADDR, 0) & PSW_MASK;
+#ifdef __s390x__
+ if (proc->mask_32bit)
+ ret &= PSW_MASK31;
+#endif
+ return (void *) ret;
}
-void set_instruction_pointer(struct process *proc, void *addr)
-{
+void
+set_instruction_pointer(struct process * proc, void * addr) {
+#ifdef __s390x__
+ if (proc->mask_32bit)
+ addr = (void *) ((long) addr & PSW_MASK31);
+#endif
ptrace(PTRACE_POKEUSER, proc->pid, PT_PSWADDR, addr);
}
-void *get_stack_pointer(struct process *proc)
-{
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR15, 0);
+void *
+get_stack_pointer(struct process * proc) {
+ long ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR15, 0) & PSW_MASK;
+#ifdef __s390x__
+ if (proc->mask_32bit)
+ ret &= PSW_MASK31;
+#endif
+ return (void *) ret;
}
-void *get_return_addr(struct process *proc, void *stack_pointer)
-{
- return (void *)(ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR14, 0) &
- 0x7fffffff);
+void *
+get_return_addr(struct process * proc, void * stack_pointer) {
+ long ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR14, 0) & PSW_MASK;
+#ifdef __s390x__
+ if (proc->mask_32bit)
+ ret &= PSW_MASK31;
+#endif
+ return (void *) ret;
}
diff --git a/sysdeps/linux-gnu/s390/signalent.h b/sysdeps/linux-gnu/s390/signalent.h
index 5395f82..714d56d 100644
--- a/sysdeps/linux-gnu/s390/signalent.h
+++ b/sysdeps/linux-gnu/s390/signalent.h
@@ -29,4 +29,5 @@
"SIGWINCH", /* 28 */
"SIGIO", /* 29 */
"SIGPWR", /* 30 */
- "SIGSYS", /* 31 */
+ "SIGUNUSED", /* 31 */
+ "SIGRTMIN", /* 32 */
diff --git a/sysdeps/linux-gnu/s390/signalent1.h b/sysdeps/linux-gnu/s390/signalent1.h
new file mode 100644
index 0000000..b5b6ca8
--- /dev/null
+++ b/sysdeps/linux-gnu/s390/signalent1.h
@@ -0,0 +1 @@
+#include "s390/signalent.h"
diff --git a/sysdeps/linux-gnu/s390/syscallent.h b/sysdeps/linux-gnu/s390/syscallent.h
index 13bd3c2..5a35d93 100644
--- a/sysdeps/linux-gnu/s390/syscallent.h
+++ b/sysdeps/linux-gnu/s390/syscallent.h
@@ -1,277 +1,5 @@
- "0", /* 0 */
- "exit", /* 1 */
- "fork", /* 2 */
- "read", /* 3 */
- "write", /* 4 */
- "open", /* 5 */
- "close", /* 6 */
- "7", /* 7 */
- "creat", /* 8 */
- "link", /* 9 */
- "unlink", /* 10 */
- "execve", /* 11 */
- "chdir", /* 12 */
- "time", /* 13 */
- "mknod", /* 14 */
- "chmod", /* 15 */
- "lchown", /* 16 */
- "17", /* 17 */
- "18", /* 18 */
- "lseek", /* 19 */
- "getpid", /* 20 */
- "mount", /* 21 */
- "umount", /* 22 */
- "setuid", /* 23 */
- "getuid", /* 24 */
- "stime", /* 25 */
- "ptrace", /* 26 */
- "alarm", /* 27 */
- "28", /* 28 */
- "pause", /* 29 */
- "utime", /* 30 */
- "31", /* 31 */
- "32", /* 32 */
- "access", /* 33 */
- "nice", /* 34 */
- "35", /* 35 */
- "sync", /* 36 */
- "kill", /* 37 */
- "rename", /* 38 */
- "mkdir", /* 39 */
- "rmdir", /* 40 */
- "dup", /* 41 */
- "pipe", /* 42 */
- "times", /* 43 */
- "44", /* 44 */
- "brk", /* 45 */
- "setgid", /* 46 */
- "getgid", /* 47 */
- "signal", /* 48 */
- "geteuid", /* 49 */
- "getegid", /* 50 */
- "acct", /* 51 */
- "umount2", /* 52 */
- "53", /* 53 */
- "ioctl", /* 54 */
- "fcntl", /* 55 */
- "56", /* 56 */
- "setpgid", /* 57 */
- "58", /* 58 */
- "59", /* 59 */
- "umask", /* 60 */
- "chroot", /* 61 */
- "ustat", /* 62 */
- "dup2", /* 63 */
- "getppid", /* 64 */
- "getpgrp", /* 65 */
- "setsid", /* 66 */
- "sigaction", /* 67 */
- "68", /* 68 */
- "69", /* 69 */
- "setreuid", /* 70 */
- "setregid", /* 71 */
- "sigsuspend", /* 72 */
- "sigpending", /* 73 */
- "sethostname", /* 74 */
- "setrlimit", /* 75 */
- "getrlimit", /* 76 */
- "getrusage", /* 77 */
- "gettimeofday", /* 78 */
- "settimeofday", /* 79 */
- "getgroups", /* 80 */
- "setgroups", /* 81 */
- "82", /* 82 */
- "symlink", /* 83 */
- "84", /* 84 */
- "readlink", /* 85 */
- "uselib", /* 86 */
- "swapon", /* 87 */
- "reboot", /* 88 */
- "readdir", /* 89 */
- "mmap", /* 90 */
- "munmap", /* 91 */
- "truncate", /* 92 */
- "ftruncate", /* 93 */
- "fchmod", /* 94 */
- "fchown", /* 95 */
- "getpriority", /* 96 */
- "setpriority", /* 97 */
- "98", /* 98 */
- "statfs", /* 99 */
- "fstatfs", /* 100 */
- "ioperm", /* 101 */
- "socketcall", /* 102 */
- "syslog", /* 103 */
- "setitimer", /* 104 */
- "getitimer", /* 105 */
- "stat", /* 106 */
- "lstat", /* 107 */
- "fstat", /* 108 */
- "109", /* 109 */
- "110", /* 110 */
- "vhangup", /* 111 */
- "idle", /* 112 */
- "113", /* 113 */
- "wait4", /* 114 */
- "swapoff", /* 115 */
- "sysinfo", /* 116 */
- "ipc", /* 117 */
- "fsync", /* 118 */
- "sigreturn", /* 119 */
- "clone", /* 120 */
- "setdomainname", /* 121 */
- "uname", /* 122 */
- "123", /* 123 */
- "adjtimex", /* 124 */
- "mprotect", /* 125 */
- "sigprocmask", /* 126 */
- "create_module", /* 127 */
- "init_module", /* 128 */
- "delete_module", /* 129 */
- "get_kernel_syms", /* 130 */
- "quotactl", /* 131 */
- "getpgid", /* 132 */
- "fchdir", /* 133 */
- "bdflush", /* 134 */
- "sysfs", /* 135 */
- "personality", /* 136 */
- "afs_syscall", /* 137 */
- "setfsuid", /* 138 */
- "setfsgid", /* 139 */
- "_llseek", /* 140 */
- "getdents", /* 141 */
- "_newselect", /* 142 */
- "flock", /* 143 */
- "msync", /* 144 */
- "readv", /* 145 */
- "writev", /* 146 */
- "getsid", /* 147 */
- "fdatasync", /* 148 */
- "_sysctl", /* 149 */
- "mlock", /* 150 */
- "munlock", /* 151 */
- "mlockall", /* 152 */
- "munlockall", /* 153 */
- "sched_setparam", /* 154 */
- "sched_getparam", /* 155 */
- "sched_setscheduler", /* 156 */
- "sched_getscheduler", /* 157 */
- "sched_yield", /* 158 */
- "sched_get_priority_max", /* 159 */
- "sched_get_priority_min", /* 160 */
- "sched_rr_get_interval", /* 161 */
- "nanosleep", /* 162 */
- "mremap", /* 163 */
- "setresuid", /* 164 */
- "getresuid", /* 165 */
- "166", /* 166 */
- "query_module", /* 167 */
- "poll", /* 168 */
- "nfsservctl", /* 169 */
- "setresgid", /* 170 */
- "getresgid", /* 171 */
- "prctl", /* 172 */
- "rt_sigreturn", /* 173 */
- "rt_sigaction", /* 174 */
- "rt_sigprocmask", /* 175 */
- "rt_sigpending", /* 176 */
- "rt_sigtimedwait", /* 177 */
- "rt_sigqueueinfo", /* 178 */
- "rt_sigsuspend", /* 179 */
- "pread", /* 180 */
- "pwrite", /* 181 */
- "chown", /* 182 */
- "getcwd", /* 183 */
- "capget", /* 184 */
- "capset", /* 185 */
- "sigaltstack", /* 186 */
- "sendfile", /* 187 */
- "getpmsg", /* 188 */
- "putpmsg", /* 189 */
- "vfork", /* 190 */
- "ugetrlimit", /* 191 */
- "mmap2", /* 192 */
- "truncate64", /* 193 */
- "ftruncate64", /* 194 */
- "stat64", /* 195 */
- "lstat64", /* 196 */
- "fstat64", /* 197 */
- "lchown32", /* 198 */
- "getuid32", /* 199 */
- "getgid32", /* 200 */
- "geteuid32", /* 201 */
- "getegid32", /* 202 */
- "setreuid32", /* 203 */
- "setregid32", /* 204 */
- "getgroups32", /* 205 */
- "setgroups32", /* 206 */
- "fchown32", /* 207 */
- "setresuid32", /* 208 */
- "getresuid32", /* 209 */
- "setresgid32", /* 210 */
- "getresgid32", /* 211 */
- "chown32", /* 212 */
- "setuid32", /* 213 */
- "setgid32", /* 214 */
- "setfsuid32", /* 215 */
- "setfsgid32", /* 216 */
- "pivot_root", /* 217 */
- "mincore", /* 218 */
- "madvise", /* 219 */
- "getdents64", /* 220 */
- "fcntl64", /* 221 */
- "readahead", /* 222 */
- "sendfile64", /* 223 */
- "setxattr", /* 224 */
- "lsetxattr", /* 225 */
- "fsetxattr", /* 226 */
- "getxattr", /* 227 */
- "lgetxattr", /* 228 */
- "fgetxattr", /* 229 */
- "listxattr", /* 230 */
- "llistxattr", /* 231 */
- "flistxattr", /* 232 */
- "removexattr", /* 233 */
- "lremovexattr", /* 234 */
- "fremovexattr", /* 235 */
- "gettid", /* 236 */
- "tkill", /* 237 */
- "futex", /* 238 */
- "sched_setaffinity", /* 239 */
- "sched_getaffinity", /* 240 */
- "241", /* 241 */
- "242", /* 242 */
- "io_setup", /* 243 */
- "io_destroy", /* 244 */
- "io_getevents", /* 245 */
- "io_submit", /* 246 */
- "io_cancel", /* 247 */
- "exit_group", /* 248 */
- "epoll_create", /* 249 */
- "epoll_ctl", /* 250 */
- "epoll_wait", /* 251 */
- "set_tid_address", /* 252 */
- "fadvise64", /* 253 */
- "timer_create", /* 254 */
- "timer_settime", /* 255 */
- "timer_gettime", /* 256 */
- "timer_getoverrun", /* 257 */
- "timer_delete", /* 258 */
- "clock_settime", /* 259 */
- "clock_gettime", /* 260 */
- "clock_getres", /* 261 */
- "clock_nanosleep", /* 262 */
- "263", /* 263 */
- "fadvise64_64", /* 264 */
- "statfs64", /* 265 */
- "fstatfs64", /* 266 */
- "267", /* 267 */
- "268", /* 268 */
- "269", /* 269 */
- "270", /* 270 */
- "mq_open", /* 271 */
- "mq_unlink", /* 272 */
- "mq_timedsend", /* 273 */
- "mq_timedreceive", /* 274 */
- "mq_notify", /* 275 */
- "mq_getsetattr", /* 276 */
+#ifdef __s390x__
+#include "s390/syscalls64.h"
+#else
+#include "s390/syscalls31.h"
+#endif
diff --git a/sysdeps/linux-gnu/s390/syscallent1.h b/sysdeps/linux-gnu/s390/syscallent1.h
new file mode 100644
index 0000000..c9fdc81
--- /dev/null
+++ b/sysdeps/linux-gnu/s390/syscallent1.h
@@ -0,0 +1 @@
+#include "s390/syscalls31.h"
diff --git a/sysdeps/linux-gnu/s390/syscalls31.h b/sysdeps/linux-gnu/s390/syscalls31.h
new file mode 100644
index 0000000..6f5876b
--- /dev/null
+++ b/sysdeps/linux-gnu/s390/syscalls31.h
@@ -0,0 +1,287 @@
+"0",
+"exit",
+"fork",
+"read",
+"write",
+"open",
+"close",
+"7",
+"creat",
+"link",
+"unlink",
+"execve",
+"chdir",
+"time",
+"mknod",
+"chmod",
+"lchown16",
+"17",
+"18",
+"lseek",
+"getpid",
+"mount",
+"oldumount",
+"setuid16",
+"getuid16",
+"stime",
+"ptrace",
+"alarm",
+"28",
+"pause",
+"utime",
+"31",
+"32",
+"access",
+"nice",
+"35",
+"sync",
+"kill",
+"rename",
+"mkdir",
+"rmdir",
+"dup",
+"pipe",
+"times",
+"44",
+"brk",
+"setgid16",
+"getgid16",
+"signal",
+"geteuid16",
+"getegid16",
+"acct",
+"umount",
+"53",
+"ioctl",
+"fcntl",
+"56",
+"setpgid",
+"58",
+"59",
+"umask",
+"chroot",
+"ustat",
+"dup2",
+"getppid",
+"getpgrp",
+"setsid",
+"sigaction",
+"68",
+"69",
+"setreuid16",
+"setregid16",
+"sigsuspend",
+"sigpending",
+"sethostname",
+"setrlimit",
+"old_getrlimit",
+"getrusage",
+"gettimeofday",
+"settimeofday",
+"getgroups16",
+"setgroups16",
+"82",
+"symlink",
+"84",
+"readlink",
+"uselib",
+"swapon",
+"reboot",
+"89",
+"old_mmap",
+"munmap",
+"truncate",
+"ftruncate",
+"fchmod",
+"fchown16",
+"getpriority",
+"setpriority",
+"98",
+"statfs",
+"fstatfs",
+"101",
+"socketcall",
+"syslog",
+"setitimer",
+"getitimer",
+"newstat",
+"newlstat",
+"newfstat",
+"109",
+"lookup_dcookie",
+"vhangup",
+"112",
+"113",
+"wait4",
+"swapoff",
+"sysinfo",
+"ipc",
+"fsync",
+"sigreturn",
+"clone",
+"setdomainname",
+"newuname",
+"123",
+"adjtimex",
+"mprotect",
+"sigprocmask",
+"127",
+"init_module",
+"delete_module",
+"130",
+"quotactl",
+"getpgid",
+"fchdir",
+"bdflush",
+"sysfs",
+"personality",
+"137",
+"setfsuid16",
+"setfsgid16",
+"llseek",
+"getdents",
+"select",
+"flock",
+"msync",
+"readv",
+"writev",
+"getsid",
+"fdatasync",
+"sysctl",
+"mlock",
+"munlock",
+"mlockall",
+"munlockall",
+"sched_setparam",
+"sched_getparam",
+"sched_setscheduler",
+"sched_getscheduler",
+"sched_yield",
+"sched_get_priority_max",
+"sched_get_priority_min",
+"sched_rr_get_interval",
+"nanosleep",
+"mremap",
+"setresuid16",
+"getresuid16",
+"166",
+"167",
+"poll",
+"nfsservctl",
+"setresgid16",
+"getresgid16",
+"prctl",
+"rt_sigreturn",
+"rt_sigaction",
+"rt_sigprocmask",
+"rt_sigpending",
+"rt_sigtimedwait",
+"rt_sigqueueinfo",
+"rt_sigsuspend",
+"pread64",
+"pwrite64",
+"chown16",
+"getcwd",
+"capget",
+"capset",
+"sigaltstack",
+"sendfile",
+"188",
+"189",
+"vfork",
+"getrlimit",
+"mmap2",
+"truncate64",
+"ftruncate64",
+"stat64",
+"lstat64",
+"fstat64",
+"lchown",
+"getuid",
+"getgid",
+"geteuid",
+"getegid",
+"setreuid",
+"setregid",
+"getgroups",
+"setgroups",
+"fchown",
+"setresuid",
+"getresuid",
+"setresgid",
+"getresgid",
+"chown",
+"setuid",
+"setgid",
+"setfsuid",
+"setfsgid",
+"pivot_root",
+"mincore",
+"madvise",
+"getdents64",
+"fcntl64",
+"readahead",
+"sendfile64",
+"setxattr",
+"lsetxattr",
+"fsetxattr",
+"getxattr",
+"lgetxattr",
+"fgetxattr",
+"listxattr",
+"llistxattr",
+"flistxattr",
+"removexattr",
+"lremovexattr",
+"fremovexattr",
+"gettid",
+"tkill",
+"futex",
+"sched_setaffinity",
+"sched_getaffinity",
+"tgkill",
+"242",
+"io_setup",
+"io_destroy",
+"io_getevents",
+"io_submit",
+"io_cancel",
+"exit_group",
+"epoll_create",
+"epoll_ctl",
+"epoll_wait",
+"set_tid_address",
+"fadvise64",
+"timer_create",
+"timer_settime",
+"timer_gettime",
+"timer_getoverrun",
+"timer_delete",
+"clock_settime",
+"clock_gettime",
+"clock_getres",
+"clock_nanosleep",
+"263",
+"fadvise64_64",
+"statfs64",
+"fstatfs64",
+"remap_file_pages",
+"268",
+"269",
+"270",
+"mq_open",
+"mq_unlink",
+"mq_timedsend",
+"mq_timedreceive",
+"mq_notify",
+"mq_getsetattr",
+"kexec_load",
+"add_key",
+"request_key",
+"keyctl",
+"waitid",
+"ioprio_set",
+"ioprio_get",
+"inotify_init",
+"inotify_add_watch",
+"inotify_rm_watch",
diff --git a/sysdeps/linux-gnu/s390/syscalls64.h b/sysdeps/linux-gnu/s390/syscalls64.h
new file mode 100644
index 0000000..8d48c71
--- /dev/null
+++ b/sysdeps/linux-gnu/s390/syscalls64.h
@@ -0,0 +1,287 @@
+"0",
+"exit",
+"fork",
+"read",
+"write",
+"open",
+"close",
+"7",
+"creat",
+"link",
+"unlink",
+"execve",
+"chdir",
+"13",
+"mknod",
+"chmod",
+"16",
+"17",
+"18",
+"lseek",
+"getpid",
+"mount",
+"oldumount",
+"23",
+"24",
+"25",
+"ptrace",
+"alarm",
+"28",
+"pause",
+"utime",
+"31",
+"32",
+"access",
+"nice",
+"35",
+"sync",
+"kill",
+"rename",
+"mkdir",
+"rmdir",
+"dup",
+"pipe",
+"times",
+"44",
+"brk",
+"46",
+"47",
+"signal",
+"49",
+"50",
+"acct",
+"umount",
+"53",
+"ioctl",
+"fcntl",
+"56",
+"setpgid",
+"58",
+"59",
+"umask",
+"chroot",
+"ustat",
+"dup2",
+"getppid",
+"getpgrp",
+"setsid",
+"sigaction",
+"68",
+"69",
+"70",
+"71",
+"sigsuspend",
+"sigpending",
+"sethostname",
+"setrlimit",
+"getrlimit",
+"getrusage",
+"gettimeofday",
+"settimeofday",
+"80",
+"81",
+"82",
+"symlink",
+"84",
+"readlink",
+"uselib",
+"swapon",
+"reboot",
+"89",
+"old_mmap",
+"munmap",
+"truncate",
+"ftruncate",
+"fchmod",
+"95",
+"getpriority",
+"setpriority",
+"98",
+"statfs",
+"fstatfs",
+"101",
+"socketcall",
+"syslog",
+"setitimer",
+"getitimer",
+"newstat",
+"newlstat",
+"newfstat",
+"109",
+"lookup_dcookie",
+"vhangup",
+"112",
+"113",
+"wait4",
+"swapoff",
+"sysinfo",
+"ipc",
+"fsync",
+"sigreturn",
+"clone",
+"setdomainname",
+"newuname",
+"123",
+"adjtimex",
+"mprotect",
+"sigprocmask",
+"127",
+"init_module",
+"delete_module",
+"130",
+"quotactl",
+"getpgid",
+"fchdir",
+"bdflush",
+"sysfs",
+"personality",
+"137",
+"138",
+"139",
+"llseek",
+"getdents",
+"select",
+"flock",
+"msync",
+"readv",
+"writev",
+"getsid",
+"fdatasync",
+"sysctl",
+"mlock",
+"munlock",
+"mlockall",
+"munlockall",
+"sched_setparam",
+"sched_getparam",
+"sched_setscheduler",
+"sched_getscheduler",
+"sched_yield",
+"sched_get_priority_max",
+"sched_get_priority_min",
+"sched_rr_get_interval",
+"nanosleep",
+"mremap",
+"164",
+"165",
+"166",
+"167",
+"poll",
+"nfsservctl",
+"170",
+"171",
+"prctl",
+"rt_sigreturn",
+"rt_sigaction",
+"rt_sigprocmask",
+"rt_sigpending",
+"rt_sigtimedwait",
+"rt_sigqueueinfo",
+"rt_sigsuspend",
+"pread64",
+"pwrite64",
+"182",
+"getcwd",
+"capget",
+"capset",
+"sigaltstack",
+"sendfile64",
+"188",
+"189",
+"vfork",
+"getrlimit",
+"mmap2",
+"193",
+"194",
+"195",
+"196",
+"197",
+"lchown",
+"getuid",
+"getgid",
+"geteuid",
+"getegid",
+"setreuid",
+"setregid",
+"getgroups",
+"setgroups",
+"fchown",
+"setresuid",
+"getresuid",
+"setresgid",
+"getresgid",
+"chown",
+"setuid",
+"setgid",
+"setfsuid",
+"setfsgid",
+"pivot_root",
+"mincore",
+"madvise",
+"getdents64",
+"221",
+"readahead",
+"223",
+"setxattr",
+"lsetxattr",
+"fsetxattr",
+"getxattr",
+"lgetxattr",
+"fgetxattr",
+"listxattr",
+"llistxattr",
+"flistxattr",
+"removexattr",
+"lremovexattr",
+"fremovexattr",
+"gettid",
+"tkill",
+"futex",
+"sched_setaffinity",
+"sched_getaffinity",
+"tgkill",
+"242",
+"io_setup",
+"io_destroy",
+"io_getevents",
+"io_submit",
+"io_cancel",
+"exit_group",
+"epoll_create",
+"epoll_ctl",
+"epoll_wait",
+"set_tid_address",
+"fadvise64_64",
+"timer_create",
+"timer_settime",
+"timer_gettime",
+"timer_getoverrun",
+"timer_delete",
+"clock_settime",
+"clock_gettime",
+"clock_getres",
+"clock_nanosleep",
+"263",
+"264",
+"statfs64",
+"fstatfs64",
+"remap_file_pages",
+"268",
+"269",
+"270",
+"mq_open",
+"mq_unlink",
+"mq_timedsend",
+"mq_timedreceive",
+"mq_notify",
+"mq_getsetattr",
+"kexec_load",
+"add_key",
+"request_key",
+"keyctl",
+"waitid",
+"ioprio_set",
+"ioprio_get",
+"inotify_init",
+"inotify_add_watch",
+"inotify_rm_watch",
diff --git a/sysdeps/linux-gnu/s390/trace.c b/sysdeps/linux-gnu/s390/trace.c
index 2208555..e0e55a4 100644
--- a/sysdeps/linux-gnu/s390/trace.c
+++ b/sysdeps/linux-gnu/s390/trace.c
@@ -4,14 +4,15 @@
** Other routines are in ../trace.c and need to be combined
** at link time with this code.
**
-** S/390 version
-** Copyright (C) 2001 IBM Poughkeepsie, IBM Corporation
+** Copyright (C) 2001,2005 IBM Corp.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
+#include <errno.h>
+#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
@@ -28,75 +29,165 @@
# define PTRACE_POKEUSER PTRACE_POKEUSR
#endif
-void get_arch_dep(struct process *proc)
-{
+void
+get_arch_dep(struct process * proc) {
+#ifdef __s390x__
+ unsigned long psw;
+
+ if (proc->arch_ptr)
+ return;
+
+ psw = ptrace(PTRACE_PEEKUSER, proc->pid, PT_PSWMASK, 0);
+
+ if ((psw & 0x000000180000000) == 0x000000080000000) {
+ proc->mask_32bit = 1;
+ proc->personality = 1;
+ }
+
+ proc->arch_ptr = (void *) 1;
+#endif
}
/* Returns 1 if syscall, 2 if sysret, 0 otherwise.
*/
-int syscall_p(struct process *proc, int status, int *sysnum)
-{
- long pswa;
- long svcinst;
- long svcno;
- long svcop;
+int
+syscall_p(struct process * proc, int status, int * sysnum) {
+ long pc, opcode, offset_reg, scno, tmp;
+ void *svc_addr;
+ int gpr_offset[16] = {PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3,
+ PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
+ PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
+ PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15};
- if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
+ if (WIFSTOPPED(status) && WSTOPSIG(status)==(SIGTRAP | proc->tracesysgood)) {
- pswa = ptrace(PTRACE_PEEKUSER, proc->pid, PT_PSWADDR, 0);
- svcinst =
- ptrace(PTRACE_PEEKTEXT, proc->pid, (char *)(pswa - 4), 0);
- svcop = (svcinst >> 8) & 0xFF;
- svcno = svcinst & 0xFF;
+ /*
+ * If we have PTRACE_O_TRACESYSGOOD and we have the new style
+ * of passing the system call number to user space via PT_GPR2
+ * then the task is quite easy.
+ */
- *sysnum = svcno;
+ *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR2, 0);
- if (*sysnum == -1) {
- return 0;
- }
- if (svcop == 0 && svcno == 1) {
- /* Breakpoint was hit... */
- return 0;
- }
- if (svcop == 10 && *sysnum >= 0) {
+ if (proc->tracesysgood) {
/* System call was encountered... */
if (proc->callstack_depth > 0 &&
- proc->callstack[proc->callstack_depth -
- 1].is_syscall) {
+ proc->callstack[proc->callstack_depth-1].is_syscall) {
+ /* syscall exit */
+ *sysnum = proc->callstack[proc->callstack_depth-1].c_un.syscall;
return 2;
} else {
- return 1;
+ /* syscall enter */
+ if (*sysnum != -ENOSYS)
+ return 1;
}
- } else {
- /* Unknown trap was encountered... */
+ }
+
+ /*
+ * At least one of the two requirements mentioned above is not
+ * met. Therefore the fun part starts here:
+ * We try to do some instruction decoding without even knowing
+ * the instruction code length of the last instruction executed.
+ * Needs to be done to get the system call number or to decide
+ * if we reached a breakpoint or even checking for a completely
+ * unrelated instruction.
+ * Just a heuristic that most of the time appears to work...
+ */
+
+ pc = ptrace(PTRACE_PEEKUSER, proc->pid, PT_PSWADDR, 0);
+ opcode = ptrace(PTRACE_PEEKTEXT, proc->pid,
+ (char *)(pc-sizeof(long)),0);
+
+ if ((opcode & 0xffff) == 0x0001) {
+ /* Breakpoint */
return 0;
}
+ else if ((opcode & 0xff00) == 0x0a00) {
+ /* SVC opcode */
+ scno = opcode & 0xff;
+ }
+ else if ((opcode & 0xff000000) == 0x44000000) {
+ /* Instruction decoding of EXECUTE... */
+ svc_addr = (void *) (opcode & 0xfff);
+
+ offset_reg = (opcode & 0x000f0000) >> 16;
+ if (offset_reg)
+ svc_addr += ptrace(PTRACE_PEEKUSER, proc->pid,
+ gpr_offset[offset_reg], 0);
+
+ offset_reg = (opcode & 0x0000f000) >> 12;
+ if (offset_reg)
+ svc_addr += ptrace(PTRACE_PEEKUSER, proc->pid,
+ gpr_offset[offset_reg], 0);
+
+ scno = ptrace(PTRACE_PEEKTEXT, proc->pid, svc_addr, 0);
+#ifdef __s390x__
+ scno >>= 48;
+#else
+ scno >>= 16;
+#endif
+ if ((scno & 0xff00) != 0x0a000)
+ return 0;
+
+ tmp = 0;
+ offset_reg = (opcode & 0x00f00000) >> 20;
+ if (offset_reg)
+ tmp = ptrace(PTRACE_PEEKUSER, proc->pid,
+ gpr_offset[offset_reg], 0);
+
+ scno = (scno | tmp) & 0xff;
+ }
+ else {
+ /* No opcode related to syscall handling */
+ return 0;
+ }
+
+ if (scno == 0)
+ scno = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR1, 0);
+
+ *sysnum = scno;
+
+ /* System call was encountered... */
+ if (proc->callstack_depth > 0 &&
+ proc->callstack[proc->callstack_depth-1].is_syscall) {
+ return 2;
+ } else {
+ return 1;
+ }
}
/* Unknown status... */
return 0;
}
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
-{
- switch (arg_num) {
- case -1: /* return value */
- return ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR2, 0);
- case 0:
- return ptrace(PTRACE_PEEKUSER, proc->pid, PT_ORIGGPR2, 0);
- case 1:
- return ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR3, 0);
- case 2:
- return ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR4, 0);
- case 3:
- return ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR5, 0);
- case 4:
- return ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR6, 0);
- default:
- fprintf(stderr, "gimme_arg called with wrong arguments\n");
- exit(2);
+long
+gimme_arg(enum tof type, struct process * proc, int arg_num) {
+ long ret;
+
+ switch(arg_num) {
+ case -1: /* return value */
+ ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR2, 0);
+ break;
+ case 0: ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_ORIGGPR2, 0);
+ break;
+ case 1: ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR3, 0);
+ break;
+ case 2: ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR4, 0);
+ break;
+ case 3: ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR5, 0);
+ break;
+ case 4: ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR6, 0);
+ break;
+ default:
+ fprintf(stderr, "gimme_arg called with wrong arguments\n");
+ exit(2);
}
+#ifdef __s390x__
+ if (proc->mask_32bit)
+ ret &= 0xffffffff;
+#endif
+ return ret;
}
-void save_register_args(enum tof type, struct process *proc)
-{
+void
+save_register_args(enum tof type, struct process * proc) {
}
diff --git a/sysdeps/linux-gnu/sparc/arch.h b/sysdeps/linux-gnu/sparc/arch.h
index d2f85d2..b3d3006 100644
--- a/sysdeps/linux-gnu/sparc/arch.h
+++ b/sysdeps/linux-gnu/sparc/arch.h
@@ -4,4 +4,8 @@
#define LT_ELFCLASS ELFCLASS32
#define LT_ELF_MACHINE EM_SPARC
+#define LT_ELFCLASS2 ELFCLASS32
#define LT_ELF_MACHINE2 EM_SPARC32PLUS
+
+#define PLTs_INIT_BY_HERE NULL
+#define E_ENTRY_NAME "_start"
diff --git a/sysdeps/linux-gnu/sparc/plt.c b/sysdeps/linux-gnu/sparc/plt.c
index 5a2edac..e39bb58 100644
--- a/sysdeps/linux-gnu/sparc/plt.c
+++ b/sysdeps/linux-gnu/sparc/plt.c
@@ -2,7 +2,13 @@
#include "ltrace.h"
#include "elf.h"
-GElf_Addr arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela)
+GElf_Addr
+arch_plt_sym_val (struct ltelf *lte, size_t ndx, GElf_Rela *rela)
{
- return rela->r_offset + 4;
+ return rela->r_offset + 4;
+}
+
+void * plt2addr(struct process *proc, void ** plt)
+{
+ return (void *) plt;
}
diff --git a/sysdeps/linux-gnu/sparc/regs.c b/sysdeps/linux-gnu/sparc/regs.c
index 1f2861a..78efec3 100644
--- a/sysdeps/linux-gnu/sparc/regs.c
+++ b/sysdeps/linux-gnu/sparc/regs.c
@@ -6,32 +6,32 @@
#include "ptrace.h"
#include "ltrace.h"
-void *get_instruction_pointer(struct process *proc)
-{
- proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
+void *
+get_instruction_pointer(struct process * proc) {
+ proc_archdep *a = (proc_archdep *)(proc->arch_ptr);
if (a->valid)
return (void *)a->regs.r_pc;
return (void *)-1;
}
-void set_instruction_pointer(struct process *proc, void *addr)
-{
- proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
+void
+set_instruction_pointer(struct process * proc, void * addr) {
+ proc_archdep *a = (proc_archdep *)(proc->arch_ptr);
if (a->valid)
a->regs.r_pc = (long)addr;
}
-void *get_stack_pointer(struct process *proc)
-{
- proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
+void *
+get_stack_pointer(struct process * proc) {
+ proc_archdep *a = (proc_archdep *)(proc->arch_ptr);
if (a->valid)
return (void *)a->regs.r_o6;
return (void *)-1;
}
-void *get_return_addr(struct process *proc, void *stack_pointer)
-{
- proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
+void *
+get_return_addr(struct process * proc, void * stack_pointer) {
+ proc_archdep *a = (proc_archdep *)(proc->arch_ptr);
unsigned int t;
if (!a->valid)
return (void *)-1;
diff --git a/sysdeps/linux-gnu/sparc/syscallent.h b/sysdeps/linux-gnu/sparc/syscallent.h
index c7ddc4f..3b6f7fe 100644
--- a/sysdeps/linux-gnu/sparc/syscallent.h
+++ b/sysdeps/linux-gnu/sparc/syscallent.h
@@ -149,12 +149,12 @@
"pciconfig_read", /* 148 */
"pciconfig_write", /* 149 */
"getsockname", /* 150 */
- "151", /* 151 */
- "152", /* 152 */
+ "inotify_init", /* 151 */
+ "inotify_add_watch", /* 152 */
"poll", /* 153 */
"getdents64", /* 154 */
"fcntl64", /* 155 */
- "156", /* 156 */
+ "inotify_rm_watch", /* 156 */
"statfs", /* 157 */
"fstatfs", /* 158 */
"umount", /* 159 */
@@ -194,7 +194,7 @@
"epoll_create", /* 193 */
"epoll_ctl", /* 194 */
"epoll_wait", /* 195 */
- "196", /* 196 */
+ "ioprio_set", /* 196 */
"getppid", /* 197 */
"sigaction", /* 198 */
"sgetmask", /* 199 */
@@ -216,7 +216,7 @@
"ipc", /* 215 */
"sigreturn", /* 216 */
"clone", /* 217 */
- "218", /* 218 */
+ "ioprio_get", /* 218 */
"adjtimex", /* 219 */
"sigprocmask", /* 220 */
"create_module", /* 221 */
@@ -278,3 +278,7 @@
"mq_notify", /* 277 */
"mq_getsetattr", /* 278 */
"waitid", /* 279 */
+ "setaltroot", /* 280 */
+ "add_key", /* 281 */
+ "request_key", /* 282 */
+ "keyctl", /* 283 */
diff --git a/sysdeps/linux-gnu/sparc/trace.c b/sysdeps/linux-gnu/sparc/trace.c
index 1f407e5..c39de44 100644
--- a/sysdeps/linux-gnu/sparc/trace.c
+++ b/sysdeps/linux-gnu/sparc/trace.c
@@ -18,8 +18,8 @@ void get_arch_dep(struct process *proc)
proc_archdep *a;
if (!proc->arch_ptr)
proc->arch_ptr = (void *)malloc(sizeof(proc_archdep));
- a = (proc_archdep *) (proc->arch_ptr);
- a->valid = (ptrace(PTRACE_GETREGS, proc->pid, &a->regs, 0) >= 0);
+ a = (proc_archdep *)(proc->arch_ptr);
+ a->valid = (ptrace (PTRACE_GETREGS, proc->pid, &a->regs, 0) >= 0);
}
/* Returns syscall number if `pid' stopped because of a syscall.
@@ -27,19 +27,16 @@ void get_arch_dep(struct process *proc)
*/
int syscall_p(struct process *proc, int status, int *sysnum)
{
- if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
+ if (WIFSTOPPED(status) && WSTOPSIG(status)==(SIGTRAP | proc->tracesysgood)) {
void *ip = get_instruction_pointer(proc);
unsigned int insn;
- if (ip == (void *)-1)
- return 0;
+ if (ip == (void *)-1) return 0;
insn = ptrace(PTRACE_PEEKTEXT, proc->pid, ip, 0);
if ((insn & 0xc1f8007f) == 0x81d00010) {
- *sysnum = ((proc_archdep *) proc->arch_ptr)->regs.r_g1;
- if ((proc->callstack_depth > 0)
- && proc->callstack[proc->callstack_depth -
- 1].is_syscall) {
+ *sysnum = ((proc_archdep *)proc->arch_ptr)->regs.r_g1;
+ if ((proc->callstack_depth > 0) && proc->callstack[proc->callstack_depth-1].is_syscall) {
return 2;
- } else if (*sysnum >= 0) {
+ } else if(*sysnum>=0) {
return 1;
}
}
@@ -47,24 +44,23 @@ int syscall_p(struct process *proc, int status, int *sysnum)
return 0;
}
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
+long gimme_arg(enum tof type, struct process * proc, int arg_num)
{
- proc_archdep *a = (proc_archdep *) proc->arch_ptr;
+ proc_archdep * a = (proc_archdep *)proc->arch_ptr;
if (!a->valid) {
fprintf(stderr, "Could not get child registers\n");
exit(1);
}
- if (arg_num == -1) /* return value */
+ if (arg_num==-1) /* return value */
return a->regs.r_o0;
- if (type == LT_TOF_FUNCTION || type == LT_TOF_SYSCALL || arg_num >= 6) {
+ if (type==LT_TOF_FUNCTION || type==LT_TOF_SYSCALL || arg_num >= 6) {
if (arg_num < 6)
return ((int *)&a->regs.r_o0)[arg_num];
- return ptrace(PTRACE_PEEKTEXT, proc->pid,
- proc->stack_pointer + 64 * (arg_num + 1));
- } else if (type == LT_TOF_FUNCTIONR)
+ return ptrace(PTRACE_PEEKTEXT, proc->pid, proc->stack_pointer+64*(arg_num + 1));
+ } else if (type==LT_TOF_FUNCTIONR)
return a->func_arg[arg_num];
- else if (type == LT_TOF_SYSCALLR)
+ else if (type==LT_TOF_SYSCALLR)
return a->sysc_arg[arg_num];
else {
fprintf(stderr, "gimme_arg called with wrong arguments\n");
@@ -73,9 +69,9 @@ long gimme_arg(enum tof type, struct process *proc, int arg_num)
return 0;
}
-void save_register_args(enum tof type, struct process *proc)
+void save_register_args(enum tof type, struct process * proc)
{
- proc_archdep *a = (proc_archdep *) proc->arch_ptr;
+ proc_archdep * a = (proc_archdep *)proc->arch_ptr;
if (a->valid) {
if (type == LT_TOF_FUNCTION)
memcpy(a->func_arg, &a->regs.r_o0, sizeof(a->func_arg));
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
index bbf40e6..cbcce4d 100644
--- a/sysdeps/linux-gnu/trace.c
+++ b/sysdeps/linux-gnu/trace.c
@@ -9,87 +9,140 @@
#include "ltrace.h"
#include "options.h"
+#include "sysdep.h"
-/* Returns 1 if the sysnum may make a new child to be created
- * (ie, with fork() or clone())
- * Returns 0 otherwise.
- */
-int fork_p(int sysnum)
+static int fork_exec_syscalls[][5] = {
{
- return 0
-#if defined(__NR_fork)
- || (sysnum == __NR_fork)
+#ifdef __NR_fork
+ __NR_fork,
+#else
+ -1,
#endif
-#if defined(__NR_clone)
- || (sysnum == __NR_clone)
+#ifdef __NR_clone
+ __NR_clone,
+#else
+ -1,
#endif
-#if defined(__NR_vfork)
- || (sysnum == __NR_vfork)
+#ifdef __NR_clone2
+ __NR_clone2,
+#else
+ -1,
#endif
-#if defined(__NR_clone2)
- || (sysnum == __NR_clone2)
+#ifdef __NR_vfork
+ __NR_vfork,
+#else
+ -1,
+#endif
+#ifdef __NR_execve
+ __NR_execve,
+#else
+ -1,
#endif
- ;
+}
+#ifdef FORK_EXEC_SYSCALLS
+FORK_EXEC_SYSCALLS
+#endif
+};
+
+/* Returns 1 if the sysnum may make a new child to be created
+ * (ie, with fork() or clone())
+ * Returns 0 otherwise.
+ */
+int
+fork_p(struct process * proc, int sysnum) {
+ int i;
+ if (proc->personality
+ >= sizeof fork_exec_syscalls / sizeof (fork_exec_syscalls [0]))
+ return 0;
+ for (i = 0; i < sizeof (fork_exec_syscalls[0]) / sizeof (int) - 1; ++i)
+ if (sysnum == fork_exec_syscalls[proc->personality][i])
+ return 1;
+ return 0;
}
/* Returns 1 if the sysnum may make the process exec other program
*/
-int exec_p(int sysnum)
-{
- return (sysnum == __NR_execve);
+int
+exec_p(struct process * proc, int sysnum) {
+ int i;
+ if (proc->personality
+ >= sizeof fork_exec_syscalls / sizeof (fork_exec_syscalls [0]))
+ return 0;
+ i = sizeof (fork_exec_syscalls[0]) / sizeof (int) - 1;
+ if (sysnum == fork_exec_syscalls[proc->personality][i])
+ return 1;
+ return 0;
}
-void trace_me(void)
-{
- if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
+void
+trace_me(void) {
+ if (ptrace(PTRACE_TRACEME, 0, 1, 0)<0) {
perror("PTRACE_TRACEME");
exit(1);
}
}
-int trace_pid(pid_t pid)
-{
+int
+trace_pid(pid_t pid) {
if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) {
return -1;
}
return 0;
}
-void untrace_pid(pid_t pid)
-{
+void
+trace_set_options(struct process * proc, pid_t pid) {
+#ifndef PTRACE_SETOPTIONS
+ #define PTRACE_SETOPTIONS 0x4200
+#endif
+#ifndef PTRACE_OLDSETOPTIONS
+ #define PTRACE_OLDSETOPTIONS 21
+#endif
+#ifndef PTRACE_O_TRACESYSGOOD
+ #define PTRACE_O_TRACESYSGOOD 0x00000001
+#endif
+ if (proc->tracesysgood & 0x80)
+ return;
+ if (ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACESYSGOOD) < 0 &&
+ ptrace(PTRACE_OLDSETOPTIONS, pid, 0, PTRACE_O_TRACESYSGOOD) < 0) {
+ perror("PTRACE_SETOPTIONS");
+ return;
+ }
+ proc->tracesysgood |= 0x80;
+}
+
+void
+untrace_pid(pid_t pid) {
ptrace(PTRACE_DETACH, pid, 1, 0);
}
-void continue_after_signal(pid_t pid, int signum)
-{
+void
+continue_after_signal(pid_t pid, int signum) {
/* We should always trace syscalls to be able to control fork(), clone(), execve()... */
ptrace(PTRACE_SYSCALL, pid, 0, signum);
}
-void continue_process(pid_t pid)
-{
+void
+continue_process(pid_t pid) {
continue_after_signal(pid, 0);
}
-void continue_enabling_breakpoint(pid_t pid, struct breakpoint *sbp)
-{
+void
+continue_enabling_breakpoint(pid_t pid, struct breakpoint * sbp) {
enable_breakpoint(pid, sbp);
continue_process(pid);
}
-void continue_after_breakpoint(struct process *proc, struct breakpoint *sbp)
-{
- if (sbp->enabled)
- disable_breakpoint(proc->pid, sbp);
-
+void
+continue_after_breakpoint(struct process *proc, struct breakpoint * sbp) {
+ if (sbp->enabled) disable_breakpoint(proc->pid, sbp);
set_instruction_pointer(proc, sbp->addr);
-
if (sbp->enabled == 0) {
continue_process(proc->pid);
} else {
proc->breakpoint_being_enabled = sbp;
-#ifdef __sparc__ || defined __ia64__
- /* we don't want to single step here */
+#if defined __sparc__ || defined __ia64___
+ /* we don't want to singlestep here */
continue_process(proc->pid);
#else
ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0);
@@ -97,27 +150,24 @@ void continue_after_breakpoint(struct process *proc, struct breakpoint *sbp)
}
}
-int umovestr(struct process *proc, void *addr, int len, void *laddr)
-{
- union {
- long a;
- char c[sizeof(long)];
- } a;
+int
+umovestr(struct process * proc, void * addr, int len, void * laddr) {
+ union { long a; char c[sizeof(long)]; } a;
int i;
- int offset = 0;
+ int offset=0;
- while (offset < len) {
- a.a = ptrace(PTRACE_PEEKTEXT, proc->pid, addr + offset, 0);
- for (i = 0; i < sizeof(long); i++) {
- if (a.c[i] && offset + i < len) {
- *(char *)(laddr + offset + i) = a.c[i];
+ while(offset<len) {
+ a.a = ptrace(PTRACE_PEEKTEXT, proc->pid, addr+offset, 0);
+ for(i=0; i<sizeof(long); i++) {
+ if (a.c[i] && offset+i < len) {
+ *(char *)(laddr+offset+i) = a.c[i];
} else {
- *(char *)(laddr + offset + i) = '\0';
+ *(char *)(laddr+offset+i) = '\0';
return 0;
}
}
offset += sizeof(long);
}
- *(char *)(laddr + offset) = '\0';
+ *(char *)(laddr+offset) = '\0';
return 0;
}
diff --git a/sysdeps/linux-gnu/x86_64/arch.h b/sysdeps/linux-gnu/x86_64/arch.h
index a7c8816..e819d2c 100644
--- a/sysdeps/linux-gnu/x86_64/arch.h
+++ b/sysdeps/linux-gnu/x86_64/arch.h
@@ -4,3 +4,12 @@
#define LT_ELFCLASS ELFCLASS64
#define LT_ELF_MACHINE EM_X86_64
+#define LT_ELFCLASS2 ELFCLASS32
+#define LT_ELF_MACHINE2 EM_386
+
+#define PLTs_INIT_BY_HERE NULL
+#define E_ENTRY_NAME "_start"
+
+/* __NR_fork, __NR_clone, __NR_clone2, __NR_vfork and __NR_execve
+ from asm-i386/unistd.h. */
+#define FORK_EXEC_SYSCALLS , { 2, 120, -1, 190, 11 }
diff --git a/sysdeps/linux-gnu/x86_64/plt.c b/sysdeps/linux-gnu/x86_64/plt.c
index 939bc4e..36d0ecd 100644
--- a/sysdeps/linux-gnu/x86_64/plt.c
+++ b/sysdeps/linux-gnu/x86_64/plt.c
@@ -2,7 +2,13 @@
#include "ltrace.h"
#include "elf.h"
-GElf_Addr arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela)
+GElf_Addr
+arch_plt_sym_val (struct ltelf *lte, size_t ndx, GElf_Rela *rela)
{
- return lte->plt_addr + (ndx + 1) * 16;
+ return lte->plt_addr + (ndx + 1) * 16;
+}
+
+void * plt2addr(struct process *proc, void ** plt)
+{
+ return (void *) plt;
}
diff --git a/sysdeps/linux-gnu/x86_64/regs.c b/sysdeps/linux-gnu/x86_64/regs.c
index a2a27a9..29160b3 100644
--- a/sysdeps/linux-gnu/x86_64/regs.c
+++ b/sysdeps/linux-gnu/x86_64/regs.c
@@ -16,22 +16,34 @@
# define PTRACE_POKEUSER PTRACE_POKEUSR
#endif
-void *get_instruction_pointer(struct process *proc)
-{
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RIP, 0);
+void *
+get_instruction_pointer(struct process * proc) {
+ long int ret = ptrace(PTRACE_PEEKUSER, proc->pid, 8*RIP, 0);
+ if (proc->mask_32bit)
+ ret &= 0xffffffff;
+ return (void *)ret;
}
-void set_instruction_pointer(struct process *proc, void *addr)
-{
- ptrace(PTRACE_POKEUSER, proc->pid, 8 * RIP, addr);
+void
+set_instruction_pointer(struct process * proc, void * addr) {
+ if (proc->mask_32bit)
+ addr = (void *)((long int) addr & 0xffffffff);
+ ptrace(PTRACE_POKEUSER, proc->pid, 8*RIP, addr);
}
-void *get_stack_pointer(struct process *proc)
-{
- return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RSP, 0);
+void *
+get_stack_pointer(struct process * proc) {
+ long int ret = ptrace(PTRACE_PEEKUSER, proc->pid, 8*RSP, 0);
+ if (proc->mask_32bit)
+ ret &= 0xffffffff;
+ return (void *)ret;
}
-void *get_return_addr(struct process *proc, void *stack_pointer)
-{
- return (void *)ptrace(PTRACE_PEEKTEXT, proc->pid, stack_pointer, 0);
+void *
+get_return_addr(struct process * proc, void * stack_pointer) {
+ unsigned long int ret;
+ ret = ptrace(PTRACE_PEEKTEXT, proc->pid, stack_pointer, 0);
+ if (proc->mask_32bit)
+ ret &= 0xffffffff;
+ return (void *)ret;
}
diff --git a/sysdeps/linux-gnu/x86_64/signalent1.h b/sysdeps/linux-gnu/x86_64/signalent1.h
new file mode 100644
index 0000000..5ead946
--- /dev/null
+++ b/sysdeps/linux-gnu/x86_64/signalent1.h
@@ -0,0 +1 @@
+#include "i386/signalent.h"
diff --git a/sysdeps/linux-gnu/x86_64/syscallent.h b/sysdeps/linux-gnu/x86_64/syscallent.h
index 31aa74a..e98f98c 100644
--- a/sysdeps/linux-gnu/x86_64/syscallent.h
+++ b/sysdeps/linux-gnu/x86_64/syscallent.h
@@ -246,3 +246,11 @@
"mq_getsetattr", /* 245 */
"kexec_load", /* 246 */
"waitid", /* 247 */
+ "add_key", /* 248 */
+ "request_key", /* 249 */
+ "keyctl", /* 250 */
+ "ioprio_set", /* 251 */
+ "ioprio_get", /* 252 */
+ "inotify_init", /* 253 */
+ "inotify_add_watch", /* 254 */
+ "inotify_rm_watch", /* 255 */
diff --git a/sysdeps/linux-gnu/x86_64/syscallent1.h b/sysdeps/linux-gnu/x86_64/syscallent1.h
new file mode 100644
index 0000000..d8dd9f7
--- /dev/null
+++ b/sysdeps/linux-gnu/x86_64/syscallent1.h
@@ -0,0 +1 @@
+#include "i386/syscallent.h"
diff --git a/sysdeps/linux-gnu/x86_64/trace.c b/sysdeps/linux-gnu/x86_64/trace.c
index 3232afd..f08583d 100644
--- a/sysdeps/linux-gnu/x86_64/trace.c
+++ b/sysdeps/linux-gnu/x86_64/trace.c
@@ -21,73 +21,93 @@
void get_arch_dep(struct process *proc)
{
+ unsigned long cs;
+ if (proc->arch_ptr)
+ return;
+ cs = ptrace(PTRACE_PEEKUSER, proc->pid, 8*CS, 0);
+ if (cs == 0x23) {
+ proc->mask_32bit = 1;
+ proc->personality = 1;
+ }
+ proc->arch_ptr = (void *) 1;
}
/* Returns 1 if syscall, 2 if sysret, 0 otherwise.
*/
-int syscall_p(struct process *proc, int status, int *sysnum)
-{
- if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
- *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, 8 * ORIG_RAX, 0);
+int
+syscall_p(struct process * proc, int status, int * sysnum) {
+ if (WIFSTOPPED(status) && WSTOPSIG(status)==(SIGTRAP | proc->tracesysgood)) {
+ *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, 8*ORIG_RAX, 0);
if (proc->callstack_depth > 0 &&
- proc->callstack[proc->callstack_depth - 1].is_syscall) {
+ proc->callstack[proc->callstack_depth-1].is_syscall) {
return 2;
}
- if (*sysnum >= 0) {
+ if (*sysnum>=0) {
return 1;
}
}
return 0;
}
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
-{
- if (arg_num == -1) { /* return value */
- return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RAX, 0);
+static unsigned int
+gimme_arg32(enum tof type, struct process * proc, int arg_num) {
+ if (arg_num==-1) { /* return value */
+ return ptrace(PTRACE_PEEKUSER, proc->pid, 8*RAX, 0);
+ }
+
+ if (type==LT_TOF_FUNCTION || type==LT_TOF_FUNCTIONR) {
+ return ptrace(PTRACE_PEEKTEXT, proc->pid, proc->stack_pointer+4*(arg_num+1), 0);
+ } else if (type==LT_TOF_SYSCALL || type==LT_TOF_SYSCALLR) {
+ switch(arg_num) {
+ case 0: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*RBX, 0);
+ case 1: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*RCX, 0);
+ case 2: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*RDX, 0);
+ case 3: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*RSI, 0);
+ case 4: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*RDI, 0);
+ case 5: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*RBP, 0);
+ default:
+ fprintf(stderr, "gimme_arg32 called with wrong arguments\n");
+ exit(2);
+ }
+ }
+ fprintf(stderr, "gimme_arg called with wrong arguments\n");
+ exit(1);
+}
+
+long
+gimme_arg(enum tof type, struct process * proc, int arg_num) {
+ if (proc->mask_32bit)
+ return (unsigned int)gimme_arg32(type, proc, arg_num);
+
+ if (arg_num==-1) { /* return value */
+ return ptrace(PTRACE_PEEKUSER, proc->pid, 8*RAX, 0);
}
- if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) {
- switch (arg_num) {
- case 0:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RDI, 0);
- case 1:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RSI, 0);
- case 2:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RDX, 0);
- case 3:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RCX, 0);
- case 4:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * R8, 0);
- case 5:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * R9, 0);
- default:
- return ptrace(PTRACE_PEEKTEXT, proc->pid,
- proc->stack_pointer + 8 * (arg_num - 6 +
- 1), 0);
- fprintf(stderr,
- "gimme_arg called with wrong arguments\n");
- exit(2);
+ if (type==LT_TOF_FUNCTION || type==LT_TOF_FUNCTIONR) {
+ switch(arg_num) {
+ case 0: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*RDI, 0);
+ case 1: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*RSI, 0);
+ case 2: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*RDX, 0);
+ case 3: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*RCX, 0);
+ case 4: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*R8, 0);
+ case 5: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*R9, 0);
+ default:
+ return ptrace(PTRACE_PEEKTEXT, proc->pid,
+ proc->stack_pointer + 8 * (arg_num - 6 + 1), 0);
}
- } else if (type == LT_TOF_SYSCALL || LT_TOF_SYSCALLR) {
- switch (arg_num) {
- case 0:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RDI, 0);
- case 1:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RSI, 0);
- case 2:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RDX, 0);
- case 3:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * R10, 0);
- case 4:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * R8, 0);
- case 5:
- return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * R9, 0);
- default:
- fprintf(stderr,
- "gimme_arg called with wrong arguments\n");
- exit(2);
+ } else if (type==LT_TOF_SYSCALL || LT_TOF_SYSCALLR) {
+ switch(arg_num) {
+ case 0: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*RDI, 0);
+ case 1: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*RSI, 0);
+ case 2: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*RDX, 0);
+ case 3: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*R10, 0);
+ case 4: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*R8, 0);
+ case 5: return ptrace(PTRACE_PEEKUSER, proc->pid, 8*R9, 0);
+ default:
+ fprintf(stderr, "gimme_arg called with wrong arguments\n");
+ exit(2);
}
} else {
fprintf(stderr, "gimme_arg called with wrong arguments\n");
@@ -97,6 +117,6 @@ long gimme_arg(enum tof type, struct process *proc, int arg_num)
return 0;
}
-void save_register_args(enum tof type, struct process *proc)
+void save_register_args(enum tof type, struct process * proc)
{
}
diff --git a/wait_for_something.c b/wait_for_something.c
index e24ee95..077c08f 100644
--- a/wait_for_something.c
+++ b/wait_for_something.c
@@ -18,10 +18,10 @@ static struct event event;
/* This should also update `current_process' */
-static struct process *pid2proc(int pid);
+static struct process * pid2proc(int pid);
-struct event *wait_for_something(void)
-{
+struct event *
+wait_for_something(void) {
pid_t pid;
int status;
int tmp;
@@ -31,11 +31,11 @@ struct event *wait_for_something(void)
exit(0);
}
pid = wait(&status);
- if (pid == -1) {
- if (errno == ECHILD) {
+ if (pid==-1) {
+ if (errno==ECHILD) {
debug(1, "No more children");
exit(0);
- } else if (errno == EINTR) {
+ } else if (errno==EINTR) {
debug(1, "wait received EINTR ?");
event.thing = LT_EV_NONE;
return &event;
@@ -54,22 +54,20 @@ struct event *wait_for_something(void)
if (event.proc->breakpoints_enabled == -1) {
enable_all_breakpoints(event.proc);
event.thing = LT_EV_NONE;
+ trace_set_options(event.proc, event.proc->pid);
continue_process(event.proc->pid);
return &event;
}
if (opt_i) {
- event.proc->instruction_pointer =
- get_instruction_pointer(event.proc);
+ event.proc->instruction_pointer = get_instruction_pointer(event.proc);
}
- switch (syscall_p(event.proc, status, &tmp)) {
- case 1:
- event.thing = LT_EV_SYSCALL;
- event.e_un.sysnum = tmp;
- return &event;
- case 2:
- event.thing = LT_EV_SYSRET;
- event.e_un.sysnum = tmp;
- return &event;
+ switch(syscall_p(event.proc, status, &tmp)) {
+ case 1: event.thing = LT_EV_SYSCALL;
+ event.e_un.sysnum = tmp;
+ return &event;
+ case 2: event.thing = LT_EV_SYSRET;
+ event.e_un.sysnum = tmp;
+ return &event;
}
if (WIFEXITED(status)) {
event.thing = LT_EV_EXIT;
@@ -85,27 +83,26 @@ struct event *wait_for_something(void)
event.thing = LT_EV_UNKNOWN;
return &event;
}
- if (WSTOPSIG(status) != SIGTRAP) {
+ if ((WSTOPSIG(status) != (SIGTRAP | event.proc->tracesysgood)) &&
+ (WSTOPSIG(status) != SIGTRAP)) {
event.thing = LT_EV_SIGNAL;
event.e_un.signum = WSTOPSIG(status);
return &event;
}
event.thing = LT_EV_BREAKPOINT;
if (!event.proc->instruction_pointer) {
- event.proc->instruction_pointer =
- get_instruction_pointer(event.proc);
+ event.proc->instruction_pointer = get_instruction_pointer(event.proc);
}
- event.e_un.brk_addr =
- event.proc->instruction_pointer - DECR_PC_AFTER_BREAK;
+ event.e_un.brk_addr = event.proc->instruction_pointer - DECR_PC_AFTER_BREAK;
return &event;
}
-static struct process *pid2proc(pid_t pid)
-{
- struct process *tmp;
+static struct process *
+pid2proc(pid_t pid) {
+ struct process * tmp;
tmp = list_of_processes;
- while (tmp) {
+ while(tmp) {
if (pid == tmp->pid) {
return tmp;
}