From d517c6fceb4e1158aef9cd573db2424220e41e49 Mon Sep 17 00:00:00 2001 From: Stefani Seibold Date: Tue, 13 Oct 2015 10:18:37 +0200 Subject: [PATCH] Version 0.2 Lots of performance improvement Better stack unwind Bug fixes --- Makefile.in | 2 +- autom4te.cache/output.0 | 23 +- autom4te.cache/output.1 | 23 +- autom4te.cache/output.2 | 23 +- autom4te.cache/requests | 792 +++++++++++++++--------------- autom4te.cache/traces.0 | 52 +- autom4te.cache/traces.1 | 52 +- autom4te.cache/traces.2 | 212 ++++---- backend.h | 5 + backtrace.h | 3 + breakpoint.c | 399 ++++++++++----- breakpoint.h | 61 ++- client/binfile.c | 153 ++++-- client/binfile.h | 31 +- client/client.c | 149 ++++-- client/client.h | 5 +- client/process.c | 105 ++-- client/process.h | 2 +- client/readline.c | 7 +- config.h.in | 3 + config/autoconf/config.guess | 6 +- config/autoconf/config.sub | 7 +- configure | 23 +- configure.ac | 5 +- dwarf.c | 137 ++++-- dwarf.h | 7 +- event.c | 90 ++-- event.h | 1 - forward.h | 1 + library.c | 238 +++++---- library.h | 55 ++- main.c | 52 +- mtelf.c | 142 ++++-- mtelf.h | 4 +- mtrace.1 | 126 +++-- options.c | 270 ++++++---- options.h | 13 +- report.c | 153 +++--- report.h | 4 +- server.c | 87 +++- server.h | 1 + sysdeps/linux-gnu/arm/dwarf-arm.c | 25 +- sysdeps/linux-gnu/backtrace.c | 8 + sysdeps/linux-gnu/ioevent.c | 1 + sysdeps/linux-gnu/ppc/dwarf-ppc.c | 5 + sysdeps/linux-gnu/proc.c | 12 +- sysdeps/linux-gnu/socket.c | 15 +- sysdeps/linux-gnu/trace.c | 74 ++- sysdeps/linux-gnu/x86/arch.c | 15 + sysdeps/linux-gnu/x86/arch.h | 14 + sysdeps/linux-gnu/x86/dwarf-x86.c | 45 +- task.c | 60 ++- task.h | 25 +- trace.c | 18 +- trace.h | 1 + 55 files changed, 2295 insertions(+), 1547 deletions(-) diff --git a/Makefile.in b/Makefile.in index 4c01147..76feb1d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -484,7 +484,7 @@ noinst_HEADERS = \ dist_man1_MANS = mtrace.1 dist_man5_MANS = mtrace.conf.5 -dist_doc_DATA = COPYING CREDITS INSTALL README TODO +dist_doc_DATA = COPYING CREDITS INSTALL README TODO HOWTO EXTRA_DIST = MAINTAINERCLEANFILES = \ configure \ diff --git a/autom4te.cache/output.0 b/autom4te.cache/output.0 index 5a3be16..f6b6be7 100644 --- a/autom4te.cache/output.0 +++ b/autom4te.cache/output.0 @@ -1,6 +1,6 @@ @%:@! /bin/sh @%:@ Guess values for system-dependent variables and create Makefiles. -@%:@ Generated by GNU Autoconf 2.69 for mtrace 0.1. +@%:@ Generated by GNU Autoconf 2.69 for mtrace 0.2. @%:@ @%:@ Report bugs to . @%:@ @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='mtrace' PACKAGE_TARNAME='mtrace' -PACKAGE_VERSION='0.1' -PACKAGE_STRING='mtrace 0.1' +PACKAGE_VERSION='0.2' +PACKAGE_STRING='mtrace 0.2' PACKAGE_BUGREPORT='stefani@seibold.net' PACKAGE_URL='' @@ -1326,7 +1326,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures mtrace 0.1 to adapt to many kinds of systems. +\`configure' configures mtrace 0.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1396,7 +1396,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of mtrace 0.1:";; + short | recursive ) echo "Configuration of mtrace 0.2:";; esac cat <<\_ACEOF @@ -1512,7 +1512,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -mtrace configure 0.1 +mtrace configure 0.2 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2118,7 +2118,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by mtrace $as_me 0.1, which was +It was created by mtrace $as_me 0.2, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -12000,7 +12000,7 @@ fi # Define the identity of the package. PACKAGE='mtrace' - VERSION='0.1' + VERSION='0.2' cat >>confdefs.h <<_ACEOF @@ -12746,6 +12746,8 @@ else $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CPPFLAGS="${saved_CPPFLAGS}" +LDFLAGS="${saved_LDFLAGS}" saved_CFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -Wall -Werror" @@ -13206,6 +13208,7 @@ for ac_func in \ strerror \ strtol \ strtoul \ + process_vm_readv \ do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` @@ -13799,7 +13802,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by mtrace $as_me 0.1, which was +This file was extended by mtrace $as_me 0.2, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13865,7 +13868,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -mtrace config.status 0.1 +mtrace config.status 0.2 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/autom4te.cache/output.1 b/autom4te.cache/output.1 index 5a3be16..f6b6be7 100644 --- a/autom4te.cache/output.1 +++ b/autom4te.cache/output.1 @@ -1,6 +1,6 @@ @%:@! /bin/sh @%:@ Guess values for system-dependent variables and create Makefiles. -@%:@ Generated by GNU Autoconf 2.69 for mtrace 0.1. +@%:@ Generated by GNU Autoconf 2.69 for mtrace 0.2. @%:@ @%:@ Report bugs to . @%:@ @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='mtrace' PACKAGE_TARNAME='mtrace' -PACKAGE_VERSION='0.1' -PACKAGE_STRING='mtrace 0.1' +PACKAGE_VERSION='0.2' +PACKAGE_STRING='mtrace 0.2' PACKAGE_BUGREPORT='stefani@seibold.net' PACKAGE_URL='' @@ -1326,7 +1326,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures mtrace 0.1 to adapt to many kinds of systems. +\`configure' configures mtrace 0.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1396,7 +1396,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of mtrace 0.1:";; + short | recursive ) echo "Configuration of mtrace 0.2:";; esac cat <<\_ACEOF @@ -1512,7 +1512,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -mtrace configure 0.1 +mtrace configure 0.2 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2118,7 +2118,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by mtrace $as_me 0.1, which was +It was created by mtrace $as_me 0.2, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -12000,7 +12000,7 @@ fi # Define the identity of the package. PACKAGE='mtrace' - VERSION='0.1' + VERSION='0.2' cat >>confdefs.h <<_ACEOF @@ -12746,6 +12746,8 @@ else $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CPPFLAGS="${saved_CPPFLAGS}" +LDFLAGS="${saved_LDFLAGS}" saved_CFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -Wall -Werror" @@ -13206,6 +13208,7 @@ for ac_func in \ strerror \ strtol \ strtoul \ + process_vm_readv \ do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` @@ -13799,7 +13802,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by mtrace $as_me 0.1, which was +This file was extended by mtrace $as_me 0.2, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13865,7 +13868,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -mtrace config.status 0.1 +mtrace config.status 0.2 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/autom4te.cache/output.2 b/autom4te.cache/output.2 index 5a3be16..f6b6be7 100644 --- a/autom4te.cache/output.2 +++ b/autom4te.cache/output.2 @@ -1,6 +1,6 @@ @%:@! /bin/sh @%:@ Guess values for system-dependent variables and create Makefiles. -@%:@ Generated by GNU Autoconf 2.69 for mtrace 0.1. +@%:@ Generated by GNU Autoconf 2.69 for mtrace 0.2. @%:@ @%:@ Report bugs to . @%:@ @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='mtrace' PACKAGE_TARNAME='mtrace' -PACKAGE_VERSION='0.1' -PACKAGE_STRING='mtrace 0.1' +PACKAGE_VERSION='0.2' +PACKAGE_STRING='mtrace 0.2' PACKAGE_BUGREPORT='stefani@seibold.net' PACKAGE_URL='' @@ -1326,7 +1326,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures mtrace 0.1 to adapt to many kinds of systems. +\`configure' configures mtrace 0.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1396,7 +1396,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of mtrace 0.1:";; + short | recursive ) echo "Configuration of mtrace 0.2:";; esac cat <<\_ACEOF @@ -1512,7 +1512,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -mtrace configure 0.1 +mtrace configure 0.2 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2118,7 +2118,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by mtrace $as_me 0.1, which was +It was created by mtrace $as_me 0.2, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -12000,7 +12000,7 @@ fi # Define the identity of the package. PACKAGE='mtrace' - VERSION='0.1' + VERSION='0.2' cat >>confdefs.h <<_ACEOF @@ -12746,6 +12746,8 @@ else $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CPPFLAGS="${saved_CPPFLAGS}" +LDFLAGS="${saved_LDFLAGS}" saved_CFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -Wall -Werror" @@ -13206,6 +13208,7 @@ for ac_func in \ strerror \ strtol \ strtoul \ + process_vm_readv \ do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` @@ -13799,7 +13802,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by mtrace $as_me 0.1, which was +This file was extended by mtrace $as_me 0.2, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13865,7 +13868,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -mtrace config.status 0.1 +mtrace config.status 0.2 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/autom4te.cache/requests b/autom4te.cache/requests index ab6bbff..0c191e8 100644 --- a/autom4te.cache/requests +++ b/autom4te.cache/requests @@ -42,186 +42,186 @@ 'configure.ac' ], { - 'LT_AC_PROG_RC' => 1, - 'AM_SUBST_NOTMAKE' => 1, - 'AC_LTDL_PREOPEN' => 1, - '_LT_AC_LANG_GCJ_CONFIG' => 1, - '_LT_AC_PROG_ECHO_BACKSLASH' => 1, - 'AC_LIBTOOL_LANG_CXX_CONFIG' => 1, - 'LT_LIB_M' => 1, - 'AM_SILENT_RULES' => 1, - 'AC_LIBTOOL_SETUP' => 1, - '_LT_AC_TRY_DLOPEN_SELF' => 1, - 'AC_PATH_MAGIC' => 1, - '_LT_AC_LOCK' => 1, - 'LTOPTIONS_VERSION' => 1, - '_LT_AC_LANG_CXX' => 1, - '_LT_LINKER_BOILERPLATE' => 1, - 'AC_LIBTOOL_LANG_GCJ_CONFIG' => 1, - 'AM_DISABLE_SHARED' => 1, - '_LT_AC_SYS_LIBPATH_AIX' => 1, - 'AC_LIBTOOL_PICMODE' => 1, + '_LT_CC_BASENAME' => 1, + 'AC_PROG_LD_RELOAD_FLAG' => 1, + 'AC_LIBTOOL_PROG_COMPILER_NO_RTTI' => 1, + 'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1, + '_AM_SET_OPTIONS' => 1, + 'AC_CHECK_LIBM' => 1, 'AU_DEFUN' => 1, - '_LT_PATH_TOOL_PREFIX' => 1, - 'AC_LTDL_DLLIB' => 1, - 'AM_PROG_NM' => 1, - 'LTDL_INSTALLABLE' => 1, - 'AC_LIBTOOL_PROG_CC_C_O' => 1, - 'LT_SYS_DLSEARCH_PATH' => 1, - '_AM_PROG_TAR' => 1, - 'AC_LTDL_DLSYM_USCORE' => 1, - '_LT_AC_LANG_F77' => 1, - '_AM_PROG_CC_C_O' => 1, - 'AM_ENABLE_SHARED' => 1, - '_LT_REQUIRED_DARWIN_CHECKS' => 1, - 'AC_LTDL_SHLIBPATH' => 1, - '_LT_AC_TAGVAR' => 1, - 'AC_CONFIG_MACRO_DIR' => 1, - 'AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE' => 1, - 'AC_LIBTOOL_OBJDIR' => 1, - '_LT_COMPILER_BOILERPLATE' => 1, - 'AM_ENABLE_STATIC' => 1, + 'AM_MISSING_HAS_RUN' => 1, + 'AC_LIBTOOL_PROG_LD_SHLIBS' => 1, + '_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, + 'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1, + '_m4_warn' => 1, '_LT_AC_SHELL_INIT' => 1, - '_LT_WITH_SYSROOT' => 1, + '_LT_DLL_DEF_P' => 1, + 'AM_AUX_DIR_EXPAND' => 1, + 'AM_RUN_LOG' => 1, + 'AC_ENABLE_STATIC' => 1, + 'AC_CONFIG_MACRO_DIR' => 1, + 'LT_LIB_M' => 1, + 'LT_FUNC_DLSYM_USCORE' => 1, + 'LT_PATH_NM' => 1, + 'LTDL_CONVENIENCE' => 1, + 'm4_pattern_allow' => 1, + '_LT_LIBOBJ' => 1, 'LT_OUTPUT' => 1, - '_LT_AC_LANG_RC_CONFIG' => 1, + 'AC_LIBTOOL_OBJDIR' => 1, + 'AC_LIBLTDL_INSTALLABLE' => 1, + '_LT_COMPILER_OPTION' => 1, + 'AM_PROG_INSTALL_SH' => 1, + '_AM_AUTOCONF_VERSION' => 1, + 'LT_SYS_DLOPEN_SELF' => 1, '_AC_AM_CONFIG_HEADER_HOOK' => 1, + 'AM_MAKE_INCLUDE' => 1, + '_AM_CONFIG_MACRO_DIRS' => 1, + 'LT_PROG_GO' => 1, + '_LT_PROG_ECHO_BACKSLASH' => 1, + 'AC_LIBTOOL_LANG_C_CONFIG' => 1, + '_LT_PROG_CXX' => 1, + 'AC_LIBTOOL_PROG_COMPILER_PIC' => 1, + 'AM_PROG_LD' => 1, + 'AM_MISSING_PROG' => 1, + 'LTOBSOLETE_VERSION' => 1, + '_AM_PROG_TAR' => 1, + 'AC_LTDL_DLLIB' => 1, + 'LT_PATH_LD' => 1, + '_LT_AC_TAGVAR' => 1, + 'AC_LIBTOOL_PROG_CC_C_O' => 1, + 'AC_LTDL_SHLIBEXT' => 1, + 'AC_LIBTOOL_F77' => 1, + 'm4_include' => 1, + 'AM_SET_LEADING_DOT' => 1, + 'AC_LIBTOOL_GCJ' => 1, '_AM_DEPENDENCIES' => 1, 'LT_WITH_LTDL' => 1, - '_LT_AC_TAGCONFIG' => 1, - '_AM_AUTOCONF_VERSION' => 1, - '_LT_PREPARE_SED_QUOTE_VARS' => 1, - '_LT_AC_LANG_CXX_CONFIG' => 1, - 'LT_LIB_DLLOAD' => 1, - 'AC_LIBTOOL_CONFIG' => 1, - '_LTDL_SETUP' => 1, - 'LT_FUNC_DLSYM_USCORE' => 1, + 'AM_DISABLE_SHARED' => 1, 'LTSUGAR_VERSION' => 1, - 'AM_MISSING_PROG' => 1, - 'LT_PROG_GO' => 1, - 'LT_AC_PROG_EGREP' => 1, - '_m4_warn' => 1, - 'AM_DISABLE_STATIC' => 1, - 'AM_PROG_CC_C_O' => 1, - 'AC_LIBTOOL_COMPILER_OPTION' => 1, - 'LT_SYS_DLOPEN_SELF' => 1, - 'AC_LIBTOOL_LANG_C_CONFIG' => 1, - 'AC_LTDL_OBJDIR' => 1, - '_LT_PROG_LTMAIN' => 1, - 'AC_LIBLTDL_CONVENIENCE' => 1, - 'LT_SUPPORTED_TAG' => 1, - 'AC_PATH_TOOL_PREFIX' => 1, - 'AC_PROG_LD_RELOAD_FLAG' => 1, - 'AC_PROG_LIBTOOL' => 1, - '_LT_CC_BASENAME' => 1, - 'AC_LIBTOOL_LANG_RC_CONFIG' => 1, - 'AC_LIBTOOL_CXX' => 1, - 'LT_SYS_MODULE_EXT' => 1, - 'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, - 'LTOBSOLETE_VERSION' => 1, - 'LT_INIT' => 1, - 'LT_FUNC_ARGZ' => 1, - 'AC_LIBTOOL_PROG_COMPILER_PIC' => 1, - 'AC_DISABLE_FAST_INSTALL' => 1, - 'AC_LIBTOOL_GCJ' => 1, - 'm4_pattern_allow' => 1, - 'AM_PROG_INSTALL_SH' => 1, - 'AC_ENABLE_SHARED' => 1, - 'AC_LIBTOOL_SYS_LIB_STRIP' => 1, - 'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1, - 'AC_DISABLE_SHARED' => 1, - 'AC_PROG_EGREP' => 1, - 'AC_LIBTOOL_LINKER_OPTION' => 1, - 'AC_LIBTOOL_FC' => 1, - 'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1, - '_AC_PROG_LIBTOOL' => 1, - 'LT_PATH_NM' => 1, - 'AM_AUX_DIR_EXPAND' => 1, - 'include' => 1, - 'AC_DISABLE_STATIC' => 1, - 'AM_SET_DEPDIR' => 1, - '_AM_MANGLE_OPTION' => 1, - 'LT_PROG_GCJ' => 1, - '_AM_SET_OPTIONS' => 1, - 'AM_AUTOMAKE_VERSION' => 1, - '_LT_AC_PROG_CXXCPP' => 1, - '_LT_PROG_FC' => 1, - 'AC_LIBTOOL_LANG_F77_CONFIG' => 1, - '_LT_PROG_CXX' => 1, - '_LT_AC_CHECK_DLFCN' => 1, - 'AM_SANITY_CHECK' => 1, - 'AC_LTDL_SYMBOL_USCORE' => 1, - 'AC_CONFIG_MACRO_DIR_TRACE' => 1, - 'AC_LIBTOOL_RC' => 1, - 'AC_LIBTOOL_F77' => 1, - 'AM_RUN_LOG' => 1, - 'm4_include' => 1, - 'AC_DEPLIBS_CHECK_METHOD' => 1, - 'LT_PATH_LD' => 1, - 'AM_MAINTAINER_MODE' => 1, - 'AM_PROG_LIBTOOL' => 1, - 'LTDL_INIT' => 1, - 'AC_LIBTOOL_DLOPEN_SELF' => 1, - 'AM_MAKE_INCLUDE' => 1, - 'LTDL_CONVENIENCE' => 1, - 'AC_LIB_LTDL' => 1, - 'LT_SYS_MODULE_PATH' => 1, - 'LT_CMD_MAX_LEN' => 1, - 'm4_pattern_forbid' => 1, - '_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, - 'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1, - 'AM_PROG_LD' => 1, - 'AC_LTDL_SHLIBEXT' => 1, - 'AC_LIBTOOL_PROG_COMPILER_NO_RTTI' => 1, - 'AC_LIBLTDL_INSTALLABLE' => 1, - 'AC_LIBTOOL_DLOPEN' => 1, - 'AC_LIBTOOL_PROG_LD_SHLIBS' => 1, - '_AM_CONFIG_MACRO_DIRS' => 1, - 'AC_LTDL_ENABLE_INSTALL' => 1, - 'AC_ENABLE_FAST_INSTALL' => 1, - 'LT_AC_PROG_GCJ' => 1, - 'AC_LTDL_SYSSEARCHPATH' => 1, - 'AM_MISSING_HAS_RUN' => 1, - 'AC_PROG_NM' => 1, - 'AM_PROG_INSTALL_STRIP' => 1, - '_AM_SUBST_NOTMAKE' => 1, - '_AM_SET_OPTION' => 1, - 'LT_PROG_RC' => 1, - 'AM_CONDITIONAL' => 1, - 'AC_ENABLE_STATIC' => 1, - 'LT_SYS_SYMBOL_USCORE' => 1, - 'AM_SET_LEADING_DOT' => 1, - '_LT_COMPILER_OPTION' => 1, - '_LT_LINKER_OPTION' => 1, - '_AM_IF_OPTION' => 1, - 'AC_LIBTOOL_WIN32_DLL' => 1, - '_LT_LIBOBJ' => 1, - 'AC_DEFUN' => 1, - 'LT_AC_PROG_SED' => 1, - 'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1, - 'AC_WITH_LTDL' => 1, - '_LT_AC_LANG_GCJ' => 1, 'AC_DEFUN_ONCE' => 1, - 'AC_LIBTOOL_POSTDEP_PREDEP' => 1, - '_LT_AC_LANG_C_CONFIG' => 1, - 'LT_CONFIG_LTDL_DIR' => 1, - '_LT_AC_FILE_LTDLL_C' => 1, - 'LTVERSION_VERSION' => 1, - 'AC_PROG_LD_GNU' => 1, - 'LT_SYS_DLOPEN_DEPLIBS' => 1, - 'AC_CHECK_LIBM' => 1, - 'AC_LIBTOOL_SYS_DYNAMIC_LINKER' => 1, - '_LT_AC_LANG_F77_CONFIG' => 1, - '_LT_AC_SYS_COMPILER' => 1, - '_LT_DLL_DEF_P' => 1, + '_LT_AC_LANG_CXX_CONFIG' => 1, + 'AC_ENABLE_FAST_INSTALL' => 1, + 'LT_FUNC_ARGZ' => 1, + '_LTDL_SETUP' => 1, + '_AC_PROG_LIBTOOL' => 1, + 'AC_DISABLE_SHARED' => 1, 'AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH' => 1, - 'LT_LANG' => 1, - 'AC_LIBTOOL_SYS_MAX_CMD_LEN' => 1, - '_LT_PROG_ECHO_BACKSLASH' => 1, - 'AC_PROG_LD' => 1, - 'AM_INIT_AUTOMAKE' => 1, + 'AM_SUBST_NOTMAKE' => 1, + 'LT_CONFIG_LTDL_DIR' => 1, + 'AM_ENABLE_STATIC' => 1, + 'AC_LIBTOOL_LANG_RC_CONFIG' => 1, + 'AM_AUTOMAKE_VERSION' => 1, + '_LT_AC_TRY_DLOPEN_SELF' => 1, + 'AC_LIBTOOL_SETUP' => 1, + 'include' => 1, + '_LT_AC_LANG_F77' => 1, + 'AM_PROG_LIBTOOL' => 1, 'AM_DEP_TRACK' => 1, - '_LT_PROG_F77' => 1 + '_LT_WITH_SYSROOT' => 1, + '_LT_AC_LANG_C_CONFIG' => 1, + 'AM_SET_DEPDIR' => 1, + 'AC_LIBTOOL_WIN32_DLL' => 1, + 'LT_SYS_MODULE_EXT' => 1, + 'LT_CMD_MAX_LEN' => 1, + 'AC_LIBTOOL_CONFIG' => 1, + 'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1, + 'AC_DEPLIBS_CHECK_METHOD' => 1, + 'AC_PATH_TOOL_PREFIX' => 1, + 'AC_LIBTOOL_LINKER_OPTION' => 1, + 'LTDL_INSTALLABLE' => 1, + 'AM_PROG_NM' => 1, + 'AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE' => 1, + 'LT_AC_PROG_RC' => 1, + 'AM_SILENT_RULES' => 1, + 'LT_SYS_MODULE_PATH' => 1, + 'AC_LIBTOOL_LANG_F77_CONFIG' => 1, + 'AM_INIT_AUTOMAKE' => 1, + 'AC_LIBLTDL_CONVENIENCE' => 1, + '_LT_AC_LANG_F77_CONFIG' => 1, + 'LTDL_INIT' => 1, + 'AM_DISABLE_STATIC' => 1, + '_LT_AC_PROG_CXXCPP' => 1, + '_LT_PATH_TOOL_PREFIX' => 1, + '_LT_PREPARE_SED_QUOTE_VARS' => 1, + 'LT_SUPPORTED_TAG' => 1, + 'AC_DISABLE_STATIC' => 1, + 'AC_LTDL_SHLIBPATH' => 1, + 'AC_LIBTOOL_POSTDEP_PREDEP' => 1, + 'AC_ENABLE_SHARED' => 1, + 'm4_pattern_forbid' => 1, + 'AC_LTDL_SYMBOL_USCORE' => 1, + 'AC_LIBTOOL_SYS_MAX_CMD_LEN' => 1, + 'AC_LTDL_ENABLE_INSTALL' => 1, + 'LT_AC_PROG_GCJ' => 1, + 'LT_LANG' => 1, + '_LT_AC_FILE_LTDLL_C' => 1, + 'AM_CONDITIONAL' => 1, + 'AC_PROG_LD_GNU' => 1, + '_LT_LINKER_OPTION' => 1, + 'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1, + 'LTOPTIONS_VERSION' => 1, + 'AC_PATH_MAGIC' => 1, + '_LT_AC_TAGCONFIG' => 1, + 'LT_INIT' => 1, + '_AM_IF_OPTION' => 1, + 'AC_LIBTOOL_SYS_DYNAMIC_LINKER' => 1, + 'AC_CONFIG_MACRO_DIR_TRACE' => 1, + 'AC_LIBTOOL_PICMODE' => 1, + '_LT_PROG_LTMAIN' => 1, + '_LT_AC_PROG_ECHO_BACKSLASH' => 1, + 'AC_LIBTOOL_LANG_CXX_CONFIG' => 1, + 'AM_ENABLE_SHARED' => 1, + 'AC_LIBTOOL_DLOPEN' => 1, + '_LT_AC_CHECK_DLFCN' => 1, + '_LT_AC_LANG_GCJ' => 1, + '_LT_LINKER_BOILERPLATE' => 1, + '_LT_PROG_FC' => 1, + '_LT_AC_SYS_COMPILER' => 1, + 'AM_PROG_CC_C_O' => 1, + 'LT_AC_PROG_EGREP' => 1, + 'LT_SYS_DLOPEN_DEPLIBS' => 1, + '_AM_SET_OPTION' => 1, + 'AC_LIBTOOL_SYS_LIB_STRIP' => 1, + 'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, + 'LT_LIB_DLLOAD' => 1, + 'AC_LTDL_DLSYM_USCORE' => 1, + 'AC_LIBTOOL_DLOPEN_SELF' => 1, + 'AM_MAINTAINER_MODE' => 1, + '_AM_PROG_CC_C_O' => 1, + 'AC_LIBTOOL_FC' => 1, + '_LT_PROG_F77' => 1, + 'LT_AC_PROG_SED' => 1, + 'AC_LIBTOOL_COMPILER_OPTION' => 1, + 'AC_LIB_LTDL' => 1, + '_LT_AC_SYS_LIBPATH_AIX' => 1, + '_AM_SUBST_NOTMAKE' => 1, + 'AC_PROG_NM' => 1, + 'LTVERSION_VERSION' => 1, + 'AC_WITH_LTDL' => 1, + 'AC_DEFUN' => 1, + '_LT_AC_LANG_GCJ_CONFIG' => 1, + 'LT_SYS_SYMBOL_USCORE' => 1, + 'AC_LTDL_SYSSEARCHPATH' => 1, + 'AC_PROG_LD' => 1, + '_LT_AC_LANG_CXX' => 1, + '_LT_COMPILER_BOILERPLATE' => 1, + 'AC_LIBTOOL_RC' => 1, + 'AC_LTDL_OBJDIR' => 1, + 'LT_SYS_DLSEARCH_PATH' => 1, + '_LT_REQUIRED_DARWIN_CHECKS' => 1, + 'AC_LIBTOOL_LANG_GCJ_CONFIG' => 1, + 'AM_PROG_INSTALL_STRIP' => 1, + '_AM_MANGLE_OPTION' => 1, + 'AC_DISABLE_FAST_INSTALL' => 1, + '_LT_AC_LOCK' => 1, + 'AC_PROG_LIBTOOL' => 1, + 'LT_PROG_RC' => 1, + 'AC_PROG_EGREP' => 1, + 'AC_LTDL_PREOPEN' => 1, + 'AM_SANITY_CHECK' => 1, + '_LT_AC_LANG_RC_CONFIG' => 1, + 'LT_PROG_GCJ' => 1, + 'AC_LIBTOOL_CXX' => 1 } ], 'Autom4te::Request' ), bless( [ @@ -263,186 +263,186 @@ 'configure.ac' ], { - 'AC_LIBTOOL_SETUP' => 1, - '_LT_AC_TRY_DLOPEN_SELF' => 1, - 'AC_PATH_MAGIC' => 1, - 'AC_LIBTOOL_LANG_CXX_CONFIG' => 1, - 'LT_LIB_M' => 1, - 'AM_SILENT_RULES' => 1, - '_LT_AC_LANG_GCJ_CONFIG' => 1, - '_LT_AC_PROG_ECHO_BACKSLASH' => 1, - 'LT_AC_PROG_RC' => 1, - 'AM_SUBST_NOTMAKE' => 1, - 'AC_LTDL_PREOPEN' => 1, - 'AC_LIBTOOL_PROG_CC_C_O' => 1, - 'LT_SYS_DLSEARCH_PATH' => 1, - 'AC_LTDL_DLSYM_USCORE' => 1, - '_AM_PROG_TAR' => 1, - '_AM_PROG_CC_C_O' => 1, - '_LT_AC_LANG_F77' => 1, - 'AM_ENABLE_SHARED' => 1, - '_LT_REQUIRED_DARWIN_CHECKS' => 1, - 'AM_PROG_NM' => 1, - 'LTDL_INSTALLABLE' => 1, - '_LT_AC_SYS_LIBPATH_AIX' => 1, - 'AC_LIBTOOL_PICMODE' => 1, - 'AU_DEFUN' => 1, - '_LT_PATH_TOOL_PREFIX' => 1, - 'AC_LTDL_DLLIB' => 1, - '_LT_AC_LOCK' => 1, - '_LT_AC_LANG_CXX' => 1, - 'LTOPTIONS_VERSION' => 1, - 'AC_LIBTOOL_LANG_GCJ_CONFIG' => 1, - '_LT_LINKER_BOILERPLATE' => 1, - 'AM_DISABLE_SHARED' => 1, - 'AM_MISSING_PROG' => 1, - 'LT_PROG_GO' => 1, - 'LT_AC_PROG_EGREP' => 1, - '_m4_warn' => 1, - '_LT_AC_TAGCONFIG' => 1, - 'LT_WITH_LTDL' => 1, - '_AM_AUTOCONF_VERSION' => 1, - '_LT_PREPARE_SED_QUOTE_VARS' => 1, - '_LT_AC_LANG_CXX_CONFIG' => 1, - 'LT_LIB_DLLOAD' => 1, - 'AC_LIBTOOL_CONFIG' => 1, - '_LTDL_SETUP' => 1, - 'LTSUGAR_VERSION' => 1, - 'LT_FUNC_DLSYM_USCORE' => 1, - 'AM_ENABLE_STATIC' => 1, - '_LT_WITH_SYSROOT' => 1, - '_LT_AC_SHELL_INIT' => 1, - 'LT_OUTPUT' => 1, - '_LT_AC_LANG_RC_CONFIG' => 1, - '_AC_AM_CONFIG_HEADER_HOOK' => 1, - '_AM_DEPENDENCIES' => 1, - 'AC_LTDL_SHLIBPATH' => 1, - '_LT_AC_TAGVAR' => 1, - 'AC_CONFIG_MACRO_DIR' => 1, - 'AC_LIBTOOL_OBJDIR' => 1, 'AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE' => 1, - '_LT_COMPILER_BOILERPLATE' => 1, - 'AC_DISABLE_SHARED' => 1, - 'AC_LIBTOOL_LINKER_OPTION' => 1, - 'AC_PROG_EGREP' => 1, - 'AC_LIBTOOL_FC' => 1, - 'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1, - 'AM_PROG_INSTALL_SH' => 1, - 'm4_pattern_allow' => 1, - 'AC_ENABLE_SHARED' => 1, - 'AC_LIBTOOL_SYS_LIB_STRIP' => 1, - 'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1, - 'AC_LIBTOOL_CXX' => 1, - 'LT_SYS_MODULE_EXT' => 1, - 'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, - 'LTOBSOLETE_VERSION' => 1, - 'LT_FUNC_ARGZ' => 1, - 'LT_INIT' => 1, - 'AC_LIBTOOL_PROG_COMPILER_PIC' => 1, - 'AC_LIBTOOL_GCJ' => 1, - 'AC_DISABLE_FAST_INSTALL' => 1, - 'AM_PROG_CC_C_O' => 1, - 'AM_DISABLE_STATIC' => 1, - 'AC_LIBTOOL_COMPILER_OPTION' => 1, - 'AC_LIBTOOL_LANG_C_CONFIG' => 1, - 'LT_SYS_DLOPEN_SELF' => 1, - 'LT_SUPPORTED_TAG' => 1, - 'AC_LIBLTDL_CONVENIENCE' => 1, - 'AC_PATH_TOOL_PREFIX' => 1, - '_LT_PROG_LTMAIN' => 1, - 'AC_LTDL_OBJDIR' => 1, - 'AC_PROG_LD_RELOAD_FLAG' => 1, - '_LT_CC_BASENAME' => 1, - 'AC_PROG_LIBTOOL' => 1, - 'AC_LIBTOOL_LANG_RC_CONFIG' => 1, - 'AM_RUN_LOG' => 1, - 'AC_DEPLIBS_CHECK_METHOD' => 1, - 'm4_include' => 1, - 'LT_PATH_LD' => 1, - 'AM_PROG_LIBTOOL' => 1, - 'AM_MAINTAINER_MODE' => 1, - '_LT_PROG_CXX' => 1, - '_LT_AC_CHECK_DLFCN' => 1, - 'AM_SANITY_CHECK' => 1, - 'AC_LTDL_SYMBOL_USCORE' => 1, - 'AC_CONFIG_MACRO_DIR_TRACE' => 1, - 'AC_LIBTOOL_RC' => 1, - 'AC_LIBTOOL_F77' => 1, - '_LT_AC_PROG_CXXCPP' => 1, - '_LT_PROG_FC' => 1, - 'AC_LIBTOOL_LANG_F77_CONFIG' => 1, - '_AC_PROG_LIBTOOL' => 1, - 'LT_PATH_NM' => 1, - 'AM_AUX_DIR_EXPAND' => 1, - 'include' => 1, - 'AC_DISABLE_STATIC' => 1, - 'AM_SET_DEPDIR' => 1, - '_AM_MANGLE_OPTION' => 1, - 'AM_AUTOMAKE_VERSION' => 1, - '_AM_SET_OPTIONS' => 1, - 'LT_PROG_GCJ' => 1, - 'AC_LTDL_SHLIBEXT' => 1, - 'AC_LIBTOOL_PROG_COMPILER_NO_RTTI' => 1, - 'AC_LIBLTDL_INSTALLABLE' => 1, - 'AC_LIBTOOL_DLOPEN' => 1, - 'AC_LIBTOOL_PROG_LD_SHLIBS' => 1, - '_AM_CONFIG_MACRO_DIRS' => 1, - '_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, - 'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1, - 'AM_PROG_LD' => 1, - 'LT_SYS_MODULE_PATH' => 1, - 'LT_CMD_MAX_LEN' => 1, - 'm4_pattern_forbid' => 1, - 'LTDL_INIT' => 1, - 'AC_LIBTOOL_DLOPEN_SELF' => 1, - 'AM_MAKE_INCLUDE' => 1, - 'LTDL_CONVENIENCE' => 1, - 'AC_LIB_LTDL' => 1, - 'AC_PROG_NM' => 1, - 'AM_PROG_INSTALL_STRIP' => 1, - '_AM_SUBST_NOTMAKE' => 1, - '_AM_SET_OPTION' => 1, - 'LT_PROG_RC' => 1, - 'AM_CONDITIONAL' => 1, - 'AC_ENABLE_STATIC' => 1, - 'AM_MISSING_HAS_RUN' => 1, - 'AC_LTDL_SYSSEARCHPATH' => 1, - 'AC_LTDL_ENABLE_INSTALL' => 1, - 'AC_ENABLE_FAST_INSTALL' => 1, - 'LT_AC_PROG_GCJ' => 1, - '_LT_AC_LANG_F77_CONFIG' => 1, - '_LT_DLL_DEF_P' => 1, - '_LT_AC_SYS_COMPILER' => 1, - 'AC_LIBTOOL_SYS_MAX_CMD_LEN' => 1, - 'LT_LANG' => 1, - 'AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH' => 1, + 'AM_PROG_NM' => 1, 'AM_INIT_AUTOMAKE' => 1, - 'AC_PROG_LD' => 1, - '_LT_PROG_ECHO_BACKSLASH' => 1, - '_LT_PROG_F77' => 1, - 'AM_DEP_TRACK' => 1, - '_LT_AC_FILE_LTDLL_C' => 1, - 'LTVERSION_VERSION' => 1, - 'AC_PROG_LD_GNU' => 1, - 'LT_SYS_DLOPEN_DEPLIBS' => 1, - 'AC_CHECK_LIBM' => 1, - 'AC_LIBTOOL_SYS_DYNAMIC_LINKER' => 1, - 'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1, - 'AC_WITH_LTDL' => 1, - '_LT_AC_LANG_GCJ' => 1, - 'AC_DEFUN_ONCE' => 1, + 'AM_SILENT_RULES' => 1, + 'LT_SYS_MODULE_PATH' => 1, + 'AC_LIBTOOL_LANG_F77_CONFIG' => 1, + 'LT_AC_PROG_RC' => 1, + '_LT_PREPARE_SED_QUOTE_VARS' => 1, + 'LT_SUPPORTED_TAG' => 1, + 'AM_DISABLE_STATIC' => 1, + '_LT_AC_PROG_CXXCPP' => 1, + '_LT_PATH_TOOL_PREFIX' => 1, + 'LTDL_INIT' => 1, + 'AC_LIBLTDL_CONVENIENCE' => 1, + '_LT_AC_LANG_F77_CONFIG' => 1, + 'm4_pattern_forbid' => 1, + 'AC_ENABLE_SHARED' => 1, + 'AC_LTDL_SYMBOL_USCORE' => 1, 'AC_LIBTOOL_POSTDEP_PREDEP' => 1, - '_LT_AC_LANG_C_CONFIG' => 1, - 'LT_CONFIG_LTDL_DIR' => 1, - 'LT_SYS_SYMBOL_USCORE' => 1, - 'AM_SET_LEADING_DOT' => 1, - '_LT_COMPILER_OPTION' => 1, + 'AC_LTDL_SHLIBPATH' => 1, + 'AC_DISABLE_STATIC' => 1, + 'AC_LTDL_ENABLE_INSTALL' => 1, + 'LT_AC_PROG_GCJ' => 1, + 'AC_LIBTOOL_SYS_MAX_CMD_LEN' => 1, + 'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1, '_LT_LINKER_OPTION' => 1, + 'AM_CONDITIONAL' => 1, + 'AC_PROG_LD_GNU' => 1, + 'LT_LANG' => 1, + '_LT_AC_FILE_LTDLL_C' => 1, '_AM_IF_OPTION' => 1, - 'AC_LIBTOOL_WIN32_DLL' => 1, - '_LT_LIBOBJ' => 1, + 'LT_INIT' => 1, + '_LT_AC_TAGCONFIG' => 1, + 'AC_PATH_MAGIC' => 1, + 'LTOPTIONS_VERSION' => 1, + '_LT_AC_CHECK_DLFCN' => 1, + 'AC_LIBTOOL_DLOPEN' => 1, + '_LT_PROG_LTMAIN' => 1, + 'AC_LIBTOOL_PICMODE' => 1, + '_LT_AC_PROG_ECHO_BACKSLASH' => 1, + 'AC_LIBTOOL_LANG_CXX_CONFIG' => 1, + 'AM_ENABLE_SHARED' => 1, + 'AC_LIBTOOL_SYS_DYNAMIC_LINKER' => 1, + 'AC_CONFIG_MACRO_DIR_TRACE' => 1, + '_LT_PROG_FC' => 1, + '_LT_LINKER_BOILERPLATE' => 1, + '_LT_AC_LANG_GCJ' => 1, + 'AC_LTDL_DLSYM_USCORE' => 1, + 'AC_LIBTOOL_SYS_LIB_STRIP' => 1, + 'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, + 'LT_LIB_DLLOAD' => 1, + 'LT_SYS_DLOPEN_DEPLIBS' => 1, + 'LT_AC_PROG_EGREP' => 1, + 'AM_PROG_CC_C_O' => 1, + '_AM_SET_OPTION' => 1, + '_LT_AC_SYS_COMPILER' => 1, + 'AC_PROG_NM' => 1, + 'LTVERSION_VERSION' => 1, 'AC_DEFUN' => 1, - 'LT_AC_PROG_SED' => 1 + 'AC_WITH_LTDL' => 1, + 'AC_LIB_LTDL' => 1, + '_LT_AC_SYS_LIBPATH_AIX' => 1, + '_AM_SUBST_NOTMAKE' => 1, + '_LT_PROG_F77' => 1, + 'LT_AC_PROG_SED' => 1, + 'AC_LIBTOOL_COMPILER_OPTION' => 1, + 'AM_MAINTAINER_MODE' => 1, + 'AC_LIBTOOL_DLOPEN_SELF' => 1, + '_AM_PROG_CC_C_O' => 1, + 'AC_LIBTOOL_FC' => 1, + 'AC_PROG_LD' => 1, + '_LT_AC_LANG_CXX' => 1, + 'AC_LTDL_SYSSEARCHPATH' => 1, + 'LT_SYS_SYMBOL_USCORE' => 1, + '_LT_AC_LANG_GCJ_CONFIG' => 1, + '_LT_COMPILER_BOILERPLATE' => 1, + '_AM_MANGLE_OPTION' => 1, + 'AM_PROG_INSTALL_STRIP' => 1, + 'AC_LIBTOOL_LANG_GCJ_CONFIG' => 1, + '_LT_REQUIRED_DARWIN_CHECKS' => 1, + 'LT_SYS_DLSEARCH_PATH' => 1, + 'AC_LTDL_OBJDIR' => 1, + 'AC_LIBTOOL_RC' => 1, + 'LT_PROG_RC' => 1, + 'AC_PROG_EGREP' => 1, + 'AC_PROG_LIBTOOL' => 1, + '_LT_AC_LOCK' => 1, + 'AC_DISABLE_FAST_INSTALL' => 1, + 'AC_LIBTOOL_CXX' => 1, + '_LT_AC_LANG_RC_CONFIG' => 1, + 'LT_PROG_GCJ' => 1, + 'AC_LTDL_PREOPEN' => 1, + 'AM_SANITY_CHECK' => 1, + 'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1, + '_AM_SET_OPTIONS' => 1, + 'AC_CHECK_LIBM' => 1, + 'AC_PROG_LD_RELOAD_FLAG' => 1, + 'AC_LIBTOOL_PROG_COMPILER_NO_RTTI' => 1, + '_LT_CC_BASENAME' => 1, + '_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, + 'AU_DEFUN' => 1, + 'AC_LIBTOOL_PROG_LD_SHLIBS' => 1, + 'AM_MISSING_HAS_RUN' => 1, + 'LT_LIB_M' => 1, + 'LT_FUNC_DLSYM_USCORE' => 1, + 'AC_ENABLE_STATIC' => 1, + 'AM_RUN_LOG' => 1, + 'AC_CONFIG_MACRO_DIR' => 1, + '_m4_warn' => 1, + 'AM_AUX_DIR_EXPAND' => 1, + '_LT_DLL_DEF_P' => 1, + '_LT_AC_SHELL_INIT' => 1, + 'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1, + 'm4_pattern_allow' => 1, + 'LTDL_CONVENIENCE' => 1, + 'LT_PATH_NM' => 1, + 'AC_LIBLTDL_INSTALLABLE' => 1, + 'AC_LIBTOOL_OBJDIR' => 1, + 'LT_OUTPUT' => 1, + '_LT_LIBOBJ' => 1, + 'LT_SYS_DLOPEN_SELF' => 1, + '_AC_AM_CONFIG_HEADER_HOOK' => 1, + 'AM_MAKE_INCLUDE' => 1, + 'AM_PROG_INSTALL_SH' => 1, + '_AM_AUTOCONF_VERSION' => 1, + '_LT_COMPILER_OPTION' => 1, + 'AM_PROG_LD' => 1, + 'AM_MISSING_PROG' => 1, + '_LT_PROG_CXX' => 1, + 'AC_LIBTOOL_PROG_COMPILER_PIC' => 1, + 'AC_LIBTOOL_LANG_C_CONFIG' => 1, + '_AM_CONFIG_MACRO_DIRS' => 1, + 'LT_PROG_GO' => 1, + '_LT_PROG_ECHO_BACKSLASH' => 1, + 'AC_LTDL_DLLIB' => 1, + '_AM_PROG_TAR' => 1, + 'LTOBSOLETE_VERSION' => 1, + '_LT_AC_TAGVAR' => 1, + 'LT_PATH_LD' => 1, + 'AM_DISABLE_SHARED' => 1, + '_AM_DEPENDENCIES' => 1, + 'LT_WITH_LTDL' => 1, + 'AC_DEFUN_ONCE' => 1, + 'LTSUGAR_VERSION' => 1, + 'AC_LIBTOOL_GCJ' => 1, + 'm4_include' => 1, + 'AC_LIBTOOL_F77' => 1, + 'AM_SET_LEADING_DOT' => 1, + 'AC_LIBTOOL_PROG_CC_C_O' => 1, + 'AC_LTDL_SHLIBEXT' => 1, + 'LT_FUNC_ARGZ' => 1, + '_LTDL_SETUP' => 1, + '_LT_AC_LANG_CXX_CONFIG' => 1, + 'AC_ENABLE_FAST_INSTALL' => 1, + 'AC_DISABLE_SHARED' => 1, + 'AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH' => 1, + '_AC_PROG_LIBTOOL' => 1, + 'AM_AUTOMAKE_VERSION' => 1, + '_LT_AC_TRY_DLOPEN_SELF' => 1, + 'AC_LIBTOOL_SETUP' => 1, + 'AM_ENABLE_STATIC' => 1, + 'AC_LIBTOOL_LANG_RC_CONFIG' => 1, + 'AM_SUBST_NOTMAKE' => 1, + 'LT_CONFIG_LTDL_DIR' => 1, + 'AM_PROG_LIBTOOL' => 1, + 'include' => 1, + '_LT_AC_LANG_F77' => 1, + 'LT_SYS_MODULE_EXT' => 1, + 'LT_CMD_MAX_LEN' => 1, + 'AM_SET_DEPDIR' => 1, + 'AC_LIBTOOL_WIN32_DLL' => 1, + '_LT_AC_LANG_C_CONFIG' => 1, + '_LT_WITH_SYSROOT' => 1, + 'AM_DEP_TRACK' => 1, + 'AC_PATH_TOOL_PREFIX' => 1, + 'LTDL_INSTALLABLE' => 1, + 'AC_LIBTOOL_LINKER_OPTION' => 1, + 'AC_DEPLIBS_CHECK_METHOD' => 1, + 'AC_LIBTOOL_CONFIG' => 1, + 'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1 } ], 'Autom4te::Request' ), bless( [ @@ -457,65 +457,65 @@ 'configure.ac' ], { - '_AM_COND_IF' => 1, - 'AM_PROG_AR' => 1, - 'AC_CONFIG_HEADERS' => 1, - 'AC_SUBST_TRACE' => 1, - 'AM_INIT_AUTOMAKE' => 1, - 'AM_POT_TOOLS' => 1, - 'AM_PROG_CXX_C_O' => 1, - 'm4_pattern_allow' => 1, - 'AC_FC_SRCEXT' => 1, - 'AC_CONFIG_SUBDIRS' => 1, - 'AC_REQUIRE_AUX_FILE' => 1, - 'AM_ENABLE_MULTILIB' => 1, - 'LT_INIT' => 1, - 'AM_GNU_GETTEXT' => 1, - '_AM_COND_ELSE' => 1, - 'LT_CONFIG_LTDL_DIR' => 1, - 'AC_CANONICAL_HOST' => 1, - 'AC_CANONICAL_BUILD' => 1, - 'm4_pattern_forbid' => 1, - 'AM_PROG_MKDIR_P' => 1, - '_AM_COND_ENDIF' => 1, - '_AM_MAKEFILE_INCLUDE' => 1, - 'LT_SUPPORTED_TAG' => 1, - 'AM_PROG_CC_C_O' => 1, - 'm4_sinclude' => 1, - 'AM_PROG_FC_C_O' => 1, - 'AM_PROG_F77_C_O' => 1, - 'AC_PROG_LIBTOOL' => 1, - 'AC_FC_PP_DEFINE' => 1, - 'AH_OUTPUT' => 1, - 'AC_SUBST' => 1, - '_AM_SUBST_NOTMAKE' => 1, - 'AM_PROG_MOC' => 1, - 'AC_CANONICAL_TARGET' => 1, - '_m4_warn' => 1, - 'AM_MAINTAINER_MODE' => 1, 'AM_MAKEFILE_INCLUDE' => 1, - 'AC_CANONICAL_SYSTEM' => 1, 'AM_CONDITIONAL' => 1, - 'AM_NLS' => 1, - 'AM_PATH_GUILE' => 1, - 'm4_include' => 1, - 'AM_EXTRA_RECURSIVE_TARGETS' => 1, - 'AC_CONFIG_LINKS' => 1, + 'AM_GNU_GETTEXT' => 1, + 'include' => 1, + 'AC_CONFIG_HEADERS' => 1, + 'AM_GNU_GETTEXT_INTL_SUBDIR' => 1, + '_AM_COND_ENDIF' => 1, + 'AC_DEFINE_TRACE_LITERAL' => 1, + 'AM_PROG_AR' => 1, + 'AC_CONFIG_LIBOBJ_DIR' => 1, + 'LT_CONFIG_LTDL_DIR' => 1, + 'AC_CONFIG_AUX_DIR' => 1, + 'AM_AUTOMAKE_VERSION' => 1, + 'AM_POT_TOOLS' => 1, + 'AM_PROG_FC_C_O' => 1, + 'AH_OUTPUT' => 1, + 'AM_ENABLE_MULTILIB' => 1, + 'AC_SUBST_TRACE' => 1, '_LT_AC_TAGCONFIG' => 1, 'AC_FC_FREEFORM' => 1, - 'AC_CONFIG_AUX_DIR' => 1, - 'AM_SILENT_RULES' => 1, + 'AM_PROG_MOC' => 1, + 'AC_CANONICAL_SYSTEM' => 1, 'sinclude' => 1, - 'AM_XGETTEXT_OPTION' => 1, + 'AC_PROG_LIBTOOL' => 1, + 'LT_INIT' => 1, + 'AM_NLS' => 1, + 'm4_include' => 1, + 'AM_PROG_CC_C_O' => 1, + 'AM_PROG_CXX_C_O' => 1, + '_AM_MAKEFILE_INCLUDE' => 1, + 'AM_INIT_AUTOMAKE' => 1, + 'AC_LIBSOURCE' => 1, + '_AM_COND_ELSE' => 1, + 'AM_SILENT_RULES' => 1, + 'AC_CONFIG_LINKS' => 1, + 'AM_EXTRA_RECURSIVE_TARGETS' => 1, + 'AC_CONFIG_SUBDIRS' => 1, 'AC_INIT' => 1, - 'AC_FC_PP_SRCEXT' => 1, + 'AC_CANONICAL_HOST' => 1, + 'AC_REQUIRE_AUX_FILE' => 1, + 'AM_XGETTEXT_OPTION' => 1, + 'AC_CANONICAL_TARGET' => 1, + 'AM_PROG_MKDIR_P' => 1, + 'AC_FC_SRCEXT' => 1, + 'm4_sinclude' => 1, + 'm4_pattern_forbid' => 1, + 'm4_pattern_allow' => 1, + 'AC_CANONICAL_BUILD' => 1, 'AC_CONFIG_FILES' => 1, - 'AM_GNU_GETTEXT_INTL_SUBDIR' => 1, - 'include' => 1, - 'AC_CONFIG_LIBOBJ_DIR' => 1, - 'AC_DEFINE_TRACE_LITERAL' => 1, - 'AM_AUTOMAKE_VERSION' => 1, - 'AC_LIBSOURCE' => 1 + 'AM_PROG_F77_C_O' => 1, + 'AC_FC_PP_SRCEXT' => 1, + '_m4_warn' => 1, + 'AM_MAINTAINER_MODE' => 1, + 'AM_PATH_GUILE' => 1, + 'LT_SUPPORTED_TAG' => 1, + 'AC_SUBST' => 1, + 'AC_FC_PP_DEFINE' => 1, + '_AM_COND_IF' => 1, + '_AM_SUBST_NOTMAKE' => 1 } ], 'Autom4te::Request' ) ); diff --git a/autom4te.cache/traces.0 b/autom4te.cache/traces.0 index 3c660df..6b179aa 100644 --- a/autom4te.cache/traces.0 +++ b/autom4te.cache/traces.0 @@ -2729,29 +2729,29 @@ m4trace:configure.ac:130: -1- m4_pattern_allow([^HAVE_LIBREADLINE$]) m4trace:configure.ac:136: -1- m4_pattern_allow([^HAVE_SELINUX_SELINUX_H$]) m4trace:configure.ac:137: -1- m4_pattern_allow([^HAVE_LIBSELINUX$]) m4trace:configure.ac:146: -1- m4_pattern_allow([^HAVE_ELF_C_READ_MMAP$]) -m4trace:configure.ac:159: -1- m4_pattern_allow([^ELF_HASH_TAKES_CHARP$]) -m4trace:configure.ac:194: -1- m4_pattern_allow([^uid_t$]) -m4trace:configure.ac:194: -1- m4_pattern_allow([^gid_t$]) -m4trace:configure.ac:196: -1- m4_pattern_allow([^pid_t$]) -m4trace:configure.ac:197: -1- m4_pattern_allow([^size_t$]) -m4trace:configure.ac:198: -1- m4_pattern_allow([^SIZEOF_LONG$]) -m4trace:configure.ac:202: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_VFORK_H$]) -m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$]) -m4trace:configure.ac:203: -1- m4_pattern_allow([^vfork$]) -m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_WORKING_FORK$]) -m4trace:configure.ac:233: -1- m4_pattern_allow([^DEBUG$]) -m4trace:configure.ac:247: -1- m4_pattern_allow([^AM_CPPFLAGS$]) -m4trace:configure.ac:248: -1- m4_pattern_allow([^AM_CFLAGS$]) -m4trace:configure.ac:249: -1- m4_pattern_allow([^AM_LDFLAGS$]) -m4trace:configure.ac:250: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$]) -m4trace:configure.ac:261: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:261: -1- m4_pattern_allow([^LTLIBOBJS$]) -m4trace:configure.ac:261: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) -m4trace:configure.ac:261: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) -m4trace:configure.ac:261: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) -m4trace:configure.ac:261: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) -m4trace:configure.ac:261: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) -m4trace:configure.ac:261: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"]) -m4trace:configure.ac:261: -1- _LT_PROG_LTMAIN -m4trace:configure.ac:261: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS +m4trace:configure.ac:161: -1- m4_pattern_allow([^ELF_HASH_TAKES_CHARP$]) +m4trace:configure.ac:196: -1- m4_pattern_allow([^uid_t$]) +m4trace:configure.ac:196: -1- m4_pattern_allow([^gid_t$]) +m4trace:configure.ac:198: -1- m4_pattern_allow([^pid_t$]) +m4trace:configure.ac:199: -1- m4_pattern_allow([^size_t$]) +m4trace:configure.ac:200: -1- m4_pattern_allow([^SIZEOF_LONG$]) +m4trace:configure.ac:204: -1- m4_pattern_allow([^LIB@&t@OBJS$]) +m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_VFORK_H$]) +m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$]) +m4trace:configure.ac:205: -1- m4_pattern_allow([^vfork$]) +m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_WORKING_FORK$]) +m4trace:configure.ac:236: -1- m4_pattern_allow([^DEBUG$]) +m4trace:configure.ac:250: -1- m4_pattern_allow([^AM_CPPFLAGS$]) +m4trace:configure.ac:251: -1- m4_pattern_allow([^AM_CFLAGS$]) +m4trace:configure.ac:252: -1- m4_pattern_allow([^AM_LDFLAGS$]) +m4trace:configure.ac:253: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$]) +m4trace:configure.ac:264: -1- m4_pattern_allow([^LIB@&t@OBJS$]) +m4trace:configure.ac:264: -1- m4_pattern_allow([^LTLIBOBJS$]) +m4trace:configure.ac:264: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) +m4trace:configure.ac:264: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) +m4trace:configure.ac:264: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) +m4trace:configure.ac:264: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) +m4trace:configure.ac:264: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) +m4trace:configure.ac:264: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"]) +m4trace:configure.ac:264: -1- _LT_PROG_LTMAIN +m4trace:configure.ac:264: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS diff --git a/autom4te.cache/traces.1 b/autom4te.cache/traces.1 index 7e0ba49..0bbc661 100644 --- a/autom4te.cache/traces.1 +++ b/autom4te.cache/traces.1 @@ -2729,29 +2729,29 @@ m4trace:configure.ac:130: -1- m4_pattern_allow([^HAVE_LIBREADLINE$]) m4trace:configure.ac:136: -1- m4_pattern_allow([^HAVE_SELINUX_SELINUX_H$]) m4trace:configure.ac:137: -1- m4_pattern_allow([^HAVE_LIBSELINUX$]) m4trace:configure.ac:146: -1- m4_pattern_allow([^HAVE_ELF_C_READ_MMAP$]) -m4trace:configure.ac:159: -1- m4_pattern_allow([^ELF_HASH_TAKES_CHARP$]) -m4trace:configure.ac:194: -1- m4_pattern_allow([^uid_t$]) -m4trace:configure.ac:194: -1- m4_pattern_allow([^gid_t$]) -m4trace:configure.ac:196: -1- m4_pattern_allow([^pid_t$]) -m4trace:configure.ac:197: -1- m4_pattern_allow([^size_t$]) -m4trace:configure.ac:198: -1- m4_pattern_allow([^SIZEOF_LONG$]) -m4trace:configure.ac:202: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_VFORK_H$]) -m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$]) -m4trace:configure.ac:203: -1- m4_pattern_allow([^vfork$]) -m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_WORKING_FORK$]) -m4trace:configure.ac:233: -1- m4_pattern_allow([^DEBUG$]) -m4trace:configure.ac:247: -1- m4_pattern_allow([^AM_CPPFLAGS$]) -m4trace:configure.ac:248: -1- m4_pattern_allow([^AM_CFLAGS$]) -m4trace:configure.ac:249: -1- m4_pattern_allow([^AM_LDFLAGS$]) -m4trace:configure.ac:250: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$]) -m4trace:configure.ac:261: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:261: -1- m4_pattern_allow([^LTLIBOBJS$]) -m4trace:configure.ac:261: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) -m4trace:configure.ac:261: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) -m4trace:configure.ac:261: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) -m4trace:configure.ac:261: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) -m4trace:configure.ac:261: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) -m4trace:configure.ac:261: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"]) -m4trace:configure.ac:261: -1- _LT_PROG_LTMAIN -m4trace:configure.ac:261: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS +m4trace:configure.ac:161: -1- m4_pattern_allow([^ELF_HASH_TAKES_CHARP$]) +m4trace:configure.ac:196: -1- m4_pattern_allow([^uid_t$]) +m4trace:configure.ac:196: -1- m4_pattern_allow([^gid_t$]) +m4trace:configure.ac:198: -1- m4_pattern_allow([^pid_t$]) +m4trace:configure.ac:199: -1- m4_pattern_allow([^size_t$]) +m4trace:configure.ac:200: -1- m4_pattern_allow([^SIZEOF_LONG$]) +m4trace:configure.ac:204: -1- m4_pattern_allow([^LIB@&t@OBJS$]) +m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_VFORK_H$]) +m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$]) +m4trace:configure.ac:205: -1- m4_pattern_allow([^vfork$]) +m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_WORKING_FORK$]) +m4trace:configure.ac:236: -1- m4_pattern_allow([^DEBUG$]) +m4trace:configure.ac:250: -1- m4_pattern_allow([^AM_CPPFLAGS$]) +m4trace:configure.ac:251: -1- m4_pattern_allow([^AM_CFLAGS$]) +m4trace:configure.ac:252: -1- m4_pattern_allow([^AM_LDFLAGS$]) +m4trace:configure.ac:253: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$]) +m4trace:configure.ac:264: -1- m4_pattern_allow([^LIB@&t@OBJS$]) +m4trace:configure.ac:264: -1- m4_pattern_allow([^LTLIBOBJS$]) +m4trace:configure.ac:264: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) +m4trace:configure.ac:264: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) +m4trace:configure.ac:264: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) +m4trace:configure.ac:264: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) +m4trace:configure.ac:264: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) +m4trace:configure.ac:264: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"]) +m4trace:configure.ac:264: -1- _LT_PROG_LTMAIN +m4trace:configure.ac:264: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS diff --git a/autom4te.cache/traces.2 b/autom4te.cache/traces.2 index 933c4b9..0cb78d8 100644 --- a/autom4te.cache/traces.2 +++ b/autom4te.cache/traces.2 @@ -3,7 +3,7 @@ m4trace:aclocal.m4:1190: -1- m4_include([config/m4/ltoptions.m4]) m4trace:aclocal.m4:1191: -1- m4_include([config/m4/ltsugar.m4]) m4trace:aclocal.m4:1192: -1- m4_include([config/m4/ltversion.m4]) m4trace:aclocal.m4:1193: -1- m4_include([config/m4/lt~obsolete.m4]) -m4trace:configure.ac:27: -1- AC_INIT([mtrace], [0.1], [stefani@seibold.net]) +m4trace:configure.ac:27: -1- AC_INIT([mtrace], [0.2], [stefani@seibold.net]) m4trace:configure.ac:27: -1- m4_pattern_forbid([^_?A[CHUM]_]) m4trace:configure.ac:27: -1- m4_pattern_forbid([_AC_]) m4trace:configure.ac:27: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section `AC_LIBOBJ vs LIBOBJS']) @@ -559,122 +559,124 @@ m4trace:configure.ac:146: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ELF_C_READ_MMAP]) m4trace:configure.ac:146: -1- m4_pattern_allow([^HAVE_ELF_C_READ_MMAP$]) m4trace:configure.ac:146: -1- AH_OUTPUT([HAVE_ELF_C_READ_MMAP], [/* we have read mmap support */ @%:@undef HAVE_ELF_C_READ_MMAP]) -m4trace:configure.ac:159: -1- AC_DEFINE_TRACE_LITERAL([ELF_HASH_TAKES_CHARP]) -m4trace:configure.ac:159: -1- m4_pattern_allow([^ELF_HASH_TAKES_CHARP$]) -m4trace:configure.ac:159: -1- AH_OUTPUT([ELF_HASH_TAKES_CHARP], [/* elf_hash() takes char* (as opposed to unsigned char *) */ +m4trace:configure.ac:161: -1- AC_DEFINE_TRACE_LITERAL([ELF_HASH_TAKES_CHARP]) +m4trace:configure.ac:161: -1- m4_pattern_allow([^ELF_HASH_TAKES_CHARP$]) +m4trace:configure.ac:161: -1- AH_OUTPUT([ELF_HASH_TAKES_CHARP], [/* elf_hash() takes char* (as opposed to unsigned char *) */ @%:@undef ELF_HASH_TAKES_CHARP]) -m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_FCNTL_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_FCNTL_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_FCNTL_H]) -m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_LIMITS_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_LIMITS_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_LIMITS_H]) -m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_STDDEF_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_STDDEF_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_STDDEF_H]) -m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_STDINT_H]) -m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_STDLIB_H]) -m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_STRING_H]) -m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_SYS_IOCTL_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_SYS_IOCTL_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_SYS_IOCTL_H]) -m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_SYS_PARAM_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_SYS_PARAM_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_SYS_PARAM_H]) -m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_SYS_TIME_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_SYS_TIME_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_SYS_TIME_H]) -m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_UNISTD_H]) -m4trace:configure.ac:194: -1- AC_DEFINE_TRACE_LITERAL([uid_t]) -m4trace:configure.ac:194: -1- m4_pattern_allow([^uid_t$]) -m4trace:configure.ac:194: -1- AH_OUTPUT([uid_t], [/* Define to `int\' if doesn\'t define. */ +m4trace:configure.ac:196: -1- AC_DEFINE_TRACE_LITERAL([uid_t]) +m4trace:configure.ac:196: -1- m4_pattern_allow([^uid_t$]) +m4trace:configure.ac:196: -1- AH_OUTPUT([uid_t], [/* Define to `int\' if doesn\'t define. */ @%:@undef uid_t]) -m4trace:configure.ac:194: -1- AC_DEFINE_TRACE_LITERAL([gid_t]) -m4trace:configure.ac:194: -1- m4_pattern_allow([^gid_t$]) -m4trace:configure.ac:194: -1- AH_OUTPUT([gid_t], [/* Define to `int\' if doesn\'t define. */ +m4trace:configure.ac:196: -1- AC_DEFINE_TRACE_LITERAL([gid_t]) +m4trace:configure.ac:196: -1- m4_pattern_allow([^gid_t$]) +m4trace:configure.ac:196: -1- AH_OUTPUT([gid_t], [/* Define to `int\' if doesn\'t define. */ @%:@undef gid_t]) -m4trace:configure.ac:195: -1- AH_OUTPUT([inline], [/* Define to `__inline__\' or `__inline\' if that\'s what the C compiler +m4trace:configure.ac:197: -1- AH_OUTPUT([inline], [/* Define to `__inline__\' or `__inline\' if that\'s what the C compiler calls it, or to nothing if \'inline\' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif]) -m4trace:configure.ac:196: -1- AC_DEFINE_TRACE_LITERAL([pid_t]) -m4trace:configure.ac:196: -1- m4_pattern_allow([^pid_t$]) -m4trace:configure.ac:196: -1- AH_OUTPUT([pid_t], [/* Define to `int\' if does not define. */ +m4trace:configure.ac:198: -1- AC_DEFINE_TRACE_LITERAL([pid_t]) +m4trace:configure.ac:198: -1- m4_pattern_allow([^pid_t$]) +m4trace:configure.ac:198: -1- AH_OUTPUT([pid_t], [/* Define to `int\' if does not define. */ @%:@undef pid_t]) -m4trace:configure.ac:197: -1- AC_DEFINE_TRACE_LITERAL([size_t]) -m4trace:configure.ac:197: -1- m4_pattern_allow([^size_t$]) -m4trace:configure.ac:197: -1- AH_OUTPUT([size_t], [/* Define to `unsigned int\' if does not define. */ +m4trace:configure.ac:199: -1- AC_DEFINE_TRACE_LITERAL([size_t]) +m4trace:configure.ac:199: -1- m4_pattern_allow([^size_t$]) +m4trace:configure.ac:199: -1- AH_OUTPUT([size_t], [/* Define to `unsigned int\' if does not define. */ @%:@undef size_t]) -m4trace:configure.ac:198: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_LONG]) -m4trace:configure.ac:198: -1- m4_pattern_allow([^SIZEOF_LONG$]) -m4trace:configure.ac:198: -1- AH_OUTPUT([SIZEOF_LONG], [/* The size of `long\', as computed by sizeof. */ +m4trace:configure.ac:200: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_LONG]) +m4trace:configure.ac:200: -1- m4_pattern_allow([^SIZEOF_LONG$]) +m4trace:configure.ac:200: -1- AH_OUTPUT([SIZEOF_LONG], [/* The size of `long\', as computed by sizeof. */ @%:@undef SIZEOF_LONG]) -m4trace:configure.ac:202: -1- AC_LIBSOURCE([error.h]) -m4trace:configure.ac:202: -1- AC_LIBSOURCE([error.c]) -m4trace:configure.ac:202: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS error.$ac_objext"]) -m4trace:configure.ac:202: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:202: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:202: -1- AC_LIBSOURCE([error.c]) -m4trace:configure.ac:203: -1- AH_OUTPUT([HAVE_VFORK_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.ac:204: -1- AC_LIBSOURCE([error.h]) +m4trace:configure.ac:204: -1- AC_LIBSOURCE([error.c]) +m4trace:configure.ac:204: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS error.$ac_objext"]) +m4trace:configure.ac:204: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) +m4trace:configure.ac:204: -1- m4_pattern_allow([^LIB@&t@OBJS$]) +m4trace:configure.ac:204: -1- AC_LIBSOURCE([error.c]) +m4trace:configure.ac:205: -1- AH_OUTPUT([HAVE_VFORK_H], [/* Define to 1 if you have the header file. */ @%:@undef HAVE_VFORK_H]) -m4trace:configure.ac:203: -1- AC_DEFINE_TRACE_LITERAL([HAVE_VFORK_H]) -m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_VFORK_H$]) -m4trace:configure.ac:203: -1- AH_OUTPUT([HAVE_FORK], [/* Define to 1 if you have the `fork\' function. */ +m4trace:configure.ac:205: -1- AC_DEFINE_TRACE_LITERAL([HAVE_VFORK_H]) +m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_VFORK_H$]) +m4trace:configure.ac:205: -1- AH_OUTPUT([HAVE_FORK], [/* Define to 1 if you have the `fork\' function. */ @%:@undef HAVE_FORK]) -m4trace:configure.ac:203: -1- AH_OUTPUT([HAVE_VFORK], [/* Define to 1 if you have the `vfork\' function. */ +m4trace:configure.ac:205: -1- AH_OUTPUT([HAVE_VFORK], [/* Define to 1 if you have the `vfork\' function. */ @%:@undef HAVE_VFORK]) -m4trace:configure.ac:203: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WORKING_VFORK]) -m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$]) -m4trace:configure.ac:203: -1- AH_OUTPUT([HAVE_WORKING_VFORK], [/* Define to 1 if `vfork\' works. */ +m4trace:configure.ac:205: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WORKING_VFORK]) +m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$]) +m4trace:configure.ac:205: -1- AH_OUTPUT([HAVE_WORKING_VFORK], [/* Define to 1 if `vfork\' works. */ @%:@undef HAVE_WORKING_VFORK]) -m4trace:configure.ac:203: -1- AC_DEFINE_TRACE_LITERAL([vfork]) -m4trace:configure.ac:203: -1- m4_pattern_allow([^vfork$]) -m4trace:configure.ac:203: -1- AH_OUTPUT([vfork], [/* Define as `fork\' if `vfork\' does not work. */ +m4trace:configure.ac:205: -1- AC_DEFINE_TRACE_LITERAL([vfork]) +m4trace:configure.ac:205: -1- m4_pattern_allow([^vfork$]) +m4trace:configure.ac:205: -1- AH_OUTPUT([vfork], [/* Define as `fork\' if `vfork\' does not work. */ @%:@undef vfork]) -m4trace:configure.ac:203: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WORKING_FORK]) -m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_WORKING_FORK$]) -m4trace:configure.ac:203: -1- AH_OUTPUT([HAVE_WORKING_FORK], [/* Define to 1 if `fork\' works. */ +m4trace:configure.ac:205: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WORKING_FORK]) +m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_WORKING_FORK$]) +m4trace:configure.ac:205: -1- AH_OUTPUT([HAVE_WORKING_FORK], [/* Define to 1 if `fork\' works. */ @%:@undef HAVE_WORKING_FORK]) -m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_ALARM], [/* Define to 1 if you have the `alarm\' function. */ +m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_ALARM], [/* Define to 1 if you have the `alarm\' function. */ @%:@undef HAVE_ALARM]) -m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_ATEXIT], [/* Define to 1 if you have the `atexit\' function. */ +m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_ATEXIT], [/* Define to 1 if you have the `atexit\' function. */ @%:@undef HAVE_ATEXIT]) -m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_GETCWD], [/* Define to 1 if you have the `getcwd\' function. */ +m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_GETCWD], [/* Define to 1 if you have the `getcwd\' function. */ @%:@undef HAVE_GETCWD]) -m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_GETTIMEOFDAY], [/* Define to 1 if you have the `gettimeofday\' function. */ +m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_GETTIMEOFDAY], [/* Define to 1 if you have the `gettimeofday\' function. */ @%:@undef HAVE_GETTIMEOFDAY]) -m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_MEMSET], [/* Define to 1 if you have the `memset\' function. */ +m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_MEMSET], [/* Define to 1 if you have the `memset\' function. */ @%:@undef HAVE_MEMSET]) -m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_MKDIR], [/* Define to 1 if you have the `mkdir\' function. */ +m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_MKDIR], [/* Define to 1 if you have the `mkdir\' function. */ @%:@undef HAVE_MKDIR]) -m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_RMDIR], [/* Define to 1 if you have the `rmdir\' function. */ +m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_RMDIR], [/* Define to 1 if you have the `rmdir\' function. */ @%:@undef HAVE_RMDIR]) -m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_STRCHR], [/* Define to 1 if you have the `strchr\' function. */ +m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_STRCHR], [/* Define to 1 if you have the `strchr\' function. */ @%:@undef HAVE_STRCHR]) -m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_STRDUP], [/* Define to 1 if you have the `strdup\' function. */ +m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_STRDUP], [/* Define to 1 if you have the `strdup\' function. */ @%:@undef HAVE_STRDUP]) -m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_STRERROR], [/* Define to 1 if you have the `strerror\' function. */ +m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_STRERROR], [/* Define to 1 if you have the `strerror\' function. */ @%:@undef HAVE_STRERROR]) -m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_STRTOL], [/* Define to 1 if you have the `strtol\' function. */ +m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_STRTOL], [/* Define to 1 if you have the `strtol\' function. */ @%:@undef HAVE_STRTOL]) -m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_STRTOUL], [/* Define to 1 if you have the `strtoul\' function. */ +m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_STRTOUL], [/* Define to 1 if you have the `strtoul\' function. */ @%:@undef HAVE_STRTOUL]) -m4trace:configure.ac:233: -1- AC_DEFINE_TRACE_LITERAL([DEBUG]) -m4trace:configure.ac:233: -1- m4_pattern_allow([^DEBUG$]) -m4trace:configure.ac:233: -1- AH_OUTPUT([DEBUG], [/* debugging */ +m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_PROCESS_VM_READV], [/* Define to 1 if you have the `process_vm_readv\' function. */ +@%:@undef HAVE_PROCESS_VM_READV]) +m4trace:configure.ac:236: -1- AC_DEFINE_TRACE_LITERAL([DEBUG]) +m4trace:configure.ac:236: -1- m4_pattern_allow([^DEBUG$]) +m4trace:configure.ac:236: -1- AH_OUTPUT([DEBUG], [/* debugging */ @%:@undef DEBUG]) -m4trace:configure.ac:247: -1- AC_SUBST([AM_CPPFLAGS]) -m4trace:configure.ac:247: -1- AC_SUBST_TRACE([AM_CPPFLAGS]) -m4trace:configure.ac:247: -1- m4_pattern_allow([^AM_CPPFLAGS$]) -m4trace:configure.ac:248: -1- AC_SUBST([AM_CFLAGS]) -m4trace:configure.ac:248: -1- AC_SUBST_TRACE([AM_CFLAGS]) -m4trace:configure.ac:248: -1- m4_pattern_allow([^AM_CFLAGS$]) -m4trace:configure.ac:249: -1- AC_SUBST([AM_LDFLAGS]) -m4trace:configure.ac:249: -1- AC_SUBST_TRACE([AM_LDFLAGS]) -m4trace:configure.ac:249: -1- m4_pattern_allow([^AM_LDFLAGS$]) -m4trace:configure.ac:250: -1- AC_SUBST([libelf_LD_LIBRARY_PATH]) -m4trace:configure.ac:250: -1- AC_SUBST_TRACE([libelf_LD_LIBRARY_PATH]) -m4trace:configure.ac:250: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$]) -m4trace:configure.ac:252: -1- AC_CONFIG_FILES([ +m4trace:configure.ac:250: -1- AC_SUBST([AM_CPPFLAGS]) +m4trace:configure.ac:250: -1- AC_SUBST_TRACE([AM_CPPFLAGS]) +m4trace:configure.ac:250: -1- m4_pattern_allow([^AM_CPPFLAGS$]) +m4trace:configure.ac:251: -1- AC_SUBST([AM_CFLAGS]) +m4trace:configure.ac:251: -1- AC_SUBST_TRACE([AM_CFLAGS]) +m4trace:configure.ac:251: -1- m4_pattern_allow([^AM_CFLAGS$]) +m4trace:configure.ac:252: -1- AC_SUBST([AM_LDFLAGS]) +m4trace:configure.ac:252: -1- AC_SUBST_TRACE([AM_LDFLAGS]) +m4trace:configure.ac:252: -1- m4_pattern_allow([^AM_LDFLAGS$]) +m4trace:configure.ac:253: -1- AC_SUBST([libelf_LD_LIBRARY_PATH]) +m4trace:configure.ac:253: -1- AC_SUBST_TRACE([libelf_LD_LIBRARY_PATH]) +m4trace:configure.ac:253: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$]) +m4trace:configure.ac:255: -1- AC_CONFIG_FILES([ Makefile client/Makefile sysdeps/Makefile @@ -683,30 +685,30 @@ m4trace:configure.ac:252: -1- AC_CONFIG_FILES([ sysdeps/linux-gnu/ppc/Makefile sysdeps/linux-gnu/arm/Makefile ]) -m4trace:configure.ac:261: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs]) -m4trace:configure.ac:261: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:261: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:261: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs]) -m4trace:configure.ac:261: -1- AC_SUBST_TRACE([LTLIBOBJS]) -m4trace:configure.ac:261: -1- m4_pattern_allow([^LTLIBOBJS$]) -m4trace:configure.ac:261: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) -m4trace:configure.ac:261: -1- AC_SUBST([am__EXEEXT_TRUE]) -m4trace:configure.ac:261: -1- AC_SUBST_TRACE([am__EXEEXT_TRUE]) -m4trace:configure.ac:261: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) -m4trace:configure.ac:261: -1- AC_SUBST([am__EXEEXT_FALSE]) -m4trace:configure.ac:261: -1- AC_SUBST_TRACE([am__EXEEXT_FALSE]) -m4trace:configure.ac:261: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) -m4trace:configure.ac:261: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) -m4trace:configure.ac:261: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) -m4trace:configure.ac:261: -1- AC_SUBST_TRACE([top_builddir]) -m4trace:configure.ac:261: -1- AC_SUBST_TRACE([top_build_prefix]) -m4trace:configure.ac:261: -1- AC_SUBST_TRACE([srcdir]) -m4trace:configure.ac:261: -1- AC_SUBST_TRACE([abs_srcdir]) -m4trace:configure.ac:261: -1- AC_SUBST_TRACE([top_srcdir]) -m4trace:configure.ac:261: -1- AC_SUBST_TRACE([abs_top_srcdir]) -m4trace:configure.ac:261: -1- AC_SUBST_TRACE([builddir]) -m4trace:configure.ac:261: -1- AC_SUBST_TRACE([abs_builddir]) -m4trace:configure.ac:261: -1- AC_SUBST_TRACE([abs_top_builddir]) -m4trace:configure.ac:261: -1- AC_SUBST_TRACE([INSTALL]) -m4trace:configure.ac:261: -1- AC_SUBST_TRACE([MKDIR_P]) -m4trace:configure.ac:261: -1- AC_REQUIRE_AUX_FILE([ltmain.sh]) +m4trace:configure.ac:264: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs]) +m4trace:configure.ac:264: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) +m4trace:configure.ac:264: -1- m4_pattern_allow([^LIB@&t@OBJS$]) +m4trace:configure.ac:264: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs]) +m4trace:configure.ac:264: -1- AC_SUBST_TRACE([LTLIBOBJS]) +m4trace:configure.ac:264: -1- m4_pattern_allow([^LTLIBOBJS$]) +m4trace:configure.ac:264: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) +m4trace:configure.ac:264: -1- AC_SUBST([am__EXEEXT_TRUE]) +m4trace:configure.ac:264: -1- AC_SUBST_TRACE([am__EXEEXT_TRUE]) +m4trace:configure.ac:264: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) +m4trace:configure.ac:264: -1- AC_SUBST([am__EXEEXT_FALSE]) +m4trace:configure.ac:264: -1- AC_SUBST_TRACE([am__EXEEXT_FALSE]) +m4trace:configure.ac:264: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) +m4trace:configure.ac:264: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) +m4trace:configure.ac:264: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) +m4trace:configure.ac:264: -1- AC_SUBST_TRACE([top_builddir]) +m4trace:configure.ac:264: -1- AC_SUBST_TRACE([top_build_prefix]) +m4trace:configure.ac:264: -1- AC_SUBST_TRACE([srcdir]) +m4trace:configure.ac:264: -1- AC_SUBST_TRACE([abs_srcdir]) +m4trace:configure.ac:264: -1- AC_SUBST_TRACE([top_srcdir]) +m4trace:configure.ac:264: -1- AC_SUBST_TRACE([abs_top_srcdir]) +m4trace:configure.ac:264: -1- AC_SUBST_TRACE([builddir]) +m4trace:configure.ac:264: -1- AC_SUBST_TRACE([abs_builddir]) +m4trace:configure.ac:264: -1- AC_SUBST_TRACE([abs_top_builddir]) +m4trace:configure.ac:264: -1- AC_SUBST_TRACE([INSTALL]) +m4trace:configure.ac:264: -1- AC_SUBST_TRACE([MKDIR_P]) +m4trace:configure.ac:264: -1- AC_REQUIRE_AUX_FILE([ltmain.sh]) diff --git a/backend.h b/backend.h index 75103c0..70eb36d 100644 --- a/backend.h +++ b/backend.h @@ -84,6 +84,10 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task)); * function returns. */ arch_addr_t get_return_addr(struct task *task); +#if HW_BREAKPOINTS > 0 +/* returns true if the hw breakpoint is pendig */ +int get_hw_bp_state(struct task *task, unsigned int n); + /* set instruction hw breakpoint */ int set_hw_bp(struct task *task, unsigned int n, arch_addr_t addr); @@ -92,6 +96,7 @@ int reset_hw_bp(struct task *task, unsigned int n); /* remove all instruction hw breakpoints */ int reset_all_hw_bp(struct task *task); +#endif /* save the process context (state, registers, stack pointer) */ int fetch_context(struct task *task); diff --git a/backtrace.h b/backtrace.h index 298a7d4..4ecb325 100644 --- a/backtrace.h +++ b/backtrace.h @@ -40,5 +40,8 @@ unsigned long backtrace_get_ip(struct task *task); /* step to next backtrace given task */ int backtrace_step(struct task *task); +/* get backtrace location type of given task */ +int backtrace_location_type(struct task *task); + #endif diff --git a/breakpoint.c b/breakpoint.c index f25c404..29d9af2 100644 --- a/breakpoint.c +++ b/breakpoint.c @@ -34,6 +34,7 @@ #include "debug.h" #include "library.h" #include "mtelf.h" +#include "options.h" #include "report.h" #include "task.h" #include "trace.h" @@ -98,54 +99,19 @@ struct breakpoint *breakpoint_find(struct task *task, arch_addr_t addr) } #if HW_BREAKPOINTS > 0 -#if HW_BREAKPOINTS > 1 -static int find_hw_bp_slot(struct task *leader) -{ - int i; - - for(i = HW_BP_SCRATCH_SLOT + 1; i < HW_BREAKPOINTS; ++i) - if ((leader->hw_bp_mask & (1 << i)) == 0) - return i; - return -1; -} -#endif - static void enable_hw_bp(struct task *task, struct breakpoint *bp) { unsigned int slot = bp->hw_bp_slot; - if (bp->hw_bp_slot != HW_BP_SCRATCH_SLOT) - assert(task->hw_bp[slot] == NULL); - + assert(bp->type != BP_SW); + assert(bp->type < BP_HW || task->hw_bp[slot] == NULL); + task->hw_bp[slot] = bp; if (set_hw_bp(task, slot, bp->addr) == -1) fatal("set_hw_bp"); } -void breakpoint_hw_clone(struct task *task) -{ - unsigned int i; - struct task *leader = task->leader; - - if (leader == task) - return; - - for(i = HW_BP_SCRATCH_SLOT + 1; i < HW_BREAKPOINTS; ++i) { - if ((leader->hw_bp_mask & (1 << i)) == 0) { - assert(task->hw_bp[i] == NULL); - continue; - } - - if (leader->hw_bp[i]) { - assert(leader->hw_bp[i]->enabled); - assert(leader->hw_bp[i]->hw_bp_slot == i); - - enable_hw_bp(task, leader->hw_bp[i]); - } - } -} - static void disable_hw_bp(struct task *task, struct breakpoint *bp) { unsigned int slot = bp->hw_bp_slot; @@ -155,33 +121,175 @@ static void disable_hw_bp(struct task *task, struct breakpoint *bp) assert(task->hw_bp[slot] == bp); - task->hw_bp[slot] = NULL; - if (reset_hw_bp(task, slot) == -1) fatal("reset_hw_bp"); + + task->hw_bp[slot] = NULL; +} + +#if HW_BREAKPOINTS > 1 +static void enable_hw_bp_cb(struct task *task, void *data) +{ + enable_hw_bp(task, data); +} + +static void disable_hw_bp_cb(struct task *task, void *data) +{ + disable_hw_bp(task, data); +} + +static void hw2sw_bp(struct task *leader, struct breakpoint *bp) +{ + each_task(leader, disable_hw_bp_cb, bp); + bp->hw = 0; + enable_sw_breakpoint(leader, bp); +} + +static int hw_bp_sort(const void *a, const void *b) +{ + const struct breakpoint *p = *(const struct breakpoint **)a; + const struct breakpoint *q = *(const struct breakpoint **)b; + + if (p->type != q->type) + return (p->type == BP_HW) ? -1 : 1; + + return (int)(q->hwcnt - p->hwcnt); +} + +void reorder_hw_bp(struct task *task) +{ + struct task *leader = task->leader; + struct list_head *it; + struct breakpoint *bp_list[leader->hw_bp_num + 1]; + struct breakpoint *bp; + struct breakpoint **p; + unsigned long hw_bp_set = 0; + unsigned int i; + unsigned int n; + + if (!leader->hw_bp_num) + return; + + n = 0; + list_for_each(it, &leader->hw_bp_list) { + bp = container_of(it, struct breakpoint, link_list); + if (bp->enabled) { + assert(n < leader->hw_bp_num); + + bp_list[n++] = bp; + } + } + + qsort(bp_list, n, sizeof(*bp_list), hw_bp_sort); + + for(i = 0; i < n; ++i) { + bp_list[i]->hwcnt = (i < HW_BREAKPOINTS - 1) ? BP_REORDER_THRESHOLD >> (i + 4) : 0; + } + + if (n > HW_BREAKPOINTS - 1) + n = HW_BREAKPOINTS - 1; + + p = bp_list; + for(i = 0; i < n; ++i) { + if (bp_list[i]->hw) { + assert(bp_list[i]->hw_bp_slot != HW_BP_SCRATCH_SLOT); + assert(bp_list[i]->hw_bp_slot < HW_BREAKPOINTS); + assert((hw_bp_set & 1 << bp_list[i]->hw_bp_slot) == 0); + + hw_bp_set |= 1 << bp_list[i]->hw_bp_slot; + } + else + *p++ = bp_list[i]; + } + *p = NULL; + + i = HW_BP_SCRATCH_SLOT + 1; + for(p = bp_list; (bp = *p); ++p) { + while(hw_bp_set & (1 << i)) + ++i; + + stop_threads(leader); + disable_sw_breakpoint(leader, bp); + + if (leader->hw_bp[i]) + hw2sw_bp(leader, leader->hw_bp[i]); + + bp->hw_bp_slot = i; + bp->hw = 1; + + each_task(leader, enable_hw_bp_cb, bp); + + ++i; + } +} + +static int insert_hw_bp_slot(struct task *task, struct breakpoint *bp) +{ + struct task *leader = task->leader; + unsigned int i; + + for(i = HW_BP_SCRATCH_SLOT + 1; i < HW_BREAKPOINTS; ++i) { + if (!leader->hw_bp[i]) + break; + + if (bp->type == BP_HW && leader->hw_bp[i]->type == BP_AUTO) { + stop_threads(leader); + hw2sw_bp(leader, leader->hw_bp[i]); + break; + } + } + + if (i >= HW_BREAKPOINTS) + return 1; + + bp->hwcnt = 0; + bp->enabled = 1; + bp->hw_bp_slot = i; + bp->hw = 1; + + each_task(leader, enable_hw_bp_cb, bp); + + return 0; +} + +void breakpoint_hw_clone(struct task *task) +{ + unsigned int i; + struct task *leader = task->leader; + + if (leader == task) + return; + + for(i = HW_BP_SCRATCH_SLOT + 1; i < HW_BREAKPOINTS; ++i) { + if (!leader->hw_bp[i]) { + assert(task->hw_bp[i] == NULL); + continue; + } + + assert(leader->hw_bp[i]->enabled); + assert(leader->hw_bp[i]->hw_bp_slot == i); + + enable_hw_bp(task, leader->hw_bp[i]); + } } void breakpoint_hw_destroy(struct task *task) { unsigned int i; - for(i = 0; i < HW_BREAKPOINTS; ++i) { - if (task->hw_bp[i]) { - assert(task->hw_bp[i]->hw_bp_slot == i); - - task->hw_bp[i] = NULL; - } - } + for(i = 0; i < HW_BREAKPOINTS; ++i) + task->hw_bp[i] = NULL; reset_all_hw_bp(task); } +#endif void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp) { if (bp->deleted) return; - if (bp->type == SW_BP) + if (bp->type != BP_HW_SCRATCH) return; assert(bp->hw_bp_slot == HW_BP_SCRATCH_SLOT); @@ -190,17 +298,12 @@ void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp) enable_hw_bp(task, bp); } -static void enable_hw_bp_cb(struct task *task, void *data) -{ - enable_hw_bp(task, data); -} - void disable_scratch_hw_bp(struct task *task, struct breakpoint *bp) { if (bp->deleted) return; - if (bp->type == SW_BP) + if (bp->type != BP_HW_SCRATCH) return; assert(bp->hw_bp_slot == HW_BP_SCRATCH_SLOT); @@ -208,11 +311,6 @@ void disable_scratch_hw_bp(struct task *task, struct breakpoint *bp) disable_hw_bp(task, bp); } -static void disable_hw_bp_cb(struct task *task, void *data) -{ - disable_hw_bp(task, data); -} - static void remove_hw_scratch_bp_cb(struct task *task, void *data) { if (task->hw_bp[HW_BP_SCRATCH_SLOT] == data) { @@ -239,29 +337,30 @@ struct breakpoint *breakpoint_new_ext(struct task *task, arch_addr_t addr, struc bp->deleted = 0; bp->ext = ext; bp->refcnt = 1; + bp->count = 0; +#if HW_BREAKPOINTS > 1 + bp->hwcnt = 0; +#endif + bp->type = bp_type; + + INIT_LIST_HEAD(&bp->link_list); switch(bp_type) { - case HW_BP_SCRATCH: + case BP_HW_SCRATCH: #if HW_BREAKPOINTS > 0 - bp->type = HW_BP_SCRATCH; bp->hw_bp_slot = HW_BP_SCRATCH_SLOT; + bp->hw = 1; break; #endif - case HW_BP: + case BP_AUTO: + case BP_HW: #if HW_BREAKPOINTS > 1 - { - int slot = find_hw_bp_slot(leader); - if (slot > 0) { - leader->hw_bp_mask |= (1 << slot); - bp->type = HW_BP; - bp->hw_bp_slot = slot; - break; - } - } + list_add_tail(&bp->link_list, &leader->hw_bp_list); + leader->hw_bp_num++; #endif - case SW_BP: - bp->type = SW_BP; + case BP_SW: memset(bp->orig_value, 0, sizeof(bp->orig_value)); + bp->hw = 0; } if (dict_add(leader->breakpoints, (unsigned long)addr, bp) < 0) { @@ -289,17 +388,21 @@ void breakpoint_enable(struct task *task, struct breakpoint *bp) debug(DEBUG_PROCESS, "pid=%d, addr=%#lx", task->pid, bp->addr); if (!bp->enabled) { - stop_threads(task); #if HW_BREAKPOINTS > 0 - if (bp->type != SW_BP) { - if (bp->type == HW_BP) - each_task(task->leader, enable_hw_bp_cb, bp); + if (bp->type == BP_HW_SCRATCH) { + bp->enabled = 1; + return; + } +#if HW_BREAKPOINTS > 1 + if (bp->type >= BP_HW) { + if (!insert_hw_bp_slot(task, bp)) + return; } - else #endif - { - enable_sw_breakpoint(task, bp); - } +#endif + stop_threads(task); + bp->hw = 0; + enable_sw_breakpoint(task, bp); bp->enabled = 1; } } @@ -312,19 +415,29 @@ void breakpoint_disable(struct task *task, struct breakpoint *bp) debug(DEBUG_PROCESS, "pid=%d, addr=%#lx", task->pid, bp->addr); if (bp->enabled) { - stop_threads(task); #if HW_BREAKPOINTS > 0 - if (bp->type != SW_BP) { - if (bp->type == HW_BP) - each_task(task->leader, disable_hw_bp_cb, bp); + if (bp->hw) { + struct task *leader = task->leader; +#if HW_BREAKPOINTS > 1 + if (bp->type != BP_HW_SCRATCH) { + assert(bp->hw_bp_slot != HW_BP_SCRATCH_SLOT); + + each_task(leader, disable_hw_bp_cb, bp); + bp->hw = 0; + } else - each_task(task->leader, remove_hw_scratch_bp_cb, bp); - } - else #endif - { - disable_sw_breakpoint(task, bp); + { + assert(bp->hw_bp_slot == HW_BP_SCRATCH_SLOT); + + each_task(leader, remove_hw_scratch_bp_cb, bp); + } + bp->enabled = 0; + return; } +#endif + stop_threads(task); + disable_sw_breakpoint(task, bp); bp->enabled = 0; } } @@ -359,24 +472,29 @@ void breakpoint_delete(struct task *task, struct breakpoint *bp) breakpoint_disable(task, bp); -#if HW_BREAKPOINTS > 0 - if (bp->type != SW_BP) { - unsigned int slot = bp->hw_bp_slot; +#if HW_BREAKPOINTS > 1 + if (bp->type >= BP_HW) { + list_del(&bp->link_list); - if (bp->type == HW_BP) { - assert(slot != HW_BP_SCRATCH_SLOT); - - leader->hw_bp_mask &= ~(1 << slot); - } - else - assert(slot == HW_BP_SCRATCH_SLOT); + leader->hw_bp_num--; } #endif - bp->deleted = 1; - dict_remove_entry(leader->breakpoints, (unsigned long)bp->addr); - breakpoint_unref(bp); + if (options.verbose > 1 && bp->libsym) { + fprintf(stderr, + "delete %s breakpoint %s:%s [%#lx] count=%u\n", + bp->type == BP_SW ? "sw" : "hw", + bp->libsym->libref->filename, + bp->libsym->func->demangled_name, + bp->addr, + bp->count); + } + + bp->deleted = 1; + bp->libsym = NULL; + + breakpoint_put(bp); } static int enable_nonlocked_bp_cb(unsigned long key, const void *value, void *data) @@ -419,6 +537,7 @@ void breakpoint_disable_all_nonlocked(struct task *leader) if (leader->breakpoints) dict_apply_to_all(leader->breakpoints, disable_nonlocked_bp_cb, leader); + leader->attached = 1; } static int enable_bp_cb(unsigned long key, const void *value, void *data) @@ -459,11 +578,15 @@ void breakpoint_disable_all(struct task *leader) if (leader->breakpoints) dict_apply_to_all(leader->breakpoints, disable_bp_cb, leader); + leader->attached = 1; } static int destroy_breakpoint_cb(unsigned long key, const void *value, void *data) { - free((struct breakpoint *)value); + struct breakpoint *bp = (struct breakpoint *)value; + struct task *leader = (struct task *)data; + + breakpoint_delete(leader, bp); return 0; } @@ -471,6 +594,7 @@ void breakpoint_clear_all(struct task *leader) { if (leader->breakpoints) { dict_apply_to_all(leader->breakpoints, &destroy_breakpoint_cb, leader); + assert(leader->hw_bp_num == 0); dict_clear(leader->breakpoints); leader->breakpoints = NULL; } @@ -487,49 +611,66 @@ static int clone_single_cb(unsigned long key, const void *value, void *data) { struct breakpoint *bp = (struct breakpoint *)value; struct task *new_task = (struct task *)data; - struct library_symbol *libsym = bp->libsym ? find_symbol(new_task, bp->libsym->addr) : NULL; size_t ext = bp->ext; if (bp->deleted) return 0; +#if HW_BREAKPOINTS > 0 + if (bp->type == BP_HW_SCRATCH) { + assert(bp->hw_bp_slot == HW_BP_SCRATCH_SLOT); + + if (bp->hw) + return 0; + } +#endif + struct breakpoint *new_bp = malloc(sizeof(*new_bp) + ext); if (!new_bp) goto fail1; - new_bp->libsym = libsym; + new_bp->libsym = bp->libsym; new_bp->addr = bp->addr; new_bp->on_hit = bp->on_hit; new_bp->enabled = bp->enabled; new_bp->locked = bp->locked; + new_bp->hw = bp->hw; new_bp->type = bp->type; new_bp->ext = ext; + new_bp->refcnt = 1; + new_bp->deleted = 0; + new_bp->count = 0; -#if HW_BREAKPOINTS > 0 - if (new_bp->type != SW_BP) { +#if HW_BREAKPOINTS > 1 + new_bp->hwcnt = 0; + + if (new_bp->type >= BP_HW) { + list_add_tail(&new_bp->link_list, &new_task->hw_bp_list); + new_task->hw_bp_num++; + } + else + INIT_LIST_HEAD(&new_bp->link_list); + + if (new_bp->hw) { new_bp->hw_bp_slot = bp->hw_bp_slot; - if (bp->type == HW_BP) { - assert(new_bp->hw_bp_slot != HW_BP_SCRATCH_SLOT); + assert(new_bp->hw_bp_slot != HW_BP_SCRATCH_SLOT); - new_task->hw_bp[new_bp->hw_bp_slot] = new_bp; + new_task->hw_bp[new_bp->hw_bp_slot] = new_bp; - if (new_bp->enabled) { - if (set_hw_bp(new_task, new_bp->hw_bp_slot, new_bp->addr) == -1) - fatal("set_hw_bp"); - } + if (new_bp->enabled) { + if (set_hw_bp(new_task, new_bp->hw_bp_slot, new_bp->addr) == -1) + fatal("set_hw_bp"); } - else - assert(new_bp->hw_bp_slot == HW_BP_SCRATCH_SLOT); } else #endif - memcpy(new_bp->orig_value, bp->orig_value, sizeof(bp->orig_value)); + memcpy(new_bp->orig_value, bp->orig_value, sizeof(bp->orig_value)); if (ext) memcpy((void *)new_bp + ext, (void *)bp + ext, ext); - if (dict_add(new_task->leader->breakpoints, (unsigned long)new_bp->addr, new_bp) < 0) { + if (dict_add(new_task->breakpoints, (unsigned long)new_bp->addr, new_bp) < 0) { fprintf(stderr, "couldn't enter breakpoint %lx to dictionary\n", new_bp->addr); goto fail2; } @@ -546,3 +687,23 @@ int breakpoint_clone_all(struct task *clone, struct task *leader) return dict_apply_to_all(leader->breakpoints, &clone_single_cb, clone); } +struct breakpoint *breakpoint_get(struct breakpoint *bp) +{ + if (bp) + ++bp->refcnt; + return bp; +} + +int breakpoint_put(struct breakpoint *bp) +{ + if (bp) { + assert(bp->refcnt != 0); + + if (--bp->refcnt) + return 0; + + free(bp); + } + return 1; +} + diff --git a/breakpoint.h b/breakpoint.h index 2acd3e8..a9674e7 100644 --- a/breakpoint.h +++ b/breakpoint.h @@ -26,34 +26,42 @@ #include +#include "arch.h" +#include "list.h" #include "sysdep.h" #include "forward.h" -#define SW_BP 0 -#define HW_BP 1 -#define HW_BP_SCRATCH 2 +#define BP_REORDER_THRESHOLD 1024U + +#define BP_SW 0 +#define BP_HW_SCRATCH 1 +#define BP_HW 2 +#define BP_AUTO 3 struct breakpoint { - arch_addr_t addr; +#if HW_BREAKPOINTS > 1 + unsigned int hwcnt; +#endif + unsigned int refcnt; + unsigned int count; + unsigned int ext:8; + unsigned int type:2; unsigned int enabled:1; unsigned int locked:1; unsigned int deleted:1; - unsigned int type:2; - unsigned int ext:8; - - unsigned int refcnt; - - int (*on_hit)(struct task *task, struct breakpoint *bp); - - struct library_symbol *libsym; - + unsigned int hw:1; union { unsigned char orig_value[BREAKPOINT_LENGTH]; #if HW_BREAKPOINTS > 0 unsigned int hw_bp_slot; #endif }; + + int (*on_hit)(struct task *task, struct breakpoint *bp); + arch_addr_t addr; + struct library_symbol *libsym; + struct list_head link_list; }; /* setup the basic breakpoint support for a given leader */ @@ -92,9 +100,6 @@ struct breakpoint *breakpoint_find(struct task *leader, arch_addr_t addr); #if HW_BREAKPOINTS > 0 void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp); void disable_scratch_hw_bp(struct task *task, struct breakpoint *bp); - -void breakpoint_hw_clone(struct task *task); -void breakpoint_hw_destroy(struct task *task); #else static inline void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp) { @@ -103,7 +108,14 @@ static inline void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp static inline void disable_scratch_hw_bp(struct task *task, struct breakpoint *bp) { } +#endif +#if HW_BREAKPOINTS > 1 +void reorder_hw_bp(struct task *task); + +void breakpoint_hw_clone(struct task *task); +void breakpoint_hw_destroy(struct task *task); +#else static inline void breakpoint_hw_clone(struct task *task) { } @@ -113,22 +125,9 @@ static inline void breakpoint_hw_destroy(struct task *task) } #endif -static inline struct breakpoint *breakpoint_ref(struct breakpoint *bp) -{ - if (bp) - ++bp->refcnt; - return bp; -} +struct breakpoint *breakpoint_get(struct breakpoint *bp); -static inline int breakpoint_unref(struct breakpoint *bp) -{ - if (bp) { - if (--bp->refcnt) - return 0; - free(bp); - } - return 1; -} +int breakpoint_put(struct breakpoint *bp); #endif diff --git a/client/binfile.c b/client/binfile.c index 94e216d..3d47394 100644 --- a/client/binfile.c +++ b/client/binfile.c @@ -25,10 +25,13 @@ #include #include #include +#include #include "binfile.h" #include "process.h" +static LIST_HEAD(list_of_binfiles); + /* These variables are used to pass information between translate_addresses and find_address_in_section. */ struct sym_info { @@ -50,7 +53,7 @@ static long slurp_symtab(struct bin_file *binfile) return 0; storage = bfd_get_symtab_upper_bound(binfile->abfd); - if (storage == 0) { + if (!storage) { storage = bfd_get_dynamic_symtab_upper_bound(binfile->abfd); dynamic = TRUE; } @@ -98,19 +101,34 @@ static void find_address_in_section(bfd *abfd, asection *section, void *data __a psi->found = bfd_find_nearest_line(abfd, section, psi->syms, psi->pc - vma, &psi->filename, &psi->functionname, &psi->line); } -char *bin_file_lookup(struct bin_file *binfile, bfd_vma addr, unsigned long off) +struct rb_sym *bin_file_lookup(struct bin_file *binfile, bfd_vma addr, unsigned long off, const char *filename) { struct sym_info si = { 0 }; - char *ret_buf = NULL; + char *sym_buf = NULL; + struct rb_root *root = &binfile->sym_table; + struct rb_node **new = &(root->rb_node), *parent = NULL; + struct rb_sym *this; if (!binfile) return NULL; - if (!binfile->abfd) - return NULL; + /* Figure out where to put new node */ + while (*new) { + this = container_of(*new, struct rb_sym, node); - if (!binfile->syms) - return NULL; + parent = *new; + + if (addr < this->addr) + new = &((*new)->rb_left); + else + if (addr > this->addr) + new = &((*new)->rb_right); + else { + bin_file_sym_get(this); + + return this; + } + } si.pc = (binfile->abfd->flags & EXEC_P) ? addr : addr - off; si.syms = binfile->syms; @@ -120,8 +138,8 @@ char *bin_file_lookup(struct bin_file *binfile, bfd_vma addr, unsigned long off) bfd_map_over_sections(binfile->abfd, find_address_in_section, &si); if (!si.found) { - if (asprintf(&ret_buf, "%s", bfd_get_filename(binfile->abfd)) == -1) - ret_buf = NULL; + if (asprintf(&sym_buf, "%s", filename) == -1) + sym_buf = NULL; } else { const char *name; @@ -141,16 +159,16 @@ char *bin_file_lookup(struct bin_file *binfile, bfd_vma addr, unsigned long off) name = alloc; } - if (ret_buf) - free(ret_buf); + if (sym_buf) + free(sym_buf); if (si.line) { - if (asprintf(&ret_buf, "%s:%u %s", si.filename ? si.filename : bfd_get_filename(binfile->abfd), si.line, name) == -1) - ret_buf = NULL; + if (asprintf(&sym_buf, "%s:%u %s", si.filename ? si.filename : filename, si.line, name) == -1) + sym_buf = NULL; } else { - if (asprintf(&ret_buf, "%s %s", si.filename ? si.filename : bfd_get_filename(binfile->abfd), name) == -1) - ret_buf = NULL; + if (asprintf(&sym_buf, "%s %s", si.filename ? si.filename : filename, name) == -1) + sym_buf = NULL; } if (alloc) @@ -160,72 +178,119 @@ char *bin_file_lookup(struct bin_file *binfile, bfd_vma addr, unsigned long off) } while (si.found); } - return ret_buf; + this = malloc(sizeof(*this)); + if (!this) + return NULL; + + this->addr = addr; + this->sym = sym_buf; + this->refcnt = 1; + this->binfile = binfile; + + ++binfile->refcnt; + + /* Add new node and rebalance tree. */ + rb_link_node(&this->node, parent, new); + rb_insert_color(&this->node, root); + + return this; } -struct bin_file *bin_file_new(const char *filename) +struct bin_file *bin_file_open(const char *filename) { - bfd *abfd; char **matching; struct bin_file *binfile; + struct list_head *it; if (!filename) return NULL; + list_for_each(it, &list_of_binfiles) { + binfile = container_of(it, struct bin_file, list); + + if (!strcmp(filename, binfile->filename)) { + bin_file_get(binfile); + return binfile; + } + } + binfile = malloc(sizeof(struct bin_file)); if (!binfile) return NULL; - abfd = bfd_openr(filename, NULL); - if (!abfd) + binfile->filename = strdup(filename); + binfile->refcnt = 1; + binfile->sym_table = RB_ROOT; + binfile->abfd = bfd_openr(binfile->filename, NULL); + + if (!binfile->abfd) goto error; - /* Decompress sections. */ -// abfd->flags |= BFD_DECOMPRESS; - - if (bfd_check_format(abfd, bfd_archive)) + if (bfd_check_format(binfile->abfd, bfd_archive)) goto error; - if (!bfd_check_format_matches(abfd, bfd_object, &matching)) + if (!bfd_check_format_matches(binfile->abfd, bfd_object, &matching)) goto error; - binfile->abfd = abfd; - if (slurp_symtab(binfile) <= 0) goto error; - binfile->refcnt = 1; + list_add_tail(&binfile->list, &list_of_binfiles); return binfile; error: - if (abfd) - bfd_close(abfd); + if (binfile->abfd) + bfd_close(binfile->abfd); + free(binfile->filename); free(binfile); return NULL; } -struct bin_file *bin_file_clone(struct bin_file *binfile) +void bin_file_get(struct bin_file *binfile) { - if (!binfile) - return NULL; - - binfile->refcnt++; - - return binfile; + ++binfile->refcnt; } -void bin_file_free(struct bin_file *binfile) +void bin_file_put(struct bin_file *binfile) { if (!binfile) return; - if (--binfile->refcnt > 0) - return; + if (!--binfile->refcnt) { + list_del(&binfile->list); - if (binfile->syms) - free(binfile->syms); + if (binfile->syms) + free(binfile->syms); - if (binfile->abfd) - bfd_close(binfile->abfd); + if (binfile->abfd) + bfd_close(binfile->abfd); + + free(binfile->filename); + free(binfile); + } } + +void bin_file_sym_get(struct rb_sym *sym) +{ + struct bin_file *binfile = sym->binfile; + + ++sym->refcnt; + ++binfile->refcnt; +} + +void bin_file_sym_put(struct rb_sym *sym) +{ + struct bin_file *binfile = sym->binfile; + + if (!--sym->refcnt) { + free(sym->sym); + + if (!binfile) + return; + + rb_erase(&sym->node, &binfile->sym_table); + } + bin_file_put(binfile); +} + diff --git a/client/binfile.h b/client/binfile.h index df680bb..7f3645a 100644 --- a/client/binfile.h +++ b/client/binfile.h @@ -24,16 +24,31 @@ #define _INC_CLIENT_BINFILE_H #include "bfdinc.h" +#include "list.h" +#include "rbtree.h" -struct bin_file { - bfd *abfd; - asymbol **syms; - unsigned int refcnt; +struct rb_sym { + struct rb_node node; + bfd_vma addr; + char *sym; + struct bin_file *binfile; + unsigned long refcnt; }; -struct bin_file *bin_file_new(const char *filename); -struct bin_file *bin_file_clone(struct bin_file *binfile); -void bin_file_free(struct bin_file *binfile); -char *bin_file_lookup(struct bin_file *binfile, bfd_vma addr, unsigned long off); +struct bin_file { + struct list_head list; + bfd *abfd; + asymbol **syms; + struct rb_root sym_table; + unsigned long refcnt; + char *filename; +}; + +struct bin_file *bin_file_open(const char *filename); +void bin_file_put(struct bin_file *binfile); +void bin_file_get(struct bin_file *binfile); +struct rb_sym *bin_file_lookup(struct bin_file *binfile, bfd_vma addr, unsigned long off, const char *filename); +void bin_file_sym_get(struct rb_sym *sym); +void bin_file_sym_put(struct rb_sym *sym); #endif diff --git a/client/client.c b/client/client.c index 2470e5a..db15c68 100644 --- a/client/client.c +++ b/client/client.c @@ -306,6 +306,7 @@ static int socket_read_msg(struct mt_msg *mt_msg, void **payload, unsigned int * else *swap_endian = 0; + if (mt_msg->payload_len) { *payload = malloc(mt_msg->payload_len); @@ -333,8 +334,10 @@ static unsigned int attached_payload(void *payload) void client_close(void) { if (client_fd != -1) { - ioevent_del_input(client_fd); - shutdown(client_fd, SHUT_RDWR); + if (thread) { + ioevent_del_input(client_fd); + shutdown(client_fd, SHUT_RDWR); + } close(client_fd); client_fd = -1; } @@ -343,11 +346,29 @@ void client_close(void) static void client_broken(void) { if (client_fd != -1) { - fprintf(stderr, "connection lost\n"); + if (!options.logfile) + fprintf(stderr, "connection lost\n"); + client_close(); } } +static void client_add_process(struct process *process) +{ + if (!first_pid) + first_pid = process->pid; + + process_rb_insert(&pid_table, process); +} + +static void client_remove_process(struct process *process) +{ + process = pid_rb_delete(&pid_table, process->pid); + + if (process) + free(process); +} + static int client_func(void) { struct mt_msg mt_msg; @@ -365,7 +386,10 @@ static int client_func(void) switch(mt_msg.operation) { case MT_DISCONNECT: - sock_send_msg(client_fd, MT_DISCONNECT, 0, 0, NULL, 0); + if (!options.trace && !options.logfile) { + printf("server disconnected\n"); + fflush(stdout); + } client_close(); break; case MT_INFO: @@ -433,7 +457,8 @@ static int client_func(void) process_exit(process); break; case MT_NOFOLLOW: - process_delete(process); + process_reset(process); + client_remove_process(process); break; case MT_SCAN: process_scan(process, payload, mt_msg.payload_len); @@ -470,6 +495,9 @@ void client_show_info(void) int client_wait_op(enum mt_operation op) { + if (options.logfile) + return -1; + for(;;) { if (client_fd == -1) return -1; @@ -483,22 +511,6 @@ int client_wait_op(enum mt_operation op) return 0; } -static int client_release_process(struct rb_node *node, void *user) -{ - struct rb_process *data = (struct rb_process *)node; - - process_delete(data->process); - free(data); - return 0; -} - -void client_finalize() -{ - client_close(); - - rb_iterate(&pid_table, client_release_process, NULL); -} - static int client_iterate_process(struct rb_node *node, void *user) { struct rb_process *data = (struct rb_process *)node; @@ -529,23 +541,6 @@ struct process *client_first_process(void) return client_find_process(first_pid); } -void client_add_process(struct process *process) -{ - if (!first_pid) - first_pid = process->pid; - - process_rb_insert(&pid_table, process); -} - -void client_remove_process(struct process *process) -{ - process = pid_rb_delete(&pid_table, process->pid); - - if (process) - free(process); -} - - static int client_init(int do_trace) { struct opt_F_t *p; @@ -602,14 +597,17 @@ int client_start(void) if (client_init(0) < 0) return -1; - client_fd = connect_to(options.client, options.port); + client_fd = connect_to(options.address, options.port); if (client_fd == -1) { - fprintf(stderr, "could not connect: %s:%s\n", options.client, options.port); + fprintf(stderr, "could not connect: %s\n", options.address); return -1; } - client_wait_op(MT_INFO); + if (client_wait_op(MT_INFO) == -1) { + fprintf(stderr, "could not talk to server\n"); + return -1; + } if (mt_info.version != MEMTRACE_SI_VERSION) { fprintf(stderr, @@ -626,6 +624,8 @@ int client_start(void) ioevent_add_input(client_fd, client_func); if (options.interactive) { + int old_client_fd = client_fd; + signal(SIGINT, SIG_IGN); signal(SIGTERM, SIG_IGN); @@ -634,6 +634,13 @@ int client_start(void) while(ioevent_watch(-1) != -1) ; + if (client_fd == -1) { + ioevent_del_input(old_client_fd); + + while(ioevent_watch(-1) != -1) + ; + } + readline_exit(); } else { @@ -697,7 +704,12 @@ int client_start_pair(int handle) int client_send_msg(struct process *process, enum mt_operation op, void *payload, unsigned int payload_len) { - int ret = sock_send_msg(client_fd, process->val16(op), process->pid, 0, payload, payload_len); + int ret; + + if (options.logfile) + return -1; + + ret = sock_send_msg(client_fd, process->val16(op), process->pid, 0, payload, payload_len); if (ret < 0) client_broken(); @@ -709,16 +721,63 @@ int client_connected(void) if (client_fd != -1) return 1; - printf("connection lost\n"); - return 0; } int client_stop(void) { - if (thread) + if (thread) { thread_join(thread); + thread = NULL; + } + client_close(); return 0; } +int client_logfile(void) +{ + const char spin[4] = "|/-\\"; + unsigned int i; + const unsigned int spindepth = 14; + + thread = NULL; + + if (client_init(1) < 0) + return -1; + + client_fd = open(options.logfile, O_RDONLY); + if (client_fd == -1) + fatal("could not open logfile: %s", options.logfile); + + printf("processing logfile `%s'... ", options.logfile); + fflush(stdout); + + for(i = 0; client_fd != -1; ++i) { + if ((i & ((1 << spindepth) - 1)) == 0) { + printf("\b%c", spin[(i >> spindepth) & (ARRAY_SIZE(spin) - 1)]); + fflush(stdout); + } + client_func(); + } + + printf("\bdone\n"); + fflush(stdout); + + if (options.interactive) { + client_show_info(); + + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + + readline_init(); + + while(ioevent_watch(-1) != -1) + ; + + readline_exit(); + } + + return 0; +} + diff --git a/client/client.h b/client/client.h index e6dbd05..0697d1b 100644 --- a/client/client.h +++ b/client/client.h @@ -27,13 +27,9 @@ struct process; -void client_finalize(); - struct process *client_first_process(void); struct process *client_find_process(pid_t pid); void client_iterate_processes(int (*func)(struct process *process)); -void client_add_process(struct process *process); -void client_remove_process(struct process *process); void client_show_info(void); int client_wait_op(enum mt_operation op); void client_close(void); @@ -42,6 +38,7 @@ int client_connected(void); int client_start(void); int client_start_pair(int handle); int client_stop(void); +int client_logfile(void); #endif diff --git a/client/process.c b/client/process.c index 03d3fe1..1fa56ec 100644 --- a/client/process.c +++ b/client/process.c @@ -56,7 +56,7 @@ struct stack { void *addrs; uint32_t size; uint32_t entries; - char **syms; + struct rb_sym **syms; enum mt_operation operation; unsigned int ignore:1; }; @@ -78,7 +78,6 @@ struct map { unsigned long addr; unsigned long size; char *filename; - char *realpath; struct bin_file *binfile; unsigned int ignore:1; }; @@ -284,7 +283,6 @@ static struct map *open_map(struct process *process, bfd_vma addr) return map; p = options.opt_b; - if (!p) p = &opt_b_default; @@ -294,53 +292,54 @@ static struct map *open_map(struct process *process, bfd_vma addr) while(len && (p->pathname)[len - 1] == '/') --len; - for(fname = map->filename; *fname == '/'; ++fname) - ; + fname = map->filename; do { - if (asprintf(&realpath, "%.*s/%s", len, p->pathname, fname) == -1) { + if (asprintf(&realpath, "%.*s%s%s", len, p->pathname, *p->pathname ? "/" : "", fname) == -1) { map->ignore = 1; return map; } - if (!access(realpath, R_OK)) { - map->binfile = bin_file_new(realpath); - - if (map->binfile) { - map->realpath = realpath; - return map; - } - } + if (!access(realpath, R_OK)) + map->binfile = bin_file_open(realpath); free(realpath); + if (map->binfile) + return map; + fname = strchr(fname + 1, '/'); } while(fname++); p = p->next; } while(p); + fprintf(stderr, "file `%s' not found!\n", map->filename); + map->ignore = 1; + return map; } -static char *resolv_address(struct process *process, bfd_vma addr) +static struct rb_sym *resolv_address(struct process *process, bfd_vma addr) { - char *sym; + struct rb_sym *sym; struct map *map = open_map(process, addr); if (!map) return NULL; - if (map->binfile) { - sym = bin_file_lookup(map->binfile, addr, map->addr); - if (sym) - return sym; + sym = bin_file_lookup(map->binfile, addr, map->addr, map->filename); + if (!sym) { + sym = malloc(sizeof(*sym)); + if (!sym) + return NULL; + + sym->addr = addr; + sym->sym = strdup(map->filename); + sym->refcnt = 1; + sym->binfile = NULL; } - - if (asprintf(&sym, "%s", map->filename) == -1) - return NULL; - return sym; } @@ -368,7 +367,7 @@ static void stack_resolv(struct process *process, struct stack *stack) struct regex_list *p; for(p = regex_ignore_list; p; p = p->next) - if (stack->syms[i] && !regexec(&p->re, stack->syms[i], 0, NULL, 0)) { + if (stack->syms[i] && !regexec(&p->re, stack->syms[i]->sym, 0, NULL, 0)) { stack->ignore = 1; break; } @@ -379,14 +378,14 @@ static void stack_resolv(struct process *process, struct stack *stack) } } -static void stack_unref(struct stack *stack) +static void stack_put(struct stack *stack) { if (--stack->refcnt == 0) { if (stack->syms) { unsigned int i; for(i = 0; i < stack->entries; ++i) - free(stack->syms[i]); + bin_file_sym_put(stack->syms[i]); free(stack->syms); } @@ -459,8 +458,11 @@ static struct rb_stack *stack_add(struct process *process, pid_t pid, void *addr else if (ret > 0) new = &((*new)->rb_right); - else + else { + assert(this->stack->operation == operation); + return this; + } } this = malloc(sizeof(*this)); @@ -511,7 +513,7 @@ static void process_dump_stack(struct process *process, struct rb_stack *this) return; for(addrs = stack->addrs, i = 0; i < stack->entries; ++i) { - if (dump_printf(" [0x%lx] %s\n", process->get_ulong(addrs), stack->syms[i] ? stack->syms[i] : "?") == -1) + if (dump_printf(" [0x%lx] %s\n", process->get_ulong(addrs), stack->syms[i] ? stack->syms[i]->sym : "?") == -1) return; addrs += process->ptr_size; @@ -648,7 +650,7 @@ static int process_rb_insert_block(struct process *process, unsigned long addr, return 0; } -static struct map *_process_add_map(struct process *process, unsigned long addr, unsigned long offset, unsigned long size, const char *filename, size_t len) +static struct map *_process_add_map(struct process *process, unsigned long addr, unsigned long offset, unsigned long size, const char *filename, size_t len, struct bin_file *binfile) { struct map *map = malloc(sizeof(*map)); @@ -656,10 +658,12 @@ static struct map *_process_add_map(struct process *process, unsigned long addr, map->offset = offset; map->size = size; map->filename = malloc(len + 1); - map->realpath = NULL; - map->binfile = NULL; + map->binfile = binfile; map->ignore = 0; + if (binfile) + bin_file_get(binfile); + safe_strncpy(map->filename, filename, len + 1); if (list_empty(&process->map_list)) { @@ -669,7 +673,7 @@ static struct map *_process_add_map(struct process *process, unsigned long addr, list_add_tail(&map->list, &process->map_list); - /* fixit: stack_add() can produce now false matches */ + /* fixit: it is possible that stack_add() can produce false matches */ return map; } @@ -682,18 +686,16 @@ void process_add_map(struct process *process, void *payload, uint32_t payload_le uint64_t offset = process->val64(mt_map->offset); uint64_t size = process->val64(mt_map->size); - _process_add_map(process, addr, offset, size, mt_map->filename, payload_len - sizeof(*mt_map)); + _process_add_map(process, addr, offset, size, mt_map->filename, payload_len - sizeof(*mt_map), NULL); } static void _process_del_map(struct map *map) { - bin_file_free(map->binfile); + bin_file_put(map->binfile); list_del(&map->list); free(map->filename); - free(map->realpath); - free(map->binfile); free(map); } @@ -752,7 +754,7 @@ void process_reset_allocations(struct process *process) process->block_table = RB_ROOT; rbtree_postorder_for_each_entry_safe(rbs, rbs_next, &process->stack_table, node) { - stack_unref(rbs->stack); + stack_put(rbs->stack); free(rbs); } process->stack_table = RB_ROOT; @@ -765,7 +767,7 @@ void process_reset_allocations(struct process *process) process->tsc = 0; } -static void process_reset(struct process *process) +void process_reset(struct process *process) { struct list_head *it, *next; @@ -808,10 +810,13 @@ void process_duplicate(struct process *process, struct process *copy) rb_iterate(©->block_table, process_rb_duplicate_block, process); + assert(copy->bytes_used == process->bytes_used); + assert(copy->n_allocations == process->n_allocations); + list_for_each(it, ©->map_list) { struct map *map = container_of(it, struct map, list); - _process_add_map(process, map->addr, map->offset, map->size, map->filename, strlen(map->filename)); + _process_add_map(process, map->addr, map->offset, map->size, map->filename, strlen(map->filename), map->binfile); } process->total_allocations = copy->total_allocations; @@ -916,7 +921,7 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb assert(i == process->stack_trees); - qsort(arr, process->stack_trees, sizeof(struct stack *), (void *)sortby); + qsort(arr, process->stack_trees, sizeof(struct rb_stack *), (void *)sortby); if (file == stderr) { unsigned long n = process->stack_trees / 2; @@ -933,7 +938,7 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb for(i = 0; i < process->stack_trees; ++i) { struct rb_stack *stack = arr[i]; - if (!stack->stack->ignore && !skipfunc(stack)) { + if (!skipfunc(stack)) { if (dump_printf( "Stack (%s):\n" " bytes used: %llu\n" @@ -1232,7 +1237,7 @@ void process_alloc(struct process *process, struct mt_msg *mt_msg, void *payload { struct rb_block *block = NULL; uint32_t payload_len = mt_msg->payload_len; - unsigned long *stack_data; + void *stack_data; unsigned long stack_size; unsigned long ptr; unsigned long size; @@ -1343,11 +1348,10 @@ void process_exit(struct process *process) { process_set_status(process, MT_PROCESS_EXIT); - if (options.client || (!options.client && !options.verbose)) - fprintf(stderr, "+++ process %d exited +++\n", process->pid); - if (!options.interactive) process_dump_sortby(process); + else + fprintf(stderr, "+++ process %d exited +++\n", process->pid); } void process_about_exit(struct process *process) @@ -1373,12 +1377,6 @@ void process_detach(struct process *process) client_send_msg(process, MT_DETACH, NULL, 0); } -void process_delete(struct process *process) -{ - process_reset(process); - free(process); -} - void process_set_status(struct process *process, enum process_status status) { process->status = status; @@ -1457,6 +1455,9 @@ static void set_block(struct rb_block *block, void *data) struct block_helper *bh = data; unsigned long addr; + if (block->stack_node->stack->ignore) + return; + if ((block->flags & bh->fmask) != 0) return; diff --git a/client/process.h b/client/process.h index c2bb5e2..a1ac11b 100644 --- a/client/process.h +++ b/client/process.h @@ -78,11 +78,11 @@ struct process { }; struct process *process_new(pid_t pid, unsigned int swap_endian, unsigned int tracing); +void process_reset(struct process *process); void process_reset_allocations(struct process *process); void process_reinit(struct process *process, unsigned int swap_endian, unsigned int is_64bit, unsigned int attached); void process_set_clone(struct process *process, struct process *clone); struct process *process_clone_of(struct process *process); -void process_delete(struct process *process); void process_duplicate(struct process *process, struct process *copy); void process_run(struct process *process, const char *libpath, const char *path, char **args); void process_set_status(struct process *process, enum process_status status); diff --git a/client/readline.c b/client/readline.c index 404d7bc..985b66b 100644 --- a/client/readline.c +++ b/client/readline.c @@ -437,10 +437,12 @@ finish: free(argv); free(linedup); + if (quit) + rl_callback_handler_remove(); + return; } - static void split_search_patch(const char *str) { struct opt_b_t *opt_b_last = NULL; @@ -870,6 +872,7 @@ void readline_init(void) void readline_exit(void) { - rl_callback_handler_remove(); + if (!quit) + rl_callback_handler_remove(); } diff --git a/config.h.in b/config.h.in index 0f9039b..ee0062b 100644 --- a/config.h.in +++ b/config.h.in @@ -75,6 +75,9 @@ /* Define to 1 if you have the `mkdir' function. */ #undef HAVE_MKDIR +/* Define to 1 if you have the `process_vm_readv' function. */ +#undef HAVE_PROCESS_VM_READV + /* Define to 1 if you have the header file. */ #undef HAVE_PTHREAD_H diff --git a/config/autoconf/config.guess b/config/autoconf/config.guess index 8a5d3f4..17a4f70 100755 --- a/config/autoconf/config.guess +++ b/config/autoconf/config.guess @@ -2,7 +2,7 @@ # Attempt to guess a canonical system name. # Copyright 1992-2015 Free Software Foundation, Inc. -timestamp='2015-03-04' +timestamp='2015-07-03' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -221,7 +221,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in release='-gnu' ;; *) - release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: @@ -1049,7 +1049,7 @@ EOF X86_64_ABI=x32 fi fi - echo x86_64-unknown-linux-gnu${X86_64_ABI} + echo ${UNAME_MACHINE}-pc-linux-${LIBC}${X86_64_ABI} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} diff --git a/config/autoconf/config.sub b/config/autoconf/config.sub index 430106a..afdef26 100755 --- a/config/autoconf/config.sub +++ b/config/autoconf/config.sub @@ -2,7 +2,7 @@ # Configuration validation subroutine script. # Copyright 1992-2015 Free Software Foundation, Inc. -timestamp='2015-03-08' +timestamp='2015-07-28' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -255,6 +255,7 @@ case $basic_machine in | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ + | ba \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ @@ -376,6 +377,7 @@ case $basic_machine in | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ + | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ @@ -428,12 +430,13 @@ case $basic_machine in | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ + | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ diff --git a/configure b/configure index 4e50b69..0400466 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for mtrace 0.1. +# Generated by GNU Autoconf 2.69 for mtrace 0.2. # # Report bugs to . # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='mtrace' PACKAGE_TARNAME='mtrace' -PACKAGE_VERSION='0.1' -PACKAGE_STRING='mtrace 0.1' +PACKAGE_VERSION='0.2' +PACKAGE_STRING='mtrace 0.2' PACKAGE_BUGREPORT='stefani@seibold.net' PACKAGE_URL='' @@ -1326,7 +1326,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures mtrace 0.1 to adapt to many kinds of systems. +\`configure' configures mtrace 0.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1396,7 +1396,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of mtrace 0.1:";; + short | recursive ) echo "Configuration of mtrace 0.2:";; esac cat <<\_ACEOF @@ -1512,7 +1512,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -mtrace configure 0.1 +mtrace configure 0.2 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2118,7 +2118,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by mtrace $as_me 0.1, which was +It was created by mtrace $as_me 0.2, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -12000,7 +12000,7 @@ fi # Define the identity of the package. PACKAGE='mtrace' - VERSION='0.1' + VERSION='0.2' cat >>confdefs.h <<_ACEOF @@ -12746,6 +12746,8 @@ else $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CPPFLAGS="${saved_CPPFLAGS}" +LDFLAGS="${saved_LDFLAGS}" saved_CFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -Wall -Werror" @@ -13206,6 +13208,7 @@ for ac_func in \ strerror \ strtol \ strtoul \ + process_vm_readv \ do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` @@ -13799,7 +13802,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by mtrace $as_me 0.1, which was +This file was extended by mtrace $as_me 0.2, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13865,7 +13868,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -mtrace config.status 0.1 +mtrace config.status 0.2 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 8d55151..305c9f3 100644 --- a/configure.ac +++ b/configure.ac @@ -24,7 +24,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.65) -AC_INIT([mtrace],[0.1],[stefani@seibold.net]) +AC_INIT([mtrace],[0.2],[stefani@seibold.net]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_SRCDIR(main.c) AC_CONFIG_MACRO_DIR([config/m4]) @@ -152,6 +152,8 @@ int main () { AC_DEFINE([HAVE_ELF_C_READ_MMAP], [1], [we have read mmap support]) AC_MSG_RESULT([yes])],[ AC_MSG_RESULT([no])]) +CPPFLAGS="${saved_CPPFLAGS}" +LDFLAGS="${saved_LDFLAGS}" saved_CFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -Wall -Werror" @@ -214,6 +216,7 @@ AC_CHECK_FUNCS([ \ strerror \ strtol \ strtoul \ + process_vm_readv \ ]) diff --git a/dwarf.c b/dwarf.c index 5960ed3..a1b7440 100644 --- a/dwarf.c +++ b/dwarf.c @@ -470,7 +470,7 @@ static int dwarf_read_encoded_pointer(struct dwarf_addr_space *as, int local, { struct dwarf_addr_space *indirect_as = as; arch_addr_t val, initial_addr = *addr; - arch_addr_t gp = as->cursor.lib->gp; + arch_addr_t gp = as->cursor.libref->gp; int is_64bit = as->is_64bit; void *tmp_ptr; int ret; @@ -486,12 +486,12 @@ static int dwarf_read_encoded_pointer(struct dwarf_addr_space *as, int local, #ifdef DEBUG struct dwarf_cursor *c = &as->cursor; - struct library *lib = c->lib; + struct libref *libref = c->libref; - if (*addr < ARCH_ADDR_T(lib->image_addr)) - fatal("invalid access mem: addr %#lx < %p", *addr, lib->image_addr); - if (*addr >= ARCH_ADDR_T(lib->image_addr + lib->load_size)) - fatal("invalid access mem: addr %#lx >= %p", *addr, lib->image_addr + lib->load_size); + if (*addr < ARCH_ADDR_T(libref->image_addr)) + fatal("invalid access mem: addr %#lx < %p", *addr, libref->image_addr); + if (*addr >= ARCH_ADDR_T(libref->image_addr + libref->load_size)) + fatal("invalid access mem: addr %#lx >= %p", *addr, libref->image_addr + libref->load_size); #endif memset(&tmp, 0, sizeof(tmp)); @@ -877,9 +877,9 @@ static int dwarf_extract_cfi_from_fde(struct dwarf_addr_space *as, void *addrp) return 0; } -static inline int lib_addr_match(struct library *lib, arch_addr_t ip) +static inline int lib_addr_match(struct libref *libref, arch_addr_t ip) { - return ip >= lib->load_addr && ip < lib->load_addr + lib->load_size; + return ip >= libref->load_addr && ip < libref->load_addr + libref->load_size; } int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip) @@ -888,25 +888,28 @@ int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip) struct task *leader; struct list_head *it; - if (as->cursor.lib) { - if (lib_addr_match(as->cursor.lib, ip)) + if (c->use_prev_instr) + ip -= 1; + + if (as->cursor.libref) { + if (lib_addr_match(as->cursor.libref, ip)) return 0; } leader = c->task->leader; - as->cursor.lib = NULL; + as->cursor.libref = NULL; list_for_each(it, &leader->libraries_list) { - struct library *lib = container_of(it, struct library, list); + struct libref *libref = container_of(it, struct library, list)->libref; - if (lib_addr_match(lib, ip)) { - as->cursor.lib = lib; + if (lib_addr_match(libref, ip)) { + as->cursor.libref = libref; break; } } - if (!as->cursor.lib) { + if (!as->cursor.libref) { debug(DEBUG_DWARF, "no mapping found for IP %#lx", ip); return -DWARF_ENOINFO; } @@ -947,21 +950,21 @@ static int dwarf_search_unwind_table(struct dwarf_addr_space *as, arch_addr_t ip void *fde_addr; int ret; struct dwarf_cie_info *dci = &as->cursor.dci; - struct library *lib = as->cursor.lib; + struct libref *libref = as->cursor.libref; - e = lookup(table_data, table_len, ip - lib->load_addr - lib->seg_offset); + e = lookup(table_data, table_len, ip - libref->load_addr - libref->seg_offset); if (!e) { /* IP is inside this table's range, but there is no explicit unwind info. */ debug(DEBUG_DWARF, "no unwind info found for IP %#lx", ip); return -DWARF_ENOINFO; } - fde_addr = lib->image_addr - lib->load_offset + e->fde_offset + lib->seg_offset; + fde_addr = libref->image_addr - libref->load_offset + e->fde_offset + libref->seg_offset; if ((ret = dwarf_extract_cfi_from_fde(as, fde_addr)) < 0) return ret; - dci->start_ip -= ARCH_ADDR_T(lib->image_addr) - lib->load_addr; + dci->start_ip -= ARCH_ADDR_T(libref->image_addr) - libref->load_addr; if (!as->is_64bit) dci->start_ip &= 0xffffffff; @@ -1824,10 +1827,10 @@ static int apply_reg_state(struct dwarf_addr_space *as, struct dwarf_reg_state * static int fetch_proc_info(struct dwarf_addr_space *as, arch_addr_t ip) { struct dwarf_cursor *c = &as->cursor; - struct library *lib = c->lib; + struct libref *libref = c->libref; int ret; - ret = dwarf_search_unwind_table(as, ip, lib->table_data, lib->table_len); + ret = dwarf_search_unwind_table(as, ip, libref->table_data, libref->table_len); if (ret < 0) return ret; @@ -1840,13 +1843,14 @@ static int fetch_proc_info(struct dwarf_addr_space *as, arch_addr_t ip) int dwarf_init_unwind(struct dwarf_addr_space *as, struct task *task) { struct dwarf_cursor *c = &as->cursor; + int ret; c->cfa = 0; c->ip = 0; c->ret_addr_column = 0; c->use_prev_instr = 0; c->valid = 1; - c->lib = NULL; + c->libref = NULL; c->task = task; as->addr = 0; @@ -1854,7 +1858,11 @@ int dwarf_init_unwind(struct dwarf_addr_space *as, struct task *task) memset(&c->dci, 0, sizeof(c->dci)); - return dwarf_arch_init_unwind(as); + ret = dwarf_arch_init_unwind(as); + if (!ret) + ret = dwarf_locate_map(as, c->ip); + + return ret; } void *dwarf_init(int is_64bit) @@ -1887,6 +1895,18 @@ void dwarf_destroy(struct dwarf_addr_space *as) free(as); } +#ifdef GUESS_CALLER +static arch_addr_t get32val(unsigned char *buf) +{ + return *(uint32_t *)buf; +} + +static arch_addr_t get64val(unsigned char *buf) +{ + return *(uint64_t *)buf; +} +#endif + int dwarf_step(struct dwarf_addr_space *as) { int ret; @@ -1900,6 +1920,10 @@ int dwarf_step(struct dwarf_addr_space *as) ip = c->ip; cfa = c->cfa; + ret = dwarf_locate_map(as, ip); + if (ret < 0) + goto fail; + /* The 'ip' can point either to the previous or next instruction depending on what type of frame we have: normal call or a place to resume execution (e.g. after signal frame). @@ -1918,10 +1942,6 @@ int dwarf_step(struct dwarf_addr_space *as) if (c->use_prev_instr) --ip; - ret = dwarf_locate_map(as, ip); - if (ret < 0) - goto fail; - ret = fetch_proc_info(as, ip); if (ret < 0) goto fail; @@ -1936,34 +1956,57 @@ int dwarf_step(struct dwarf_addr_space *as) if (ret < 0) goto fail; - return 0; + ret = dwarf_locate_map(as, c->ip); + if (ret < 0) + goto fail; + return 0; fail: + c->ip = ip; + if (ret == -DWARF_ENOINFO) { debug(DEBUG_DWARF, "try arch specific step"); ret = dwarf_arch_step(as); if (!ret) { - if (dwarf_locate_map(as, c->use_prev_instr ? c->ip - 1 : c->ip)) + if (dwarf_locate_map(as, c->ip) < 0) ret = -DWARF_ENOINFO; } } if (ret) { - unsigned int i; +#ifdef GUESS_CALLER + ssize_t n; + unsigned char buf[4096]; - for(i = 0; i < 16; ++i) { - if (dwarf_readw(as, &cfa, &ip, as->is_64bit)) - break; + n = copy_from_proc(c->task, cfa, &buf, ARRAY_SIZE(buf)); + if (n > 0) { + arch_addr_t (*getval)(unsigned char *buf); + ssize_t i; + ssize_t addr_size = DWARF_ADDR_SIZE(as); - if (!dwarf_locate_map(as, ip)) { - c->cfa = cfa; - c->ip = ip; + if (addr_size == 8) + getval = get64val; + else + getval = get32val; - return 0; + for(i = 0; i + addr_size <= n ; i += addr_size) { + ip = getval(&buf[i]); + +#if 0 + if (c->ip - ip < 16384) + continue; +#endif + + if (!dwarf_locate_map(as, ip) && dwarf_arch_check_call(as, ip)) { + c->cfa = cfa + i + addr_size; + c->ip = ip; + + return 0; + } } } - +#endif debug(DEBUG_DWARF, "error %d", ret); c->valid = 0; @@ -1982,7 +2025,7 @@ arch_addr_t dwarf_get_ip(struct dwarf_addr_space *as) return c->ip; } -int dwarf_get_unwind_table(struct task *task, struct library *lib, struct dwarf_eh_frame_hdr *hdr) +int dwarf_get_unwind_table(struct task *task, struct libref *libref, struct dwarf_eh_frame_hdr *hdr) { arch_addr_t addr, fde_count; int ret; @@ -1991,7 +2034,7 @@ int dwarf_get_unwind_table(struct task *task, struct library *lib, struct dwarf_ memset(&tmp_as, 0, sizeof(tmp_as)); tmp_as.is_64bit = task->is_64bit; - tmp_as.cursor.lib = lib; + tmp_as.cursor.libref = libref; tmp_as.cursor.task = task; if (hdr->version != DW_EH_VERSION) { @@ -2014,9 +2057,19 @@ int dwarf_get_unwind_table(struct task *task, struct library *lib, struct dwarf_ return -DWARF_EINVAL; } - lib->table_data = (void *)addr; - lib->table_len = fde_count; + libref->table_data = (void *)addr; + libref->table_len = fde_count; return 0; } +int dwarf_location_type(struct dwarf_addr_space *as) +{ + struct libref *libref = as->cursor.libref; + + if (!libref) + return -1; + + return libref->type; +} + diff --git a/dwarf.h b/dwarf.h index d57b411..5b8acaa 100644 --- a/dwarf.h +++ b/dwarf.h @@ -89,7 +89,7 @@ struct dwarf_cursor { arch_addr_t ret_addr_column; /* column for return-address */ unsigned int use_prev_instr:1; /* use previous (= call) or current (= signal) instruction? */ unsigned int valid:1; - struct library *lib; + struct libref *libref; struct dwarf_cie_info dci; struct dwarf_loc *loc; }; @@ -119,12 +119,15 @@ int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip); int dwarf_get(struct dwarf_addr_space *as, struct dwarf_loc loc, arch_addr_t *valp); -int dwarf_get_unwind_table(struct task *task, struct library *lib, struct dwarf_eh_frame_hdr *hdr); +int dwarf_get_unwind_table(struct task *task, struct libref *libref, struct dwarf_eh_frame_hdr *hdr); + +int dwarf_location_type(struct dwarf_addr_space *as); int dwarf_arch_init(struct dwarf_addr_space *as); int dwarf_arch_init_unwind(struct dwarf_addr_space *as); int dwarf_arch_step(struct dwarf_addr_space *as); int dwarf_arch_map_reg(struct dwarf_addr_space *as, unsigned int reg); +int dwarf_arch_check_call(struct dwarf_addr_space *as, arch_addr_t ip); #ifdef DWARF_TO_REGNUM unsigned int dwarf_to_regnum(unsigned int reg); diff --git a/event.c b/event.c index 492aa3d..cb78a3d 100644 --- a/event.c +++ b/event.c @@ -61,12 +61,6 @@ void queue_event(struct task *task) } } -void wait_for_event(struct task *task) -{ - while(task->event.type == EVENT_NONE) - queue_event(wait_event()); -} - struct task *next_event(void) { if (!list_empty(&event_head)) { @@ -113,7 +107,7 @@ static void show_clone(struct task *task, enum event_type type) fprintf(stderr, "+++ process pid=%d %s (newpid=%d) +++\n", task->pid, str, task->event.e_un.newpid); } -static struct task *handle_clone(struct task *task, enum event_type type) +static void handle_clone(struct task *task, enum event_type type) { struct task *newtask; int newpid = task->event.e_un.newpid; @@ -135,7 +129,7 @@ static struct task *handle_clone(struct task *task, enum event_type type) if (!options.follow) { remove_proc(newtask); - return task; + return; } report_fork(newtask, task); @@ -147,21 +141,23 @@ static struct task *handle_clone(struct task *task, enum event_type type) continue_task(newtask, newtask->event.e_un.signum); - return task; + return; fail: fprintf(stderr, "Error during init of tracing process %d\n" "This process won't be traced.\n", newpid ); - - return task; } -static struct task *handle_signal(struct task *task) +static void handle_signal(struct task *task) { + if (options.verbose > 1) { + if (task->event.e_un.signum && (task->event.e_un.signum != SIGSTOP || !task->was_stopped)) + fprintf(stderr, "+++ process pid=%d signal %d: %s +++\n", task->pid, task->event.e_un.signum, strsignal(task->event.e_un.signum)); + } + continue_task(task, task->event.e_un.signum); - return task; } static void show_exit(struct task *task) @@ -171,17 +167,18 @@ static void show_exit(struct task *task) } -static struct task *handle_about_exit(struct task *task) +static void handle_about_exit(struct task *task) { - if (task->leader == task) - report_about_exit(task); - else - continue_task(task, 0); - - return task; + if (task->leader == task) { + if (report_about_exit(task) != -1) { + task->about_exit = 1; + return; + } + } + continue_task(task, 0); } -static struct task *handle_exit(struct task *task) +static void handle_exit(struct task *task) { show_exit(task); @@ -189,13 +186,12 @@ static struct task *handle_exit(struct task *task) report_exit(task); remove_proc(task); } - else + else { remove_task(task); - - return NULL; + } } -static struct task *handle_exit_signal(struct task *task) +static void handle_exit_signal(struct task *task) { if (options.verbose) fprintf(stderr, "+++ process pid=%d killed by signal %s (%d) +++\n", task->pid, strsignal(task->event.e_un.signum), task->event.e_un.signum); @@ -204,13 +200,12 @@ static struct task *handle_exit_signal(struct task *task) report_exit(task); remove_proc(task); } - else + else { remove_task(task); - - return NULL; + } } -static struct task *handle_exec(struct task *task) +static void handle_exec(struct task *task) { debug(DEBUG_FUNCTION, "pid=%d", task->pid); @@ -226,12 +221,11 @@ static struct task *handle_exec(struct task *task) fprintf(stderr, "+++ process pid=%d exec (%s) +++\n", task->pid, library_execname(task)); continue_task(task, 0); - return task; + return; nofollow: report_nofollow(task); untrace: remove_proc(task); - return NULL; } static int handle_call_after(struct task *task, struct breakpoint *bp) @@ -247,12 +241,22 @@ static int handle_call_after(struct task *task, struct breakpoint *bp) return 0; } -static struct task *handle_breakpoint(struct task *task) +static void handle_breakpoint(struct task *task) { struct breakpoint *bp = task->event.e_un.breakpoint; debug(DEBUG_FUNCTION, "pid=%d, addr=%#lx", task->pid, bp->addr); +#if HW_BREAKPOINTS > 1 + if (bp->type >= BP_HW) { + if (++bp->hwcnt >= (BP_REORDER_THRESHOLD << bp->hw)) + reorder_hw_bp(task); + } +#endif + + if (options.verbose) + ++bp->count; + if (bp->deleted) { struct breakpoint *nbp = breakpoint_find(task, bp->addr); @@ -264,7 +268,7 @@ static struct task *handle_breakpoint(struct task *task) } if (task->skip_bp == bp) { - breakpoint_unref(task->skip_bp); + breakpoint_put(task->skip_bp); task->skip_bp = NULL; skip_breakpoint(task, bp); goto end; @@ -281,7 +285,7 @@ static struct task *handle_breakpoint(struct task *task) save_param_context(task); if (libsym->func->report_out) { - task->breakpoint = breakpoint_insert(task, get_return_addr(task), NULL, HW_BP_SCRATCH); + task->breakpoint = breakpoint_insert(task, get_return_addr(task), NULL, BP_HW_SCRATCH); if (task->breakpoint) { task->libsym = libsym; task->breakpoint->on_hit = handle_call_after; @@ -298,9 +302,7 @@ static struct task *handle_breakpoint(struct task *task) skip_breakpoint(task, bp); end: - breakpoint_unref(bp); - - return task; + breakpoint_put(bp); } int handle_event(void) @@ -322,33 +324,33 @@ int handle_event(void) break; case EVENT_SIGNAL: debug(DEBUG_EVENT_HANDLER, "pid=%d, event signal %d", task->pid, event->e_un.signum); - task = handle_signal(task); + handle_signal(task); break; case EVENT_ABOUT_EXIT: debug(DEBUG_EVENT_HANDLER, "pid=%d, event exit %d", task->pid, event->e_un.ret_val); - task = handle_about_exit(task); + handle_about_exit(task); break; case EVENT_EXIT: debug(DEBUG_EVENT_HANDLER, "pid=%d, event exit %d", task->pid, event->e_un.ret_val); - task = handle_exit(task); + handle_exit(task); break; case EVENT_EXIT_SIGNAL: debug(DEBUG_EVENT_HANDLER, "pid=%d, event exit signal %d", task->pid, event->e_un.signum); - task = handle_exit_signal(task); + handle_exit_signal(task); break; case EVENT_FORK: case EVENT_VFORK: case EVENT_CLONE: debug(DEBUG_EVENT_HANDLER, "pid=%d, event clone (%u)", task->pid, event->e_un.newpid); - task = handle_clone(task, type); + handle_clone(task, type); break; case EVENT_EXEC: debug(DEBUG_EVENT_HANDLER, "pid=%d, event exec()", task->pid); - task = handle_exec(task); + handle_exec(task); break; case EVENT_BREAKPOINT: debug(DEBUG_EVENT_HANDLER, "pid=%d, event breakpoint %#lx", task->pid, event->e_un.breakpoint->addr); - task = handle_breakpoint(task); + handle_breakpoint(task); break; default: fprintf(stderr, "Error! unknown event?\n"); diff --git a/event.h b/event.h index 0673215..a825317 100644 --- a/event.h +++ b/event.h @@ -53,7 +53,6 @@ struct event { void init_event(struct task *task); void remove_event(struct task *task); struct task *next_event(void); -void wait_for_event(struct task *task); void queue_event(struct task *task); int handle_event(void); diff --git a/forward.h b/forward.h index 8cee44b..0b1789e 100644 --- a/forward.h +++ b/forward.h @@ -28,6 +28,7 @@ struct event; struct task; struct breakpoint; +struct libref; struct library; struct library_symbol; struct mt_elf; diff --git a/library.c b/library.c index 498f5ea..64806df 100644 --- a/library.c +++ b/library.c @@ -38,126 +38,107 @@ #include "server.h" #include "task.h" -struct library_symbol *library_symbol_new(struct library *lib, arch_addr_t addr, const struct function *func) +struct libref *libref_new(unsigned int type) +{ + struct libref *libref = malloc(sizeof(*libref)); + + if (!libref) + return NULL; + + memset(libref, 0, sizeof(*libref)); + + libref->refcnt = 0; + libref->type = type; + + INIT_LIST_HEAD(&libref->sym_list); + + return libref; +} + + +void libref_delete(struct libref *libref) +{ + struct list_head *it, *next; + + list_for_each_safe(it, next, &libref->sym_list) { + struct library_symbol *sym = container_of(it, struct library_symbol, list); + + list_del(&sym->list); + free(sym); + } + + if (libref->image_addr) + munmap(libref->image_addr, libref->load_size); + + free((void *)libref->filename); + free(libref); +} + +static void libref_put(struct libref *libref) +{ + assert(libref->refcnt != 0); + + if (!--libref->refcnt) + libref_delete(libref); +} + +static struct libref *libref_get(struct libref *libref) +{ + assert(libref); + + ++libref->refcnt; + + return libref; +} + +void libref_set_filename(struct libref *libref, const char *new_name) +{ + free((void *)libref->filename); + libref->filename = new_name ? strdup(new_name) : NULL; +} + +struct library_symbol *library_symbol_new(struct libref *libref, arch_addr_t addr, const struct function *func) { struct library_symbol *libsym = malloc(sizeof(*libsym)); if (!libsym) return NULL; - INIT_LIST_HEAD(&libsym->list); - libsym->lib = NULL; + libsym->libref = libref; libsym->func = func; libsym->addr = addr; - list_add_tail(&libsym->list, &lib->sym_list); + list_add_tail(&libsym->list, &libref->sym_list); return libsym; } -static void library_symbol_destroy(struct task *task, struct library_symbol *libsym) -{ - struct breakpoint *bp = breakpoint_find(task, libsym->addr); - - if (bp) - breakpoint_delete(task, bp); - - list_del(&libsym->list); - free(libsym); -} - -static struct library_symbol *library_symbol_clone(struct library *lib, struct library_symbol *libsym) -{ - struct library_symbol *retp = library_symbol_new(lib, libsym->addr, libsym->func); - if (!retp) - return NULL; - - return retp; -} - -struct library *library_new(void) -{ - struct library *lib = malloc(sizeof(*lib)); - - if (lib == NULL) - return NULL; - - memset(lib, 0, sizeof(*lib)); - - INIT_LIST_HEAD(&lib->list); - INIT_LIST_HEAD(&lib->sym_list); - - return lib; -} - -void library_destroy(struct task *task, struct library *lib) +void library_delete(struct task *task, struct library *lib) { if (lib == NULL) return; struct list_head *it, *next; + struct libref *libref = lib->libref; - list_for_each_safe(it, next, &lib->sym_list) { - struct library_symbol *sym = container_of(it, struct library_symbol, list); + list_for_each_safe(it, next, &libref->sym_list) { + struct breakpoint *bp = breakpoint_find(task, container_of(it, struct library_symbol, list)->addr); - library_symbol_destroy(task, sym); + if (bp) + breakpoint_delete(task, bp); } list_del(&lib->list); - - if (lib->image_addr) - munmap(lib->image_addr, lib->load_size); - free(lib); + + libref_put(libref); } -void library_set_filename(struct library *lib, const char *new_name) -{ - free((void *)lib->filename); - lib->filename = new_name ? strdup(new_name) : NULL; -} - -static struct library *library_clone(struct task *clone, struct library *lib) -{ - struct list_head *it; - struct library *retp = library_new(); - - if (!retp) - return NULL; - - library_set_filename(retp, lib->filename); - - retp->key = lib->key; - - /* Clone symbols. */ - list_for_each(it, &lib->sym_list) { - if (!library_symbol_clone(retp, container_of(it, struct library_symbol, list))) - goto fail; - } - - return retp; -fail: - /* Release what we managed to allocate. */ - library_destroy(clone, retp); - return NULL; -} - -static void library_each_symbol(struct library *lib, void (*cb)(struct library_symbol *, void *), void *data) -{ - struct list_head *it, *next; - - list_for_each_safe(it, next, &lib->sym_list) { - struct library_symbol *sym = container_of(it, struct library_symbol, list); - - (*cb) (sym, data); - } -} - -struct library_symbol *library_find_symbol(struct library *lib, arch_addr_t addr) +struct library_symbol *library_find_symbol(struct libref *libref, arch_addr_t addr) { struct list_head *it; - list_for_each(it, &lib->sym_list) { + list_for_each(it, &libref->sym_list) { struct library_symbol *sym = container_of(it, struct library_symbol, list); if (sym->addr == addr) @@ -166,21 +147,6 @@ struct library_symbol *library_find_symbol(struct library *lib, arch_addr_t addr return NULL; } -struct library_symbol *find_symbol(struct task *leader, arch_addr_t addr) -{ - /* Clone symbols first so that we can clone and relink breakpoints. */ - struct list_head *it; - - list_for_each(it, &leader->libraries_list) { - struct library *lib = container_of(it, struct library, list); - struct library_symbol *libsym = library_find_symbol(lib, addr); - - if (libsym) - return libsym; - } - return NULL; -} - struct library *library_find_with_key(struct list_head *list, arch_addr_t key) { struct list_head *it; @@ -188,7 +154,7 @@ struct library *library_find_with_key(struct list_head *list, arch_addr_t key) list_for_each(it, list) { struct library *lib = container_of(it, struct library, list); - if (lib->key == key) + if (lib->libref->key == key) return lib; } return NULL; @@ -200,13 +166,14 @@ void library_delete_list(struct task *leader, struct list_head *list) list_for_each_safe(it, next, list) { struct library *lib = container_of(it, struct library, list); + struct libref *libref = lib->libref; - debug(DEBUG_FUNCTION, "%s@%#lx", lib->filename, lib->base); + debug(DEBUG_FUNCTION, "%s@%#lx", libref->filename, libref->base); if (options.verbose > 1) - fprintf(stderr, "+++ library del pid=%d %s@%#lx %#lx-%#lx +++\n", leader->pid, lib->filename, lib->base, lib->load_addr, lib->load_addr + lib->load_size); + fprintf(stderr, "+++ library del pid=%d %s@%#lx %#lx-%#lx +++\n", leader->pid, libref->filename, libref->base, libref->load_addr, libref->load_addr + libref->load_size); - library_destroy(leader, lib); + library_delete(leader, lib); } } @@ -222,7 +189,7 @@ static void cb_breakpoint_for_symbol(struct library_symbol *libsym, void *data) bp->libsym = libsym; return; } - bp = breakpoint_new(task, addr, libsym, libsym->func->hw_bp_min <= HW_BREAKPOINTS ? HW_BP : SW_BP); + bp = breakpoint_new(task, addr, libsym, BP_AUTO); if (!bp) fprintf(stderr, "Couldn't insert breakpoint for %s to %d: %s", libsym->func->name, task->pid, strerror(errno)); @@ -230,21 +197,50 @@ static void cb_breakpoint_for_symbol(struct library_symbol *libsym, void *data) breakpoint_enable(task, bp); } -void library_add(struct task *leader, struct library *lib) +static void library_each_symbol(struct libref *libref, void (*cb)(struct library_symbol *, void *), void *data) { + struct list_head *it, *next; + + list_for_each_safe(it, next, &libref->sym_list) { + struct library_symbol *sym = container_of(it, struct library_symbol, list); + + (*cb) (sym, data); + } +} + +static struct library *_library_add(struct task *leader, struct libref *libref) +{ + debug(DEBUG_PROCESS, "%s@%#lx to pid=%d", libref->filename, libref->base, leader->pid); + assert(leader->leader == leader); - debug(DEBUG_PROCESS, "%s@%#lx to pid=%d", lib->filename, lib->base, leader->pid); + struct library *lib = malloc(sizeof(*lib)); - if (options.verbose > 1) - fprintf(stderr, "+++ library add pid=%d %s@%#lx %#lx-%#lx +++\n", leader->pid, lib->filename, lib->base, lib->load_addr, lib->load_addr + lib->load_size); + if (lib == NULL) + return NULL; - /* Insert breakpoints for all active symbols. */ - library_each_symbol(lib, cb_breakpoint_for_symbol, leader); + memset(lib, 0, sizeof(*lib)); + + lib->libref = libref_get(libref); list_add_tail(&lib->list, &leader->libraries_list); + if (options.verbose > 1) + fprintf(stderr, "+++ library add pid=%d %s@%#lx %#lx-%#lx +++\n", leader->pid, libref->filename, libref->base, libref->load_addr, libref->load_addr + libref->load_size); + + return lib; +} + +struct library *library_add(struct task *leader, struct libref *libref) +{ + struct library *lib = _library_add(leader, libref); + + /* Insert breakpoints for all active symbols. */ + library_each_symbol(libref, cb_breakpoint_for_symbol, leader); + report_add_map(leader, lib); + + return lib; } void library_clear_all(struct task *leader) @@ -258,12 +254,8 @@ int library_clone_all(struct task *clone, struct task *leader) list_for_each(it, &leader->libraries_list) { struct library *lib = container_of(it, struct library, list); - struct library *nlibp = library_clone(clone, lib); - if (!nlibp) - return -1; - - list_add_tail(&nlibp->list, &clone->libraries_list); + _library_add(clone, lib->libref); } return 0; } @@ -278,6 +270,6 @@ const char *library_execname(struct task *leader) if (list_empty(&leader->libraries_list)) return NULL; - return container_of(leader->libraries_list.next, struct library, list)->filename; + return container_of(leader->libraries_list.next, struct library, list)->libref->filename; } diff --git a/library.h b/library.h index 88d3c99..4c1ca7d 100644 --- a/library.h +++ b/library.h @@ -31,21 +31,18 @@ #include "list.h" #include "mtelf.h" +#define LIBTYPE_LIB 0 +#define LIBTYPE_MAIN 1 +#define LIBTYPE_LOADER 2 + struct library_symbol { struct list_head list; - struct library *lib; + struct libref *libref; const struct function *func; arch_addr_t addr; }; -struct library_symbol *library_symbol_new(struct library *lib, arch_addr_t addr, const struct function *func); - -struct library { - struct list_head list; - /* Symbols associated with the library. This includes a - * symbols that don't have a breakpoint attached (yet). */ - struct list_head sym_list; - +struct libref { /* Unique key. Two library objects are considered equal, if * they have the same key. */ arch_addr_t key; @@ -74,24 +71,36 @@ struct library { unsigned long seg_offset; void *table_data; unsigned long table_len; + unsigned int type; + #ifdef __arm__ void *exidx_data; unsigned long exidx_len; #endif + + unsigned int refcnt; + + /* Symbols associated with the library. This includes a + * symbols that don't have a breakpoint attached (yet). */ + struct list_head sym_list; }; -/* Init LIB. */ -struct library *library_new(void); +struct library { + /* link list of libraries associated with the task */ + struct list_head list; -/* Destroy library. Doesn't free LIB itself. Symbols are destroyed - * and freed. */ -void library_destroy(struct task *leader, struct library *lib); + /* pointer to the real library refernce */ + struct libref *libref; +}; -/* Set library filename. Frees the old name if necessary. */ -void library_set_filename(struct library *lib, const char *new_name); +/* create a new symbol */ +struct library_symbol *library_symbol_new(struct libref *libref, arch_addr_t addr, const struct function *func); + +/* Delete library. Symbols are destroyed and freed. */ +void library_delete(struct task *leader, struct library *lib); /* Add a library to the list of the thread leader libraries. */ -void library_add(struct task *leader, struct library *lib); +struct library *library_add(struct task *leader, struct libref *libref); /* delete a given list of libraries */ void library_delete_list(struct task *leader, struct list_head *list); @@ -109,13 +118,19 @@ void library_setup(struct task *leader); const char *library_execname(struct task *leader); /* Iterate through list of symbols of library. */ -struct library_symbol *library_find_symbol(struct library *lib, arch_addr_t addr); +struct library_symbol *library_find_symbol(struct libref *libref, arch_addr_t addr); /* find a library with a given key */ struct library *library_find_with_key(struct list_head *list, arch_addr_t key); -/* Iterate through list all symbols of leader task. */ -struct library_symbol *find_symbol(struct task *leader, arch_addr_t addr); +/* create a library reference. */ +struct libref *libref_new(unsigned int type); + +/* delete a library reference. */ +void libref_delete(struct libref *libref); + +/* Set library filename. Frees the old name if necessary. */ +void libref_set_filename(struct libref *libref, const char *new_name); #endif diff --git a/main.c b/main.c index 932a35f..cad55dd 100644 --- a/main.c +++ b/main.c @@ -64,15 +64,15 @@ void mtrace_request_exit(void) wait_event_wakeup(); } -static void dump_process(struct task *leader) +static void detach_process(struct task *leader) { if (!leader) return; - pid_t pid = leader->pid; - report_detach(leader); + pid_t pid = leader->pid; + while(server_handle_command() != -1) { struct task *task = pid2task(pid); @@ -88,12 +88,7 @@ static void mtrace_exit(void) { if (!options.interactive) { each_process(stop_threads); - - while(server_connected()) { - if (task_list_empty()) - break; - dump_process(get_first_process()); - } + each_process(detach_process); } each_process(remove_proc); @@ -139,24 +134,35 @@ int main(int argc, char *argv[]) { char **cmd = process_options(argc, argv); - if (options.client) { - if (client_start() == -1) - exit(EXIT_FAILURE); - return 0; - } + if (options.trace) { + if (options.logfile) { + if (server_logfile() == -1) + exit(EXIT_FAILURE); + } + else + if (options.server) { + if (server_start() == -1) + exit(EXIT_FAILURE); + } + else { + int ret = server_start_pair(); - if (options.server) { - if (server_start() == -1) - exit(EXIT_FAILURE); + if (ret == -1) + exit(EXIT_FAILURE); + + if (client_start_pair(ret)) + exit(EXIT_FAILURE); + } } else { - int ret = server_start_pair(); - - if (ret == -1) - exit(EXIT_FAILURE); - - if (client_start_pair(ret)) + if (options.logfile) { + if (client_logfile() == -1) + exit(EXIT_FAILURE); + } + else + if (client_start() == -1) exit(EXIT_FAILURE); + return 0; } mtrace_init(cmd); diff --git a/mtelf.c b/mtelf.c index 0281a96..1a3b788 100644 --- a/mtelf.c +++ b/mtelf.c @@ -146,7 +146,7 @@ static void read_symbol_table(struct mt_elf *mte, const char *filename, Elf_Scn *strsp = data->d_buf; } -static int populate_this_symtab(struct mt_elf *mte, struct library *lib, Elf_Data *symtab, const char *strtab, size_t size) +static int populate_this_symtab(struct mt_elf *mte, struct libref *libref, Elf_Data *symtab, const char *strtab, size_t size) { size_t i; @@ -177,9 +177,9 @@ static int populate_this_symtab(struct mt_elf *mte, struct library *lib, Elf_Dat arch_addr_t addr = ARCH_ADDR_T(sym.st_value + mte->bias); - struct library_symbol *libsym = library_find_symbol(lib, addr); + struct library_symbol *libsym = library_find_symbol(libref, addr); if (!libsym) { - struct library_symbol *libsym = library_symbol_new(lib, addr, func); + struct library_symbol *libsym = library_symbol_new(libref, addr, func); if (!libsym) { fprintf(stderr, "couldn't init symbol: %s%s\n", name, func->name); @@ -191,21 +191,30 @@ static int populate_this_symtab(struct mt_elf *mte, struct library *lib, Elf_Dat if (libsym->func->level > func->level) libsym->func = func; } + if (options.verbose > 1) + fprintf(stderr, "breakpoint for %s:%s at %#lx\n", libref->filename, func->demangled_name, addr); } return 0; } -static int populate_symtab(struct mt_elf *mte, struct library *lib) +static int populate_symtab(struct mt_elf *mte, struct libref *libref) { + struct opt_O_t *p; + + for(p = options.opt_O; p; p = p->next) { + if (!strcmp(p->pathname, libref->filename)) + return 0; + } + if (mte->symtab != NULL && mte->strtab != NULL) { - int status = populate_this_symtab(mte, lib, mte->symtab, mte->strtab, mte->symtab_count); + int status = populate_this_symtab(mte, libref, mte->symtab, mte->strtab, mte->symtab_count); if (status < 0) return status; } - return populate_this_symtab(mte, lib, mte->dynsym, mte->dynstr, mte->dynsym_count); + return populate_this_symtab(mte, libref, mte->dynsym, mte->dynstr, mte->dynsym_count); } static inline int elf_map_image(struct mt_elf *mte, void **image_addr) @@ -223,32 +232,32 @@ static inline int elf_map_image(struct mt_elf *mte, void **image_addr) return 0; } -static int elf_lib_init(struct mt_elf *mte, struct task *task, struct library *lib) +static int elf_lib_init(struct mt_elf *mte, struct task *task, struct libref *libref) { - if (elf_map_image(mte, &lib->image_addr)) + if (elf_map_image(mte, &libref->image_addr)) return -1; - lib->base = ARCH_ADDR_T(mte->base_addr); - lib->entry = ARCH_ADDR_T(mte->entry_addr); - lib->load_offset = mte->txt_hdr.p_offset; - lib->load_addr = mte->txt_hdr.p_vaddr + mte->bias; - lib->load_size = mte->txt_hdr.p_filesz; - lib->seg_offset = mte->eh_hdr.p_offset; - lib->gp = mte->pltgot; + libref->base = ARCH_ADDR_T(mte->base_addr); + libref->entry = ARCH_ADDR_T(mte->entry_addr); + libref->load_offset = mte->txt_hdr.p_offset; + libref->load_addr = mte->txt_hdr.p_vaddr + mte->bias; + libref->load_size = mte->txt_hdr.p_filesz; + libref->seg_offset = mte->eh_hdr.p_offset; + libref->gp = mte->pltgot; #ifdef __arm__ if (mte->exidx_hdr.p_filesz) { - lib->exidx_data = lib->image_addr + mte->exidx_hdr.p_offset; - lib->exidx_len = mte->exidx_hdr.p_memsz; + libref->exidx_data = libref->image_addr + mte->exidx_hdr.p_offset; + libref->exidx_len = mte->exidx_hdr.p_memsz; } #endif if (mte->eh_hdr.p_filesz && mte->dyn_addr) { - if (dwarf_get_unwind_table(task, lib, (struct dwarf_eh_frame_hdr *)(lib->image_addr - lib->load_offset + mte->eh_hdr.p_offset)) < 0) + if (dwarf_get_unwind_table(task, libref, (struct dwarf_eh_frame_hdr *)(libref->image_addr - libref->load_offset + mte->eh_hdr.p_offset)) < 0) return -1; } - if (populate_symtab(mte, lib) < 0) + if (populate_symtab(mte, libref) < 0) return -1; return 0; @@ -370,12 +379,12 @@ static int elf_read(struct mt_elf *mte, struct task *task, const char *filename, return 0; } -int elf_read_library(struct task *task, struct library *lib, const char *filename, GElf_Addr bias) +int elf_read_library(struct task *task, struct libref *libref, const char *filename, GElf_Addr bias) { struct mt_elf mte = { }; int ret; - library_set_filename(lib, filename); + libref_set_filename(libref, filename); if (elf_read(&mte, task, filename, bias) == -1) return -1; @@ -383,7 +392,7 @@ int elf_read_library(struct task *task, struct library *lib, const char *filenam mte.bias = bias; mte.entry_addr = mte.ehdr.e_entry + bias; - ret = elf_lib_init(&mte, task, lib); + ret = elf_lib_init(&mte, task, libref); close_elf(&mte); @@ -456,7 +465,7 @@ static int entry_breakpoint_on_hit(struct task *task, struct breakpoint *a) return 1; } -struct library *elf_read_main_binary(struct task *task) +struct libref *elf_read_main_binary(struct task *task) { char fname[PATH_MAX]; int ret; @@ -464,14 +473,14 @@ struct library *elf_read_main_binary(struct task *task) struct mt_elf mte = { }; unsigned long entry; unsigned long base; - struct library *lib; + struct libref *libref; filename = pid2name(task->pid); if (!filename) return NULL; - lib = library_new(); - if (lib == NULL) + libref = libref_new(LIBTYPE_MAIN); + if (libref == NULL) goto fail1; ret = readlink(filename, fname, sizeof(fname) - 1); @@ -480,7 +489,7 @@ struct library *elf_read_main_binary(struct task *task) fname[ret] = 0; - library_set_filename(lib, strdup(fname)); + libref_set_filename(libref, fname); if (elf_read(&mte, task, filename, 0) == -1) goto fail3; @@ -497,57 +506,90 @@ struct library *elf_read_main_binary(struct task *task) mte.bias = (GElf_Addr) (uintptr_t) entry - mte.ehdr.e_entry; mte.entry_addr = (GElf_Addr) (uintptr_t) entry; - if (elf_lib_init(&mte, task, lib)) + libref->key = ARCH_ADDR_T(mte.bias); + + if (elf_lib_init(&mte, task, libref)) goto fail3; close_elf(&mte); report_attach(task); - library_add(task, lib); - - if (!linkmap_init(task, ARCH_ADDR_T(mte.dyn_addr))) - return lib; + library_add(task, libref); if (!mte.interp) - return lib; + return libref; struct mt_elf mte_ld = { }; copy_str_from_proc(task, ARCH_ADDR_T(mte.interp), fname, sizeof(fname)); if (!elf_read(&mte_ld, task, fname, (GElf_Addr)base)) { + struct libref *libref; + + libref = libref_new(LIBTYPE_LOADER); + if (libref == NULL) + goto fail4; + + libref_set_filename(libref, fname); + mte_ld.bias = (GElf_Addr)base; mte_ld.entry_addr = mte_ld.ehdr.e_entry + (GElf_Addr)base; - arch_addr_t addr = find_solib_break(&mte_ld); - if (!addr) - addr = ARCH_ADDR_T(entry); + libref->key = ARCH_ADDR_T(mte_ld.bias); - struct entry_breakpoint *entry_bp = (void *)breakpoint_new_ext(task, addr, NULL, 0, sizeof(*entry_bp) - sizeof(entry_bp->breakpoint)); - if (!entry_bp) + ret = elf_lib_init(&mte_ld, task, libref); + if (!ret) { + library_add(task, libref); + + if (linkmap_init(task, ARCH_ADDR_T(mte.dyn_addr))) { + arch_addr_t addr = find_solib_break(&mte_ld); + if (!addr) + addr = ARCH_ADDR_T(entry); + + struct entry_breakpoint *entry_bp = (void *)breakpoint_new_ext(task, addr, NULL, 0, sizeof(*entry_bp) - sizeof(entry_bp->breakpoint)); + if (!entry_bp) + fprintf(stderr, + "Couldn't initialize entry breakpoint for PID %d.\n" + "Tracing events may be missed.\n", + task->pid + ); + else { + entry_bp->breakpoint.on_hit = entry_breakpoint_on_hit; + entry_bp->breakpoint.locked = 1; + entry_bp->dyn_addr = ARCH_ADDR_T(mte.dyn_addr); + + breakpoint_enable(task, &entry_bp->breakpoint); + } + } + } + else { fprintf(stderr, - "Couldn't initialize entry breakpoint for PID %d.\n" - "Some tracing events may be missed.\n", + "Couldn't read dynamic loader `%s` for PID %d.\n" + "Tracing events may be missed.\n", + fname, task->pid ); - else { - entry_bp->breakpoint.on_hit = entry_breakpoint_on_hit; - entry_bp->breakpoint.locked = 1; - entry_bp->dyn_addr = ARCH_ADDR_T(mte.dyn_addr); - - breakpoint_enable(task, &entry_bp->breakpoint); } +fail4: + close_elf(&mte_ld); + } + else { + fprintf(stderr, + "Couldn't open dynamic loader `%s` for PID %d.\n" + "Tracing events may be missed.\n", + fname, + task->pid + ); } - close_elf(&mte_ld); - return lib; + return libref; fail3: close_elf(&mte); fail2: - library_destroy(task, lib); + libref_delete(libref); fail1: free(filename); - return lib; + return libref; } diff --git a/mtelf.h b/mtelf.h index 27102f6..0ceb1b2 100644 --- a/mtelf.h +++ b/mtelf.h @@ -58,10 +58,10 @@ struct elf_image { size_t size; /* (file-) size of the image */ }; -int elf_read_library(struct task *task, struct library *lib, const char *filename, GElf_Addr bias); +int elf_read_library(struct task *task, struct libref *libref, const char *filename, GElf_Addr bias); /* Create a library object representing the main binary. */ -struct library *elf_read_main_binary(struct task *task); +struct libref *elf_read_main_binary(struct task *task); #endif diff --git a/mtrace.1 b/mtrace.1 index 5309998..f1c822f 100644 --- a/mtrace.1 +++ b/mtrace.1 @@ -16,7 +16,7 @@ .\" Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA .\" 02110-1301 USA .\" -.TH MTRACE "1" "May 2015" "" "User Commands" +.TH MTRACE "12" "Oct 2015" "" "User Commands" .SH NAME mtrace \- A dynamic memory allocation tracer .SH SYNOPSIS @@ -24,14 +24,14 @@ mtrace \- A dynamic memory allocation tracer .\" --------------------------------------------------------------------------- .\" .PP -.B mtrace +.BR mtrace " \-t|\-\-trace .\" .\" Output formatting: .\" [\-d|\-\-depth \fIlevel\fR] -[\-F|\-\-config \fIfile\fR] +[\-F|\-\-config \fIfilename\fR] [\-S|\-\-sort \fIoption\fR] -[\-o|\-\-output \fIfile\fR] +[\-o|\-\-output \fIfilename\fR] .\" .\" Various: .\" @@ -39,8 +39,11 @@ mtrace \- A dynamic memory allocation tracer [\-b|\-\-binpath \fIpath\fR] [\-C|\-\-cwd \fIpath\fR] [\-D|\-\-debug \fImask\fR] +[\-i|\-\-interactive] +[\-l|\-\-logfile \fIfilename\fR] [\-n|\-\-nocpp] -[\-u \fIusername\fR] +[\-O|\-\-omit \fIfilename\fR] +[\-u|\-\-user \fIusername\fR] [\-v|\-\-verbose] .\" .\" What processes to trace: @@ -53,42 +56,22 @@ mtrace \- A dynamic memory allocation tracer .\" --------------------------------------------------------------------------- .\" .PP -.BR mtrace " \-c|\-\-client addr" -[\-P|\-\-port num] -[\-i|\-\-interactive] -.\" -.\" Output formatting: -.\" -[\-b|\-\-binpath \fIpath\fR] -[\-F|\-\-config \fIfile\fR] -[\-S|\-\-sort \fIoption\fR] -[\-o|\-\-output \fIfilenfR] -.\" -.\" Various: -.\" -[\-a|\-\-autoscan] -[\-D|\-\-debug \fImask\fR] -[\-v|\-\-verbose] -.\" -.\" --------------------------------------------------------------------------- -.\" -.PP -.BR mtrace " \-s|\-\-server" -[\-P|\-\-port num] -[\-l|\-\-listen addr] +.BR mtrace " \-t|\-\-trace \-r|\-\-remote \fIaddr\fR" +[\-P|\-\-port \fInum\fR] [\-w|\-\-wait] .\" .\" Output formatting: .\" [\-d|\-\-depth \fIlevel\fR] -[\-o|\-\-output \fIfile\fR] .\" .\" Various: .\" [\-C|\-\-cwd \fIpath\fR] [\-D|\-\-debug \fImask\fR] +[\-l|\-\-logfile \fIfilename\fR] [\-n|\-\-nocpp] -[\-u \fIusername\fR] +[\-O|\-\-omit \fIfilename\fR] +[\-u|\-\-user \fIusername\fR] [\-v|\-\-verbose] .\" .\" What processes to trace: @@ -101,30 +84,25 @@ mtrace \- A dynamic memory allocation tracer .\" --------------------------------------------------------------------------- .\" .PP -.B mtrace -i|\-\-interactive +.BR mtrace +[\-r|\-\-remote \fIaddr\fR] +[\-P|\-\-port \fInum\fR] .\" .\" Output formatting: .\" -[\-d|\-\-depth \fIlevel\fR] -[\-F|\-\-config \fIfile\fR] +[\-F|\-\-config \fIfilename\fR] [\-S|\-\-sort \fIoption\fR] +[\-o|\-\-output \fIfilename\fR] .\" .\" Various: .\" [\-a|\-\-autoscan] [\-b|\-\-binpath \fIpath\fR] -[\-C|\-\-cwd] [\-D|\-\-debug \fImask\fR] -[\-n|\-\-nocpp] -[\-u \fIusername\fR] +[\-i|\-\-interactive] +[\-l|\-\-logfile \fIfilename\fR] [\-v|\-\-verbose] .\" -.\" What processes to trace: -.\" -[\-e|\-\-follow\-exec] -[\-f|\-\-follow\-fork] -[\-p|\-\-pid \fIpid\fR] -.\" .\" --------------------------------------------------------------------------- .\" .PP @@ -154,7 +132,7 @@ writable memory mappings of the program against the pointer of an allocation. If the memory address will be not found during a scan there is a high change for a missing reference and therefore for a memory leak. -The following funtions will be intercepted: +The following functions will be intercepted: .in +4 .nf @@ -226,13 +204,7 @@ of the binary to the search path. If the binary is not found it will strip down the leading directory of the remote path and try again until no more leading directory is found. It is possible to add several binary search paths by passing more than one \-b option. -.IP "\-c, \-\-client \fIaddr\fR" -Run -.B mtrace -as client and connect to a socket. If addr begins with / or . it will assumed -a named socket, otherwise it will be passed to getaddrinfo(3), which handles -any kind of hostname, IPv4 or IPv6 addresses. -.IP "\-C, \-\-cwd \fIpath\fR" +.IP "\-c, \-\-cwd \fIpath\fR" This option is valid in any mode except the client mode. Its used for locating libraries for an attached process which are linked with relative paths. In this case @@ -249,12 +221,12 @@ to see what can be used. This option is only available when was build with --enable-debug. .IP "\-d, \-\-depth \fIlevel\fR" Do backtrace of \fIlevel\fR stack frames for each memory allocation function. +.IP "\-e, \-\-follow-exec" +Trace processes as they are created by one of the currently traced processes as +a result of execve(2) system call. .IP "\-f, \-\-follow-fork" Trace child processes as they are created by one of the currently traced processes as a result of the fork(2) system call. -.IP "\-f, \-\-follow-exec" -Trace processes as they are created by one of the currently traced processes as -a result of execve(2) system call. .IP "\-F, \-\-config \fIpath" Set the config file. For a detailed description of this file see mtrace.conf(5). It is possible to pass several config files by passing more @@ -266,24 +238,31 @@ $XDG_CONFIG_HOME/mtrace, SYSCONFDIR/mtrace.conf, /etc/mtrace.conf .IP "\-h, \-\-help" -Show a summary of the options to mtrace and exit. +Show a summary of the options to \fBmtrace\fR and exit. .IP "\-i, \-\-interactive" Enables the interactive mode for client or when attaching to a process. See the section \fBINTERACTIVE MODE\fR to learn more about the interactive commands in this mode. .IP "\-k, \-\-kill" -Kill mtrace in case of a bookkeeping error. This options is for +Kill \fBmtrace\fR in case of a bookkeeping error. This options is intended for .B mtrace development only! -.IP "\-l, \-\-listen \fIaddr" -Listen on socket path or address in server mode. If addr begins with / or . it -will assumed a named socket, otherwise it will be passed to getaddrinfo(3), -which handles any kind of hostname, IPv4 or IPv6 addresses. +.IP "\-O, \-\-omit \fIfilename" +Do not place any dynamic memory interception breakpoints in the given file. +This is usefull when a library offers memory allocation functions which does +only forward the calls. Use of this option can improve the trace performace in +this case. It is possible to omit several files by passing more than one +\-O option. .IP "\-o, \-\-output \fIfilename" Write the trace output to the file \fIfilename\fR rather than to stderr. When passing this option the output will be written in reserve order in opposite the stderr output. So the highest value of the sort order is at the beginning of the file and the lowest at the end of the file. +.IP "\-l, \-\-logfile \fIfilename" +Use a given logfile instead of a socket connection. In trace mode all data will +be written into the logfile. In the non trace mode the data will be retrieved +from the logfile. This option can improve the performance of the trace +since the trace will be split into to different actions. .IP "\-n, \-\-nocpp" Disable the trace of C++ allocation operators. This is safe and faster for libstdc++, since this library does call malloc() and free() inside the allocation operators. @@ -294,11 +273,13 @@ It is possible to attach to several processes by passing more than one \-p option. .IP "\-P, \-\-port \fInum" Set the port number for client or server mode. The default port number is 4576. -.IP "\-s, \-\-server" -Run mtrace in server mode. This is mostly needed for remote cross architecture -trace or when running an interactive client. If no \-l and \-P option is passed -to the sever mode, the server will listen on any address using port 4576. -.IP "\-S, \-\-sortby keyword" +.IP "\-r, \-\-remote \fIaddr" +Run \fBmtrace\fR in remote mode. Use \fIaddr\fR as socket path or address. If +\fIaddr\fR begins with / or . it will assumed a named socket, otherwise it +will be passed to getaddrinfo(3), which handles any kind of hostname, IPv4 or +IPv6 addresses. If this option is passed in conjunction with -t, mtrace will be +execute in server mode, otherwise in client mode. +.IP "\-s, \-\-sortby keyword" Sort the output of the stack backtraces by keyword. Valid keywords are: .RS @@ -349,7 +330,11 @@ Sort by the pseudo time stamp counter. Each stack backtrace will get an increme Sort by number of bytes in use of all open allocations. .RE .RE -.IP "\-u \fIusername" +.IP "\-t, \-\-trace" +Run \fBmtrace\fR in trace mode. In this mode all attached processes will run under +the control of \fBmtrace\fR and all dynamic memory function calls will be traced. +If this options is not given, \fBmtrace\fR will run in client mode. +.IP "\-u, \-\-user \fIusername\fR" Run command with the userid, groupid and supplementary groups of .IR username . This option is only useful when running as root and enables the @@ -358,7 +343,7 @@ correct execution of setuid and/or setgid binaries. Be verbose and display more details about what going on. This option can be repeated for a more detailed view. .IP "\-V, \-\-version" -Show the version number of mtrace and exit. +Show the version number of \fBmtrace\fR and exit. .IP "\-w, \-\-wait" This option stops the execution of the traced processes until a client is connected to the server. So this option is only valid in server mode. @@ -481,12 +466,12 @@ Start allocation tracing. Show allocation status. .IP "stop \fIpid\fR" -Stop allocation tracing. Note that in this state the \fIscan\fR command can +Stop allocation tracing. Note that in this state a \fIscan\fR command can not performed. .SH BUGS -It only works on Linux for X86, X86_64, ARM 32 and PowerPC 32. No Hardware -Breakpoint support on ARM and PowerPC. No ARM Thumb support. See TODO file +It only works on Linux for X86, X86_64, ARM 32 and PowerPC 32. No Hardware +Breakpoint support on ARM and PowerPC. No ARM Thumb support. See TODO file for more open issues. .LP .PP @@ -505,4 +490,5 @@ See mtrace.conf(5) for details on the syntax of this file. Stefani Seibold .SH "SEE ALSO" .BR mtrace.conf(5), -.BR ptrace(2) +.BR ptrace(2), +.BR perf(1) diff --git a/options.c b/options.c index 74f32ef..ef3fd7b 100644 --- a/options.c +++ b/options.c @@ -46,16 +46,19 @@ #endif #define MIN_STACK 4 -#define MAX_STACK 128 +#define MAX_STACK 64 #define DEFAULT_STACK 15 #define DEFAULT_PORT 4576 +static char *sockdef; + struct options_t options; static struct opt_F_t *opt_F_last; static struct opt_p_t *opt_p_last; static struct opt_b_t *opt_b_last; +static struct opt_O_t *opt_O_last; static char *progname; /* Program name (`mtrace') */ @@ -74,8 +77,7 @@ static void usage(void) "\n" " -a, --autoscan scan memory on exit of a traced program\n" " -b, --binpath=path binary search path (may be repeated)\n" - " -c, --client=addr connect to socket (path or address)\n" - " -C, --cwd=path use as current working directory for traced process\n" + " -c, --cwd=path use as current working directory for traced process\n" #ifdef DEBUG " -D, --debug=MASK enable debugging (see -Dh or --debug=help)\n" " -Dh, --debug=help show help on debugging\n" @@ -86,15 +88,17 @@ static void usage(void) " -f, --follow-fork trace forked children\n" " -h, --help display this help and exit\n" " -i, --interactive interactive client mode\n" + " -O, --omit=FILE do not place breakpoint in this file\n" " -k, --kill abort mtrace on unexpected error conditon\n" - " -l, --listen listen on socket path or address in server mode\n" + " -l, --logfile use log file instead of socket connection\n" " -n, --nocpp disable trace of c++ allocation operators (faster for libstdc++)\n" " -o, --output=FILE write the trace output to file with given name\n" " -p, --pid=PID attach to the process with the process ID pid (may be repeated)\n" " -P, --port=PORT socket port (default: " STR(DEFAULT_PORT) ")\n" - " -s, --server server mode\n" - " -S, --sort-by=type sort dump by type:\n" + " -r, --remote=addr remote use address (path, address or host)\n" + " -s, --sort-by=type sort dump by type:\n" " allocations, average, bytes-leaked, leaks, stacks, total, tsc, usage\n" + " -t, --trace trace mode\n" " -u, --user=USERNAME run command with the userid, groupid of username\n" " -V, --version output version information and exit\n" " -v, --verbose verbose mode (repeat for higher verbosity)\n" @@ -228,8 +232,8 @@ static int parse_int(const char *optarg, char opt, int min, int max) { char *endptr; long int l = strtol(optarg, &endptr, 0); - if (l < min || (max != 0 && l > max) - || *optarg == 0 || *endptr != 0) { + + if (l < min || (max != 0 && l > max) || *optarg == 0 || *endptr != 0) { const char *fmt = max != 0 ? "Invalid argument to -%c: '%s'. Use integer %d..%d.\n" : "Invalid argument to -%c: '%s'. Use integer >=%d.\n"; fprintf(stderr, fmt, opt, optarg, min, max); exit(1); @@ -240,6 +244,10 @@ static int parse_int(const char *optarg, char opt, int min, int max) char **process_options(int argc, char **argv) { char *output = NULL; + char *cwd = NULL; + + if (!sockdef) + asprintf(&sockdef, "/tmp/mtrace%u.sock", getuid()); progname = argv[0]; @@ -252,15 +260,17 @@ char **process_options(int argc, char **argv) options.interactive = 0; options.verbose = 0; options.wait = 0; - options.client = NULL; + options.address = NULL; + options.trace = 0; options.server = 0; - options.listen = NULL; + options.logfile = NULL; options.user = NULL; options.command = NULL; options.cwd = -1; options.opt_p = NULL; options.opt_F = NULL; options.opt_b = NULL; + options.opt_O = NULL; options.sort_by = -1; options.debug = 0; options.kill = 0; @@ -272,9 +282,8 @@ char **process_options(int argc, char **argv) static const struct option long_options[] = { { "auto_scan", 0, 0, 'a' }, { "binpath", 1, 0, 'b' }, - { "client", 1, 0, 'c' }, { "config", 1, 0, 'F' }, - { "cwd", 1, 0, 'C' }, + { "cwd", 1, 0, 'c' }, { "debug", 1, 0, 'D' }, { "depth", 1, 0, 'd' }, { "help", 0, 0, 'h' }, @@ -282,22 +291,25 @@ char **process_options(int argc, char **argv) { "follow-exec", 0, 0, 'e' }, { "interactive", 0, 0, 'i' }, { "kill", 0, 0, 'k' }, - { "listen", 1, 0, 'l' }, + { "logfile", 1, 0, 'l' }, { "nocpp", 1, 0, 'n' }, { "output", 1, 0, 'o' }, + { "omit", 1, 0, 'O' }, { "pid", 1, 0, 'p' }, { "port", 1, 0, 'P' }, - { "server", 0, 0, 's' }, - { "sort-by", 1, 0, 'S' }, + { "remote", 1, 0, 'r' }, + { "sort-by", 1, 0, 's' }, + { "trace", 0, 0, 't' }, { "user", 1, 0, 'u' }, { "version", 0, 0, 'V' }, { "verbose", 0, 0, 'v' }, { "wait", 0, 0, 'w' }, { 0, 0, 0, 0 } }; + c = getopt_long(argc, argv, - "+aefhiknsVvw" - "b:c:C:D:F:l:o:p:P:u:d:S:", + "+aefhikLntVvw" + "b:c:d:D:F:l:o:O:p:P:r:s:u:", long_options, &option_index); @@ -328,15 +340,10 @@ char **process_options(int argc, char **argv) break; } case 'c': - options.client = optarg; + cwd = optarg; break; - case 'C': - options.cwd = open(optarg, O_RDONLY|O_DIRECTORY); - - if (options.cwd == -1) { - fprintf(stderr, "%s: `%s' %s\n", progname, optarg, strerror(errno)); - exit(1); - } + case 'd': + options.bt_depth = parse_int(optarg, 'd', 1, 0); break; case 'D': { @@ -354,28 +361,52 @@ char **process_options(int argc, char **argv) #endif break; } + case 'e': + options.follow_exec = 1; + break; case 'f': options.follow = 1; break; case 'F': - if (add_opt_F(strdup(optarg)) == -1) { + if (add_opt_F(optarg) == -1) { fprintf(stderr, "config file not found %s\n", optarg); exit(1); } break; case 'h': - usage(); exit(0); case 'i': options.interactive = 1; break; + case 'k': + options.kill = 1; + break; case 'l': - options.listen = optarg; + options.logfile = optarg; break; case 'o': output = optarg; break; + case 'O': + { + struct opt_O_t *tmp = malloc(sizeof(*tmp)); + + if (!tmp) { + fprintf(stderr, "%s\n", strerror(errno)); + exit(1); + } + tmp->pathname = strdup(optarg); + tmp->next = NULL; + + if (opt_O_last) + opt_O_last->next = tmp; + opt_O_last = tmp; + + if (!options.opt_O) + options.opt_O = tmp; + break; + } case 'n': options.nocpp = 1; break; @@ -401,37 +432,10 @@ char **process_options(int argc, char **argv) case 'P': options.port = optarg; break; - case 'u': - options.user = optarg; - break; - case 'V': - printf("mtrace version " PACKAGE_VERSION ".\n" - "Copyright (C) 2015 Stefani Seibold .\n" - "\n" - "This software was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany.\n" - "\n" - "This is free software; see the GNU General Public Licence\n" - "version 2 or later for copying conditions. There is NO warranty.\n"); - exit(0); - case 'd': - options.bt_depth = parse_int(optarg, 'd', 1, 0); - break; - case 'e': - options.follow_exec = 1; - break; - case 'k': - options.kill = 1; - break; - case 'v': - options.verbose++; - break; - case 'w': - options.wait = 1; + case 'r': + options.address = optarg; break; case 's': - options.server = 1; - break; - case 'S': if (!strncmp(optarg, "allocations", 2)) options.sort_by = OPT_SORT_ALLOCATIONS; else @@ -460,6 +464,27 @@ char **process_options(int argc, char **argv) exit(1); } break; + case 't': + options.trace = 1; + break; + case 'u': + options.user = optarg; + break; + case 'V': + printf("mtrace version " PACKAGE_VERSION ".\n" + "Copyright (C) 2015 Stefani Seibold .\n" + "\n" + "This software was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany.\n" + "\n" + "This is free software; see the GNU General Public Licence\n" + "version 2 or later for copying conditions. There is NO warranty.\n"); + exit(0); + case 'v': + options.verbose++; + break; + case 'w': + options.wait = 1; + break; default: err_usage(); } @@ -471,68 +496,118 @@ char **process_options(int argc, char **argv) if (argc > 0) options.command = search_for_command(argv[0]); - if (options.sort_by == OPT_SORT_LEAKS || options.sort_by == OPT_SORT_BYTES_LEAKED) - options.auto_scan = 1; - if (!options.client && !options.opt_p && argc < 1) { - fprintf(stderr, "%s: too few arguments\n", progname); + if (options.address && options.logfile) { + fprintf(stderr, "%s: either logfile or remote address is valid\n", progname); err_usage(); } - if (!options.server && options.listen) { - fprintf(stderr, "%s: listen mode can only valid in server mode\n", progname); - err_usage(); - } + if (options.trace) { + if (!options.opt_p && !options.command) { + fprintf(stderr, "%s: trace requires -p or executable\n", progname); + err_usage(); + } - if (options.client && (options.opt_p || argc > 0)) { - fprintf(stderr, "%s: client mode does not require -p nor executable\n", progname); - err_usage(); - } + if (options.auto_scan) { + fprintf(stderr, "%s: scan option can not passed in when trace mode\n", progname); + err_usage(); + } - if (options.client && options.nocpp) { - fprintf(stderr, "%s: client mode does not require -n\n", progname); - err_usage(); - } + if (options.sort_by != -1) { + fprintf(stderr, "%s: sort-by can not passed in trace mode\n", progname); + err_usage(); + } - if (options.client && options.server) { - fprintf(stderr, "%s: choose between client and server mode\n", progname); - err_usage(); - } + if (options.opt_b) { + fprintf(stderr, "%s: binpath can only used in client mode\n", progname); + err_usage(); + } - if (options.opt_b && !options.client) { - fprintf(stderr, "%s: binpath can only used in client mode\n", progname); - err_usage(); + if (options.address) { + if (!strcmp(options.address, ".")) + options.address = sockdef; + + options.server = 1; + } + } + else { + if (options.opt_p || options.command) { + fprintf(stderr, "%s: client mode does not require -p nor executable\n", progname); + err_usage(); + } + + if (options.nocpp) { + fprintf(stderr, "%s: client mode does not require -n\n", progname); + err_usage(); + } + + if (options.user) { + fprintf(stderr, "%s: user can only passed in trace mode\n", progname); + err_usage(); + } + + if (!options.address) + options.address = sockdef; } if (options.interactive) { - if ((!options.client && !options.opt_p) || options.command) { - fprintf(stderr, "%s: interactive mode can only invoked in -p or -c mode\n", progname); + if (options.server) { + fprintf(stderr, "%s: interactive mode not available in server mode\n", progname); err_usage(); } - output = NULL; - if (options.auto_scan) + if (options.trace) { + if (options.command) { + fprintf(stderr, "%s: cannot execute process and interactive console at the same time in trace mode\n", progname); + err_usage(); + } + + if (!options.opt_p) { + fprintf(stderr, "%s: interactive console requieres -p in trace mode\n", progname); + err_usage(); + } + } + + + if (options.auto_scan) { fprintf(stderr, "%s: auto scan ignored in interactive mode\n", progname); + options.auto_scan = 0; + } + + if (options.sort_by != -1) { + fprintf(stderr, "%s: sort-by ignored in interactive mode\n", progname); + options.sort_by = -1; + } } - if (options.auto_scan && options.server) { - fprintf(stderr, "%s: scan option can not passed in -s mode\n", progname); - err_usage(); + if (output) { + if (options.interactive) { + fprintf(stderr, "%s: output not valid in interactive mode\n", progname); + err_usage(); + } + + if (options.logfile) { + fprintf(stderr, "%s: either logfile or output is valid\n", progname); + err_usage(); + } + + if (options.server) { + fprintf(stderr, "%s: output not valid in server mode\n", progname); + err_usage(); + } } if (options.port) { - if (!options.client && !options.server) { - fprintf(stderr, "%s: Port only valid in client or server mode \n", progname); + if (!options.address) { + fprintf(stderr, "%s: port only valid in client or trace mode\n", progname); err_usage(); } } else options.port = STR(DEFAULT_PORT); - if (options.sort_by != -1 && options.server) { - fprintf(stderr, "%s: sort-by can not passed in -s mode\n", progname); - err_usage(); - } + if (options.sort_by == OPT_SORT_LEAKS || options.sort_by == OPT_SORT_BYTES_LEAKED) + options.auto_scan = 1; if (options.bt_depth < MIN_STACK) options.bt_depth = MIN_STACK; @@ -554,6 +629,15 @@ char **process_options(int argc, char **argv) fcntl(fileno(options.output), F_SETFD, FD_CLOEXEC); } + if (cwd) { + options.cwd = open(cwd, O_RDONLY|O_DIRECTORY); + + if (options.cwd == -1) { + fprintf(stderr, "%s: `%s' %s\n", progname, optarg, strerror(errno)); + exit(1); + } + } + return &argv[0]; } diff --git a/options.h b/options.h index e61a7fe..b67e93b 100644 --- a/options.h +++ b/options.h @@ -55,6 +55,11 @@ struct opt_b_t { struct opt_b_t *next; }; +struct opt_O_t { + char *pathname; + struct opt_O_t *next; +}; + struct options_t { int auto_scan; /* scan memory on every exit of a trace program */ int bt_depth; /* how may levels of stack frames to show */ @@ -62,10 +67,11 @@ struct options_t { int follow_exec; /* follow exec system calls */ int interactive; /* interactive mode */ FILE *output; /* output to a specific file */ - int server; /* server mode flag */ + int trace; /* trace mode flag */ int kill; /* kill on errors */ - char *listen; /* server listen on socket path or address */ - char *client; /* connect to socket path or address */ + int server; /* true for server listen */ + char *logfile; /* logfile path */ + char *address; /* connect to socket path or address */ char *user; /* -u: username to run command as */ int verbose; /* verbose mode */ int wait; /* wait for client connection */ @@ -75,6 +81,7 @@ struct options_t { struct opt_p_t *opt_p; /* attach to process with a given pid */ struct opt_F_t *opt_F; /* alternate configuration file(s) */ struct opt_b_t *opt_b; /* binary search path(s) */ + struct opt_O_t *opt_O; /* omits path list */ int sort_by; /* sort dump in non interative and non server mode */ int debug; /* debug */ int nocpp; /* disable trace of c++ allocation operators */ diff --git a/report.c b/report.c index 7132354..0f95964 100644 --- a/report.c +++ b/report.c @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include #include "backend.h" #include "backtrace.h" @@ -38,25 +41,32 @@ #include "task.h" #include "trace.h" -static int report_alloc64(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth) +static int report_alloc64(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, unsigned int depth, struct library_symbol *libsym) { - int i = 0; + unsigned int i = 0; struct mt_alloc_payload_64 *alloc = alloca(sizeof(*alloc) + depth * sizeof(uint64_t)); alloc->ptr = (uint64_t)ptr; alloc->size = (uint64_t)size; - if (depth && backtrace_init_unwind(task) >= 0) { - do { - alloc->data[i] = (uint64_t)backtrace_get_ip(task); - if (!alloc->data[i]) - break; + if (depth) { + alloc->data[i++] = libsym->addr; - ++i; + if (backtrace_init_unwind(task) >= 0) { + while(i < depth) { + if (backtrace_location_type(task) != LIBTYPE_LOADER) { + alloc->data[i] = (uint64_t)backtrace_get_ip(task); - if (backtrace_step(task) < 0) - break; - } while(i < depth); + if (!alloc->data[i]) + break; + + ++i; + } + + if (backtrace_step(task) < 0) + break; + } + } } skip_breakpoint(task, task->event.e_un.breakpoint); @@ -64,7 +74,7 @@ static int report_alloc64(struct task *task, enum mt_operation op, unsigned long return server_send_msg(op, task->leader->pid, task->pid, alloc, sizeof(*alloc) + i * sizeof(uint64_t)); } -static int report_alloc32(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth) +static int report_alloc32(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth, struct library_symbol *libsym) { int i = 0; struct mt_alloc_payload_32 *alloc = alloca(sizeof(*alloc) + depth * sizeof(uint32_t)); @@ -72,17 +82,24 @@ static int report_alloc32(struct task *task, enum mt_operation op, unsigned long alloc->ptr = (uint32_t)ptr; alloc->size = (uint32_t)size; - if (depth && backtrace_init_unwind(task) >= 0) { - do { - alloc->data[i] = (uint32_t)backtrace_get_ip(task); - if (!alloc->data[i]) - break; + if (depth) { + alloc->data[i++] = libsym->addr; - ++i; + if (backtrace_init_unwind(task) >= 0) { + while(i < depth) { + if (backtrace_location_type(task) != LIBTYPE_LOADER) { + alloc->data[i] = (uint32_t)backtrace_get_ip(task); - if (backtrace_step(task) < 0) - break; - } while(i < depth); + if (!alloc->data[i]) + break; + + ++i; + } + + if (backtrace_step(task) < 0) + break; + } + } } skip_breakpoint(task, task->event.e_un.breakpoint); @@ -90,7 +107,7 @@ static int report_alloc32(struct task *task, enum mt_operation op, unsigned long return server_send_msg(op, task->leader->pid, task->pid, alloc, sizeof(*alloc) + i * sizeof(uint32_t)); } -static int report_alloc(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth) +static int report_alloc(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth, struct library_symbol *libsym) { if (!ptr) return 0; @@ -101,9 +118,9 @@ static int report_alloc(struct task *task, enum mt_operation op, unsigned long p debug(DEBUG_FUNCTION, "%d [%d]: %#lx %lu", op, task->pid, ptr, size); if (task_is_64bit(task)) - return report_alloc64(task, op, ptr, size, depth); + return report_alloc64(task, op, ptr, size, depth, libsym); else - return report_alloc32(task, op, ptr, size, depth); + return report_alloc32(task, op, ptr, size, depth, libsym); } static int _null(struct task *task, struct library_symbol *libsym) @@ -119,7 +136,7 @@ static int _report_malloc(struct task *task, struct library_symbol *libsym) unsigned long size = fetch_param(task, 0); unsigned long ret = fetch_retval(task); - return report_alloc(task, MT_MALLOC, ret, size, options.bt_depth); + return report_alloc(task, MT_MALLOC, ret, size, options.bt_depth, libsym); } static int report_free(struct task *task, struct library_symbol *libsym) @@ -129,7 +146,7 @@ static int report_free(struct task *task, struct library_symbol *libsym) unsigned long addr = fetch_param(task, 0); - return report_alloc(task, MT_FREE, addr, 0, 0); + return report_alloc(task, MT_FREE, addr, 0, 0, libsym); } static int _report_realloc(struct task *task, struct library_symbol *libsym) @@ -142,9 +159,9 @@ static int _report_realloc(struct task *task, struct library_symbol *libsym) unsigned long ret = fetch_retval(task); if (ret) - return report_alloc(task, MT_REALLOC, ret, size, options.bt_depth); + return report_alloc(task, MT_REALLOC, ret, size, options.bt_depth, libsym); else - return report_alloc(task, MT_REALLOC_FAILED, addr, 1, options.bt_depth); + return report_alloc(task, MT_REALLOC_FAILED, addr, 1, options.bt_depth, libsym); } static int report_realloc(struct task *task, struct library_symbol *libsym) @@ -155,7 +172,7 @@ static int report_realloc(struct task *task, struct library_symbol *libsym) unsigned long addr = fetch_param(task, 0); unsigned long size = fetch_param(task, 1); - return report_alloc(task, MT_REALLOC_ENTER, addr, size, options.bt_depth); + return report_alloc(task, MT_REALLOC_ENTER, addr, size, options.bt_depth, libsym); } static int _report_calloc(struct task *task, struct library_symbol *libsym) @@ -166,7 +183,7 @@ static int _report_calloc(struct task *task, struct library_symbol *libsym) unsigned long size = fetch_param(task, 0) * fetch_param(task, 1); unsigned long ret = fetch_retval(task); - return report_alloc(task, MT_MALLOC, ret, size, options.bt_depth); + return report_alloc(task, MT_MALLOC, ret, size, options.bt_depth, libsym); } static int _report_mmap(struct task *task, struct library_symbol *libsym) @@ -181,7 +198,7 @@ static int _report_mmap(struct task *task, struct library_symbol *libsym) unsigned long size = fetch_param(task, 1); - return report_alloc(task, MT_MMAP, ret, size, options.bt_depth); + return report_alloc(task, MT_MMAP, ret, size, options.bt_depth, libsym); } static int _report_mmap64(struct task *task, struct library_symbol *libsym) @@ -211,7 +228,7 @@ static int _report_mmap64(struct task *task, struct library_symbol *libsym) else size.l = fetch_param(task, 1); - return report_alloc(task, MT_MMAP64, ret, size.l, options.bt_depth); + return report_alloc(task, MT_MMAP64, ret, size.l, options.bt_depth, libsym); } static int report_munmap(struct task *task, struct library_symbol *libsym) @@ -222,7 +239,7 @@ static int report_munmap(struct task *task, struct library_symbol *libsym) unsigned long addr = fetch_param(task, 0); unsigned long size = fetch_param(task, 1); - return report_alloc(task, MT_MUNMAP, addr, size, 0); + return report_alloc(task, MT_MUNMAP, addr, size, 0, libsym); } static int _report_memalign(struct task *task, struct library_symbol *libsym) @@ -233,7 +250,7 @@ static int _report_memalign(struct task *task, struct library_symbol *libsym) unsigned long size = fetch_param(task, 1); unsigned long ret = fetch_retval(task); - return report_alloc(task, MT_MEMALIGN, ret, size, options.bt_depth); + return report_alloc(task, MT_MEMALIGN, ret, size, options.bt_depth, libsym); } static int _report_posix_memalign(struct task *task, struct library_symbol *libsym) @@ -260,7 +277,7 @@ static int _report_posix_memalign(struct task *task, struct library_symbol *libs new_ptr = tmp; } - return report_alloc(task, MT_POSIX_MEMALIGN, new_ptr, size, options.bt_depth); + return report_alloc(task, MT_POSIX_MEMALIGN, new_ptr, size, options.bt_depth, libsym); } static int _report_aligned_alloc(struct task *task, struct library_symbol *libsym) @@ -271,7 +288,7 @@ static int _report_aligned_alloc(struct task *task, struct library_symbol *libsy unsigned long size = fetch_param(task, 1); unsigned long ret = fetch_retval(task); - return report_alloc(task, MT_ALIGNED_ALLOC, ret, size, options.bt_depth); + return report_alloc(task, MT_ALIGNED_ALLOC, ret, size, options.bt_depth, libsym); } static int _report_valloc(struct task *task, struct library_symbol *libsym) @@ -282,7 +299,7 @@ static int _report_valloc(struct task *task, struct library_symbol *libsym) unsigned long size = fetch_param(task, 0); unsigned long ret = fetch_retval(task); - return report_alloc(task, MT_VALLOC, ret, size, options.bt_depth); + return report_alloc(task, MT_VALLOC, ret, size, options.bt_depth, libsym); } static int _report_pvalloc(struct task *task, struct library_symbol *libsym) @@ -293,7 +310,7 @@ static int _report_pvalloc(struct task *task, struct library_symbol *libsym) unsigned long size = fetch_param(task, 0); unsigned long ret = fetch_retval(task); - return report_alloc(task, MT_PVALLOC, ret, size, options.bt_depth); + return report_alloc(task, MT_PVALLOC, ret, size, options.bt_depth, libsym); } static int report_mremap(struct task *task, struct library_symbol *libsym) @@ -301,7 +318,7 @@ static int report_mremap(struct task *task, struct library_symbol *libsym) unsigned long addr = fetch_param(task, 0); unsigned long size = fetch_param(task, 1); - return report_alloc(task, MT_MUNMAP, addr, size, 0); + return report_alloc(task, MT_MUNMAP, addr, size, 0, libsym); } static int _report_mremap(struct task *task, struct library_symbol *libsym) @@ -309,33 +326,33 @@ static int _report_mremap(struct task *task, struct library_symbol *libsym) unsigned long size = fetch_param(task, 2); unsigned long ret = fetch_retval(task); - return report_alloc(task, MT_MMAP, ret, size, options.bt_depth); + return report_alloc(task, MT_MMAP, ret, size, options.bt_depth, libsym); } static const struct function flist[] = { - { "malloc", 0, 2, NULL, _report_malloc }, - { "free", 0, 3, report_free, NULL }, - { "realloc", 0, 4, report_realloc, _report_realloc }, - { "calloc", 0, 5, NULL, _report_calloc }, - { "posix_memalign", 0, 6, NULL, _report_posix_memalign }, - { "mmap", 0, 7, NULL, _report_mmap }, - { "mmap64", 1, 8, NULL, _report_mmap64 }, - { "munmap", 0, 9, report_munmap, _null }, - { "memalign", 0, 10, NULL, _report_memalign }, - { "aligned_alloc", 1, 11, NULL, _report_aligned_alloc }, - { "valloc", 1, 12, NULL, _report_valloc }, - { "pvalloc", 1, 13, NULL, _report_pvalloc }, - { "mremap", 0, 14, report_mremap, _report_mremap }, - { "cfree", 1, 15, report_free, NULL }, + { "malloc", "malloc", 0, NULL, _report_malloc }, + { "free", "free", 0, report_free, NULL }, + { "realloc", "realloc", 0, report_realloc, _report_realloc }, + { "calloc", "calloc", 0, NULL, _report_calloc }, + { "posix_memalign", "posix_memalign", 0, NULL, _report_posix_memalign }, + { "mmap", "mmap", 0, NULL, _report_mmap }, + { "mmap64", "mmap64", 1, NULL, _report_mmap64 }, + { "munmap", "munmap", 0, report_munmap, _null }, + { "memalign", "memalign", 0, NULL, _report_memalign }, + { "aligned_alloc", "aligned_alloc", 1, NULL, _report_aligned_alloc }, + { "valloc", "valloc", 1, NULL, _report_valloc }, + { "pvalloc", "pvalloc", 1, NULL, _report_pvalloc }, + { "mremap", "mremap", 0, report_mremap, _report_mremap }, + { "cfree", "cfree", 1, report_free, NULL }, - { "_Znwm", 1, 17, NULL, _report_malloc }, /* operator new(unsigned long) */ - { "_Znam", 1, 18, NULL, _report_malloc }, /* operator new[](unsigned long) */ - { "_ZnwmRKSt9nothrow_t", 1, 19, NULL, _report_malloc }, /* operator new(unsigned long, std::nothrow_t const&) */ - { "_ZnamRKSt9nothrow_t", 1, 20, NULL, _report_malloc }, /* operator new[](unsigned long, std::nothrow_t const& */ - { "_ZdlPv", 1, 21, report_free, NULL }, /* operator delete(void*) */ - { "_ZdaPv", 1, 22, report_free, NULL }, /* operator delete[](void*) */ - { "_ZdlPvRKSt9nothrow_t", 1, 23, report_free, NULL }, /* operator delete(void*, std::nothrow_t const&) */ - { "_ZdaPvRKSt9nothrow_t", 1, 24, report_free, NULL }, /* operator delete[](void*, std::nothrow_t const&) */ + { "new(unsigned long)", "_Znwm", 1, NULL, _report_malloc }, + { "new[](unsigned long)", "_Znam", 1, NULL, _report_malloc }, + { "new(unsigned long, std::nothrow_t const&)", "_ZnwmRKSt9nothrow_t", 1, NULL, _report_malloc }, + { "new[](unsigned long, std::nothrow_t const&)", "_ZnamRKSt9nothrow_t", 1, NULL, _report_malloc }, + { "delete(void*)", "_ZdlPv", 1, report_free, NULL }, + { "delete[](void*)", "_ZdaPv", 1, report_free, NULL }, + { "delete(void*, std::nothrow_t const&)", "_ZdlPvRKSt9nothrow_t", 1, report_free, NULL }, + { "delete[](void*, std::nothrow_t const&)", "_ZdaPvRKSt9nothrow_t", 1, report_free, NULL }, }; const struct function *flist_matches_symbol(const char *sym_name) @@ -354,14 +371,14 @@ const struct function *flist_matches_symbol(const char *sym_name) int _report_map(struct task *task, struct library *lib, enum mt_operation op) { - size_t len = strlen(lib->filename) + 1; + struct libref *libref = lib->libref; + size_t len = strlen(libref->filename) + 1; struct mt_map_payload *payload = alloca(sizeof(struct mt_map_payload) + len); + payload->addr = libref->load_addr; + payload->offset = libref->load_offset; + payload->size = libref->load_size; - payload->addr = lib->load_addr; - payload->offset = lib->load_offset; - payload->size = lib->load_size; - - memcpy(payload->filename, lib->filename, len); + memcpy(payload->filename, libref->filename, len); return server_send_msg(op, task->pid, 0, payload, sizeof(struct mt_map_payload) + len); } diff --git a/report.h b/report.h index 13094c5..09345b6 100644 --- a/report.h +++ b/report.h @@ -26,12 +26,12 @@ #include "forward.h" struct function { + /* symbol name */ + const char *demangled_name; /* symbol name */ const char *name; /* level for aliased symbol */ unsigned int level; - /* minimum number of hw breakpoints for using a hw bp */ - unsigned int hw_bp_min; /* report when function is entered */ int (*report_in)(struct task *task, struct library_symbol *libsym); /* report when function is exited */ diff --git a/server.c b/server.c index ea60a59..51e7a79 100644 --- a/server.c +++ b/server.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "backend.h" #include "breakpoint.h" @@ -83,10 +84,13 @@ int server_connected(void) static void server_close(void) { if (server_connected()) { - shutdown(server_fd, SHUT_RDWR); + if (!options.logfile) + shutdown(server_fd, SHUT_RDWR); + close(server_fd); server_fd = -1; each_process(&stop_trace); + each_pid(&fix_about_exit); } } @@ -94,10 +98,11 @@ int server_poll(void) { int ret = 0; + if (command_pending) { ret = server_handle_command(); - if (options.server) + if (options.trace) ret = 0; command_pending = 0; @@ -119,10 +124,15 @@ int server_handle_command(void) { int ret; struct mt_msg cmd; - void *payload = NULL; + void *payload; struct task *task; - unsigned int mode = server_mode; + unsigned int mode; + if (options.logfile) + return -1; + + payload = NULL; + mode = server_mode; server_mode = MODE_NONE; switch(mode) { @@ -154,7 +164,7 @@ int server_handle_command(void) } server_close(); - return options.server ? 0: -1; + return options.trace ? 0: -1; } if (cmd.payload_len) { @@ -250,27 +260,25 @@ int server_start(void) if (!thread) return -1; - listen_fd = bind_to(options.listen, options.port); + server_mode = MODE_NONE; + + listen_fd = bind_to(options.address, options.port); if (listen_fd < 0) - fatal("colud not bind socket: %s:%s", options.listen, options.port); + fatal("could not bind socket: %s", options.address); if (listen(listen_fd, 1) < 0) fatal("listen (%s)", strerror(errno)); if (options.wait) { - fprintf(stderr, "waiting for client connection...\n"); + fprintf(stderr, "waiting for client connection... "); server_fd = TEMP_FAILURE_RETRY(accept(listen_fd, NULL, 0)); if (server_fd < 0) fatal("accept (%s)", strerror(errno)); + fprintf(stderr, "connected!\n"); + server_mode = MODE_ACCEPTED; report_info(1); - report_processes(); - - each_process(&start_trace); - } - else { - each_process(&stop_trace); } sem_init(&sem, 0, 1); @@ -308,6 +316,9 @@ int server_start_pair(void) { int sv[2]; + server_mode = MODE_NONE; + listen_fd = -1; + thread = thread_new(); if (!thread) return -1; @@ -332,20 +343,45 @@ int server_start_pair(void) int server_send_msg(enum mt_operation op, uint32_t pid, uint32_t tid, const void *payload, unsigned int payload_len) { + if (options.logfile) { + struct iovec io[2]; + struct mt_msg mt_msg; + int ret; + + mt_msg.operation = op; + mt_msg.pid = pid; + mt_msg.tid = tid; + mt_msg.payload_len = payload_len; + + io[0].iov_base = &mt_msg; + io[0].iov_len = sizeof(mt_msg); + + io[1].iov_base = (void *)payload; + io[1].iov_len = payload_len; + + ret = writev(server_fd, io, ARRAY_SIZE(io)); + + if ((size_t)ret != io[0].iov_len + io[1].iov_len) + return -1; + + return ret; + } + return sock_send_msg(server_fd, op, pid, tid, payload, payload_len); } int server_stop(void) { - thread_cancel(thread); - if (thread) - thread_join(thread); - server_close(); if (listen_fd != -1) { - if (is_named(options.listen)) - unlink(options.listen); + thread_cancel(thread); + if (thread) + thread_join(thread); + + if (is_named(options.address)) + unlink(options.address); + close(listen_fd); listen_fd = -1; } @@ -353,3 +389,14 @@ int server_stop(void) return 0; } +int server_logfile(void) +{ + listen_fd = -1; + + server_fd = open(options.logfile, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR); + if (server_fd == -1) + fatal("could not open logfile: %s", options.logfile); + + return 0; +} + diff --git a/server.h b/server.h index 33f8e34..9bb49cf 100644 --- a/server.h +++ b/server.h @@ -34,6 +34,7 @@ int server_handle_command(void); int server_connected(void); int server_stop(void); int server_poll(void); +int server_logfile(void); #endif diff --git a/sysdeps/linux-gnu/arm/dwarf-arm.c b/sysdeps/linux-gnu/arm/dwarf-arm.c index 994d2db..b9255f6 100644 --- a/sysdeps/linux-gnu/arm/dwarf-arm.c +++ b/sysdeps/linux-gnu/arm/dwarf-arm.c @@ -176,12 +176,12 @@ static inline int access_mem(struct dwarf_addr_space *as, arch_addr_t addr, void #ifdef DEBUG if (as) { struct dwarf_cursor *c = &as->cursor; - struct library *lib = c->lib; + struct libref *libref = c->libref; - if (addr < ARCH_ADDR_T(lib->image_addr)) - fatal("invalid access mem: addr %#lx < %p", addr, lib->image_addr); - if (addr >= ARCH_ADDR_T(lib->image_addr + lib->load_size)) - fatal("invalid access mem: addr %#lx >= %p", addr, lib->image_addr + lib->load_size); + if (addr < ARCH_ADDR_T(libref->image_addr)) + fatal("invalid access mem: addr %#lx < %p", addr, libref->image_addr); + if (addr >= ARCH_ADDR_T(libref->image_addr + libref->load_size)) + fatal("invalid access mem: addr %#lx >= %p", addr, libref->image_addr + libref->load_size); } #endif @@ -506,8 +506,8 @@ static int arm_exidx_extract(struct dwarf_addr_space *as, arch_addr_t entry, uin static unsigned long arm_search_unwind_table(struct dwarf_addr_space *as, arch_addr_t ip, void *exidx_data, unsigned long exidx_len) { struct dwarf_cursor *c = &as->cursor; - struct library *lib = c->lib; - unsigned long map_offset = (unsigned long)lib->image_addr + lib->load_offset - lib->load_addr; + struct libref *libref = c->libref; + unsigned long map_offset = (unsigned long)libref->image_addr + libref->load_offset - libref->load_addr; unsigned long lo, hi, e, f; arch_addr_t val; @@ -542,12 +542,12 @@ static unsigned long arm_search_unwind_table(struct dwarf_addr_space *as, arch_a static int arm_exidx_step(struct dwarf_addr_space *as) { struct dwarf_cursor *c = &as->cursor; - struct library *lib = c->lib; + struct libref *libref = c->libref; arch_addr_t old_ip, old_cfa, entry; uint8_t buf[32]; int ret; - if (!lib) + if (!libref) return -DWARF_ENOINFO; old_ip = c->ip; @@ -556,7 +556,7 @@ static int arm_exidx_step(struct dwarf_addr_space *as) /* mark PC unsaved */ c->loc[DWARF_ARM_PC] = DWARF_NULL_LOC; - entry = arm_search_unwind_table(as, c->ip, lib->exidx_data, lib->exidx_len); + entry = arm_search_unwind_table(as, c->ip, libref->exidx_data, libref->exidx_len); if (!entry) return -DWARF_ENOINFO; @@ -646,3 +646,8 @@ int dwarf_arch_step(struct dwarf_addr_space *as) return -DWARF_EBADFRAME; } +int dwarf_arch_check_call(struct dwarf_addr_space *as, arch_addr_t ip) +{ + return 1; +} + diff --git a/sysdeps/linux-gnu/backtrace.c b/sysdeps/linux-gnu/backtrace.c index d3da710..f35fb66 100644 --- a/sysdeps/linux-gnu/backtrace.c +++ b/sysdeps/linux-gnu/backtrace.c @@ -72,3 +72,11 @@ int backtrace_step(struct task *task) return dwarf_step(task->leader->backtrace); } +int backtrace_location_type(struct task *task) +{ + assert(task->leader); + assert(task->leader->backtrace); + + return dwarf_location_type(task->leader->backtrace); +} + diff --git a/sysdeps/linux-gnu/ioevent.c b/sysdeps/linux-gnu/ioevent.c index c7ce9ea..fac26d2 100644 --- a/sysdeps/linux-gnu/ioevent.c +++ b/sysdeps/linux-gnu/ioevent.c @@ -24,6 +24,7 @@ #include #include +#include #include #include diff --git a/sysdeps/linux-gnu/ppc/dwarf-ppc.c b/sysdeps/linux-gnu/ppc/dwarf-ppc.c index 7d91547..00dc3c7 100644 --- a/sysdeps/linux-gnu/ppc/dwarf-ppc.c +++ b/sysdeps/linux-gnu/ppc/dwarf-ppc.c @@ -269,3 +269,8 @@ unsigned int dwarf_to_regnum(unsigned int num) return ~0; } +int dwarf_arch_check_call(struct dwarf_addr_space *as, arch_addr_t ip) +{ + return 1; +} + diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c index 049a3a5..b35df92 100644 --- a/sysdeps/linux-gnu/proc.c +++ b/sysdeps/linux-gnu/proc.c @@ -413,22 +413,22 @@ static void linkmap_add(struct task *task, struct lt_r_debug_64 *dbg) ) continue; - struct library *lib = library_new(); + struct libref *libref = libref_new(LIBTYPE_LIB); - if (!lib) { + if (!libref) { fprintf(stderr, "Couldn't instance library object %s\n", lib_name); continue; } - if (elf_read_library(task, lib, lib_name, rlm.l_addr) < 0) { - library_destroy(task, lib); + if (elf_read_library(task, libref, lib_name, rlm.l_addr) < 0) { + libref_delete(libref); fprintf(stderr, "Couldn't load ELF object %s\n", lib_name); continue; } - lib->key = ARCH_ADDR_T(rlm.l_addr); + libref->key = ARCH_ADDR_T(rlm.l_addr); - library_add(task, lib); + library_add(task, libref); } return; diff --git a/sysdeps/linux-gnu/socket.c b/sysdeps/linux-gnu/socket.c index 4e859c7..b30edac 100644 --- a/sysdeps/linux-gnu/socket.c +++ b/sysdeps/linux-gnu/socket.c @@ -113,13 +113,16 @@ int sock_send_msg(int fd, enum mt_operation op, uint32_t pid, uint32_t tid, cons return ret; } -static int sock_unix(const char *path, struct sock_u_descr *descr) +static int sock_unix(const char *path, struct sock_u_descr *descr, int create) { struct stat statbuf; if (stat(path, &statbuf) >= 0) { if (!S_ISSOCK(statbuf.st_mode)) return -1; + + if (create) + unlink(path); } descr->addr.sun_family = AF_UNIX; @@ -160,7 +163,7 @@ int connect_to(const char *node, const char *service) if (*node == '/' || *node == '.') { struct sock_u_descr descr; - sfd = sock_unix(node, &descr); + sfd = sock_unix(node, &descr, 0); if (sfd == -1) return -1; @@ -201,7 +204,7 @@ int bind_to(const char *node, const char *service) if (is_named(node)) { struct sock_u_descr descr; - sfd = sock_unix(node, &descr); + sfd = sock_unix(node, &descr, 1); if (sfd == -1) return -1; @@ -218,6 +221,9 @@ int bind_to(const char *node, const char *service) if (sfd == -1) continue; + if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1))) + fatal("setsockopt (%s)", strerror(errno)); + if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) break; @@ -228,9 +234,6 @@ int bind_to(const char *node, const char *service) return -1; } - if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1))) - fatal("setsockopt (%s)", strerror(errno)); - return sfd; } diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c index 314deb4..2d77dfe 100644 --- a/sysdeps/linux-gnu/trace.c +++ b/sysdeps/linux-gnu/trace.c @@ -37,6 +37,7 @@ #include #include #include +#include #ifdef HAVE_LIBSELINUX #include @@ -124,7 +125,7 @@ static int child_event(struct task *task, enum event_type ev) int pid = data; if (!pid2task(pid)) { - struct task *child = task_new(pid, 0); + struct task *child = task_new(pid); if (!child) return -1; @@ -235,7 +236,7 @@ static void process_event(struct task *task, int status) if (stop_signal == 0) return; - if (stop_signal != SIGTRAP && stop_signal != SIGSEGV && stop_signal != SIGILL) + if (stop_signal != SIGTRAP) return; if (fetch_context(task) == -1) { @@ -251,14 +252,15 @@ static void process_event(struct task *task, int status) for(i = 0; i < HW_BREAKPOINTS; ++i) { if (task->hw_bp[i] && task->hw_bp[i]->addr == ip) { - /* todo: check if this was really a hw bp */ - bp = task->hw_bp[i]; + if (get_hw_bp_state(task, i)) + bp = task->hw_bp[i]; + break; } } if (bp) { - assert(bp->type != SW_BP); + assert(bp->type != BP_SW); assert(bp->hw_bp_slot == i); if (options.verbose > 1) @@ -268,9 +270,15 @@ static void process_event(struct task *task, int status) #endif { bp = breakpoint_find(leader, ip - DECR_PC_AFTER_BREAK); - if (!bp) + if (!bp) { + task->event.type = EVENT_NONE; + continue_task(task, 0); return; - assert(bp->type == SW_BP); + } +#if HW_BREAKPOINTS > 0 + assert(bp->type != BP_HW_SCRATCH); + assert(bp->hw == 0); +#endif if (options.verbose > 1) ++leader->num_sw_bp; @@ -284,7 +292,7 @@ static void process_event(struct task *task, int status) return; #endif task->event.type = EVENT_BREAKPOINT; - task->event.e_un.breakpoint = breakpoint_ref(bp); + task->event.e_un.breakpoint = breakpoint_get(bp); debug(DEBUG_EVENT, "BREAKPOINT: pid=%d, addr=%#lx", task->pid, task->event.e_un.breakpoint->addr); @@ -344,7 +352,6 @@ int untrace_task(struct task *task, int signum) fprintf(stderr, "PTRACE_SETOPTIONS pid=%d %s\n", task->pid, strerror(errno)); ret = -1; goto skip; - } signum = fix_signal(task, signum); @@ -525,7 +532,7 @@ struct task *wait_event(void) task = pid2task(pid); if (!task) { - task = task_new(pid, 0); + task = task_new(pid); if (task) trace_setup(task, status, SIGSTOP); @@ -552,16 +559,53 @@ void wait_event_wakeup(void) pthread_mutex_unlock(&mutex); } +#ifndef HAVE_PROCESS_VM_READV +static ssize_t process_vm_readv(pid_t pid, const struct iovec *local_iov, unsigned long liovcnt, const struct iovec *remote_iov, unsigned long riovcnt, unsigned long flags) +{ +#ifdef __NR_process_vm_readv + return syscall(__NR_process_vm_readv, pid, local_iov, liovcnt, remote_iov, riovcnt, flags); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif + ssize_t copy_from_proc(struct task *task, arch_addr_t addr, void *dst, size_t len) { + static int process_vm_call_nosys; + ssize_t num_bytes; + size_t n; union { long a; char c[sizeof(long)]; } a; - ssize_t num_bytes = 0; - size_t n = sizeof(a.a); + if (len > sizeof(a) && !process_vm_call_nosys) { + struct iovec local[1]; + struct iovec remote[1]; + local[0].iov_base = dst; + local[0].iov_len = len; + remote[0].iov_base = (void *)addr; + remote[0].iov_len = len; + + num_bytes = process_vm_readv(task->pid, local, 1, remote, 1, 0); + if (num_bytes != -1) + return num_bytes; + + if (errno != EFAULT) { + if (errno != ENOSYS) { + fprintf(stderr, "%s pid=%d process_vm_readv: %s\n", __FUNCTION__, task->pid, strerror(errno)); + return -1; + } + + process_vm_call_nosys = 1; + } + } + + num_bytes = 0; + n = sizeof(a.a); errno = 0; while (len) { @@ -589,13 +633,15 @@ ssize_t copy_from_proc(struct task *task, arch_addr_t addr, void *dst, size_t le ssize_t copy_to_proc(struct task *task, arch_addr_t addr, const void *src, size_t len) { + ssize_t num_bytes; + size_t n; union { long a; char c[sizeof(long)]; } a; - ssize_t num_bytes = 0; - size_t n = sizeof(a.a); + num_bytes = 0; + n = sizeof(a.a); while (len) { if (n > len) { diff --git a/sysdeps/linux-gnu/x86/arch.c b/sysdeps/linux-gnu/x86/arch.c index a119fbd..7a07dbe 100644 --- a/sysdeps/linux-gnu/x86/arch.c +++ b/sysdeps/linux-gnu/x86/arch.c @@ -37,6 +37,21 @@ #define BP_RW 2 #define BP_W 4 +int get_hw_bp_state(struct task *task, unsigned int n) +{ + long ret; + + errno = 0; + ret = ptrace(PTRACE_PEEKUSER, task->pid, offsetof(struct user, u_debugreg[6]), 0); + if (ret == -1 && errno) { + if (errno != ESRCH) + fprintf(stderr, "PTRACE_PEEKUSER u_debugreg[6] pid=%d %s\n", task->pid, strerror(errno)); + + return 0; + } + return (ret & (1 << n)) != 0; +} + static int _apply_hw_bp(struct task *task, uint32_t dr7) { long ret; diff --git a/sysdeps/linux-gnu/x86/arch.h b/sysdeps/linux-gnu/x86/arch.h index 43d14a8..5445243 100644 --- a/sysdeps/linux-gnu/x86/arch.h +++ b/sysdeps/linux-gnu/x86/arch.h @@ -28,6 +28,7 @@ #include #include #include +#include #define BREAKPOINT_VALUE { 0xcc } #define BREAKPOINT_LENGTH 1 @@ -40,8 +41,21 @@ #ifdef __x86_64__ #define MT_ELFCLASS2 ELFCLASS64 #define MT_ELF_MACHINE2 EM_X86_64 + +#ifndef __NR_process_vm_readv +#define __NR_process_vm_readv 310 #endif +#else /* __x86_64__ */ + +#ifndef __NR_process_vm_readv +#define __NR_process_vm_readv 347 +#endif + +#endif /* __x86_64__ */ + +#define GUESS_CALLER + #define HW_BREAKPOINTS 4 #define TASK_HAVE_PROCESS_DATA diff --git a/sysdeps/linux-gnu/x86/dwarf-x86.c b/sysdeps/linux-gnu/x86/dwarf-x86.c index a5ae480..60ee8b1 100644 --- a/sysdeps/linux-gnu/x86/dwarf-x86.c +++ b/sysdeps/linux-gnu/x86/dwarf-x86.c @@ -31,6 +31,7 @@ #include "backend.h" #include "debug.h" #include "dwarf.h" +#include "library.h" #include "task.h" struct arch_reg { @@ -266,7 +267,7 @@ int dwarf_arch_step(struct dwarf_addr_space *as) c->loc[arch_reg->bp] = DWARF_MEM_LOC(rbp); c->loc[arch_reg->ip] = DWARF_MEM_LOC(rbp + DWARF_ADDR_SIZE(as)); c->cfa = rbp + DWARF_ADDR_SIZE(as) * 2; - c->use_prev_instr = 1; + c->use_prev_instr = 0; } } @@ -304,3 +305,45 @@ int dwarf_arch_map_reg(struct dwarf_addr_space *as, unsigned int reg) return dwarf_to_regnum_map32[reg]; } +static struct call_op { + unsigned int off; + unsigned int len; + unsigned char *mask; + unsigned char *op; +} call_op[] = +{ + { 5, 1, (unsigned char [1]){ 0xff }, (unsigned char [1]){ 0xe8 } }, /* call */ + { 3, 2, (unsigned char [2]){ 0xff, 0xff }, (unsigned char [2]){ 0xff, 0x14 } }, /* call *(sp) */ + { 2, 2, (unsigned char [2]){ 0xff, 0xfc }, (unsigned char [2]){ 0xff, 0x10 } }, /* call *(reg) */ + { 4, 2, (unsigned char [2]){ 0xff, 0xff }, (unsigned char [2]){ 0xff, 0x54 } }, /* call *off8(reg, idx, scale) */ + { 3, 2, (unsigned char [2]){ 0xff, 0xfc }, (unsigned char [2]){ 0xff, 0x50 } }, /* call *off8 */ + { 7, 2, (unsigned char [2]){ 0xff, 0xff }, (unsigned char [2]){ 0xff, 0x94 } }, /* call *off32(reg, idx, scale) */ + { 6, 2, (unsigned char [2]){ 0xff, 0xfc }, (unsigned char [2]){ 0xff, 0x90 } }, /* call *off32 */ + { 2, 2, (unsigned char [2]){ 0xff, 0xfc }, (unsigned char [2]){ 0xff, 0xd0 } }, /* call *reg */ + { 0 } +}; + +int dwarf_arch_check_call(struct dwarf_addr_space *as, arch_addr_t ip) +{ + static struct call_op *p; + struct dwarf_cursor *c = &as->cursor; + struct libref *libref = c->libref; + + for(p = call_op; p->len; ++p) { + if (ip - ARCH_ADDR_T(libref->load_addr) >= p->off) { + unsigned int i; + unsigned char *addr = libref->image_addr + ip - p->off - libref->load_addr; + + for(i = 0; i < call_op[i].len; ++i) { + if ((addr[i] & p->mask[i]) != p->op[i]) + break; + } + + if (i == p->len) + return 1; + } + } + + return 0; +} + diff --git a/task.c b/task.c index 436def6..e39e5cb 100644 --- a/task.c +++ b/task.c @@ -42,6 +42,7 @@ #include "library.h" #include "mtelf.h" #include "report.h" +#include "server.h" #include "task.h" #include "trace.h" @@ -130,7 +131,7 @@ static int leader_setup(struct task *leader) return backtrace_init(leader); } -static int task_init(struct task *task, int attached) +static int task_init(struct task *task) { pid_t tgid; @@ -163,7 +164,7 @@ static int task_init(struct task *task, int attached) list_add_tail(&task->task_list, &task->leader->task_list); } - task->attached = attached; + task->attached = 1; if (arch_task_init(task) < 0) return -1; @@ -171,6 +172,8 @@ static int task_init(struct task *task, int attached) if (os_task_init(task) < 0) return -1; + breakpoint_hw_destroy(task); + return 0; } @@ -186,6 +189,8 @@ static int leader_cleanup(struct task *leader) breakpoint_clear_all(leader); backtrace_destroy(leader); + list_del(&leader->leader_list); + return 1; } @@ -194,7 +199,6 @@ static void leader_release(struct task *leader) if (!leader_cleanup(leader)) return; - list_del(&leader->leader_list); free(leader); } @@ -220,7 +224,7 @@ static void task_destroy(struct task *task) leader_release(leader); } -struct task *task_new(pid_t pid, int traced) +struct task *task_new(pid_t pid) { struct task *task = malloc(sizeof(*task)); @@ -230,16 +234,19 @@ struct task *task_new(pid_t pid, int traced) memset(task, 0, sizeof(*task)); task->pid = pid; - task->traced = traced; - task->stopped = traced; + task->traced = 0; + task->stopped = 0; task->was_stopped = 0; INIT_LIST_HEAD(&task->task_list); INIT_LIST_HEAD(&task->leader_list); +#if HW_BREAKPOINTS > 1 + INIT_LIST_HEAD(&task->hw_bp_list); +#endif library_setup(task); - if (task_init(task, 1) < 0) + if (task_init(task) < 0) goto fail1; init_event(task); @@ -257,7 +264,7 @@ static void remove_task_cb(struct task *task, void *data) if (task != data) { debug(DEBUG_FUNCTION, "clear pid=%d from leader pid=%d", task->pid, task->leader->pid); - remove_task(task); + task_destroy(task); } } @@ -265,21 +272,23 @@ int process_exec(struct task *task) { struct task *leader = task->leader; - leader->threads_stopped--; - - breakpoint_disable_all(leader); each_task(leader, &remove_task_cb, leader); + breakpoint_disable_all(leader); os_task_destroy(leader); arch_task_destroy(leader); leader_cleanup(leader); - if (task_init(leader, 0) < 0) + assert(leader->threads == 0); + + if (task_init(leader) < 0) goto fail; - assert(leader->leader == leader); + if (server_connected()) + task->attached = 0; - leader->threads_stopped++; + assert(leader->leader == leader); + assert(leader->threads_stopped == 1); if (leader_setup(leader) < 0) goto fail; @@ -311,7 +320,7 @@ struct task *task_create(const char *command, char **argv) _exit(EXIT_FAILURE); } - task = task_new(pid, 0); + task = task_new(pid); if (!task) goto fail2; @@ -321,6 +330,9 @@ struct task *task_create(const char *command, char **argv) if (trace_set_options(task) < 0) goto fail2; + if (server_connected()) + task->attached = 0; + if (leader_setup(task) < 0) goto fail1; @@ -344,6 +356,7 @@ int task_clone(struct task *task, struct task *newtask) assert(newtask->backtrace == NULL); newtask->is_64bit = task->is_64bit; + newtask->attached = task->attached; breakpoint_hw_clone(newtask); @@ -374,6 +387,7 @@ int task_fork(struct task *task, struct task *newtask) newtask->libsym = task->libsym; newtask->context = task->context; + newtask->attached = task->attached; if (task->breakpoint) newtask->breakpoint = breakpoint_find(newtask, newtask->breakpoint->addr); @@ -381,7 +395,7 @@ int task_fork(struct task *task, struct task *newtask) newtask->breakpoint = NULL; if (task->skip_bp) - newtask->skip_bp = breakpoint_ref(breakpoint_find(newtask, newtask->skip_bp->addr)); + newtask->skip_bp = breakpoint_get(breakpoint_find(newtask, newtask->skip_bp->addr)); else newtask->skip_bp = NULL; @@ -401,7 +415,7 @@ fail: void task_reset_bp(struct task *task) { - breakpoint_unref(task->skip_bp); + breakpoint_put(task->skip_bp); task->breakpoint = NULL; task->skip_bp = NULL; @@ -413,7 +427,7 @@ static struct task *open_one_pid(pid_t pid) debug(DEBUG_PROCESS, "pid=%d", pid); - task = task_new(pid, 0); + task = task_new(pid); if (task == NULL) goto fail1; @@ -425,7 +439,7 @@ static struct task *open_one_pid(pid_t pid) return task; fail2: - remove_task(task); + task_destroy(task); fail1: return NULL; } @@ -513,14 +527,6 @@ fail1: remove_proc(leader); } -struct task *get_first_process(void) -{ - if (list_empty(&list_of_leaders)) - return NULL; - - return container_of(list_of_leaders.next, struct task, leader_list); -} - void each_process(void (*cb)(struct task *task)) { struct list_head *it, *next; diff --git a/task.h b/task.h index 41b0aa5..d302778 100644 --- a/task.h +++ b/task.h @@ -56,6 +56,7 @@ struct task { unsigned int is_64bit:1; unsigned int attached:1; unsigned int deleted:1; + unsigned int about_exit:1; struct breakpoint *breakpoint; struct library_symbol *libsym; @@ -75,9 +76,6 @@ struct task { /* pointer to a breakpoint which was interrupt by a signal during skip */ struct breakpoint *skip_bp; - /* array of addresses of hw breakpoints */ - struct breakpoint *hw_bp[HW_BREAKPOINTS]; - /* set in leader: number of stopped threads including the leader */ unsigned int threads_stopped; @@ -99,16 +97,26 @@ struct task { /* set in leader: number of threads including the leader */ unsigned int threads; - /* only used in leader: bit mask for used hw breakpoints */ - unsigned long hw_bp_mask; - /* struct task chaining. */ struct list_head leader_list; + +#if HW_BREAKPOINTS > 1 + /* set in leader: list of hw breakpoints */ + struct list_head hw_bp_list; + + /* set in leader: number of registered hw breakpoints */ + unsigned long hw_bp_num; +#endif + +#if HW_BREAKPOINTS > 0 + /* array of active hw breakpoints */ + struct breakpoint *hw_bp[HW_BREAKPOINTS]; +#endif }; int process_exec(struct task *task); -struct task *task_new(pid_t pid, int traced); +struct task *task_new(pid_t pid); struct task *task_create(const char *command, char **argv); @@ -125,9 +133,6 @@ int task_fork(struct task *task, struct task *newtask); /* reset all breakpoints for task */ void task_reset_bp(struct task *task); -/* get first process of leader list */ -struct task *get_first_process(void); - /* Iterate through the leader tasks that mtrace currently traces. */ void each_process(void (*cb)(struct task *task)); diff --git a/trace.c b/trace.c index efa26f2..2c3cf55 100644 --- a/trace.c +++ b/trace.c @@ -48,7 +48,7 @@ int skip_breakpoint(struct task *task, struct breakpoint *bp) if (task->event.type != EVENT_NONE) return 1; - if (bp->enabled && bp->type == SW_BP) { + if (bp->enabled && !bp->hw) { int ret = 0; breakpoint_disable(task, bp); @@ -56,8 +56,8 @@ int skip_breakpoint(struct task *task, struct breakpoint *bp) breakpoint_enable(task, bp); if (ret) { if (ret == 1) { - breakpoint_unref(task->skip_bp); - task->skip_bp = breakpoint_ref(bp); + breakpoint_put(task->skip_bp); + task->skip_bp = breakpoint_get(bp); } return ret; } @@ -67,6 +67,15 @@ int skip_breakpoint(struct task *task, struct breakpoint *bp) return 0; } +void fix_about_exit(struct task *task) +{ + if (task->about_exit) { + task->about_exit = 0; + + continue_task(task, 0); + } +} + void detach_task(struct task *task) { int sig = 0; @@ -77,10 +86,11 @@ void detach_task(struct task *task) sig = task->event.e_un.signum; else if (task->event.type == EVENT_BREAKPOINT) - breakpoint_unref(task->event.e_un.breakpoint); + breakpoint_put(task->event.e_un.breakpoint); remove_event(task); breakpoint_hw_destroy(task); + fix_about_exit(task); untrace_task(task, sig); } diff --git a/trace.h b/trace.h index 0a1eb6c..855454c 100644 --- a/trace.h +++ b/trace.h @@ -25,6 +25,7 @@ #include "forward.h" +void fix_about_exit(struct task *task); void detach_task(struct task *task); void detach_proc(struct task *leader); int skip_breakpoint(struct task *task, struct breakpoint *bp);