diff options
author | Anas Nashif <anas.nashif@intel.com> | 2013-01-15 08:32:18 -0800 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2013-01-15 08:32:18 -0800 |
commit | 689b9dbb8d7f88ab91e7741932ed000b6e49be9a (patch) | |
tree | 463f5a1df8b2d35644c260e7bf6c8e0a26198af1 /sysdeps | |
parent | 59749d048d9e452f049f9151735b5256756919c3 (diff) | |
download | ltrace-689b9dbb8d7f88ab91e7741932ed000b6e49be9a.tar.gz ltrace-689b9dbb8d7f88ab91e7741932ed000b6e49be9a.tar.bz2 ltrace-689b9dbb8d7f88ab91e7741932ed000b6e49be9a.zip |
Imported Upstream version 0.7.2upstream/0.7.2
Diffstat (limited to 'sysdeps')
154 files changed, 17748 insertions, 2166 deletions
diff --git a/sysdeps/Makefile.am b/sysdeps/Makefile.am new file mode 100644 index 0000000..36f93c1 --- /dev/null +++ b/sysdeps/Makefile.am @@ -0,0 +1,29 @@ +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + +DIST_SUBDIRS = \ + linux-gnu + +SUBDIRS = \ + $(HOST_OS) + +noinst_HEADERS = \ + sysdep.h + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/sysdeps/Makefile.in b/sysdeps/Makefile.in new file mode 100644 index 0000000..d072917 --- /dev/null +++ b/sysdeps/Makefile.in @@ -0,0 +1,602 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = sysdeps +DIST_COMMON = README $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/m4/libtool.m4 \ + $(top_srcdir)/config/m4/ltoptions.m4 \ + $(top_srcdir)/config/m4/ltsugar.m4 \ + $(top_srcdir)/config/m4/ltversion.m4 \ + $(top_srcdir)/config/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +HEADERS = $(noinst_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_VALGRIND = @HAVE_VALGRIND@ +HOST_CPU = @HOST_CPU@ +HOST_OS = @HOST_OS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libelf_LD_LIBRARY_PATH = @libelf_LD_LIBRARY_PATH@ +liberty_LIBS = @liberty_LIBS@ +libexecdir = @libexecdir@ +libstdcxx_LIBS = @libstdcxx_LIBS@ +libsupcxx_LIBS = @libsupcxx_LIBS@ +libunwind_LD_LIBRARY_PATH = @libunwind_LD_LIBRARY_PATH@ +libunwind_LIBS = @libunwind_LIBS@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +DIST_SUBDIRS = \ + linux-gnu + +SUBDIRS = \ + $(HOST_OS) + +noinst_HEADERS = \ + sysdep.h + +MAINTAINERCLEANFILES = \ + Makefile.in + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign sysdeps/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign sysdeps/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(HEADERS) +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sysdeps/README b/sysdeps/README index ce033ef..db51c9e 100644 --- a/sysdeps/README +++ b/sysdeps/README @@ -7,26 +7,5 @@ first target, and must remove "sysdep.o" in this dir. Files "sysdep.h", "signalent.h" and "syscallent.h" must be present inside the directory after invoking the first target of the Makefile. ------------ -"sysdep.o" must export the following functions: - -Event * next_event(void); -void continue_after_breakpoint(Process * proc, Breakpoint * sbp, int delete_it); -void continue_after_signal(pid_t pid, int signum); -void continue_enabling_breakpoint(pid_t pid, Breakpoint * sbp); -void continue_process(pid_t pid); -void enable_breakpoint(pid_t pid, Breakpoint * sbp); -void disable_breakpoint(pid_t pid, Breakpoint * sbp); -int fork_p(int sysnum); -int exec_p(int sysnum); -int syscall_p(Process * proc, int status, int * sysnum); -void * get_instruction_pointer(pid_t pid); -void * get_stack_pointer(pid_t pid); -void * get_return_addr(pid_t pid, void * stack_pointer); -long gimme_arg(enum tof type, Process * proc, arg_type_info*); -int umovestr(Process * proc, void * addr, int len, void * laddr); -int umovelong(Process * proc, void * addr, long * result); -char * pid2name(pid_t pid); -void trace_me(void); -int trace_pid(pid_t pid); -void untrace_pid(pid_t pid); +See the file "backend.h" for description of backend interfaces, which +have to be provided by "sysdep.o". diff --git a/sysdeps/linux-gnu/Makefile b/sysdeps/linux-gnu/Makefile deleted file mode 100644 index eb1ec60..0000000 --- a/sysdeps/linux-gnu/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -ARCH := $(shell uname -m | sed \ - -e s/i.86/i386/ \ - -e s/sun4u/sparc64/ \ - -e s/sparc64/sparc/ \ - -e s/arm.*/arm/ \ - -e s/sa110/arm/ \ - -e s/ppc64/ppc/ \ - -e s/s390x/s390/ \ - ) - -CPPFLAGS += -I$(TOPDIR)/sysdeps/linux-gnu/$(ARCH) - -OBJ = events.o trace.o proc.o breakpoint.o - -all: sysdep.h signalent.h syscallent.h arch_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 - -arch_syscallent.h: - if [ -f $(ARCH)/arch_syscallent.h ]; then \ - cp $(ARCH)/arch_syscallent.h arch_syscallent.h; \ - else \ - > arch_syscallent.h; \ - fi - -../sysdep.o: os.o $(ARCH)/arch.o - $(CC) -nostdlib -r -o ../sysdep.o os.o $(ARCH)/arch.o - -os.o: $(OBJ) - $(CC) -nostdlib -r -o os.o $(OBJ) - -$(ARCH)/arch.o: dummy - $(MAKE) -C $(ARCH) - -clean: - $(MAKE) -C $(ARCH) clean - rm -f $(OBJ) sysdep.h signalent.h signalent1.h syscallent.h arch_syscallent.h - rm -f syscallent1.h os.o sysdep.o ../sysdep.o - -dummy: diff --git a/sysdeps/linux-gnu/Makefile.am b/sysdeps/linux-gnu/Makefile.am new file mode 100644 index 0000000..bfa67d6 --- /dev/null +++ b/sysdeps/linux-gnu/Makefile.am @@ -0,0 +1,46 @@ +# This file is part of ltrace. +# Copyright (C) 2010,2012 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + +DIST_SUBDIRS = alpha arm cris ia64 m68k mipsel ppc s390 sparc x86 + +SUBDIRS = \ + $(HOST_CPU) + +noinst_LTLIBRARIES = \ + ../libos.la + +___libos_la_SOURCES = \ + events.c \ + trace.c \ + proc.c \ + breakpoint.c + +___libos_la_LIBADD = \ + libcpu.la + +noinst_HEADERS = arch_syscallent.h signalent1.h syscallent1.h trace.h \ + trace-defs.h events.h os.h + +EXTRA_DIST = \ + arch_mksyscallent \ + mksignalent \ + mksyscallent \ + mksyscallent_s390 + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/sysdeps/linux-gnu/Makefile.in b/sysdeps/linux-gnu/Makefile.in new file mode 100644 index 0000000..e00136b --- /dev/null +++ b/sysdeps/linux-gnu/Makefile.in @@ -0,0 +1,692 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# This file is part of ltrace. +# Copyright (C) 2010,2012 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = sysdeps/linux-gnu +DIST_COMMON = README $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/m4/libtool.m4 \ + $(top_srcdir)/config/m4/ltoptions.m4 \ + $(top_srcdir)/config/m4/ltsugar.m4 \ + $(top_srcdir)/config/m4/ltversion.m4 \ + $(top_srcdir)/config/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +___libos_la_DEPENDENCIES = libcpu.la +am____libos_la_OBJECTS = events.lo trace.lo proc.lo breakpoint.lo +___libos_la_OBJECTS = $(am____libos_la_OBJECTS) +am__dirstamp = $(am__leading_dot)dirstamp +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/autoconf/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(___libos_la_SOURCES) +DIST_SOURCES = $(___libos_la_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +HEADERS = $(noinst_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_VALGRIND = @HAVE_VALGRIND@ +HOST_CPU = @HOST_CPU@ +HOST_OS = @HOST_OS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libelf_LD_LIBRARY_PATH = @libelf_LD_LIBRARY_PATH@ +liberty_LIBS = @liberty_LIBS@ +libexecdir = @libexecdir@ +libstdcxx_LIBS = @libstdcxx_LIBS@ +libsupcxx_LIBS = @libsupcxx_LIBS@ +libunwind_LD_LIBRARY_PATH = @libunwind_LD_LIBRARY_PATH@ +libunwind_LIBS = @libunwind_LIBS@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +DIST_SUBDIRS = alpha arm cris ia64 m68k mipsel ppc s390 sparc x86 +SUBDIRS = \ + $(HOST_CPU) + +noinst_LTLIBRARIES = \ + ../libos.la + +___libos_la_SOURCES = \ + events.c \ + trace.c \ + proc.c \ + breakpoint.c + +___libos_la_LIBADD = \ + libcpu.la + +noinst_HEADERS = arch_syscallent.h signalent1.h syscallent1.h trace.h \ + trace-defs.h events.h os.h + +EXTRA_DIST = \ + arch_mksyscallent \ + mksignalent \ + mksyscallent \ + mksyscallent_s390 + +MAINTAINERCLEANFILES = \ + Makefile.in + +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign sysdeps/linux-gnu/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign sysdeps/linux-gnu/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +../$(am__dirstamp): + @$(MKDIR_P) .. + @: > ../$(am__dirstamp) +../libos.la: $(___libos_la_OBJECTS) $(___libos_la_DEPENDENCIES) ../$(am__dirstamp) + $(LINK) $(___libos_la_OBJECTS) $(___libos_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/breakpoint.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/events.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf ../.libs ../_libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f ../$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-recursive + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + clean-noinstLTLIBRARIES ctags ctags-recursive distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sysdeps/linux-gnu/alpha/Makefile b/sysdeps/linux-gnu/alpha/Makefile deleted file mode 100644 index 60d7531..0000000 --- a/sysdeps/linux-gnu/alpha/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -OBJ = trace.o regs.o plt.o - -all: arch.o - -arch.o: $(OBJ) - $(CC) -nostdlib -r -o arch.o $(OBJ) - -clean: - $(RM) $(OBJ) arch.o - diff --git a/sysdeps/linux-gnu/alpha/Makefile.am b/sysdeps/linux-gnu/alpha/Makefile.am new file mode 100644 index 0000000..5c6ecc2 --- /dev/null +++ b/sysdeps/linux-gnu/alpha/Makefile.am @@ -0,0 +1,34 @@ +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ + trace.c + +noinst_HEADERS = \ + arch.h \ + ptrace.h \ + signalent.h \ + syscallent.h + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/sysdeps/linux-gnu/alpha/Makefile.in b/sysdeps/linux-gnu/alpha/Makefile.in new file mode 100644 index 0000000..99a5886 --- /dev/null +++ b/sysdeps/linux-gnu/alpha/Makefile.in @@ -0,0 +1,528 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = sysdeps/linux-gnu/alpha +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/m4/libtool.m4 \ + $(top_srcdir)/config/m4/ltoptions.m4 \ + $(top_srcdir)/config/m4/ltsugar.m4 \ + $(top_srcdir)/config/m4/ltversion.m4 \ + $(top_srcdir)/config/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +___libcpu_la_LIBADD = +am____libcpu_la_OBJECTS = plt.lo regs.lo trace.lo +___libcpu_la_OBJECTS = $(am____libcpu_la_OBJECTS) +am__dirstamp = $(am__leading_dot)dirstamp +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/autoconf/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(___libcpu_la_SOURCES) +DIST_SOURCES = $(___libcpu_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_VALGRIND = @HAVE_VALGRIND@ +HOST_CPU = @HOST_CPU@ +HOST_OS = @HOST_OS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libelf_LD_LIBRARY_PATH = @libelf_LD_LIBRARY_PATH@ +liberty_LIBS = @liberty_LIBS@ +libexecdir = @libexecdir@ +libstdcxx_LIBS = @libstdcxx_LIBS@ +libsupcxx_LIBS = @libsupcxx_LIBS@ +libunwind_LD_LIBRARY_PATH = @libunwind_LD_LIBRARY_PATH@ +libunwind_LIBS = @libunwind_LIBS@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ + trace.c + +noinst_HEADERS = \ + arch.h \ + ptrace.h \ + signalent.h \ + syscallent.h + +MAINTAINERCLEANFILES = \ + Makefile.in + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign sysdeps/linux-gnu/alpha/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign sysdeps/linux-gnu/alpha/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +../$(am__dirstamp): + @$(MKDIR_P) .. + @: > ../$(am__dirstamp) +../libcpu.la: $(___libcpu_la_OBJECTS) $(___libcpu_la_DEPENDENCIES) ../$(am__dirstamp) + $(LINK) $(___libcpu_la_OBJECTS) $(___libcpu_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf ../.libs ../_libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f ../$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sysdeps/linux-gnu/alpha/arch.h b/sysdeps/linux-gnu/alpha/arch.h index 1107b5f..0696621 100644 --- a/sysdeps/linux-gnu/alpha/arch.h +++ b/sysdeps/linux-gnu/alpha/arch.h @@ -1,6 +1,27 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2004 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #define BREAKPOINT_VALUE { 0x80, 0x00, 0x00, 0x00 } #define BREAKPOINT_LENGTH 4 #define DECR_PC_AFTER_BREAK 4 +#define ARCH_ENDIAN_LITTLE #define LT_ELFCLASS ELFCLASS64 #define LT_ELF_MACHINE EM_ALPHA diff --git a/sysdeps/linux-gnu/alpha/plt.c b/sysdeps/linux-gnu/alpha/plt.c index 83337b2..c7ce9fe 100644 --- a/sysdeps/linux-gnu/alpha/plt.c +++ b/sysdeps/linux-gnu/alpha/plt.c @@ -1,4 +1,25 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2004,2008,2009 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include <gelf.h> +#include "proc.h" #include "common.h" GElf_Addr diff --git a/sysdeps/linux-gnu/alpha/ptrace.h b/sysdeps/linux-gnu/alpha/ptrace.h index c3cbcb6..ad7e0d6 100644 --- a/sysdeps/linux-gnu/alpha/ptrace.h +++ b/sysdeps/linux-gnu/alpha/ptrace.h @@ -1 +1,21 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2004 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include <sys/ptrace.h> diff --git a/sysdeps/linux-gnu/alpha/regs.c b/sysdeps/linux-gnu/alpha/regs.c index 9554e48..0b46afd 100644 --- a/sysdeps/linux-gnu/alpha/regs.c +++ b/sysdeps/linux-gnu/alpha/regs.c @@ -1,9 +1,30 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2004,2008,2009 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "config.h" #include <sys/types.h> #include <sys/ptrace.h> #include <asm/ptrace.h> +#include "proc.h" #include "common.h" #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) diff --git a/sysdeps/linux-gnu/alpha/signalent.h b/sysdeps/linux-gnu/alpha/signalent.h index c2a6170..e9588fa 100644 --- a/sysdeps/linux-gnu/alpha/signalent.h +++ b/sysdeps/linux-gnu/alpha/signalent.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + "SIG_0", /* 0 */ "SIGHUP", /* 1 */ "SIGINT", /* 2 */ diff --git a/sysdeps/linux-gnu/alpha/syscallent.h b/sysdeps/linux-gnu/alpha/syscallent.h index 7cacc8c..9a24315 100644 --- a/sysdeps/linux-gnu/alpha/syscallent.h +++ b/sysdeps/linux-gnu/alpha/syscallent.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + "osf_syscall", /* 0, not implemented */ "exit", /* 1 */ "fork", /* 2 */ diff --git a/sysdeps/linux-gnu/alpha/trace.c b/sysdeps/linux-gnu/alpha/trace.c index e4d4063..a7c5e59 100644 --- a/sysdeps/linux-gnu/alpha/trace.c +++ b/sysdeps/linux-gnu/alpha/trace.c @@ -1,3 +1,24 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2004,2008,2009 Juan Cespedes + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "config.h" #include <sys/types.h> @@ -6,6 +27,7 @@ #include <sys/ptrace.h> #include <asm/ptrace.h> +#include "proc.h" #include "common.h" #include "debug.h" @@ -47,7 +69,8 @@ syscall_p(Process *proc, int status, int *sysnum) { } long -gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { +gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info) +{ if (arg_num == -1) { /* return value */ return ptrace(PTRACE_PEEKUSER, proc->pid, 0 /* REG_R0 */ , 0); } @@ -69,7 +92,3 @@ gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { } return 0; } - -void -save_register_args(enum tof type, Process *proc) { -} diff --git a/sysdeps/linux-gnu/arch_mksyscallent b/sysdeps/linux-gnu/arch_mksyscallent index 853d62d..ce79e26 100644 --- a/sysdeps/linux-gnu/arch_mksyscallent +++ b/sysdeps/linux-gnu/arch_mksyscallent @@ -1,4 +1,21 @@ #!/usr/bin/awk -f +# This file is part of ltrace. +# Copyright (C) 2008 Juan Cespedes +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA # hack expression to generate arch_syscallent.h from <asm/unistd.h> # It reads from stdin and writes to stdout diff --git a/sysdeps/linux-gnu/arch_syscallent.h b/sysdeps/linux-gnu/arch_syscallent.h new file mode 100644 index 0000000..74d8e19 --- /dev/null +++ b/sysdeps/linux-gnu/arch_syscallent.h @@ -0,0 +1 @@ +/* This file is intentionally left blank */ diff --git a/sysdeps/linux-gnu/arm/Makefile b/sysdeps/linux-gnu/arm/Makefile deleted file mode 100644 index f55ba48..0000000 --- a/sysdeps/linux-gnu/arm/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -OBJ = trace.o regs.o plt.o breakpoint.o - -all: arch.o - -arch.o: $(OBJ) arch.h - $(CC) -nostdlib -r -o arch.o $(OBJ) - -clean: - $(RM) $(OBJ) arch.o - diff --git a/sysdeps/linux-gnu/arm/Makefile.am b/sysdeps/linux-gnu/arm/Makefile.am new file mode 100644 index 0000000..385424c --- /dev/null +++ b/sysdeps/linux-gnu/arm/Makefile.am @@ -0,0 +1,36 @@ +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + breakpoint.c \ + plt.c \ + regs.c \ + trace.c + +noinst_HEADERS = \ + arch.h \ + arch_syscallent.h \ + ptrace.h \ + signalent.h \ + syscallent.h + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/sysdeps/linux-gnu/arm/Makefile.in b/sysdeps/linux-gnu/arm/Makefile.in new file mode 100644 index 0000000..ad6475d --- /dev/null +++ b/sysdeps/linux-gnu/arm/Makefile.in @@ -0,0 +1,531 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = sysdeps/linux-gnu/arm +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/m4/libtool.m4 \ + $(top_srcdir)/config/m4/ltoptions.m4 \ + $(top_srcdir)/config/m4/ltsugar.m4 \ + $(top_srcdir)/config/m4/ltversion.m4 \ + $(top_srcdir)/config/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +___libcpu_la_LIBADD = +am____libcpu_la_OBJECTS = breakpoint.lo plt.lo regs.lo trace.lo +___libcpu_la_OBJECTS = $(am____libcpu_la_OBJECTS) +am__dirstamp = $(am__leading_dot)dirstamp +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/autoconf/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(___libcpu_la_SOURCES) +DIST_SOURCES = $(___libcpu_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_VALGRIND = @HAVE_VALGRIND@ +HOST_CPU = @HOST_CPU@ +HOST_OS = @HOST_OS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libelf_LD_LIBRARY_PATH = @libelf_LD_LIBRARY_PATH@ +liberty_LIBS = @liberty_LIBS@ +libexecdir = @libexecdir@ +libstdcxx_LIBS = @libstdcxx_LIBS@ +libsupcxx_LIBS = @libsupcxx_LIBS@ +libunwind_LD_LIBRARY_PATH = @libunwind_LD_LIBRARY_PATH@ +libunwind_LIBS = @libunwind_LIBS@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + breakpoint.c \ + plt.c \ + regs.c \ + trace.c + +noinst_HEADERS = \ + arch.h \ + arch_syscallent.h \ + ptrace.h \ + signalent.h \ + syscallent.h + +MAINTAINERCLEANFILES = \ + Makefile.in + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign sysdeps/linux-gnu/arm/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign sysdeps/linux-gnu/arm/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +../$(am__dirstamp): + @$(MKDIR_P) .. + @: > ../$(am__dirstamp) +../libcpu.la: $(___libcpu_la_OBJECTS) $(___libcpu_la_DEPENDENCIES) ../$(am__dirstamp) + $(LINK) $(___libcpu_la_OBJECTS) $(___libcpu_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/breakpoint.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf ../.libs ../_libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f ../$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sysdeps/linux-gnu/arm/arch.h b/sysdeps/linux-gnu/arm/arch.h index 8f2dfb3..291443a 100644 --- a/sysdeps/linux-gnu/arm/arch.h +++ b/sysdeps/linux-gnu/arm/arch.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 1998,2004,2008 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #define ARCH_HAVE_ENABLE_BREAKPOINT 1 #define ARCH_HAVE_DISABLE_BREAKPOINT 1 @@ -6,6 +26,12 @@ #define THUMB_BREAKPOINT_VALUE { 0x01, 0xde } #define THUMB_BREAKPOINT_LENGTH 2 #define DECR_PC_AFTER_BREAK 0 +#define ARCH_ENDIAN_LITTLE #define LT_ELFCLASS ELFCLASS32 #define LT_ELF_MACHINE EM_ARM + +#define ARCH_HAVE_BREAKPOINT_DATA +struct arch_breakpoint_data { + int thumb_mode; +}; diff --git a/sysdeps/linux-gnu/arm/arch_syscallent.h b/sysdeps/linux-gnu/arm/arch_syscallent.h index ce1e844..f5bb295 100644 --- a/sysdeps/linux-gnu/arm/arch_syscallent.h +++ b/sysdeps/linux-gnu/arm/arch_syscallent.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2008 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + "0", /* 0 */ "breakpoint", /* 1 */ "cacheflush", /* 2 */ diff --git a/sysdeps/linux-gnu/arm/breakpoint.c b/sysdeps/linux-gnu/arm/breakpoint.c index 4c20260..5748401 100644 --- a/sysdeps/linux-gnu/arm/breakpoint.c +++ b/sysdeps/linux-gnu/arm/breakpoint.c @@ -23,14 +23,16 @@ */ #include <sys/ptrace.h> +#include <sys/types.h> + #include "config.h" -#include "arch.h" -#include "options.h" -#include "output.h" +#include "breakpoint.h" #include "debug.h" +#include "proc.h" void -arch_enable_breakpoint(pid_t pid, Breakpoint *sbp) { +arch_enable_breakpoint(pid_t pid, struct breakpoint *sbp) +{ unsigned int i, j; const unsigned char break_insn[] = BREAKPOINT_VALUE; const unsigned char thumb_break_insn[] = THUMB_BREAKPOINT_VALUE; @@ -38,40 +40,79 @@ arch_enable_breakpoint(pid_t pid, Breakpoint *sbp) { debug(1, "arch_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); - unsigned char *bytes = (unsigned char *)&a; + union _ { long l; unsigned char b[SIZEOF_LONG]; }; + union _ orig, current; + unsigned char *bytes = current.b; + for (j = 0; j < sizeof(long); j++) { + orig.b[j] = sbp->orig_value[i * sizeof(long) + j]; + } + current.l = ptrace(PTRACE_PEEKTEXT, pid, sbp->addr + i * sizeof(long), 0); - debug(2, "current = 0x%lx, orig_value = 0x%lx, thumb_mode = %d", a, *(long *)&sbp->orig_value, sbp->thumb_mode); + debug(2, "current = 0x%lx, orig_value = 0x%lx, thumb_mode = %d", + current.l, orig.l, sbp->arch.thumb_mode); for (j = 0; j < sizeof(long) && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) { sbp->orig_value[i * sizeof(long) + j] = bytes[j]; - if (!sbp->thumb_mode) { + if (!sbp->arch.thumb_mode) { bytes[j] = break_insn[i * sizeof(long) + j]; } else if (j < THUMB_BREAKPOINT_LENGTH) { bytes[j] = thumb_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), + (void *)current.l); } } void -arch_disable_breakpoint(pid_t pid, const Breakpoint *sbp) { +arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp) +{ unsigned int i, j; - const unsigned char break_insn[] = BREAKPOINT_VALUE; - const unsigned char thumb_break_insn[] = THUMB_BREAKPOINT_VALUE; debug(1, "arch_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); - unsigned char *bytes = (unsigned char *)&a; + union _ { long l; unsigned char b[SIZEOF_LONG]; }; + union _ orig, current; + unsigned char *bytes = current.b; + for (j = 0; j < sizeof(long); j++) { + orig.b[j] = sbp->orig_value[i * sizeof(long) + j]; + } + current.l = ptrace(PTRACE_PEEKTEXT, pid, sbp->addr + i * sizeof(long), 0); - debug(2, "current = 0x%lx, orig_value = 0x%lx, thumb_mode = %d", a, *(long *)&sbp->orig_value, sbp->thumb_mode); + debug(2, "current = 0x%lx, orig_value = 0x%lx, thumb_mode = %d", + current.l, orig.l, sbp->arch.thumb_mode); for (j = 0; j < sizeof(long) && i * sizeof(long) + j < BREAKPOINT_LENGTH; 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), + (void *)current.l); } } + +int +arch_breakpoint_init(struct Process *proc, struct breakpoint *sbp) +{ + /* XXX That uintptr_t cast is there temporarily until + * arch_addr_t becomes integral type. */ + int thumb_mode = ((uintptr_t)sbp->addr) & 1; + if (thumb_mode) + sbp->addr = (void *)((uintptr_t)sbp->addr & ~1); + sbp->arch.thumb_mode = thumb_mode | proc->thumb_mode; + /* XXX This doesn't seem like it belongs here. */ + proc->thumb_mode = 0; + return 0; +} + +void +arch_breakpoint_destroy(struct breakpoint *sbp) +{ +} + +int +arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp) +{ + retp->arch.thumb_mode = sbp->arch.thumb_mode; + return 0; +} diff --git a/sysdeps/linux-gnu/arm/plt.c b/sysdeps/linux-gnu/arm/plt.c index bd92a63..1b97705 100644 --- a/sysdeps/linux-gnu/arm/plt.c +++ b/sysdeps/linux-gnu/arm/plt.c @@ -1,9 +1,45 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2010 Zach Welch, CodeSourcery + * Copyright (C) 2004,2008,2009 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include <gelf.h> -#include "common.h" + +#include "proc.h" +#include "library.h" +#include "ltrace-elf.h" + +static int +arch_plt_entry_has_stub(struct ltelf *lte, size_t off) { + uint16_t op = *(uint16_t *)((char *)lte->relplt->d_buf + off); + return op == 0x4778; +} GElf_Addr arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { - return lte->plt_addr + 20 + ndx * 12; + size_t start = lte->relplt->d_size + 12; + size_t off = start + 20, i; + for (i = 0; i < ndx; i++) + off += arch_plt_entry_has_stub(lte, off) ? 16 : 12; + if (arch_plt_entry_has_stub(lte, off)) + off += 4; + return lte->plt_addr + off - start; } void * diff --git a/sysdeps/linux-gnu/arm/ptrace.h b/sysdeps/linux-gnu/arm/ptrace.h index 52215bc..41106d8 100644 --- a/sysdeps/linux-gnu/arm/ptrace.h +++ b/sysdeps/linux-gnu/arm/ptrace.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2004,2008 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include <sys/ptrace.h> #include <asm/ptrace.h> diff --git a/sysdeps/linux-gnu/arm/regs.c b/sysdeps/linux-gnu/arm/regs.c index 2488b0a..484de7f 100644 --- a/sysdeps/linux-gnu/arm/regs.c +++ b/sysdeps/linux-gnu/arm/regs.c @@ -1,9 +1,31 @@ +/* + * This file is part of ltrace. + * Copyright (C) 1998,2002,2004,2008,2009 Juan Cespedes + * Copyright (C) 2009 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "config.h" #include <sys/types.h> #include <sys/ptrace.h> #include <asm/ptrace.h> +#include "proc.h" #include "common.h" #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) @@ -14,9 +36,9 @@ # define PTRACE_POKEUSER PTRACE_POKEUSR #endif -#define off_pc 60 -#define off_lr 56 -#define off_sp 52 +#define off_pc ((void *)60) +#define off_lr ((void *)56) +#define off_sp ((void *)52) void * get_instruction_pointer(Process *proc) { @@ -39,13 +61,20 @@ void * get_return_addr(Process *proc, void *stack_pointer) { long addr = ptrace(PTRACE_PEEKUSER, proc->pid, off_lr, 0); + /* Remember & unset the thumb mode bit. XXX This is really a + * bit of a hack, as we assume that the following + * insert_breakpoint call will be related to this address. + * This interface should really be get_return_breakpoint, or + * maybe install_return_breakpoint. */ proc->thumb_mode = addr & 1; if (proc->thumb_mode) addr &= ~1; + return (void *)addr; } void set_return_addr(Process *proc, void *addr) { - ptrace(PTRACE_POKEUSER, proc->pid, off_lr, addr); + long iaddr = (int)addr | proc->thumb_mode; + ptrace(PTRACE_POKEUSER, proc->pid, off_lr, (void *)iaddr); } diff --git a/sysdeps/linux-gnu/arm/signalent.h b/sysdeps/linux-gnu/arm/signalent.h index 0afb004..4c28c9d 100644 --- a/sysdeps/linux-gnu/arm/signalent.h +++ b/sysdeps/linux-gnu/arm/signalent.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + "SIG_0", /* 0 */ "SIGHUP", /* 1 */ "SIGINT", /* 2 */ diff --git a/sysdeps/linux-gnu/arm/syscallent.h b/sysdeps/linux-gnu/arm/syscallent.h index 4113234..3b9bcfd 100644 --- a/sysdeps/linux-gnu/arm/syscallent.h +++ b/sysdeps/linux-gnu/arm/syscallent.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + "restart_syscall", /* 0 */ "exit", /* 1 */ "fork", /* 2 */ diff --git a/sysdeps/linux-gnu/arm/trace.c b/sysdeps/linux-gnu/arm/trace.c index 10f7cc4..c528cfb 100644 --- a/sysdeps/linux-gnu/arm/trace.c +++ b/sysdeps/linux-gnu/arm/trace.c @@ -1,3 +1,25 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * Copyright (C) 1998,2004,2008,2009 Juan Cespedes + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "config.h" #include <string.h> @@ -7,6 +29,7 @@ #include <sys/ptrace.h> #include <asm/ptrace.h> +#include "proc.h" #include "common.h" #include "output.h" #include "ptrace.h" @@ -19,10 +42,10 @@ # define PTRACE_POKEUSER PTRACE_POKEUSR #endif -#define off_r0 0 -#define off_r7 28 -#define off_ip 48 -#define off_pc 60 +#define off_r0 ((void *)0) +#define off_r7 ((void *)28) +#define off_ip ((void *)48) +#define off_pc ((void *)60) void get_arch_dep(Process *proc) { @@ -44,12 +67,15 @@ syscall_p(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); + unsigned pc = ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0); + pc = pc - 4; /* fetch the SWI instruction */ - int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 4, 0); + unsigned insn = ptrace(PTRACE_PEEKTEXT, proc->pid, + (void *)pc, 0); int ip = ptrace(PTRACE_PEEKUSER, proc->pid, off_ip, 0); - if (insn == 0xef000000 || insn == 0x0f000000) { + if (insn == 0xef000000 || insn == 0x0f000000 + || (insn & 0xffff0000) == 0xdf000000) { /* EABI syscall */ *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, off_r7, 0); } else if ((insn & 0xfff00000) == 0xef900000) { @@ -61,8 +87,9 @@ syscall_p(Process *proc, int status, int *sysnum) { * are coming from a signal handler, so the current * PC does not point to the instruction just after the * "swi" one. */ - output_line(proc, "unexpected instruction 0x%x at %p", insn, pc - 4); - return -1; + output_line(proc, "unexpected instruction 0x%x at %p", + insn, pc); + return 0; } if ((*sysnum & 0xf0000) == 0xf0000) { /* arch-specific syscall */ @@ -77,7 +104,8 @@ syscall_p(Process *proc, int status, int *sysnum) { } long -gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { +gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info) +{ proc_archdep *a = (proc_archdep *) proc->arch_ptr; if (arg_num == -1) { /* return value */ @@ -91,8 +119,8 @@ gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { return a->regs.uregs[arg_num]; if (a->valid && type == LT_TOF_FUNCTIONR) return a->func_arg[arg_num]; - return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, - 0); + return ptrace(PTRACE_PEEKUSER, proc->pid, + (void *)(4 * arg_num), 0); } else { return ptrace(PTRACE_PEEKDATA, proc->pid, proc->stack_pointer + 4 * (arg_num - 4), @@ -104,8 +132,8 @@ gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { return a->regs.uregs[arg_num]; if (a->valid && type == LT_TOF_SYSCALLR) return a->sysc_arg[arg_num]; - return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, - 0); + return ptrace(PTRACE_PEEKUSER, proc->pid, + (void *)(4 * arg_num), 0); } else { return ptrace(PTRACE_PEEKDATA, proc->pid, proc->stack_pointer + 4 * (arg_num - 5), @@ -118,14 +146,3 @@ gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { return 0; } - -void -save_register_args(enum tof type, Process *proc) { - proc_archdep *a = (proc_archdep *) proc->arch_ptr; - if (a->valid) { - if (type == LT_TOF_FUNCTION) - memcpy(a->func_arg, a->regs.uregs, sizeof(a->func_arg)); - else - memcpy(a->sysc_arg, a->regs.uregs, sizeof(a->sysc_arg)); - } -} diff --git a/sysdeps/linux-gnu/breakpoint.c b/sysdeps/linux-gnu/breakpoint.c index 5ca131a..fe336b1 100644 --- a/sysdeps/linux-gnu/breakpoint.c +++ b/sysdeps/linux-gnu/breakpoint.c @@ -1,39 +1,62 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2011 Petr Machata, Red Hat Inc. + * Copyright (C) 2006 Ian Wienand + * Copyright (C) 2002,2008,2009 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "config.h" #include <sys/ptrace.h> +#include <errno.h> #include <string.h> +#include <stdio.h> #include "common.h" -#include "arch.h" - -static unsigned char break_insn[] = BREAKPOINT_VALUE; +#include "backend.h" +#include "sysdep.h" +#include "breakpoint.h" +#include "proc.h" +#include "library.h" #ifdef ARCH_HAVE_ENABLE_BREAKPOINT -extern void arch_enable_breakpoint(pid_t, Breakpoint *); -void -enable_breakpoint(pid_t pid, Breakpoint *sbp) { - if (sbp->libsym) { - debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p, symbol=%s", pid, sbp->addr, sbp->libsym->name); - } else { - debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p", pid, sbp->addr); - } - arch_enable_breakpoint(pid, sbp); -} -#else +extern void arch_enable_breakpoint(pid_t, struct breakpoint *); +#else /* ARCH_HAVE_ENABLE_BREAKPOINT */ void -enable_breakpoint(pid_t pid, Breakpoint *sbp) { +arch_enable_breakpoint(pid_t pid, struct breakpoint *sbp) +{ + static unsigned char break_insn[] = BREAKPOINT_VALUE; unsigned int i, j; - if (sbp->libsym) { - debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p, symbol=%s", pid, sbp->addr, sbp->libsym->name); - } else { - debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p", pid, sbp->addr); - } + debug(DEBUG_PROCESS, + "arch_enable_breakpoint: pid=%d, addr=%p, symbol=%s", + pid, sbp->addr, breakpoint_name(sbp)); for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) { - long a = - ptrace(PTRACE_PEEKTEXT, pid, sbp->addr + i * sizeof(long), - 0); + long a = ptrace(PTRACE_PEEKTEXT, pid, + sbp->addr + i * sizeof(long), 0); + if (a == -1 && errno) { + fprintf(stderr, "enable_breakpoint" + " pid=%d, addr=%p, symbol=%s: %s\n", + pid, sbp->addr, breakpoint_name(sbp), + strerror(errno)); + return; + } for (j = 0; j < sizeof(long) && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) { @@ -42,37 +65,48 @@ enable_breakpoint(pid_t pid, Breakpoint *sbp) { 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); + a = ptrace(PTRACE_POKETEXT, pid, + sbp->addr + i * sizeof(long), a); + if (a == -1) { + fprintf(stderr, "enable_breakpoint" + " pid=%d, addr=%p, symbol=%s: %s\n", + pid, sbp->addr, breakpoint_name(sbp), + strerror(errno)); + return; + } } } #endif /* ARCH_HAVE_ENABLE_BREAKPOINT */ -#ifdef ARCH_HAVE_DISABLE_BREAKPOINT -extern void arch_disable_breakpoint(pid_t, const Breakpoint *sbp); void -disable_breakpoint(pid_t pid, const Breakpoint *sbp) { - if (sbp->libsym) { - debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p, symbol=%s", pid, sbp->addr, sbp->libsym->name); - } else { - debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p", pid, sbp->addr); - } - arch_disable_breakpoint(pid, sbp); +enable_breakpoint(Process *proc, struct breakpoint *sbp) +{ + debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p, symbol=%s", + proc->pid, sbp->addr, breakpoint_name(sbp)); + arch_enable_breakpoint(proc->pid, sbp); } -#else + +#ifdef ARCH_HAVE_DISABLE_BREAKPOINT +extern void arch_disable_breakpoint(pid_t, const struct breakpoint *sbp); +#else /* ARCH_HAVE_DISABLE_BREAKPOINT */ void -disable_breakpoint(pid_t pid, const Breakpoint *sbp) { +arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp) +{ unsigned int i, j; - if (sbp->libsym) { - debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p, symbol=%s", pid, sbp->addr, sbp->libsym->name); - } else { - debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p", pid, sbp->addr); - } + debug(DEBUG_PROCESS, + "arch_disable_breakpoint: pid=%d, addr=%p, symbol=%s", + pid, sbp->addr, breakpoint_name(sbp)); for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) { - long a = - ptrace(PTRACE_PEEKTEXT, pid, sbp->addr + i * sizeof(long), - 0); + long a = ptrace(PTRACE_PEEKTEXT, pid, + sbp->addr + i * sizeof(long), 0); + if (a == -1 && errno) { + fprintf(stderr, + "disable_breakpoint pid=%d, addr=%p: %s\n", + pid, sbp->addr, strerror(errno)); + return; + } for (j = 0; j < sizeof(long) && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) { @@ -80,7 +114,22 @@ disable_breakpoint(pid_t pid, const Breakpoint *sbp) { bytes[j] = sbp->orig_value[i * sizeof(long) + j]; } - ptrace(PTRACE_POKETEXT, pid, sbp->addr + i * sizeof(long), a); + a = ptrace(PTRACE_POKETEXT, pid, + sbp->addr + i * sizeof(long), a); + if (a == -1 && errno) { + fprintf(stderr, + "disable_breakpoint pid=%d, addr=%p: %s\n", + pid, sbp->addr, strerror(errno)); + return; + } } } #endif /* ARCH_HAVE_DISABLE_BREAKPOINT */ + +void +disable_breakpoint(Process *proc, struct breakpoint *sbp) +{ + debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p, symbol=%s", + proc->pid, sbp->addr, breakpoint_name(sbp)); + arch_disable_breakpoint(proc->pid, sbp); +} diff --git a/sysdeps/linux-gnu/cris/Makefile.am b/sysdeps/linux-gnu/cris/Makefile.am new file mode 100644 index 0000000..30cb0fd --- /dev/null +++ b/sysdeps/linux-gnu/cris/Makefile.am @@ -0,0 +1,34 @@ +# This file is part of ltrace. +# Copyright (C) 2012 Edgar E. Iglesias, Axis Communications +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ + trace.c + +noinst_HEADERS = \ + arch.h \ + ptrace.h \ + signalent.h \ + syscallent.h + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/sysdeps/linux-gnu/cris/Makefile.in b/sysdeps/linux-gnu/cris/Makefile.in new file mode 100644 index 0000000..c978410 --- /dev/null +++ b/sysdeps/linux-gnu/cris/Makefile.in @@ -0,0 +1,528 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# This file is part of ltrace. +# Copyright (C) 2012 Edgar E. Iglesias, Axis Communications +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = sysdeps/linux-gnu/cris +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/m4/libtool.m4 \ + $(top_srcdir)/config/m4/ltoptions.m4 \ + $(top_srcdir)/config/m4/ltsugar.m4 \ + $(top_srcdir)/config/m4/ltversion.m4 \ + $(top_srcdir)/config/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +___libcpu_la_LIBADD = +am____libcpu_la_OBJECTS = plt.lo regs.lo trace.lo +___libcpu_la_OBJECTS = $(am____libcpu_la_OBJECTS) +am__dirstamp = $(am__leading_dot)dirstamp +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/autoconf/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(___libcpu_la_SOURCES) +DIST_SOURCES = $(___libcpu_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_VALGRIND = @HAVE_VALGRIND@ +HOST_CPU = @HOST_CPU@ +HOST_OS = @HOST_OS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libelf_LD_LIBRARY_PATH = @libelf_LD_LIBRARY_PATH@ +liberty_LIBS = @liberty_LIBS@ +libexecdir = @libexecdir@ +libstdcxx_LIBS = @libstdcxx_LIBS@ +libsupcxx_LIBS = @libsupcxx_LIBS@ +libunwind_LD_LIBRARY_PATH = @libunwind_LD_LIBRARY_PATH@ +libunwind_LIBS = @libunwind_LIBS@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ + trace.c + +noinst_HEADERS = \ + arch.h \ + ptrace.h \ + signalent.h \ + syscallent.h + +MAINTAINERCLEANFILES = \ + Makefile.in + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign sysdeps/linux-gnu/cris/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign sysdeps/linux-gnu/cris/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +../$(am__dirstamp): + @$(MKDIR_P) .. + @: > ../$(am__dirstamp) +../libcpu.la: $(___libcpu_la_OBJECTS) $(___libcpu_la_DEPENDENCIES) ../$(am__dirstamp) + $(LINK) $(___libcpu_la_OBJECTS) $(___libcpu_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf ../.libs ../_libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f ../$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sysdeps/linux-gnu/cris/arch.h b/sysdeps/linux-gnu/cris/arch.h new file mode 100644 index 0000000..099dc3f --- /dev/null +++ b/sysdeps/linux-gnu/cris/arch.h @@ -0,0 +1,27 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2010 Edgar E. Iglesias + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#define BREAKPOINT_VALUE { 0x38, 0xe9 } +#define BREAKPOINT_LENGTH 2 +#define DECR_PC_AFTER_BREAK 0 +#define ARCH_ENDIAN_LITTLE + +#define LT_ELFCLASS ELFCLASS32 +#define LT_ELF_MACHINE EM_CRIS diff --git a/sysdeps/linux-gnu/cris/plt.c b/sysdeps/linux-gnu/cris/plt.c new file mode 100644 index 0000000..427ae93 --- /dev/null +++ b/sysdeps/linux-gnu/cris/plt.c @@ -0,0 +1,34 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2010 Edgar E. Iglesias + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include <gelf.h> +#include "proc.h" +#include "common.h" +#include "library.h" + +GElf_Addr arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) +{ + return lte->plt_addr + 0x20 + (ndx * 26); +} + +void *sym2addr(Process *proc, struct library_symbol *sym) +{ + return sym->enter_addr; +} diff --git a/sysdeps/linux-gnu/cris/ptrace.h b/sysdeps/linux-gnu/cris/ptrace.h new file mode 100644 index 0000000..8f04f16 --- /dev/null +++ b/sysdeps/linux-gnu/cris/ptrace.h @@ -0,0 +1,21 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2010 Edgar E. Iglesias + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include <sys/ptrace.h> diff --git a/sysdeps/linux-gnu/cris/regs.c b/sysdeps/linux-gnu/cris/regs.c new file mode 100644 index 0000000..7028b9e --- /dev/null +++ b/sysdeps/linux-gnu/cris/regs.c @@ -0,0 +1,58 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2010 Edgar E. Iglesias + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/ptrace.h> +#include <asm/ptrace.h> + +#include "proc.h" +#include "common.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +void *get_instruction_pointer(Process *proc) +{ + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_PPC, 0); +} + +void set_instruction_pointer(Process *proc, void *addr) +{ + ptrace(PTRACE_POKEUSER, proc->pid, 4 * PT_PPC, addr); +} + +void *get_stack_pointer(Process *proc) +{ + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_USP, 0); +} + +void *get_return_addr(Process *proc, void *stack_pointer) +{ + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_SRP, 0); +} diff --git a/sysdeps/linux-gnu/cris/signalent.h b/sysdeps/linux-gnu/cris/signalent.h new file mode 100644 index 0000000..71cedbe --- /dev/null +++ b/sysdeps/linux-gnu/cris/signalent.h @@ -0,0 +1,52 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2010 Edgar E. Iglesias + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + + "SIG_0", /* 0 */ + "SIGHUP", /* 1 */ + "SIGINT", /* 2 */ + "SIGQUIT", /* 3 */ + "SIGILL", /* 4 */ + "SIGTRAP", /* 5 */ + "SIGABRT", /* 6 */ + "SIGBUS", /* 7 */ + "SIGFPE", /* 8 */ + "SIGKILL", /* 9 */ + "SIGUSR1", /* 10 */ + "SIGSEGV", /* 11 */ + "SIGUSR2", /* 12 */ + "SIGPIPE", /* 13 */ + "SIGALRM", /* 14 */ + "SIGTERM", /* 15 */ + "SIGSTKFLT", /* 16 */ + "SIGCHLD", /* 17 */ + "SIGCONT", /* 18 */ + "SIGSTOP", /* 19 */ + "SIGTSTP", /* 20 */ + "SIGTTIN", /* 21 */ + "SIGTTOU", /* 22 */ + "SIGURG", /* 23 */ + "SIGXCPU", /* 24 */ + "SIGXFSZ", /* 25 */ + "SIGVTALRM", /* 26 */ + "SIGPROF", /* 27 */ + "SIGWINCH", /* 28 */ + "SIGIO", /* 29 */ + "SIGPWR", /* 30 */ + "SIGSYS", /* 31 */ diff --git a/sysdeps/linux-gnu/cris/syscallent.h b/sysdeps/linux-gnu/cris/syscallent.h new file mode 100644 index 0000000..7a7d1ca --- /dev/null +++ b/sysdeps/linux-gnu/cris/syscallent.h @@ -0,0 +1,345 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2010 Edgar E. Iglesias + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +"0", /* 0 */ + "exit", +"fork", +"read", +"write", +"open", +"close", +"waitpid", +"creat", +"link", +"unlink", +"execve", +"chdir", +"time", +"mknod", +"chmod", +"lchown", +"break", +"oldstat", +"lseek", +"getpid", +"mount", +"umount", +"setuid", +"getuid", +"stime", +"ptrace", +"alarm", +"oldfstat", +"pause", +"utime", +"stty", +"gtty", +"access", +"nice", +"ftime", +"sync", +"kill", +"rename", +"mkdir", +"rmdir", +"dup", +"pipe", +"times", +"prof", +"brk", +"setgid", +"getgid", +"signal", +"geteuid", +"getegid", +"acct", +"umount2", +"lock", +"ioctl", +"fcntl", +"mpx", +"setpgid", +"ulimit", +"oldolduname", +"umask", +"chroot", +"ustat", +"dup2", +"getppid", +"getpgrp", +"setsid", +"sigaction", +"sgetmask", +"ssetmask", +"setreuid", +"setregid", +"sigsuspend", +"sigpending", +"sethostname", +"setrlimit", +"getrlimit", +"getrusage", +"gettimeofday", +"settimeofday", +"getgroups", +"setgroups", +"select", +"symlink", +"oldlstat", +"readlink", +"uselib", +"swapon", +"reboot", +"readdir", +"mmap", +"munmap", +"truncate", +"ftruncate", +"fchmod", +"fchown", +"getpriority", +"setpriority", +"profil", +"statfs", +"fstatfs", +"ioperm", +"socketcall", +"syslog", +"setitimer", +"getitimer", +"stat", +"lstat", +"fstat", +"olduname", +"iopl", +"vhangup", +"idle", +"vm86", +"wait4", +"swapoff", +"sysinfo", +"ipc", +"fsync", +"sigreturn", +"clone", +"setdomainname", +"uname", +"modify_ldt", +"adjtimex", +"mprotect", +"sigprocmask", +"create_module", +"init_module", +"delete_module", +"get_kernel_syms", +"quotactl", +"getpgid", +"fchdir", +"bdflush", +"sysfs", +"personality", +"afs_syscall", +"setfsuid", +"setfsgid", +"_llseek", +"getdents", +"_newselect", +"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", +"setresuid", +"getresuid", +"invalid", +"query_module", +"poll", +"nfsservctl", +"setresgid", +"getresgid", +"prctl", +"rt_sigreturn", +"rt_sigaction", +"rt_sigprocmask", +"rt_sigpending", +"rt_sigtimedwait", +"rt_sigqueueinfo", +"rt_sigsuspend", +"pread64", +"pwrite64", +"chown", +"getcwd", +"capget", +"capset", +"sigaltstack", +"sendfile", +"getpmsg", +"putpmsg", +"vfork", +"ugetrlimit", +"mmap2", +"truncate64", +"ftruncate64", +"stat64", +"lstat64", +"fstat64", +"lchown32", +"getuid32", +"getgid32", +"geteuid32", +"getegid32", +"setreuid32", +"setregid32", +"getgroups32", +"setgroups32", +"fchown32", +"setresuid32", +"getresuid32", +"setresgid32", +"getresgid32", +"chown32", +"setuid32", +"setgid32", +"setfsuid32", +"setfsgid32", +"pivot_root", +"mincore", +"madvise", +"getdents64", +"fcntl64", +"invalid", +"invalid", +"gettid", +"readahead", +"setxattr", +"lsetxattr", +"fsetxattr", +"getxattr", +"lgetxattr", +"fgetxattr", +"listxattr", +"llistxattr", +"flistxattr", +"removexattr", +"lremovexattr", +"fremovexattr", +"tkill", +"sendfile64", +"futex", +"sched_setaffinity", +"sched_getaffinity", +"set_thread_area", +"get_thread_area", +"io_setup", +"io_destroy", +"io_getevents", +"io_submit", +"io_cancel", +"fadvise64", +"invalid", +"exit_group", +"lookup_dcookie", +"epoll_create", +"epoll_ctl", +"epoll_wait", +"remap_file_pages", +"set_tid_address", +"timer_create", +"timer_settime", +"timer_gettime", +"timer_getoverrun", +"timer_delete", +"clock_settime", +"clock_gettime", +"clock_getres", +"clock_nanosleep", +"statfs64", +"fstatfs64", +"tgkill", +"utimes", +"fadvise64_64", +"vserver", +"mbind", +"get_mempolicy", +"set_mempolicy", +"mq_open", +"mq_unlink", +"mq_timedsend", +"mq_timedreceive", +"mq_notify", +"mq_getsetattr", +"kexec_load", +"waitid", +"invalid", +"add_key", +"request_key", +"keyctl", +"ioprio_set", +"ioprio_get", +"inotify_init", +"inotify_add_watch", +"inotify_rm_watch", +"migrate_pages", +"openat", +"mkdirat", +"mknodat", +"fchownat", +"futimesat", +"fstatat64", +"unlinkat", +"renameat", +"linkat", +"symlinkat", +"readlinkat", +"fchmodat", +"faccessat", +"pselect6", +"ppoll", +"unshare", +"set_robust_list", +"get_robust_list", +"splice", +"sync_file_range", +"tee", +"vmsplice", +"move_pages", +"getcpu", +"epoll_pwait", +"utimensat", +"signalfd", +"timerfd", +"eventfd", +"fallocate", diff --git a/sysdeps/linux-gnu/cris/trace.c b/sysdeps/linux-gnu/cris/trace.c new file mode 100644 index 0000000..98cb7d8 --- /dev/null +++ b/sysdeps/linux-gnu/cris/trace.c @@ -0,0 +1,93 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2010 Edgar E. Iglesias + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#include <sys/ptrace.h> +#include <asm/ptrace.h> +#include <elf.h> + +#include "proc.h" +#include "common.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +void get_arch_dep(Process *proc) +{ +} + +/* Returns 1 if syscall, 2 if sysret, 0 otherwise. + */ +#define SYSCALL_INSN 0xe93d +int syscall_p(Process *proc, int status, int *sysnum) +{ + if (WIFSTOPPED(status) + && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { + long pc = (long)get_instruction_pointer(proc); + unsigned int insn = + (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(long), + 0); + + if ((insn >> 16) == SYSCALL_INSN) { + *sysnum = + (int)ptrace(PTRACE_PEEKUSER, proc->pid, + sizeof(long) * PT_R9, 0); + if (proc->callstack_depth > 0 + && proc->callstack[proc->callstack_depth - + 1].is_syscall) { + return 2; + } + return 1; + } + } + return 0; +} + +long gimme_arg(enum tof type, Process *proc, int arg_num, + struct arg_type_info *info) +{ + int pid = proc->pid; + + if (arg_num == -1) { /* return value */ + return ptrace(PTRACE_PEEKUSER, pid, PT_R10 * 4, 0); + } else if (arg_num < 6) { + int pt_arg[6] = + { + PT_ORIG_R10, PT_R11, PT_R12, PT_R13, PT_MOF, + PT_SRP + }; + return ptrace(PTRACE_PEEKUSER, pid, pt_arg[arg_num] * 4, 0); + } else { + return ptrace(PTRACE_PEEKDATA, pid, + proc->stack_pointer + 4 * (arg_num - 6), 0); + } + return 0; +} diff --git a/sysdeps/linux-gnu/events.c b/sysdeps/linux-gnu/events.c index a1e2a14..077a656 100644 --- a/sysdeps/linux-gnu/events.c +++ b/sysdeps/linux-gnu/events.c @@ -1,31 +1,163 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2007,2011,2012 Petr Machata, Red Hat Inc. + * Copyright (C) 1998,2001,2004,2007,2008,2009 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "config.h" #define _GNU_SOURCE 1 -#include <stdlib.h> +#include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> +#include <assert.h> #include <errno.h> #include <signal.h> +#include <stdio.h> +#include <stdlib.h> #include <string.h> -#include <sys/ptrace.h> +#include <unistd.h> -#include "common.h" +#include "backend.h" +#include "breakpoint.h" +#include "debug.h" +#include "events.h" +#include "proc.h" +#include "linux-gnu/trace-defs.h" static Event event; +/* A queue of events that we missed while enabling the + * breakpoint in one of tasks. */ +static Event * delayed_events = NULL; +static Event * end_delayed_events = NULL; + +static enum callback_status +first (Process * proc, void * data) +{ + return CBS_STOP; +} + +void +enque_event(Event * event) +{ + debug(DEBUG_FUNCTION, "%d: queuing event %d for later", + event->proc->pid, event->type); + Event * ne = malloc(sizeof(*ne)); + if (ne == NULL) { + fprintf(stderr, "event will be missed: %s\n", strerror(errno)); + return; + } + + *ne = *event; + ne->next = NULL; + if (end_delayed_events == NULL) { + assert(delayed_events == NULL); + end_delayed_events = delayed_events = ne; + } + else { + assert(delayed_events != NULL); + end_delayed_events = end_delayed_events->next = ne; + } +} + Event * -next_event(void) { +each_qd_event(enum ecb_status (*pred)(Event *, void *), void * data) +{ + Event * prev = delayed_events; + Event * event; + for (event = prev; event != NULL; ) { + switch ((*pred)(event, data)) { + case ecb_cont: + prev = event; + event = event->next; + continue; + + case ecb_deque: + debug(DEBUG_FUNCTION, "dequeuing event %d for %d", + event->type, + event->proc != NULL ? event->proc->pid : -1); + /* + printf("dequeuing event %d for %d\n", event->type, + event->proc != NULL ? event->proc->pid : -1) ; + */ + if (end_delayed_events == event) + end_delayed_events = prev; + if (delayed_events == event) + delayed_events = event->next; + else + prev->next = event->next; + if (delayed_events == NULL) + end_delayed_events = NULL; + /* fall-through */ + + case ecb_yield: + return event; + } + } + + return NULL; +} + +static enum ecb_status +event_process_not_reenabling(Event * event, void * data) +{ + if (event->proc == NULL + || event->proc->leader == NULL + || event->proc->leader->event_handler == NULL) + return ecb_deque; + else + return ecb_cont; +} + +static Event * +next_qd_event(void) +{ + return each_qd_event(&event_process_not_reenabling, NULL); +} + +int linux_in_waitpid = 0; + +Event * +next_event(void) +{ pid_t pid; int status; int tmp; int stop_signal; debug(DEBUG_FUNCTION, "next_event()"); - if (!list_of_processes) { + Event * ev; + if ((ev = next_qd_event()) != NULL) { + event = *ev; + free(ev); + return &event; + } + + if (!each_process(NULL, &first, NULL)) { debug(DEBUG_EVENT, "event: No more traced programs: exiting"); exit(0); } + + linux_in_waitpid = 1; pid = waitpid(-1, &status, __WALL); + linux_in_waitpid = 0; + if (pid == -1) { if (errno == ECHILD) { debug(DEBUG_EVENT, "event: No more traced programs: exiting"); @@ -40,26 +172,84 @@ next_event(void) { } event.proc = pid2proc(pid); if (!event.proc || event.proc->state == STATE_BEING_CREATED) { + /* Work around (presumably) a bug on some kernels, + * where we are seeing a waitpid event even though the + * process is still reported to be running. Wait for + * the tracing stop to propagate. But don't get stuck + * here forever. + * + * We need the process in T, because there's a lot of + * ptracing going on all over the place, and these + * calls fail when the process is not in T. + * + * N.B. This was observed on RHEL 5 Itanium, but I'm + * turning this on globally, to save some poor soul + * down the road (which could well be me a year from + * now) the pain of figuring this out all over again. + * Petr Machata 2011-11-22. */ + int i = 0; + for (; i < 100 && process_status(pid) != ps_tracing_stop; ++i) { + debug(2, "waiting for %d to stop", pid); + usleep(10000); + } event.type = EVENT_NEW; event.e_un.newpid = pid; debug(DEBUG_EVENT, "event: NEW: pid=%d", pid); return &event; } get_arch_dep(event.proc); - event.proc->instruction_pointer = NULL; debug(3, "event from pid %u", pid); - if (event.proc->breakpoints_enabled == -1) { - enable_all_breakpoints(event.proc); - event.type = EVENT_NONE; - trace_set_options(event.proc, event.proc->pid); - continue_process(event.proc->pid); - debug(DEBUG_EVENT, "event: NONE: pid=%d (enabling breakpoints)", pid); + Process *leader = event.proc->leader; + + /* The process should be stopped after the waitpid call. But + * when the whole thread group is terminated, we see + * individual tasks spontaneously transitioning from 't' to + * 'R' and 'Z'. Calls to ptrace fail and /proc/pid/status may + * not even be available anymore, so we can't check in + * advance. So we just drop the error checking around ptrace + * calls. We check for termination ex post when it fails, + * suppress the event, and let the event loop collect the + * termination in the next iteration. */ +#define CHECK_PROCESS_TERMINATED \ + do { \ + int errno_save = errno; \ + switch (process_stopped(pid)) \ + case 0: \ + case -1: { \ + debug(DEBUG_EVENT, \ + "process not stopped, is it terminating?"); \ + event.type = EVENT_NONE; \ + continue_process(event.proc->pid); \ + return &event; \ + } \ + errno = errno_save; \ + } while (0) + + event.proc->instruction_pointer = (void *)(uintptr_t)-1; + + /* Check for task termination now, before we have a need to + * call CHECK_PROCESS_TERMINATED later. That would suppress + * the event that we are processing. */ + if (WIFSIGNALED(status)) { + event.type = EVENT_EXIT_SIGNAL; + event.e_un.signum = WTERMSIG(status); + debug(DEBUG_EVENT, "event: EXIT_SIGNAL: pid=%d, signum=%d", pid, event.e_un.signum); return &event; } - if (opt_i) { - event.proc->instruction_pointer = - get_instruction_pointer(event.proc); + if (WIFEXITED(status)) { + event.type = EVENT_EXIT; + event.e_un.ret_val = WEXITSTATUS(status); + debug(DEBUG_EVENT, "event: EXIT: pid=%d, status=%d", pid, event.e_un.ret_val); + return &event; } + + event.proc->instruction_pointer = get_instruction_pointer(event.proc); + if (event.proc->instruction_pointer == (void *)(uintptr_t)-1) { + CHECK_PROCESS_TERMINATED; + if (errno != 0) + perror("get_instruction_pointer"); + } + switch (syscall_p(event.proc, status, &tmp)) { case 1: event.type = EVENT_SYSCALL; @@ -82,36 +272,30 @@ next_event(void) { debug(DEBUG_EVENT, "event: ARCH_SYSRET: pid=%d, sysnum=%d", pid, tmp); return &event; case -1: - event.type = EVENT_NONE; - continue_process(event.proc->pid); - debug(DEBUG_EVENT, "event: NONE: pid=%d (syscall_p returned -1)", pid); - return &event; + CHECK_PROCESS_TERMINATED; + if (errno != 0) + perror("syscall_p"); } - if (WIFSTOPPED(status) && ((status>>16 == PTRACE_EVENT_FORK) || (status>>16 == PTRACE_EVENT_VFORK) || (status>>16 == PTRACE_EVENT_CLONE))) { - unsigned long data; - ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data); - event.type = EVENT_CLONE; - event.e_un.newpid = data; - debug(DEBUG_EVENT, "event: CLONE: pid=%d, newpid=%d", pid, (int)data); - return &event; + if (WIFSTOPPED(status)) { + int what = status >> 16; + if (what == PTRACE_EVENT_VFORK + || what == PTRACE_EVENT_FORK + || what == PTRACE_EVENT_CLONE) { + unsigned long data; + event.type = what == PTRACE_EVENT_VFORK + ? EVENT_VFORK : EVENT_CLONE; + ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data); + event.e_un.newpid = data; + debug(DEBUG_EVENT, "event: CLONE: pid=%d, newpid=%d", + pid, (int)data); + return &event; + } } if (WIFSTOPPED(status) && (status>>16 == PTRACE_EVENT_EXEC)) { event.type = EVENT_EXEC; debug(DEBUG_EVENT, "event: EXEC: pid=%d", pid); return &event; } - if (WIFEXITED(status)) { - event.type = EVENT_EXIT; - event.e_un.ret_val = WEXITSTATUS(status); - debug(DEBUG_EVENT, "event: EXIT: pid=%d, status=%d", pid, event.e_un.ret_val); - return &event; - } - if (WIFSIGNALED(status)) { - event.type = EVENT_EXIT_SIGNAL; - event.e_un.signum = WTERMSIG(status); - debug(DEBUG_EVENT, "event: EXIT_SIGNAL: pid=%d, signum=%d", pid, event.e_un.signum); - return &event; - } if (!WIFSTOPPED(status)) { /* should never happen */ event.type = EVENT_NONE; @@ -122,22 +306,19 @@ next_event(void) { stop_signal = WSTOPSIG(status); /* On some targets, breakpoints are signalled not using - SIGTRAP, but also with SIGILL, SIGSEGV or SIGEMT. Check - for these. (TODO: is this true?) */ - if (stop_signal == SIGSEGV - || stop_signal == SIGILL -#ifdef SIGEMT - || stop_signal == SIGEMT -#endif - ) { - if (!event.proc->instruction_pointer) { - event.proc->instruction_pointer = - get_instruction_pointer(event.proc); - } + SIGTRAP, but also with SIGILL, SIGSEGV or SIGEMT. SIGEMT + is not defined on Linux, but check for the others. - if (address2bpstruct(event.proc, event.proc->instruction_pointer)) + N.B. see comments in GDB's infrun.c for details. I've + actually seen this on an Itanium machine on RHEL 5, I don't + remember the exact kernel version anymore. ia64-sigill.s + in the test suite tests this. Petr Machata 2011-06-08. */ + void * break_address + = event.proc->instruction_pointer - DECR_PC_AFTER_BREAK; + if ((stop_signal == SIGSEGV || stop_signal == SIGILL) + && leader != NULL + && address2bpstruct(leader, break_address)) stop_signal = SIGTRAP; - } if (stop_signal != (SIGTRAP | event.proc->tracesysgood) && stop_signal != SIGTRAP) { @@ -150,12 +331,25 @@ next_event(void) { /* last case [by exhaustion] */ event.type = EVENT_BREAKPOINT; - if (!event.proc->instruction_pointer) { - 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 = break_address; debug(DEBUG_EVENT, "event: BREAKPOINT: pid=%d, addr=%p", pid, event.e_un.brk_addr); + return &event; } + +static enum ecb_status +event_for_proc(struct Event *event, void *data) +{ + if (event->proc == data) + return ecb_deque; + else + return ecb_cont; +} + +void +delete_events_for(struct Process *proc) +{ + struct Event *event; + while ((event = each_qd_event(&event_for_proc, proc)) != NULL) + free(event); +} diff --git a/sysdeps/linux-gnu/events.h b/sysdeps/linux-gnu/events.h new file mode 100644 index 0000000..3802aff --- /dev/null +++ b/sysdeps/linux-gnu/events.h @@ -0,0 +1,41 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef SYSDEPS_LINUX_GNU_EVENTS_H +#define SYSDEPS_LINUX_GNU_EVENTS_H + +#include "forward.h" + +/* Declarations for event que functions. */ + +enum ecb_status { + ecb_cont, /* The iteration should continue. */ + ecb_yield, /* The iteration should stop, yielding this + * event. */ + ecb_deque, /* Like ecb_stop, but the event should be removed + * from the queue. */ +}; + +struct Event *each_qd_event(enum ecb_status (*cb)(struct Event *event, + void *data), void *data); +void delete_events_for(struct Process * proc); +void enque_event(struct Event *event); + +#endif /* SYSDEPS_LINUX_GNU_EVENTS_H */ diff --git a/sysdeps/linux-gnu/i386/Makefile b/sysdeps/linux-gnu/i386/Makefile deleted file mode 100644 index 60d7531..0000000 --- a/sysdeps/linux-gnu/i386/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -OBJ = trace.o regs.o plt.o - -all: arch.o - -arch.o: $(OBJ) - $(CC) -nostdlib -r -o arch.o $(OBJ) - -clean: - $(RM) $(OBJ) arch.o - diff --git a/sysdeps/linux-gnu/i386/arch.h b/sysdeps/linux-gnu/i386/arch.h deleted file mode 100644 index dc7383f..0000000 --- a/sysdeps/linux-gnu/i386/arch.h +++ /dev/null @@ -1,6 +0,0 @@ -#define BREAKPOINT_VALUE {0xcc} -#define BREAKPOINT_LENGTH 1 -#define DECR_PC_AFTER_BREAK 1 - -#define LT_ELFCLASS ELFCLASS32 -#define LT_ELF_MACHINE EM_386 diff --git a/sysdeps/linux-gnu/i386/plt.c b/sysdeps/linux-gnu/i386/plt.c deleted file mode 100644 index b53ff44..0000000 --- a/sysdeps/linux-gnu/i386/plt.c +++ /dev/null @@ -1,12 +0,0 @@ -#include <gelf.h> -#include "common.h" - -GElf_Addr -arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { - return lte->plt_addr + (ndx + 1) * 16; -} - -void * -sym2addr(Process *proc, struct library_symbol *sym) { - return sym->enter_addr; -} diff --git a/sysdeps/linux-gnu/i386/ptrace.h b/sysdeps/linux-gnu/i386/ptrace.h deleted file mode 100644 index c3cbcb6..0000000 --- a/sysdeps/linux-gnu/i386/ptrace.h +++ /dev/null @@ -1 +0,0 @@ -#include <sys/ptrace.h> diff --git a/sysdeps/linux-gnu/i386/regs.c b/sysdeps/linux-gnu/i386/regs.c deleted file mode 100644 index 6777f17..0000000 --- a/sysdeps/linux-gnu/i386/regs.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "config.h" - -#include <sys/types.h> -#include <sys/ptrace.h> -#include <asm/ptrace.h> - -#include "common.h" - -#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) -# define PTRACE_PEEKUSER PTRACE_PEEKUSR -#endif - -#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) -# define PTRACE_POKEUSER PTRACE_POKEUSR -#endif - -void * -get_instruction_pointer(Process *proc) { - return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * EIP, 0); -} - -void -set_instruction_pointer(Process *proc, void *addr) { - ptrace(PTRACE_POKEUSER, proc->pid, 4 * EIP, (long)addr); -} - -void * -get_stack_pointer(Process *proc) { - return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * UESP, 0); -} - -void * -get_return_addr(Process *proc, void *stack_pointer) { - return (void *)ptrace(PTRACE_PEEKTEXT, proc->pid, stack_pointer, 0); -} - -void -set_return_addr(Process *proc, void *addr) { - ptrace(PTRACE_POKETEXT, proc->pid, proc->stack_pointer, (long)addr); -} diff --git a/sysdeps/linux-gnu/i386/syscallent.h b/sysdeps/linux-gnu/i386/syscallent.h deleted file mode 100644 index 8f4c887..0000000 --- a/sysdeps/linux-gnu/i386/syscallent.h +++ /dev/null @@ -1,317 +0,0 @@ - "restart_syscall", /* 0 */ - "exit", /* 1 */ - "fork", /* 2 */ - "read", /* 3 */ - "write", /* 4 */ - "open", /* 5 */ - "close", /* 6 */ - "waitpid", /* 7 */ - "creat", /* 8 */ - "link", /* 9 */ - "unlink", /* 10 */ - "execve", /* 11 */ - "chdir", /* 12 */ - "time", /* 13 */ - "mknod", /* 14 */ - "chmod", /* 15 */ - "lchown", /* 16 */ - "break", /* 17 */ - "oldstat", /* 18 */ - "lseek", /* 19 */ - "getpid", /* 20 */ - "mount", /* 21 */ - "umount", /* 22 */ - "setuid", /* 23 */ - "getuid", /* 24 */ - "stime", /* 25 */ - "ptrace", /* 26 */ - "alarm", /* 27 */ - "oldfstat", /* 28 */ - "pause", /* 29 */ - "utime", /* 30 */ - "stty", /* 31 */ - "gtty", /* 32 */ - "access", /* 33 */ - "nice", /* 34 */ - "ftime", /* 35 */ - "sync", /* 36 */ - "kill", /* 37 */ - "rename", /* 38 */ - "mkdir", /* 39 */ - "rmdir", /* 40 */ - "dup", /* 41 */ - "pipe", /* 42 */ - "times", /* 43 */ - "prof", /* 44 */ - "brk", /* 45 */ - "setgid", /* 46 */ - "getgid", /* 47 */ - "signal", /* 48 */ - "geteuid", /* 49 */ - "getegid", /* 50 */ - "acct", /* 51 */ - "umount2", /* 52 */ - "lock", /* 53 */ - "ioctl", /* 54 */ - "fcntl", /* 55 */ - "mpx", /* 56 */ - "setpgid", /* 57 */ - "ulimit", /* 58 */ - "oldolduname", /* 59 */ - "umask", /* 60 */ - "chroot", /* 61 */ - "ustat", /* 62 */ - "dup2", /* 63 */ - "getppid", /* 64 */ - "getpgrp", /* 65 */ - "setsid", /* 66 */ - "sigaction", /* 67 */ - "sgetmask", /* 68 */ - "ssetmask", /* 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 */ - "select", /* 82 */ - "symlink", /* 83 */ - "oldlstat", /* 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 */ - "profil", /* 98 */ - "statfs", /* 99 */ - "fstatfs", /* 100 */ - "ioperm", /* 101 */ - "socketcall", /* 102 */ - "syslog", /* 103 */ - "setitimer", /* 104 */ - "getitimer", /* 105 */ - "stat", /* 106 */ - "lstat", /* 107 */ - "fstat", /* 108 */ - "olduname", /* 109 */ - "iopl", /* 110 */ - "vhangup", /* 111 */ - "idle", /* 112 */ - "vm86old", /* 113 */ - "wait4", /* 114 */ - "swapoff", /* 115 */ - "sysinfo", /* 116 */ - "ipc", /* 117 */ - "fsync", /* 118 */ - "sigreturn", /* 119 */ - "clone", /* 120 */ - "setdomainname", /* 121 */ - "uname", /* 122 */ - "modify_ldt", /* 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 */ - "vm86", /* 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 */ - "pread64", /* 180 */ - "pwrite64", /* 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 */ - "madvise1", /* 219 */ - "getdents64", /* 220 */ - "fcntl64", /* 221 */ - "222", /* 222 */ - "223", /* 223 */ - "gettid", /* 224 */ - "readahead", /* 225 */ - "setxattr", /* 226 */ - "lsetxattr", /* 227 */ - "fsetxattr", /* 228 */ - "getxattr", /* 229 */ - "lgetxattr", /* 230 */ - "fgetxattr", /* 231 */ - "listxattr", /* 232 */ - "llistxattr", /* 233 */ - "flistxattr", /* 234 */ - "removexattr", /* 235 */ - "lremovexattr", /* 236 */ - "fremovexattr", /* 237 */ - "tkill", /* 238 */ - "sendfile64", /* 239 */ - "futex", /* 240 */ - "sched_setaffinity", /* 241 */ - "sched_getaffinity", /* 242 */ - "set_thread_area", /* 243 */ - "get_thread_area", /* 244 */ - "io_setup", /* 245 */ - "io_destroy", /* 246 */ - "io_getevents", /* 247 */ - "io_submit", /* 248 */ - "io_cancel", /* 249 */ - "fadvise64", /* 250 */ - "251", /* 251 */ - "exit_group", /* 252 */ - "lookup_dcookie", /* 253 */ - "epoll_create", /* 254 */ - "epoll_ctl", /* 255 */ - "epoll_wait", /* 256 */ - "remap_file_pages", /* 257 */ - "set_tid_address", /* 258 */ - "timer_create", /* 259 */ - "260", /* 260 */ - "261", /* 261 */ - "262", /* 262 */ - "263", /* 263 */ - "264", /* 264 */ - "265", /* 265 */ - "266", /* 266 */ - "267", /* 267 */ - "statfs64", /* 268 */ - "fstatfs64", /* 269 */ - "tgkill", /* 270 */ - "utimes", /* 271 */ - "fadvise64_64", /* 272 */ - "vserver", /* 273 */ - "mbind", /* 274 */ - "get_mempolicy", /* 275 */ - "set_mempolicy", /* 276 */ - "mq_open", /* 277 */ - "278", /* 278 */ - "279", /* 279 */ - "280", /* 280 */ - "281", /* 281 */ - "282", /* 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 */ - "migrate_pages", /* 294 */ - "openat", /* 295 */ - "mkdirat", /* 296 */ - "mknodat", /* 297 */ - "fchownat", /* 298 */ - "futimesat", /* 299 */ - "fstatat64", /* 300 */ - "unlinkat", /* 301 */ - "renameat", /* 302 */ - "linkat", /* 303 */ - "symlinkat", /* 304 */ - "readlinkat", /* 305 */ - "fchmodat", /* 306 */ - "faccessat", /* 307 */ - "pselect6", /* 308 */ - "ppoll", /* 309 */ - "unshare", /* 310 */ - "set_robust_list", /* 311 */ - "get_robust_list", /* 312 */ - "splice", /* 313 */ - "sync_file_range", /* 314 */ - "tee", /* 315 */ - "vmsplice", /* 316 */ diff --git a/sysdeps/linux-gnu/i386/trace.c b/sysdeps/linux-gnu/i386/trace.c deleted file mode 100644 index 76f1105..0000000 --- a/sysdeps/linux-gnu/i386/trace.c +++ /dev/null @@ -1,85 +0,0 @@ -#include "config.h" - -#include <stdlib.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <signal.h> -#include <sys/ptrace.h> -#include <asm/ptrace.h> - -#include "common.h" - -#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) -# define PTRACE_PEEKUSER PTRACE_PEEKUSR -#endif - -#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) -# define PTRACE_POKEUSER PTRACE_POKEUSR -#endif - -void -get_arch_dep(Process *proc) { -} - -/* Returns 1 if syscall, 2 if sysret, 0 otherwise. - */ -int -syscall_p(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].c_un.syscall == *sysnum) { - return 2; - } - - if (*sysnum >= 0) { - return 1; - } - } - return 0; -} - -long -gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { - 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 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); - } -#else - return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, 0); -#endif - } else { - fprintf(stderr, "gimme_arg called with wrong arguments\n"); - exit(1); - } - - return 0; -} - -void -save_register_args(enum tof type, Process *proc) { -} diff --git a/sysdeps/linux-gnu/ia64/Makefile b/sysdeps/linux-gnu/ia64/Makefile deleted file mode 100644 index 4f0ef63..0000000 --- a/sysdeps/linux-gnu/ia64/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -OBJ = trace.o regs.o plt.o breakpoint.o - -all: arch.o - -arch.o: $(OBJ) - $(LD) -r -o arch.o $(OBJ) - -clean: - $(RM) $(OBJ) arch.o - diff --git a/sysdeps/linux-gnu/ia64/Makefile.am b/sysdeps/linux-gnu/ia64/Makefile.am new file mode 100644 index 0000000..c5fd360 --- /dev/null +++ b/sysdeps/linux-gnu/ia64/Makefile.am @@ -0,0 +1,36 @@ +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + breakpoint.c \ + plt.c \ + regs.c \ + trace.c \ + fetch.c + +noinst_HEADERS = \ + arch.h \ + ptrace.h \ + signalent.h \ + syscallent.h + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/sysdeps/linux-gnu/ia64/Makefile.in b/sysdeps/linux-gnu/ia64/Makefile.in new file mode 100644 index 0000000..a4eb305 --- /dev/null +++ b/sysdeps/linux-gnu/ia64/Makefile.in @@ -0,0 +1,533 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = sysdeps/linux-gnu/ia64 +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/m4/libtool.m4 \ + $(top_srcdir)/config/m4/ltoptions.m4 \ + $(top_srcdir)/config/m4/ltsugar.m4 \ + $(top_srcdir)/config/m4/ltversion.m4 \ + $(top_srcdir)/config/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +___libcpu_la_LIBADD = +am____libcpu_la_OBJECTS = breakpoint.lo plt.lo regs.lo trace.lo \ + fetch.lo +___libcpu_la_OBJECTS = $(am____libcpu_la_OBJECTS) +am__dirstamp = $(am__leading_dot)dirstamp +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/autoconf/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(___libcpu_la_SOURCES) +DIST_SOURCES = $(___libcpu_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_VALGRIND = @HAVE_VALGRIND@ +HOST_CPU = @HOST_CPU@ +HOST_OS = @HOST_OS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libelf_LD_LIBRARY_PATH = @libelf_LD_LIBRARY_PATH@ +liberty_LIBS = @liberty_LIBS@ +libexecdir = @libexecdir@ +libstdcxx_LIBS = @libstdcxx_LIBS@ +libsupcxx_LIBS = @libsupcxx_LIBS@ +libunwind_LD_LIBRARY_PATH = @libunwind_LD_LIBRARY_PATH@ +libunwind_LIBS = @libunwind_LIBS@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + breakpoint.c \ + plt.c \ + regs.c \ + trace.c \ + fetch.c + +noinst_HEADERS = \ + arch.h \ + ptrace.h \ + signalent.h \ + syscallent.h + +MAINTAINERCLEANFILES = \ + Makefile.in + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign sysdeps/linux-gnu/ia64/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign sysdeps/linux-gnu/ia64/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +../$(am__dirstamp): + @$(MKDIR_P) .. + @: > ../$(am__dirstamp) +../libcpu.la: $(___libcpu_la_OBJECTS) $(___libcpu_la_DEPENDENCIES) ../$(am__dirstamp) + $(LINK) $(___libcpu_la_OBJECTS) $(___libcpu_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/breakpoint.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fetch.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf ../.libs ../_libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f ../$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sysdeps/linux-gnu/ia64/arch.h b/sysdeps/linux-gnu/ia64/arch.h index 673047c..82780d4 100644 --- a/sysdeps/linux-gnu/ia64/arch.h +++ b/sysdeps/linux-gnu/ia64/arch.h @@ -1,9 +1,34 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006,2011,2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #define ARCH_HAVE_DISABLE_BREAKPOINT 1 #define ARCH_HAVE_ENABLE_BREAKPOINT 1 +#define ARCH_HAVE_FETCH_ARG +#define ARCH_HAVE_FETCH_PACK #define BREAKPOINT_LENGTH 16 #define BREAKPOINT_VALUE {0} #define DECR_PC_AFTER_BREAK 0 +#define ARCH_ENDIAN_LITTLE +#define ARCH_HAVE_TRANSLATE_ADDRESS #define LT_ELFCLASS ELFCLASS64 #define LT_ELF_MACHINE EM_IA_64 diff --git a/sysdeps/linux-gnu/ia64/breakpoint.c b/sysdeps/linux-gnu/ia64/breakpoint.c index 4f09173..ca34e93 100644 --- a/sysdeps/linux-gnu/ia64/breakpoint.c +++ b/sysdeps/linux-gnu/ia64/breakpoint.c @@ -1,14 +1,33 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2008,2009 Juan Cespedes + * Copyright (C) 2005,2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + /* IA64 breakpoint support. Much of this clagged from gdb * -Ian Wienand <ianw@gelato.unsw.edu.au> 10/3/2005 */ -#include "config.h" - #include <sys/ptrace.h> #include <string.h> -#include "arch.h" -#include "options.h" -#include "output.h" +#include <assert.h> + +#include "breakpoint.h" #include "debug.h" static long long @@ -153,7 +172,8 @@ union bundle_t { }; void -arch_enable_breakpoint(pid_t pid, Breakpoint *sbp) { +arch_enable_breakpoint(pid_t pid, struct breakpoint *sbp) +{ unsigned long addr = (unsigned long)sbp->addr; union bundle_t bundle; @@ -163,9 +183,7 @@ arch_enable_breakpoint(pid_t pid, Breakpoint *sbp) { debug(1, "Enable Breakpoint at %p)", sbp->addr); - if (slotnum > 2) - printf - ("Can't insert breakpoint for slot numbers greater than 2."); + assert(slotnum <= 2); addr &= ~0x0f; bundle.ubundle[0] = ptrace(PTRACE_PEEKTEXT, pid, addr, 0); @@ -190,7 +208,8 @@ arch_enable_breakpoint(pid_t pid, Breakpoint *sbp) { } void -arch_disable_breakpoint(pid_t pid, const Breakpoint *sbp) { +arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp) +{ unsigned long addr = (unsigned long)sbp->addr; int slotnum = (int)(addr & 0x0f) & 0x3; diff --git a/sysdeps/linux-gnu/ia64/fetch.c b/sysdeps/linux-gnu/ia64/fetch.c new file mode 100644 index 0000000..54dc5b8 --- /dev/null +++ b/sysdeps/linux-gnu/ia64/fetch.c @@ -0,0 +1,502 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2008,2009 Juan Cespedes + * Copyright (C) 2006 Steve Fink + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include <stdlib.h> +#include <assert.h> +#include <sys/rse.h> +#include <ptrace.h> +#include <string.h> +#include <errno.h> + +#include "backend.h" +#include "fetch.h" +#include "type.h" +#include "proc.h" +#include "value.h" + +struct fetch_context { + arch_addr_t stack_pointer; + struct pt_all_user_regs regs; + enum param_pack_flavor ppflavor; + + /* Return values larger than 256 bits (except HFAs of up to 8 + * elements) are returned in a buffer allocated by the + * caller. A pointer to the buffer is passed to the called + * procedure in r8. This register is not guaranteed to be + * preserved by the called procedure. */ + unsigned long r8; + + int slot_n; + int flt; +}; + +union cfm_t { + struct { + unsigned long sof:7; + unsigned long sol:7; + unsigned long sor:4; + unsigned long rrb_gr:7; + unsigned long rrb_fr:7; + unsigned long rrb_pr:6; + } cfm; + unsigned long value; +}; + +static int +fetch_context_init(struct Process *proc, struct fetch_context *context) +{ + context->slot_n = 0; + context->flt = 8; + if (ptrace(PTRACE_GETREGS, proc->pid, 0, &context->regs) < 0) + return -1; + context->stack_pointer = (void *)(context->regs.gr[12] + 16); + context->ppflavor = PARAM_PACK_ARGS; + + return 0; +} + +struct fetch_context * +arch_fetch_arg_init(enum tof type, struct Process *proc, + struct arg_type_info *ret_info) +{ + struct fetch_context *context = malloc(sizeof(*context)); + if (context == NULL + || fetch_context_init(proc, context) < 0) { + free(context); + return NULL; + } + context->r8 = context->regs.gr[8]; + + return context; +} + +struct fetch_context * +arch_fetch_arg_clone(struct Process *proc, + struct fetch_context *context) +{ + struct fetch_context *clone = malloc(sizeof(*context)); + if (clone == NULL) + return NULL; + *clone = *context; + return clone; +} + +int +allocate_stack_slot(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep) +{ + size_t al = type_alignof(proc, info); + size_t sz = type_sizeof(proc, info); + if (al == (size_t)-1 || sz == (size_t)-1) + return -1; + + errno = 0; + long value = ptrace(PTRACE_PEEKDATA, proc->pid, ctx->stack_pointer, 0); + if (value == -1 && errno != 0) + return -1; + ctx->stack_pointer += 8; + value_set_word(valuep, value); + + return 0; +} + +static int +allocate_reg(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep) +{ + if (ctx->slot_n >= 8) + return allocate_stack_slot(ctx, proc, info, valuep); + + int reg_num = ctx->slot_n++; + if (ctx->slot_n == 8) + ctx->flt = 16; + if (valuep == NULL) + return 0; + + /* This would normally be brought over from asm/ptrace.h, but + * when we do, we get namespace conflicts between asm/fpu.h + * and libunwind. */ + enum { PT_AUR_BSP = 17 }; + + union cfm_t cfm = { .value = ctx->regs.cfm }; + unsigned long *bsp = (unsigned long *)ctx->regs.ar[PT_AUR_BSP]; + unsigned long idx = -cfm.cfm.sof + reg_num; + unsigned long *ptr = ia64_rse_skip_regs(bsp, idx); + errno = 0; + long ret = ptrace(PTRACE_PEEKDATA, proc->pid, ptr, 0); + if (ret == -1 && errno != 0) + return -1; + + value_set_word(valuep, ret); + return 0; +} + +static int +copy_aggregate_part(struct fetch_context *ctx, struct Process *proc, + unsigned char *buf, size_t size) +{ + size_t slots = (size + 7) / 8; + struct arg_type_info *long_info = type_get_simple(ARGTYPE_LONG); + while (slots-- > 0) { + size_t chunk_sz = size > 8 ? 8 : size; + size -= 8; + + struct value tmp; + value_init(&tmp, proc, NULL, long_info, 0); + int rc = allocate_reg(ctx, proc, long_info, &tmp); + if (rc >= 0) { + memcpy(buf, value_get_data(&tmp, NULL), chunk_sz); + buf += 8; + } + value_destroy(&tmp); + if (rc < 0) + return -1; + } + return 0; +} + +static int +allocate_arg(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep) +{ + size_t sz = type_sizeof(proc, info); + size_t align = type_alignof(proc, info); + if (sz == (size_t)-1 || align == (size_t)-1) + return -1; + + unsigned char *buf = value_reserve(valuep, sz); + if (buf == NULL) + return -1; + + assert(align == 0 || align == 1 || align == 2 || align == 4 + || align == 8 || align == 16); + + /* For aggregates with an external alignment of 16 bytes, the + * Next Even policy is used. 128-bit integers use the Next + * Even policy as well. */ + if (align == 16 && ctx->slot_n % 2 != 0) + allocate_reg(ctx, proc, info, NULL); + + int rc= copy_aggregate_part(ctx, proc, buf, sz); + + return rc; +} + +/* Stolen from David Mosberger's utrace tool, which he released under + the GPL + (http://www.gelato.unsw.edu.au/archives/linux-ia64/0104/1405.html) */ +static inline double +fpreg_to_double (struct ia64_fpreg *fp) { + double result; + asm ("ldf.fill %0=%1" : "=f"(result) : "m"(*fp)); + return result; +} + +static int +allocate_float(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep, + int take_slot) +{ + /* The actual parameter is passed in the next available + * floating-point parameter register, if one is + * available. Floating-point parameter registers are allocated + * as needed from the range f8-f15, starting with f8. */ + /* Any register parameters corresponding to a + * variable-argument specification are passed in GRs. */ + if (ctx->flt > 15 || ctx->ppflavor == PARAM_PACK_VARARGS) + /* If all available floating-point parameter registers + * have been used, the actual parameter is passed in + * the appropriate general register(s). */ + return allocate_reg(ctx, proc, info, valuep); + + union { + double d; + float f; + char buf[0]; + } u = { .d = fpreg_to_double(&ctx->regs.fr[ctx->flt++]) }; + if (take_slot) + allocate_reg(ctx, proc, info, NULL); + + if (info->type == ARGTYPE_FLOAT) + u.f = u.d; + else + assert(info->type == ARGTYPE_DOUBLE); + + if (value_reserve(valuep, sizeof(u)) == NULL) + return -1; + memmove(value_get_raw_data(valuep), u.buf, sizeof(u)); + + return 0; +} + +static enum arg_type +get_hfa_type(struct arg_type_info *info, size_t *countp) +{ + size_t n = type_aggregate_size(info); + if (n == (size_t)-1) + return ARGTYPE_VOID; + + enum arg_type type = ARGTYPE_VOID; + *countp = 0; + + while (n-- > 0) { + struct arg_type_info *emt = type_element(info, n); + + enum arg_type emt_type = emt->type; + size_t emt_count = 1; + if (emt_type == ARGTYPE_STRUCT || emt_type == ARGTYPE_ARRAY) + emt_type = get_hfa_type(emt, &emt_count); + + if (type == ARGTYPE_VOID) { + if (emt_type != ARGTYPE_FLOAT + && emt_type != ARGTYPE_DOUBLE) + return ARGTYPE_VOID; + type = emt_type; + } + if (emt_type != type) + return ARGTYPE_VOID; + *countp += emt_count; + } + return type; +} + +static int +allocate_hfa(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep, + enum arg_type hfa_type, size_t hfa_count) +{ + size_t sz = type_sizeof(proc, info); + if (sz == (size_t)-1) + return -1; + + /* If an actual parameter is known to correspond to an HFA + * formal parameter, each element is passed in the next + * available floating-point argument register, until the eight + * argument registers are exhausted. The remaining elements of + * the aggregate are passed in output GRs, according to the + * normal conventions. + * + * Because HFAs are mapped to parameter slots as aggregates, + * single-precision HFAs will be allocated with two + * floating-point values in each parameter slot, but only one + * value per register. + * + * It is possible for the first of two values in a parameter + * slot to occupy the last available floating- point parameter + * register. In this case, the second value is passed in its + * designated GR, but the half of the GR that would have + * contained the first value is undefined. */ + + size_t slot_off = 0; + + unsigned char *buf = value_reserve(valuep, sz); + if (buf == NULL) + return -1; + + struct arg_type_info *hfa_info = type_get_simple(hfa_type); + size_t hfa_sz = type_sizeof(proc, hfa_info); + + /* Pass in register the part that we can. */ + while (ctx->flt <= 15 && hfa_count > 0) { + struct value tmp; + value_init(&tmp, proc, NULL, hfa_info, 0); + int rc = allocate_float(ctx, proc, hfa_info, &tmp, 0); + if (rc >= 0) { + memcpy(buf, value_get_data(&tmp, NULL), hfa_sz); + slot_off += hfa_sz; + buf += hfa_sz; + hfa_count--; + + /* Scratch each fully used slot. */ + while (slot_off >= 8) { + if (allocate_reg(ctx, proc, info, NULL) < 0) + rc = -1; + slot_off -= 8; + } + } + value_destroy(&tmp); + if (rc < 0) + return -1; + } + + /* If we have half-slot opened (the case where odd + * ARGTYPE_FLOAT member fits into the last floating point + * register, and the following even member does not), finish + * it first. */ + struct arg_type_info *long_info = type_get_simple(ARGTYPE_LONG); + if (slot_off != 0 && hfa_count > 0) { + struct value tmp; + value_init(&tmp, proc, NULL, long_info, 0); + int rc = allocate_reg(ctx, proc, long_info, &tmp); + if (rc >= 0) { + unsigned char *data = value_get_data(&tmp, NULL); + memcpy(buf, data, 8 - slot_off); + buf += 8 - slot_off; + hfa_count--; + } + value_destroy(&tmp); + if (rc < 0) { + return -1; + } + } + + /* The rest is passed in registers and on stack. */ + size_t rest = hfa_count * hfa_sz; + return copy_aggregate_part(ctx, proc, buf, rest); +} + +static int +allocate_ret(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep) +{ + size_t sz = type_sizeof(proc, info); + if (sz == (size_t)-1) + return -1; + + /* Homogeneous floating-point aggregates [...] are returned in + * floating-point registers, provided the array or structure + * contains no more than eight individual values. The + * elements of the aggregate are placed in successive + * floating-point registers, beginning with f8. */ + if (info->type == ARGTYPE_STRUCT || info->type == ARGTYPE_ARRAY) { + size_t hfa_size; + enum arg_type hfa_type = get_hfa_type(info, &hfa_size); + if (hfa_type != ARGTYPE_VOID && hfa_size <= 8) + return allocate_hfa(ctx, proc, info, valuep, + hfa_type, hfa_size); + } + + /* Integers and pointers are passed in r8. 128-bit integers + * are passed in r8 and r9. Aggregates of up to 256 bits [32 + * bytes] are passed in registers r8...r11. */ + if (sz <= 32) { + unsigned char *buf = value_reserve(valuep, sz); + if (buf == NULL) + return -1; + memcpy(buf, ctx->regs.gr + 8, sz); + return 0; + } + + if (value_pass_by_reference(valuep) < 0) + return -1; + value_set_word(valuep, ctx->r8); + return 0; +} + +int +arch_fetch_arg_next(struct fetch_context *ctx, enum tof type, + struct Process *proc, + struct arg_type_info *info, struct value *valuep) +{ + switch (info->type) { + enum arg_type hfa_type; + size_t hfa_size; + + case ARGTYPE_VOID: + value_set_word(valuep, 0); + return 0; + + case ARGTYPE_FLOAT: + case ARGTYPE_DOUBLE: + return allocate_float(ctx, proc, info, valuep, 1); + + case ARGTYPE_STRUCT: + hfa_type = get_hfa_type(info, &hfa_size); + if (hfa_type != ARGTYPE_VOID) + return allocate_hfa(ctx, proc, info, valuep, + hfa_type, hfa_size); + /* Fall through. */ + case ARGTYPE_CHAR: + case ARGTYPE_SHORT: + case ARGTYPE_USHORT: + case ARGTYPE_INT: + case ARGTYPE_UINT: + case ARGTYPE_LONG: + case ARGTYPE_ULONG: + case ARGTYPE_POINTER: + return allocate_arg(ctx, proc, info, valuep); + + case ARGTYPE_ARRAY: + /* Arrays decay into pointers. XXX Fortran? */ + default: + assert(info->type != info->type); + abort(); + } +} + +int +arch_fetch_retval(struct fetch_context *ctx, enum tof type, + struct Process *proc, struct arg_type_info *info, + struct value *valuep) +{ + if (fetch_context_init(proc, ctx) < 0) + return -1; + + switch (info->type) { + case ARGTYPE_VOID: + case ARGTYPE_FLOAT: + case ARGTYPE_DOUBLE: + /* The rules for returning those types are the same as + * for passing them in arguments. */ + return arch_fetch_arg_next(ctx, type, proc, info, valuep); + + case ARGTYPE_CHAR: + case ARGTYPE_SHORT: + case ARGTYPE_USHORT: + case ARGTYPE_INT: + case ARGTYPE_UINT: + case ARGTYPE_LONG: + case ARGTYPE_ULONG: + case ARGTYPE_POINTER: + case ARGTYPE_STRUCT: + return allocate_ret(ctx, proc, info, valuep); + + case ARGTYPE_ARRAY: + /* Arrays decay into pointers. XXX Fortran? */ + assert(info->type != ARGTYPE_ARRAY); + abort(); + } + assert("unhandled type"); + abort(); + return arch_fetch_arg_next(ctx, type, proc, info, valuep); +} + +void +arch_fetch_arg_done(struct fetch_context *context) +{ + free(context); +} + +int +arch_fetch_param_pack_start(struct fetch_context *context, + enum param_pack_flavor ppflavor) +{ + context->ppflavor = ppflavor; + return 0; +} + +void +arch_fetch_param_pack_end(struct fetch_context *context) +{ + context->ppflavor = PARAM_PACK_ARGS; +} diff --git a/sysdeps/linux-gnu/ia64/plt.c b/sysdeps/linux-gnu/ia64/plt.c index 7fd451b..a29488f 100644 --- a/sysdeps/linux-gnu/ia64/plt.c +++ b/sysdeps/linux-gnu/ia64/plt.c @@ -1,29 +1,56 @@ -#include <gelf.h> -#include "common.h" - -/* A bundle is 128 bits */ -#define BUNDLE_SIZE 16 - /* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2008,2009 Juan Cespedes + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ - The PLT has - - ] 3 bundles as a header - - ] The special reserved entry +#include <errno.h> +#include <gelf.h> +#include <stdio.h> +#include <string.h> +#include <sys/ptrace.h> - ] Following that, each PLT entry has it's initial code that the GOT entry - points to. Each PLT entry has one bundle allocated. +#include "proc.h" +#include "common.h" +#include "library.h" - ] Following that, each PLT entry has two bundles of actual PLT code, - i.e. load up the address from the GOT and jump to it. This is the - point we want to insert the breakpoint, as this will be captured - every time we jump to the PLT entry in the code. +/* A bundle is 128 bits. */ +#define BUNDLE_SIZE 16 -*/ +/* The PLT has + * + * - 3 bundles as a header + * + * - The special reserved entry + * + * - Following that, each PLT entry has it's initial code that the GOT + * entry points to. Each PLT entry has one bundle allocated. + * + * - Following that, each PLT entry has two bundles of actual PLT + * code, i.e. load up the address from the GOT and jump to it. This + * is the point we want to insert the breakpoint, as this will be + * captured every time we jump to the PLT entry in the code. + */ GElf_Addr -arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { +arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) +{ /* Find number of entires by removing header and special * entry, dividing total size by three, since each PLT entry * will have 3 bundles (1 for inital entry and two for the PLT @@ -35,7 +62,7 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { unsigned long addr = lte->plt_addr + (4 * BUNDLE_SIZE) + (BUNDLE_SIZE * entries) + (2 * ndx * BUNDLE_SIZE); - debug(3, "Found PLT %d entry at %lx\n", ndx, addr); + debug(3, "Found PLT %zd entry at %lx", ndx, addr); return addr; } @@ -44,3 +71,29 @@ void * sym2addr(Process *proc, struct library_symbol *sym) { return sym->enter_addr; } + +int +arch_translate_address_dyn(struct Process *proc, + arch_addr_t addr, arch_addr_t *ret) +{ + errno = 0; + unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0); + if (l == -1UL && errno) { + fprintf(stderr, "dynamic .opd translation of %p: %s\n", + addr, strerror(errno)); + return -1; + } + + /* XXX The double cast should be removed when + * arch_addr_t becomes integral type. */ + *ret = (arch_addr_t)(uintptr_t)l; + return 0; +} + +int +arch_translate_address(struct ltelf *lte, + arch_addr_t addr, arch_addr_t *ret) +{ + *ret = addr; + return 0; +} diff --git a/sysdeps/linux-gnu/ia64/ptrace.h b/sysdeps/linux-gnu/ia64/ptrace.h index c3cbcb6..ef63b4f 100644 --- a/sysdeps/linux-gnu/ia64/ptrace.h +++ b/sysdeps/linux-gnu/ia64/ptrace.h @@ -1 +1,21 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include <sys/ptrace.h> diff --git a/sysdeps/linux-gnu/ia64/regs.c b/sysdeps/linux-gnu/ia64/regs.c index d161d34..cbc2744 100644 --- a/sysdeps/linux-gnu/ia64/regs.c +++ b/sysdeps/linux-gnu/ia64/regs.c @@ -1,13 +1,36 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2008,2009 Juan Cespedes + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "config.h" #include <sys/types.h> #include <sys/ptrace.h> +#include <errno.h> #include <asm/ptrace_offsets.h> #include <asm/rse.h> #include <stddef.h> -#include "debug.h" +#include "proc.h" #include "common.h" void * @@ -37,12 +60,18 @@ set_instruction_pointer(Process *proc, void *addr) { void * get_stack_pointer(Process *proc) { - return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, PT_R12, 0); + long l = ptrace(PTRACE_PEEKUSER, proc->pid, PT_R12, 0); + if (l == -1 && errno) + return NULL; + return (void *)l; } void * get_return_addr(Process *proc, void *stack_pointer) { - return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, PT_B0, 0); + long l = ptrace(PTRACE_PEEKUSER, proc->pid, PT_B0, 0); + if (l == -1 && errno) + return NULL; + return (void *)l; } void diff --git a/sysdeps/linux-gnu/ia64/signalent.h b/sysdeps/linux-gnu/ia64/signalent.h index 5395f82..31699db 100644 --- a/sysdeps/linux-gnu/ia64/signalent.h +++ b/sysdeps/linux-gnu/ia64/signalent.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + "SIG_0", /* 0 */ "SIGHUP", /* 1 */ "SIGINT", /* 2 */ diff --git a/sysdeps/linux-gnu/ia64/syscallent.h b/sysdeps/linux-gnu/ia64/syscallent.h index 9bb4fb8..094cea2 100644 --- a/sysdeps/linux-gnu/ia64/syscallent.h +++ b/sysdeps/linux-gnu/ia64/syscallent.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + "0", /* 0 */ "1", /* 1 */ "2", /* 2 */ diff --git a/sysdeps/linux-gnu/ia64/trace.c b/sysdeps/linux-gnu/ia64/trace.c index 799e0ff..e608275 100644 --- a/sysdeps/linux-gnu/ia64/trace.c +++ b/sysdeps/linux-gnu/ia64/trace.c @@ -1,3 +1,25 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2008,2009 Juan Cespedes + * Copyright (C) 2006 Steve Fink + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "config.h" #include <stdlib.h> @@ -9,8 +31,11 @@ #include <string.h> #include <asm/ptrace_offsets.h> #include <asm/rse.h> +#include <errno.h> +#include "proc.h" #include "common.h" +#include "type.h" /* What we think of as a bundle, ptrace thinks of it as two unsigned * longs */ @@ -48,9 +73,10 @@ int syscall_p(Process *proc, int status, int *sysnum) { if (WIFSTOPPED(status) && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { - unsigned long slot = - (ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IPSR, 0) >> 41) & - 0x3; + long l = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IPSR, 0); + if (l == -1 && errno) + return -1; + unsigned long slot = ((unsigned long)l >> 41) & 0x3; unsigned long ip = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IIP, 0); @@ -114,155 +140,6 @@ syscall_p(Process *proc, int status, int *sysnum) { return 0; } -/* Stolen from David Mosberger's utrace tool, which he released under - the GPL - (http://www.gelato.unsw.edu.au/archives/linux-ia64/0104/1405.html) */ -static inline double -fpreg_to_double (struct ia64_fpreg *fp) { - double result; - - asm ("ldf.fill %0=%1" : "=f"(result) : "m"(*fp)); - return result; -} - -static long -gimme_long_arg(enum tof type, Process *proc, int arg_num) { - union cfm_t cfm; - unsigned long bsp; - - bsp = ptrace(PTRACE_PEEKUSER, proc->pid, PT_AR_BSP, 0); - cfm.value = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CFM, 0); - - if (arg_num == -1) /* return value */ - return ptrace(PTRACE_PEEKUSER, proc->pid, PT_R8, 0); - - /* First 8 arguments are passed in registers on the register - * stack, the following arguments are passed on the stack - * after a 16 byte scratch area - * - * If the function has returned, the ia64 register window has - * been reverted to the caller's configuration. So although in - * the callee, the first parameter is in R32, in the caller - * the first parameter comes in the registers after the local - * registers (really, input parameters plus locals, but the - * hardware doesn't track the distinction.) So we have to add - * in the size of the local area (sol) to find the first - * parameter passed to the callee. */ - if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { - if (arg_num < 8) { - if (type == LT_TOF_FUNCTIONR) - arg_num += cfm.cfm.sol; - - return ptrace(PTRACE_PEEKDATA, proc->pid, - (long)ia64_rse_skip_regs((unsigned long *)bsp, - -cfm.cfm.sof + arg_num), - 0); - } else { - unsigned long sp = - ptrace(PTRACE_PEEKUSER, proc->pid, PT_R12, 0) + 16; - return ptrace(PTRACE_PEEKDATA, proc->pid, - sp + (8 * (arg_num - 8))); - } - } - - if (type == LT_TOF_SYSCALL || LT_TOF_SYSCALLR) - return ptrace(PTRACE_PEEKDATA, proc->pid, - (long)ia64_rse_skip_regs((unsigned long *)bsp, arg_num), - 0); - - /* error if we get here */ - fprintf(stderr, "gimme_arg called with wrong arguments\n"); - exit(1); -} - -static long float_regs[8] = { PT_F8, PT_F9, PT_F10, PT_F11, - PT_F12, PT_F13, PT_F14, PT_F15 }; -static double -gimme_float_arg(enum tof type, Process *proc, int arg_num) { - union cfm_t cfm; - unsigned long bsp; - struct ia64_fpreg reg; - - if (arg_num == -1) { /* return value */ - reg.u.bits[0] = ptrace(PTRACE_PEEKUSER, proc->pid, - PT_F8, 0); - reg.u.bits[1] = ptrace(PTRACE_PEEKUSER, proc->pid, - PT_F8 + 0x8, 0); - return fpreg_to_double(®); - } - - bsp = ptrace(PTRACE_PEEKUSER, proc->pid, PT_AR_BSP, 0); - cfm.value = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CFM, 0); - - /* The first 8 arguments are passed in regular registers - * (counting from R32), unless they are floating point values - * (the case in question here). In that case, up to the first - * 8 regular registers are still "allocated" for each of the - * first 8 parameters, but if a parameter is floating point, - * then the register is left unset and the parameter is passed - * in the first available floating-point register, counting - * from F8. - * - * Take func(int a, float f, int b, double d), for example. - * a - passed in R32 - * f - R33 left unset, value passed in F8 - * b - passed in R34 - * d - R35 left unset, value passed in F9 - * - * ltrace handles this by counting floating point arguments - * while parsing declarations. The "arg_num" in this routine - * (which is only called for floating point values) really - * means which floating point parameter we're looking for, - * ignoring everything else. - * - * Following the first 8 arguments, the remaining arguments - * are passed on the stack after a 16 byte scratch area - */ - if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { - if (arg_num < 8) { - reg.u.bits[0] = ptrace(PTRACE_PEEKUSER, proc->pid, - float_regs[arg_num], 0); - reg.u.bits[1] = ptrace(PTRACE_PEEKUSER, proc->pid, - float_regs[arg_num] + 0x8, 0); - return fpreg_to_double(®); - } else { - unsigned long sp = - ptrace(PTRACE_PEEKUSER, proc->pid, PT_R12, 0) + 16; - reg.u.bits[0] = ptrace(PTRACE_PEEKDATA, proc->pid, - sp + (8 * (arg_num - 8))); - reg.u.bits[0] = ptrace(PTRACE_PEEKDATA, proc->pid, - sp + (8 * (arg_num - 8)) + 0x8); - return fpreg_to_double(®); - } - } - - /* error if we get here */ - fprintf(stderr, "gimme_arg called with wrong arguments\n"); - exit(1); -} - -long -gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { - union { - long l; - float f; - double d; - } cvt; - - if (info->type == ARGTYPE_FLOAT) - cvt.f = gimme_float_arg(type, proc, info->u.float_info.float_index); - else if (info->type == ARGTYPE_DOUBLE) - cvt.d = gimme_float_arg(type, proc, info->u.double_info.float_index); - else - cvt.l = gimme_long_arg(type, proc, arg_num); - - return cvt.l; -} - -void -save_register_args(enum tof type, Process *proc) { -} - void get_arch_dep(Process *proc) { } diff --git a/sysdeps/linux-gnu/m68k/Makefile b/sysdeps/linux-gnu/m68k/Makefile deleted file mode 100644 index 60d7531..0000000 --- a/sysdeps/linux-gnu/m68k/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -OBJ = trace.o regs.o plt.o - -all: arch.o - -arch.o: $(OBJ) - $(CC) -nostdlib -r -o arch.o $(OBJ) - -clean: - $(RM) $(OBJ) arch.o - diff --git a/sysdeps/linux-gnu/m68k/Makefile.am b/sysdeps/linux-gnu/m68k/Makefile.am new file mode 100644 index 0000000..aa63e15 --- /dev/null +++ b/sysdeps/linux-gnu/m68k/Makefile.am @@ -0,0 +1,35 @@ +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ + trace.c \ + fetch.c + +noinst_HEADERS = \ + arch.h \ + ptrace.h \ + signalent.h \ + syscallent.h + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/sysdeps/linux-gnu/m68k/Makefile.in b/sysdeps/linux-gnu/m68k/Makefile.in new file mode 100644 index 0000000..45eebd3 --- /dev/null +++ b/sysdeps/linux-gnu/m68k/Makefile.in @@ -0,0 +1,530 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = sysdeps/linux-gnu/m68k +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/m4/libtool.m4 \ + $(top_srcdir)/config/m4/ltoptions.m4 \ + $(top_srcdir)/config/m4/ltsugar.m4 \ + $(top_srcdir)/config/m4/ltversion.m4 \ + $(top_srcdir)/config/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +___libcpu_la_LIBADD = +am____libcpu_la_OBJECTS = plt.lo regs.lo trace.lo fetch.lo +___libcpu_la_OBJECTS = $(am____libcpu_la_OBJECTS) +am__dirstamp = $(am__leading_dot)dirstamp +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/autoconf/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(___libcpu_la_SOURCES) +DIST_SOURCES = $(___libcpu_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_VALGRIND = @HAVE_VALGRIND@ +HOST_CPU = @HOST_CPU@ +HOST_OS = @HOST_OS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libelf_LD_LIBRARY_PATH = @libelf_LD_LIBRARY_PATH@ +liberty_LIBS = @liberty_LIBS@ +libexecdir = @libexecdir@ +libstdcxx_LIBS = @libstdcxx_LIBS@ +libsupcxx_LIBS = @libsupcxx_LIBS@ +libunwind_LD_LIBRARY_PATH = @libunwind_LD_LIBRARY_PATH@ +libunwind_LIBS = @libunwind_LIBS@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ + trace.c \ + fetch.c + +noinst_HEADERS = \ + arch.h \ + ptrace.h \ + signalent.h \ + syscallent.h + +MAINTAINERCLEANFILES = \ + Makefile.in + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign sysdeps/linux-gnu/m68k/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign sysdeps/linux-gnu/m68k/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +../$(am__dirstamp): + @$(MKDIR_P) .. + @: > ../$(am__dirstamp) +../libcpu.la: $(___libcpu_la_OBJECTS) $(___libcpu_la_DEPENDENCIES) ../$(am__dirstamp) + $(LINK) $(___libcpu_la_OBJECTS) $(___libcpu_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fetch.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf ../.libs ../_libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f ../$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sysdeps/linux-gnu/m68k/arch.h b/sysdeps/linux-gnu/m68k/arch.h index 1790d09..3829901 100644 --- a/sysdeps/linux-gnu/m68k/arch.h +++ b/sysdeps/linux-gnu/m68k/arch.h @@ -1,6 +1,29 @@ +/* + * This file is part of ltrace. + * Copyright (C) 1998,2002,2004 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#define ARCH_HAVE_FETCH_ARG + #define BREAKPOINT_VALUE { 0x4e, 0x4f } #define BREAKPOINT_LENGTH 2 #define DECR_PC_AFTER_BREAK 2 +#define ARCH_ENDIAN_BIG #define LT_ELFCLASS ELFCLASS32 #define LT_ELF_MACHINE EM_68K diff --git a/sysdeps/linux-gnu/m68k/fetch.c b/sysdeps/linux-gnu/m68k/fetch.c new file mode 100644 index 0000000..f6d8a0b --- /dev/null +++ b/sysdeps/linux-gnu/m68k/fetch.c @@ -0,0 +1,239 @@ +/* + * This file is part of ltrace. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <sys/types.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <sys/procfs.h> +#include <sys/reg.h> + +#include "backend.h" +#include "expr.h" +#include "fetch.h" +#include "proc.h" +#include "ptrace.h" +#include "type.h" +#include "value.h" + +struct fetch_context +{ + elf_gregset_t regs; + elf_fpregset_t fpregs; + + int arg_num; + arch_addr_t stack_pointer; + struct value retval; +}; + +static int +fetch_register_banks(struct Process *proc, struct fetch_context *context, + int floating) +{ + if (ptrace(PTRACE_GETREGS, proc->pid, 0, &context->regs) < 0) + return -1; + + if (floating + && ptrace(PTRACE_GETFPREGS, proc->pid, 0, &context->fpregs) < 0) + return -1; + + return 0; +} + +struct fetch_context * +arch_fetch_arg_init(enum tof type, struct Process *proc, + struct arg_type_info *ret_info) +{ + struct fetch_context *context = malloc(sizeof(*context)); + if (context == NULL) + return NULL; + + assert(type != LT_TOF_FUNCTIONR && type != LT_TOF_SYSCALLR); + if (fetch_register_banks(proc, context, type == LT_TOF_FUNCTION) < 0) { + fail: + free(context); + return NULL; + } + + context->arg_num = 0; + context->stack_pointer = (arch_addr_t)context->regs[PT_USP] + 4; + + size_t sz = type_sizeof(proc, ret_info); + if (sz == (size_t)-1) + goto fail; + + if (ret_info->type == ARGTYPE_STRUCT && !(sz <= 4 || sz == 8)) { + value_init(&context->retval, proc, NULL, ret_info, 0); + + if (value_pass_by_reference(&context->retval) < 0) + goto fail; + value_set_word(&context->retval, context->regs[PT_A1]); + } else { + value_init_detached(&context->retval, NULL, NULL, 0); + } + + return context; +} + +struct fetch_context * +arch_fetch_arg_clone(struct Process *proc, struct fetch_context *context) +{ + struct fetch_context *ret = malloc(sizeof(*ret)); + if (ret == NULL) + return NULL; + *ret = *context; + return ret; +} + +int +arch_fetch_arg_next(struct fetch_context *context, enum tof type, + struct Process *proc, struct arg_type_info *info, + struct value *valuep) +{ + size_t sz = type_sizeof(proc, info); + if (sz == (size_t)-1) + return -1; + + if (type == LT_TOF_SYSCALL) { + int reg; + + switch (context->arg_num++) { + case 0: reg = PT_D1; break; + case 1: reg = PT_D2; break; + case 2: reg = PT_D3; break; + case 3: reg = PT_D4; break; + case 4: reg = PT_D5; break; + case 5: reg = PT_A0; break; + default: + assert(!"More than six syscall arguments???"); + abort(); + } + value_set_word(valuep, context->regs[reg]); + } else { + size_t a = type_alignof(valuep->inferior, valuep->type); + if (a < 4) + a = 4; + context->stack_pointer = (arch_addr_t) + align((unsigned long)context->stack_pointer, a); + if (sz < 4) + context->stack_pointer += 4 - sz; + + value_in_inferior(valuep, context->stack_pointer); + context->stack_pointer += sz; + } + + return 0; +} + +int +arch_fetch_retval(struct fetch_context *context, enum tof type, + struct Process *proc, struct arg_type_info *info, + struct value *valuep) +{ + if (fetch_register_banks(proc, context, type == LT_TOF_FUNCTIONR) < 0) + return -1; + + if (context->retval.type != NULL) { + /* Struct return value was extracted when in fetch + * init. */ + *valuep = context->retval; + return 0; + } + + size_t sz = type_sizeof(proc, info); + if (sz == (size_t)-1) + return -1; + if (value_reserve(valuep, sz) == NULL) + return -1; + + switch (info->type) { + case ARGTYPE_VOID: + return 0; + + case ARGTYPE_INT: + case ARGTYPE_UINT: + case ARGTYPE_LONG: + case ARGTYPE_ULONG: + case ARGTYPE_CHAR: + case ARGTYPE_SHORT: + case ARGTYPE_USHORT: + case ARGTYPE_POINTER: + { + unsigned char *buf = value_get_raw_data(valuep); + int reg = info->type == ARGTYPE_POINTER ? PT_A0 : PT_D0; + unsigned char *val + = (unsigned char *)&context->regs[reg]; + if (sz < 4) val += 4 - sz; + memcpy(buf, val, sz); + } + return 0; + + case ARGTYPE_FLOAT: + case ARGTYPE_DOUBLE: + { + union { + long double ld; + double d; + float f; + char buf[0]; + } u; + + unsigned long *reg = &context->fpregs.fpregs[0]; + memcpy (&u.ld, reg, sizeof (u.ld)); + if (valuep->type->type == ARGTYPE_FLOAT) + u.f = (float)u.ld; + else if (valuep->type->type == ARGTYPE_DOUBLE) + u.d = (double)u.ld; + else { + assert(!"Unexpected floating type!"); + abort(); + } + unsigned char *buf = value_get_raw_data (valuep); + memcpy (buf, u.buf, sz); + } + return 0; + + case ARGTYPE_STRUCT: + { + unsigned char *buf = value_get_raw_data(valuep); + unsigned char *val + = (unsigned char *)&context->regs[PT_D0]; + + assert(sz <= 4 || sz == 8); + if (sz < 4) val += 4 - sz; + memcpy(buf, val, sz <= 4 ? sz : 4); + if (sz == 8) + memcpy(buf + 4, &context->regs[PT_D1], 4); + } + return 0; + + default: + assert(!"Unexpected m68k retval type!"); + abort(); + } + + abort(); +} + +void +arch_fetch_arg_done(struct fetch_context *context) +{ + if (context != NULL) + free(context); +} diff --git a/sysdeps/linux-gnu/m68k/plt.c b/sysdeps/linux-gnu/m68k/plt.c index 508d7fc..c1b37dd 100644 --- a/sysdeps/linux-gnu/m68k/plt.c +++ b/sysdeps/linux-gnu/m68k/plt.c @@ -1,10 +1,32 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2004,2008,2009 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include <gelf.h> +#include "proc.h" #include "common.h" +#include "library.h" 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); + * ((lte->ehdr.e_flags & EF_CPU32) ? 24 : 20); } void * diff --git a/sysdeps/linux-gnu/m68k/ptrace.h b/sysdeps/linux-gnu/m68k/ptrace.h index c3cbcb6..ad7e0d6 100644 --- a/sysdeps/linux-gnu/m68k/ptrace.h +++ b/sysdeps/linux-gnu/m68k/ptrace.h @@ -1 +1,21 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2004 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include <sys/ptrace.h> diff --git a/sysdeps/linux-gnu/m68k/regs.c b/sysdeps/linux-gnu/m68k/regs.c index 959a60e..4afdfbb 100644 --- a/sysdeps/linux-gnu/m68k/regs.c +++ b/sysdeps/linux-gnu/m68k/regs.c @@ -1,9 +1,30 @@ +/* + * This file is part of ltrace. + * Copyright (C) 1998,2002,2004,2008,2009 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "config.h" #include <sys/types.h> #include <sys/ptrace.h> #include <asm/ptrace.h> +#include "proc.h" #include "common.h" #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) diff --git a/sysdeps/linux-gnu/m68k/signalent.h b/sysdeps/linux-gnu/m68k/signalent.h index 5395f82..31699db 100644 --- a/sysdeps/linux-gnu/m68k/signalent.h +++ b/sysdeps/linux-gnu/m68k/signalent.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + "SIG_0", /* 0 */ "SIGHUP", /* 1 */ "SIGINT", /* 2 */ diff --git a/sysdeps/linux-gnu/m68k/syscallent.h b/sysdeps/linux-gnu/m68k/syscallent.h index 4d65b39..ceafd2e 100644 --- a/sysdeps/linux-gnu/m68k/syscallent.h +++ b/sysdeps/linux-gnu/m68k/syscallent.h @@ -1,4 +1,25 @@ - "0", /* 0 */ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Andreas Schwab + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + + "restart_syscall", /* 0 */ "exit", /* 1 */ "fork", /* 2 */ "read", /* 3 */ @@ -15,7 +36,7 @@ "mknod", /* 14 */ "chmod", /* 15 */ "chown", /* 16 */ - "break", /* 17 */ + "17", /* 17 */ "oldstat", /* 18 */ "lseek", /* 19 */ "getpid", /* 20 */ @@ -29,11 +50,11 @@ "oldfstat", /* 28 */ "pause", /* 29 */ "utime", /* 30 */ - "stty", /* 31 */ - "gtty", /* 32 */ + "31", /* 31 */ + "32", /* 32 */ "access", /* 33 */ "nice", /* 34 */ - "ftime", /* 35 */ + "35", /* 35 */ "sync", /* 36 */ "kill", /* 37 */ "rename", /* 38 */ @@ -42,7 +63,7 @@ "dup", /* 41 */ "pipe", /* 42 */ "times", /* 43 */ - "prof", /* 44 */ + "44", /* 44 */ "brk", /* 45 */ "setgid", /* 46 */ "getgid", /* 47 */ @@ -51,13 +72,13 @@ "getegid", /* 50 */ "acct", /* 51 */ "umount2", /* 52 */ - "lock", /* 53 */ + "53", /* 53 */ "ioctl", /* 54 */ "fcntl", /* 55 */ - "mpx", /* 56 */ + "56", /* 56 */ "setpgid", /* 57 */ - "ulimit", /* 58 */ - "oldolduname", /* 59 */ + "58", /* 58 */ + "59", /* 59 */ "umask", /* 60 */ "chroot", /* 61 */ "ustat", /* 62 */ @@ -96,10 +117,10 @@ "fchown", /* 95 */ "getpriority", /* 96 */ "setpriority", /* 97 */ - "profil", /* 98 */ + "98", /* 98 */ "statfs", /* 99 */ "fstatfs", /* 100 */ - "ioperm", /* 101 */ + "101", /* 101 */ "socketcall", /* 102 */ "syslog", /* 103 */ "setitimer", /* 104 */ @@ -107,7 +128,7 @@ "stat", /* 106 */ "lstat", /* 107 */ "fstat", /* 108 */ - "olduname", /* 109 */ + "109", /* 109 */ "110", /* 110 */ "vhangup", /* 111 */ "112", /* 112 */ @@ -135,7 +156,7 @@ "bdflush", /* 134 */ "sysfs", /* 135 */ "personality", /* 136 */ - "afs_syscall", /* 137 */ + "137", /* 137 */ "setfsuid", /* 138 */ "setfsgid", /* 139 */ "_llseek", /* 140 */ @@ -276,7 +297,72 @@ "mq_notify", /* 275 */ "mq_getsetattr", /* 276 */ "waitid", /* 277 */ - "vserver", /* 278 */ + "278", /* 278 */ "add_key", /* 279 */ "request_key", /* 280 */ "keyctl", /* 281 */ + "ioprio_set", /* 282 */ + "ioprio_get", /* 283 */ + "inotify_init", /* 284 */ + "inotify_add_watch", /* 285 */ + "inotify_rm_watch", /* 286 */ + "migrate_pages", /* 287 */ + "openat", /* 288 */ + "mkdirat", /* 289 */ + "mknodat", /* 290 */ + "fchownat", /* 291 */ + "futimesat", /* 292 */ + "fstatat64", /* 293 */ + "unlinkat", /* 294 */ + "renameat", /* 295 */ + "linkat", /* 296 */ + "symlinkat", /* 297 */ + "readlinkat", /* 298 */ + "fchmodat", /* 299 */ + "faccessat", /* 300 */ + "pselect6", /* 301 */ + "ppoll", /* 302 */ + "unshare", /* 303 */ + "set_robust_list", /* 304 */ + "get_robust_list", /* 305 */ + "splice", /* 306 */ + "sync_file_range", /* 307 */ + "tee", /* 308 */ + "vmsplice", /* 309 */ + "move_pages", /* 310 */ + "sched_setaffinity", /* 311 */ + "sched_getaffinity", /* 312 */ + "kexec_load", /* 313 */ + "getcpu", /* 314 */ + "epoll_pwait", /* 315 */ + "utimensat", /* 316 */ + "signalfd", /* 317 */ + "timerfd_create", /* 318 */ + "eventfd", /* 319 */ + "fallocate", /* 320 */ + "timerfd_settime", /* 321 */ + "timerfd_gettime", /* 322 */ + "signalfd4", /* 323 */ + "eventfd2", /* 324 */ + "epoll_create1", /* 325 */ + "dup3", /* 326 */ + "pipe2", /* 327 */ + "inotify_init1", /* 328 */ + "preadv", /* 329 */ + "pwritev", /* 330 */ + "rt_tgsigqueueinfo", /* 331 */ + "perf_event_open", /* 332 */ + "get_thread_area", /* 333 */ + "set_thread_area", /* 334 */ + "atomic_cmpxchg_32", /* 335 */ + "atomic_barrier", /* 336 */ + "fanotify_init", /* 337 */ + "fanotify_mark", /* 338 */ + "prlimit64", /* 339 */ + "name_to_handle_at", /* 340 */ + "open_by_handle_at", /* 341 */ + "clock_adjtime", /* 342 */ + "syncfs", /* 343 */ + "setns", /* 344 */ + "process_vm_readv", /* 345 */ + "process_vm_writev", /* 346 */ diff --git a/sysdeps/linux-gnu/m68k/trace.c b/sysdeps/linux-gnu/m68k/trace.c index 2f89fdf..311ffd5 100644 --- a/sysdeps/linux-gnu/m68k/trace.c +++ b/sysdeps/linux-gnu/m68k/trace.c @@ -1,3 +1,25 @@ +/* + * This file is part of ltrace. + * Copyright (C) 1998,2001,2004,2008,2009 Juan Cespedes + * Copyright (C) 2009 Juan Cespedes + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "config.h" #include <sys/types.h> @@ -6,6 +28,7 @@ #include <sys/ptrace.h> #include <asm/ptrace.h> +#include "proc.h" #include "common.h" #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) @@ -44,46 +67,3 @@ syscall_p(Process *proc, int status, int *sysnum) { } return 0; } - -long -gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { - 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 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); - } -#else - /* That hack works on m68k, too */ - return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, 0); -#endif - } else { - fprintf(stderr, "gimme_arg called with wrong arguments\n"); - exit(1); - } - - return 0; -} - -void -save_register_args(enum tof type, Process *proc) { -} diff --git a/sysdeps/linux-gnu/mipsel/Doxyfile b/sysdeps/linux-gnu/mipsel/Doxyfile index b4f5eb2..165f929 100644 --- a/sysdeps/linux-gnu/mipsel/Doxyfile +++ b/sysdeps/linux-gnu/mipsel/Doxyfile @@ -1,3 +1,21 @@ +# This file is part of ltrace. +# Copyright (C) 2006 Eric Vaitl, Cisco Systems, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + # Doxyfile 1.5.1 #--------------------------------------------------------------------------- diff --git a/sysdeps/linux-gnu/mipsel/Makefile b/sysdeps/linux-gnu/mipsel/Makefile deleted file mode 100644 index 44f4aae..0000000 --- a/sysdeps/linux-gnu/mipsel/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -.PHONY: all deps clean docs - -OBJ = trace.o regs.o plt.o -SRC=$(OBJ:.o=.c) - -all: arch.o - -deps: - $(CC) $(CFLAGS) $(CPPFLAGS) -M $(SRC) > .depends - -arch.o: $(OBJ) arch.h - $(CC) -nostdlib -r -o arch.o $(OBJ) - -clean: - -rm -f $(OBJ) arch.o - -rm -rf html - -docs: - doxygen - - --include .depends diff --git a/sysdeps/linux-gnu/mipsel/Makefile.am b/sysdeps/linux-gnu/mipsel/Makefile.am new file mode 100644 index 0000000..9cf8f19 --- /dev/null +++ b/sysdeps/linux-gnu/mipsel/Makefile.am @@ -0,0 +1,38 @@ +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ + trace.c + +noinst_HEADERS = \ + arch.h \ + mipsel.h \ + ptrace.h \ + signalent.h \ + syscallent.h + +EXTRA_DIST = \ + Doxyfile + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/sysdeps/linux-gnu/mipsel/Makefile.in b/sysdeps/linux-gnu/mipsel/Makefile.in new file mode 100644 index 0000000..f0a1b06 --- /dev/null +++ b/sysdeps/linux-gnu/mipsel/Makefile.in @@ -0,0 +1,532 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = sysdeps/linux-gnu/mipsel +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/m4/libtool.m4 \ + $(top_srcdir)/config/m4/ltoptions.m4 \ + $(top_srcdir)/config/m4/ltsugar.m4 \ + $(top_srcdir)/config/m4/ltversion.m4 \ + $(top_srcdir)/config/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +___libcpu_la_LIBADD = +am____libcpu_la_OBJECTS = plt.lo regs.lo trace.lo +___libcpu_la_OBJECTS = $(am____libcpu_la_OBJECTS) +am__dirstamp = $(am__leading_dot)dirstamp +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/autoconf/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(___libcpu_la_SOURCES) +DIST_SOURCES = $(___libcpu_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_VALGRIND = @HAVE_VALGRIND@ +HOST_CPU = @HOST_CPU@ +HOST_OS = @HOST_OS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libelf_LD_LIBRARY_PATH = @libelf_LD_LIBRARY_PATH@ +liberty_LIBS = @liberty_LIBS@ +libexecdir = @libexecdir@ +libstdcxx_LIBS = @libstdcxx_LIBS@ +libsupcxx_LIBS = @libsupcxx_LIBS@ +libunwind_LD_LIBRARY_PATH = @libunwind_LD_LIBRARY_PATH@ +libunwind_LIBS = @libunwind_LIBS@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ + trace.c + +noinst_HEADERS = \ + arch.h \ + mipsel.h \ + ptrace.h \ + signalent.h \ + syscallent.h + +EXTRA_DIST = \ + Doxyfile + +MAINTAINERCLEANFILES = \ + Makefile.in + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign sysdeps/linux-gnu/mipsel/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign sysdeps/linux-gnu/mipsel/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +../$(am__dirstamp): + @$(MKDIR_P) .. + @: > ../$(am__dirstamp) +../libcpu.la: $(___libcpu_la_OBJECTS) $(___libcpu_la_DEPENDENCIES) ../$(am__dirstamp) + $(LINK) $(___libcpu_la_OBJECTS) $(___libcpu_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf ../.libs ../_libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f ../$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sysdeps/linux-gnu/mipsel/arch.h b/sysdeps/linux-gnu/mipsel/arch.h index dd0ca35..684b546 100644 --- a/sysdeps/linux-gnu/mipsel/arch.h +++ b/sysdeps/linux-gnu/mipsel/arch.h @@ -1,9 +1,67 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Eric Vaitl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef LTRACE_MIPS_ARCH_H +#define LTRACE_MIPS_ARCH_H + +#include <stddef.h> +#include <gelf.h> + #define BREAKPOINT_VALUE { 0x0d, 0x00, 0x00, 0x00 } #define BREAKPOINT_LENGTH 4 #define DECR_PC_AFTER_BREAK 0 +#define ARCH_ENDIAN_LITTLE #define LT_ELFCLASS ELFCLASS32 #define LT_ELF_MACHINE EM_MIPS -#define PLTs_INIT_BY_HERE "_start" -#define E_ENTRY_NAME "_start" +#define ARCH_HAVE_LTELF_DATA +struct arch_ltelf_data { + size_t pltgot_addr; + size_t mips_local_gotno; + size_t mips_gotsym; +}; + +#define ARCH_HAVE_FIND_DL_DEBUG +#define ARCH_HAVE_GET_SYMINFO +#define ARCH_HAVE_DYNLINK_DONE +#define ARCH_HAVE_ADD_PLT_ENTRY +#define ARCH_HAVE_ATOMIC_SINGLESTEP +#define ARCH_HAVE_SYMBOL_RET + +#define ARCH_HAVE_LIBRARY_SYMBOL_DATA +enum mips_plt_type +{ + MIPS_PLT_UNRESOLVED, + MIPS_PLT_RESOLVED, +}; + +struct arch_library_symbol_data { + enum mips_plt_type type; + GElf_Addr resolved_addr; + GElf_Addr stub_addr; + + /* Set for FUNCs that have GOT entries but not PLT entries. */ + int gotonly : 1; + /* Set for FUNCs that have PLT entries that are always used. */ + int pltalways : 1; +}; + +#endif /* LTRACE_MIPS_ARCH_H */ diff --git a/sysdeps/linux-gnu/mipsel/mipsel.h b/sysdeps/linux-gnu/mipsel/mipsel.h index a63cafd..a2dbda2 100644 --- a/sysdeps/linux-gnu/mipsel/mipsel.h +++ b/sysdeps/linux-gnu/mipsel/mipsel.h @@ -1,11 +1,33 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2010 Arnaud Patard, Mandriva SA + * Copyright (C) 2006 Eric Vaitl, Cisco Systems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #ifndef MIPSEL_h #define MIPSEL_h -// linux-2.4.30/arch/mips/kernel/ptrace.c for these offsets. +// asm/ptrace.h for these offsets. #define off_v0 2 #define off_pc 64 #define off_a0 4 #define off_a3 7 #define off_lr 31 +#define off_fpr0 32 #define off_sp 29 #endif // MIPSEL_h diff --git a/sysdeps/linux-gnu/mipsel/plt.c b/sysdeps/linux-gnu/mipsel/plt.c index 003171b..b277fbc 100644 --- a/sysdeps/linux-gnu/mipsel/plt.c +++ b/sysdeps/linux-gnu/mipsel/plt.c @@ -1,13 +1,51 @@ -#include <debug.h> +/* + * This file is part of ltrace. + * Copyright (C) 2012 Edgar E. Iglesias, Axis Communications + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2008,2009 Juan Cespedes + * Copyright (C) 2006 Eric Vaitl, Cisco Systems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include <string.h> +#include <error.h> +#include <errno.h> #include <gelf.h> #include <sys/ptrace.h> + #include "common.h" +#include "debug.h" +#include "proc.h" +#include "library.h" +#include "breakpoint.h" +#include "backend.h" /** \addtogroup mipsel @{ */ +/* Are we in pure CPIC mode (the non-PIC ABI extension)? */ +static inline int +mips_elf_is_cpic(unsigned int elf_flags) +{ + return (elf_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC; +} + /** \param lte Structure containing link table entry information \param ndx Index into .dynsym @@ -32,10 +70,19 @@ */ GElf_Addr -arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { - debug(1,"plt_addr %x ndx %#x",lte->pltgot_addr, ndx); - return lte->pltgot_addr + - sizeof(void *) * (lte->mips_local_gotno + (ndx - lte->mips_gotsym)); +arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela) +{ + debug(1,"plt_addr %zx ndx %#zx",lte->arch.pltgot_addr, ndx); + + if (mips_elf_is_cpic(lte->ehdr.e_flags)) { + /* Return a pointer into the PLT. */ + return lte->plt_addr + 16 * 2 + (ndx * 16); + } + + /* Return a pointer to a GOT entry. */ + return lte->arch.pltgot_addr + + sizeof(void *) * (lte->arch.mips_local_gotno + + (ndx - lte->arch.mips_gotsym)); } /** \param proc The process to work on. @@ -59,6 +106,12 @@ arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { void * sym2addr(Process *proc, struct library_symbol *sym) { long ret; + + if (sym->arch.pltalways + || (!sym->arch.gotonly && sym->plt_type == LS_TOPLT_NONE)) { + return sym->enter_addr; + } + if(!proc->pid){ return 0; } @@ -69,4 +122,304 @@ sym2addr(Process *proc, struct library_symbol *sym) { return (void *)ret;; } +/* Address of run time loader map, used for debugging. */ +#define DT_MIPS_RLD_MAP 0x70000016 +int +arch_find_dl_debug(struct Process *proc, arch_addr_t dyn_addr, + arch_addr_t *ret) +{ + arch_addr_t rld_addr; + int r; + + /* MIPS puts the address of the r_debug structure into the + * DT_MIPS_RLD_MAP entry instead of into the DT_DEBUG entry. */ + r = proc_find_dynamic_entry_addr(proc, dyn_addr, + DT_MIPS_RLD_MAP, &rld_addr); + if (r == 0) { + if (umovebytes(proc, rld_addr, + ret, sizeof *ret) != sizeof *ret) { + r = -1; + } + } + return r; +} + + +/* + * MIPS doesn't have traditional got.plt entries with corresponding + * relocations. + * + * sym_index is an offset into the external GOT entries. Filter out + * stuff that are not functions. + */ +int +arch_get_sym_info(struct ltelf *lte, const char *filename, + size_t sym_index, GElf_Rela *rela, GElf_Sym *sym) +{ + const char *name; + + if (mips_elf_is_cpic(lte->ehdr.e_flags)) { + return elf_get_sym_info(lte, filename, sym_index, rela, sym); + } + + /* Fixup the offset. */ + sym_index += lte->arch.mips_gotsym; + + if (gelf_getsym(lte->dynsym, sym_index, sym) == NULL){ + error(EXIT_FAILURE, 0, + "Couldn't get relocation from \"%s\"", filename); + } + + name = lte->dynstr + sym->st_name; + if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) { + debug(2, "sym %s not a function", name); + return -1; + } + + return 0; +} + +/** + MIPS ABI Supplement: + + DT_PLTGOT This member holds the address of the .got section. + + DT_MIPS_SYMTABNO This member holds the number of entries in the + .dynsym section. + + DT_MIPS_LOCAL_GOTNO This member holds the number of local global + offset table entries. + + DT_MIPS_GOTSYM This member holds the index of the first dyamic + symbol table entry that corresponds to an entry in the gobal offset + table. + + */ +int +arch_elf_init(struct ltelf *lte, struct library *lib) +{ + Elf_Scn *scn; + GElf_Shdr shdr; + + /* FIXME: for CPIC we should really scan both GOT tables + * to pick up relocations to external functions. Right now + * function pointers from the main binary to external functions + * can't be traced in CPIC mode. */ + if (mips_elf_is_cpic(lte->ehdr.e_flags)) { + return 0; /* We are already done. */ + } + + if (elf_get_section_type(lte, SHT_DYNAMIC, &scn, &shdr) < 0 + || scn == NULL) { + fail: + error(0, 0, "Couldn't get SHT_DYNAMIC: %s", + elf_errmsg(-1)); + return -1; + } + + Elf_Data *data = elf_loaddata(scn, &shdr); + if (data == NULL) + goto fail; + + size_t j; + for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) { + GElf_Dyn dyn; + if (gelf_getdyn(data, j, &dyn) == NULL) + goto fail; + + if(dyn.d_tag == DT_PLTGOT) { + lte->arch.pltgot_addr = dyn.d_un.d_ptr; + } + if(dyn.d_tag == DT_MIPS_LOCAL_GOTNO){ + lte->arch.mips_local_gotno = dyn.d_un.d_val; + } + if(dyn.d_tag == DT_MIPS_GOTSYM){ + lte->arch.mips_gotsym = dyn.d_un.d_val; + } + } + + /* Tell the generic code how many dynamic trace:able symbols + * we've got. */ + lte->relplt_count = lte->dynsym_count - lte->arch.mips_gotsym; + return 0; +} + +void +arch_elf_destroy(struct ltelf *lte) +{ +} + +/* When functions return we check if the symbol needs an updated + breakpoint with the resolved address. */ +void arch_symbol_ret(struct Process *proc, struct library_symbol *libsym) +{ + struct breakpoint *bp; + arch_addr_t resolved_addr; + struct Process *leader = proc->leader; + + /* Only deal with unresolved symbols. */ + if (libsym->arch.type != MIPS_PLT_UNRESOLVED) + return; + + /* Get out if we are always using the PLT. */ + if (libsym->arch.pltalways) + return; + + resolved_addr = sym2addr(proc, libsym); + libsym->arch.resolved_addr = (uintptr_t) resolved_addr; + libsym->arch.type = MIPS_PLT_RESOLVED; + + if (libsym->arch.stub_addr == libsym->arch.resolved_addr) { + /* Prelinked symbol. No need to add new breakpoint. */ + return; + } + + bp = malloc(sizeof (*bp)); + if (bp == NULL) { + fprintf(stderr, "Failed to allocate bp for %s\n", + libsym->name); + return; + } + + if (breakpoint_init(bp, leader, resolved_addr, libsym) < 0) + goto err; + + if (proc_add_breakpoint(leader, bp) < 0) { + breakpoint_destroy(bp); + goto err; + } + + if (breakpoint_turn_on(bp, leader) < 0) { + proc_remove_breakpoint(leader, bp); + breakpoint_destroy(bp); + goto err; + } + return; +err: + free(bp); +} + +static enum callback_status +cb_enable_breakpoint_sym(struct library_symbol *libsym, void *data) +{ + struct Process *proc = data; + arch_addr_t bp_addr; + + if (!libsym->arch.gotonly) + return CBS_CONT; + + /* Update state. */ + bp_addr = sym2addr(proc, libsym); + /* XXX The cast to uintptr_t should be removed when + * arch_addr_t becomes integral type. keywords: double cast. */ + libsym->arch.resolved_addr = (uintptr_t) bp_addr; + + if (libsym->arch.resolved_addr == 0) + /* FIXME: What does this mean? */ + return CBS_CONT; + + libsym->arch.type = MIPS_PLT_RESOLVED; + + /* Now, activate the symbol causing a breakpoint to be added. */ + if (proc_activate_delayed_symbol(proc, libsym) < 0) { + fprintf(stderr, "Failed to activate delayed sym %s\n", + libsym->name); + } + return CBS_CONT; +} + +static enum callback_status +cb_enable_breakpoint_lib(struct Process *proc, struct library *lib, void *data) +{ + library_each_symbol(lib, NULL, cb_enable_breakpoint_sym, proc); + return CBS_CONT; +} + +void arch_dynlink_done(struct Process *proc) +{ + proc_each_library(proc->leader, NULL, cb_enable_breakpoint_lib, NULL); +} + +enum plt_status +arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte, + const char *a_name, GElf_Rela *rela, size_t ndx, + struct library_symbol **ret) +{ + char *name = NULL; + int sym_index = ndx + lte->arch.mips_gotsym; + + struct library_symbol *libsym = malloc(sizeof(*libsym)); + if (libsym == NULL) + return plt_fail; + + GElf_Addr addr = arch_plt_sym_val(lte, sym_index, 0); + + name = strdup(a_name); + if (name == NULL) { + fprintf(stderr, "%s: failed %s(%#llx): %s\n", __func__, + name, addr, strerror(errno)); + goto fail; + } + + /* XXX The double cast should be removed when + * arch_addr_t becomes integral type. */ + if (library_symbol_init(libsym, + (arch_addr_t) (uintptr_t) addr, + name, 1, LS_TOPLT_EXEC) < 0) { + fprintf(stderr, "%s: failed %s : %llx\n", __func__, name, addr); + goto fail; + } + + arch_addr_t bp_addr = sym2addr(proc, libsym); + /* XXX This cast should be removed when + * arch_addr_t becomes integral type. keywords: double cast. */ + libsym->arch.stub_addr = (uintptr_t) bp_addr; + + if (bp_addr == 0) { + /* Function pointers without PLT entries. */ + libsym->plt_type = LS_TOPLT_NONE; + libsym->arch.gotonly = 1; + libsym->arch.type = MIPS_PLT_UNRESOLVED; + + /* Delay breakpoint activation until the symbol gets + * resolved. */ + libsym->delayed = 1; + } else if (mips_elf_is_cpic(lte->ehdr.e_flags)) { + libsym->arch.pltalways = 1; + } + + *ret = libsym; + return plt_ok; + +fail: + free(name); + free(libsym); + return plt_fail; +} + +int +arch_library_symbol_init(struct library_symbol *libsym) +{ + libsym->arch.pltalways = 0; + libsym->arch.gotonly = 0; + libsym->arch.type = MIPS_PLT_UNRESOLVED; + if (libsym->plt_type == LS_TOPLT_NONE) { + libsym->arch.type = MIPS_PLT_RESOLVED; + } + return 0; +} + +void +arch_library_symbol_destroy(struct library_symbol *libsym) +{ +} + +int +arch_library_symbol_clone(struct library_symbol *retp, + struct library_symbol *libsym) +{ + retp->arch = libsym->arch; + return 0; +} + /**@}*/ diff --git a/sysdeps/linux-gnu/mipsel/ptrace.h b/sysdeps/linux-gnu/mipsel/ptrace.h index c3cbcb6..00c8673 100644 --- a/sysdeps/linux-gnu/mipsel/ptrace.h +++ b/sysdeps/linux-gnu/mipsel/ptrace.h @@ -1 +1,21 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Eric Vaitl, Cisco Systems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include <sys/ptrace.h> diff --git a/sysdeps/linux-gnu/mipsel/regs.c b/sysdeps/linux-gnu/mipsel/regs.c index a7a6de1..8731ac5 100644 --- a/sysdeps/linux-gnu/mipsel/regs.c +++ b/sysdeps/linux-gnu/mipsel/regs.c @@ -1,11 +1,32 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2008,2009 Juan Cespedes + * Copyright (C) 2006 Eric Vaitl, Cisco Systems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "config.h" #include <stddef.h> #include <sys/types.h> #include <sys/ptrace.h> #include <asm/ptrace.h> -#include <linux/user.h> +#include "proc.h" #include "common.h" #include "mipsel.h" diff --git a/sysdeps/linux-gnu/mipsel/signalent.h b/sysdeps/linux-gnu/mipsel/signalent.h index 6bb1ff6..d779af5 100644 --- a/sysdeps/linux-gnu/mipsel/signalent.h +++ b/sysdeps/linux-gnu/mipsel/signalent.h @@ -1,32 +1,52 @@ -"SIG_0", /* 0 */ - "SIGHUP", // 1 /* Hangup (POSIX). */ - "SIGINT", // 2 /* Interrupt (ANSI). */ - "SIGQUIT", // 3 /* Quit (POSIX). */ - "SIGILL", // 4 /* Illegal instruction (ANSI). */ - "SIGTRAP", // 5 /* Trace trap (POSIX). */ - "SIGIOT", // 6 /* IOT trap (4.2 BSD). */ - "SIGEMT", // 7 - "SIGFPE", // 8 /* Floating-point exception (ANSI). */ - "SIGKILL", // 9 /* Kill, unblockable (POSIX). */ - "SIGBUS", // 10 /* BUS error (4.2 BSD). */ - "SIGSEGV", // 11 /* Segmentation violation (ANSI). */ - "SIGSYS", // 12 - "SIGPIPE", // 13 /* Broken pipe (POSIX). */ - "SIGALRM", // 14 /* Alarm clock (POSIX). */ - "SIGTERM", // 15 /* Termination (ANSI). */ - "SIGUSR1", // 16 /* User-defined signal 1 (POSIX). */ - "SIGUSR2", // 17 /* User-defined signal 2 (POSIX). */ - "SIGCHLD", // 18 /* Child status has changed (POSIX). */ - "SIGPWR", // 19 /* Power failure restart (System V). */ - "SIGWINCH", // 20 /* Window size change (4.3 BSD, Sun). */ - "SIGURG", // 21 /* Urgent condition on socket (4.2 BSD). */ - "SIGIO", // 22 /* I/O now possible (4.2 BSD). */ - "SIGSTOP", // 23 /* Stop, unblockable (POSIX). */ - "SIGTSTP", // 24 /* Keyboard stop (POSIX). */ - "SIGCONT", // 25 /* Continue (POSIX). */ - "SIGTTIN", // 26 /* Background read from tty (POSIX). */ - "SIGTTOU", // 27 /* Background write to tty (POSIX). */ - "SIGVTALRM", // 28 /* Virtual alarm clock (4.2 BSD). */ - "SIGPROF", // 29 /* Profiling alarm clock (4.2 BSD). */ - "SIGXCPU", // 30 /* CPU limit exceeded (4.2 BSD). */ - "SIGXFSZ", // 31 /* File size limit exceeded (4.2 BSD). */ +/* + * This file is part of ltrace. + * Copyright (C) 2010 Arnaud Patard, Mandriva SA + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + + "SIG_0", /* 0 */ + "SIGHUP", /* 1 */ + "SIGINT", /* 2 */ + "SIGQUIT", /* 3 */ + "SIGILL", /* 4 */ + "SIGTRAP", /* 5 */ + "SIGIOT", /* 6 */ + "SIGEMT", /* 7 */ + "SIGFPE", /* 8 */ + "SIGKILL", /* 9 */ + "SIGBUS", /* 10 */ + "SIGSEGV", /* 11 */ + "SIGSYS", /* 12 */ + "SIGPIPE", /* 13 */ + "SIGALRM", /* 14 */ + "SIGTERM", /* 15 */ + "SIGUSR1", /* 16 */ + "SIGUSR2", /* 17 */ + "SIGCHLD", /* 18 */ + "SIGPWR", /* 19 */ + "SIGWINCH", /* 20 */ + "SIGURG", /* 21 */ + "SIGIO", /* 22 */ + "SIGSTOP", /* 23 */ + "SIGTSTP", /* 24 */ + "SIGCONT", /* 25 */ + "SIGTTIN", /* 26 */ + "SIGTTOU", /* 27 */ + "SIGVTALRM", /* 28 */ + "SIGPROF", /* 29 */ + "SIGXCPU", /* 30 */ + "SIGXFSZ", /* 31 */ diff --git a/sysdeps/linux-gnu/mipsel/syscallent.h b/sysdeps/linux-gnu/mipsel/syscallent.h index bed43fe..c0e5dd6 100644 --- a/sysdeps/linux-gnu/mipsel/syscallent.h +++ b/sysdeps/linux-gnu/mipsel/syscallent.h @@ -1,241 +1,368 @@ - "0", /*Linux + 0*/ - "exit", /*Linux + 1*/ - "fork", /*Linux + 2*/ - "read", /*Linux + 3*/ - "write", /*Linux + 4*/ - "open", /*Linux + 5*/ - "close", /*Linux + 6*/ - "waitpid", /*Linux + 7*/ - "creat", /*Linux + 8*/ - "link", /*Linux + 9*/ - "unlink", /*Linux + 10*/ - "execve", /*Linux + 11*/ - "chdir", /*Linux + 12*/ - "time", /*Linux + 13*/ - "mknod", /*Linux + 14*/ - "chmod", /*Linux + 15*/ - "lchown", /*Linux + 16*/ - "break", /*Linux + 17*/ - "unused18", /*Linux + 18*/ - "lseek", /*Linux + 19*/ - "getpid", /*Linux + 20*/ - "mount", /*Linux + 21*/ - "umount", /*Linux + 22*/ - "setuid", /*Linux + 23*/ - "getuid", /*Linux + 24*/ - "stime", /*Linux + 25*/ - "ptrace", /*Linux + 26*/ - "alarm", /*Linux + 27*/ - "unused28", /*Linux + 28*/ - "pause", /*Linux + 29*/ - "utime", /*Linux + 30*/ - "stty", /*Linux + 31*/ - "gtty", /*Linux + 32*/ - "access", /*Linux + 33*/ - "nice", /*Linux + 34*/ - "ftime", /*Linux + 35*/ - "sync", /*Linux + 36*/ - "kill", /*Linux + 37*/ - "rename", /*Linux + 38*/ - "mkdir", /*Linux + 39*/ - "rmdir", /*Linux + 40*/ - "dup", /*Linux + 41*/ - "pipe", /*Linux + 42*/ - "times", /*Linux + 43*/ - "prof", /*Linux + 44*/ - "brk", /*Linux + 45*/ - "setgid", /*Linux + 46*/ - "getgid", /*Linux + 47*/ - "signal", /*Linux + 48*/ - "geteuid", /*Linux + 49*/ - "getegid", /*Linux + 50*/ - "acct", /*Linux + 51*/ - "umount2", /*Linux + 52*/ - "lock", /*Linux + 53*/ - "ioctl", /*Linux + 54*/ - "fcntl", /*Linux + 55*/ - "mpx", /*Linux + 56*/ - "setpgid", /*Linux + 57*/ - "ulimit", /*Linux + 58*/ - "unused59", /*Linux + 59*/ - "umask", /*Linux + 60*/ - "chroot", /*Linux + 61*/ - "ustat", /*Linux + 62*/ - "dup2", /*Linux + 63*/ - "getppid", /*Linux + 64*/ - "getpgrp", /*Linux + 65*/ - "setsid", /*Linux + 66*/ - "sigaction", /*Linux + 67*/ - "sgetmask", /*Linux + 68*/ - "ssetmask", /*Linux + 69*/ - "setreuid", /*Linux + 70*/ - "setregid", /*Linux + 71*/ - "sigsuspend", /*Linux + 72*/ - "sigpending", /*Linux + 73*/ - "sethostname", /*Linux + 74*/ - "setrlimit", /*Linux + 75*/ - "getrlimit", /*Linux + 76*/ - "getrusage", /*Linux + 77*/ - "gettimeofday", /*Linux + 78*/ - "settimeofday", /*Linux + 79*/ - "getgroups", /*Linux + 80*/ - "setgroups", /*Linux + 81*/ - "reserved82", /*Linux + 82*/ - "symlink", /*Linux + 83*/ - "unused84", /*Linux + 84*/ - "readlink", /*Linux + 85*/ - "uselib", /*Linux + 86*/ - "swapon", /*Linux + 87*/ - "reboot", /*Linux + 88*/ - "readdir", /*Linux + 89*/ - "mmap", /*Linux + 90*/ - "munmap", /*Linux + 91*/ - "truncate", /*Linux + 92*/ - "ftruncate", /*Linux + 93*/ - "fchmod", /*Linux + 94*/ - "fchown", /*Linux + 95*/ - "getpriority", /*Linux + 96*/ - "setpriority", /*Linux + 97*/ - "profil", /*Linux + 98*/ - "statfs", /*Linux + 99*/ - "fstatfs", /*Linux + 100*/ - "ioperm", /*Linux + 101*/ - "socketcall", /*Linux + 102*/ - "syslog", /*Linux + 103*/ - "setitimer", /*Linux + 104*/ - "getitimer", /*Linux + 105*/ - "stat", /*Linux + 106*/ - "lstat", /*Linux + 107*/ - "fstat", /*Linux + 108*/ - "unused109", /*Linux + 109*/ - "iopl", /*Linux + 110*/ - "vhangup", /*Linux + 111*/ - "idle", /*Linux + 112*/ - "vm86", /*Linux + 113*/ - "wait4", /*Linux + 114*/ - "swapoff", /*Linux + 115*/ - "sysinfo", /*Linux + 116*/ - "ipc", /*Linux + 117*/ - "fsync", /*Linux + 118*/ - "sigreturn", /*Linux + 119*/ - "clone", /*Linux + 120*/ - "setdomainname", /*Linux + 121*/ - "uname", /*Linux + 122*/ - "modify_ldt", /*Linux + 123*/ - "adjtimex", /*Linux + 124*/ - "mprotect", /*Linux + 125*/ - "sigprocmask", /*Linux + 126*/ - "create_module", /*Linux + 127*/ - "init_module", /*Linux + 128*/ - "delete_module", /*Linux + 129*/ - "get_kernel_syms", /*Linux + 130*/ - "quotactl", /*Linux + 131*/ - "getpgid", /*Linux + 132*/ - "fchdir", /*Linux + 133*/ - "bdflush", /*Linux + 134*/ - "sysfs", /*Linux + 135*/ - "personality", /*Linux + 136*/ - "afs_syscall", /*Linux + 137*/ /* Syscall for Andrew File System */ - "setfsuid", /*Linux + 138*/ - "setfsgid", /*Linux + 139*/ - "_llseek", /*Linux + 140*/ - "getdents", /*Linux + 141*/ - "_newselect", /*Linux + 142*/ - "flock", /*Linux + 143*/ - "msync", /*Linux + 144*/ - "readv", /*Linux + 145*/ - "writev", /*Linux + 146*/ - "cacheflush", /*Linux + 147*/ - "cachectl", /*Linux + 148*/ - "sysmips", /*Linux + 149*/ - "unused150", /*Linux + 150*/ - "getsid", /*Linux + 151*/ - "fdatasync", /*Linux + 152*/ - "_sysctl", /*Linux + 153*/ - "mlock", /*Linux + 154*/ - "munlock", /*Linux + 155*/ - "mlockall", /*Linux + 156*/ - "munlockall", /*Linux + 157*/ - "sched_setparam", /*Linux + 158*/ - "sched_getparam", /*Linux + 159*/ - "sched_setscheduler", /*Linux + 160*/ - "sched_getscheduler", /*Linux + 161*/ - "sched_yield", /*Linux + 162*/ - "sched_get_priority_max", /*Linux + 163*/ - "sched_get_priority_min", /*Linux + 164*/ - "sched_rr_get_interval", /*Linux + 165*/ - "nanosleep", /*Linux + 166*/ - "mremap", /*Linux + 167*/ - "accept", /*Linux + 168*/ - "bind", /*Linux + 169*/ - "connect", /*Linux + 170*/ - "getpeername", /*Linux + 171*/ - "getsockname", /*Linux + 172*/ - "getsockopt", /*Linux + 173*/ - "listen", /*Linux + 174*/ - "recv", /*Linux + 175*/ - "recvfrom", /*Linux + 176*/ - "recvmsg", /*Linux + 177*/ - "send", /*Linux + 178*/ - "sendmsg", /*Linux + 179*/ - "sendto", /*Linux + 180*/ - "setsockopt", /*Linux + 181*/ - "shutdown", /*Linux + 182*/ - "socket", /*Linux + 183*/ - "socketpair", /*Linux + 184*/ - "setresuid", /*Linux + 185*/ - "getresuid", /*Linux + 186*/ - "query_module", /*Linux + 187*/ - "poll", /*Linux + 188*/ - "nfsservctl", /*Linux + 189*/ - "setresgid", /*Linux + 190*/ - "getresgid", /*Linux + 191*/ - "prctl", /*Linux + 192*/ - "rt_sigreturn", /*Linux + 193*/ - "rt_sigaction", /*Linux + 194*/ - "rt_sigprocmask", /*Linux + 195*/ - "rt_sigpending", /*Linux + 196*/ - "rt_sigtimedwait", /*Linux + 197*/ - "rt_sigqueueinfo", /*Linux + 198*/ - "rt_sigsuspend", /*Linux + 199*/ - "pread", /*Linux + 200*/ - "pwrite", /*Linux + 201*/ - "chown", /*Linux + 202*/ - "getcwd", /*Linux + 203*/ - "capget", /*Linux + 204*/ - "capset", /*Linux + 205*/ - "sigaltstack", /*Linux + 206*/ - "sendfile", /*Linux + 207*/ - "getpmsg", /*Linux + 208*/ - "putpmsg", /*Linux + 209*/ - "mmap2", /*Linux + 210*/ - "truncate64", /*Linux + 211*/ - "ftruncate64", /*Linux + 212*/ - "stat64", /*Linux + 213*/ - "lstat64", /*Linux + 214*/ - "fstat64", /*Linux + 215*/ - "pivot_root", /*Linux + 216*/ - "mincore", /*Linux + 217*/ - "madvise", /*Linux + 218*/ - "getdents64", /*Linux + 219*/ - "fcntl64", /*Linux + 220*/ - "security", /*Linux + 221*/ - "gettid", /*Linux + 222*/ - "readahead", /*Linux + 223*/ - "setxattr", /*Linux + 224*/ - "lsetxattr", /*Linux + 225*/ - "fsetxattr", /*Linux + 226*/ - "getxattr", /*Linux + 227*/ - "lgetxattr", /*Linux + 228*/ - "fgetxattr", /*Linux + 229*/ - "listxattr", /*Linux + 230*/ - "llistxattr", /*Linux + 231*/ - "flistxattr", /*Linux + 232*/ - "removexattr", /*Linux + 233*/ - "lremovexattr", /*Linux + 234*/ - "fremovexattr", /*Linux + 235*/ - "tkill", /*Linux + 236*/ - "sendfile64", /*Linux + 237*/ - "futex", /*Linux + 238*/ - "sched_setaffinity", /*Linux + 239*/ - "sched_getaffinity", /*Linux + 240*/ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2010 Arnaud Patard, Mandriva SA + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + + "syscall", /* 0 */ + "exit", /* 1 */ + "fork", /* 2 */ + "read", /* 3 */ + "write", /* 4 */ + "open", /* 5 */ + "close", /* 6 */ + "waitpid", /* 7 */ + "creat", /* 8 */ + "link", /* 9 */ + "unlink", /* 10 */ + "execve", /* 11 */ + "chdir", /* 12 */ + "time", /* 13 */ + "mknod", /* 14 */ + "chmod", /* 15 */ + "lchown", /* 16 */ + "break", /* 17 */ + "unused18", /* 18 */ + "lseek", /* 19 */ + "getpid", /* 20 */ + "mount", /* 21 */ + "umount", /* 22 */ + "setuid", /* 23 */ + "getuid", /* 24 */ + "stime", /* 25 */ + "ptrace", /* 26 */ + "alarm", /* 27 */ + "unused28", /* 28 */ + "pause", /* 29 */ + "utime", /* 30 */ + "stty", /* 31 */ + "gtty", /* 32 */ + "access", /* 33 */ + "nice", /* 34 */ + "ftime", /* 35 */ + "sync", /* 36 */ + "kill", /* 37 */ + "rename", /* 38 */ + "mkdir", /* 39 */ + "rmdir", /* 40 */ + "dup", /* 41 */ + "pipe", /* 42 */ + "times", /* 43 */ + "prof", /* 44 */ + "brk", /* 45 */ + "setgid", /* 46 */ + "getgid", /* 47 */ + "signal", /* 48 */ + "geteuid", /* 49 */ + "getegid", /* 50 */ + "acct", /* 51 */ + "umount2", /* 52 */ + "lock", /* 53 */ + "ioctl", /* 54 */ + "fcntl", /* 55 */ + "mpx", /* 56 */ + "setpgid", /* 57 */ + "ulimit", /* 58 */ + "unused59", /* 59 */ + "umask", /* 60 */ + "chroot", /* 61 */ + "ustat", /* 62 */ + "dup2", /* 63 */ + "getppid", /* 64 */ + "getpgrp", /* 65 */ + "setsid", /* 66 */ + "sigaction", /* 67 */ + "sgetmask", /* 68 */ + "ssetmask", /* 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 */ + "reserved82", /* 82 */ + "symlink", /* 83 */ + "unused84", /* 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 */ + "profil", /* 98 */ + "statfs", /* 99 */ + "fstatfs", /* 100 */ + "ioperm", /* 101 */ + "socketcall", /* 102 */ + "syslog", /* 103 */ + "setitimer", /* 104 */ + "getitimer", /* 105 */ + "stat", /* 106 */ + "lstat", /* 107 */ + "fstat", /* 108 */ + "unused109", /* 109 */ + "iopl", /* 110 */ + "vhangup", /* 111 */ + "idle", /* 112 */ + "vm86", /* 113 */ + "wait4", /* 114 */ + "swapoff", /* 115 */ + "sysinfo", /* 116 */ + "ipc", /* 117 */ + "fsync", /* 118 */ + "sigreturn", /* 119 */ + "clone", /* 120 */ + "setdomainname", /* 121 */ + "uname", /* 122 */ + "modify_ldt", /* 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 */ + "cacheflush", /* 147 */ + "cachectl", /* 148 */ + "sysmips", /* 149 */ + "unused150", /* 150 */ + "getsid", /* 151 */ + "fdatasync", /* 152 */ + "_sysctl", /* 153 */ + "mlock", /* 154 */ + "munlock", /* 155 */ + "mlockall", /* 156 */ + "munlockall", /* 157 */ + "sched_setparam", /* 158 */ + "sched_getparam", /* 159 */ + "sched_setscheduler", /* 160 */ + "sched_getscheduler", /* 161 */ + "sched_yield", /* 162 */ + "sched_get_priority_max", /* 163 */ + "sched_get_priority_min", /* 164 */ + "sched_rr_get_interval", /* 165 */ + "nanosleep", /* 166 */ + "mremap", /* 167 */ + "accept", /* 168 */ + "bind", /* 169 */ + "connect", /* 170 */ + "getpeername", /* 171 */ + "getsockname", /* 172 */ + "getsockopt", /* 173 */ + "listen", /* 174 */ + "recv", /* 175 */ + "recvfrom", /* 176 */ + "recvmsg", /* 177 */ + "send", /* 178 */ + "sendmsg", /* 179 */ + "sendto", /* 180 */ + "setsockopt", /* 181 */ + "shutdown", /* 182 */ + "socket", /* 183 */ + "socketpair", /* 184 */ + "setresuid", /* 185 */ + "getresuid", /* 186 */ + "query_module", /* 187 */ + "poll", /* 188 */ + "nfsservctl", /* 189 */ + "setresgid", /* 190 */ + "getresgid", /* 191 */ + "prctl", /* 192 */ + "rt_sigreturn", /* 193 */ + "rt_sigaction", /* 194 */ + "rt_sigprocmask", /* 195 */ + "rt_sigpending", /* 196 */ + "rt_sigtimedwait", /* 197 */ + "rt_sigqueueinfo", /* 198 */ + "rt_sigsuspend", /* 199 */ + "pread64", /* 200 */ + "pwrite64", /* 201 */ + "chown", /* 202 */ + "getcwd", /* 203 */ + "capget", /* 204 */ + "capset", /* 205 */ + "sigaltstack", /* 206 */ + "sendfile", /* 207 */ + "getpmsg", /* 208 */ + "putpmsg", /* 209 */ + "mmap2", /* 210 */ + "truncate64", /* 211 */ + "ftruncate64", /* 212 */ + "stat64", /* 213 */ + "lstat64", /* 214 */ + "fstat64", /* 215 */ + "pivot_root", /* 216 */ + "mincore", /* 217 */ + "madvise", /* 218 */ + "getdents64", /* 219 */ + "fcntl64", /* 220 */ + "reserved221", /* 221 */ + "gettid", /* 222 */ + "readahead", /* 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 */ + "tkill", /* 236 */ + "sendfile64", /* 237 */ + "futex", /* 238 */ + "sched_setaffinity", /* 239 */ + "sched_getaffinity", /* 240 */ + "io_setup", /* 241 */ + "io_destroy", /* 242 */ + "io_getevents", /* 243 */ + "io_submit", /* 244 */ + "io_cancel", /* 245 */ + "exit_group", /* 246 */ + "lookup_dcookie", /* 247 */ + "epoll_create", /* 248 */ + "epoll_ctl", /* 249 */ + "epoll_wait", /* 250 */ + "remap_file_pages", /* 251 */ + "set_tid_address", /* 252 */ + "restart_syscall", /* 253 */ + "fadvise64", /* 254 */ + "statfs64", /* 255 */ + "fstatfs64", /* 256 */ + "timer_create", /* 257 */ + "timer_settime", /* 258 */ + "timer_gettime", /* 259 */ + "timer_getoverrun", /* 260 */ + "timer_delete", /* 261 */ + "clock_settime", /* 262 */ + "clock_gettime", /* 263 */ + "clock_getres", /* 264 */ + "clock_nanosleep", /* 265 */ + "tgkill", /* 266 */ + "utimes", /* 267 */ + "mbind", /* 268 */ + "get_mempolicy", /* 269 */ + "set_mempolicy", /* 270 */ + "mq_open", /* 271 */ + "mq_unlink", /* 272 */ + "mq_timedsend", /* 273 */ + "mq_timedreceive", /* 274 */ + "mq_notify", /* 275 */ + "mq_getsetattr", /* 276 */ + "vserver", /* 277 */ + "waitid", /* 278 */ + "279", /* 279 */ + "add_key", /* 280 */ + "request_key", /* 281 */ + "keyctl", /* 282 */ + "set_thread_area", /* 283 */ + "inotify_init", /* 284 */ + "inotify_add_watch", /* 285 */ + "inotify_rm_watch", /* 286 */ + "migrate_pages", /* 287 */ + "openat", /* 288 */ + "mkdirat", /* 289 */ + "mknodat", /* 290 */ + "fchownat", /* 291 */ + "futimesat", /* 292 */ + "fstatat64", /* 293 */ + "unlinkat", /* 294 */ + "renameat", /* 295 */ + "linkat", /* 296 */ + "symlinkat", /* 297 */ + "readlinkat", /* 298 */ + "fchmodat", /* 299 */ + "faccessat", /* 300 */ + "pselect6", /* 301 */ + "ppoll", /* 302 */ + "unshare", /* 303 */ + "splice", /* 304 */ + "sync_file_range", /* 305 */ + "tee", /* 306 */ + "vmsplice", /* 307 */ + "move_pages", /* 308 */ + "set_robust_list", /* 309 */ + "get_robust_list", /* 310 */ + "kexec_load", /* 311 */ + "getcpu", /* 312 */ + "epoll_pwait", /* 313 */ + "ioprio_set", /* 314 */ + "ioprio_get", /* 315 */ + "utimensat", /* 316 */ + "signalfd", /* 317 */ + "timerfd", /* 318 */ + "eventfd", /* 319 */ + "fallocate", /* 320 */ + "timerfd_create", /* 321 */ + "timerfd_gettime", /* 322 */ + "timerfd_settime", /* 323 */ + "signalfd4", /* 324 */ + "eventfd2", /* 325 */ + "epoll_create1", /* 326 */ + "dup3", /* 327 */ + "pipe2", /* 328 */ + "inotify_init1", /* 329 */ + "preadv", /* 330 */ + "pwritev", /* 331 */ + "rt_tgsigqueueinfo", /* 332 */ + "perf_event_open", /* 333 */ + "accept4", /* 334 */ + "recvmmsg", /* 335 */ + "fanotify_init", /* 336 */ + "fanotify_mark", /* 337 */ + "prlimit64", /* 338 */ + "name_to_handle_at", /* 339 */ + "open_by_handle_at", /* 340 */ + "clock_adjtime", /* 341 */ + "syncfs", /* 342 */ + "sendmmsg", /* 343 */ + "setns", /* 344 */ + "process_vm_readv", /* 345 */ + "process_vm_writev", /* 346 */ diff --git a/sysdeps/linux-gnu/mipsel/trace.c b/sysdeps/linux-gnu/mipsel/trace.c index ff94930..db9ec21 100644 --- a/sysdeps/linux-gnu/mipsel/trace.c +++ b/sysdeps/linux-gnu/mipsel/trace.c @@ -1,3 +1,26 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Edgar E. Iglesias, Axis Communications + * Copyright (C) 2010 Arnaud Patard, Mandriva SA + * Copyright (C) 2008,2009 Juan Cespedes + * Copyright (C) 2006 Eric Vaitl, Cisco Systems, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "config.h" #include <sys/types.h> @@ -5,9 +28,15 @@ #include <signal.h> #include <sys/ptrace.h> #include <asm/ptrace.h> -#include "debug.h" +#include <assert.h> + +#include "backend.h" #include "common.h" +#include "debug.h" #include "mipsel.h" +#include "proc.h" +#include "type.h" + #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) # define PTRACE_PEEKUSER PTRACE_PEEKUSR #endif @@ -88,6 +117,177 @@ syscall_p(Process *proc, int status, int *sysnum) { } return 0; } + +/* Based on GDB code. */ +#define mips32_op(x) (x >> 26) +#define itype_op(x) (x >> 26) +#define itype_rs(x) ((x >> 21) & 0x1f) +#define itype_rt(x) ((x >> 16) & 0x1f) +#define itype_immediate(x) (x & 0xffff) + +#define jtype_op(x) (x >> 26) +#define jtype_target(x) (x & 0x03ffffff) + +#define rtype_op(x) (x >> 26) +#define rtype_rs(x) ((x >> 21) & 0x1f) +#define rtype_rt(x) ((x >> 16) & 0x1f) +#define rtype_rd(x) ((x >> 11) & 0x1f) +#define rtype_shamt(x) ((x >> 6) & 0x1f) +#define rtype_funct(x) (x & 0x3f) + +static int32_t +mips32_relative_offset (uint32_t inst) +{ + return ((itype_immediate(inst) ^ 0x8000) - 0x8000) << 2; +} + +int mips_next_pcs(struct Process *proc, uint32_t pc, uint32_t *newpc) +{ + uint32_t inst, rx; + int op; + int rn; + int nr = 0; + + inst = ptrace(PTRACE_PEEKTEXT, proc->pid, pc, 0); + + if ((inst & 0xe0000000) != 0) { + /* Check for branches. */ + if (itype_op(inst) >> 2 == 5) { + /* BEQL, BNEL, BLEZL, BGTZL: bits 0101xx */ + op = (itype_op(inst) & 0x03); + switch (op) + { + case 0: /* BEQL */ + case 1: /* BNEL */ + case 2: /* BLEZL */ + case 3: /* BGTZL */ + newpc[nr++] = pc + 8; + newpc[nr++] = pc + 4 + + mips32_relative_offset(inst); + break; + default: + newpc[nr++] = pc + 4; + break; + } + } else if (itype_op(inst) == 17 && itype_rs(inst) == 8) { + /* Step over the branch. */ + newpc[nr++] = pc + 8; + newpc[nr++] = pc + mips32_relative_offset(inst) + 4; + } else { + newpc[nr++] = pc + 4; + } + } else { + /* Further subdivide into SPECIAL, REGIMM and other. */ + switch (op = itype_op(inst) & 0x07) + { + case 0: + op = rtype_funct(inst); + switch (op) + { + case 8: /* JR */ + case 9: /* JALR */ + rn = rtype_rs(inst); + + rx = ptrace(PTRACE_PEEKUSER,proc->pid, rn, 0); + newpc[nr++] = rx; + break; + default: + case 12: /* SYSCALL */ + newpc[nr++] = pc + 4; + break; + } + break; + case 1: + op = itype_rt(inst); + switch (op) + { + case 0: + case 1: + case 2: + case 3: + case 16: + case 17: + case 18: + case 19: + newpc[nr++] = pc + 8; + newpc[nr++] = pc + 4 + + mips32_relative_offset(inst); + break; + default: + newpc[nr++] = pc + 4; + break; + } + break; + case 2: /* J */ + case 3: /* JAL */ + rx = jtype_target(inst) << 2; + /* Upper four bits get never changed... */ + newpc[nr++] = rx + ((pc + 4) & ~0x0fffffff); + break; + case 4: /* BEQ */ + if (itype_rs(inst) == itype_rt(inst)) { + /* Compare the same reg for equality, always + * follow the branch. */ + newpc[nr++] = pc + 4 + + mips32_relative_offset(inst); + break; + } + /* Fall through. */ + default: + case 5: + case 6: + case 7: + /* Step over the branch. */ + newpc[nr++] = pc + 8; + newpc[nr++] = pc + mips32_relative_offset(inst) + 4; + break; + } + } + if (nr <= 0 || nr > 2) + goto fail; + if (nr == 2) { + if (newpc[1] == 0) + goto fail; + } + if (newpc[0] == 0) + goto fail; + + assert(nr == 1 || nr == 2); + return nr; + +fail: + printf("nr=%d pc=%x\n", nr, pc); + printf("pc=%x %x\n", newpc[0], newpc[1]); + return 0; +} + +int +arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp, + int (*add_cb)(void *addr, void *data), + void *add_cb_data) +{ + uint32_t pc = (uint32_t) get_instruction_pointer(proc); + uint32_t newpcs[2]; + int nr; + + nr = mips_next_pcs(proc, pc, newpcs); + + while (nr-- > 0) { + arch_addr_t baddr = (arch_addr_t) newpcs[nr]; + /* Not sure what to do here. We've already got a bp? */ + if (dict_find_entry(proc->leader->breakpoints, baddr) != NULL) { + fprintf(stderr, "skip %p %p\n", baddr, add_cb_data); + continue; + } + + if (add_cb(baddr, add_cb_data) < 0) + return -1; + } + + ptrace(PTRACE_SYSCALL, proc->pid, 0, 0); + return 0; +} + /** \param type Function/syscall call or return. \param proc The process that had an event. @@ -117,51 +317,61 @@ I'm not doing any floating point support here. */ long -gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { +gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info) +{ long ret; + long addr; debug(2,"type %d arg %d",type,arg_num); - if (type == LT_TOF_FUNCTION || type == LT_TOF_SYSCALL){ + if (arg_num == -1) { + if(type == LT_TOF_FUNCTIONR) { + return ptrace(PTRACE_PEEKUSER,proc->pid,off_v0,0); + } + if (type == LT_TOF_SYSCALLR) { + unsigned a3=ptrace(PTRACE_PEEKUSER, proc->pid,off_a3,0); + unsigned v0=ptrace(PTRACE_PEEKUSER, proc->pid,off_v0,0); + if(!a3){ + return v0; + } + return -1; + } + } + if (type == LT_TOF_FUNCTION || type == LT_TOF_SYSCALL) { + /* o32: float args are in f12 and f14 */ + if ((info->type == ARGTYPE_FLOAT) && (arg_num < 2)) { + ret=ptrace(PTRACE_PEEKUSER,proc->pid,off_fpr0+12+arg_num*2,0); + debug(2,"ret = %#lx",ret); + return ret; + } if(arg_num <4){ ret=ptrace(PTRACE_PEEKUSER,proc->pid,off_a0+arg_num,0); debug(2,"ret = %#lx",ret); return ret; } else { - // If we need this, I think we can look at [sp+16] for arg_num==4. - CP; - return 0; + /* not sure it's going to work for something else than syscall */ + addr=ptrace(PTRACE_PEEKUSER,proc->pid,off_sp,0); + if (addr == -1) { + debug(2,"ret = %#lx",addr); + return addr; + } + ret = addr + 4*arg_num; + ret=ptrace(PTRACE_PEEKTEXT,proc->pid,addr,0); + debug(2,"ret = %#lx",ret); + return ret; } } - if(arg_num>=0){ - fprintf(stderr,"args on return?"); - } - if(type == LT_TOF_FUNCTIONR) { - return ptrace(PTRACE_PEEKUSER,proc->pid,off_v0,0); - } - if (type == LT_TOF_SYSCALLR) { - unsigned a3=ptrace(PTRACE_PEEKUSER, proc->pid,off_a3,0); - unsigned v0=ptrace(PTRACE_PEEKUSER, proc->pid,off_v0,0); - if(!a3){ - return v0; + if (type == LT_TOF_FUNCTIONR || type == LT_TOF_SYSCALLR){ + addr=ptrace(PTRACE_PEEKUSER,proc->pid,off_sp,0); + if (addr == -1) { + debug(2,"ret = %#lx",addr); + return addr; } - return -1; + ret = addr + 4*arg_num; + ret=ptrace(PTRACE_PEEKTEXT,proc->pid,addr,0); + debug(2,"ret = %#lx",ret); + return ret; } fprintf(stderr, "gimme_arg called with wrong arguments\n"); return 0; } -/** - \param type Type of call/return - \param proc Process to work with. - - Called by \c output_left(), which is called on a syscall or - function. - - The other architectures stub this out, but seems to be the place to - stash off the arguments on a call so we have them on the return. - -*/ -void -save_register_args(enum tof type, Process *proc) { -} - /**@}*/ diff --git a/sysdeps/linux-gnu/mksignalent b/sysdeps/linux-gnu/mksignalent index 316d81f..b78b692 100755 --- a/sysdeps/linux-gnu/mksignalent +++ b/sysdeps/linux-gnu/mksignalent @@ -1,4 +1,21 @@ #!/usr/bin/awk -f +# This file is part of ltrace. +# Copyright (C) 1999 Juan Cespedes +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA # hack expression to generate arch/signalent.h from <asm/signal.h> # It reads from stdin and writes to stdout diff --git a/sysdeps/linux-gnu/mksyscallent b/sysdeps/linux-gnu/mksyscallent index e0c3ec7..615ff06 100755 --- a/sysdeps/linux-gnu/mksyscallent +++ b/sysdeps/linux-gnu/mksyscallent @@ -1,4 +1,22 @@ #!/usr/bin/awk -f +# This file is part of ltrace. +# Copyright (C) 2006 Ian Wienand +# Copyright (C) 1999 Juan Cespedes +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA # hack expression to generate arch/syscallent.h from <asm/unistd.h> # It reads from stdin and writes to stdout diff --git a/sysdeps/linux-gnu/mksyscallent_s390 b/sysdeps/linux-gnu/mksyscallent_s390 index 73416d9..1964d14 100644 --- a/sysdeps/linux-gnu/mksyscallent_s390 +++ b/sysdeps/linux-gnu/mksyscallent_s390 @@ -1,4 +1,22 @@ #!/usr/bin/perl +# This file is part of ltrace. +# Copyright (C) 2006 Heiko Carstens, IBM Corporation +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + # # Generate syscall table for s390/s390x # diff --git a/sysdeps/linux-gnu/os.h b/sysdeps/linux-gnu/os.h new file mode 100644 index 0000000..62bf38b --- /dev/null +++ b/sysdeps/linux-gnu/os.h @@ -0,0 +1,25 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#define OS_HAVE_PROCESS_DATA +struct os_process_data { + arch_addr_t debug_addr; + int debug_state; +}; diff --git a/sysdeps/linux-gnu/ppc/Makefile b/sysdeps/linux-gnu/ppc/Makefile deleted file mode 100644 index 60d7531..0000000 --- a/sysdeps/linux-gnu/ppc/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -OBJ = trace.o regs.o plt.o - -all: arch.o - -arch.o: $(OBJ) - $(CC) -nostdlib -r -o arch.o $(OBJ) - -clean: - $(RM) $(OBJ) arch.o - diff --git a/sysdeps/linux-gnu/ppc/Makefile.am b/sysdeps/linux-gnu/ppc/Makefile.am new file mode 100644 index 0000000..2239ae3 --- /dev/null +++ b/sysdeps/linux-gnu/ppc/Makefile.am @@ -0,0 +1,36 @@ +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ + trace.c \ + fetch.c + +noinst_HEADERS = \ + arch.h \ + insn.h \ + ptrace.h \ + signalent.h \ + syscallent.h + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/sysdeps/linux-gnu/ppc/Makefile.in b/sysdeps/linux-gnu/ppc/Makefile.in new file mode 100644 index 0000000..bcc9d84 --- /dev/null +++ b/sysdeps/linux-gnu/ppc/Makefile.in @@ -0,0 +1,531 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = sysdeps/linux-gnu/ppc +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/m4/libtool.m4 \ + $(top_srcdir)/config/m4/ltoptions.m4 \ + $(top_srcdir)/config/m4/ltsugar.m4 \ + $(top_srcdir)/config/m4/ltversion.m4 \ + $(top_srcdir)/config/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +___libcpu_la_LIBADD = +am____libcpu_la_OBJECTS = plt.lo regs.lo trace.lo fetch.lo +___libcpu_la_OBJECTS = $(am____libcpu_la_OBJECTS) +am__dirstamp = $(am__leading_dot)dirstamp +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/autoconf/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(___libcpu_la_SOURCES) +DIST_SOURCES = $(___libcpu_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_VALGRIND = @HAVE_VALGRIND@ +HOST_CPU = @HOST_CPU@ +HOST_OS = @HOST_OS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libelf_LD_LIBRARY_PATH = @libelf_LD_LIBRARY_PATH@ +liberty_LIBS = @liberty_LIBS@ +libexecdir = @libexecdir@ +libstdcxx_LIBS = @libstdcxx_LIBS@ +libsupcxx_LIBS = @libsupcxx_LIBS@ +libunwind_LD_LIBRARY_PATH = @libunwind_LD_LIBRARY_PATH@ +libunwind_LIBS = @libunwind_LIBS@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ + trace.c \ + fetch.c + +noinst_HEADERS = \ + arch.h \ + insn.h \ + ptrace.h \ + signalent.h \ + syscallent.h + +MAINTAINERCLEANFILES = \ + Makefile.in + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign sysdeps/linux-gnu/ppc/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign sysdeps/linux-gnu/ppc/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +../$(am__dirstamp): + @$(MKDIR_P) .. + @: > ../$(am__dirstamp) +../libcpu.la: $(___libcpu_la_OBJECTS) $(___libcpu_la_DEPENDENCIES) ../$(am__dirstamp) + $(LINK) $(___libcpu_la_OBJECTS) $(___libcpu_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fetch.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf ../.libs ../_libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f ../$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sysdeps/linux-gnu/ppc/arch.h b/sysdeps/linux-gnu/ppc/arch.h index 711b4a3..fb8768a 100644 --- a/sysdeps/linux-gnu/ppc/arch.h +++ b/sysdeps/linux-gnu/ppc/arch.h @@ -1,3 +1,29 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata + * Copyright (C) 2006 Paul Gilliam + * Copyright (C) 2002,2004 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#ifndef LTRACE_PPC_ARCH_H +#define LTRACE_PPC_ARCH_H + +#include <gelf.h> + #define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 } #define BREAKPOINT_LENGTH 4 #define DECR_PC_AFTER_BREAK 0 @@ -11,14 +37,72 @@ #define ARCH_SUPPORTS_OPD #endif -#define PLT_REINITALISATION_BP "_start" +#define ARCH_HAVE_ATOMIC_SINGLESTEP +#define ARCH_HAVE_ADD_PLT_ENTRY +#define ARCH_HAVE_TRANSLATE_ADDRESS +#define ARCH_HAVE_DYNLINK_DONE +#define ARCH_HAVE_FETCH_ARG +#define ARCH_ENDIAN_BIG +#define ARCH_HAVE_SIZEOF +#define ARCH_HAVE_ALIGNOF -/* Start of arch-specific functions. */ -#define ARCH_HAVE_UMOVELONG +struct library_symbol; -#define PPC_NOP { 0x60, 0x00, 0x00, 0x00 } -#define PPC_NOP_LENGTH 4 +#define ARCH_HAVE_LTELF_DATA +struct arch_ltelf_data { + GElf_Addr plt_stub_vma; + struct library_symbol *stubs; + Elf_Data *opd_data; + GElf_Addr opd_base; + GElf_Xword opd_size; + int secure_plt; +}; -#if (PPC_NOP_LENGTH != BREAKPOINT_LENGTH) -#error "Length of the breakpoint value not equal to the length of a nop instruction" -#endif +#define ARCH_HAVE_LIBRARY_DATA +struct arch_library_data { + GElf_Addr pltgot_addr; + int bss_plt_prelinked; +}; + +enum ppc64_plt_type { + /* Either a non-PLT symbol, or PPC32 symbol. */ + PPC_DEFAULT = 0, + + /* PPC64 STUB, never resolved. */ + PPC64_PLT_STUB, + + /* Unresolved PLT symbol (.plt contains PLT address). */ + PPC_PLT_UNRESOLVED, + + /* Resolved PLT symbol. The corresponding .plt slot contained + * target address, which was changed to the address of + * corresponding PLT entry. The original is now saved in + * RESOLVED_VALUE. */ + PPC_PLT_RESOLVED, +}; + +#define ARCH_HAVE_LIBRARY_SYMBOL_DATA +struct arch_library_symbol_data { + enum ppc64_plt_type type; + GElf_Addr resolved_value; + + /* Address of corresponding slot in .plt. */ + GElf_Addr plt_slot_addr; +}; + +#define ARCH_HAVE_BREAKPOINT_DATA +struct arch_breakpoint_data { + /* We need this just for arch_breakpoint_init. */ +}; + +#define ARCH_HAVE_PROCESS_DATA +struct arch_process_data { + /* Breakpoint that hits when the dynamic linker is about to + * update a .plt slot. NULL before that address is known. */ + struct breakpoint *dl_plt_update_bp; + + /* PLT update breakpoint looks here for the handler. */ + struct process_stopping_handler *handler; +}; + +#endif /* LTRACE_PPC_ARCH_H */ diff --git a/sysdeps/linux-gnu/ppc/fetch.c b/sysdeps/linux-gnu/ppc/fetch.c new file mode 100644 index 0000000..9963a1e --- /dev/null +++ b/sysdeps/linux-gnu/ppc/fetch.c @@ -0,0 +1,436 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include <assert.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ucontext.h> + +#include "backend.h" +#include "fetch.h" +#include "type.h" +#include "ptrace.h" +#include "proc.h" +#include "value.h" + +static int allocate_gpr(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep); + +/* Floating point registers have the same width on 32-bit as well as + * 64-bit PPC, but <ucontext.h> presents a different API depending on + * whether ltrace is PPC32 or PPC64. + * + * This is PPC64 definition. The PPC32 is simply an array of 33 + * doubles, and doesn't contain the terminating pad. Both seem + * compatible enough. */ +struct fpregs_t +{ + double fpregs[32]; + double fpscr; + unsigned int _pad[2]; +}; + +typedef uint32_t gregs32_t[48]; +typedef uint64_t gregs64_t[48]; + +struct fetch_context { + arch_addr_t stack_pointer; + int greg; + int freg; + int ret_struct; + + union { + gregs32_t r32; + gregs64_t r64; + } regs; + struct fpregs_t fpregs; + +}; + +static int +fetch_context_init(struct Process *proc, struct fetch_context *context) +{ + context->greg = 3; + context->freg = 1; + + if (proc->e_machine == EM_PPC) + context->stack_pointer = proc->stack_pointer + 8; + else + context->stack_pointer = proc->stack_pointer + 112; + + /* When ltrace is 64-bit, we might use PTRACE_GETREGS to + * obtain 64-bit as well as 32-bit registers. But if we do it + * this way, 32-bit ltrace can obtain 64-bit registers. + * + * XXX this direction is not supported as of this writing, but + * should be eventually. */ + if (proc->e_machine == EM_PPC64) { + if (ptrace(PTRACE_GETREGS64, proc->pid, 0, + &context->regs.r64) < 0) + return -1; + } else { +#ifdef __powerpc64__ + if (ptrace(PTRACE_GETREGS, proc->pid, 0, + &context->regs.r64) < 0) + return -1; + unsigned i; + for (i = 0; i < sizeof(context->regs.r64)/8; ++i) + context->regs.r32[i] = context->regs.r64[i]; +#else + if (ptrace(PTRACE_GETREGS, proc->pid, 0, + &context->regs.r32) < 0) + return -1; +#endif + } + + if (ptrace(PTRACE_GETFPREGS, proc->pid, 0, &context->fpregs) < 0) + return -1; + + return 0; +} + +struct fetch_context * +arch_fetch_arg_init(enum tof type, struct Process *proc, + struct arg_type_info *ret_info) +{ + struct fetch_context *context = malloc(sizeof(*context)); + if (context == NULL + || fetch_context_init(proc, context) < 0) { + free(context); + return NULL; + } + + /* Aggregates or unions of any length, and character strings + * of length longer than 8 bytes, will be returned in a + * storage buffer allocated by the caller. The caller will + * pass the address of this buffer as a hidden first argument + * in r3, causing the first explicit argument to be passed in + * r4. */ + context->ret_struct = ret_info->type == ARGTYPE_STRUCT; + if (context->ret_struct) + context->greg++; + + return context; +} + +struct fetch_context * +arch_fetch_arg_clone(struct Process *proc, + struct fetch_context *context) +{ + struct fetch_context *clone = malloc(sizeof(*context)); + if (clone == NULL) + return NULL; + *clone = *context; + return clone; +} + +static int +allocate_stack_slot(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep) +{ + size_t sz = type_sizeof(proc, info); + if (sz == (size_t)-1) + return -1; + + size_t a = type_alignof(proc, info); + size_t off = 0; + if (proc->e_machine == EM_PPC && a < 4) + a = 4; + else if (proc->e_machine == EM_PPC64 && a < 8) + a = 8; + + /* XXX Remove the two double casts when arch_addr_t + * becomes integral type. */ + uintptr_t tmp = align((uint64_t)(uintptr_t)ctx->stack_pointer, a); + ctx->stack_pointer = (arch_addr_t)tmp; + + if (valuep != NULL) + value_in_inferior(valuep, ctx->stack_pointer + off); + ctx->stack_pointer += sz; + + return 0; +} + +static uint64_t +read_gpr(struct fetch_context *ctx, struct Process *proc, int reg_num) +{ + if (proc->e_machine == EM_PPC) + return ctx->regs.r32[reg_num]; + else + return ctx->regs.r64[reg_num]; +} + +/* The support for little endian PowerPC is in upstream Linux and BFD, + * and Unix-like Solaris, which we might well support at some point, + * runs PowerPC in little endian as well. This code moves SZ-sized + * value to the beginning of W-sized BUF regardless of + * endian. */ +static void +align_small_int(unsigned char *buf, size_t w, size_t sz) +{ + assert(w == 4 || w == 8); + union { + uint64_t i64; + uint32_t i32; + uint16_t i16; + uint8_t i8; + char buf[0]; + } u; + memcpy(u.buf, buf, w); + if (w == 4) + u.i64 = u.i32; + + switch (sz) { + case 1: + u.i8 = u.i64; + break; + case 2: + u.i16 = u.i64; + break; + case 4: + u.i32 = u.i64; + case 8: + break; + } + + memcpy(buf, u.buf, sz); +} + +static int +allocate_gpr(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep) +{ + if (ctx->greg > 10) + return allocate_stack_slot(ctx, proc, info, valuep); + + int reg_num = ctx->greg++; + if (valuep == NULL) + return 0; + + size_t sz = type_sizeof(proc, info); + if (sz == (size_t)-1) + return -1; + assert(sz == 1 || sz == 2 || sz == 4 || sz == 8); + if (value_reserve(valuep, sz) == NULL) + return -1; + + union { + uint64_t i64; + unsigned char buf[0]; + } u; + + u.i64 = read_gpr(ctx, proc, reg_num); + if (proc->e_machine == EM_PPC) + align_small_int(u.buf, 8, sz); + memcpy(value_get_raw_data(valuep), u.buf, sz); + return 0; +} + +static int +allocate_float(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep) +{ + int pool = proc->e_machine == EM_PPC64 ? 13 : 8; + if (ctx->freg <= pool) { + union { + double d; + float f; + char buf[0]; + } u = { .d = ctx->fpregs.fpregs[ctx->freg] }; + + ctx->freg++; + if (proc->e_machine == EM_PPC64) + allocate_gpr(ctx, proc, info, NULL); + + size_t sz = sizeof(double); + if (info->type == ARGTYPE_FLOAT) { + sz = sizeof(float); + u.f = (float)u.d; + } + + if (value_reserve(valuep, sz) == NULL) + return -1; + + memcpy(value_get_raw_data(valuep), u.buf, sz); + return 0; + } + return allocate_stack_slot(ctx, proc, info, valuep); +} + +static int +allocate_argument(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep) +{ + /* Floating point types and void are handled specially. */ + switch (info->type) { + case ARGTYPE_VOID: + value_set_word(valuep, 0); + return 0; + + case ARGTYPE_FLOAT: + case ARGTYPE_DOUBLE: + return allocate_float(ctx, proc, info, valuep); + + case ARGTYPE_STRUCT: + if (proc->e_machine == EM_PPC) { + if (value_pass_by_reference(valuep) < 0) + return -1; + } else { + /* PPC64: Fixed size aggregates and unions passed by + * value are mapped to as many doublewords of the + * parameter save area as the value uses in memory. + * [...] The first eight doublewords mapped to the + * parameter save area correspond to the registers r3 + * through r10. */ + } + /* fall through */ + case ARGTYPE_CHAR: + case ARGTYPE_SHORT: + case ARGTYPE_USHORT: + case ARGTYPE_INT: + case ARGTYPE_UINT: + case ARGTYPE_LONG: + case ARGTYPE_ULONG: + case ARGTYPE_POINTER: + break; + + case ARGTYPE_ARRAY: + /* Arrays decay into pointers. XXX Fortran? */ + default: + assert(info->type != info->type); + abort(); + } + + unsigned width = proc->e_machine == EM_PPC64 ? 8 : 4; + + /* For other cases (integral types and aggregates), read the + * eightbytes comprising the data. */ + size_t sz = type_sizeof(proc, valuep->type); + if (sz == (size_t)-1) + return -1; + size_t slots = (sz + width - 1) / width; /* Round up. */ + unsigned char *buf = value_reserve(valuep, slots * width); + if (buf == NULL) + return -1; + struct arg_type_info *long_info = type_get_simple(ARGTYPE_LONG); + + unsigned char *ptr = buf; + while (slots-- > 0) { + struct value val; + value_init(&val, proc, NULL, long_info, 0); + + /* Floating point registers [...] are used [...] to + pass [...] one member aggregates passed by value + containing a floating point value[.] Note that for + one member aggregates, "containing" extends to + aggregates within aggregates ad infinitum. */ + int rc; + struct arg_type_info *fp_info + = type_get_fp_equivalent(valuep->type); + if (fp_info != NULL) + rc = allocate_float(ctx, proc, fp_info, &val); + else + rc = allocate_gpr(ctx, proc, long_info, &val); + + if (rc >= 0) { + memcpy(ptr, value_get_data(&val, NULL), width); + ptr += width; + } + value_destroy(&val); + + /* Bail out if we failed or if we are dealing with + * FP-equivalent. Those don't need the adjustments + * made below. */ + if (rc < 0 || fp_info != NULL) + return rc; + } + + /* Small values need post-processing. */ + if (sz < width) { + switch (info->type) { + default: + abort(); + + /* Simple integer types (char, short, int, long, enum) + * are mapped to a single doubleword. Values shorter + * than a doubleword are sign or zero extended as + * necessary. */ + case ARGTYPE_CHAR: + case ARGTYPE_SHORT: + case ARGTYPE_INT: + case ARGTYPE_USHORT: + case ARGTYPE_UINT: + align_small_int(buf, width, sz); + break; + + /* Single precision floating point values are mapped + * to the second word in a single doubleword. + * + * An aggregate or union smaller than one doubleword + * in size is padded so that it appears in the least + * significant bits of the doubleword. */ + case ARGTYPE_FLOAT: + case ARGTYPE_ARRAY: + case ARGTYPE_STRUCT: + memmove(buf, buf + width - sz, sz); + break; + } + } + + return 0; +} + +int +arch_fetch_arg_next(struct fetch_context *ctx, enum tof type, + struct Process *proc, + struct arg_type_info *info, struct value *valuep) +{ + return allocate_argument(ctx, proc, info, valuep); +} + +int +arch_fetch_retval(struct fetch_context *ctx, enum tof type, + struct Process *proc, struct arg_type_info *info, + struct value *valuep) +{ + if (ctx->ret_struct) { + assert(info->type == ARGTYPE_STRUCT); + + uint64_t addr = read_gpr(ctx, proc, 3); + value_init(valuep, proc, NULL, info, 0); + + valuep->where = VAL_LOC_INFERIOR; + /* XXX Remove the double cast when arch_addr_t + * becomes integral type. */ + valuep->u.address = (arch_addr_t)(uintptr_t)addr; + return 0; + } + + if (fetch_context_init(proc, ctx) < 0) + return -1; + return allocate_argument(ctx, proc, info, valuep); +} + +void +arch_fetch_arg_done(struct fetch_context *context) +{ + free(context); +} diff --git a/sysdeps/linux-gnu/ppc/insn.h b/sysdeps/linux-gnu/ppc/insn.h new file mode 100644 index 0000000..cd94b5e --- /dev/null +++ b/sysdeps/linux-gnu/ppc/insn.h @@ -0,0 +1,45 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +/* Instruction masks used during single-stepping of atomic + * sequences. This was lifted from GDB. */ +#define LWARX_MASK 0xfc0007fe +#define LWARX_INSTRUCTION 0x7c000028 +#define LDARX_INSTRUCTION 0x7c0000A8 +#define STWCX_MASK 0xfc0007ff +#define STWCX_INSTRUCTION 0x7c00012d +#define STDCX_INSTRUCTION 0x7c0001ad +#define BRANCH_MASK 0xfc000000 +#define BC_MASK 0xfc000000 +#define BC_INSN 0x40000000 +#define B_INSN 0x48000000 + +static inline arch_addr_t +ppc_branch_dest(arch_addr_t addr, uint32_t insn) +{ + int immediate = ((insn & 0xfffc) ^ 0x8000) - 0x8000; + int absolute = insn & 2; + + /* XXX drop the following double casts. */ + if (absolute) + return (arch_addr_t)(uintptr_t)immediate; + else + return addr + (uintptr_t)immediate; +} diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c index 31830fb..f83f087 100644 --- a/sysdeps/linux-gnu/ppc/plt.c +++ b/sysdeps/linux-gnu/ppc/plt.c @@ -1,54 +1,1038 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2004,2008,2009 Juan Cespedes + * Copyright (C) 2006 Paul Gilliam + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include <gelf.h> +#include <sys/ptrace.h> +#include <errno.h> +#include <inttypes.h> +#include <assert.h> +#include <string.h> + +#include "proc.h" #include "common.h" +#include "insn.h" +#include "library.h" +#include "breakpoint.h" +#include "linux-gnu/trace.h" +#include "backend.h" + +/* There are two PLT types on 32-bit PPC: old-style, BSS PLT, and + * new-style "secure" PLT. We can tell one from the other by the + * flags on the .plt section. If it's +X (executable), it's BSS PLT, + * otherwise it's secure. + * + * BSS PLT works the same way as most architectures: the .plt section + * contains trampolines and we put breakpoints to those. If not + * prelinked, .plt contains zeroes, and dynamic linker fills in the + * initial set of trampolines, which means that we need to delay + * enabling breakpoints until after binary entry point is hit. + * Additionally, after first call, dynamic linker updates .plt with + * branch to resolved address. That means that on first hit, we must + * do something similar to the PPC64 gambit described below. + * + * With secure PLT, the .plt section doesn't contain instructions but + * addresses. The real PLT table is stored in .text. Addresses of + * those PLT entries can be computed, and apart from the fact that + * they are in .text, they are ordinary PLT entries. + * + * 64-bit PPC is more involved. Program linker creates for each + * library call a _stub_ symbol named xxxxxxxx.plt_call.<callee> + * (where xxxxxxxx is a hexadecimal number). That stub does the call + * dispatch: it loads an address of a function to call from the + * section .plt, and branches. PLT entries themselves are essentially + * a curried call to the resolver. When the symbol is resolved, the + * resolver updates the value stored in .plt, and the next time + * around, the stub calls the library function directly. So we make + * at most one trip (none if the binary is prelinked) through each PLT + * entry, and correspondingly that is useless as a breakpoint site. + * + * Note the three confusing terms: stubs (that play the role of PLT + * entries), PLT entries, .plt section. + * + * We first check symbol tables and see if we happen to have stub + * symbols available. If yes we just put breakpoints to those, and + * treat them as usual breakpoints. The only tricky part is realizing + * that there can be more than one breakpoint per symbol. + * + * The case that we don't have the stub symbols available is harder. + * The following scheme uses two kinds of PLT breakpoints: unresolved + * and resolved (to some address). When the process starts (or when + * we attach), we distribute unresolved PLT breakpoints to the PLT + * entries (not stubs). Then we look in .plt, and for each entry + * whose value is different than the corresponding PLT entry address, + * we assume it was already resolved, and convert the breakpoint to + * resolved. We also rewrite the resolved value in .plt back to the + * PLT address. + * + * When a PLT entry hits a resolved breakpoint (which happens because + * we rewrite .plt with the original unresolved addresses), we move + * the instruction pointer to the corresponding address and continue + * the process as if nothing happened. + * + * When unresolved PLT entry is called for the first time, we need to + * catch the new value that the resolver will write to a .plt slot. + * We also need to prevent another thread from racing through and + * taking the branch without ltrace noticing. So when unresolved PLT + * entry hits, we have to stop all threads. We then single-step + * through the resolver, until the .plt slot changes. When it does, + * we treat it the same way as above: convert the PLT breakpoint to + * resolved, and rewrite the .plt value back to PLT address. We then + * start all threads again. + * + * As an optimization, we remember the address where the address was + * resolved, and put a breakpoint there. The next time around (when + * the next PLT entry is to be resolved), instead of single-stepping + * through half the dynamic linker, we just let the thread run and hit + * this breakpoint. When it hits, we know the PLT entry was resolved. + * + * XXX TODO If we have hardware watch point, we might put a read watch + * on .plt slot, and discover the offenders this way. I don't know + * the details, but I assume at most a handful (like, one or two, if + * available at all) addresses may be watched at a time, and thus this + * would be used as an amendment of the above rather than full-on + * solution to PLT tracing on PPC. + */ + +#define PPC_PLT_STUB_SIZE 16 +#define PPC64_PLT_STUB_SIZE 8 //xxx + +static inline int +host_powerpc64() +{ +#ifdef __powerpc64__ + return 1; +#else + return 0; +#endif +} + +int +read_target_4(struct Process *proc, arch_addr_t addr, uint32_t *lp) +{ + unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0); + if (l == -1UL && errno) + return -1; +#ifdef __powerpc64__ + l >>= 32; +#endif + *lp = l; + return 0; +} + +static int +read_target_8(struct Process *proc, arch_addr_t addr, uint64_t *lp) +{ + unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0); + if (l == -1UL && errno) + return -1; + if (host_powerpc64()) { + *lp = l; + } else { + unsigned long l2 = ptrace(PTRACE_PEEKTEXT, proc->pid, + addr + 4, 0); + if (l2 == -1UL && errno) + return -1; + *lp = ((uint64_t)l << 32) | l2; + } + return 0; +} + +int +read_target_long(struct Process *proc, arch_addr_t addr, uint64_t *lp) +{ + if (proc->e_machine == EM_PPC) { + uint32_t w; + int ret = read_target_4(proc, addr, &w); + if (ret >= 0) + *lp = (uint64_t)w; + return ret; + } else { + return read_target_8(proc, addr, lp); + } +} + +static void +mark_as_resolved(struct library_symbol *libsym, GElf_Addr value) +{ + libsym->arch.type = PPC_PLT_RESOLVED; + libsym->arch.resolved_value = value; +} + +void +arch_dynlink_done(struct Process *proc) +{ + /* On PPC32 with BSS PLT, we need to enable delayed symbols. */ + struct library_symbol *libsym = NULL; + while ((libsym = proc_each_symbol(proc, libsym, + library_symbol_delayed_cb, NULL))) { + if (read_target_8(proc, libsym->enter_addr, + &libsym->arch.resolved_value) < 0) { + fprintf(stderr, + "couldn't read PLT value for %s(%p): %s\n", + libsym->name, libsym->enter_addr, + strerror(errno)); + return; + } + + /* arch_dynlink_done is called on attach as well. In + * that case some slots will have been resolved + * already. Unresolved PLT looks like this: + * + * <sleep@plt>: li r11,0 + * <sleep@plt+4>: b "resolve" + * + * "resolve" is another address in PLTGOT (the same + * block that all the PLT slots are it). When + * resolved, it looks either this way: + * + * <sleep@plt>: b 0xfea88d0 <sleep> + * + * Which is easy to detect. It can also look this + * way: + * + * <sleep@plt>: li r11,0 + * <sleep@plt+4>: b "dispatch" + * + * The "dispatch" address lies in PLTGOT as well. In + * current GNU toolchain, "dispatch" address is the + * same as PLTGOT address. We rely on this to figure + * out whether the address is resolved or not. */ + uint32_t insn1 = libsym->arch.resolved_value >> 32; + uint32_t insn2 = (uint32_t)libsym->arch.resolved_value; + if ((insn1 & BRANCH_MASK) == B_INSN + || ((insn2 & BRANCH_MASK) == B_INSN + /* XXX double cast */ + && (ppc_branch_dest(libsym->enter_addr + 4, insn2) + == (void*)(long)libsym->lib->arch.pltgot_addr))) + mark_as_resolved(libsym, libsym->arch.resolved_value); + + if (proc_activate_delayed_symbol(proc, libsym) < 0) + return; + + /* XXX double cast */ + libsym->arch.plt_slot_addr + = (GElf_Addr)(uintptr_t)libsym->enter_addr; + } +} GElf_Addr -arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { - return rela->r_offset; +arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela *rela) +{ + if (lte->ehdr.e_machine == EM_PPC && lte->arch.secure_plt) { + assert(lte->arch.plt_stub_vma != 0); + return lte->arch.plt_stub_vma + PPC_PLT_STUB_SIZE * ndx; + + } else if (lte->ehdr.e_machine == EM_PPC) { + return rela->r_offset; + + } else { + /* If we get here, we don't have stub symbols. In + * that case we put brakpoints to PLT entries the same + * as the PPC32 secure PLT case does. */ + assert(lte->arch.plt_stub_vma != 0); + return lte->arch.plt_stub_vma + PPC64_PLT_STUB_SIZE * ndx; + } +} + +/* This entry point is called when ltelf is not available + * anymore--during runtime. At that point we don't have to concern + * ourselves with bias, as the values in OPD have been resolved + * already. */ +int +arch_translate_address_dyn(struct Process *proc, + arch_addr_t addr, arch_addr_t *ret) +{ + if (proc->e_machine == EM_PPC64) { + uint64_t value; + if (read_target_8(proc, addr, &value) < 0) { + fprintf(stderr, + "dynamic .opd translation of %p: %s\n", + addr, strerror(errno)); + return -1; + } + /* XXX The double cast should be removed when + * arch_addr_t becomes integral type. */ + *ret = (arch_addr_t)(uintptr_t)value; + return 0; + } + + *ret = addr; + return 0; +} + +int +arch_translate_address(struct ltelf *lte, + arch_addr_t addr, arch_addr_t *ret) +{ + if (lte->ehdr.e_machine == EM_PPC64) { + /* XXX The double cast should be removed when + * arch_addr_t becomes integral type. */ + GElf_Xword offset + = (GElf_Addr)(uintptr_t)addr - lte->arch.opd_base; + uint64_t value; + if (elf_read_u64(lte->arch.opd_data, offset, &value) < 0) { + fprintf(stderr, "static .opd translation of %p: %s\n", + addr, elf_errmsg(-1)); + return -1; + } + *ret = (arch_addr_t)(uintptr_t)(value + lte->bias); + return 0; + } + + *ret = addr; + return 0; +} + +static int +load_opd_data(struct ltelf *lte, struct library *lib) +{ + Elf_Scn *sec; + GElf_Shdr shdr; + if (elf_get_section_named(lte, ".opd", &sec, &shdr) < 0) { + fail: + fprintf(stderr, "couldn't find .opd data\n"); + return -1; + } + + lte->arch.opd_data = elf_rawdata(sec, NULL); + if (lte->arch.opd_data == NULL) + goto fail; + + lte->arch.opd_base = shdr.sh_addr + lte->bias; + lte->arch.opd_size = shdr.sh_size; + + return 0; } void * -sym2addr(Process *proc, struct library_symbol *sym) { - void *addr = sym->enter_addr; - long pt_ret; +sym2addr(struct Process *proc, struct library_symbol *sym) +{ + return sym->enter_addr; +} - debug(3, 0); +static GElf_Addr +get_glink_vma(struct ltelf *lte, GElf_Addr ppcgot, Elf_Data *plt_data) +{ + Elf_Scn *ppcgot_sec = NULL; + GElf_Shdr ppcgot_shdr; + if (ppcgot != 0 + && elf_get_section_covering(lte, ppcgot, + &ppcgot_sec, &ppcgot_shdr) < 0) + fprintf(stderr, + "DT_PPC_GOT=%#"PRIx64", but no such section found\n", + ppcgot); - if (sym->plt_type != LS_TOPLT_POINT) { - return addr; + if (ppcgot_sec != NULL) { + Elf_Data *data = elf_loaddata(ppcgot_sec, &ppcgot_shdr); + if (data == NULL || data->d_size < 8 ) { + fprintf(stderr, "couldn't read GOT data\n"); + } else { + // where PPCGOT begins in .got + size_t offset = ppcgot - ppcgot_shdr.sh_addr; + assert(offset % 4 == 0); + uint32_t glink_vma; + if (elf_read_u32(data, offset + 4, &glink_vma) < 0) { + fprintf(stderr, "couldn't read glink VMA" + " address at %zd@GOT\n", offset); + return 0; + } + if (glink_vma != 0) { + debug(1, "PPC GOT glink_vma address: %#" PRIx32, + glink_vma); + return (GElf_Addr)glink_vma; + } + } } - if (proc->pid == 0) { + if (plt_data != NULL) { + uint32_t glink_vma; + if (elf_read_u32(plt_data, 0, &glink_vma) < 0) { + fprintf(stderr, "couldn't read glink VMA address\n"); + return 0; + } + debug(1, ".plt glink_vma address: %#" PRIx32, glink_vma); + return (GElf_Addr)glink_vma; + } + + return 0; +} + +static int +load_dynamic_entry(struct ltelf *lte, int tag, GElf_Addr *valuep) +{ + Elf_Scn *scn; + GElf_Shdr shdr; + if (elf_get_section_type(lte, SHT_DYNAMIC, &scn, &shdr) < 0 + || scn == NULL) { + fail: + fprintf(stderr, "Couldn't get SHT_DYNAMIC: %s\n", + elf_errmsg(-1)); + return -1; + } + + Elf_Data *data = elf_loaddata(scn, &shdr); + if (data == NULL) + goto fail; + + size_t j; + for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) { + GElf_Dyn dyn; + if (gelf_getdyn(data, j, &dyn) == NULL) + goto fail; + + if(dyn.d_tag == tag) { + *valuep = dyn.d_un.d_ptr; + return 0; + } + } + + return -1; +} + +static int +nonzero_data(Elf_Data *data) +{ + /* We are not supposed to get here if there's no PLT. */ + assert(data != NULL); + + unsigned char *buf = data->d_buf; + if (buf == NULL) return 0; + + size_t i; + for (i = 0; i < data->d_size; ++i) + if (buf[i] != 0) + return 1; + return 0; +} + +int +arch_elf_init(struct ltelf *lte, struct library *lib) +{ + if (lte->ehdr.e_machine == EM_PPC64 + && load_opd_data(lte, lib) < 0) + return -1; + + lte->arch.secure_plt = !(lte->plt_flags & SHF_EXECINSTR); + + /* For PPC32 BSS, it is important whether the binary was + * prelinked. If .plt section is NODATA, or if it contains + * zeroes, then this library is not prelinked, and we need to + * delay breakpoints. */ + if (lte->ehdr.e_machine == EM_PPC && !lte->arch.secure_plt) + lib->arch.bss_plt_prelinked = nonzero_data(lte->plt_data); + else + /* For cases where it's irrelevant, initialize the + * value to something conspicuous. */ + lib->arch.bss_plt_prelinked = -1; + + if (lte->ehdr.e_machine == EM_PPC && lte->arch.secure_plt) { + GElf_Addr ppcgot; + if (load_dynamic_entry(lte, DT_PPC_GOT, &ppcgot) < 0) { + fprintf(stderr, "couldn't find DT_PPC_GOT\n"); + return -1; + } + GElf_Addr glink_vma = get_glink_vma(lte, ppcgot, lte->plt_data); + + assert(lte->relplt_size % 12 == 0); + size_t count = lte->relplt_size / 12; // size of RELA entry + lte->arch.plt_stub_vma = glink_vma + - (GElf_Addr)count * PPC_PLT_STUB_SIZE; + debug(1, "stub_vma is %#" PRIx64, lte->arch.plt_stub_vma); + + } else if (lte->ehdr.e_machine == EM_PPC64) { + GElf_Addr glink_vma; + if (load_dynamic_entry(lte, DT_PPC64_GLINK, &glink_vma) < 0) { + fprintf(stderr, "couldn't find DT_PPC64_GLINK\n"); + return -1; + } + + /* The first glink stub starts at offset 32. */ + lte->arch.plt_stub_vma = glink_vma + 32; + + } else { + /* By exhaustion--PPC32 BSS. */ + if (load_dynamic_entry(lte, DT_PLTGOT, + &lib->arch.pltgot_addr) < 0) { + fprintf(stderr, "couldn't find DT_PLTGOT\n"); + return -1; + } + } + + /* On PPC64, look for stub symbols in symbol table. These are + * called: xxxxxxxx.plt_call.callee_name@version+addend. */ + if (lte->ehdr.e_machine == EM_PPC64 + && lte->symtab != NULL && lte->strtab != NULL) { + + /* N.B. We can't simply skip the symbols that we fail + * to read or malloc. There may be more than one stub + * per symbol name, and if we failed in one but + * succeeded in another, the PLT enabling code would + * have no way to tell that something is missing. We + * could work around that, of course, but it doesn't + * seem worth the trouble. So if anything fails, we + * just pretend that we don't have stub symbols at + * all, as if the binary is stripped. */ + + size_t i; + for (i = 0; i < lte->symtab_count; ++i) { + GElf_Sym sym; + if (gelf_getsym(lte->symtab, i, &sym) == NULL) { + struct library_symbol *sym, *next; + fail: + for (sym = lte->arch.stubs; sym != NULL; ) { + next = sym->next; + library_symbol_destroy(sym); + free(sym); + sym = next; + } + lte->arch.stubs = NULL; + break; + } + + const char *name = lte->strtab + sym.st_name; + +#define STUBN ".plt_call." + if ((name = strstr(name, STUBN)) == NULL) + continue; + name += sizeof(STUBN) - 1; +#undef STUBN + + size_t len; + const char *ver = strchr(name, '@'); + if (ver != NULL) { + len = ver - name; + + } else { + /* If there is "+" at all, check that + * the symbol name ends in "+0". */ + const char *add = strrchr(name, '+'); + if (add != NULL) { + assert(strcmp(add, "+0") == 0); + len = add - name; + } else { + len = strlen(name); + } + } + + char *sym_name = strndup(name, len); + struct library_symbol *libsym = malloc(sizeof(*libsym)); + if (sym_name == NULL || libsym == NULL) { + fail2: + free(sym_name); + free(libsym); + goto fail; + } + + /* XXX The double cast should be removed when + * arch_addr_t becomes integral type. */ + arch_addr_t addr = (arch_addr_t) + (uintptr_t)sym.st_value + lte->bias; + if (library_symbol_init(libsym, addr, sym_name, 1, + LS_TOPLT_EXEC) < 0) + goto fail2; + libsym->arch.type = PPC64_PLT_STUB; + libsym->next = lte->arch.stubs; + lte->arch.stubs = libsym; + } + } + + return 0; +} + +static int +read_plt_slot_value(struct Process *proc, GElf_Addr addr, GElf_Addr *valp) +{ + /* On PPC64, we read from .plt, which contains 8 byte + * addresses. On PPC32 we read from .plt, which contains 4 + * byte instructions, but the PLT is two instructions, and + * either can change. */ + uint64_t l; + /* XXX double cast. */ + if (read_target_8(proc, (arch_addr_t)(uintptr_t)addr, &l) < 0) { + fprintf(stderr, "ptrace .plt slot value @%#" PRIx64": %s\n", + addr, strerror(errno)); + return -1; + } + + *valp = (GElf_Addr)l; + return 0; +} + +static int +unresolve_plt_slot(struct Process *proc, GElf_Addr addr, GElf_Addr value) +{ + /* We only modify plt_entry[0], which holds the resolved + * address of the routine. We keep the TOC and environment + * pointers intact. Hence the only adjustment that we need to + * do is to IP. */ + if (ptrace(PTRACE_POKETEXT, proc->pid, addr, value) < 0) { + fprintf(stderr, "failed to unresolve .plt slot: %s\n", + strerror(errno)); + return -1; + } + return 0; +} + +enum plt_status +arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte, + const char *a_name, GElf_Rela *rela, size_t ndx, + struct library_symbol **ret) +{ + if (lte->ehdr.e_machine == EM_PPC) { + if (lte->arch.secure_plt) + return plt_default; + + struct library_symbol *libsym = NULL; + if (default_elf_add_plt_entry(proc, lte, a_name, rela, ndx, + &libsym) < 0) + return plt_fail; + + /* On PPC32 with BSS PLT, delay the symbol until + * dynamic linker is done. */ + assert(!libsym->delayed); + libsym->delayed = 1; + + *ret = libsym; + return plt_ok; + } + + /* PPC64. If we have stubs, we return a chain of breakpoint + * sites, one for each stub that corresponds to this PLT + * entry. */ + struct library_symbol *chain = NULL; + struct library_symbol **symp; + for (symp = <e->arch.stubs; *symp != NULL; ) { + struct library_symbol *sym = *symp; + if (strcmp(sym->name, a_name) != 0) { + symp = &(*symp)->next; + continue; + } + + /* Re-chain the symbol from stubs to CHAIN. */ + *symp = sym->next; + sym->next = chain; + chain = sym; } - if (options.debug >= 3) { - xinfdump(proc->pid, (void *)(((long)addr-32)&0xfffffff0), - sizeof(void*)*8); + if (chain != NULL) { + *ret = chain; + return plt_ok; } - // 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. + /* We don't have stub symbols. Find corresponding .plt slot, + * and check whether it contains the corresponding PLT address + * (or 0 if the dynamic linker hasn't run yet). N.B. we don't + * want read this from ELF file, but from process image. That + * makes a difference if we are attaching to a running + * process. */ - // On a PowerPC-32 system, there are two types of PLTs: secure (new) and - // non-secure (old). For the secure case, the PLT is simply a pointer - // and we can treat it much as we do for the PowerPC-64 case. For the - // non-secure case, the PLT is executable code and we can put the - // break-point right in the PLT. + GElf_Addr plt_entry_addr = arch_plt_sym_val(lte, ndx, rela); + GElf_Addr plt_slot_addr = rela->r_offset; + assert(plt_slot_addr >= lte->plt_addr + || plt_slot_addr < lte->plt_addr + lte->plt_size); - pt_ret = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0); + GElf_Addr plt_slot_value; + if (read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value) < 0) + return plt_fail; + + char *name = strdup(a_name); + struct library_symbol *libsym = malloc(sizeof(*libsym)); + if (name == NULL || libsym == NULL) { + fprintf(stderr, "allocation for .plt slot: %s\n", + strerror(errno)); + fail: + free(name); + free(libsym); + return plt_fail; + } + + /* XXX The double cast should be removed when + * arch_addr_t becomes integral type. */ + if (library_symbol_init(libsym, + (arch_addr_t)(uintptr_t)plt_entry_addr, + name, 1, LS_TOPLT_EXEC) < 0) + goto fail; + libsym->arch.plt_slot_addr = plt_slot_addr; + + if (plt_slot_value == plt_entry_addr || plt_slot_value == 0) { + libsym->arch.type = PPC_PLT_UNRESOLVED; + libsym->arch.resolved_value = plt_entry_addr; - if (proc->mask_32bit) { - // Assume big-endian. - addr = (void *)((pt_ret >> 32) & 0xffffffff); } else { - addr = (void *)pt_ret; + /* Unresolve the .plt slot. If the binary was + * prelinked, this makes the code invalid, because in + * case of prelinked binary, the dynamic linker + * doesn't update .plt[0] and .plt[1] with addresses + * of the resover. But we don't care, we will never + * need to enter the resolver. That just means that + * we have to un-un-resolve this back before we + * detach. */ + + if (unresolve_plt_slot(proc, plt_slot_addr, plt_entry_addr) < 0) { + library_symbol_destroy(libsym); + goto fail; + } + mark_as_resolved(libsym, plt_slot_value); + } + + *ret = libsym; + return plt_ok; +} + +void +arch_elf_destroy(struct ltelf *lte) +{ + struct library_symbol *sym; + for (sym = lte->arch.stubs; sym != NULL; ) { + struct library_symbol *next = sym->next; + library_symbol_destroy(sym); + free(sym); + sym = next; + } +} + +static void +dl_plt_update_bp_on_hit(struct breakpoint *bp, struct Process *proc) +{ + debug(DEBUG_PROCESS, "pid=%d dl_plt_update_bp_on_hit %s(%p)", + proc->pid, breakpoint_name(bp), bp->addr); + struct process_stopping_handler *self = proc->arch.handler; + assert(self != NULL); + + struct library_symbol *libsym = self->breakpoint_being_enabled->libsym; + GElf_Addr value; + if (read_plt_slot_value(proc, libsym->arch.plt_slot_addr, &value) < 0) + return; + + /* On PPC64, we rewrite the slot value. */ + if (proc->e_machine == EM_PPC64) + unresolve_plt_slot(proc, libsym->arch.plt_slot_addr, + libsym->arch.resolved_value); + /* We mark the breakpoint as resolved on both arches. */ + mark_as_resolved(libsym, value); + + /* cb_on_all_stopped looks if HANDLER is set to NULL as a way + * to check that this was run. It's an error if it + * wasn't. */ + proc->arch.handler = NULL; + + breakpoint_turn_off(bp, proc); +} + +static void +cb_on_all_stopped(struct process_stopping_handler *self) +{ + /* Put that in for dl_plt_update_bp_on_hit to see. */ + assert(self->task_enabling_breakpoint->arch.handler == NULL); + self->task_enabling_breakpoint->arch.handler = self; + + linux_ptrace_disable_and_continue(self); +} + +static enum callback_status +cb_keep_stepping_p(struct process_stopping_handler *self) +{ + struct Process *proc = self->task_enabling_breakpoint; + struct library_symbol *libsym = self->breakpoint_being_enabled->libsym; + + GElf_Addr value; + if (read_plt_slot_value(proc, libsym->arch.plt_slot_addr, &value) < 0) + return CBS_FAIL; + + /* In UNRESOLVED state, the RESOLVED_VALUE in fact contains + * the PLT entry value. */ + if (value == libsym->arch.resolved_value) + return CBS_CONT; + + debug(DEBUG_PROCESS, "pid=%d PLT got resolved to value %#"PRIx64, + proc->pid, value); + + /* The .plt slot got resolved! We can migrate the breakpoint + * to RESOLVED and stop single-stepping. */ + if (proc->e_machine == EM_PPC64 + && unresolve_plt_slot(proc, libsym->arch.plt_slot_addr, + libsym->arch.resolved_value) < 0) + return CBS_FAIL; + + /* Resolving on PPC64 consists of overwriting a doubleword in + * .plt. That doubleword is than read back by a stub, and + * jumped on. Hopefully we can assume that double word update + * is done on a single place only, as it contains a final + * address. We still need to look around for any sync + * instruction, but essentially it is safe to optimize away + * the single stepping next time and install a post-update + * breakpoint. + * + * The situation on PPC32 BSS is more complicated. The + * dynamic linker here updates potentially several + * instructions (XXX currently we assume two) and the rules + * are more complicated. Sometimes it's enough to adjust just + * one of the addresses--the logic for generating optimal + * dispatch depends on relative addresses of the .plt entry + * and the jump destination. We can't assume that the some + * instruction block does the update every time. So on PPC32, + * we turn the optimization off and just step through it each + * time. */ + if (proc->e_machine == EM_PPC) + goto done; + + /* Install breakpoint to the address where the change takes + * place. If we fail, then that just means that we'll have to + * singlestep the next time around as well. */ + struct Process *leader = proc->leader; + if (leader == NULL || leader->arch.dl_plt_update_bp != NULL) + goto done; + + /* We need to install to the next instruction. ADDR points to + * a store instruction, so moving the breakpoint one + * instruction forward is safe. */ + arch_addr_t addr = get_instruction_pointer(proc) + 4; + leader->arch.dl_plt_update_bp = insert_breakpoint(proc, addr, NULL); + if (leader->arch.dl_plt_update_bp == NULL) + goto done; + + static struct bp_callbacks dl_plt_update_cbs = { + .on_hit = dl_plt_update_bp_on_hit, + }; + leader->arch.dl_plt_update_bp->cbs = &dl_plt_update_cbs; + + /* Turn it off for now. We will turn it on again when we hit + * the PLT entry that needs this. */ + breakpoint_turn_off(leader->arch.dl_plt_update_bp, proc); + +done: + mark_as_resolved(libsym, value); + + return CBS_STOP; +} + +static void +jump_to_entry_point(struct Process *proc, struct breakpoint *bp) +{ + /* XXX The double cast should be removed when + * arch_addr_t becomes integral type. */ + arch_addr_t rv = (arch_addr_t) + (uintptr_t)bp->libsym->arch.resolved_value; + set_instruction_pointer(proc, rv); +} + +static void +ppc_plt_bp_continue(struct breakpoint *bp, struct Process *proc) +{ + switch (bp->libsym->arch.type) { + struct Process *leader; + void (*on_all_stopped)(struct process_stopping_handler *); + enum callback_status (*keep_stepping_p) + (struct process_stopping_handler *); + + case PPC_DEFAULT: + assert(proc->e_machine == EM_PPC); + assert(bp->libsym != NULL); + assert(bp->libsym->lib->arch.bss_plt_prelinked == 0); + /* Fall through. */ + + case PPC_PLT_UNRESOLVED: + on_all_stopped = NULL; + keep_stepping_p = NULL; + leader = proc->leader; + + if (leader != NULL && leader->arch.dl_plt_update_bp != NULL + && breakpoint_turn_on(leader->arch.dl_plt_update_bp, + proc) >= 0) + on_all_stopped = cb_on_all_stopped; + else + keep_stepping_p = cb_keep_stepping_p; + + if (process_install_stopping_handler + (proc, bp, on_all_stopped, keep_stepping_p, NULL) < 0) { + fprintf(stderr, "ppc_plt_bp_continue: " + "couldn't install event handler\n"); + continue_after_breakpoint(proc, bp); + } + return; + + case PPC_PLT_RESOLVED: + if (proc->e_machine == EM_PPC) { + continue_after_breakpoint(proc, bp); + return; + } + + jump_to_entry_point(proc, bp); + continue_process(proc->pid); + return; + + case PPC64_PLT_STUB: + /* These should never hit here. */ + break; + } + + assert(bp->libsym->arch.type != bp->libsym->arch.type); + abort(); +} + +/* When a process is in a PLT stub, it may have already read the data + * in .plt that we changed. If we detach now, it will jump to PLT + * entry and continue to the dynamic linker, where it will SIGSEGV, + * because zeroth .plt slot is not filled in prelinked binaries, and + * the dynamic linker needs that data. Moreover, the process may + * actually have hit the breakpoint already. This functions tries to + * detect both cases and do any fix-ups necessary to mend this + * situation. */ +static enum callback_status +detach_task_cb(struct Process *task, void *data) +{ + struct breakpoint *bp = data; + + if (get_instruction_pointer(task) == bp->addr) { + debug(DEBUG_PROCESS, "%d at %p, which is PLT slot", + task->pid, bp->addr); + jump_to_entry_point(task, bp); + return CBS_CONT; } - return addr; + /* XXX There's still a window of several instructions where we + * might catch the task inside a stub such that it has already + * read destination address from .plt, but hasn't jumped yet, + * thus avoiding the breakpoint. */ + + return CBS_CONT; +} + +static void +ppc_plt_bp_retract(struct breakpoint *bp, struct Process *proc) +{ + /* On PPC64, we rewrite .plt with PLT entry addresses. This + * needs to be undone. Unfortunately, the program may have + * made decisions based on that value */ + if (proc->e_machine == EM_PPC64 + && bp->libsym != NULL + && bp->libsym->arch.type == PPC_PLT_RESOLVED) { + each_task(proc->leader, NULL, detach_task_cb, bp); + unresolve_plt_slot(proc, bp->libsym->arch.plt_slot_addr, + bp->libsym->arch.resolved_value); + } +} + +void +arch_library_init(struct library *lib) +{ +} + +void +arch_library_destroy(struct library *lib) +{ +} + +void +arch_library_clone(struct library *retp, struct library *lib) +{ +} + +int +arch_library_symbol_init(struct library_symbol *libsym) +{ + /* We set type explicitly in the code above, where we have the + * necessary context. This is for calls from ltrace-elf.c and + * such. */ + libsym->arch.type = PPC_DEFAULT; + return 0; +} + +void +arch_library_symbol_destroy(struct library_symbol *libsym) +{ +} + +int +arch_library_symbol_clone(struct library_symbol *retp, + struct library_symbol *libsym) +{ + retp->arch = libsym->arch; + return 0; +} + +/* For some symbol types, we need to set up custom callbacks. XXX we + * don't need PROC here, we can store the data in BP if it is of + * interest to us. */ +int +arch_breakpoint_init(struct Process *proc, struct breakpoint *bp) +{ + /* Artificial and entry-point breakpoints are plain. */ + if (bp->libsym == NULL || bp->libsym->plt_type != LS_TOPLT_EXEC) + return 0; + + /* On PPC, secure PLT and prelinked BSS PLT are plain. */ + if (proc->e_machine == EM_PPC + && bp->libsym->lib->arch.bss_plt_prelinked != 0) + return 0; + + /* On PPC64, stub PLT breakpoints are plain. */ + if (proc->e_machine == EM_PPC64 + && bp->libsym->arch.type == PPC64_PLT_STUB) + return 0; + + static struct bp_callbacks cbs = { + .on_continue = ppc_plt_bp_continue, + .on_retract = ppc_plt_bp_retract, + }; + breakpoint_set_callbacks(bp, &cbs); + return 0; +} + +void +arch_breakpoint_destroy(struct breakpoint *bp) +{ +} + +int +arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp) +{ + retp->arch = sbp->arch; + return 0; +} + +int +arch_process_init(struct Process *proc) +{ + proc->arch.dl_plt_update_bp = NULL; + proc->arch.handler = NULL; + return 0; +} + +void +arch_process_destroy(struct Process *proc) +{ +} + +int +arch_process_clone(struct Process *retp, struct Process *proc) +{ + retp->arch = proc->arch; + return 0; +} + +int +arch_process_exec(struct Process *proc) +{ + return arch_process_init(proc); } diff --git a/sysdeps/linux-gnu/ppc/ptrace.h b/sysdeps/linux-gnu/ppc/ptrace.h index c3cbcb6..57c230c 100644 --- a/sysdeps/linux-gnu/ppc/ptrace.h +++ b/sysdeps/linux-gnu/ppc/ptrace.h @@ -1 +1,21 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2010 Petr Machata, Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include <sys/ptrace.h> diff --git a/sysdeps/linux-gnu/ppc/regs.c b/sysdeps/linux-gnu/ppc/regs.c index eca58ff..37f89a4 100644 --- a/sysdeps/linux-gnu/ppc/regs.c +++ b/sysdeps/linux-gnu/ppc/regs.c @@ -1,9 +1,34 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2002,2008,2009 Juan Cespedes + * Copyright (C) 2009 Juan Cespedes + * Copyright (C) 2008 Luis Machado, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "config.h" #include <sys/types.h> #include <sys/ptrace.h> #include <asm/ptrace.h> +#include <errno.h> +#include <error.h> +#include "proc.h" #include "common.h" #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) @@ -20,8 +45,10 @@ get_instruction_pointer(Process *proc) { } void -set_instruction_pointer(Process *proc, void *addr) { - ptrace(PTRACE_POKEUSER, proc->pid, sizeof(long)*PT_NIP, addr); +set_instruction_pointer(Process *proc, void *addr) +{ + if (ptrace(PTRACE_POKEUSER, proc->pid, sizeof(long)*PT_NIP, addr) != 0) + error(0, errno, "set_instruction_pointer"); } void * diff --git a/sysdeps/linux-gnu/ppc/signalent.h b/sysdeps/linux-gnu/ppc/signalent.h index d58a36c..9b8baa0 100644 --- a/sysdeps/linux-gnu/ppc/signalent.h +++ b/sysdeps/linux-gnu/ppc/signalent.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + "SIG_0", /* 0 */ "SIGHUP", /* 1 */ "SIGINT", /* 2 */ diff --git a/sysdeps/linux-gnu/ppc/syscallent.h b/sysdeps/linux-gnu/ppc/syscallent.h index 5ce5739..6989e81 100644 --- a/sysdeps/linux-gnu/ppc/syscallent.h +++ b/sysdeps/linux-gnu/ppc/syscallent.h @@ -1,4 +1,25 @@ -"0", /* 0 */ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + + "restart_syscall", /* 0 */ "exit", /* 1 */ "fork", /* 2 */ "read", /* 3 */ @@ -177,8 +198,8 @@ "rt_sigtimedwait", /* 176 */ "rt_sigqueueinfo", /* 177 */ "rt_sigsuspend", /* 178 */ - "pread", /* 179 */ - "pwrite", /* 180 */ + "pread64", /* 179 */ + "pwrite64", /* 180 */ "chown", /* 181 */ "getcwd", /* 182 */ "capget", /* 183 */ @@ -254,6 +275,12 @@ "fstatfs64", /* 253 */ "fadvise64_64", /* 254 */ "rtas", /* 255 */ + "sys_debug_setcontext", /* 256 */ + "server", /* 257 */ + "migrate_pages", /* 258 */ + "mbind", /* 259 */ + "get_mempolicy", /* 260 */ + "set_mempolicy", /* 261 */ "mq_open", /* 262 */ "mq_unlink", /* 263 */ "mq_timedsend", /* 264 */ @@ -270,3 +297,78 @@ "inotify_init", /* 275 */ "inotify_add_watch", /* 276 */ "inotify_rm_watch", /* 277 */ + "spu_run", /* 278 */ + "spu_create", /* 279 */ + "pselect6", /* 280 */ + "ppoll", /* 281 */ + "unshare", /* 282 */ + "splice", /* 283 */ + "tee", /* 284 */ + "vmsplice", /* 285 */ + "openat", /* 286 */ + "mkdirat", /* 287 */ + "mknodat", /* 288 */ + "fchownat", /* 289 */ + "futimesat", /* 290 */ + "fstatat64", /* 291 */ + "unlinkat", /* 292 */ + "renameat", /* 293 */ + "linkat", /* 294 */ + "symlinkat", /* 295 */ + "readlinkat", /* 296 */ + "fchmodat", /* 297 */ + "faccessat", /* 298 */ + "get_robust_list", /* 299 */ + "set_robust_list", /* 300 */ + "move_pages", /* 301 */ + "getcpu", /* 302 */ + "epoll_pwait", /* 303 */ + "utimensat", /* 304 */ + "signalfd", /* 305 */ + "timerfd_create", /* 306 */ + "eventfd", /* 307 */ + "sync_file_range2", /* 308 */ + "fallocate", /* 309 */ + "subpage_prot", /* 310 */ + "timerfd_settime", /* 311 */ + "timerfd_gettime", /* 312 */ + "signalfd4", /* 313 */ + "eventfd2", /* 314 */ + "epoll_create1", /* 315 */ + "dup3", /* 316 */ + "pipe2", /* 317 */ + "inotify_init1", /* 318 */ + "perf_event_open", /* 319 */ + "preadv", /* 320 */ + "pwritev", /* 321 */ + "rt_tgsigqueueinfo", /* 322 */ + "fanotify_init", /* 323 */ + "fanotify_mark", /* 324 */ + "prlimit64", /* 325 */ + "socket", /* 326 */ + "bind", /* 327 */ + "connect", /* 328 */ + "listen", /* 329 */ + "accept", /* 330 */ + "getsockname", /* 331 */ + "getpeername", /* 332 */ + "socketpair", /* 333 */ + "send", /* 334 */ + "sendto", /* 335 */ + "recv", /* 336 */ + "recvfrom", /* 337 */ + "shutdown", /* 338 */ + "setsockopt", /* 339 */ + "getsockopt", /* 340 */ + "sendmsg", /* 341 */ + "recvmsg", /* 342 */ + "recvmmsg", /* 343 */ + "accept4", /* 344 */ + "name_to_handle_at", /* 345 */ + "open_by_handle_at", /* 346 */ + "clock_adjtime", /* 347 */ + "syncfs", /* 348 */ + "sendmmsg", /* 349 */ + "setns", /* 350 */ + "process_vm_readv", /* 351 */ + "process_writev", /* 352 */ diff --git a/sysdeps/linux-gnu/ppc/trace.c b/sysdeps/linux-gnu/ppc/trace.c index 81fb71d..4357a1e 100644 --- a/sysdeps/linux-gnu/ppc/trace.c +++ b/sysdeps/linux-gnu/ppc/trace.c @@ -1,14 +1,44 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2010,2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2011 Andreas Schwab + * Copyright (C) 2002,2004,2008,2009 Juan Cespedes + * Copyright (C) 2008 Luis Machado, IBM Corporation + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "config.h" -#include <sys/types.h> -#include <sys/wait.h> -#include <signal.h> -#include <sys/ptrace.h> -#include <asm/ptrace.h> +#include <assert.h> #include <elf.h> #include <errno.h> +#include <signal.h> +#include <string.h> +#include <sys/types.h> +#include <sys/wait.h> +#include "backend.h" +#include "breakpoint.h" #include "common.h" +#include "insn.h" +#include "proc.h" +#include "ptrace.h" +#include "type.h" #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) # define PTRACE_PEEKUSER PTRACE_PEEKUSR @@ -21,20 +51,13 @@ void get_arch_dep(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 -unsigned int greg = 3; -unsigned int freg = 1; -unsigned int vreg = 2; - +/* Returns 1 if syscall, 2 if sysret, 0 otherwise. */ int syscall_p(Process *proc, int status, int *sysnum) { if (WIFSTOPPED(status) @@ -59,97 +82,167 @@ syscall_p(Process *proc, int status, int *sysnum) { return 0; } -/* Grab functions arguments based on the PPC64 ABI. */ -long -gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { - long data; - - if (type == LT_TOF_FUNCTIONR) { - if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) - return ptrace (PTRACE_PEEKUSER, proc->pid, - sizeof (long) * (PT_FPR0 + 1), 0); - else - return ptrace (PTRACE_PEEKUSER, proc->pid, - sizeof (long) * PT_R3, 0); - } +/* The atomic skip code is mostly taken from GDB. */ - /* Check if we're entering a new function call to list parameters. If - so, initialize the register control variables to keep track of where - the parameters were stored. */ - if (type == LT_TOF_FUNCTION && arg_num == 0) { - /* Initialize the set of registrers for parameter passing. */ - greg = 3; - freg = 1; - vreg = 2; +/* In plt.h. XXX make this official interface. */ +int read_target_4(struct Process *proc, arch_addr_t addr, uint32_t *lp); + +int +arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp, + int (*add_cb)(void *addr, void *data), + void *add_cb_data) +{ + arch_addr_t ip = get_instruction_pointer(proc); + struct breakpoint *other = address2bpstruct(proc->leader, ip); + + debug(1, "arch_atomic_singlestep pid=%d addr=%p %s(%p)", + proc->pid, ip, breakpoint_name(sbp), sbp->addr); + + /* If the original instruction was lwarx/ldarx, we can't + * single-step over it, instead we have to execute the whole + * atomic block at once. */ + union { + uint32_t insn; + char buf[BREAKPOINT_LENGTH]; + } u; + if (other != NULL) { + memcpy(u.buf, sbp->orig_value, BREAKPOINT_LENGTH); + } else if (read_target_4(proc, ip, &u.insn) < 0) { + fprintf(stderr, "couldn't read instruction at IP %p\n", ip); + /* Do the normal singlestep. */ + return 1; } - if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) { - if (freg <= 13 || (proc->mask_32bit && freg <= 8)) { - data = ptrace (PTRACE_PEEKUSER, proc->pid, - sizeof (long) * (PT_FPR0 + freg), 0); - - if (info->type == ARGTYPE_FLOAT) { - /* float values passed in FP registers are automatically - promoted to double. We need to convert it back to float - before printing. */ - union { long val; float fval; double dval; } cvt; - cvt.val = data; - cvt.fval = (float) cvt.dval; - data = cvt.val; - } + if ((u.insn & LWARX_MASK) != LWARX_INSTRUCTION + && (u.insn & LWARX_MASK) != LDARX_INSTRUCTION) + return 1; + + debug(1, "singlestep over atomic block at %p", ip); + + int insn_count; + arch_addr_t addr = ip; + for (insn_count = 0; ; ++insn_count) { + addr += 4; + unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0); + if (l == (unsigned long)-1 && errno) + return -1; + uint32_t insn; +#ifdef __powerpc64__ + insn = l >> 32; +#else + insn = l; +#endif - freg++; - greg++; + /* If a conditional branch is found, put a breakpoint + * in its destination address. */ + if ((insn & BRANCH_MASK) == BC_INSN) { + arch_addr_t branch_addr = ppc_branch_dest(addr, insn); + debug(1, "pid=%d, branch in atomic block from %p to %p", + proc->pid, addr, branch_addr); + if (add_cb(branch_addr, add_cb_data) < 0) + return -1; + } - return data; + /* Assume that the atomic sequence ends with a + * stwcx/stdcx instruction. */ + if ((insn & STWCX_MASK) == STWCX_INSTRUCTION + || (insn & STWCX_MASK) == STDCX_INSTRUCTION) { + debug(1, "pid=%d, found end of atomic block %p at %p", + proc->pid, ip, addr); + break; } - } - else if (greg <= 10) { - data = ptrace (PTRACE_PEEKUSER, proc->pid, - sizeof (long) * greg, 0); - greg++; - return data; + /* Arbitrary cut-off. If we didn't find the + * terminating instruction by now, just give up. */ + if (insn_count > 16) { + fprintf(stderr, "[%d] couldn't find end of atomic block" + " at %p\n", proc->pid, ip); + return -1; + } } - else - return ptrace (PTRACE_PEEKDATA, proc->pid, - proc->stack_pointer + sizeof (long) * - (arg_num - 8), 0); + /* Put the breakpoint to the next instruction. */ + addr += 4; + if (add_cb(addr, add_cb_data) < 0) + return -1; + + debug(1, "PTRACE_CONT"); + ptrace(PTRACE_CONT, proc->pid, 0, 0); return 0; } -void -save_register_args(enum tof type, Process *proc) { +size_t +arch_type_sizeof(struct Process *proc, struct arg_type_info *info) +{ + if (proc == NULL) + return (size_t)-2; + + switch (info->type) { + case ARGTYPE_VOID: + return 0; + + case ARGTYPE_CHAR: + return 1; + + case ARGTYPE_SHORT: + case ARGTYPE_USHORT: + return 2; + + case ARGTYPE_INT: + case ARGTYPE_UINT: + return 4; + + case ARGTYPE_LONG: + case ARGTYPE_ULONG: + case ARGTYPE_POINTER: + return proc->e_machine == EM_PPC64 ? 8 : 4; + + case ARGTYPE_FLOAT: + return 4; + case ARGTYPE_DOUBLE: + return 8; + + case ARGTYPE_ARRAY: + case ARGTYPE_STRUCT: + /* Use default value. */ + return (size_t)-2; + + default: + assert(info->type != info->type); + abort(); + break; + } } -/* Read a single long from the process's memory address 'addr'. */ -int -arch_umovelong (Process *proc, void *addr, long *result, arg_type_info *info) { - long pointed_to; - - errno = 0; - - pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0); - - if (pointed_to == -1 && errno) - return -errno; - - /* Since int's are 4-bytes (long is 8-bytes) in length for ppc64, we - need to shift the long values returned by ptrace to end up with - the correct value. */ - - if (info) { - if (info->type == ARGTYPE_INT || (proc->mask_32bit && (info->type == ARGTYPE_POINTER - || info->type == ARGTYPE_STRING))) { - pointed_to = pointed_to >> 32; - - /* Make sure we have nothing in the upper word so we can - do a explicit cast from long to int later in the code. */ - pointed_to &= 0x00000000ffffffff; - } +size_t +arch_type_alignof(struct Process *proc, struct arg_type_info *info) +{ + if (proc == NULL) + return (size_t)-2; + + switch (info->type) { + default: + assert(info->type != info->type); + abort(); + break; + + case ARGTYPE_CHAR: + case ARGTYPE_SHORT: + case ARGTYPE_USHORT: + case ARGTYPE_INT: + case ARGTYPE_UINT: + case ARGTYPE_LONG: + case ARGTYPE_ULONG: + case ARGTYPE_POINTER: + case ARGTYPE_FLOAT: + case ARGTYPE_DOUBLE: + /* On both PPC and PPC64, fundamental types have the + * same alignment as size. */ + return arch_type_sizeof(proc, info); + + case ARGTYPE_ARRAY: + case ARGTYPE_STRUCT: + /* Use default value. */ + return (size_t)-2; } - - *result = pointed_to; - return 0; } diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c index 4251c1d..5adfb16 100644 --- a/sysdeps/linux-gnu/proc.c +++ b/sysdeps/linux-gnu/proc.c @@ -1,11 +1,53 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2010 Zachary T Welch, CodeSourcery + * Copyright (C) 2010 Joe Damato + * Copyright (C) 1998,2008,2009 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#define _GNU_SOURCE /* For getline. */ #include "config.h" +#include <sys/stat.h> +#include <sys/syscall.h> #include <sys/types.h> +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <link.h> +#include <signal.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> -#include <signal.h> #include <unistd.h> +#include "backend.h" +#include "breakpoint.h" +#include "config.h" +#include "debug.h" +#include "events.h" +#include "library.h" +#include "ltrace-elf.h" +#include "proc.h" + /* /proc/pid doesn't exist just after the fork, and sometimes `ltrace' * couldn't open it to find the executable. So it may be necessary to * have a bit delay @@ -13,17 +55,19 @@ #define MAX_DELAY 100000 /* 100000 microseconds = 0.1 seconds */ +#define PROC_PID_FILE(VAR, FORMAT, PID) \ + char VAR[strlen(FORMAT) + 6]; \ + sprintf(VAR, FORMAT, PID) + /* * Returns a (malloc'd) file name corresponding to a running pid */ char * pid2name(pid_t pid) { - char proc_exe[1024]; - if (!kill(pid, 0)) { int delay = 0; - sprintf(proc_exe, "/proc/%d/exe", pid); + PROC_PID_FILE(proc_exe, "/proc/%d/exe", pid); while (delay < MAX_DELAY) { if (!access(proc_exe, F_OK)) { @@ -34,3 +78,655 @@ pid2name(pid_t pid) { } return NULL; } + +static FILE * +open_status_file(pid_t pid) +{ + PROC_PID_FILE(fn, "/proc/%d/status", pid); + /* Don't complain if we fail. This would typically happen + when the process is about to terminate, and these files are + not available anymore. This function is called from the + event loop, and we don't want to clutter the output just + because the process terminates. */ + return fopen(fn, "r"); +} + +static char * +find_line_starting(FILE * file, const char * prefix, size_t len) +{ + char * line = NULL; + size_t line_len = 0; + while (!feof(file)) { + if (getline(&line, &line_len, file) < 0) + return NULL; + if (strncmp(line, prefix, len) == 0) + return line; + } + return NULL; +} + +static void +each_line_starting(FILE *file, const char *prefix, + enum callback_status (*cb)(const char *line, + const char *prefix, + void *data), + void *data) +{ + size_t len = strlen(prefix); + char * line; + while ((line = find_line_starting(file, prefix, len)) != NULL) { + enum callback_status st = (*cb)(line, prefix, data); + free(line); + if (st == CBS_STOP) + return; + } +} + +static enum callback_status +process_leader_cb(const char *line, const char *prefix, void *data) +{ + pid_t * pidp = data; + *pidp = atoi(line + strlen(prefix)); + return CBS_STOP; +} + +pid_t +process_leader(pid_t pid) +{ + pid_t tgid = 0; + FILE * file = open_status_file(pid); + if (file != NULL) { + each_line_starting(file, "Tgid:\t", &process_leader_cb, &tgid); + fclose(file); + } + + return tgid; +} + +static enum callback_status +process_stopped_cb(const char *line, const char *prefix, void *data) +{ + char c = line[strlen(prefix)]; + // t:tracing stop, T:job control stop + *(int *)data = (c == 't' || c == 'T'); + return CBS_STOP; +} + +int +process_stopped(pid_t pid) +{ + int is_stopped = -1; + FILE * file = open_status_file(pid); + if (file != NULL) { + each_line_starting(file, "State:\t", &process_stopped_cb, + &is_stopped); + fclose(file); + } + return is_stopped; +} + +static enum callback_status +process_status_cb(const char *line, const char *prefix, void *data) +{ + const char * status = line + strlen(prefix); + const char c = *status; + +#define RETURN(C) do { \ + *(enum process_status *)data = C; \ + return CBS_STOP; \ + } while (0) + + switch (c) { + case 'Z': RETURN(ps_zombie); + case 't': RETURN(ps_tracing_stop); + case 'T': + /* This can be either "T (stopped)" or, for older + * kernels, "T (tracing stop)". */ + if (!strcmp(status, "T (stopped)\n")) + RETURN(ps_stop); + else if (!strcmp(status, "T (tracing stop)\n")) + RETURN(ps_tracing_stop); + else { + fprintf(stderr, "Unknown process status: %s", + status); + RETURN(ps_stop); /* Some sort of stop + * anyway. */ + } + case 'D': + case 'S': RETURN(ps_sleeping); + } + + RETURN(ps_other); +#undef RETURN +} + +enum process_status +process_status(pid_t pid) +{ + enum process_status ret = ps_invalid; + FILE * file = open_status_file(pid); + if (file != NULL) { + each_line_starting(file, "State:\t", &process_status_cb, &ret); + fclose(file); + if (ret == ps_invalid) + fprintf(stderr, "process_status %d: %s", pid, + strerror(errno)); + } else + /* If the file is not present, the process presumably + * exited already. */ + ret = ps_zombie; + + return ret; +} + +static int +all_digits(const char *str) +{ + while (isdigit(*str)) + str++; + return !*str; +} + +int +process_tasks(pid_t pid, pid_t **ret_tasks, size_t *ret_n) +{ + PROC_PID_FILE(fn, "/proc/%d/task", pid); + DIR * d = opendir(fn); + if (d == NULL) + return -1; + + pid_t *tasks = NULL; + size_t n = 0; + size_t alloc = 0; + + while (1) { + struct dirent entry; + struct dirent *result; + if (readdir_r(d, &entry, &result) != 0) { + free(tasks); + return -1; + } + if (result == NULL) + break; + if (result->d_type == DT_DIR && all_digits(result->d_name)) { + pid_t npid = atoi(result->d_name); + if (n >= alloc) { + alloc = alloc > 0 ? (2 * alloc) : 8; + pid_t *ntasks = realloc(tasks, + sizeof(*tasks) * alloc); + if (ntasks == NULL) { + free(tasks); + return -1; + } + tasks = ntasks; + } + if (n >= alloc) + abort(); + tasks[n++] = npid; + } + } + + closedir(d); + + *ret_tasks = tasks; + *ret_n = n; + return 0; +} + +/* On native 64-bit system, we need to be careful when handling cross + * tracing. This select appropriate pointer depending on host and + * target architectures. XXX Really we should abstract this into the + * ABI object, as theorized about somewhere on pmachata/revamp + * branch. */ +static void * +select_32_64(struct Process *proc, void *p32, void *p64) +{ + if (sizeof(long) == 4 || proc->mask_32bit) + return p32; + else + return p64; +} + +static int +fetch_dyn64(struct Process *proc, arch_addr_t *addr, Elf64_Dyn *ret) +{ + if (umovebytes(proc, *addr, ret, sizeof(*ret)) != sizeof(*ret)) + return -1; + *addr += sizeof(*ret); + return 0; +} + +static int +fetch_dyn32(struct Process *proc, arch_addr_t *addr, Elf64_Dyn *ret) +{ + Elf32_Dyn dyn; + if (umovebytes(proc, *addr, &dyn, sizeof(dyn)) != sizeof(dyn)) + return -1; + + *addr += sizeof(dyn); + ret->d_tag = dyn.d_tag; + ret->d_un.d_val = dyn.d_un.d_val; + + return 0; +} + +static int (* +dyn_fetcher(struct Process *proc))(struct Process *, + arch_addr_t *, Elf64_Dyn *) +{ + return select_32_64(proc, fetch_dyn32, fetch_dyn64); +} + +int +proc_find_dynamic_entry_addr(struct Process *proc, arch_addr_t src_addr, + int d_tag, arch_addr_t *ret) +{ + debug(DEBUG_FUNCTION, "find_dynamic_entry()"); + + if (ret == NULL || src_addr == 0 || d_tag < 0) + return -1; + + int i = 0; + while (1) { + Elf64_Dyn entry; + if (dyn_fetcher(proc)(proc, &src_addr, &entry) < 0 + || entry.d_tag == DT_NULL + || i++ > 100) { /* Arbitrary cut-off so that we + * don't loop forever if the + * binary is corrupted. */ + debug(2, "Couldn't find address for dtag!"); + return -1; + } + + if (entry.d_tag == d_tag) { + /* XXX The double cast should be removed when + * arch_addr_t becomes integral type. */ + *ret = (arch_addr_t)(uintptr_t)entry.d_un.d_val; + debug(2, "found address: %p in dtag %d", *ret, d_tag); + return 0; + } + } +} + +/* Our own type for representing 32-bit linkmap. We can't rely on the + * definition in link.h, because that's only accurate for our host + * architecture, not for target architecture (where the traced process + * runs). */ +#define LT_LINK_MAP(BITS) \ + { \ + Elf##BITS##_Addr l_addr; \ + Elf##BITS##_Addr l_name; \ + Elf##BITS##_Addr l_ld; \ + Elf##BITS##_Addr l_next; \ + Elf##BITS##_Addr l_prev; \ + } +struct lt_link_map_32 LT_LINK_MAP(32); +struct lt_link_map_64 LT_LINK_MAP(64); + +static int +fetch_lm64(struct Process *proc, arch_addr_t addr, + struct lt_link_map_64 *ret) +{ + if (umovebytes(proc, addr, ret, sizeof(*ret)) != sizeof(*ret)) + return -1; + return 0; +} + +static int +fetch_lm32(struct Process *proc, arch_addr_t addr, + struct lt_link_map_64 *ret) +{ + struct lt_link_map_32 lm; + if (umovebytes(proc, addr, &lm, sizeof(lm)) != sizeof(lm)) + return -1; + + ret->l_addr = lm.l_addr; + ret->l_name = lm.l_name; + ret->l_ld = lm.l_ld; + ret->l_next = lm.l_next; + ret->l_prev = lm.l_prev; + + return 0; +} + +static int (* +lm_fetcher(struct Process *proc))(struct Process *, + arch_addr_t, struct lt_link_map_64 *) +{ + return select_32_64(proc, fetch_lm32, fetch_lm64); +} + +/* The same as above holds for struct r_debug. */ +#define LT_R_DEBUG(BITS) \ + { \ + int r_version; \ + Elf##BITS##_Addr r_map; \ + Elf##BITS##_Addr r_brk; \ + int r_state; \ + Elf##BITS##_Addr r_ldbase; \ + } + +struct lt_r_debug_32 LT_R_DEBUG(32); +struct lt_r_debug_64 LT_R_DEBUG(64); + +static int +fetch_rd64(struct Process *proc, arch_addr_t addr, + struct lt_r_debug_64 *ret) +{ + if (umovebytes(proc, addr, ret, sizeof(*ret)) != sizeof(*ret)) + return -1; + return 0; +} + +static int +fetch_rd32(struct Process *proc, arch_addr_t addr, + struct lt_r_debug_64 *ret) +{ + struct lt_r_debug_32 rd; + if (umovebytes(proc, addr, &rd, sizeof(rd)) != sizeof(rd)) + return -1; + + ret->r_version = rd.r_version; + ret->r_map = rd.r_map; + ret->r_brk = rd.r_brk; + ret->r_state = rd.r_state; + ret->r_ldbase = rd.r_ldbase; + + return 0; +} + +static int (* +rdebug_fetcher(struct Process *proc))(struct Process *, + arch_addr_t, struct lt_r_debug_64 *) +{ + return select_32_64(proc, fetch_rd32, fetch_rd64); +} + +static int +fetch_auxv64_entry(int fd, Elf64_auxv_t *ret) +{ + /* Reaching EOF is as much problem as not reading whole + * entry. */ + return read(fd, ret, sizeof(*ret)) == sizeof(*ret) ? 0 : -1; +} + +static int +fetch_auxv32_entry(int fd, Elf64_auxv_t *ret) +{ + Elf32_auxv_t auxv; + if (read(fd, &auxv, sizeof(auxv)) != sizeof(auxv)) + return -1; + + ret->a_type = auxv.a_type; + ret->a_un.a_val = auxv.a_un.a_val; + return 0; +} + +static int (* +auxv_fetcher(struct Process *proc))(int, Elf64_auxv_t *) +{ + return select_32_64(proc, fetch_auxv32_entry, fetch_auxv64_entry); +} + +static void +crawl_linkmap(struct Process *proc, struct lt_r_debug_64 *dbg) +{ + debug (DEBUG_FUNCTION, "crawl_linkmap()"); + + if (!dbg || !dbg->r_map) { + debug(2, "Debug structure or it's linkmap are NULL!"); + return; + } + + /* XXX The double cast should be removed when + * arch_addr_t becomes integral type. */ + arch_addr_t addr = (arch_addr_t)(uintptr_t)dbg->r_map; + + while (addr != 0) { + struct lt_link_map_64 rlm; + if (lm_fetcher(proc)(proc, addr, &rlm) < 0) { + debug(2, "Unable to read link map"); + return; + } + + arch_addr_t key = addr; + /* XXX The double cast should be removed when + * arch_addr_t becomes integral type. */ + addr = (arch_addr_t)(uintptr_t)rlm.l_next; + if (rlm.l_name == 0) { + debug(2, "Name of mapped library is NULL"); + return; + } + + char lib_name[BUFSIZ]; + /* XXX The double cast should be removed when + * arch_addr_t becomes integral type. */ + umovebytes(proc, (arch_addr_t)(uintptr_t)rlm.l_name, + lib_name, sizeof(lib_name)); + + /* Library name can be an empty string, in which case + * the entry represents either the main binary, or a + * VDSO. Unfortunately we can't rely on that, as in + * recent glibc, that entry is initialized to VDSO + * SONAME. + * + * It's not clear how to detect VDSO in this case. We + * can't assume that l_name of real DSOs will be + * either absolute or relative (for LD_LIBRARY_PATH=: + * it will be neither). We can't compare l_addr with + * AT_SYSINFO_EHDR either, as l_addr is bias (which + * also means it's not unique, and therefore useless + * for this). We could load VDSO from process image + * and at least compare actual SONAMEs. For now, this + * kludge is about the best that we can do. */ + if (*lib_name == 0 + || strcmp(lib_name, "linux-vdso.so.1") == 0 + || strcmp(lib_name, "linux-gate.so.1") == 0 + || strcmp(lib_name, "linux-vdso32.so.1") == 0 + || strcmp(lib_name, "linux-vdso64.so.1") == 0) + continue; + + /* Do we have that library already? */ + if (proc_each_library(proc, NULL, library_with_key_cb, &key)) + continue; + + struct library *lib = malloc(sizeof(*lib)); + if (lib == NULL) { + fail: + if (lib != NULL) + library_destroy(lib); + fprintf(stderr, "Couldn't load ELF object %s: %s\n", + lib_name, strerror(errno)); + continue; + } + library_init(lib, LT_LIBTYPE_DSO); + + if (ltelf_read_library(lib, proc, lib_name, rlm.l_addr) < 0) + goto fail; + + lib->key = key; + proc_add_library(proc, lib); + } + return; +} + +static int +load_debug_struct(struct Process *proc, struct lt_r_debug_64 *ret) +{ + debug(DEBUG_FUNCTION, "load_debug_struct"); + + if (rdebug_fetcher(proc)(proc, proc->os.debug_addr, ret) < 0) { + debug(2, "This process does not have a debug structure!"); + return -1; + } + + return 0; +} + +static void +rdebug_bp_on_hit(struct breakpoint *bp, struct Process *proc) +{ + debug(DEBUG_FUNCTION, "arch_check_dbg"); + + struct lt_r_debug_64 rdbg; + if (load_debug_struct(proc, &rdbg) < 0) { + debug(2, "Unable to load debug structure!"); + return; + } + + if (rdbg.r_state == RT_CONSISTENT) { + debug(2, "Linkmap is now consistent"); + switch (proc->os.debug_state) { + case RT_ADD: + debug(2, "Adding DSO to linkmap"); + crawl_linkmap(proc, &rdbg); + break; + case RT_DELETE: + debug(2, "Removing DSO from linkmap"); + // XXX unload that library + break; + default: + debug(2, "Unexpected debug state!"); + } + } + + proc->os.debug_state = rdbg.r_state; +} + +#ifndef ARCH_HAVE_FIND_DL_DEBUG +int +arch_find_dl_debug(struct Process *proc, arch_addr_t dyn_addr, + arch_addr_t *ret) +{ + return proc_find_dynamic_entry_addr(proc, dyn_addr, DT_DEBUG, ret); +} +#endif + +int +linkmap_init(struct Process *proc, arch_addr_t dyn_addr) +{ + debug(DEBUG_FUNCTION, "linkmap_init(%d, dyn_addr=%p)", proc->pid, dyn_addr); + + if (arch_find_dl_debug(proc, dyn_addr, &proc->os.debug_addr) == -1) { + debug(2, "Couldn't find debug structure!"); + return -1; + } + + int status; + struct lt_r_debug_64 rdbg; + if ((status = load_debug_struct(proc, &rdbg)) < 0) { + debug(2, "No debug structure or no memory to allocate one!"); + return status; + } + + /* XXX The double cast should be removed when + * arch_addr_t becomes integral type. */ + arch_addr_t addr = (arch_addr_t)(uintptr_t)rdbg.r_brk; + if (arch_translate_address_dyn(proc, addr, &addr) < 0) + return -1; + + struct breakpoint *rdebug_bp = insert_breakpoint(proc, addr, NULL); + static struct bp_callbacks rdebug_callbacks = { + .on_hit = rdebug_bp_on_hit, + }; + rdebug_bp->cbs = &rdebug_callbacks; + + crawl_linkmap(proc, &rdbg); + + return 0; +} + +int +task_kill (pid_t pid, int sig) +{ + // Taken from GDB + int ret; + + errno = 0; + ret = syscall (__NR_tkill, pid, sig); + return ret; +} + +void +process_removed(struct Process *proc) +{ + delete_events_for(proc); +} + +int +process_get_entry(struct Process *proc, + arch_addr_t *entryp, + arch_addr_t *interp_biasp) +{ + PROC_PID_FILE(fn, "/proc/%d/auxv", proc->pid); + int fd = open(fn, O_RDONLY); + int ret = 0; + if (fd == -1) { + fail: + fprintf(stderr, "couldn't read %s: %s", fn, strerror(errno)); + ret = -1; + done: + if (fd != -1) + close(fd); + return ret; + } + + arch_addr_t at_entry = 0; + arch_addr_t at_bias = 0; + while (1) { + Elf64_auxv_t entry = {}; + if (auxv_fetcher(proc)(fd, &entry) < 0) + goto fail; + + switch (entry.a_type) { + case AT_BASE: + /* XXX The double cast should be removed when + * arch_addr_t becomes integral type. */ + at_bias = (arch_addr_t)(uintptr_t)entry.a_un.a_val; + continue; + + case AT_ENTRY: + /* XXX The double cast should be removed when + * arch_addr_t becomes integral type. */ + at_entry = (arch_addr_t)(uintptr_t)entry.a_un.a_val; + default: + continue; + + case AT_NULL: + break; + } + break; + } + + if (entryp != NULL) + *entryp = at_entry; + if (interp_biasp != NULL) + *interp_biasp = at_bias; + goto done; +} + +int +os_process_init(struct Process *proc) +{ + proc->os.debug_addr = 0; + proc->os.debug_state = 0; + return 0; +} + +void +os_process_destroy(struct Process *proc) +{ +} + +int +os_process_clone(struct Process *retp, struct Process *proc) +{ + retp->os = proc->os; + return 0; +} + +int +os_process_exec(struct Process *proc) +{ + return 0; +} diff --git a/sysdeps/linux-gnu/s390/Makefile b/sysdeps/linux-gnu/s390/Makefile deleted file mode 100644 index cea1b45..0000000 --- a/sysdeps/linux-gnu/s390/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# -# S/390 version -# Copyright (C) 2001 IBM Poughkeepsie, IBM Corporation -# -OBJ = trace.o regs.o plt.o - -all: arch.o - -arch.o: $(OBJ) - $(CC) -nostdlib -r -o arch.o $(OBJ) - -clean: - $(RM) $(OBJ) arch.o diff --git a/sysdeps/linux-gnu/s390/Makefile.am b/sysdeps/linux-gnu/s390/Makefile.am new file mode 100644 index 0000000..22741bd --- /dev/null +++ b/sysdeps/linux-gnu/s390/Makefile.am @@ -0,0 +1,39 @@ +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ + trace.c \ + fetch.c + +noinst_HEADERS = \ + arch.h \ + ptrace.h \ + signalent1.h \ + signalent.h \ + syscallent1.h \ + syscallent.h \ + syscalls31.h \ + syscalls64.h + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/sysdeps/linux-gnu/s390/Makefile.in b/sysdeps/linux-gnu/s390/Makefile.in new file mode 100644 index 0000000..0f55ef5 --- /dev/null +++ b/sysdeps/linux-gnu/s390/Makefile.in @@ -0,0 +1,534 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = sysdeps/linux-gnu/s390 +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/m4/libtool.m4 \ + $(top_srcdir)/config/m4/ltoptions.m4 \ + $(top_srcdir)/config/m4/ltsugar.m4 \ + $(top_srcdir)/config/m4/ltversion.m4 \ + $(top_srcdir)/config/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +___libcpu_la_LIBADD = +am____libcpu_la_OBJECTS = plt.lo regs.lo trace.lo fetch.lo +___libcpu_la_OBJECTS = $(am____libcpu_la_OBJECTS) +am__dirstamp = $(am__leading_dot)dirstamp +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/autoconf/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(___libcpu_la_SOURCES) +DIST_SOURCES = $(___libcpu_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_VALGRIND = @HAVE_VALGRIND@ +HOST_CPU = @HOST_CPU@ +HOST_OS = @HOST_OS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libelf_LD_LIBRARY_PATH = @libelf_LD_LIBRARY_PATH@ +liberty_LIBS = @liberty_LIBS@ +libexecdir = @libexecdir@ +libstdcxx_LIBS = @libstdcxx_LIBS@ +libsupcxx_LIBS = @libsupcxx_LIBS@ +libunwind_LD_LIBRARY_PATH = @libunwind_LD_LIBRARY_PATH@ +libunwind_LIBS = @libunwind_LIBS@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ + trace.c \ + fetch.c + +noinst_HEADERS = \ + arch.h \ + ptrace.h \ + signalent1.h \ + signalent.h \ + syscallent1.h \ + syscallent.h \ + syscalls31.h \ + syscalls64.h + +MAINTAINERCLEANFILES = \ + Makefile.in + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign sysdeps/linux-gnu/s390/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign sysdeps/linux-gnu/s390/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +../$(am__dirstamp): + @$(MKDIR_P) .. + @: > ../$(am__dirstamp) +../libcpu.la: $(___libcpu_la_OBJECTS) $(___libcpu_la_DEPENDENCIES) ../$(am__dirstamp) + $(LINK) $(___libcpu_la_OBJECTS) $(___libcpu_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fetch.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf ../.libs ../_libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f ../$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sysdeps/linux-gnu/s390/arch.h b/sysdeps/linux-gnu/s390/arch.h index 03690b8..0d412dc 100644 --- a/sysdeps/linux-gnu/s390/arch.h +++ b/sysdeps/linux-gnu/s390/arch.h @@ -1,18 +1,35 @@ /* -** S/390 version -** (C) Copyright 2001 IBM Poughkeepsie, IBM Corporation -*/ + * This file is part of ltrace. + * Copyright (C) 2001 IBM Poughkeepsie, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ #define BREAKPOINT_VALUE { 0x00, 0x01 } #define BREAKPOINT_LENGTH 2 #define DECR_PC_AFTER_BREAK 2 +#define ARCH_ENDIAN_BIG +#define ARCH_HAVE_FETCH_ARG +#define ARCH_HAVE_SIZEOF +#define ARCH_HAVE_ALIGNOF -#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 + +#ifdef __s390x__ +#define LT_ELFCLASS2 ELFCLASS64 +#define LT_ELF_MACHINE2 EM_S390 #endif diff --git a/sysdeps/linux-gnu/s390/fetch.c b/sysdeps/linux-gnu/s390/fetch.c new file mode 100644 index 0000000..fa8f42d --- /dev/null +++ b/sysdeps/linux-gnu/s390/fetch.c @@ -0,0 +1,289 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include <asm/ptrace.h> +#include <sys/ptrace.h> +#include <sys/ucontext.h> +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "backend.h" +#include "fetch.h" +#include "type.h" +#include "proc.h" +#include "value.h" + +struct fetch_context { + struct user_regs_struct regs; + arch_addr_t stack_pointer; + int greg; + int freg; +}; + +static int +s390x(struct fetch_context *ctx) +{ + /* +--------+--------+--------+ + * | PSW.31 | PSW.32 | mode | + * +--------+--------+--------+ + * | 0 | 0 | 24-bit | Not supported in Linux + * | 0 | 1 | 31-bit | s390 compatible mode + * | 1 | 1 | 64-bit | z/Architecture, "s390x" + * +--------+--------+--------+ + * (Note: The leftmost bit is PSW.0, rightmost PSW.63.) + */ + +#ifdef __s390x__ + if ((ctx->regs.psw.mask & 0x180000000UL) == 0x180000000UL) + return 1; +#endif + return 0; +} + +static int +fetch_register_banks(struct Process *proc, struct fetch_context *ctx) +{ + ptrace_area parea; + parea.len = sizeof(ctx->regs); + parea.process_addr = (uintptr_t)&ctx->regs; + parea.kernel_addr = 0; + if (ptrace(PTRACE_PEEKUSR_AREA, proc->pid, &parea, NULL) < 0) { + fprintf(stderr, "fetch_register_banks GPR: %s\n", + strerror(errno)); + return -1; + } + return 0; +} + +static int +fetch_context_init(struct Process *proc, struct fetch_context *context) +{ + context->greg = 2; + context->freg = 0; + return fetch_register_banks(proc, context); +} + +struct fetch_context * +arch_fetch_arg_init(enum tof type, struct Process *proc, + struct arg_type_info *ret_info) +{ + struct fetch_context *context = malloc(sizeof(*context)); + if (context == NULL + || fetch_context_init(proc, context) < 0) { + fprintf(stderr, "arch_fetch_arg_init: %s\n", + strerror(errno)); + free(context); + return NULL; + } + + context->stack_pointer = get_stack_pointer(proc) + + (s390x(context) ? 160 : 96); + if (ret_info->type == ARGTYPE_STRUCT) + ++context->greg; + + return context; +} + +struct fetch_context * +arch_fetch_arg_clone(struct Process *proc, + struct fetch_context *context) +{ + struct fetch_context *clone = malloc(sizeof(*context)); + if (clone == NULL) + return NULL; + *clone = *context; + return clone; +} + +static int +allocate_stack_slot(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep, + size_t sz) +{ + /* Note: here we shouldn't see large composite types, those + * are passed by reference, which is handled below. Here we + * only deal with integers, floats, small structs, etc. */ + + size_t a; + if (s390x(ctx)) { + assert(sz <= 8); + a = 8; + } else { + /* Note: double is 8 bytes. */ + assert(sz <= 8); + a = 4; + } + + size_t off = sz < a ? a - sz : 0; + value_in_inferior(valuep, ctx->stack_pointer + off); + + ctx->stack_pointer += sz > a ? sz : a; + return 0; +} + +static void +copy_gpr(struct fetch_context *ctx, struct value *valuep, int regno) +{ + value_set_word(valuep, ctx->regs.gprs[regno]); +} + +static int +allocate_gpr(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep, + size_t sz) +{ + if (ctx->greg > 6) + return allocate_stack_slot(ctx, proc, info, valuep, sz); + + copy_gpr(ctx, valuep, ctx->greg++); + return 0; +} + +static int +allocate_gpr_pair(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep, + size_t sz) +{ + assert(!s390x(ctx)); + assert(sz <= 8); + + if (ctx->greg > 5) { + ctx->greg = 7; + return allocate_stack_slot(ctx, proc, info, valuep, sz); + } + + if (value_reserve(valuep, sz) == NULL) + return -1; + + unsigned char *ptr = value_get_raw_data(valuep); + union { + struct { + uint32_t a; + uint32_t b; + }; + unsigned char buf[8]; + } u; + u.a = ctx->regs.gprs[ctx->greg++]; + u.b = ctx->regs.gprs[ctx->greg++]; + memcpy(ptr, u.buf, sz); + + return 0; +} + +static int +allocate_fpr(struct fetch_context *ctx, struct Process *proc, + struct arg_type_info *info, struct value *valuep, + size_t sz) +{ + int pool = s390x(ctx) ? 6 : 2; + + if (ctx->freg > pool) + return allocate_stack_slot(ctx, proc, info, valuep, sz); + + if (value_reserve(valuep, sz) == NULL) + return -1; + + memcpy(value_get_raw_data(valuep), + &ctx->regs.fp_regs.fprs[ctx->freg], sz); + ctx->freg += 2; + + return 0; +} + +int +arch_fetch_arg_next(struct fetch_context *ctx, enum tof type, + struct Process *proc, + struct arg_type_info *info, struct value *valuep) +{ + size_t sz = type_sizeof(proc, info); + if (sz == (size_t)-1) + return -1; + + switch (info->type) { + case ARGTYPE_VOID: + value_set_word(valuep, 0); + return 0; + + case ARGTYPE_STRUCT: + if (type_get_fp_equivalent(info) != NULL) + /* fall through */ + case ARGTYPE_FLOAT: + case ARGTYPE_DOUBLE: + return allocate_fpr(ctx, proc, info, valuep, sz); + + /* Structures<4 bytes on s390 and structures<8 bytes + * on s390x are passed in register. On s390, long + * long and structures<8 bytes are passed in two + * consecutive registers (if two are available). */ + + if (sz <= (s390x(ctx) ? 8 : 4)) + return allocate_gpr(ctx, proc, info, valuep, sz); + else if (sz <= 8) + return allocate_gpr_pair(ctx, proc, info, valuep, sz); + + /* fall through */ + + case ARGTYPE_ARRAY: + if (value_pass_by_reference(valuep) < 0) + return -1; + /* fall through */ + + case ARGTYPE_INT: + case ARGTYPE_UINT: + case ARGTYPE_LONG: + case ARGTYPE_ULONG: + case ARGTYPE_CHAR: + case ARGTYPE_SHORT: + case ARGTYPE_USHORT: + case ARGTYPE_POINTER: + return allocate_gpr(ctx, proc, info, valuep, sz); + + default: + assert(info->type != info->type); + abort(); + } + return -1; +} + +int +arch_fetch_retval(struct fetch_context *ctx, enum tof type, + struct Process *proc, struct arg_type_info *info, + struct value *valuep) +{ + if (info->type == ARGTYPE_STRUCT) { + if (value_pass_by_reference(valuep) < 0) + return -1; + copy_gpr(ctx, valuep, 2); + return 0; + } + + if (fetch_context_init(proc, ctx) < 0) + return -1; + return arch_fetch_arg_next(ctx, type, proc, info, valuep); +} + +void +arch_fetch_arg_done(struct fetch_context *context) +{ + free(context); +} diff --git a/sysdeps/linux-gnu/s390/plt.c b/sysdeps/linux-gnu/s390/plt.c index 85a1dd1..5f612e5 100644 --- a/sysdeps/linux-gnu/s390/plt.c +++ b/sysdeps/linux-gnu/s390/plt.c @@ -1,5 +1,27 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2004,2008,2009 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include <gelf.h> +#include "proc.h" #include "common.h" +#include "library.h" GElf_Addr arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { diff --git a/sysdeps/linux-gnu/s390/ptrace.h b/sysdeps/linux-gnu/s390/ptrace.h index c3cbcb6..ad7e0d6 100644 --- a/sysdeps/linux-gnu/s390/ptrace.h +++ b/sysdeps/linux-gnu/s390/ptrace.h @@ -1 +1,21 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2004 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include <sys/ptrace.h> diff --git a/sysdeps/linux-gnu/s390/regs.c b/sysdeps/linux-gnu/s390/regs.c index 169893e..0592ccd 100644 --- a/sysdeps/linux-gnu/s390/regs.c +++ b/sysdeps/linux-gnu/s390/regs.c @@ -1,7 +1,25 @@ /* -** S/390 version -** Copyright (C) 2001 IBM Poughkeepsie, IBM Corporation -*/ + * This file is part of ltrace. + * Copyright (C) 2002,2004,2008,2009 Juan Cespedes + * Copyright (C) 2009 Juan Cespedes + * Copyright (C) 2006 Ian Wienand + * Copyright (C) 2001 IBM Poughkeepsie, IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ #include "config.h" @@ -9,6 +27,7 @@ #include <sys/ptrace.h> #include <asm/ptrace.h> +#include "proc.h" #include "common.h" #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) diff --git a/sysdeps/linux-gnu/s390/signalent.h b/sysdeps/linux-gnu/s390/signalent.h index 35b74f1..218b057 100644 --- a/sysdeps/linux-gnu/s390/signalent.h +++ b/sysdeps/linux-gnu/s390/signalent.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + "SIG_0", /* 0 */ "SIGHUP", /* 1 */ "SIGINT", /* 2 */ diff --git a/sysdeps/linux-gnu/s390/signalent1.h b/sysdeps/linux-gnu/s390/signalent1.h index b5b6ca8..0f529bb 100644 --- a/sysdeps/linux-gnu/s390/signalent1.h +++ b/sysdeps/linux-gnu/s390/signalent1.h @@ -1 +1,21 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "s390/signalent.h" diff --git a/sysdeps/linux-gnu/s390/syscallent.h b/sysdeps/linux-gnu/s390/syscallent.h index 5a35d93..03d0541 100644 --- a/sysdeps/linux-gnu/s390/syscallent.h +++ b/sysdeps/linux-gnu/s390/syscallent.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #ifdef __s390x__ #include "s390/syscalls64.h" #else diff --git a/sysdeps/linux-gnu/s390/syscallent1.h b/sysdeps/linux-gnu/s390/syscallent1.h index c9fdc81..8d80a54 100644 --- a/sysdeps/linux-gnu/s390/syscallent1.h +++ b/sysdeps/linux-gnu/s390/syscallent1.h @@ -1 +1,21 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "s390/syscalls31.h" diff --git a/sysdeps/linux-gnu/s390/syscalls31.h b/sysdeps/linux-gnu/s390/syscalls31.h index 42631eb..46f4cf3 100644 --- a/sysdeps/linux-gnu/s390/syscalls31.h +++ b/sysdeps/linux-gnu/s390/syscalls31.h @@ -1,3 +1,24 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Heiko Carstens, IBM Corporation + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + "0", /* 0 */ "exit", /* 1 */ "fork", /* 2 */ diff --git a/sysdeps/linux-gnu/s390/syscalls64.h b/sysdeps/linux-gnu/s390/syscalls64.h index 97be52c..f2ec7f4 100644 --- a/sysdeps/linux-gnu/s390/syscalls64.h +++ b/sysdeps/linux-gnu/s390/syscalls64.h @@ -1,3 +1,24 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Heiko Carstens, IBM Corporation + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + "0", /* 0 */ "exit", /* 1 */ "fork", /* 2 */ diff --git a/sysdeps/linux-gnu/s390/trace.c b/sysdeps/linux-gnu/s390/trace.c index 9df2437..b9e05ff 100644 --- a/sysdeps/linux-gnu/s390/trace.c +++ b/sysdeps/linux-gnu/s390/trace.c @@ -1,23 +1,38 @@ /* -** S390 specific part of trace.c -** -** Other routines are in ../trace.c and need to be combined -** at link time with this code. -** -** Copyright (C) 2001,2005 IBM Corp. -*/ + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2001,2005 IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ #include "config.h" -#include <errno.h> -#include <stdlib.h> +#include <asm/ptrace.h> +#include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> +#include <assert.h> +#include <errno.h> #include <signal.h> -#include <sys/ptrace.h> -#include <asm/ptrace.h> +#include <stdlib.h> #include "common.h" +#include "proc.h" +#include "type.h" #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) # define PTRACE_PEEKUSER PTRACE_PEEKUSR @@ -159,40 +174,84 @@ syscall_p(Process *proc, int status, int *sysnum) { return 0; } -long -gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { - long ret; +size_t +arch_type_sizeof(struct Process *proc, struct arg_type_info *info) +{ + if (proc == NULL) + return (size_t)-2; + + switch (info->type) { + case ARGTYPE_VOID: + return 0; + + case ARGTYPE_CHAR: + return 1; + + case ARGTYPE_SHORT: + case ARGTYPE_USHORT: + return 2; + + case ARGTYPE_INT: + case ARGTYPE_UINT: + return 4; + + case ARGTYPE_LONG: + case ARGTYPE_ULONG: + case ARGTYPE_POINTER: + return proc->e_class == ELFCLASS64 ? 8 : 4; + + case ARGTYPE_FLOAT: + return 4; + case ARGTYPE_DOUBLE: + return 8; + + case ARGTYPE_ARRAY: + case ARGTYPE_STRUCT: + /* Use default value. */ + return (size_t)-2; - 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); + assert(info->type != info->type); + abort(); } -#ifdef __s390x__ - if (proc->mask_32bit) - ret &= 0xffffffff; -#endif - return ret; } -void -save_register_args(enum tof type, Process *proc) { +size_t +arch_type_alignof(struct Process *proc, struct arg_type_info *info) +{ + if (proc == NULL) + return (size_t)-2; + + switch (info->type) { + default: + assert(info->type != info->type); + break; + + case ARGTYPE_CHAR: + return 1; + + case ARGTYPE_SHORT: + case ARGTYPE_USHORT: + return 2; + + case ARGTYPE_INT: + case ARGTYPE_UINT: + return 4; + + case ARGTYPE_LONG: + case ARGTYPE_ULONG: + case ARGTYPE_POINTER: + return proc->e_class == ELFCLASS64 ? 8 : 4; + + case ARGTYPE_FLOAT: + return 4; + case ARGTYPE_DOUBLE: + return 8; + + case ARGTYPE_ARRAY: + case ARGTYPE_STRUCT: + /* Use default value. */ + return (size_t)-2; + } + abort(); } diff --git a/sysdeps/linux-gnu/signalent1.h b/sysdeps/linux-gnu/signalent1.h new file mode 100644 index 0000000..74d8e19 --- /dev/null +++ b/sysdeps/linux-gnu/signalent1.h @@ -0,0 +1 @@ +/* This file is intentionally left blank */ diff --git a/sysdeps/linux-gnu/sparc/Makefile b/sysdeps/linux-gnu/sparc/Makefile deleted file mode 100644 index b3914e5..0000000 --- a/sysdeps/linux-gnu/sparc/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -OBJ = regs.o trace.o plt.o - -all: arch.o - -arch.o: $(OBJ) - $(CC) -nostdlib -r -o arch.o $(OBJ) - -clean: - $(RM) $(OBJ) arch.o diff --git a/sysdeps/linux-gnu/sparc/Makefile.am b/sysdeps/linux-gnu/sparc/Makefile.am new file mode 100644 index 0000000..5c6ecc2 --- /dev/null +++ b/sysdeps/linux-gnu/sparc/Makefile.am @@ -0,0 +1,34 @@ +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ + trace.c + +noinst_HEADERS = \ + arch.h \ + ptrace.h \ + signalent.h \ + syscallent.h + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/sysdeps/linux-gnu/sparc/Makefile.in b/sysdeps/linux-gnu/sparc/Makefile.in new file mode 100644 index 0000000..d94a1d8 --- /dev/null +++ b/sysdeps/linux-gnu/sparc/Makefile.in @@ -0,0 +1,528 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = sysdeps/linux-gnu/sparc +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/m4/libtool.m4 \ + $(top_srcdir)/config/m4/ltoptions.m4 \ + $(top_srcdir)/config/m4/ltsugar.m4 \ + $(top_srcdir)/config/m4/ltversion.m4 \ + $(top_srcdir)/config/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +___libcpu_la_LIBADD = +am____libcpu_la_OBJECTS = plt.lo regs.lo trace.lo +___libcpu_la_OBJECTS = $(am____libcpu_la_OBJECTS) +am__dirstamp = $(am__leading_dot)dirstamp +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/autoconf/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(___libcpu_la_SOURCES) +DIST_SOURCES = $(___libcpu_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_VALGRIND = @HAVE_VALGRIND@ +HOST_CPU = @HOST_CPU@ +HOST_OS = @HOST_OS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libelf_LD_LIBRARY_PATH = @libelf_LD_LIBRARY_PATH@ +liberty_LIBS = @liberty_LIBS@ +libexecdir = @libexecdir@ +libstdcxx_LIBS = @libstdcxx_LIBS@ +libsupcxx_LIBS = @libsupcxx_LIBS@ +libunwind_LD_LIBRARY_PATH = @libunwind_LD_LIBRARY_PATH@ +libunwind_LIBS = @libunwind_LIBS@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ + trace.c + +noinst_HEADERS = \ + arch.h \ + ptrace.h \ + signalent.h \ + syscallent.h + +MAINTAINERCLEANFILES = \ + Makefile.in + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign sysdeps/linux-gnu/sparc/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign sysdeps/linux-gnu/sparc/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +../$(am__dirstamp): + @$(MKDIR_P) .. + @: > ../$(am__dirstamp) +../libcpu.la: $(___libcpu_la_OBJECTS) $(___libcpu_la_DEPENDENCIES) ../$(am__dirstamp) + $(LINK) $(___libcpu_la_OBJECTS) $(___libcpu_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf ../.libs ../_libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f ../$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sysdeps/linux-gnu/sparc/arch.h b/sysdeps/linux-gnu/sparc/arch.h index 75251b8..9685d13 100644 --- a/sysdeps/linux-gnu/sparc/arch.h +++ b/sysdeps/linux-gnu/sparc/arch.h @@ -1,6 +1,27 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2004 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #define BREAKPOINT_VALUE {0x91, 0xd0, 0x20, 0x01} #define BREAKPOINT_LENGTH 4 #define DECR_PC_AFTER_BREAK 0 +#define ARCH_ENDIAN_BIG #define LT_ELFCLASS ELFCLASS32 #define LT_ELF_MACHINE EM_SPARC diff --git a/sysdeps/linux-gnu/sparc/plt.c b/sysdeps/linux-gnu/sparc/plt.c index f9e6d80..40bbabc 100644 --- a/sysdeps/linux-gnu/sparc/plt.c +++ b/sysdeps/linux-gnu/sparc/plt.c @@ -1,4 +1,25 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2004,2008,2009 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include <gelf.h> +#include "proc.h" #include "common.h" GElf_Addr diff --git a/sysdeps/linux-gnu/sparc/ptrace.h b/sysdeps/linux-gnu/sparc/ptrace.h index bbaf01a..cbc35a6 100644 --- a/sysdeps/linux-gnu/sparc/ptrace.h +++ b/sysdeps/linux-gnu/sparc/ptrace.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2004,2009 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #undef PTRACE_GETREGS #undef PTRACE_SETREGS #undef PTRACE_GETFPREGS diff --git a/sysdeps/linux-gnu/sparc/regs.c b/sysdeps/linux-gnu/sparc/regs.c index 49d2729..5e5ad20 100644 --- a/sysdeps/linux-gnu/sparc/regs.c +++ b/sysdeps/linux-gnu/sparc/regs.c @@ -1,7 +1,29 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2004,2008,2009 Juan Cespedes + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "config.h" #include <sys/types.h> #include "ptrace.h" +#include "proc.h" #include "common.h" void * diff --git a/sysdeps/linux-gnu/sparc/signalent.h b/sysdeps/linux-gnu/sparc/signalent.h index d30f69e..8555456 100644 --- a/sysdeps/linux-gnu/sparc/signalent.h +++ b/sysdeps/linux-gnu/sparc/signalent.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + "SIG_0", /* 0 */ "SIGHUP", /* 1 */ "SIGINT", /* 2 */ diff --git a/sysdeps/linux-gnu/sparc/syscallent.h b/sysdeps/linux-gnu/sparc/syscallent.h index 96eeec9..bb309c6 100644 --- a/sysdeps/linux-gnu/sparc/syscallent.h +++ b/sysdeps/linux-gnu/sparc/syscallent.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + "0", /* 0 */ "exit", /* 1 */ "fork", /* 2 */ diff --git a/sysdeps/linux-gnu/sparc/trace.c b/sysdeps/linux-gnu/sparc/trace.c index 7f05b55..e1725ff 100644 --- a/sysdeps/linux-gnu/sparc/trace.c +++ b/sysdeps/linux-gnu/sparc/trace.c @@ -1,3 +1,24 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2004,2008,2009 Juan Cespedes + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + #include "config.h" #include <stdlib.h> @@ -6,6 +27,7 @@ #include <signal.h> #include <string.h> #include "ptrace.h" +#include "proc.h" #include "common.h" void @@ -44,7 +66,8 @@ syscall_p(Process *proc, int status, int *sysnum) { } long -gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { +gimme_arg(enum tof type, Process *proc, int arg_num, struct arg_type_info *info) +{ proc_archdep *a = (proc_archdep *) proc->arch_ptr; if (!a->valid) { fprintf(stderr, "Could not get child registers\n"); @@ -68,14 +91,3 @@ gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { } return 0; } - -void -save_register_args(enum tof type, Process *proc) { - proc_archdep *a = (proc_archdep *) proc->arch_ptr; - if (a->valid) { - if (type == LT_TOF_FUNCTION) - memcpy(a->func_arg, &a->regs.u_regs[UREG_G7], sizeof(a->func_arg)); - else - memcpy(a->sysc_arg, &a->regs.u_regs[UREG_G7], sizeof(a->sysc_arg)); - } -} diff --git a/sysdeps/linux-gnu/syscallent1.h b/sysdeps/linux-gnu/syscallent1.h new file mode 100644 index 0000000..74d8e19 --- /dev/null +++ b/sysdeps/linux-gnu/syscallent1.h @@ -0,0 +1 @@ +/* This file is intentionally left blank */ diff --git a/sysdeps/linux-gnu/trace-defs.h b/sysdeps/linux-gnu/trace-defs.h new file mode 100644 index 0000000..aa69b83 --- /dev/null +++ b/sysdeps/linux-gnu/trace-defs.h @@ -0,0 +1,92 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#ifndef _TRACE_DEFS_H_ +#define _TRACE_DEFS_H_ +#include <sys/ptrace.h> + +/* If the system headers did not provide the constants, hard-code the + * normal values. */ +#ifndef PTRACE_OLDSETOPTIONS +# define PTRACE_OLDSETOPTIONS 21 +#endif + +#ifndef PTRACE_SETOPTIONS +# define PTRACE_SETOPTIONS 0x4200 +#endif + +#ifndef PTRACE_GETEVENTMSG +# define PTRACE_GETEVENTMSG 0x4201 +#endif + +/* Options set using PTRACE_SETOPTIONS. */ +#ifndef PTRACE_O_TRACESYSGOOD +# define PTRACE_O_TRACESYSGOOD 0x00000001 +#endif + +#ifndef PTRACE_O_TRACEFORK +# define PTRACE_O_TRACEFORK 0x00000002 +#endif + +#ifndef PTRACE_O_TRACEVFORK +# define PTRACE_O_TRACEVFORK 0x00000004 +#endif + +#ifndef PTRACE_O_TRACECLONE +# define PTRACE_O_TRACECLONE 0x00000008 +#endif + +#ifndef PTRACE_O_TRACEEXEC +# define PTRACE_O_TRACEEXEC 0x00000010 +#endif + +#ifndef PTRACE_O_TRACEVFORKDONE +# define PTRACE_O_TRACEVFORKDONE 0x00000020 +#endif + +#ifndef PTRACE_O_TRACEEXIT +# define PTRACE_O_TRACEEXIT 0x00000040 +#endif + +/* Wait extended result codes for the above trace options. */ +#ifndef PTRACE_EVENT_FORK +# define PTRACE_EVENT_FORK 1 +#endif + +#ifndef PTRACE_EVENT_VFORK +# define PTRACE_EVENT_VFORK 2 +#endif + +#ifndef PTRACE_EVENT_CLONE +# define PTRACE_EVENT_CLONE 3 +#endif + +#ifndef PTRACE_EVENT_EXEC +# define PTRACE_EVENT_EXEC 4 +#endif + +#ifndef PTRACE_EVENT_VFORK_DONE +# define PTRACE_EVENT_VFORK_DONE 5 +#endif + +#ifndef PTRACE_EVENT_EXIT +# define PTRACE_EVENT_EXIT 6 +#endif + +#endif /* _TRACE_DEFS_H_ */ diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c index df5b090..e13b761 100644 --- a/sysdeps/linux-gnu/trace.c +++ b/sysdeps/linux-gnu/trace.c @@ -1,104 +1,129 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2007,2011,2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2010 Joe Damato + * Copyright (C) 1998,2002,2003,2004,2008,2009 Juan Cespedes + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include "config.h" + +#include <asm/unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <assert.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <errno.h> #include <unistd.h> -#include <sys/types.h> -#include <sys/wait.h> -#include "ptrace.h" -#include <asm/unistd.h> -#include "common.h" - -/* If the system headers did not provide the constants, hard-code the normal - values. */ -#ifndef PTRACE_EVENT_FORK - -#define PTRACE_OLDSETOPTIONS 21 -#define PTRACE_SETOPTIONS 0x4200 -#define PTRACE_GETEVENTMSG 0x4201 - -/* options set using PTRACE_SETOPTIONS */ -#define PTRACE_O_TRACESYSGOOD 0x00000001 -#define PTRACE_O_TRACEFORK 0x00000002 -#define PTRACE_O_TRACEVFORK 0x00000004 -#define PTRACE_O_TRACECLONE 0x00000008 -#define PTRACE_O_TRACEEXEC 0x00000010 -#define PTRACE_O_TRACEVFORKDONE 0x00000020 -#define PTRACE_O_TRACEEXIT 0x00000040 - -/* Wait extended result codes for the above trace options. */ -#define PTRACE_EVENT_FORK 1 -#define PTRACE_EVENT_VFORK 2 -#define PTRACE_EVENT_CLONE 3 -#define PTRACE_EVENT_EXEC 4 -#define PTRACE_EVENT_VFORK_DONE 5 -#define PTRACE_EVENT_EXIT 6 - -#endif /* PTRACE_EVENT_FORK */ - -#ifdef ARCH_HAVE_UMOVELONG -extern int arch_umovelong (Process *, void *, long *, arg_type_info *); -int -umovelong (Process *proc, void *addr, long *result, arg_type_info *info) { - return arch_umovelong (proc, addr, result, info); -} -#else -/* Read a single long from the process's memory address 'addr' */ -int -umovelong (Process *proc, void *addr, long *result, arg_type_info *info) { - long pointed_to; +#ifdef HAVE_LIBSELINUX +# include <selinux/selinux.h> +#endif - errno = 0; - pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0); - if (pointed_to == -1 && errno) - return -errno; +#include "linux-gnu/trace.h" +#include "linux-gnu/trace-defs.h" +#include "backend.h" +#include "breakpoint.h" +#include "debug.h" +#include "events.h" +#include "options.h" +#include "proc.h" +#include "ptrace.h" +#include "type.h" - *result = pointed_to; - return 0; +void +trace_fail_warning(pid_t pid) +{ + /* This was adapted from GDB. */ +#ifdef HAVE_LIBSELINUX + static int checked = 0; + if (checked) + return; + checked = 1; + + /* -1 is returned for errors, 0 if it has no effect, 1 if + * PTRACE_ATTACH is forbidden. */ + if (security_get_boolean_active("deny_ptrace") == 1) + fprintf(stderr, +"The SELinux boolean 'deny_ptrace' is enabled, which may prevent ltrace from\n" +"tracing other processes. You can disable this process attach protection by\n" +"issuing 'setsebool deny_ptrace=0' in the superuser context.\n"); +#endif /* HAVE_LIBSELINUX */ } -#endif void -trace_me(void) { - debug(DEBUG_PROCESS, "trace_me: pid=%d\n", getpid()); - if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) { +trace_me(void) +{ + debug(DEBUG_PROCESS, "trace_me: pid=%d", getpid()); + if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { perror("PTRACE_TRACEME"); + trace_fail_warning(getpid()); exit(1); } } +/* There's a (hopefully) brief period of time after the child process + * forks when we can't trace it yet. Here we wait for kernel to + * prepare the process. */ int -trace_pid(pid_t pid) { - debug(DEBUG_PROCESS, "trace_pid: pid=%d\n", pid); - if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) { - return -1; - } - +wait_for_proc(pid_t pid) +{ /* man ptrace: PTRACE_ATTACH attaches to the process specified in pid. The child is sent a SIGSTOP, but will not necessarily have stopped by the completion of this call; use wait() to wait for the child to stop. */ - if (waitpid (pid, NULL, 0) != pid) { + if (waitpid(pid, NULL, __WALL) != pid) { perror ("trace_pid: waitpid"); - exit (1); + return -1; } return 0; } +int +trace_pid(pid_t pid) +{ + debug(DEBUG_PROCESS, "trace_pid: pid=%d", pid); + /* This shouldn't emit error messages, as there are legitimate + * reasons that the PID can't be attached: like it may have + * already ended. */ + if (ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) + return -1; + + return wait_for_proc(pid); +} + void -trace_set_options(Process *proc, pid_t pid) { +trace_set_options(struct Process *proc) +{ if (proc->tracesysgood & 0x80) return; - debug(DEBUG_PROCESS, "trace_set_options: pid=%d\n", pid); + pid_t pid = proc->pid; + debug(DEBUG_PROCESS, "trace_set_options: pid=%d", pid); long options = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXEC; - if (ptrace(PTRACE_SETOPTIONS, pid, 0, options) < 0 && - ptrace(PTRACE_OLDSETOPTIONS, pid, 0, options) < 0) { + if (ptrace(PTRACE_SETOPTIONS, pid, 0, (void *)options) < 0 && + ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)options) < 0) { perror("PTRACE_SETOPTIONS"); return; } @@ -107,87 +132,1077 @@ trace_set_options(Process *proc, pid_t pid) { void untrace_pid(pid_t pid) { - debug(DEBUG_PROCESS, "untrace_pid: pid=%d\n", pid); - ptrace(PTRACE_DETACH, pid, 1, 0); + debug(DEBUG_PROCESS, "untrace_pid: pid=%d", pid); + ptrace(PTRACE_DETACH, pid, 0, 0); } void -continue_after_signal(pid_t pid, int signum) { - Process *proc; +continue_after_signal(pid_t pid, int signum) +{ + debug(DEBUG_PROCESS, "continue_after_signal: pid=%d, signum=%d", + pid, signum); + ptrace(PTRACE_SYSCALL, pid, 0, (void *)(uintptr_t)signum); +} - debug(DEBUG_PROCESS, "continue_after_signal: pid=%d, signum=%d", pid, signum); +static enum ecb_status +event_for_pid(Event *event, void *data) +{ + if (event->proc != NULL && event->proc->pid == (pid_t)(uintptr_t)data) + return ecb_yield; + return ecb_cont; +} - proc = pid2proc(pid); - if (proc && proc->breakpoint_being_enabled) { -#if defined __sparc__ || defined __ia64___ - ptrace(PTRACE_SYSCALL, pid, 0, signum); -#else - ptrace(PTRACE_SINGLESTEP, pid, 0, signum); -#endif +static int +have_events_for(pid_t pid) +{ + return each_qd_event(event_for_pid, (void *)(uintptr_t)pid) != NULL; +} + +void +continue_process(pid_t pid) +{ + debug(DEBUG_PROCESS, "continue_process: pid=%d", pid); + + /* Only really continue the process if there are no events in + the queue for this process. Otherwise just wait for the + other events to arrive. */ + if (!have_events_for(pid)) + /* We always trace syscalls to control fork(), + * clone(), execve()... */ + ptrace(PTRACE_SYSCALL, pid, 0, 0); + else + debug(DEBUG_PROCESS, + "putting off the continue, events in que."); +} + +static struct pid_task * +get_task_info(struct pid_set *pids, pid_t pid) +{ + assert(pid != 0); + size_t i; + for (i = 0; i < pids->count; ++i) + if (pids->tasks[i].pid == pid) + return &pids->tasks[i]; + + return NULL; +} + +static struct pid_task * +add_task_info(struct pid_set *pids, pid_t pid) +{ + if (pids->count == pids->alloc) { + size_t ns = (2 * pids->alloc) ?: 4; + struct pid_task *n = realloc(pids->tasks, + sizeof(*pids->tasks) * ns); + if (n == NULL) + return NULL; + pids->tasks = n; + pids->alloc = ns; + } + struct pid_task * task_info = &pids->tasks[pids->count++]; + memset(task_info, 0, sizeof(*task_info)); + task_info->pid = pid; + return task_info; +} + +static enum callback_status +task_stopped(struct Process *task, void *data) +{ + enum process_status st = process_status(task->pid); + if (data != NULL) + *(enum process_status *)data = st; + + /* If the task is already stopped, don't worry about it. + * Likewise if it managed to become a zombie or terminate in + * the meantime. This can happen when the whole thread group + * is terminating. */ + switch (st) { + case ps_invalid: + case ps_tracing_stop: + case ps_zombie: + return CBS_CONT; + case ps_sleeping: + case ps_stop: + case ps_other: + return CBS_STOP; + } + + abort (); +} + +/* Task is blocked if it's stopped, or if it's a vfork parent. */ +static enum callback_status +task_blocked(struct Process *task, void *data) +{ + struct pid_set *pids = data; + struct pid_task *task_info = get_task_info(pids, task->pid); + if (task_info != NULL + && task_info->vforked) + return CBS_CONT; + + return task_stopped(task, NULL); +} + +static Event *process_vfork_on_event(struct event_handler *super, Event *event); + +static enum callback_status +task_vforked(struct Process *task, void *data) +{ + if (task->event_handler != NULL + && task->event_handler->on_event == &process_vfork_on_event) + return CBS_STOP; + return CBS_CONT; +} + +static int +is_vfork_parent(struct Process *task) +{ + return each_task(task->leader, NULL, &task_vforked, NULL) != NULL; +} + +static enum callback_status +send_sigstop(struct Process *task, void *data) +{ + struct Process *leader = task->leader; + struct pid_set *pids = data; + + /* Look for pre-existing task record, or add new. */ + struct pid_task *task_info = get_task_info(pids, task->pid); + if (task_info == NULL) + task_info = add_task_info(pids, task->pid); + if (task_info == NULL) { + perror("send_sigstop: add_task_info"); + destroy_event_handler(leader); + /* Signal failure upwards. */ + return CBS_STOP; + } + + /* This task still has not been attached to. It should be + stopped by the kernel. */ + if (task->state == STATE_BEING_CREATED) + return CBS_CONT; + + /* Don't bother sending SIGSTOP if we are already stopped, or + * if we sent the SIGSTOP already, which happens when we are + * handling "onexit" and inherited the handler from breakpoint + * re-enablement. */ + enum process_status st; + if (task_stopped(task, &st) == CBS_CONT) + return CBS_CONT; + if (task_info->sigstopped) { + if (!task_info->delivered) + return CBS_CONT; + task_info->delivered = 0; + } + + /* Also don't attempt to stop the process if it's a parent of + * vforked process. We set up event handler specially to hint + * us. In that case parent is in D state, which we use to + * weed out unnecessary looping. */ + if (st == ps_sleeping + && is_vfork_parent (task)) { + task_info->vforked = 1; + return CBS_CONT; + } + + if (task_kill(task->pid, SIGSTOP) >= 0) { + debug(DEBUG_PROCESS, "send SIGSTOP to %d", task->pid); + task_info->sigstopped = 1; + } else + fprintf(stderr, + "Warning: couldn't send SIGSTOP to %d\n", task->pid); + + return CBS_CONT; +} + +/* On certain kernels, detaching right after a singlestep causes the + tracee to be killed with a SIGTRAP (that even though the singlestep + was properly caught by waitpid. The ugly workaround is to put a + breakpoint where IP points and let the process continue. After + this the breakpoint can be retracted and the process detached. */ +static void +ugly_workaround(struct Process *proc) +{ + void *ip = get_instruction_pointer(proc); + struct breakpoint *sbp = dict_find_entry(proc->leader->breakpoints, ip); + if (sbp != NULL) + enable_breakpoint(proc, sbp); + else + insert_breakpoint(proc, ip, NULL); + ptrace(PTRACE_CONT, proc->pid, 0, 0); +} + +static void +process_stopping_done(struct process_stopping_handler *self, + struct Process *leader) +{ + debug(DEBUG_PROCESS, "process stopping done %d", + self->task_enabling_breakpoint->pid); + + if (!self->exiting) { + size_t i; + for (i = 0; i < self->pids.count; ++i) + if (self->pids.tasks[i].pid != 0 + && (self->pids.tasks[i].delivered + || self->pids.tasks[i].sysret)) + continue_process(self->pids.tasks[i].pid); + continue_process(self->task_enabling_breakpoint->pid); + } + + if (self->exiting) { + ugly_workaround: + self->state = psh_ugly_workaround; + ugly_workaround(self->task_enabling_breakpoint); } else { - ptrace(PTRACE_SYSCALL, pid, 0, signum); + switch ((self->ugly_workaround_p)(self)) { + case CBS_FAIL: + /* xxx handle me */ + case CBS_STOP: + break; + case CBS_CONT: + goto ugly_workaround; + } + destroy_event_handler(leader); } } -void -continue_process(pid_t pid) { - /* We always trace syscalls to control fork(), clone(), execve()... */ +/* Before we detach, we need to make sure that task's IP is on the + * edge of an instruction. So for tasks that have a breakpoint event + * in the queue, we adjust the instruction pointer, just like + * continue_after_breakpoint does. */ +static enum ecb_status +undo_breakpoint(Event *event, void *data) +{ + if (event != NULL + && event->proc->leader == data + && event->type == EVENT_BREAKPOINT) + set_instruction_pointer(event->proc, event->e_un.brk_addr); + return ecb_cont; +} - debug(DEBUG_PROCESS, "continue_process: pid=%d", pid); +static enum callback_status +untrace_task(struct Process *task, void *data) +{ + if (task != data) + untrace_pid(task->pid); + return CBS_CONT; +} + +static enum callback_status +remove_task(struct Process *task, void *data) +{ + /* Don't untrace leader just yet. */ + if (task != data) + remove_process(task); + return CBS_CONT; +} + +static enum callback_status +retract_breakpoint_cb(struct Process *proc, struct breakpoint *bp, void *data) +{ + breakpoint_on_retract(bp, proc); + return CBS_CONT; +} + +static void +detach_process(struct Process *leader) +{ + each_qd_event(&undo_breakpoint, leader); + disable_all_breakpoints(leader); + proc_each_breakpoint(leader, NULL, retract_breakpoint_cb, NULL); + + /* Now untrace the process, if it was attached to by -p. */ + struct opt_p_t *it; + for (it = opt_p; it != NULL; it = it->next) { + struct Process *proc = pid2proc(it->pid); + if (proc == NULL) + continue; + if (proc->leader == leader) { + each_task(leader, NULL, &untrace_task, NULL); + break; + } + } + each_task(leader, NULL, &remove_task, leader); + destroy_event_handler(leader); + remove_task(leader, NULL); +} + +static void +handle_stopping_event(struct pid_task *task_info, Event **eventp) +{ + /* Mark all events, so that we know whom to SIGCONT later. */ + if (task_info != NULL) + task_info->got_event = 1; + + Event *event = *eventp; + + /* In every state, sink SIGSTOP events for tasks that it was + * sent to. */ + if (task_info != NULL + && event->type == EVENT_SIGNAL + && event->e_un.signum == SIGSTOP) { + debug(DEBUG_PROCESS, "SIGSTOP delivered to %d", task_info->pid); + if (task_info->sigstopped + && !task_info->delivered) { + task_info->delivered = 1; + *eventp = NULL; // sink the event + } else + fprintf(stderr, "suspicious: %d got SIGSTOP, but " + "sigstopped=%d and delivered=%d\n", + task_info->pid, task_info->sigstopped, + task_info->delivered); + } +} + +/* Some SIGSTOPs may have not been delivered to their respective tasks + * yet. They are still in the queue. If we have seen an event for + * that process, continue it, so that the SIGSTOP can be delivered and + * caught by ltrace. We don't mind that the process is after + * breakpoint (and therefore potentially doesn't have aligned IP), + * because the signal will be delivered without the process actually + * starting. */ +static void +continue_for_sigstop_delivery(struct pid_set *pids) +{ + size_t i; + for (i = 0; i < pids->count; ++i) { + if (pids->tasks[i].pid != 0 + && pids->tasks[i].sigstopped + && !pids->tasks[i].delivered + && pids->tasks[i].got_event) { + debug(DEBUG_PROCESS, "continue %d for SIGSTOP delivery", + pids->tasks[i].pid); + ptrace(PTRACE_SYSCALL, pids->tasks[i].pid, 0, 0); + } + } +} + +static int +event_exit_p(Event *event) +{ + return event != NULL && (event->type == EVENT_EXIT + || event->type == EVENT_EXIT_SIGNAL); +} - ptrace(PTRACE_SYSCALL, pid, 0, 0); +static int +event_exit_or_none_p(Event *event) +{ + return event == NULL || event_exit_p(event) + || event->type == EVENT_NONE; +} + +static int +await_sigstop_delivery(struct pid_set *pids, struct pid_task *task_info, + Event *event) +{ + /* If we still didn't get our SIGSTOP, continue the process + * and carry on. */ + if (event != NULL && !event_exit_or_none_p(event) + && task_info != NULL && task_info->sigstopped) { + debug(DEBUG_PROCESS, "continue %d for SIGSTOP delivery", + task_info->pid); + /* We should get the signal the first thing + * after this, so it should be OK to continue + * even if we are over a breakpoint. */ + ptrace(PTRACE_SYSCALL, task_info->pid, 0, 0); + + } else { + /* If all SIGSTOPs were delivered, uninstall the + * handler and continue everyone. */ + /* XXX I suspect that we should check tasks that are + * still around. Is things are now, there should be a + * race between waiting for everyone to stop and one + * of the tasks exiting. */ + int all_clear = 1; + size_t i; + for (i = 0; i < pids->count; ++i) + if (pids->tasks[i].pid != 0 + && pids->tasks[i].sigstopped + && !pids->tasks[i].delivered) { + all_clear = 0; + break; + } + return all_clear; + } + + return 0; +} + +static int +all_stops_accountable(struct pid_set *pids) +{ + size_t i; + for (i = 0; i < pids->count; ++i) + if (pids->tasks[i].pid != 0 + && !pids->tasks[i].got_event + && !have_events_for(pids->tasks[i].pid)) + return 0; + return 1; +} + +/* The protocol is: 0 for success, negative for failure, positive if + * default singlestep is to be used. */ +int arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp, + int (*add_cb)(void *addr, void *data), + void *add_cb_data); + +#ifndef ARCH_HAVE_ATOMIC_SINGLESTEP +int +arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp, + int (*add_cb)(void *addr, void *data), + void *add_cb_data) +{ + return 1; +} +#endif + +static Event *process_stopping_on_event(struct event_handler *super, + Event *event); + +static void +remove_atomic_breakpoints(struct Process *proc) +{ + struct process_stopping_handler *self + = (void *)proc->leader->event_handler; + assert(self != NULL); + assert(self->super.on_event == process_stopping_on_event); + + int ct = sizeof(self->atomic_skip_bp_addrs) + / sizeof(*self->atomic_skip_bp_addrs); + int i; + for (i = 0; i < ct; ++i) + if (self->atomic_skip_bp_addrs[i] != 0) { + delete_breakpoint(proc, self->atomic_skip_bp_addrs[i]); + self->atomic_skip_bp_addrs[i] = 0; + } +} + +static void +atomic_singlestep_bp_on_hit(struct breakpoint *bp, struct Process *proc) +{ + remove_atomic_breakpoints(proc); +} + +static int +atomic_singlestep_add_bp(void *addr, void *data) +{ + struct process_stopping_handler *self = data; + struct Process *proc = self->task_enabling_breakpoint; + + int ct = sizeof(self->atomic_skip_bp_addrs) + / sizeof(*self->atomic_skip_bp_addrs); + int i; + for (i = 0; i < ct; ++i) + if (self->atomic_skip_bp_addrs[i] == 0) { + self->atomic_skip_bp_addrs[i] = addr; + static struct bp_callbacks cbs = { + .on_hit = atomic_singlestep_bp_on_hit, + }; + struct breakpoint *bp + = insert_breakpoint(proc, addr, NULL); + breakpoint_set_callbacks(bp, &cbs); + return 0; + } + + assert(!"Too many atomic singlestep breakpoints!"); + abort(); +} + +static int +singlestep(struct process_stopping_handler *self) +{ + struct Process *proc = self->task_enabling_breakpoint; + + int status = arch_atomic_singlestep(self->task_enabling_breakpoint, + self->breakpoint_being_enabled, + &atomic_singlestep_add_bp, self); + + /* Propagate failure and success. */ + if (status <= 0) + return status; + + /* Otherwise do the default action: singlestep. */ + debug(1, "PTRACE_SINGLESTEP"); + if (ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0)) { + perror("PTRACE_SINGLESTEP"); + return -1; + } + return 0; +} + +static void +post_singlestep(struct process_stopping_handler *self, + struct Event **eventp) +{ + continue_for_sigstop_delivery(&self->pids); + + if (*eventp != NULL && (*eventp)->type == EVENT_BREAKPOINT) + *eventp = NULL; // handled + + struct Process *proc = self->task_enabling_breakpoint; + + remove_atomic_breakpoints(proc); + self->breakpoint_being_enabled = NULL; +} + +static void +singlestep_error(struct process_stopping_handler *self) +{ + struct Process *teb = self->task_enabling_breakpoint; + struct breakpoint *sbp = self->breakpoint_being_enabled; + fprintf(stderr, "%d couldn't continue when handling %s (%p) at %p\n", + teb->pid, breakpoint_name(sbp), sbp->addr, + get_instruction_pointer(teb)); + delete_breakpoint(teb->leader, sbp->addr); +} + +static void +pt_continue(struct process_stopping_handler *self) +{ + struct Process *teb = self->task_enabling_breakpoint; + debug(1, "PTRACE_CONT"); + ptrace(PTRACE_CONT, teb->pid, 0, 0); +} + +static void +pt_singlestep(struct process_stopping_handler *self) +{ + if (singlestep(self) < 0) + singlestep_error(self); +} + +static void +disable_and(struct process_stopping_handler *self, + void (*do_this)(struct process_stopping_handler *self)) +{ + struct Process *teb = self->task_enabling_breakpoint; + debug(DEBUG_PROCESS, "all stopped, now singlestep/cont %d", teb->pid); + if (self->breakpoint_being_enabled->enabled) + disable_breakpoint(teb, self->breakpoint_being_enabled); + (do_this)(self); + self->state = psh_singlestep; +} + +void +linux_ptrace_disable_and_singlestep(struct process_stopping_handler *self) +{ + disable_and(self, &pt_singlestep); } void -continue_enabling_breakpoint(pid_t pid, Breakpoint *sbp) { - enable_breakpoint(pid, sbp); - continue_process(pid); +linux_ptrace_disable_and_continue(struct process_stopping_handler *self) +{ + disable_and(self, &pt_continue); +} + +/* This event handler is installed when we are in the process of + * stopping the whole thread group to do the pointer re-enablement for + * one of the threads. We pump all events to the queue for later + * processing while we wait for all the threads to stop. When this + * happens, we let the re-enablement thread to PTRACE_SINGLESTEP, + * re-enable, and continue everyone. */ +static Event * +process_stopping_on_event(struct event_handler *super, Event *event) +{ + struct process_stopping_handler *self = (void *)super; + struct Process *task = event->proc; + struct Process *leader = task->leader; + struct Process *teb = self->task_enabling_breakpoint; + + debug(DEBUG_PROCESS, + "process_stopping_on_event: pid %d; event type %d; state %d", + task->pid, event->type, self->state); + + struct pid_task *task_info = get_task_info(&self->pids, task->pid); + if (task_info == NULL) + fprintf(stderr, "new task??? %d\n", task->pid); + handle_stopping_event(task_info, &event); + + int state = self->state; + int event_to_queue = !event_exit_or_none_p(event); + + /* Deactivate the entry if the task exits. */ + if (event_exit_p(event) && task_info != NULL) + task_info->pid = 0; + + /* Always handle sysrets. Whether sysret occurred and what + * sys it rets from may need to be determined based on process + * stack, so we need to keep that in sync with reality. Note + * that we don't continue the process after the sysret is + * handled. See continue_after_syscall. */ + if (event != NULL && event->type == EVENT_SYSRET) { + debug(1, "%d LT_EV_SYSRET", event->proc->pid); + event_to_queue = 0; + task_info->sysret = 1; + } + + switch (state) { + case psh_stopping: + /* If everyone is stopped, singlestep. */ + if (each_task(leader, NULL, &task_blocked, + &self->pids) == NULL) { + (self->on_all_stopped)(self); + state = self->state; + } + break; + + case psh_singlestep: + /* In singlestep state, breakpoint signifies that we + * have now stepped, and can re-enable the breakpoint. */ + if (event != NULL && task == teb) { + + /* If this was caused by a real breakpoint, as + * opposed to a singlestep, assume that it's + * an artificial breakpoint installed for some + * reason for the re-enablement. In that case + * handle it. */ + if (event->type == EVENT_BREAKPOINT) { + arch_addr_t ip + = get_instruction_pointer(task); + struct breakpoint *other + = address2bpstruct(leader, ip); + if (other != NULL) + breakpoint_on_hit(other, task); + } + + /* If we got SIGNAL instead of BREAKPOINT, + * then this is not singlestep at all. */ + if (event->type == EVENT_SIGNAL) { + do_singlestep: + if (singlestep(self) < 0) { + singlestep_error(self); + post_singlestep(self, &event); + goto psh_sinking; + } + break; + } else { + switch ((self->keep_stepping_p)(self)) { + case CBS_FAIL: + /* XXX handle me */ + case CBS_STOP: + break; + case CBS_CONT: + /* Sink singlestep event. */ + if (event->type == EVENT_BREAKPOINT) + event = NULL; + goto do_singlestep; + } + } + + /* Re-enable the breakpoint that we are + * stepping over. */ + struct breakpoint *sbp = self->breakpoint_being_enabled; + if (sbp->enabled) + enable_breakpoint(teb, sbp); + + post_singlestep(self, &event); + goto psh_sinking; + } + break; + + psh_sinking: + state = self->state = psh_sinking; + case psh_sinking: + if (await_sigstop_delivery(&self->pids, task_info, event)) + process_stopping_done(self, leader); + break; + + case psh_ugly_workaround: + if (event == NULL) + break; + if (event->type == EVENT_BREAKPOINT) { + undo_breakpoint(event, leader); + if (task == teb) + self->task_enabling_breakpoint = NULL; + } + if (self->task_enabling_breakpoint == NULL + && all_stops_accountable(&self->pids)) { + undo_breakpoint(event, leader); + detach_process(leader); + event = NULL; // handled + } + } + + if (event != NULL && event_to_queue) { + enque_event(event); + event = NULL; // sink the event + } + + return event; +} + +static void +process_stopping_destroy(struct event_handler *super) +{ + struct process_stopping_handler *self = (void *)super; + free(self->pids.tasks); +} + +static enum callback_status +no(struct process_stopping_handler *self) +{ + return CBS_STOP; +} + +int +process_install_stopping_handler(struct Process *proc, struct breakpoint *sbp, + void (*as)(struct process_stopping_handler *), + enum callback_status (*ks) + (struct process_stopping_handler *), + enum callback_status (*uw) + (struct process_stopping_handler *)) +{ + debug(DEBUG_FUNCTION, + "process_install_stopping_handler: pid=%d", proc->pid); + + struct process_stopping_handler *handler = calloc(sizeof(*handler), 1); + if (handler == NULL) + return -1; + + if (as == NULL) + as = &linux_ptrace_disable_and_singlestep; + if (ks == NULL) + ks = &no; + if (uw == NULL) + uw = &no; + + handler->super.on_event = process_stopping_on_event; + handler->super.destroy = process_stopping_destroy; + handler->task_enabling_breakpoint = proc; + handler->breakpoint_being_enabled = sbp; + handler->on_all_stopped = as; + handler->keep_stepping_p = ks; + handler->ugly_workaround_p = uw; + + install_event_handler(proc->leader, &handler->super); + + if (each_task(proc->leader, NULL, &send_sigstop, + &handler->pids) != NULL) { + destroy_event_handler(proc); + return -1; + } + + /* And deliver the first fake event, in case all the + * conditions are already fulfilled. */ + Event ev = { + .type = EVENT_NONE, + .proc = proc, + }; + process_stopping_on_event(&handler->super, &ev); + + return 0; } void -continue_after_breakpoint(Process *proc, Breakpoint *sbp) { - if (sbp->enabled) - disable_breakpoint(proc->pid, sbp); +continue_after_breakpoint(Process *proc, struct breakpoint *sbp) +{ + debug(DEBUG_PROCESS, + "continue_after_breakpoint: pid=%d, addr=%p", + proc->pid, sbp->addr); + set_instruction_pointer(proc, sbp->addr); + if (sbp->enabled == 0) { continue_process(proc->pid); } else { - debug(DEBUG_PROCESS, "continue_after_breakpoint: pid=%d, addr=%p", proc->pid, sbp->addr); - proc->breakpoint_being_enabled = sbp; #if defined __sparc__ || defined __ia64___ /* we don't want to singlestep here */ continue_process(proc->pid); #else - ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0); + if (process_install_stopping_handler + (proc, sbp, NULL, NULL, NULL) < 0) { + perror("process_stopping_handler_create"); + /* Carry on not bothering to re-enable. */ + continue_process(proc->pid); + } #endif } } -/* Read a series of bytes starting at the process's memory address - 'addr' and continuing until a NUL ('\0') is seen or 'len' bytes - have been read. -*/ +/** + * Ltrace exit. When we are about to exit, we have to go through all + * the processes, stop them all, remove all the breakpoints, and then + * detach the processes that we attached to using -p. If we left the + * other tasks running, they might hit stray return breakpoints and + * produce artifacts, so we better stop everyone, even if it's a bit + * of extra work. + */ +struct ltrace_exiting_handler +{ + struct event_handler super; + struct pid_set pids; +}; + +static Event * +ltrace_exiting_on_event(struct event_handler *super, Event *event) +{ + struct ltrace_exiting_handler *self = (void *)super; + struct Process *task = event->proc; + struct Process *leader = task->leader; + + debug(DEBUG_PROCESS, + "ltrace_exiting_on_event: pid %d; event type %d", + task->pid, event->type); + + struct pid_task *task_info = get_task_info(&self->pids, task->pid); + handle_stopping_event(task_info, &event); + + if (event != NULL && event->type == EVENT_BREAKPOINT) + undo_breakpoint(event, leader); + + if (await_sigstop_delivery(&self->pids, task_info, event) + && all_stops_accountable(&self->pids)) + detach_process(leader); + + /* Sink all non-exit events. We are about to exit, so we + * don't bother with queuing them. */ + if (event_exit_or_none_p(event)) + return event; + + return NULL; +} + +static void +ltrace_exiting_destroy(struct event_handler *super) +{ + struct ltrace_exiting_handler *self = (void *)super; + free(self->pids.tasks); +} + +static int +ltrace_exiting_install_handler(struct Process *proc) +{ + /* Only install to leader. */ + if (proc->leader != proc) + return 0; + + /* Perhaps we are already installed, if the user passed + * several -p options that are tasks of one process. */ + if (proc->event_handler != NULL + && proc->event_handler->on_event == <race_exiting_on_event) + return 0; + + /* If stopping handler is already present, let it do the + * work. */ + if (proc->event_handler != NULL) { + assert(proc->event_handler->on_event + == &process_stopping_on_event); + struct process_stopping_handler *other + = (void *)proc->event_handler; + other->exiting = 1; + return 0; + } + + struct ltrace_exiting_handler *handler + = calloc(sizeof(*handler), 1); + if (handler == NULL) { + perror("malloc exiting handler"); + fatal: + /* XXXXXXXXXXXXXXXXXXX fixme */ + return -1; + } + + handler->super.on_event = ltrace_exiting_on_event; + handler->super.destroy = ltrace_exiting_destroy; + install_event_handler(proc->leader, &handler->super); + + if (each_task(proc->leader, NULL, &send_sigstop, + &handler->pids) != NULL) + goto fatal; + + return 0; +} + +/* + * When the traced process vforks, it's suspended until the child + * process calls _exit or exec*. In the meantime, the two share the + * address space. + * + * The child process should only ever call _exit or exec*, but we + * can't count on that (it's not the role of ltrace to policy, but to + * observe). In any case, we will _at least_ have to deal with + * removal of vfork return breakpoint (which we have to smuggle back + * in, so that the parent can see it, too), and introduction of exec* + * return breakpoint. Since we already have both breakpoint actions + * to deal with, we might as well support it all. + * + * The gist is that we pretend that the child is in a thread group + * with its parent, and handle it as a multi-threaded case, with the + * exception that we know that the parent is blocked, and don't + * attempt to stop it. When the child execs, we undo the setup. + */ + +struct process_vfork_handler +{ + struct event_handler super; + void *bp_addr; +}; + +static Event * +process_vfork_on_event(struct event_handler *super, Event *event) +{ + debug(DEBUG_PROCESS, + "process_vfork_on_event: pid %d; event type %d", + event->proc->pid, event->type); + + struct process_vfork_handler *self = (void *)super; + struct breakpoint *sbp; + assert(self != NULL); + + switch (event->type) { + case EVENT_BREAKPOINT: + /* Remember the vfork return breakpoint. */ + if (self->bp_addr == 0) + self->bp_addr = event->e_un.brk_addr; + break; + + case EVENT_EXIT: + case EVENT_EXIT_SIGNAL: + case EVENT_EXEC: + /* Smuggle back in the vfork return breakpoint, so + * that our parent can trip over it once again. */ + if (self->bp_addr != 0) { + sbp = dict_find_entry(event->proc->leader->breakpoints, + self->bp_addr); + if (sbp != NULL) + assert(sbp->libsym == NULL); + /* We don't mind failing that, it's not a big + * deal to not display one extra vfork return. */ + insert_breakpoint(event->proc->parent, + self->bp_addr, NULL); + } + + continue_process(event->proc->parent->pid); + + /* Remove the leader that we artificially set up + * earlier. */ + change_process_leader(event->proc, event->proc); + destroy_event_handler(event->proc); + + default: + ; + } + + return event; +} + +void +continue_after_vfork(struct Process *proc) +{ + debug(DEBUG_PROCESS, "continue_after_vfork: pid=%d", proc->pid); + struct process_vfork_handler *handler = calloc(sizeof(*handler), 1); + if (handler == NULL) { + perror("malloc vfork handler"); + /* Carry on not bothering to treat the process as + * necessary. */ + continue_process(proc->parent->pid); + return; + } + + /* We must set up custom event handler, so that we see + * exec/exit events for the task itself. */ + handler->super.on_event = process_vfork_on_event; + install_event_handler(proc, &handler->super); + + /* Make sure that the child is sole thread. */ + assert(proc->leader == proc); + assert(proc->next == NULL || proc->next->leader != proc); + + /* Make sure that the child's parent is properly set up. */ + assert(proc->parent != NULL); + assert(proc->parent->leader != NULL); + + change_process_leader(proc, proc->parent->leader); +} + +static int +is_mid_stopping(Process *proc) +{ + return proc != NULL + && proc->event_handler != NULL + && proc->event_handler->on_event == &process_stopping_on_event; +} + +void +continue_after_syscall(struct Process *proc, int sysnum, int ret_p) +{ + /* Don't continue if we are mid-stopping. */ + if (ret_p && (is_mid_stopping(proc) || is_mid_stopping(proc->leader))) { + debug(DEBUG_PROCESS, + "continue_after_syscall: don't continue %d", + proc->pid); + return; + } + continue_process(proc->pid); +} + +/* If ltrace gets SIGINT, the processes directly or indirectly run by + * ltrace get it too. We just have to wait long enough for the signal + * to be delivered and the process terminated, which we notice and + * exit ltrace, too. So there's not much we need to do there. We + * want to keep tracing those processes as usual, in case they just + * SIG_IGN the SIGINT to do their shutdown etc. + * + * For processes ran on the background, we want to install an exit + * handler that stops all the threads, removes all breakpoints, and + * detaches. + */ +void +os_ltrace_exiting(void) +{ + struct opt_p_t *it; + for (it = opt_p; it != NULL; it = it->next) { + struct Process *proc = pid2proc(it->pid); + if (proc == NULL || proc->leader == NULL) + continue; + if (ltrace_exiting_install_handler(proc->leader) < 0) + fprintf(stderr, + "Couldn't install exiting handler for %d.\n", + proc->pid); + } +} + int -umovestr(Process *proc, void *addr, int len, void *laddr) { +os_ltrace_exiting_sighandler(void) +{ + extern int linux_in_waitpid; + if (linux_in_waitpid) { + os_ltrace_exiting(); + return 1; + } + return 0; +} + +size_t +umovebytes(Process *proc, void *addr, void *laddr, size_t len) { + union { long a; char c[sizeof(long)]; } a; - int i; - int offset = 0; + int started = 0; + size_t offset = 0, bytes_read = 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 + (signed)i < len) { - *(char *)(laddr + offset + i) = a.c[i]; - } else { - *(char *)(laddr + offset + i) = '\0'; - return 0; - } + if (a.a == -1 && errno) { + if (started && errno == EIO) + return bytes_read; + else + return -1; + } + started = 1; + + if (len - offset >= sizeof(long)) { + memcpy(laddr + offset, &a.c[0], sizeof(long)); + bytes_read += sizeof(long); + } + else { + memcpy(laddr + offset, &a.c[0], len - offset); + bytes_read += (len - offset); } offset += sizeof(long); } - *(char *)(laddr + offset) = '\0'; - return 0; + + return bytes_read; } diff --git a/sysdeps/linux-gnu/trace.h b/sysdeps/linux-gnu/trace.h new file mode 100644 index 0000000..88ac33d --- /dev/null +++ b/sysdeps/linux-gnu/trace.h @@ -0,0 +1,121 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef _LTRACE_LINUX_TRACE_H_ +#define _LTRACE_LINUX_TRACE_H_ + +#include "proc.h" + +/* This publishes some Linux-specific data structures used for process + * handling. */ + +/** + * This is used for bookkeeping related to PIDs that the event + * handlers work with. + */ +struct pid_task { + pid_t pid; /* This may be 0 for tasks that exited + * mid-handling. */ + int sigstopped : 1; + int got_event : 1; + int delivered : 1; + int vforked : 1; + int sysret : 1; +}; + +struct pid_set { + struct pid_task *tasks; + size_t count; + size_t alloc; +}; + +/** + * Breakpoint re-enablement. When we hit a breakpoint, we must + * disable it, single-step, and re-enable it. That single-step can be + * done only by one task in a task group, while others are stopped, + * otherwise the processes would race for who sees the breakpoint + * disabled and who doesn't. The following is to keep track of it + * all. + */ +struct process_stopping_handler +{ + struct event_handler super; + + /* The task that is doing the re-enablement. */ + struct Process *task_enabling_breakpoint; + + /* The pointer being re-enabled. */ + struct breakpoint *breakpoint_being_enabled; + + /* Artificial atomic skip breakpoint, if any needed. */ + void *atomic_skip_bp_addrs[2]; + + /* When all tasks are stopped, this callback gets called. */ + void (*on_all_stopped)(struct process_stopping_handler *); + + /* When we get a singlestep event, this is called to decide + * whether to stop stepping, or whether to enable the + * brakpoint, sink remaining signals, and continue + * everyone. */ + enum callback_status (*keep_stepping_p) + (struct process_stopping_handler *); + + /* Whether we need to use ugly workaround to get around + * various problems with singlestepping. */ + enum callback_status (*ugly_workaround_p) + (struct process_stopping_handler *); + + enum { + /* We are waiting for everyone to land in t/T. */ + psh_stopping = 0, + + /* We are doing the PTRACE_SINGLESTEP. */ + psh_singlestep, + + /* We are waiting for all the SIGSTOPs to arrive so + * that we can sink them. */ + psh_sinking, + + /* This is for tracking the ugly workaround. */ + psh_ugly_workaround, + } state; + + int exiting; + + struct pid_set pids; +}; + +/* Allocate a process stopping handler, initialize it and install it. + * Return 0 on success or a negative value on failure. Pass NULL for + * each callback to use a default instead. The default for + * ON_ALL_STOPPED is LINUX_PTRACE_DISABLE_AND_SINGLESTEP, the default + * for KEEP_STEPPING_P and UGLY_WORKAROUND_P is "no". */ +int process_install_stopping_handler + (struct Process *proc, struct breakpoint *sbp, + void (*on_all_stopped)(struct process_stopping_handler *), + enum callback_status (*keep_stepping_p) + (struct process_stopping_handler *), + enum callback_status (*ugly_workaround_p) + (struct process_stopping_handler *)); + +void linux_ptrace_disable_and_singlestep(struct process_stopping_handler *self); +void linux_ptrace_disable_and_continue(struct process_stopping_handler *self); + +#endif /* _LTRACE_LINUX_TRACE_H_ */ diff --git a/sysdeps/linux-gnu/x86/Makefile.am b/sysdeps/linux-gnu/x86/Makefile.am new file mode 100644 index 0000000..ee45bab --- /dev/null +++ b/sysdeps/linux-gnu/x86/Makefile.am @@ -0,0 +1,37 @@ +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ + trace.c \ + fetch.c + +noinst_HEADERS = \ + arch.h \ + ptrace.h \ + signalent.h \ + signalent1.h \ + syscallent.h \ + syscallent1.h + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/sysdeps/linux-gnu/x86/Makefile.in b/sysdeps/linux-gnu/x86/Makefile.in new file mode 100644 index 0000000..bb7bc9f --- /dev/null +++ b/sysdeps/linux-gnu/x86/Makefile.in @@ -0,0 +1,532 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# This file is part of ltrace. +# Copyright (C) 2010 Marc Kleine-Budde, Pengutronix +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = sysdeps/linux-gnu/x86 +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/config/m4/libtool.m4 \ + $(top_srcdir)/config/m4/ltoptions.m4 \ + $(top_srcdir)/config/m4/ltsugar.m4 \ + $(top_srcdir)/config/m4/ltversion.m4 \ + $(top_srcdir)/config/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +___libcpu_la_LIBADD = +am____libcpu_la_OBJECTS = plt.lo regs.lo trace.lo fetch.lo +___libcpu_la_OBJECTS = $(am____libcpu_la_OBJECTS) +am__dirstamp = $(am__leading_dot)dirstamp +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/config/autoconf/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(___libcpu_la_SOURCES) +DIST_SOURCES = $(___libcpu_la_SOURCES) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAVE_VALGRIND = @HAVE_VALGRIND@ +HOST_CPU = @HOST_CPU@ +HOST_OS = @HOST_OS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libelf_LD_LIBRARY_PATH = @libelf_LD_LIBRARY_PATH@ +liberty_LIBS = @liberty_LIBS@ +libexecdir = @libexecdir@ +libstdcxx_LIBS = @libstdcxx_LIBS@ +libsupcxx_LIBS = @libsupcxx_LIBS@ +libunwind_LD_LIBRARY_PATH = @libunwind_LD_LIBRARY_PATH@ +libunwind_LIBS = @libunwind_LIBS@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = \ + ../libcpu.la + +___libcpu_la_SOURCES = \ + plt.c \ + regs.c \ + trace.c \ + fetch.c + +noinst_HEADERS = \ + arch.h \ + ptrace.h \ + signalent.h \ + signalent1.h \ + syscallent.h \ + syscallent1.h + +MAINTAINERCLEANFILES = \ + Makefile.in + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign sysdeps/linux-gnu/x86/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign sysdeps/linux-gnu/x86/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +../$(am__dirstamp): + @$(MKDIR_P) .. + @: > ../$(am__dirstamp) +../libcpu.la: $(___libcpu_la_OBJECTS) $(___libcpu_la_DEPENDENCIES) ../$(am__dirstamp) + $(LINK) $(___libcpu_la_OBJECTS) $(___libcpu_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fetch.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf ../.libs ../_libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f ../$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sysdeps/linux-gnu/x86/arch.h b/sysdeps/linux-gnu/x86/arch.h new file mode 100644 index 0000000..329cfba --- /dev/null +++ b/sysdeps/linux-gnu/x86/arch.h @@ -0,0 +1,36 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2011, 2012 Petr Machata + * Copyright (C) 2006 Ian Wienand + * Copyright (C) 2004 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#define BREAKPOINT_VALUE {0xcc} +#define BREAKPOINT_LENGTH 1 +#define DECR_PC_AFTER_BREAK 1 +#define ARCH_HAVE_FETCH_ARG +#define ARCH_HAVE_SIZEOF +#define ARCH_HAVE_ALIGNOF +#define ARCH_ENDIAN_LITTLE + +#ifdef __x86_64__ +#define LT_ELFCLASS ELFCLASS64 +#define LT_ELF_MACHINE EM_X86_64 +#endif +#define LT_ELFCLASS2 ELFCLASS32 +#define LT_ELF_MACHINE2 EM_386 diff --git a/sysdeps/linux-gnu/x86/fetch.c b/sysdeps/linux-gnu/x86/fetch.c new file mode 100644 index 0000000..4dab4cc --- /dev/null +++ b/sysdeps/linux-gnu/x86/fetch.c @@ -0,0 +1,849 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2011,2012 Petr Machata + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include "config.h" + +#include <sys/types.h> +#include <assert.h> +#include <gelf.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "backend.h" +#include "expr.h" +#include "fetch.h" +#include "proc.h" +#include "ptrace.h" +#include "type.h" +#include "value.h" + +enum arg_class { + CLASS_INTEGER, + CLASS_SSE, + CLASS_NO, + CLASS_MEMORY, + CLASS_X87, +}; + +enum reg_pool { + POOL_FUNCALL, + POOL_SYSCALL, + /* A common pool for system call and function call return is + * enough, the ABI is similar enough. */ + POOL_RETVAL, +}; + +struct fetch_context +{ + struct user_regs_struct iregs; + struct user_fpregs_struct fpregs; + + void *stack_pointer; + size_t ireg; /* Used-up integer registers. */ + size_t freg; /* Used-up floating registers. */ + + union { + struct { + /* Storage classes for return type. We need + * to compute them anyway, so let's keep them + * around. */ + enum arg_class ret_classes[2]; + ssize_t num_ret_classes; + } x86_64; + struct { + struct value retval; + } ix86; + } u; +}; + +#ifndef __x86_64__ +__attribute__((noreturn)) static void +i386_unreachable(void) +{ + abort(); +} +#endif + +static int +contains_unaligned_fields(struct arg_type_info *info) +{ + /* XXX currently we don't support structure alignment. */ + return 0; +} + +static int +has_nontrivial_ctor_dtor(struct arg_type_info *info) +{ + /* XXX another unsupported aspect of type info. We might call + * these types "class" instead of "struct" in the config + * file. */ + return 0; +} + +static void +copy_int_register(struct fetch_context *context, + struct value *valuep, unsigned long val, size_t offset) +{ + if (valuep != NULL) { + unsigned char *buf = value_get_raw_data(valuep); + memcpy(buf + offset, &val, sizeof(val)); + } + context->ireg++; +} + +static void +copy_sse_register(struct fetch_context *context, struct value *valuep, + int half, size_t sz, size_t offset) +{ +#ifdef __x86_64__ + union { + uint32_t sse[4]; + long halves[2]; + } u; + size_t off = 4 * context->freg++; + memcpy(u.sse, context->fpregs.xmm_space + off, sizeof(u.sse)); + + if (valuep != NULL) { + unsigned char *buf = value_get_raw_data(valuep); + memcpy(buf + offset, u.halves + half, sz); + } +#else + i386_unreachable(); +#endif +} + +static void +allocate_stack_slot(struct fetch_context *context, + struct value *valuep, size_t sz, size_t offset, + size_t archw) +{ + size_t a = type_alignof(valuep->inferior, valuep->type); + if (a < archw) + a = archw; + context->stack_pointer + = (void *)align((unsigned long)context->stack_pointer, a); + + if (valuep != NULL) + value_in_inferior(valuep, context->stack_pointer); + context->stack_pointer += sz; +} + +static enum arg_class +allocate_x87(struct fetch_context *context, struct value *valuep, + size_t sz, size_t offset, enum reg_pool pool, size_t archw) +{ + /* Both i386 and x86_64 ABI only ever really use x87 registers + * to return values. Otherwise, the parameter is treated as + * if it were CLASS_MEMORY. On x86_64 x87 registers are only + * used for returning long double values, which we currently + * don't support. */ + + if (pool != POOL_RETVAL) { + allocate_stack_slot(context, valuep, sz, offset, archw); + return CLASS_MEMORY; + + } + + /* If the class is X87, the value is returned on the X87 stack + * in %st0 as 80-bit x87 number. + * + * If the class is X87UP, the value is returned together with + * the previous X87 value in %st0. + * + * If the class is COMPLEX_X87, the real part of the value is + * returned in %st0 and the imaginary part in %st1. */ + + if (valuep != NULL) { + union { + long double ld; + double d; + float f; + char buf[0]; + } u; + + /* The x87 floating point value is in long double + * format, so we need to convert in to the right type. + * Alternatively we might just leave it as is and + * smuggle the long double type into the value (via + * value_set_type), but for that we first need to + * support long double in the first place. */ + +#ifdef __x86_64__ + unsigned int *reg; +#else + long int *reg; +#endif + reg = &context->fpregs.st_space[0]; + memcpy(&u.ld, reg, sizeof(u)); + if (valuep->type->type == ARGTYPE_FLOAT) + u.f = (float)u.ld; + else if (valuep->type->type == ARGTYPE_DOUBLE) + u.d = (double)u.ld; + else + assert(!"Unexpected floating type!"), abort(); + + unsigned char *buf = value_get_raw_data(valuep); + memcpy(buf + offset, u.buf, sz); + } + return CLASS_X87; +} + +static enum arg_class +allocate_integer(struct fetch_context *context, struct value *valuep, + size_t sz, size_t offset, enum reg_pool pool) +{ +#define HANDLE(NUM, WHICH) \ + case NUM: \ + copy_int_register(context, valuep, \ + context->iregs.WHICH, offset); \ + return CLASS_INTEGER + + switch (pool) { + case POOL_FUNCALL: +#ifdef __x86_64__ + switch (context->ireg) { + HANDLE(0, rdi); + HANDLE(1, rsi); + HANDLE(2, rdx); + HANDLE(3, rcx); + HANDLE(4, r8); + HANDLE(5, r9); + default: + allocate_stack_slot(context, valuep, sz, offset, 8); + return CLASS_MEMORY; + } +#else + i386_unreachable(); +#endif + + case POOL_SYSCALL: +#ifdef __x86_64__ + switch (context->ireg) { + HANDLE(0, rdi); + HANDLE(1, rsi); + HANDLE(2, rdx); + HANDLE(3, r10); + HANDLE(4, r8); + HANDLE(5, r9); + default: + assert(!"More than six syscall arguments???"); + abort(); + } +#else + i386_unreachable(); +#endif + + case POOL_RETVAL: + switch (context->ireg) { +#ifdef __x86_64__ + HANDLE(0, rax); + HANDLE(1, rdx); +#else + HANDLE(0, eax); +#endif + default: + assert(!"Too many return value classes."); + abort(); + } + } + + abort(); + +#undef HANDLE +} + +static enum arg_class +allocate_sse(struct fetch_context *context, struct value *valuep, + size_t sz, size_t offset, enum reg_pool pool) +{ + size_t num_regs = 0; + switch (pool) { + case POOL_FUNCALL: + num_regs = 8; + case POOL_SYSCALL: + break; + case POOL_RETVAL: + num_regs = 2; + } + + if (context->freg >= num_regs) { + /* We shouldn't see overflow for RETVAL or SYSCALL + * pool. */ + assert(pool == POOL_FUNCALL); + allocate_stack_slot(context, valuep, sz, offset, 8); + return CLASS_MEMORY; + } else { + copy_sse_register(context, valuep, 0, sz, offset); + return CLASS_SSE; + } +} + +/* This allocates registers or stack space for another argument of the + * class CLS. */ +static enum arg_class +allocate_class(enum arg_class cls, struct fetch_context *context, + struct value *valuep, size_t sz, size_t offset, enum reg_pool pool) +{ + switch (cls) { + case CLASS_MEMORY: + allocate_stack_slot(context, valuep, sz, offset, 8); + case CLASS_NO: + return cls; + + case CLASS_INTEGER: + return allocate_integer(context, valuep, sz, offset, pool); + + case CLASS_SSE: + return allocate_sse(context, valuep, sz, offset, pool); + + case CLASS_X87: + return allocate_x87(context, valuep, sz, offset, pool, 8); + } + abort(); +} + +static ssize_t +classify(struct Process *proc, struct fetch_context *context, + struct arg_type_info *info, struct value *valuep, enum arg_class classes[], + size_t sz, size_t eightbytes); + +/* This classifies one eightbyte part of an array or struct. */ +static ssize_t +classify_eightbyte(struct Process *proc, struct fetch_context *context, + struct arg_type_info *info, struct value *valuep, + enum arg_class *classp, size_t start, size_t end, + struct arg_type_info *(*getter)(struct arg_type_info *, + size_t)) +{ + size_t i; + enum arg_class cls = CLASS_NO; + for (i = start; i < end; ++i) { + enum arg_class cls2; + struct arg_type_info *info2 = getter(info, i); + size_t sz = type_sizeof(proc, info2); + if (sz == (size_t)-1) + return -1; + if (classify(proc, context, info2, valuep, &cls2, sz, 1) < 0) + return -1; + + if (cls == CLASS_NO) + cls = cls2; + else if (cls2 == CLASS_NO || cls == cls2) + ; + else if (cls == CLASS_MEMORY || cls2 == CLASS_MEMORY) + cls = CLASS_MEMORY; + else if (cls == CLASS_INTEGER || cls2 == CLASS_INTEGER) + cls = CLASS_INTEGER; + else + cls = CLASS_SSE; + } + + *classp = cls; + return 1; +} + +/* This classifies small arrays and structs. */ +static ssize_t +classify_eightbytes(struct Process *proc, struct fetch_context *context, + struct arg_type_info *info, struct value *valuep, + enum arg_class classes[], size_t elements, + size_t eightbytes, + struct arg_type_info *(*getter)(struct arg_type_info *, + size_t)) +{ + if (eightbytes > 1) { + /* Where the second eightbyte starts. Number of the + * first element in the structure that belongs to the + * second eightbyte. */ + size_t start_2nd = 0; + size_t i; + for (i = 0; i < elements; ++i) + if (type_offsetof(proc, info, i) >= 8) { + start_2nd = i; + break; + } + + enum arg_class cls1, cls2; + if (classify_eightbyte(proc, context, info, valuep, &cls1, + 0, start_2nd, getter) < 0 + || classify_eightbyte(proc, context, info, valuep, &cls2, + start_2nd, elements, getter) < 0) + return -1; + + if (cls1 == CLASS_MEMORY || cls2 == CLASS_MEMORY) { + classes[0] = CLASS_MEMORY; + return 1; + } + + classes[0] = cls1; + classes[1] = cls2; + return 2; + } + + return classify_eightbyte(proc, context, info, valuep, classes, + 0, elements, getter); +} + +static struct arg_type_info * +get_array_field(struct arg_type_info *info, size_t emt) +{ + return info->u.array_info.elt_type; +} + +static int +flatten_structure(struct arg_type_info *flattened, struct arg_type_info *info) +{ + size_t i; + for (i = 0; i < type_struct_size(info); ++i) { + struct arg_type_info *field = type_struct_get(info, i); + assert(field != NULL); + switch (field->type) { + case ARGTYPE_STRUCT: + if (flatten_structure(flattened, field) < 0) + return -1; + break; + + default: + if (type_struct_add(flattened, field, 0) < 0) + return -1; + } + } + return 0; +} + +static ssize_t +classify(struct Process *proc, struct fetch_context *context, + struct arg_type_info *info, struct value *valuep, enum arg_class classes[], + size_t sz, size_t eightbytes) +{ + switch (info->type) { + struct arg_type_info flattened; + case ARGTYPE_VOID: + return 0; + + case ARGTYPE_CHAR: + case ARGTYPE_SHORT: + case ARGTYPE_USHORT: + case ARGTYPE_INT: + case ARGTYPE_UINT: + case ARGTYPE_LONG: + case ARGTYPE_ULONG: + + case ARGTYPE_POINTER: + /* and LONGLONG */ + /* CLASS_INTEGER */ + classes[0] = CLASS_INTEGER; + return 1; + + case ARGTYPE_FLOAT: + case ARGTYPE_DOUBLE: + /* and DECIMAL, and _m64 */ + classes[0] = CLASS_SSE; + return 1; + + case ARGTYPE_ARRAY: + /* N.B. this cannot be top-level array, those decay to + * pointers. Therefore, it must be inside structure + * that's at most 2 eightbytes long. */ + + /* Structures with flexible array members can't be + * passed by value. */ + assert(expr_is_compile_constant(info->u.array_info.length)); + + long l; + if (expr_eval_constant(info->u.array_info.length, &l) < 0) + return -1; + + return classify_eightbytes(proc, context, info, valuep, classes, + (size_t)l, eightbytes, + get_array_field); + + case ARGTYPE_STRUCT: + /* N.B. "big" structs are dealt with in the caller. + * + * First, we need to flatten the structure. In + * struct(float,struct(float,float)), first two floats + * both belong to the same eightbyte. */ + type_init_struct(&flattened); + + ssize_t ret; + if (flatten_structure(&flattened, info) < 0) { + ret = -1; + goto done; + } + ret = classify_eightbytes(proc, context, &flattened, + valuep, classes, + type_struct_size(&flattened), + eightbytes, type_struct_get); + done: + type_destroy(&flattened); + return ret; + + default: + /* Unsupported type. */ + assert(info->type != info->type); + abort(); + } + abort(); +} + +static ssize_t +pass_by_reference(struct value *valuep, enum arg_class classes[]) +{ + if (valuep != NULL && value_pass_by_reference(valuep) < 0) + return -1; + classes[0] = CLASS_INTEGER; + return 1; +} + +static ssize_t +classify_argument(struct Process *proc, struct fetch_context *context, + struct arg_type_info *info, struct value *valuep, + enum arg_class classes[], size_t *sizep) +{ + size_t sz = type_sizeof(proc, info); + if (sz == (size_t)-1) + return -1; + *sizep = sz; + + size_t eightbytes = (sz + 7) / 8; /* Round up. */ + + /* Arrays decay into pointers. */ + assert(info->type != ARGTYPE_ARRAY); + + if (info->type == ARGTYPE_STRUCT) { + if (eightbytes > 2 || contains_unaligned_fields(info)) { + classes[0] = CLASS_MEMORY; + return 1; + } + + if (has_nontrivial_ctor_dtor(info)) + return pass_by_reference(valuep, classes); + } + + return classify(proc, context, info, valuep, classes, sz, eightbytes); +} + +static int +fetch_register_banks(struct Process *proc, struct fetch_context *context, + int floating) +{ + if (ptrace(PTRACE_GETREGS, proc->pid, 0, &context->iregs) < 0) + return -1; + context->ireg = 0; + + if (floating) { + if (ptrace(PTRACE_GETFPREGS, proc->pid, + 0, &context->fpregs) < 0) + return -1; + context->freg = 0; + } else { + context->freg = -1; + } + + return 0; +} + +static int +arch_fetch_arg_next_32(struct fetch_context *context, enum tof type, + struct Process *proc, struct arg_type_info *info, + struct value *valuep) +{ + size_t sz = type_sizeof(proc, info); + if (sz == (size_t)-1) + return -1; + + allocate_stack_slot(context, valuep, sz, 0, 4); + + return 0; +} + +static int +arch_fetch_retval_32(struct fetch_context *context, enum tof type, + struct Process *proc, struct arg_type_info *info, + struct value *valuep) +{ + if (fetch_register_banks(proc, context, type == LT_TOF_FUNCTIONR) < 0) + return -1; + + struct value *retval = &context->u.ix86.retval; + if (retval->type != NULL) { + /* Struct return value was extracted when in fetch + * init. */ + memcpy(valuep, &context->u.ix86.retval, sizeof(*valuep)); + return 0; + } + + size_t sz = type_sizeof(proc, info); + if (sz == (size_t)-1) + return -1; + if (value_reserve(valuep, sz) == NULL) + return -1; + + switch (info->type) { + enum arg_class cls; + case ARGTYPE_VOID: + return 0; + + case ARGTYPE_INT: + case ARGTYPE_UINT: + case ARGTYPE_LONG: + case ARGTYPE_ULONG: + case ARGTYPE_CHAR: + case ARGTYPE_SHORT: + case ARGTYPE_USHORT: + case ARGTYPE_POINTER: + cls = allocate_integer(context, valuep, sz, 0, POOL_RETVAL); + assert(cls == CLASS_INTEGER); + return 0; + + case ARGTYPE_FLOAT: + case ARGTYPE_DOUBLE: + cls = allocate_x87(context, valuep, sz, 0, POOL_RETVAL, 4); + assert(cls == CLASS_X87); + return 0; + + case ARGTYPE_STRUCT: /* Handled above. */ + default: + assert(!"Unexpected i386 retval type!"); + abort(); + } + + abort(); +} + +static arch_addr_t +fetch_stack_pointer(struct fetch_context *context) +{ + arch_addr_t sp; +#ifdef __x86_64__ + sp = (arch_addr_t)context->iregs.rsp; +#else + sp = (arch_addr_t)context->iregs.esp; +#endif + return sp; +} + +struct fetch_context * +arch_fetch_arg_init_32(struct fetch_context *context, + enum tof type, struct Process *proc, + struct arg_type_info *ret_info) +{ + context->stack_pointer = fetch_stack_pointer(context) + 4; + + size_t sz = type_sizeof(proc, ret_info); + if (sz == (size_t)-1) + return NULL; + + struct value *retval = &context->u.ix86.retval; + if (ret_info->type == ARGTYPE_STRUCT) { + value_init(retval, proc, NULL, ret_info, 0); + + enum arg_class dummy[2]; + if (pass_by_reference(retval, dummy) < 0) + return NULL; + allocate_stack_slot(context, retval, 4, 0, 4); + + } else { + value_init_detached(retval, NULL, NULL, 0); + } + + return context; +} + +struct fetch_context * +arch_fetch_arg_init_64(struct fetch_context *ctx, enum tof type, + struct Process *proc, struct arg_type_info *ret_info) +{ + /* The first stack slot holds a return address. */ + ctx->stack_pointer = fetch_stack_pointer(ctx) + 8; + + size_t size; + ctx->u.x86_64.num_ret_classes + = classify_argument(proc, ctx, ret_info, NULL, + ctx->u.x86_64.ret_classes, &size); + if (ctx->u.x86_64.num_ret_classes == -1) + return NULL; + + /* If the class is MEMORY, then the first argument is a hidden + * pointer to the allocated storage. */ + if (ctx->u.x86_64.num_ret_classes > 0 + && ctx->u.x86_64.ret_classes[0] == CLASS_MEMORY) { + /* MEMORY should be the sole class. */ + assert(ctx->u.x86_64.num_ret_classes == 1); + allocate_integer(ctx, NULL, size, 0, POOL_FUNCALL); + } + + return ctx; +} + +struct fetch_context * +arch_fetch_arg_init(enum tof type, struct Process *proc, + struct arg_type_info *ret_info) +{ + struct fetch_context *ctx = malloc(sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + assert(type != LT_TOF_FUNCTIONR + && type != LT_TOF_SYSCALLR); + if (fetch_register_banks(proc, ctx, type == LT_TOF_FUNCTION) < 0) { + fail: + free(ctx); + return NULL; + } + + struct fetch_context *ret; + if (proc->e_machine == EM_386) + ret = arch_fetch_arg_init_32(ctx, type, proc, ret_info); + else + ret = arch_fetch_arg_init_64(ctx, type, proc, ret_info); + if (ret == NULL) + goto fail; + return ret; +} + +struct fetch_context * +arch_fetch_arg_clone(struct Process *proc, struct fetch_context *context) +{ + struct fetch_context *ret = malloc(sizeof(*ret)); + if (ret == NULL) + return NULL; + return memcpy(ret, context, sizeof(*ret)); +} + +static int +arch_fetch_pool_arg_next(struct fetch_context *context, enum tof type, + struct Process *proc, struct arg_type_info *info, + struct value *valuep, enum reg_pool pool) +{ + enum arg_class classes[2]; + size_t sz, sz1; + ssize_t i; + ssize_t nclasses = classify_argument(proc, context, info, valuep, + classes, &sz); + if (nclasses == -1) + return -1; + if (value_reserve(valuep, sz) == NULL) + return -1; + + /* If there are no registers available for any eightbyte of an + * argument, the whole argument is passed on the stack. If + * registers have already been assigned for some eightbytes of + * such an argument, the assignments get reverted. */ + struct fetch_context tmp_context = *context; + int revert; + if (nclasses == 1) { + revert = allocate_class(classes[0], &tmp_context, + valuep, sz, 0, pool) != classes[0]; + } else { + revert = 0; + for (i = 0; i < nclasses; ++i) { + sz1 = (size_t)(8 * (i + 1)) > sz ? sz - 8 * i : 8; + if (allocate_class(classes[i], &tmp_context, valuep, + sz1, 8 * i, pool) != classes[i]) + revert = 1; + } + } + + if (nclasses > 1 && revert) + allocate_class(CLASS_MEMORY, context, valuep, sz, 0, pool); + else + *context = tmp_context; /* Commit. */ + + return 0; +} + +int +arch_fetch_fun_retval(struct fetch_context *context, enum tof type, + struct Process *proc, struct arg_type_info *info, + struct value *valuep) +{ + assert(type != LT_TOF_FUNCTION + && type != LT_TOF_SYSCALL); + if (value_reserve(valuep, 8 * context->u.x86_64.num_ret_classes) == NULL + || fetch_register_banks(proc, context, + type == LT_TOF_FUNCTIONR) < 0) + return -1; + + if (context->u.x86_64.num_ret_classes == 1 + && context->u.x86_64.ret_classes[0] == CLASS_MEMORY) + pass_by_reference(valuep, context->u.x86_64.ret_classes); + + size_t sz = type_sizeof(proc, valuep->type); + if (sz == (size_t)-1) + return -1; + + ssize_t i; + size_t sz1 = context->u.x86_64.num_ret_classes == 1 ? sz : 8; + for (i = 0; i < context->u.x86_64.num_ret_classes; ++i) { + enum arg_class cls + = allocate_class(context->u.x86_64.ret_classes[i], + context, valuep, sz1, + 8 * i, POOL_RETVAL); + assert(cls == context->u.x86_64.ret_classes[i]); + } + return 0; +} + +int +arch_fetch_arg_next(struct fetch_context *context, enum tof type, + struct Process *proc, struct arg_type_info *info, + struct value *valuep) +{ + if (proc->e_machine == EM_386) + return arch_fetch_arg_next_32(context, type, proc, + info, valuep); + + switch (type) { + case LT_TOF_FUNCTION: + case LT_TOF_FUNCTIONR: + return arch_fetch_pool_arg_next(context, type, proc, + info, valuep, POOL_FUNCALL); + + case LT_TOF_SYSCALL: + case LT_TOF_SYSCALLR: + return arch_fetch_pool_arg_next(context, type, proc, + info, valuep, POOL_SYSCALL); + } + + abort(); +} + +int +arch_fetch_retval(struct fetch_context *context, enum tof type, + struct Process *proc, struct arg_type_info *info, + struct value *valuep) +{ + if (proc->e_machine == EM_386) + return arch_fetch_retval_32(context, type, proc, info, valuep); + + return arch_fetch_fun_retval(context, type, proc, info, valuep); +} + +void +arch_fetch_arg_done(struct fetch_context *context) +{ + if (context != NULL) + free(context); +} diff --git a/sysdeps/linux-gnu/x86/plt.c b/sysdeps/linux-gnu/x86/plt.c new file mode 100644 index 0000000..dc6f183 --- /dev/null +++ b/sysdeps/linux-gnu/x86/plt.c @@ -0,0 +1,34 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2004,2008,2009 Juan Cespedes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include <gelf.h> +#include "proc.h" +#include "common.h" +#include "library.h" + +GElf_Addr +arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { + return lte->plt_addr + (ndx + 1) * 16; +} + +void * +sym2addr(Process *proc, struct library_symbol *sym) { + return sym->enter_addr; +} diff --git a/sysdeps/linux-gnu/x86/ptrace.h b/sysdeps/linux-gnu/x86/ptrace.h new file mode 100644 index 0000000..dc4734a --- /dev/null +++ b/sysdeps/linux-gnu/x86/ptrace.h @@ -0,0 +1,21 @@ +/* + * This file is part of ltrace. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include <sys/ptrace.h> +#include <sys/user.h> diff --git a/sysdeps/linux-gnu/x86/regs.c b/sysdeps/linux-gnu/x86/regs.c new file mode 100644 index 0000000..ca6470b --- /dev/null +++ b/sysdeps/linux-gnu/x86/regs.c @@ -0,0 +1,116 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * Copyright (C) 1998,2002,2004,2008,2009 Juan Cespedes + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#include "config.h" + +#include <sys/types.h> +#include <sys/ptrace.h> +#include <sys/reg.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#include "backend.h" +#include "proc.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +#ifdef __x86_64__ +# define XIP (8 * RIP) +# define XSP (8 * RSP) +#else +# define XIP (4 * EIP) +# define XSP (4 * UESP) +#endif + +static arch_addr_t +conv_32(arch_addr_t val) +{ + /* XXX Drop the multiple double casts when arch_addr_t + * becomes integral. */ + return (arch_addr_t)(uintptr_t)(uint32_t)(uintptr_t)val; +} + +void * +get_instruction_pointer(struct Process *proc) +{ + long int ret = ptrace(PTRACE_PEEKUSER, proc->pid, XIP, 0); + if (proc->e_machine == EM_386) + ret &= 0xffffffff; + return (void *)ret; +} + +void +set_instruction_pointer(struct Process *proc, arch_addr_t addr) +{ + if (proc->e_machine == EM_386) + addr = conv_32(addr); + ptrace(PTRACE_POKEUSER, proc->pid, XIP, addr); +} + +void * +get_stack_pointer(struct Process *proc) +{ + long sp = ptrace(PTRACE_PEEKUSER, proc->pid, XSP, 0); + if (sp == -1 && errno) { + fprintf(stderr, "Couldn't read SP register: %s\n", + strerror(errno)); + return NULL; + } + + /* XXX Drop the multiple double casts when arch_addr_t + * becomes integral. */ + arch_addr_t ret = (arch_addr_t)(uintptr_t)sp; + if (proc->e_machine == EM_386) + ret = conv_32(ret); + return ret; +} + +void * +get_return_addr(struct Process *proc, void *sp) +{ + long a = ptrace(PTRACE_PEEKTEXT, proc->pid, sp, 0); + if (a == -1 && errno) { + fprintf(stderr, "Couldn't read return value: %s\n", + strerror(errno)); + return NULL; + } + + /* XXX Drop the multiple double casts when arch_addr_t + * becomes integral. */ + arch_addr_t ret = (arch_addr_t)(uintptr_t)a; + if (proc->e_machine == EM_386) + ret = conv_32(ret); + return ret; +} + +void +set_return_addr(Process *proc, void *addr) { + if (proc->e_machine == EM_386) + addr = (void *)((long int)addr & 0xffffffff); + ptrace(PTRACE_POKETEXT, proc->pid, proc->stack_pointer, addr); +} diff --git a/sysdeps/linux-gnu/x86_64/signalent.h b/sysdeps/linux-gnu/x86/signalent.h index d58a36c..9b8baa0 100644 --- a/sysdeps/linux-gnu/x86_64/signalent.h +++ b/sysdeps/linux-gnu/x86/signalent.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + "SIG_0", /* 0 */ "SIGHUP", /* 1 */ "SIGINT", /* 2 */ diff --git a/sysdeps/linux-gnu/i386/signalent.h b/sysdeps/linux-gnu/x86/signalent1.h index 5395f82..31699db 100644 --- a/sysdeps/linux-gnu/i386/signalent.h +++ b/sysdeps/linux-gnu/x86/signalent1.h @@ -1,3 +1,23 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + "SIG_0", /* 0 */ "SIGHUP", /* 1 */ "SIGINT", /* 2 */ diff --git a/sysdeps/linux-gnu/x86/syscallent.h b/sysdeps/linux-gnu/x86/syscallent.h new file mode 100644 index 0000000..345fe20 --- /dev/null +++ b/sysdeps/linux-gnu/x86/syscallent.h @@ -0,0 +1,370 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +/* This file is for i386 system call names. */ + "restart_syscall", /* 0 */ + "exit", /* 1 */ + "fork", /* 2 */ + "read", /* 3 */ + "write", /* 4 */ + "open", /* 5 */ + "close", /* 6 */ + "waitpid", /* 7 */ + "creat", /* 8 */ + "link", /* 9 */ + "unlink", /* 10 */ + "execve", /* 11 */ + "chdir", /* 12 */ + "time", /* 13 */ + "mknod", /* 14 */ + "chmod", /* 15 */ + "lchown", /* 16 */ + "break", /* 17 */ + "oldstat", /* 18 */ + "lseek", /* 19 */ + "getpid", /* 20 */ + "mount", /* 21 */ + "umount", /* 22 */ + "setuid", /* 23 */ + "getuid", /* 24 */ + "stime", /* 25 */ + "ptrace", /* 26 */ + "alarm", /* 27 */ + "oldfstat", /* 28 */ + "pause", /* 29 */ + "utime", /* 30 */ + "stty", /* 31 */ + "gtty", /* 32 */ + "access", /* 33 */ + "nice", /* 34 */ + "ftime", /* 35 */ + "sync", /* 36 */ + "kill", /* 37 */ + "rename", /* 38 */ + "mkdir", /* 39 */ + "rmdir", /* 40 */ + "dup", /* 41 */ + "pipe", /* 42 */ + "times", /* 43 */ + "prof", /* 44 */ + "brk", /* 45 */ + "setgid", /* 46 */ + "getgid", /* 47 */ + "signal", /* 48 */ + "geteuid", /* 49 */ + "getegid", /* 50 */ + "acct", /* 51 */ + "umount2", /* 52 */ + "lock", /* 53 */ + "ioctl", /* 54 */ + "fcntl", /* 55 */ + "mpx", /* 56 */ + "setpgid", /* 57 */ + "ulimit", /* 58 */ + "oldolduname", /* 59 */ + "umask", /* 60 */ + "chroot", /* 61 */ + "ustat", /* 62 */ + "dup2", /* 63 */ + "getppid", /* 64 */ + "getpgrp", /* 65 */ + "setsid", /* 66 */ + "sigaction", /* 67 */ + "sgetmask", /* 68 */ + "ssetmask", /* 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 */ + "select", /* 82 */ + "symlink", /* 83 */ + "oldlstat", /* 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 */ + "profil", /* 98 */ + "statfs", /* 99 */ + "fstatfs", /* 100 */ + "ioperm", /* 101 */ + "socketcall", /* 102 */ + "syslog", /* 103 */ + "setitimer", /* 104 */ + "getitimer", /* 105 */ + "stat", /* 106 */ + "lstat", /* 107 */ + "fstat", /* 108 */ + "olduname", /* 109 */ + "iopl", /* 110 */ + "vhangup", /* 111 */ + "idle", /* 112 */ + "vm86old", /* 113 */ + "wait4", /* 114 */ + "swapoff", /* 115 */ + "sysinfo", /* 116 */ + "ipc", /* 117 */ + "fsync", /* 118 */ + "sigreturn", /* 119 */ + "clone", /* 120 */ + "setdomainname", /* 121 */ + "uname", /* 122 */ + "modify_ldt", /* 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 */ + "vm86", /* 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 */ + "pread64", /* 180 */ + "pwrite64", /* 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 */ + "madvise1", /* 219 */ + "getdents64", /* 220 */ + "fcntl64", /* 221 */ + "222", /* 222 */ + "223", /* 223 */ + "gettid", /* 224 */ + "readahead", /* 225 */ + "setxattr", /* 226 */ + "lsetxattr", /* 227 */ + "fsetxattr", /* 228 */ + "getxattr", /* 229 */ + "lgetxattr", /* 230 */ + "fgetxattr", /* 231 */ + "listxattr", /* 232 */ + "llistxattr", /* 233 */ + "flistxattr", /* 234 */ + "removexattr", /* 235 */ + "lremovexattr", /* 236 */ + "fremovexattr", /* 237 */ + "tkill", /* 238 */ + "sendfile64", /* 239 */ + "futex", /* 240 */ + "sched_setaffinity", /* 241 */ + "sched_getaffinity", /* 242 */ + "set_thread_area", /* 243 */ + "get_thread_area", /* 244 */ + "io_setup", /* 245 */ + "io_destroy", /* 246 */ + "io_getevents", /* 247 */ + "io_submit", /* 248 */ + "io_cancel", /* 249 */ + "fadvise64", /* 250 */ + "251", /* 251 */ + "exit_group", /* 252 */ + "lookup_dcookie", /* 253 */ + "epoll_create", /* 254 */ + "epoll_ctl", /* 255 */ + "epoll_wait", /* 256 */ + "remap_file_pages", /* 257 */ + "set_tid_address", /* 258 */ + "timer_create", /* 259 */ + "260", /* 260 */ + "261", /* 261 */ + "262", /* 262 */ + "263", /* 263 */ + "264", /* 264 */ + "265", /* 265 */ + "266", /* 266 */ + "267", /* 267 */ + "statfs64", /* 268 */ + "fstatfs64", /* 269 */ + "tgkill", /* 270 */ + "utimes", /* 271 */ + "fadvise64_64", /* 272 */ + "vserver", /* 273 */ + "mbind", /* 274 */ + "get_mempolicy", /* 275 */ + "set_mempolicy", /* 276 */ + "mq_open", /* 277 */ + "278", /* 278 */ + "279", /* 279 */ + "280", /* 280 */ + "281", /* 281 */ + "282", /* 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 */ + "migrate_pages", /* 294 */ + "openat", /* 295 */ + "mkdirat", /* 296 */ + "mknodat", /* 297 */ + "fchownat", /* 298 */ + "futimesat", /* 299 */ + "fstatat64", /* 300 */ + "unlinkat", /* 301 */ + "renameat", /* 302 */ + "linkat", /* 303 */ + "symlinkat", /* 304 */ + "readlinkat", /* 305 */ + "fchmodat", /* 306 */ + "faccessat", /* 307 */ + "pselect6", /* 308 */ + "ppoll", /* 309 */ + "unshare", /* 310 */ + "set_robust_list", /* 311 */ + "get_robust_list", /* 312 */ + "splice", /* 313 */ + "sync_file_range", /* 314 */ + "tee", /* 315 */ + "vmsplice", /* 316 */ + "move_pages", /* 317 */ + "getcpu", /* 318 */ + "epoll_pwait", /* 319 */ + "utimensat", /* 320 */ + "signalfd", /* 321 */ + "timerfd_create", /* 322 */ + "eventfd", /* 323 */ + "fallocate", /* 324 */ + "timerfd_settime", /* 325 */ + "timerfd_gettime", /* 326 */ + "signalfd4", /* 327 */ + "eventfd2", /* 328 */ + "epoll_create1", /* 329 */ + "dup3", /* 330 */ + "pipe2", /* 331 */ + "inotify_init1", /* 332 */ + "preadv", /* 333 */ + "pwritev", /* 334 */ + "rt_tgsigqueueinfo", /* 335 */ + "perf_event_open", /* 336 */ + "recvmmsg", /* 337 */ + "fanotify_init", /* 338 */ + "fanotify_mark", /* 339 */ + "prlimit64", /* 340 */ + "name_to_handle_at", /* 341 */ + "open_by_handle_at", /* 342 */ + "clock_adjtime", /* 343 */ + "syncfs", /* 344 */ + "sendmmsg", /* 345 */ + "setns", /* 346 */ + "process_vm_readv", /* 347 */ + "process_vm_writev", /* 348 */ diff --git a/sysdeps/linux-gnu/x86/syscallent1.h b/sysdeps/linux-gnu/x86/syscallent1.h new file mode 100644 index 0000000..91ae8d6 --- /dev/null +++ b/sysdeps/linux-gnu/x86/syscallent1.h @@ -0,0 +1,333 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +/* This file is for x86_64 system call names. */ + "read", /* 0 */ + "write", /* 1 */ + "open", /* 2 */ + "close", /* 3 */ + "stat", /* 4 */ + "fstat", /* 5 */ + "lstat", /* 6 */ + "poll", /* 7 */ + "lseek", /* 8 */ + "mmap", /* 9 */ + "mprotect", /* 10 */ + "munmap", /* 11 */ + "brk", /* 12 */ + "rt_sigaction", /* 13 */ + "rt_sigprocmask", /* 14 */ + "rt_sigreturn", /* 15 */ + "ioctl", /* 16 */ + "pread", /* 17 */ + "pwrite", /* 18 */ + "readv", /* 19 */ + "writev", /* 20 */ + "access", /* 21 */ + "pipe", /* 22 */ + "select", /* 23 */ + "sched_yield", /* 24 */ + "mremap", /* 25 */ + "msync", /* 26 */ + "mincore", /* 27 */ + "madvise", /* 28 */ + "shmget", /* 29 */ + "shmat", /* 30 */ + "shmctl", /* 31 */ + "dup", /* 32 */ + "dup2", /* 33 */ + "pause", /* 34 */ + "nanosleep", /* 35 */ + "getitimer", /* 36 */ + "alarm", /* 37 */ + "setitimer", /* 38 */ + "getpid", /* 39 */ + "sendfile", /* 40 */ + "socket", /* 41 */ + "connect", /* 42 */ + "accept", /* 43 */ + "sendto", /* 44 */ + "recvfrom", /* 45 */ + "sendmsg", /* 46 */ + "recvmsg", /* 47 */ + "shutdown", /* 48 */ + "bind", /* 49 */ + "listen", /* 50 */ + "getsockname", /* 51 */ + "getpeername", /* 52 */ + "socketpair", /* 53 */ + "setsockopt", /* 54 */ + "getsockopt", /* 55 */ + "clone", /* 56 */ + "fork", /* 57 */ + "vfork", /* 58 */ + "execve", /* 59 */ + "exit", /* 60 */ + "wait4", /* 61 */ + "kill", /* 62 */ + "uname", /* 63 */ + "semget", /* 64 */ + "semop", /* 65 */ + "semctl", /* 66 */ + "shmdt", /* 67 */ + "msgget", /* 68 */ + "msgsnd", /* 69 */ + "msgrcv", /* 70 */ + "msgctl", /* 71 */ + "fcntl", /* 72 */ + "flock", /* 73 */ + "fsync", /* 74 */ + "fdatasync", /* 75 */ + "truncate", /* 76 */ + "ftruncate", /* 77 */ + "getdents", /* 78 */ + "getcwd", /* 79 */ + "chdir", /* 80 */ + "fchdir", /* 81 */ + "rename", /* 82 */ + "mkdir", /* 83 */ + "rmdir", /* 84 */ + "creat", /* 85 */ + "link", /* 86 */ + "unlink", /* 87 */ + "symlink", /* 88 */ + "readlink", /* 89 */ + "chmod", /* 90 */ + "fchmod", /* 91 */ + "chown", /* 92 */ + "fchown", /* 93 */ + "lchown", /* 94 */ + "umask", /* 95 */ + "gettimeofday", /* 96 */ + "getrlimit", /* 97 */ + "getrusage", /* 98 */ + "sysinfo", /* 99 */ + "times", /* 100 */ + "ptrace", /* 101 */ + "getuid", /* 102 */ + "syslog", /* 103 */ + "getgid", /* 104 */ + "setuid", /* 105 */ + "setgid", /* 106 */ + "geteuid", /* 107 */ + "getegid", /* 108 */ + "setpgid", /* 109 */ + "getppid", /* 110 */ + "getpgrp", /* 111 */ + "setsid", /* 112 */ + "setreuid", /* 113 */ + "setregid", /* 114 */ + "getgroups", /* 115 */ + "setgroups", /* 116 */ + "setresuid", /* 117 */ + "getresuid", /* 118 */ + "setresgid", /* 119 */ + "getresgid", /* 120 */ + "getpgid", /* 121 */ + "setfsuid", /* 122 */ + "setfsgid", /* 123 */ + "getsid", /* 124 */ + "capget", /* 125 */ + "capset", /* 126 */ + "rt_sigpending", /* 127 */ + "rt_sigtimedwait", /* 128 */ + "rt_sigqueueinfo", /* 129 */ + "rt_sigsuspend", /* 130 */ + "sigaltstack", /* 131 */ + "utime", /* 132 */ + "mknod", /* 133 */ + "uselib", /* 134 */ + "personality", /* 135 */ + "ustat", /* 136 */ + "statfs", /* 137 */ + "fstatfs", /* 138 */ + "sysfs", /* 139 */ + "getpriority", /* 140 */ + "setpriority", /* 141 */ + "sched_setparam", /* 142 */ + "sched_getparam", /* 143 */ + "sched_setscheduler", /* 144 */ + "sched_getscheduler", /* 145 */ + "sched_get_priority_max", /* 146 */ + "sched_get_priority_min", /* 147 */ + "sched_rr_get_interval", /* 148 */ + "mlock", /* 149 */ + "munlock", /* 150 */ + "mlockall", /* 151 */ + "munlockall", /* 152 */ + "vhangup", /* 153 */ + "modify_ldt", /* 154 */ + "pivot_root", /* 155 */ + "_sysctl", /* 156 */ + "prctl", /* 157 */ + "arch_prctl", /* 158 */ + "adjtimex", /* 159 */ + "setrlimit", /* 160 */ + "chroot", /* 161 */ + "sync", /* 162 */ + "acct", /* 163 */ + "settimeofday", /* 164 */ + "mount", /* 165 */ + "umount2", /* 166 */ + "swapon", /* 167 */ + "swapoff", /* 168 */ + "reboot", /* 169 */ + "sethostname", /* 170 */ + "setdomainname", /* 171 */ + "iopl", /* 172 */ + "ioperm", /* 173 */ + "create_module", /* 174 */ + "init_module", /* 175 */ + "delete_module", /* 176 */ + "get_kernel_syms", /* 177 */ + "query_module", /* 178 */ + "quotactl", /* 179 */ + "nfsservctl", /* 180 */ + "getpmsg", /* 181 */ + "putpmsg", /* 182 */ + "afs_syscall", /* 183 */ + "tuxcall", /* 184 */ + "security", /* 185 */ + "gettid", /* 186 */ + "readahead", /* 187 */ + "setxattr", /* 188 */ + "lsetxattr", /* 189 */ + "fsetxattr", /* 190 */ + "getxattr", /* 191 */ + "lgetxattr", /* 192 */ + "fgetxattr", /* 193 */ + "listxattr", /* 194 */ + "llistxattr", /* 195 */ + "flistxattr", /* 196 */ + "removexattr", /* 197 */ + "lremovexattr", /* 198 */ + "fremovexattr", /* 199 */ + "tkill", /* 200 */ + "time", /* 201 */ + "futex", /* 202 */ + "sched_setaffinity", /* 203 */ + "sched_getaffinity", /* 204 */ + "set_thread_area", /* 205 */ + "io_setup", /* 206 */ + "io_destroy", /* 207 */ + "io_getevents", /* 208 */ + "io_submit", /* 209 */ + "io_cancel", /* 210 */ + "get_thread_area", /* 211 */ + "lookup_dcookie", /* 212 */ + "epoll_create", /* 213 */ + "epoll_ctl", /* 214 */ + "epoll_wait", /* 215 */ + "remap_file_pages", /* 216 */ + "getdents64", /* 217 */ + "set_tid_address", /* 218 */ + "restart_syscall", /* 219 */ + "semtimedop", /* 220 */ + "fadvise64", /* 221 */ + "timer_create", /* 222 */ + "timer_settime", /* 223 */ + "timer_gettime", /* 224 */ + "timer_getoverrun", /* 225 */ + "timer_delete", /* 226 */ + "clock_settime", /* 227 */ + "clock_gettime", /* 228 */ + "clock_getres", /* 229 */ + "clock_nanosleep", /* 230 */ + "exit_group", /* 231 */ + "epoll_wait", /* 232 */ + "epoll_ctl", /* 233 */ + "tgkill", /* 234 */ + "utimes", /* 235 */ + "vserver", /* 236 */ + "mbind", /* 237 */ + "set_mempolicy", /* 238 */ + "get_mempolicy", /* 239 */ + "mq_open", /* 240 */ + "mq_unlink", /* 241 */ + "mq_timedsend", /* 242 */ + "mq_timedreceive", /* 243 */ + "mq_notify", /* 244 */ + "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 */ + "migrate_pages", /* 256 */ + "openat", /* 257 */ + "mkdirat", /* 258 */ + "mknodat", /* 259 */ + "fchownat", /* 260 */ + "futimesat", /* 261 */ + "newfstatat", /* 262 */ + "unlinkat", /* 263 */ + "renameat", /* 264 */ + "linkat", /* 265 */ + "symlinkat", /* 266 */ + "readlinkat", /* 267 */ + "fchmodat", /* 268 */ + "faccessat", /* 269 */ + "pselect6", /* 270 */ + "ppoll", /* 271 */ + "unshare", /* 272 */ + "set_robust_list", /* 273 */ + "get_robust_list", /* 274 */ + "splice", /* 275 */ + "tee", /* 276 */ + "sync_file_range", /* 277 */ + "vmsplice", /* 278 */ + "move_pages", /* 279 */ + "utimensat", /* 280 */ + "epoll_pwait", /* 281 */ + "signalfd", /* 282 */ + "timerfd_create", /* 283 */ + "eventfd", /* 284 */ + "fallocate", /* 285 */ + "timerfd_settime", /* 286 */ + "timerfd_gettime", /* 287 */ + "accept4", /* 288 */ + "signalfd4", /* 289 */ + "eventfd2", /* 290 */ + "epoll_create1", /* 291 */ + "dup3", /* 292 */ + "pipe2", /* 293 */ + "inotify_init1", /* 294 */ + "preadv", /* 295 */ + "pwritev", /* 296 */ + "rt_tgsigqueueinfo", /* 297 */ + "perf_event_open", /* 298 */ + "recvmmsg", /* 299 */ + "fanotify_init", /* 300 */ + "fanotify_mark", /* 301 */ + "prlimit64", /* 302 */ + "name_to_handle_at", /* 303 */ + "open_by_handle_at", /* 304 */ + "clock_adjtime", /* 305 */ + "syncfs", /* 306 */ + "sendmmsg", /* 307 */ + "setns", /* 308 */ + "getcpu", /* 309 */ + "process_vm_readv", /* 310 */ + "process_vm_writev", /* 311 */ diff --git a/sysdeps/linux-gnu/x86/trace.c b/sysdeps/linux-gnu/x86/trace.c new file mode 100644 index 0000000..ed8bdb4 --- /dev/null +++ b/sysdeps/linux-gnu/x86/trace.c @@ -0,0 +1,191 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2010,2011,2012 Petr Machata, Red Hat Inc. + * Copyright (C) 2004,2008,2009 Juan Cespedes + * Copyright (C) 2006 Ian Wienand + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include "config.h" + +#include <sys/reg.h> +#include <sys/wait.h> +#include <assert.h> +#include <errno.h> +#include <stdlib.h> + +#include "backend.h" +#include "debug.h" +#include "proc.h" +#include "ptrace.h" +#include "type.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +#ifdef __x86_64__ +# define ORIG_XAX (8 * ORIG_RAX) +#else +# define ORIG_XAX (4 * ORIG_EAX) +#endif + +#ifdef __x86_64__ +static const int x86_64 = 1; +#else +static const int x86_64 = 0; +#endif + +void +get_arch_dep(struct Process *proc) +{ + /* Unfortunately there are still remnants of mask_32bit uses + * around. */ + + if (proc->e_machine == EM_X86_64) { + proc->mask_32bit = 0; + proc->personality = 1; + } else if (x86_64) { /* x86_64/i386 */ + proc->mask_32bit = 1; + proc->personality = 0; + } else { + proc->mask_32bit = 0; + proc->personality = 0; + } +} + +/* 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 | proc->tracesysgood)) { + struct callstack_element *elem = NULL; + if (proc->callstack_depth > 0) + elem = proc->callstack + proc->callstack_depth - 1; + + long int ret = ptrace(PTRACE_PEEKUSER, proc->pid, ORIG_XAX, 0); + if (ret == -1) { + if (errno) + return -1; + /* Otherwise, ORIG_RAX == -1 means that the + * system call should not be restarted. In + * that case rely on what we have on + * stack. */ + if (elem != NULL && elem->is_syscall) + ret = elem->c_un.syscall; + } + + *sysnum = ret; + debug(DEBUG_FUNCTION, "sysnum=%ld %p %d", ret, + get_instruction_pointer(proc), errno); + if (elem != NULL && elem->is_syscall + && elem->c_un.syscall == *sysnum) + return 2; + + if (*sysnum >= 0) + return 1; + } + return 0; +} + +size_t +arch_type_sizeof(struct Process *proc, struct arg_type_info *info) +{ + if (proc == NULL) + return (size_t)-2; + + switch (info->type) { + case ARGTYPE_VOID: + return 0; + + case ARGTYPE_CHAR: + return 1; + + case ARGTYPE_SHORT: + case ARGTYPE_USHORT: + return 2; + + case ARGTYPE_INT: + case ARGTYPE_UINT: + return 4; + + case ARGTYPE_LONG: + case ARGTYPE_ULONG: + case ARGTYPE_POINTER: + return proc->e_machine == EM_X86_64 ? 8 : 4; + + case ARGTYPE_FLOAT: + return 4; + case ARGTYPE_DOUBLE: + return 8; + + case ARGTYPE_ARRAY: + case ARGTYPE_STRUCT: + /* Use default value. */ + return (size_t)-2; + + default: + assert(info->type != info->type); + abort(); + } +} + +size_t +arch_type_alignof(struct Process *proc, struct arg_type_info *info) +{ + if (proc == NULL) + return (size_t)-2; + + switch (info->type) { + default: + assert(info->type != info->type); + abort(); + break; + + case ARGTYPE_CHAR: + return 1; + + case ARGTYPE_SHORT: + case ARGTYPE_USHORT: + return 2; + + case ARGTYPE_INT: + case ARGTYPE_UINT: + return 4; + + case ARGTYPE_LONG: + case ARGTYPE_ULONG: + case ARGTYPE_POINTER: + return proc->e_machine == EM_X86_64 ? 8 : 4; + + case ARGTYPE_FLOAT: + return 4; + case ARGTYPE_DOUBLE: + return proc->e_machine == EM_X86_64 ? 8 : 4; + + case ARGTYPE_ARRAY: + case ARGTYPE_STRUCT: + /* Use default value. */ + return (size_t)-2; + } +} diff --git a/sysdeps/linux-gnu/x86_64/Makefile b/sysdeps/linux-gnu/x86_64/Makefile deleted file mode 100644 index 0a19c97..0000000 --- a/sysdeps/linux-gnu/x86_64/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -OBJ = trace.o regs.o plt.o - -all: arch.o - -arch.o: $(OBJ) - $(CC) -nostdlib -r -o arch.o $(OBJ) - -clean: - $(RM) $(OBJ) arch.o diff --git a/sysdeps/linux-gnu/x86_64/arch.h b/sysdeps/linux-gnu/x86_64/arch.h deleted file mode 100644 index 255395c..0000000 --- a/sysdeps/linux-gnu/x86_64/arch.h +++ /dev/null @@ -1,12 +0,0 @@ -#define BREAKPOINT_VALUE {0xcc} -#define BREAKPOINT_LENGTH 1 -#define DECR_PC_AFTER_BREAK 1 - -#define LT_ELFCLASS ELFCLASS64 -#define LT_ELF_MACHINE EM_X86_64 -#define LT_ELFCLASS2 ELFCLASS32 -#define LT_ELF_MACHINE2 EM_386 - -/* __NR_fork, __NR_clone, __NR_clone2, __NR_vfork and __NR_execve - from asm-i386/unistd.h. */ -#define FORK_EXEC_SYSCALLS , { 2, 120, -1, 190, 11 } diff --git a/sysdeps/linux-gnu/x86_64/ffcheck.c b/sysdeps/linux-gnu/x86_64/ffcheck.c deleted file mode 100644 index e69de29..0000000 --- a/sysdeps/linux-gnu/x86_64/ffcheck.c +++ /dev/null diff --git a/sysdeps/linux-gnu/x86_64/plt.c b/sysdeps/linux-gnu/x86_64/plt.c deleted file mode 100644 index b53ff44..0000000 --- a/sysdeps/linux-gnu/x86_64/plt.c +++ /dev/null @@ -1,12 +0,0 @@ -#include <gelf.h> -#include "common.h" - -GElf_Addr -arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { - return lte->plt_addr + (ndx + 1) * 16; -} - -void * -sym2addr(Process *proc, struct library_symbol *sym) { - return sym->enter_addr; -} diff --git a/sysdeps/linux-gnu/x86_64/ptrace.h b/sysdeps/linux-gnu/x86_64/ptrace.h deleted file mode 100644 index c3cbcb6..0000000 --- a/sysdeps/linux-gnu/x86_64/ptrace.h +++ /dev/null @@ -1 +0,0 @@ -#include <sys/ptrace.h> diff --git a/sysdeps/linux-gnu/x86_64/regs.c b/sysdeps/linux-gnu/x86_64/regs.c deleted file mode 100644 index ed1f118..0000000 --- a/sysdeps/linux-gnu/x86_64/regs.c +++ /dev/null @@ -1,54 +0,0 @@ -#include "config.h" - -#include <sys/types.h> -#include <sys/ptrace.h> -#include <sys/reg.h> - -#include "common.h" - -#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) -# define PTRACE_PEEKUSER PTRACE_PEEKUSR -#endif - -#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) -# define PTRACE_POKEUSER PTRACE_POKEUSR -#endif - -void * -get_instruction_pointer(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(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(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(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; -} - -void -set_return_addr(Process *proc, void *addr) { - if (proc->mask_32bit) - addr = (void *)((long int)addr & 0xffffffff); - ptrace(PTRACE_POKETEXT, proc->pid, proc->stack_pointer, addr); -} diff --git a/sysdeps/linux-gnu/x86_64/signalent1.h b/sysdeps/linux-gnu/x86_64/signalent1.h deleted file mode 100644 index 5ead946..0000000 --- a/sysdeps/linux-gnu/x86_64/signalent1.h +++ /dev/null @@ -1 +0,0 @@ -#include "i386/signalent.h" diff --git a/sysdeps/linux-gnu/x86_64/syscallent.h b/sysdeps/linux-gnu/x86_64/syscallent.h deleted file mode 100644 index 5e5f88a..0000000 --- a/sysdeps/linux-gnu/x86_64/syscallent.h +++ /dev/null @@ -1,256 +0,0 @@ -"read", /* 0 */ - "write", /* 1 */ - "open", /* 2 */ - "close", /* 3 */ - "stat", /* 4 */ - "fstat", /* 5 */ - "lstat", /* 6 */ - "poll", /* 7 */ - "lseek", /* 8 */ - "mmap", /* 9 */ - "mprotect", /* 10 */ - "munmap", /* 11 */ - "brk", /* 12 */ - "rt_sigaction", /* 13 */ - "rt_sigprocmask", /* 14 */ - "rt_sigreturn", /* 15 */ - "ioctl", /* 16 */ - "pread", /* 17 */ - "pwrite", /* 18 */ - "readv", /* 19 */ - "writev", /* 20 */ - "access", /* 21 */ - "pipe", /* 22 */ - "select", /* 23 */ - "sched_yield", /* 24 */ - "mremap", /* 25 */ - "msync", /* 26 */ - "mincore", /* 27 */ - "madvise", /* 28 */ - "shmget", /* 29 */ - "shmat", /* 30 */ - "shmctl", /* 31 */ - "dup", /* 32 */ - "dup2", /* 33 */ - "pause", /* 34 */ - "nanosleep", /* 35 */ - "getitimer", /* 36 */ - "alarm", /* 37 */ - "setitimer", /* 38 */ - "getpid", /* 39 */ - "sendfile", /* 40 */ - "socket", /* 41 */ - "connect", /* 42 */ - "accept", /* 43 */ - "sendto", /* 44 */ - "recvfrom", /* 45 */ - "sendmsg", /* 46 */ - "recvmsg", /* 47 */ - "shutdown", /* 48 */ - "bind", /* 49 */ - "listen", /* 50 */ - "getsockname", /* 51 */ - "getpeername", /* 52 */ - "socketpair", /* 53 */ - "setsockopt", /* 54 */ - "getsockopt", /* 55 */ - "clone", /* 56 */ - "fork", /* 57 */ - "vfork", /* 58 */ - "execve", /* 59 */ - "exit", /* 60 */ - "wait4", /* 61 */ - "kill", /* 62 */ - "uname", /* 63 */ - "semget", /* 64 */ - "semop", /* 65 */ - "semctl", /* 66 */ - "shmdt", /* 67 */ - "msgget", /* 68 */ - "msgsnd", /* 69 */ - "msgrcv", /* 70 */ - "msgctl", /* 71 */ - "fcntl", /* 72 */ - "flock", /* 73 */ - "fsync", /* 74 */ - "fdatasync", /* 75 */ - "truncate", /* 76 */ - "ftruncate", /* 77 */ - "getdents", /* 78 */ - "getcwd", /* 79 */ - "chdir", /* 80 */ - "fchdir", /* 81 */ - "rename", /* 82 */ - "mkdir", /* 83 */ - "rmdir", /* 84 */ - "creat", /* 85 */ - "link", /* 86 */ - "unlink", /* 87 */ - "symlink", /* 88 */ - "readlink", /* 89 */ - "chmod", /* 90 */ - "fchmod", /* 91 */ - "chown", /* 92 */ - "fchown", /* 93 */ - "lchown", /* 94 */ - "umask", /* 95 */ - "gettimeofday", /* 96 */ - "getrlimit", /* 97 */ - "getrusage", /* 98 */ - "sysinfo", /* 99 */ - "times", /* 100 */ - "ptrace", /* 101 */ - "getuid", /* 102 */ - "syslog", /* 103 */ - "getgid", /* 104 */ - "setuid", /* 105 */ - "setgid", /* 106 */ - "geteuid", /* 107 */ - "getegid", /* 108 */ - "setpgid", /* 109 */ - "getppid", /* 110 */ - "getpgrp", /* 111 */ - "setsid", /* 112 */ - "setreuid", /* 113 */ - "setregid", /* 114 */ - "getgroups", /* 115 */ - "setgroups", /* 116 */ - "setresuid", /* 117 */ - "getresuid", /* 118 */ - "setresgid", /* 119 */ - "getresgid", /* 120 */ - "getpgid", /* 121 */ - "setfsuid", /* 122 */ - "setfsgid", /* 123 */ - "getsid", /* 124 */ - "capget", /* 125 */ - "capset", /* 126 */ - "rt_sigpending", /* 127 */ - "rt_sigtimedwait", /* 128 */ - "rt_sigqueueinfo", /* 129 */ - "rt_sigsuspend", /* 130 */ - "sigaltstack", /* 131 */ - "utime", /* 132 */ - "mknod", /* 133 */ - "uselib", /* 134 */ - "personality", /* 135 */ - "ustat", /* 136 */ - "statfs", /* 137 */ - "fstatfs", /* 138 */ - "sysfs", /* 139 */ - "getpriority", /* 140 */ - "setpriority", /* 141 */ - "sched_setparam", /* 142 */ - "sched_getparam", /* 143 */ - "sched_setscheduler", /* 144 */ - "sched_getscheduler", /* 145 */ - "sched_get_priority_max", /* 146 */ - "sched_get_priority_min", /* 147 */ - "sched_rr_get_interval", /* 148 */ - "mlock", /* 149 */ - "munlock", /* 150 */ - "mlockall", /* 151 */ - "munlockall", /* 152 */ - "vhangup", /* 153 */ - "modify_ldt", /* 154 */ - "pivot_root", /* 155 */ - "_sysctl", /* 156 */ - "prctl", /* 157 */ - "arch_prctl", /* 158 */ - "adjtimex", /* 159 */ - "setrlimit", /* 160 */ - "chroot", /* 161 */ - "sync", /* 162 */ - "acct", /* 163 */ - "settimeofday", /* 164 */ - "mount", /* 165 */ - "umount2", /* 166 */ - "swapon", /* 167 */ - "swapoff", /* 168 */ - "reboot", /* 169 */ - "sethostname", /* 170 */ - "setdomainname", /* 171 */ - "iopl", /* 172 */ - "ioperm", /* 173 */ - "create_module", /* 174 */ - "init_module", /* 175 */ - "delete_module", /* 176 */ - "get_kernel_syms", /* 177 */ - "query_module", /* 178 */ - "quotactl", /* 179 */ - "nfsservctl", /* 180 */ - "getpmsg", /* 181 */ - "putpmsg", /* 182 */ - "afs_syscall", /* 183 */ - "tuxcall", /* 184 */ - "security", /* 185 */ - "gettid", /* 186 */ - "readahead", /* 187 */ - "setxattr", /* 188 */ - "lsetxattr", /* 189 */ - "fsetxattr", /* 190 */ - "getxattr", /* 191 */ - "lgetxattr", /* 192 */ - "fgetxattr", /* 193 */ - "listxattr", /* 194 */ - "llistxattr", /* 195 */ - "flistxattr", /* 196 */ - "removexattr", /* 197 */ - "lremovexattr", /* 198 */ - "fremovexattr", /* 199 */ - "tkill", /* 200 */ - "time", /* 201 */ - "futex", /* 202 */ - "sched_setaffinity", /* 203 */ - "sched_getaffinity", /* 204 */ - "set_thread_area", /* 205 */ - "io_setup", /* 206 */ - "io_destroy", /* 207 */ - "io_getevents", /* 208 */ - "io_submit", /* 209 */ - "io_cancel", /* 210 */ - "get_thread_area", /* 211 */ - "lookup_dcookie", /* 212 */ - "epoll_create", /* 213 */ - "epoll_ctl", /* 214 */ - "epoll_wait", /* 215 */ - "remap_file_pages", /* 216 */ - "getdents64", /* 217 */ - "set_tid_address", /* 218 */ - "restart_syscall", /* 219 */ - "semtimedop", /* 220 */ - "fadvise64", /* 221 */ - "timer_create", /* 222 */ - "timer_settime", /* 223 */ - "timer_gettime", /* 224 */ - "timer_getoverrun", /* 225 */ - "timer_delete", /* 226 */ - "clock_settime", /* 227 */ - "clock_gettime", /* 228 */ - "clock_getres", /* 229 */ - "clock_nanosleep", /* 230 */ - "exit_group", /* 231 */ - "epoll_wait", /* 232 */ - "epoll_ctl", /* 233 */ - "tgkill", /* 234 */ - "utimes", /* 235 */ - "vserver", /* 236 */ - "mbind", /* 237 */ - "set_mempolicy", /* 238 */ - "get_mempolicy", /* 239 */ - "mq_open", /* 240 */ - "mq_unlink", /* 241 */ - "mq_timedsend", /* 242 */ - "mq_timedreceive", /* 243 */ - "mq_notify", /* 244 */ - "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 deleted file mode 100644 index d8dd9f7..0000000 --- a/sysdeps/linux-gnu/x86_64/syscallent1.h +++ /dev/null @@ -1 +0,0 @@ -#include "i386/syscallent.h" diff --git a/sysdeps/linux-gnu/x86_64/trace.c b/sysdeps/linux-gnu/x86_64/trace.c deleted file mode 100644 index 189734d..0000000 --- a/sysdeps/linux-gnu/x86_64/trace.c +++ /dev/null @@ -1,144 +0,0 @@ -#include "config.h" - -#include <sys/types.h> -#include <sys/wait.h> -#include <signal.h> -#include <stdlib.h> -#include <sys/ptrace.h> -#include <sys/reg.h> - -#include "common.h" - -#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) -# define PTRACE_PEEKUSER PTRACE_PEEKUSR -#endif - -#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) -# define PTRACE_POKEUSER PTRACE_POKEUSR -#endif - -void -get_arch_dep(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(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].c_un.syscall == *sysnum) { - return 2; - } - - if (*sysnum >= 0) { - return 1; - } - } - return 0; -} - -static unsigned int -gimme_arg32(enum tof type, 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, Process *proc, int arg_num, arg_type_info *info) { - 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); - } - } 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"); - exit(1); - } - - return 0; -} - -void -save_register_args(enum tof type, Process *proc) { -} diff --git a/sysdeps/sysdep.h b/sysdeps/sysdep.h new file mode 100644 index 0000000..e8e287f --- /dev/null +++ b/sysdeps/sysdep.h @@ -0,0 +1,66 @@ +/* + * This file is part of ltrace. + * Copyright (C) 2012 Petr Machata, Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef LTRACE_SYSDEP_H +#define LTRACE_SYSDEP_H + +#include <arch.h> +#ifndef ARCH_HAVE_ADDRESS_TYPES +/* We should in general be able to trace 64-bit processes with 32-bit + * ltrace. (At least PPC has several PTRACE requests related to + * tracing 64-on-32, so presumably it should be possible.) But ltrace + * is currently hopelessly infested with using void* for host address. + * So keep with it, for now. */ +typedef void *arch_addr_t; +#endif + +#include <os.h> + +#ifndef ARCH_HAVE_LTELF_DATA +struct arch_ltelf_data { +}; +#endif + +#ifndef ARCH_HAVE_BREAKPOINT_DATA +struct arch_breakpoint_data { +}; +#endif + +#ifndef ARCH_HAVE_LIBRARY_SYMBOL_DATA +struct arch_library_symbol_data { +}; +#endif + +#ifndef ARCH_HAVE_LIBRARY_DATA +struct arch_library_data { +}; +#endif + +#ifndef OS_HAVE_PROCESS_DATA +struct os_process_data { +}; +#endif + +#ifndef ARCH_HAVE_PROCESS_DATA +struct arch_process_data { +}; +#endif + +#endif /* LTRACE_SYSDEP_H */ |