From 3aed8a6e6b3f412b212689915ad7f22e5c9d1469 Mon Sep 17 00:00:00 2001 From: Stefani Seibold Date: Sun, 22 Nov 2015 10:24:06 +0100 Subject: [PATCH] new version 0.5 performance improvements and optimizations bug fixes advanced monitoring --- README.md | 2 +- TODO | 2 - autom4te.cache/output.0 | 69 ++- autom4te.cache/output.1 | 69 ++- autom4te.cache/output.2 | 69 ++- autom4te.cache/requests | 738 +++++++++++++++--------------- autom4te.cache/traces.0 | 31 +- autom4te.cache/traces.1 | 31 +- autom4te.cache/traces.2 | 94 ++-- backtrace.h | 69 ++- breakpoint.c | 36 +- breakpoint.h | 2 +- client/client.c | 127 +++-- client/client.h | 3 +- client/dump.c | 21 +- client/process.c | 215 +++++++-- client/process.h | 6 +- client/readline.c | 2 + common.c | 8 +- common.h | 8 + config.h.in | 6 + configure | 69 ++- configure.ac | 6 +- dwarf.c | 330 ++++++------- dwarf.h | 31 +- event.c | 60 ++- library.c | 60 ++- library.h | 7 + main.c | 26 +- main.h | 11 + memtrace.h | 41 +- mtelf.c | 7 +- options.h | 1 + report.c | 236 +++++----- report.h | 4 +- server.c | 14 +- server.h | 2 +- sysdeps/linux-gnu/Makefile.am | 1 - sysdeps/linux-gnu/Makefile.in | 6 +- sysdeps/linux-gnu/backtrace.c | 82 ---- sysdeps/linux-gnu/ioevent.c | 19 +- sysdeps/linux-gnu/ioevent.h | 5 +- sysdeps/linux-gnu/os.c | 7 +- sysdeps/linux-gnu/proc.c | 24 +- sysdeps/linux-gnu/socket.c | 14 +- sysdeps/linux-gnu/socket.h | 2 +- sysdeps/linux-gnu/trace.c | 79 ++-- sysdeps/linux-gnu/x86/arch.c | 8 +- sysdeps/linux-gnu/x86/dwarf-x86.c | 14 +- task.c | 86 ++-- task.h | 81 +++- timer.h | 62 +++ trace.c | 17 +- 53 files changed, 1842 insertions(+), 1178 deletions(-) delete mode 100644 sysdeps/linux-gnu/backtrace.c create mode 100644 timer.h diff --git a/README.md b/README.md index 0d85710..fd770e0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Mtrace ------ -mtrace-ng is an interactive dynamic memory tracer, debugger and statistical analyses tool for C and C++, which intercepts, records and reports all kinds of dynamic memory allocations. +mtrace-ng is a dynamic memory tracer, debugger and statistical analyses tool for C and C++, which intercepts, records and reports all kinds of dynamic memory allocations. It supports the developer to get statistics about the memory usage and finding memory leaks in an arbitrate program. Since mtrace-ng is using breakpoints for tracing the program, there is no need of modification of the source code nor any recompilation. diff --git a/TODO b/TODO index 1dfcc08..6751051 100644 --- a/TODO +++ b/TODO @@ -2,7 +2,5 @@ ppc single step enhancement arm thumb support dwarf debug support arm & ppc hw bp support -dwarf caching invalid stack trace cache for unmapped libraries -restore REALLOC_TRY when realloc fails mremap revamp diff --git a/autom4te.cache/output.0 b/autom4te.cache/output.0 index 0351635..af03e56 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-ng 0.4. +@%:@ Generated by GNU Autoconf 2.69 for mtrace-ng 0.5. @%:@ @%:@ Report bugs to . @%:@ @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='mtrace-ng' PACKAGE_TARNAME='mtrace-ng' -PACKAGE_VERSION='0.4' -PACKAGE_STRING='mtrace-ng 0.4' +PACKAGE_VERSION='0.5' +PACKAGE_STRING='mtrace-ng 0.5' PACKAGE_BUGREPORT='stefani@seibold.net' PACKAGE_URL='' @@ -1329,7 +1329,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-ng 0.4 to adapt to many kinds of systems. +\`configure' configures mtrace-ng 0.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1399,7 +1399,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of mtrace-ng 0.4:";; + short | recursive ) echo "Configuration of mtrace-ng 0.5:";; esac cat <<\_ACEOF @@ -1518,7 +1518,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -mtrace-ng configure 0.4 +mtrace-ng configure 0.5 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2124,7 +2124,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-ng $as_me 0.4, which was +It was created by mtrace-ng $as_me 0.5, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -12006,7 +12006,7 @@ fi # Define the identity of the package. PACKAGE='mtrace-ng' - VERSION='0.4' + VERSION='0.5' cat >>confdefs.h <<_ACEOF @@ -13238,6 +13238,7 @@ for ac_func in \ atexit \ getcwd \ gettimeofday \ + clock_gettime \ memset \ mkdir \ rmdir \ @@ -13260,6 +13261,54 @@ fi done +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +$as_echo_n "checking for clock_gettime in -lrt... " >&6; } +if ${ac_cv_lib_rt_clock_gettime+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (); +int +main () +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_rt_clock_gettime=yes +else + ac_cv_lib_rt_clock_gettime=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : + cat >>confdefs.h <<_ACEOF +@%:@define HAVE_LIBRT 1 +_ACEOF + + LIBS="-lrt $LIBS" + +else + as_fn_error $? "*** librt not found on your system" "$LINENO" 5 + +fi + # # Debugging @@ -13844,7 +13893,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-ng $as_me 0.4, which was +This file was extended by mtrace-ng $as_me 0.5, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13910,7 +13959,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-ng config.status 0.4 +mtrace-ng config.status 0.5 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 0351635..af03e56 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-ng 0.4. +@%:@ Generated by GNU Autoconf 2.69 for mtrace-ng 0.5. @%:@ @%:@ Report bugs to . @%:@ @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='mtrace-ng' PACKAGE_TARNAME='mtrace-ng' -PACKAGE_VERSION='0.4' -PACKAGE_STRING='mtrace-ng 0.4' +PACKAGE_VERSION='0.5' +PACKAGE_STRING='mtrace-ng 0.5' PACKAGE_BUGREPORT='stefani@seibold.net' PACKAGE_URL='' @@ -1329,7 +1329,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-ng 0.4 to adapt to many kinds of systems. +\`configure' configures mtrace-ng 0.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1399,7 +1399,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of mtrace-ng 0.4:";; + short | recursive ) echo "Configuration of mtrace-ng 0.5:";; esac cat <<\_ACEOF @@ -1518,7 +1518,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -mtrace-ng configure 0.4 +mtrace-ng configure 0.5 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2124,7 +2124,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-ng $as_me 0.4, which was +It was created by mtrace-ng $as_me 0.5, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -12006,7 +12006,7 @@ fi # Define the identity of the package. PACKAGE='mtrace-ng' - VERSION='0.4' + VERSION='0.5' cat >>confdefs.h <<_ACEOF @@ -13238,6 +13238,7 @@ for ac_func in \ atexit \ getcwd \ gettimeofday \ + clock_gettime \ memset \ mkdir \ rmdir \ @@ -13260,6 +13261,54 @@ fi done +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +$as_echo_n "checking for clock_gettime in -lrt... " >&6; } +if ${ac_cv_lib_rt_clock_gettime+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (); +int +main () +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_rt_clock_gettime=yes +else + ac_cv_lib_rt_clock_gettime=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : + cat >>confdefs.h <<_ACEOF +@%:@define HAVE_LIBRT 1 +_ACEOF + + LIBS="-lrt $LIBS" + +else + as_fn_error $? "*** librt not found on your system" "$LINENO" 5 + +fi + # # Debugging @@ -13844,7 +13893,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-ng $as_me 0.4, which was +This file was extended by mtrace-ng $as_me 0.5, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13910,7 +13959,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-ng config.status 0.4 +mtrace-ng config.status 0.5 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 0351635..af03e56 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-ng 0.4. +@%:@ Generated by GNU Autoconf 2.69 for mtrace-ng 0.5. @%:@ @%:@ Report bugs to . @%:@ @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='mtrace-ng' PACKAGE_TARNAME='mtrace-ng' -PACKAGE_VERSION='0.4' -PACKAGE_STRING='mtrace-ng 0.4' +PACKAGE_VERSION='0.5' +PACKAGE_STRING='mtrace-ng 0.5' PACKAGE_BUGREPORT='stefani@seibold.net' PACKAGE_URL='' @@ -1329,7 +1329,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-ng 0.4 to adapt to many kinds of systems. +\`configure' configures mtrace-ng 0.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1399,7 +1399,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of mtrace-ng 0.4:";; + short | recursive ) echo "Configuration of mtrace-ng 0.5:";; esac cat <<\_ACEOF @@ -1518,7 +1518,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -mtrace-ng configure 0.4 +mtrace-ng configure 0.5 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2124,7 +2124,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-ng $as_me 0.4, which was +It was created by mtrace-ng $as_me 0.5, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -12006,7 +12006,7 @@ fi # Define the identity of the package. PACKAGE='mtrace-ng' - VERSION='0.4' + VERSION='0.5' cat >>confdefs.h <<_ACEOF @@ -13238,6 +13238,7 @@ for ac_func in \ atexit \ getcwd \ gettimeofday \ + clock_gettime \ memset \ mkdir \ rmdir \ @@ -13260,6 +13261,54 @@ fi done +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +$as_echo_n "checking for clock_gettime in -lrt... " >&6; } +if ${ac_cv_lib_rt_clock_gettime+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (); +int +main () +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_rt_clock_gettime=yes +else + ac_cv_lib_rt_clock_gettime=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : + cat >>confdefs.h <<_ACEOF +@%:@define HAVE_LIBRT 1 +_ACEOF + + LIBS="-lrt $LIBS" + +else + as_fn_error $? "*** librt not found on your system" "$LINENO" 5 + +fi + # # Debugging @@ -13844,7 +13893,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-ng $as_me 0.4, which was +This file was extended by mtrace-ng $as_me 0.5, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13910,7 +13959,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-ng config.status 0.4 +mtrace-ng config.status 0.5 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 7e13d56..ef2139e 100644 --- a/autom4te.cache/requests +++ b/autom4te.cache/requests @@ -42,186 +42,186 @@ 'configure.ac' ], { - 'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1, - 'AC_LIBTOOL_LANG_GCJ_CONFIG' => 1, - '_LT_AC_TAGVAR' => 1, - 'LT_OUTPUT' => 1, - 'LTVERSION_VERSION' => 1, - '_AM_MANGLE_OPTION' => 1, - '_AM_PROG_CC_C_O' => 1, + 'AM_SUBST_NOTMAKE' => 1, + 'AC_PROG_LD' => 1, + 'AC_WITH_LTDL' => 1, + 'LT_SYS_MODULE_EXT' => 1, + 'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1, + 'AC_ENABLE_FAST_INSTALL' => 1, + '_LT_PREPARE_SED_QUOTE_VARS' => 1, + '_AM_PROG_TAR' => 1, + 'AM_INIT_AUTOMAKE' => 1, + 'LT_SYS_SYMBOL_USCORE' => 1, + '_LT_AC_PROG_ECHO_BACKSLASH' => 1, + 'm4_pattern_allow' => 1, + 'LT_SYS_DLOPEN_SELF' => 1, + 'AC_LIBTOOL_COMPILER_OPTION' => 1, + 'AC_ENABLE_SHARED' => 1, + 'AC_LTDL_PREOPEN' => 1, + 'AM_MISSING_HAS_RUN' => 1, 'LTOBSOLETE_VERSION' => 1, - 'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1, - 'AM_RUN_LOG' => 1, - 'AC_LIBTOOL_WIN32_DLL' => 1, - 'AC_PROG_LD_RELOAD_FLAG' => 1, - '_LT_DLL_DEF_P' => 1, - 'AC_LIBTOOL_PROG_COMPILER_PIC' => 1, + 'LTDL_CONVENIENCE' => 1, + '_LT_PATH_TOOL_PREFIX' => 1, + 'AC_LIBTOOL_LANG_RC_CONFIG' => 1, + 'AC_LIBTOOL_SETUP' => 1, + 'LT_PROG_RC' => 1, + 'LT_LIB_M' => 1, + 'AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE' => 1, + '_LT_AC_LANG_CXX_CONFIG' => 1, + 'AC_LIBTOOL_SYS_DYNAMIC_LINKER' => 1, + 'AC_LIBTOOL_SYS_LIB_STRIP' => 1, + '_LT_AC_LANG_F77_CONFIG' => 1, + 'AC_LTDL_OBJDIR' => 1, + 'm4_include' => 1, + 'AM_DEP_TRACK' => 1, + '_LT_LINKER_BOILERPLATE' => 1, 'AC_LTDL_ENABLE_INSTALL' => 1, - 'LT_WITH_LTDL' => 1, - 'AC_LTDL_DLSYM_USCORE' => 1, - '_LT_COMPILER_OPTION' => 1, - 'LTSUGAR_VERSION' => 1, - 'AC_LIBTOOL_COMPILER_OPTION' => 1, - 'LT_PATH_LD' => 1, - 'AC_LTDL_SHLIBEXT' => 1, - '_LT_AC_SHELL_INIT' => 1, - 'AM_SILENT_RULES' => 1, - 'AM_PROG_LD' => 1, - 'AC_LIBTOOL_PROG_COMPILER_NO_RTTI' => 1, - '_LT_WITH_SYSROOT' => 1, + 'AM_ENABLE_STATIC' => 1, 'AC_DISABLE_FAST_INSTALL' => 1, - 'AC_LIBTOOL_LANG_RC_CONFIG' => 1, - 'AC_PROG_EGREP' => 1, - '_LT_AC_SYS_COMPILER' => 1, - 'LT_CMD_MAX_LEN' => 1, + 'AC_LIBTOOL_GCJ' => 1, + 'LTDL_INSTALLABLE' => 1, + '_LT_LINKER_OPTION' => 1, + 'include' => 1, 'LTDL_INIT' => 1, - 'AC_LIBLTDL_INSTALLABLE' => 1, - 'AM_INIT_AUTOMAKE' => 1, - 'AC_ENABLE_SHARED' => 1, - 'LT_AC_PROG_EGREP' => 1, - 'AC_LIBTOOL_POSTDEP_PREDEP' => 1, - '_LT_PROG_ECHO_BACKSLASH' => 1, - 'AM_SUBST_NOTMAKE' => 1, - '_LT_REQUIRED_DARWIN_CHECKS' => 1, - '_LTDL_SETUP' => 1, + '_LT_PROG_LTMAIN' => 1, + 'AC_LIBTOOL_F77' => 1, + 'AC_DISABLE_SHARED' => 1, + 'AC_LIBTOOL_LANG_GCJ_CONFIG' => 1, + 'AM_SET_DEPDIR' => 1, + 'AM_AUTOMAKE_VERSION' => 1, + 'AC_LIB_LTDL' => 1, + '_LT_AC_TAGVAR' => 1, + '_LT_PROG_FC' => 1, + 'LT_SYS_DLOPEN_DEPLIBS' => 1, + 'AC_LTDL_DLSYM_USCORE' => 1, + 'AC_LIBTOOL_LANG_F77_CONFIG' => 1, + 'LT_FUNC_DLSYM_USCORE' => 1, 'AC_LIBTOOL_LINKER_OPTION' => 1, - 'LT_PROG_GO' => 1, - 'AM_DISABLE_STATIC' => 1, - '_LT_LINKER_BOILERPLATE' => 1, - 'AM_PROG_LIBTOOL' => 1, - '_AC_AM_CONFIG_HEADER_HOOK' => 1, + 'AM_RUN_LOG' => 1, 'AC_LTDL_SHLIBPATH' => 1, - 'LT_LIB_M' => 1, + 'LTOPTIONS_VERSION' => 1, + 'AC_LIBTOOL_SYS_MAX_CMD_LEN' => 1, + '_LT_AC_LANG_F77' => 1, + '_LT_REQUIRED_DARWIN_CHECKS' => 1, + '_LTDL_SETUP' => 1, + 'AC_LTDL_SYMBOL_USCORE' => 1, + 'AM_AUX_DIR_EXPAND' => 1, 'AC_LIBLTDL_CONVENIENCE' => 1, - 'LT_SYS_SYMBOL_USCORE' => 1, - 'LT_FUNC_ARGZ' => 1, - '_LT_LIBOBJ' => 1, - 'm4_pattern_forbid' => 1, - 'AM_DISABLE_SHARED' => 1, - '_LT_AC_LANG_C_CONFIG' => 1, - '_LT_PROG_F77' => 1, - 'AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE' => 1, - 'AM_PROG_NM' => 1, - 'AC_CONFIG_MACRO_DIR' => 1, + '_LT_AC_CHECK_DLFCN' => 1, + 'AC_LIBTOOL_OBJDIR' => 1, + '_AM_SUBST_NOTMAKE' => 1, + 'AC_LTDL_DLLIB' => 1, + '_LT_AC_LANG_RC_CONFIG' => 1, '_LT_AC_LANG_GCJ_CONFIG' => 1, - '_LT_LINKER_OPTION' => 1, - 'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1, - 'AC_LIBTOOL_LANG_CXX_CONFIG' => 1, - 'AC_DISABLE_SHARED' => 1, - 'LT_PROG_GCJ' => 1, - 'AM_ENABLE_SHARED' => 1, + '_m4_warn' => 1, + 'AM_MISSING_PROG' => 1, + 'AC_LTDL_SHLIBEXT' => 1, + 'AC_CONFIG_MACRO_DIR' => 1, + 'AC_DISABLE_STATIC' => 1, + '_LT_AC_PROG_CXXCPP' => 1, + '_LT_PROG_F77' => 1, + 'AC_DEPLIBS_CHECK_METHOD' => 1, + 'LT_SYS_DLSEARCH_PATH' => 1, + 'AM_DISABLE_SHARED' => 1, + 'LT_CONFIG_LTDL_DIR' => 1, + '_AC_PROG_LIBTOOL' => 1, 'AC_LIBTOOL_DLOPEN' => 1, - '_LT_AC_LOCK' => 1, - 'AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH' => 1, + 'AM_PROG_LIBTOOL' => 1, + 'AC_LIBTOOL_PROG_LD_SHLIBS' => 1, + 'AM_PROG_INSTALL_STRIP' => 1, + '_AM_IF_OPTION' => 1, + 'AC_LIBTOOL_DLOPEN_SELF' => 1, + '_LT_COMPILER_BOILERPLATE' => 1, + 'AC_CONFIG_MACRO_DIR_TRACE' => 1, + 'AM_SILENT_RULES' => 1, + 'AC_LTDL_SYSSEARCHPATH' => 1, + '_LT_CC_BASENAME' => 1, 'AC_PATH_TOOL_PREFIX' => 1, - 'AC_CHECK_LIBM' => 1, + 'AM_MAINTAINER_MODE' => 1, + 'm4_pattern_forbid' => 1, + '_AM_MANGLE_OPTION' => 1, + '_LT_AC_FILE_LTDLL_C' => 1, + 'AC_PROG_LD_GNU' => 1, + 'AM_MAKE_INCLUDE' => 1, + 'AC_PROG_EGREP' => 1, + 'LT_LANG' => 1, + 'LT_AC_PROG_EGREP' => 1, + '_AM_DEPENDENCIES' => 1, + '_LT_AC_SYS_LIBPATH_AIX' => 1, + 'AC_LIBTOOL_FC' => 1, + 'AC_LIBTOOL_CONFIG' => 1, + '_LT_PROG_ECHO_BACKSLASH' => 1, + 'AC_PATH_MAGIC' => 1, + 'AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH' => 1, + '_LT_COMPILER_OPTION' => 1, + 'LT_FUNC_ARGZ' => 1, + 'AM_SANITY_CHECK' => 1, + 'AC_DEFUN' => 1, + 'AC_PROG_LD_RELOAD_FLAG' => 1, 'AC_LIBTOOL_PICMODE' => 1, - 'AU_DEFUN' => 1, - '_AM_SET_OPTIONS' => 1, '_LT_AC_TRY_DLOPEN_SELF' => 1, - 'LT_AC_PROG_SED' => 1, + '_LT_AC_TAGCONFIG' => 1, 'AC_DEFUN_ONCE' => 1, - 'AC_WITH_LTDL' => 1, - 'AC_LIBTOOL_DLOPEN_SELF' => 1, - 'AC_LIBTOOL_SETUP' => 1, - '_LT_CC_BASENAME' => 1, - 'AC_CONFIG_MACRO_DIR_TRACE' => 1, - '_LT_AC_CHECK_DLFCN' => 1, - '_LT_PREPARE_SED_QUOTE_VARS' => 1, - 'AC_LIBTOOL_CXX' => 1, - 'AC_LIBTOOL_GCJ' => 1, - 'LT_SYS_DLOPEN_SELF' => 1, - 'LT_PROG_RC' => 1, - 'AC_DEPLIBS_CHECK_METHOD' => 1, - 'LT_AC_PROG_RC' => 1, - 'AC_PROG_LD_GNU' => 1, + 'AM_CONDITIONAL' => 1, 'LT_AC_PROG_GCJ' => 1, - 'm4_include' => 1, - 'AC_LTDL_SYSSEARCHPATH' => 1, - 'AM_PROG_INSTALL_SH' => 1, - '_LT_AC_PROG_CXXCPP' => 1, - 'AC_LTDL_PREOPEN' => 1, - 'AC_DEFUN' => 1, - 'AC_LIBTOOL_OBJDIR' => 1, - 'AM_AUX_DIR_EXPAND' => 1, - 'm4_pattern_allow' => 1, - '_LT_AC_SYS_LIBPATH_AIX' => 1, - '_AM_AUTOCONF_VERSION' => 1, - '_LT_AC_LANG_CXX' => 1, - 'AC_LIBTOOL_PROG_CC_C_O' => 1, - 'AM_MAINTAINER_MODE' => 1, - 'AM_SET_DEPDIR' => 1, - '_AM_SET_OPTION' => 1, - 'AM_ENABLE_STATIC' => 1, + '_LT_AC_LOCK' => 1, + 'AM_PROG_CC_C_O' => 1, 'AC_PROG_NM' => 1, - '_LT_AC_LANG_F77' => 1, - '_LT_PROG_CXX' => 1, - 'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1, - 'AC_LIBTOOL_FC' => 1, - '_LT_PROG_LTMAIN' => 1, - 'LTOPTIONS_VERSION' => 1, - '_LT_PATH_TOOL_PREFIX' => 1, - 'AM_SET_LEADING_DOT' => 1, + '_LT_AC_LANG_C_CONFIG' => 1, '_AM_CONFIG_MACRO_DIRS' => 1, - 'AC_ENABLE_FAST_INSTALL' => 1, - '_LT_AC_PROG_ECHO_BACKSLASH' => 1, - '_AM_PROG_TAR' => 1, - 'include' => 1, - 'AC_PATH_MAGIC' => 1, - '_LT_PROG_FC' => 1, - 'AM_PROG_INSTALL_STRIP' => 1, - 'LT_FUNC_DLSYM_USCORE' => 1, 'LT_LIB_DLLOAD' => 1, - 'AC_LTDL_OBJDIR' => 1, - 'AM_AUTOMAKE_VERSION' => 1, - 'LT_LANG' => 1, - 'AC_LIB_LTDL' => 1, - '_AC_PROG_LIBTOOL' => 1, - 'AM_MISSING_PROG' => 1, - '_AM_SUBST_NOTMAKE' => 1, - 'AC_PROG_LIBTOOL' => 1, - '_m4_warn' => 1, - 'AC_PROG_LD' => 1, - 'LT_PATH_NM' => 1, - 'AC_LIBTOOL_SYS_LIB_STRIP' => 1, - 'AC_LIBTOOL_CONFIG' => 1, - 'LT_SYS_DLSEARCH_PATH' => 1, - '_LT_AC_LANG_F77_CONFIG' => 1, - 'AM_DEP_TRACK' => 1, - 'LTDL_INSTALLABLE' => 1, + 'LT_CMD_MAX_LEN' => 1, + 'AU_DEFUN' => 1, + '_LT_AC_LANG_CXX' => 1, + '_LT_DLL_DEF_P' => 1, + 'LT_PROG_GO' => 1, + 'AM_PROG_INSTALL_SH' => 1, + 'AC_LIBTOOL_PROG_COMPILER_PIC' => 1, + 'AM_DISABLE_STATIC' => 1, + 'AC_CHECK_LIBM' => 1, + '_AM_SET_OPTIONS' => 1, + 'AC_LIBTOOL_WIN32_DLL' => 1, + 'AM_PROG_LD' => 1, + '_LT_AC_SHELL_INIT' => 1, 'LT_SYS_MODULE_PATH' => 1, + 'AC_LIBTOOL_RC' => 1, + 'AM_ENABLE_SHARED' => 1, + '_LT_AC_LANG_GCJ' => 1, + 'AC_ENABLE_STATIC' => 1, '_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, - '_AM_DEPENDENCIES' => 1, - '_LT_AC_LANG_CXX_CONFIG' => 1, - 'AM_CONDITIONAL' => 1, - '_LT_AC_TAGCONFIG' => 1, - 'LT_SYS_DLOPEN_DEPLIBS' => 1, - 'LT_CONFIG_LTDL_DIR' => 1, - 'AM_MAKE_INCLUDE' => 1, + '_AM_SET_OPTION' => 1, + 'LTVERSION_VERSION' => 1, + 'AC_LIBLTDL_INSTALLABLE' => 1, + 'LT_AC_PROG_RC' => 1, + 'AC_LIBTOOL_POSTDEP_PREDEP' => 1, + 'LT_AC_PROG_SED' => 1, + '_AM_PROG_CC_C_O' => 1, + 'AM_SET_LEADING_DOT' => 1, + '_LT_AC_SYS_COMPILER' => 1, + 'AC_LIBTOOL_PROG_CC_C_O' => 1, + '_LT_WITH_SYSROOT' => 1, + 'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, 'LT_INIT' => 1, - 'AC_LIBTOOL_SYS_DYNAMIC_LINKER' => 1, - 'AC_LIBTOOL_LANG_F77_CONFIG' => 1, - '_LT_AC_LANG_GCJ' => 1, - 'AM_MISSING_HAS_RUN' => 1, - '_LT_AC_FILE_LTDLL_C' => 1, - 'LT_SYS_MODULE_EXT' => 1, - 'AC_DISABLE_STATIC' => 1, - '_AM_IF_OPTION' => 1, - 'AM_SANITY_CHECK' => 1, + 'LT_PATH_LD' => 1, + 'LT_OUTPUT' => 1, 'LT_SUPPORTED_TAG' => 1, - 'AC_LIBTOOL_F77' => 1, - '_LT_AC_LANG_RC_CONFIG' => 1, - 'AC_LIBTOOL_RC' => 1, - 'AC_LIBTOOL_PROG_LD_SHLIBS' => 1, - 'AC_ENABLE_STATIC' => 1, - 'AC_LTDL_DLLIB' => 1, - 'AC_LTDL_SYMBOL_USCORE' => 1, + 'AM_PROG_NM' => 1, + 'LT_WITH_LTDL' => 1, + 'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1, + 'AC_LIBTOOL_LANG_CXX_CONFIG' => 1, 'AC_LIBTOOL_LANG_C_CONFIG' => 1, - 'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, - 'LTDL_CONVENIENCE' => 1, - 'AC_LIBTOOL_SYS_MAX_CMD_LEN' => 1, - 'AM_PROG_CC_C_O' => 1, - '_LT_COMPILER_BOILERPLATE' => 1 + '_LT_PROG_CXX' => 1, + 'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1, + '_AC_AM_CONFIG_HEADER_HOOK' => 1, + 'LT_PATH_NM' => 1, + 'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1, + 'LT_PROG_GCJ' => 1, + 'AC_LIBTOOL_PROG_COMPILER_NO_RTTI' => 1, + 'LTSUGAR_VERSION' => 1, + '_AM_AUTOCONF_VERSION' => 1, + 'AC_LIBTOOL_CXX' => 1, + 'AC_PROG_LIBTOOL' => 1, + '_LT_LIBOBJ' => 1 } ], 'Autom4te::Request' ), bless( [ @@ -263,186 +263,186 @@ 'configure.ac' ], { - 'AC_LTDL_ENABLE_INSTALL' => 1, - 'LT_WITH_LTDL' => 1, - 'AC_LTDL_DLSYM_USCORE' => 1, + 'LT_FUNC_ARGZ' => 1, + 'AM_SANITY_CHECK' => 1, '_LT_COMPILER_OPTION' => 1, - 'LTSUGAR_VERSION' => 1, - 'AC_LIBTOOL_COMPILER_OPTION' => 1, - 'LT_PATH_LD' => 1, - 'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1, - 'AC_LIBTOOL_LANG_GCJ_CONFIG' => 1, - '_LT_AC_TAGVAR' => 1, - 'LT_OUTPUT' => 1, - '_AM_MANGLE_OPTION' => 1, - 'LTVERSION_VERSION' => 1, - '_AM_PROG_CC_C_O' => 1, - 'LTOBSOLETE_VERSION' => 1, - 'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1, - 'AM_RUN_LOG' => 1, - 'AC_LIBTOOL_WIN32_DLL' => 1, - 'AC_PROG_LD_RELOAD_FLAG' => 1, - '_LT_DLL_DEF_P' => 1, - 'AC_LIBTOOL_PROG_COMPILER_PIC' => 1, - 'LT_AC_PROG_EGREP' => 1, - 'AC_LIBTOOL_POSTDEP_PREDEP' => 1, - '_LT_PROG_ECHO_BACKSLASH' => 1, - 'AM_SUBST_NOTMAKE' => 1, - '_LT_REQUIRED_DARWIN_CHECKS' => 1, - '_LTDL_SETUP' => 1, - 'AC_LIBTOOL_LINKER_OPTION' => 1, - 'AM_DISABLE_STATIC' => 1, - 'LT_PROG_GO' => 1, - '_LT_LINKER_BOILERPLATE' => 1, - 'AM_PROG_LIBTOOL' => 1, - '_AC_AM_CONFIG_HEADER_HOOK' => 1, - 'AC_LTDL_SHLIBEXT' => 1, - '_LT_AC_SHELL_INIT' => 1, - 'AM_PROG_LD' => 1, - 'AM_SILENT_RULES' => 1, - 'AC_LIBTOOL_PROG_COMPILER_NO_RTTI' => 1, - 'AC_LIBTOOL_LANG_RC_CONFIG' => 1, - 'AC_DISABLE_FAST_INSTALL' => 1, - '_LT_WITH_SYSROOT' => 1, - 'AC_PROG_EGREP' => 1, - '_LT_AC_SYS_COMPILER' => 1, - 'LT_CMD_MAX_LEN' => 1, - 'AC_LIBLTDL_INSTALLABLE' => 1, - 'LTDL_INIT' => 1, - 'AC_ENABLE_SHARED' => 1, - 'AM_INIT_AUTOMAKE' => 1, - '_LT_AC_LANG_GCJ_CONFIG' => 1, - 'AC_CONFIG_MACRO_DIR' => 1, - '_LT_LINKER_OPTION' => 1, - 'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1, - 'AC_LIBTOOL_LANG_CXX_CONFIG' => 1, - 'AC_DISABLE_SHARED' => 1, - 'AM_ENABLE_SHARED' => 1, - 'LT_PROG_GCJ' => 1, - 'AC_LIBTOOL_DLOPEN' => 1, - '_LT_AC_LOCK' => 1, 'AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH' => 1, - 'AC_PATH_TOOL_PREFIX' => 1, - 'AC_CHECK_LIBM' => 1, - 'AC_LTDL_SHLIBPATH' => 1, - 'LT_LIB_M' => 1, - 'AC_LIBLTDL_CONVENIENCE' => 1, - 'LT_SYS_SYMBOL_USCORE' => 1, - 'LT_FUNC_ARGZ' => 1, - '_LT_LIBOBJ' => 1, - 'm4_pattern_forbid' => 1, - '_LT_AC_LANG_C_CONFIG' => 1, - 'AM_DISABLE_SHARED' => 1, - '_LT_PROG_F77' => 1, - 'AM_PROG_NM' => 1, - 'AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE' => 1, - 'AC_LIBTOOL_SETUP' => 1, - '_LT_CC_BASENAME' => 1, - 'AC_CONFIG_MACRO_DIR_TRACE' => 1, - '_LT_AC_CHECK_DLFCN' => 1, - '_LT_PREPARE_SED_QUOTE_VARS' => 1, - 'AC_LIBTOOL_CXX' => 1, - 'AC_LIBTOOL_GCJ' => 1, - 'LT_SYS_DLOPEN_SELF' => 1, - 'LT_PROG_RC' => 1, - 'AC_DEPLIBS_CHECK_METHOD' => 1, - 'AU_DEFUN' => 1, + 'AC_PROG_LD_RELOAD_FLAG' => 1, + 'AC_DEFUN' => 1, + 'AC_DEFUN_ONCE' => 1, + '_LT_AC_TAGCONFIG' => 1, 'AC_LIBTOOL_PICMODE' => 1, - '_AM_SET_OPTIONS' => 1, - 'LT_AC_PROG_SED' => 1, '_LT_AC_TRY_DLOPEN_SELF' => 1, - 'AC_DEFUN_ONCE' => 1, - 'AC_WITH_LTDL' => 1, - 'AC_LIBTOOL_DLOPEN_SELF' => 1, - '_AM_AUTOCONF_VERSION' => 1, - '_LT_AC_SYS_LIBPATH_AIX' => 1, - 'AM_SET_DEPDIR' => 1, - 'AC_LIBTOOL_PROG_CC_C_O' => 1, - 'AM_MAINTAINER_MODE' => 1, - '_LT_AC_LANG_CXX' => 1, - '_AM_SET_OPTION' => 1, - 'AM_ENABLE_STATIC' => 1, - 'AC_PROG_NM' => 1, - '_LT_PROG_CXX' => 1, - '_LT_AC_LANG_F77' => 1, - 'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1, - 'AC_LIBTOOL_FC' => 1, - '_LT_PROG_LTMAIN' => 1, - 'LT_AC_PROG_RC' => 1, - 'AC_PROG_LD_GNU' => 1, + 'AM_PROG_CC_C_O' => 1, + '_LT_AC_LOCK' => 1, 'LT_AC_PROG_GCJ' => 1, - 'm4_include' => 1, - 'AC_LTDL_SYSSEARCHPATH' => 1, - 'AM_PROG_INSTALL_SH' => 1, - 'AC_LTDL_PREOPEN' => 1, - 'AC_DEFUN' => 1, - '_LT_AC_PROG_CXXCPP' => 1, - 'AM_AUX_DIR_EXPAND' => 1, - 'AC_LIBTOOL_OBJDIR' => 1, - 'm4_pattern_allow' => 1, - '_AM_PROG_TAR' => 1, - 'include' => 1, - 'AC_PATH_MAGIC' => 1, - '_LT_PROG_FC' => 1, - 'LT_FUNC_DLSYM_USCORE' => 1, - 'AM_PROG_INSTALL_STRIP' => 1, - 'LT_LIB_DLLOAD' => 1, - 'AC_LTDL_OBJDIR' => 1, - 'AM_AUTOMAKE_VERSION' => 1, - 'LT_LANG' => 1, - '_AC_PROG_LIBTOOL' => 1, - 'AC_LIB_LTDL' => 1, - 'AM_MISSING_PROG' => 1, - '_AM_SUBST_NOTMAKE' => 1, - '_m4_warn' => 1, - 'AC_PROG_LIBTOOL' => 1, - 'AC_PROG_LD' => 1, - 'LT_PATH_NM' => 1, - 'LTOPTIONS_VERSION' => 1, - '_LT_PATH_TOOL_PREFIX' => 1, - 'AM_SET_LEADING_DOT' => 1, - 'AC_ENABLE_FAST_INSTALL' => 1, - '_AM_CONFIG_MACRO_DIRS' => 1, - '_LT_AC_PROG_ECHO_BACKSLASH' => 1, - '_LT_AC_LANG_CXX_CONFIG' => 1, - 'LT_SYS_DLOPEN_DEPLIBS' => 1, - '_LT_AC_TAGCONFIG' => 1, 'AM_CONDITIONAL' => 1, - 'LT_CONFIG_LTDL_DIR' => 1, + '_AM_CONFIG_MACRO_DIRS' => 1, + 'AC_PROG_NM' => 1, + '_LT_AC_LANG_C_CONFIG' => 1, + 'LT_LIB_DLLOAD' => 1, + 'LT_CMD_MAX_LEN' => 1, + '_LT_DLL_DEF_P' => 1, + '_LT_AC_LANG_CXX' => 1, + 'AU_DEFUN' => 1, + 'AM_PROG_INSTALL_STRIP' => 1, + 'AC_LIBTOOL_PROG_LD_SHLIBS' => 1, + 'AM_PROG_LIBTOOL' => 1, + '_LT_COMPILER_BOILERPLATE' => 1, + '_AM_IF_OPTION' => 1, + 'AC_LIBTOOL_DLOPEN_SELF' => 1, + 'AM_SILENT_RULES' => 1, + 'AC_CONFIG_MACRO_DIR_TRACE' => 1, + 'm4_pattern_forbid' => 1, + 'AM_MAINTAINER_MODE' => 1, + 'AC_PATH_TOOL_PREFIX' => 1, + '_LT_CC_BASENAME' => 1, + 'AC_LTDL_SYSSEARCHPATH' => 1, + 'AC_PROG_LD_GNU' => 1, + '_LT_AC_FILE_LTDLL_C' => 1, + '_AM_MANGLE_OPTION' => 1, + 'AC_PROG_EGREP' => 1, + 'LT_LANG' => 1, 'AM_MAKE_INCLUDE' => 1, + '_AM_DEPENDENCIES' => 1, + 'LT_AC_PROG_EGREP' => 1, + '_LT_PROG_ECHO_BACKSLASH' => 1, + 'AC_PATH_MAGIC' => 1, + 'AC_LIBTOOL_CONFIG' => 1, + 'AC_LIBTOOL_FC' => 1, + '_LT_AC_SYS_LIBPATH_AIX' => 1, + 'AC_LIBTOOL_POSTDEP_PREDEP' => 1, + 'LT_AC_PROG_RC' => 1, + '_LT_AC_SYS_COMPILER' => 1, + '_AM_PROG_CC_C_O' => 1, + 'AM_SET_LEADING_DOT' => 1, + 'LT_AC_PROG_SED' => 1, + '_LT_WITH_SYSROOT' => 1, + 'AC_LIBTOOL_PROG_CC_C_O' => 1, + 'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1, + 'LT_WITH_LTDL' => 1, + 'AM_PROG_NM' => 1, + 'LT_SUPPORTED_TAG' => 1, + 'LT_OUTPUT' => 1, 'LT_INIT' => 1, + 'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, + 'LT_PATH_LD' => 1, + 'AC_LIBTOOL_LANG_CXX_CONFIG' => 1, + 'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1, + '_LT_PROG_CXX' => 1, + 'AC_LIBTOOL_LANG_C_CONFIG' => 1, + 'AC_LIBTOOL_PROG_COMPILER_NO_RTTI' => 1, + 'LT_PROG_GCJ' => 1, + 'LT_PATH_NM' => 1, + 'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1, + '_AC_AM_CONFIG_HEADER_HOOK' => 1, + '_LT_LIBOBJ' => 1, + 'LTSUGAR_VERSION' => 1, + 'AC_LIBTOOL_CXX' => 1, + 'AC_PROG_LIBTOOL' => 1, + '_AM_AUTOCONF_VERSION' => 1, + 'AM_DISABLE_STATIC' => 1, + 'AC_LIBTOOL_PROG_COMPILER_PIC' => 1, + 'AM_PROG_INSTALL_SH' => 1, + 'LT_PROG_GO' => 1, + '_AM_SET_OPTIONS' => 1, + 'AC_CHECK_LIBM' => 1, + 'AM_PROG_LD' => 1, + 'AC_LIBTOOL_WIN32_DLL' => 1, + 'AC_LIBTOOL_RC' => 1, + 'LT_SYS_MODULE_PATH' => 1, + '_LT_AC_SHELL_INIT' => 1, + 'AC_ENABLE_STATIC' => 1, + '_LT_AC_LANG_GCJ' => 1, + 'AM_ENABLE_SHARED' => 1, + '_AM_SET_OPTION' => 1, + '_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, + 'LTVERSION_VERSION' => 1, + 'AC_LIBLTDL_INSTALLABLE' => 1, + 'LT_LIB_M' => 1, + 'LT_PROG_RC' => 1, + 'AC_LIBTOOL_SETUP' => 1, 'AC_LIBTOOL_SYS_DYNAMIC_LINKER' => 1, - 'AC_LIBTOOL_SYS_LIB_STRIP' => 1, - 'AC_LIBTOOL_CONFIG' => 1, - 'LT_SYS_DLSEARCH_PATH' => 1, + '_LT_AC_LANG_CXX_CONFIG' => 1, + 'AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE' => 1, + 'm4_include' => 1, + 'AC_LTDL_OBJDIR' => 1, '_LT_AC_LANG_F77_CONFIG' => 1, + 'AC_LIBTOOL_SYS_LIB_STRIP' => 1, + '_LT_LINKER_BOILERPLATE' => 1, 'AM_DEP_TRACK' => 1, + 'include' => 1, 'LTDL_INSTALLABLE' => 1, - 'LT_SYS_MODULE_PATH' => 1, - '_AM_DEPENDENCIES' => 1, - '_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, - 'LT_SUPPORTED_TAG' => 1, + '_LT_LINKER_OPTION' => 1, + 'AC_LIBTOOL_GCJ' => 1, + 'AC_DISABLE_FAST_INSTALL' => 1, + 'AM_ENABLE_STATIC' => 1, + 'AC_LTDL_ENABLE_INSTALL' => 1, 'AC_LIBTOOL_F77' => 1, - 'AC_LIBTOOL_RC' => 1, - '_LT_AC_LANG_RC_CONFIG' => 1, - 'AC_LIBTOOL_PROG_LD_SHLIBS' => 1, - 'AC_ENABLE_STATIC' => 1, + '_LT_PROG_LTMAIN' => 1, + 'LTDL_INIT' => 1, + 'AM_SET_DEPDIR' => 1, + 'AM_AUTOMAKE_VERSION' => 1, + 'AC_LIBTOOL_LANG_GCJ_CONFIG' => 1, + 'AC_DISABLE_SHARED' => 1, + 'AM_SUBST_NOTMAKE' => 1, + 'AC_PROG_LD' => 1, + 'AC_WITH_LTDL' => 1, + 'LT_SYS_MODULE_EXT' => 1, + '_LT_AC_PROG_ECHO_BACKSLASH' => 1, + 'LT_SYS_SYMBOL_USCORE' => 1, + 'AM_INIT_AUTOMAKE' => 1, + '_AM_PROG_TAR' => 1, + 'AC_ENABLE_FAST_INSTALL' => 1, + '_LT_PREPARE_SED_QUOTE_VARS' => 1, + 'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1, + 'AC_LTDL_PREOPEN' => 1, + 'AC_ENABLE_SHARED' => 1, + 'AC_LIBTOOL_COMPILER_OPTION' => 1, + 'LT_SYS_DLOPEN_SELF' => 1, + 'm4_pattern_allow' => 1, + 'LTOBSOLETE_VERSION' => 1, + 'AM_MISSING_HAS_RUN' => 1, + 'AC_LIBTOOL_LANG_RC_CONFIG' => 1, + '_LT_PATH_TOOL_PREFIX' => 1, + 'LTDL_CONVENIENCE' => 1, + '_LTDL_SETUP' => 1, + '_LT_REQUIRED_DARWIN_CHECKS' => 1, + '_LT_AC_LANG_F77' => 1, + '_AM_SUBST_NOTMAKE' => 1, + '_LT_AC_CHECK_DLFCN' => 1, + 'AC_LIBTOOL_OBJDIR' => 1, + 'AC_LIBLTDL_CONVENIENCE' => 1, + 'AM_AUX_DIR_EXPAND' => 1, 'AC_LTDL_SYMBOL_USCORE' => 1, 'AC_LTDL_DLLIB' => 1, - 'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1, - 'AC_LIBTOOL_LANG_C_CONFIG' => 1, - 'AC_LIBTOOL_SYS_MAX_CMD_LEN' => 1, - 'LTDL_CONVENIENCE' => 1, - 'AM_PROG_CC_C_O' => 1, - '_LT_COMPILER_BOILERPLATE' => 1, - 'AC_LIBTOOL_LANG_F77_CONFIG' => 1, - '_LT_AC_LANG_GCJ' => 1, - 'AM_MISSING_HAS_RUN' => 1, - '_LT_AC_FILE_LTDLL_C' => 1, - 'LT_SYS_MODULE_EXT' => 1, + '_m4_warn' => 1, + '_LT_AC_LANG_GCJ_CONFIG' => 1, + '_LT_AC_LANG_RC_CONFIG' => 1, + 'AM_MISSING_PROG' => 1, + 'AC_LTDL_SHLIBEXT' => 1, 'AC_DISABLE_STATIC' => 1, - 'AM_SANITY_CHECK' => 1, - '_AM_IF_OPTION' => 1 + 'AC_CONFIG_MACRO_DIR' => 1, + 'AM_DISABLE_SHARED' => 1, + 'LT_SYS_DLSEARCH_PATH' => 1, + 'AC_DEPLIBS_CHECK_METHOD' => 1, + '_LT_PROG_F77' => 1, + '_LT_AC_PROG_CXXCPP' => 1, + 'AC_LIBTOOL_DLOPEN' => 1, + 'LT_CONFIG_LTDL_DIR' => 1, + '_AC_PROG_LIBTOOL' => 1, + 'AC_LIB_LTDL' => 1, + '_LT_PROG_FC' => 1, + '_LT_AC_TAGVAR' => 1, + 'AC_LTDL_DLSYM_USCORE' => 1, + 'LT_SYS_DLOPEN_DEPLIBS' => 1, + 'LT_FUNC_DLSYM_USCORE' => 1, + 'AC_LIBTOOL_LANG_F77_CONFIG' => 1, + 'AC_LIBTOOL_LINKER_OPTION' => 1, + 'AM_RUN_LOG' => 1, + 'LTOPTIONS_VERSION' => 1, + 'AC_LIBTOOL_SYS_MAX_CMD_LEN' => 1, + 'AC_LTDL_SHLIBPATH' => 1 } ], 'Autom4te::Request' ), bless( [ @@ -457,65 +457,65 @@ 'configure.ac' ], { - 'AC_CONFIG_LIBOBJ_DIR' => 1, - 'AC_FC_FREEFORM' => 1, - 'AC_REQUIRE_AUX_FILE' => 1, - 'AC_CANONICAL_TARGET' => 1, - 'AC_SUBST' => 1, - 'm4_include' => 1, - 'AC_CONFIG_AUX_DIR' => 1, + 'AC_SUBST_TRACE' => 1, + 'm4_pattern_allow' => 1, + 'AM_INIT_AUTOMAKE' => 1, 'AC_FC_PP_SRCEXT' => 1, - 'AM_PROG_CXX_C_O' => 1, + 'AC_CANONICAL_SYSTEM' => 1, 'AC_CONFIG_FILES' => 1, - 'm4_pattern_forbid' => 1, - 'AC_CONFIG_LINKS' => 1, - 'AC_DEFINE_TRACE_LITERAL' => 1, - 'm4_pattern_allow' => 1, - '_AM_COND_ENDIF' => 1, + 'AC_FC_SRCEXT' => 1, + 'AC_CONFIG_AUX_DIR' => 1, + 'AM_PROG_FC_C_O' => 1, + 'AC_CANONICAL_BUILD' => 1, + 'AC_CANONICAL_TARGET' => 1, 'AM_ENABLE_MULTILIB' => 1, + 'AM_EXTRA_RECURSIVE_TARGETS' => 1, + 'AM_PROG_MOC' => 1, + 'AC_REQUIRE_AUX_FILE' => 1, + 'AC_CONFIG_LIBOBJ_DIR' => 1, + 'AH_OUTPUT' => 1, + 'AM_PROG_CXX_C_O' => 1, + 'AC_FC_FREEFORM' => 1, + 'm4_pattern_forbid' => 1, 'AM_MAINTAINER_MODE' => 1, - 'sinclude' => 1, - 'AC_CANONICAL_BUILD' => 1, - 'AM_PROG_AR' => 1, - 'AC_FC_PP_DEFINE' => 1, + '_AM_COND_ENDIF' => 1, + 'AM_PROG_MKDIR_P' => 1, + 'AM_MAKEFILE_INCLUDE' => 1, + 'AM_SILENT_RULES' => 1, 'AC_CONFIG_HEADERS' => 1, - '_LT_AC_TAGCONFIG' => 1, - 'AM_POT_TOOLS' => 1, - 'AM_CONDITIONAL' => 1, - 'LT_CONFIG_LTDL_DIR' => 1, - 'AM_XGETTEXT_OPTION' => 1, '_AM_MAKEFILE_INCLUDE' => 1, + 'include' => 1, + 'AC_FC_PP_DEFINE' => 1, '_AM_COND_IF' => 1, - 'LT_INIT' => 1, - 'AM_PROG_F77_C_O' => 1, - 'AM_MAKEFILE_INCLUDE' => 1, + 'AM_GNU_GETTEXT' => 1, 'AC_CONFIG_SUBDIRS' => 1, - 'AC_SUBST_TRACE' => 1, - 'AM_PROG_MKDIR_P' => 1, - 'AM_NLS' => 1, - 'AM_SILENT_RULES' => 1, - 'AM_EXTRA_RECURSIVE_TARGETS' => 1, - '_AM_COND_ELSE' => 1, - 'AC_INIT' => 1, - 'AC_FC_SRCEXT' => 1, + 'AM_AUTOMAKE_VERSION' => 1, + 'AM_PROG_AR' => 1, + 'AC_PROG_LIBTOOL' => 1, + 'LT_CONFIG_LTDL_DIR' => 1, 'AM_PATH_GUILE' => 1, - 'AC_CANONICAL_HOST' => 1, - 'm4_sinclude' => 1, - 'AC_CANONICAL_SYSTEM' => 1, - 'AM_GNU_GETTEXT' => 1, - 'AM_INIT_AUTOMAKE' => 1, + 'AC_DEFINE_TRACE_LITERAL' => 1, 'AM_GNU_GETTEXT_INTL_SUBDIR' => 1, - 'AH_OUTPUT' => 1, - 'AM_PROG_MOC' => 1, - 'LT_SUPPORTED_TAG' => 1, - 'include' => 1, - 'AC_LIBSOURCE' => 1, - 'AM_AUTOMAKE_VERSION' => 1, - 'AM_PROG_FC_C_O' => 1, + 'AM_POT_TOOLS' => 1, '_AM_SUBST_NOTMAKE' => 1, + 'm4_sinclude' => 1, + '_AM_COND_ELSE' => 1, + 'AM_XGETTEXT_OPTION' => 1, + 'AC_LIBSOURCE' => 1, + 'AC_INIT' => 1, + 'sinclude' => 1, + 'AM_NLS' => 1, + 'AC_SUBST' => 1, '_m4_warn' => 1, - 'AC_PROG_LIBTOOL' => 1, - 'AM_PROG_CC_C_O' => 1 + 'AM_PROG_CC_C_O' => 1, + 'LT_SUPPORTED_TAG' => 1, + 'AC_CONFIG_LINKS' => 1, + 'LT_INIT' => 1, + 'AM_CONDITIONAL' => 1, + 'm4_include' => 1, + 'AM_PROG_F77_C_O' => 1, + '_LT_AC_TAGCONFIG' => 1, + 'AC_CANONICAL_HOST' => 1 } ], 'Autom4te::Request' ) ); diff --git a/autom4te.cache/traces.0 b/autom4te.cache/traces.0 index 03566d1..1b1e35d 100644 --- a/autom4te.cache/traces.0 +++ b/autom4te.cache/traces.0 @@ -2746,18 +2746,19 @@ m4trace:configure.ac:224: -1- m4_pattern_allow([^HAVE_VFORK_H$]) m4trace:configure.ac:224: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$]) m4trace:configure.ac:224: -1- m4_pattern_allow([^vfork$]) m4trace:configure.ac:224: -1- m4_pattern_allow([^HAVE_WORKING_FORK$]) -m4trace:configure.ac:255: -1- m4_pattern_allow([^DEBUG$]) -m4trace:configure.ac:269: -1- m4_pattern_allow([^AM_CPPFLAGS$]) -m4trace:configure.ac:270: -1- m4_pattern_allow([^AM_CFLAGS$]) -m4trace:configure.ac:271: -1- m4_pattern_allow([^AM_LDFLAGS$]) -m4trace:configure.ac:272: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$]) -m4trace:configure.ac:283: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:283: -1- m4_pattern_allow([^LTLIBOBJS$]) -m4trace:configure.ac:283: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) -m4trace:configure.ac:283: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) -m4trace:configure.ac:283: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) -m4trace:configure.ac:283: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) -m4trace:configure.ac:283: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) -m4trace:configure.ac:283: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"]) -m4trace:configure.ac:283: -1- _LT_PROG_LTMAIN -m4trace:configure.ac:283: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS +m4trace:configure.ac:242: -1- m4_pattern_allow([^HAVE_LIBRT$]) +m4trace:configure.ac:259: -1- m4_pattern_allow([^DEBUG$]) +m4trace:configure.ac:273: -1- m4_pattern_allow([^AM_CPPFLAGS$]) +m4trace:configure.ac:274: -1- m4_pattern_allow([^AM_CFLAGS$]) +m4trace:configure.ac:275: -1- m4_pattern_allow([^AM_LDFLAGS$]) +m4trace:configure.ac:276: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$]) +m4trace:configure.ac:287: -1- m4_pattern_allow([^LIB@&t@OBJS$]) +m4trace:configure.ac:287: -1- m4_pattern_allow([^LTLIBOBJS$]) +m4trace:configure.ac:287: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) +m4trace:configure.ac:287: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) +m4trace:configure.ac:287: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) +m4trace:configure.ac:287: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) +m4trace:configure.ac:287: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) +m4trace:configure.ac:287: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"]) +m4trace:configure.ac:287: -1- _LT_PROG_LTMAIN +m4trace:configure.ac:287: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS diff --git a/autom4te.cache/traces.1 b/autom4te.cache/traces.1 index 53025d1..6d1817c 100644 --- a/autom4te.cache/traces.1 +++ b/autom4te.cache/traces.1 @@ -2746,18 +2746,19 @@ m4trace:configure.ac:224: -1- m4_pattern_allow([^HAVE_VFORK_H$]) m4trace:configure.ac:224: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$]) m4trace:configure.ac:224: -1- m4_pattern_allow([^vfork$]) m4trace:configure.ac:224: -1- m4_pattern_allow([^HAVE_WORKING_FORK$]) -m4trace:configure.ac:255: -1- m4_pattern_allow([^DEBUG$]) -m4trace:configure.ac:269: -1- m4_pattern_allow([^AM_CPPFLAGS$]) -m4trace:configure.ac:270: -1- m4_pattern_allow([^AM_CFLAGS$]) -m4trace:configure.ac:271: -1- m4_pattern_allow([^AM_LDFLAGS$]) -m4trace:configure.ac:272: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$]) -m4trace:configure.ac:283: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:283: -1- m4_pattern_allow([^LTLIBOBJS$]) -m4trace:configure.ac:283: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) -m4trace:configure.ac:283: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) -m4trace:configure.ac:283: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) -m4trace:configure.ac:283: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) -m4trace:configure.ac:283: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) -m4trace:configure.ac:283: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"]) -m4trace:configure.ac:283: -1- _LT_PROG_LTMAIN -m4trace:configure.ac:283: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS +m4trace:configure.ac:242: -1- m4_pattern_allow([^HAVE_LIBRT$]) +m4trace:configure.ac:259: -1- m4_pattern_allow([^DEBUG$]) +m4trace:configure.ac:273: -1- m4_pattern_allow([^AM_CPPFLAGS$]) +m4trace:configure.ac:274: -1- m4_pattern_allow([^AM_CFLAGS$]) +m4trace:configure.ac:275: -1- m4_pattern_allow([^AM_LDFLAGS$]) +m4trace:configure.ac:276: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$]) +m4trace:configure.ac:287: -1- m4_pattern_allow([^LIB@&t@OBJS$]) +m4trace:configure.ac:287: -1- m4_pattern_allow([^LTLIBOBJS$]) +m4trace:configure.ac:287: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) +m4trace:configure.ac:287: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) +m4trace:configure.ac:287: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) +m4trace:configure.ac:287: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) +m4trace:configure.ac:287: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) +m4trace:configure.ac:287: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"]) +m4trace:configure.ac:287: -1- _LT_PROG_LTMAIN +m4trace:configure.ac:287: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS diff --git a/autom4te.cache/traces.2 b/autom4te.cache/traces.2 index 79a2df3..262b55b 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-ng], [0.4], [stefani@seibold.net]) +m4trace:configure.ac:27: -1- AC_INIT([mtrace-ng], [0.5], [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']) @@ -655,6 +655,8 @@ m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_GETCWD], [/* Define to 1 if you ha @%:@undef HAVE_GETCWD]) m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_GETTIMEOFDAY], [/* Define to 1 if you have the `gettimeofday\' function. */ @%:@undef HAVE_GETTIMEOFDAY]) +m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_CLOCK_GETTIME], [/* Define to 1 if you have the `clock_gettime\' function. */ +@%:@undef HAVE_CLOCK_GETTIME]) m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_MEMSET], [/* Define to 1 if you have the `memset\' function. */ @%:@undef HAVE_MEMSET]) m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_MKDIR], [/* Define to 1 if you have the `mkdir\' function. */ @@ -673,23 +675,27 @@ m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_STRTOUL], [/* Define to 1 if you h @%:@undef HAVE_STRTOUL]) m4trace:configure.ac:225: -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:255: -1- AC_DEFINE_TRACE_LITERAL([DEBUG]) -m4trace:configure.ac:255: -1- m4_pattern_allow([^DEBUG$]) -m4trace:configure.ac:255: -1- AH_OUTPUT([DEBUG], [/* debugging */ +m4trace:configure.ac:242: -1- AH_OUTPUT([HAVE_LIBRT], [/* Define to 1 if you have the `rt\' library (-lrt). */ +@%:@undef HAVE_LIBRT]) +m4trace:configure.ac:242: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBRT]) +m4trace:configure.ac:242: -1- m4_pattern_allow([^HAVE_LIBRT$]) +m4trace:configure.ac:259: -1- AC_DEFINE_TRACE_LITERAL([DEBUG]) +m4trace:configure.ac:259: -1- m4_pattern_allow([^DEBUG$]) +m4trace:configure.ac:259: -1- AH_OUTPUT([DEBUG], [/* debugging */ @%:@undef DEBUG]) -m4trace:configure.ac:269: -1- AC_SUBST([AM_CPPFLAGS]) -m4trace:configure.ac:269: -1- AC_SUBST_TRACE([AM_CPPFLAGS]) -m4trace:configure.ac:269: -1- m4_pattern_allow([^AM_CPPFLAGS$]) -m4trace:configure.ac:270: -1- AC_SUBST([AM_CFLAGS]) -m4trace:configure.ac:270: -1- AC_SUBST_TRACE([AM_CFLAGS]) -m4trace:configure.ac:270: -1- m4_pattern_allow([^AM_CFLAGS$]) -m4trace:configure.ac:271: -1- AC_SUBST([AM_LDFLAGS]) -m4trace:configure.ac:271: -1- AC_SUBST_TRACE([AM_LDFLAGS]) -m4trace:configure.ac:271: -1- m4_pattern_allow([^AM_LDFLAGS$]) -m4trace:configure.ac:272: -1- AC_SUBST([libelf_LD_LIBRARY_PATH]) -m4trace:configure.ac:272: -1- AC_SUBST_TRACE([libelf_LD_LIBRARY_PATH]) -m4trace:configure.ac:272: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$]) -m4trace:configure.ac:274: -1- AC_CONFIG_FILES([ +m4trace:configure.ac:273: -1- AC_SUBST([AM_CPPFLAGS]) +m4trace:configure.ac:273: -1- AC_SUBST_TRACE([AM_CPPFLAGS]) +m4trace:configure.ac:273: -1- m4_pattern_allow([^AM_CPPFLAGS$]) +m4trace:configure.ac:274: -1- AC_SUBST([AM_CFLAGS]) +m4trace:configure.ac:274: -1- AC_SUBST_TRACE([AM_CFLAGS]) +m4trace:configure.ac:274: -1- m4_pattern_allow([^AM_CFLAGS$]) +m4trace:configure.ac:275: -1- AC_SUBST([AM_LDFLAGS]) +m4trace:configure.ac:275: -1- AC_SUBST_TRACE([AM_LDFLAGS]) +m4trace:configure.ac:275: -1- m4_pattern_allow([^AM_LDFLAGS$]) +m4trace:configure.ac:276: -1- AC_SUBST([libelf_LD_LIBRARY_PATH]) +m4trace:configure.ac:276: -1- AC_SUBST_TRACE([libelf_LD_LIBRARY_PATH]) +m4trace:configure.ac:276: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$]) +m4trace:configure.ac:278: -1- AC_CONFIG_FILES([ Makefile client/Makefile sysdeps/Makefile @@ -698,30 +704,30 @@ m4trace:configure.ac:274: -1- AC_CONFIG_FILES([ sysdeps/linux-gnu/ppc/Makefile sysdeps/linux-gnu/arm/Makefile ]) -m4trace:configure.ac:283: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs]) -m4trace:configure.ac:283: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) -m4trace:configure.ac:283: -1- m4_pattern_allow([^LIB@&t@OBJS$]) -m4trace:configure.ac:283: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs]) -m4trace:configure.ac:283: -1- AC_SUBST_TRACE([LTLIBOBJS]) -m4trace:configure.ac:283: -1- m4_pattern_allow([^LTLIBOBJS$]) -m4trace:configure.ac:283: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) -m4trace:configure.ac:283: -1- AC_SUBST([am__EXEEXT_TRUE]) -m4trace:configure.ac:283: -1- AC_SUBST_TRACE([am__EXEEXT_TRUE]) -m4trace:configure.ac:283: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) -m4trace:configure.ac:283: -1- AC_SUBST([am__EXEEXT_FALSE]) -m4trace:configure.ac:283: -1- AC_SUBST_TRACE([am__EXEEXT_FALSE]) -m4trace:configure.ac:283: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) -m4trace:configure.ac:283: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) -m4trace:configure.ac:283: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) -m4trace:configure.ac:283: -1- AC_SUBST_TRACE([top_builddir]) -m4trace:configure.ac:283: -1- AC_SUBST_TRACE([top_build_prefix]) -m4trace:configure.ac:283: -1- AC_SUBST_TRACE([srcdir]) -m4trace:configure.ac:283: -1- AC_SUBST_TRACE([abs_srcdir]) -m4trace:configure.ac:283: -1- AC_SUBST_TRACE([top_srcdir]) -m4trace:configure.ac:283: -1- AC_SUBST_TRACE([abs_top_srcdir]) -m4trace:configure.ac:283: -1- AC_SUBST_TRACE([builddir]) -m4trace:configure.ac:283: -1- AC_SUBST_TRACE([abs_builddir]) -m4trace:configure.ac:283: -1- AC_SUBST_TRACE([abs_top_builddir]) -m4trace:configure.ac:283: -1- AC_SUBST_TRACE([INSTALL]) -m4trace:configure.ac:283: -1- AC_SUBST_TRACE([MKDIR_P]) -m4trace:configure.ac:283: -1- AC_REQUIRE_AUX_FILE([ltmain.sh]) +m4trace:configure.ac:287: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs]) +m4trace:configure.ac:287: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) +m4trace:configure.ac:287: -1- m4_pattern_allow([^LIB@&t@OBJS$]) +m4trace:configure.ac:287: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs]) +m4trace:configure.ac:287: -1- AC_SUBST_TRACE([LTLIBOBJS]) +m4trace:configure.ac:287: -1- m4_pattern_allow([^LTLIBOBJS$]) +m4trace:configure.ac:287: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) +m4trace:configure.ac:287: -1- AC_SUBST([am__EXEEXT_TRUE]) +m4trace:configure.ac:287: -1- AC_SUBST_TRACE([am__EXEEXT_TRUE]) +m4trace:configure.ac:287: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) +m4trace:configure.ac:287: -1- AC_SUBST([am__EXEEXT_FALSE]) +m4trace:configure.ac:287: -1- AC_SUBST_TRACE([am__EXEEXT_FALSE]) +m4trace:configure.ac:287: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) +m4trace:configure.ac:287: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) +m4trace:configure.ac:287: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) +m4trace:configure.ac:287: -1- AC_SUBST_TRACE([top_builddir]) +m4trace:configure.ac:287: -1- AC_SUBST_TRACE([top_build_prefix]) +m4trace:configure.ac:287: -1- AC_SUBST_TRACE([srcdir]) +m4trace:configure.ac:287: -1- AC_SUBST_TRACE([abs_srcdir]) +m4trace:configure.ac:287: -1- AC_SUBST_TRACE([top_srcdir]) +m4trace:configure.ac:287: -1- AC_SUBST_TRACE([abs_top_srcdir]) +m4trace:configure.ac:287: -1- AC_SUBST_TRACE([builddir]) +m4trace:configure.ac:287: -1- AC_SUBST_TRACE([abs_builddir]) +m4trace:configure.ac:287: -1- AC_SUBST_TRACE([abs_top_builddir]) +m4trace:configure.ac:287: -1- AC_SUBST_TRACE([INSTALL]) +m4trace:configure.ac:287: -1- AC_SUBST_TRACE([MKDIR_P]) +m4trace:configure.ac:287: -1- AC_REQUIRE_AUX_FILE([ltmain.sh]) diff --git a/backtrace.h b/backtrace.h index ad0b80c..26fa2f0 100644 --- a/backtrace.h +++ b/backtrace.h @@ -23,25 +23,82 @@ #ifndef _INC_BACKTRACE_H #define _INC_BACKTRACE_H +#include + +#include "dwarf.h" +#include "main.h" +#include "options.h" #include "task.h" +#include "timer.h" /* init backtrace for given leader task */ -int backtrace_init(struct task *task); +static inline int backtrace_init(struct task *task) +{ + assert(task->leader == task); + assert(task->backtrace == NULL); + + task->backtrace = dwarf_init(task->is_64bit); + + return task->backtrace != NULL; +} /* destroy backtrace for given leader task */ -void backtrace_destroy(struct task *task); +static inline void backtrace_destroy(struct task *task) +{ + assert(task->leader == task); + + if (task->backtrace) { + dwarf_destroy(task->backtrace); + + task->backtrace = NULL; + } +} /* start backtrace for given task */ -int backtrace_init_unwind(struct task *task); +static inline int backtrace_init_unwind(struct task *task) +{ + assert(task->leader); + assert(task->leader->backtrace); + + return dwarf_init_unwind(task->leader->backtrace, task); +} /* get backtrace IP address for given task */ -unsigned long backtrace_get_ip(struct task *task); +static inline unsigned long backtrace_get_ip(struct task *task) +{ + assert(task->leader); + assert(task->leader->backtrace); + + return dwarf_get_ip(task->leader->backtrace); +} /* step to next backtrace given task */ -int backtrace_step(struct task *task); +static inline int backtrace_step(struct task *task) +{ + int ret; + struct timespec start; + + assert(task->leader); + assert(task->leader->backtrace); + + if (unlikely(options.verbose > 1)) + start_time(&start); + + ret = dwarf_step(task->leader->backtrace); + + if (unlikely(options.verbose > 1)) + set_timer(&start, &backtrace_time); + + return ret; +} /* get backtrace location type of given task */ -int backtrace_location_type(struct task *task); +static inline int backtrace_location_type(struct task *task) +{ + assert(task->leader); + assert(task->leader->backtrace); + return dwarf_location_type(task->leader->backtrace); +} #endif diff --git a/breakpoint.c b/breakpoint.c index d73c635..cb0f1a6 100644 --- a/breakpoint.c +++ b/breakpoint.c @@ -108,7 +108,7 @@ static void enable_hw_bp(struct task *task, struct breakpoint *bp) task->hw_bp[slot] = bp; - if (set_hw_bp(task, slot, bp->addr) == -1) + if (unlikely(set_hw_bp(task, slot, bp->addr) == -1)) fatal("set_hw_bp"); } @@ -116,12 +116,12 @@ static void disable_hw_bp(struct task *task, struct breakpoint *bp) { unsigned int slot = bp->hw_bp_slot; - if (!task->hw_bp[slot]) + if (unlikely(!task->hw_bp[slot])) return; assert(task->hw_bp[slot] == bp); - if (reset_hw_bp(task, slot) == -1) + if (unlikely(reset_hw_bp(task, slot) == -1)) fatal("reset_hw_bp"); task->hw_bp[slot] = NULL; @@ -286,10 +286,10 @@ void breakpoint_hw_destroy(struct task *task) void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp) { - if (bp->deleted) + if (unlikely(bp->deleted)) return; - if (bp->type != BP_HW_SCRATCH) + if (unlikely(bp->type != BP_HW_SCRATCH)) return; assert(bp->hw_bp_slot == HW_BP_SCRATCH_SLOT); @@ -300,10 +300,10 @@ void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp) void disable_scratch_hw_bp(struct task *task, struct breakpoint *bp) { - if (bp->deleted) + if (unlikely(bp->deleted)) return; - if (bp->type != BP_HW_SCRATCH) + if (unlikely(bp->type != BP_HW_SCRATCH)) return; assert(bp->hw_bp_slot == HW_BP_SCRATCH_SLOT); @@ -385,12 +385,12 @@ struct breakpoint *breakpoint_new(struct task *task, arch_addr_t addr, struct li void breakpoint_enable(struct task *task, struct breakpoint *bp) { - if (bp->deleted) + if (unlikely(bp->deleted)) return; debug(DEBUG_PROCESS, "pid=%d, addr=%#lx", task->pid, bp->addr); - if (!bp->enabled) { + if (likely(!bp->enabled)) { #if HW_BREAKPOINTS > 0 if (bp->type == BP_HW_SCRATCH) { bp->enabled = 1; @@ -412,12 +412,12 @@ void breakpoint_enable(struct task *task, struct breakpoint *bp) void breakpoint_disable(struct task *task, struct breakpoint *bp) { - if (bp->deleted) + if (unlikely(bp->deleted)) return; debug(DEBUG_PROCESS, "pid=%d, addr=%#lx", task->pid, bp->addr); - if (bp->enabled) { + if (likely(bp->enabled)) { #if HW_BREAKPOINTS > 0 if (bp->hw) { struct task *leader = task->leader; @@ -449,13 +449,13 @@ struct breakpoint *breakpoint_insert(struct task *task, arch_addr_t addr, struct { debug(DEBUG_FUNCTION, "pid=%d, addr=%lx, symbol=%s", task->pid, addr, libsym ? libsym->func->name : "NULL"); - if (!addr) + if (unlikely(!addr)) return NULL; struct breakpoint *bp = breakpoint_find(task, addr); - if (!bp) { + if (unlikely(!bp)) { bp = breakpoint_new(task, addr, libsym, type); - if (!bp) + if (unlikely(!bp)) return NULL; } @@ -484,7 +484,7 @@ void breakpoint_delete(struct task *task, struct breakpoint *bp) #endif dict_remove_entry(leader->breakpoints, (unsigned long)bp->addr); - if (options.verbose > 1 && bp->libsym) { + if (unlikely(options.verbose > 1 && bp->libsym)) { fprintf(stderr, "delete %s breakpoint %s:%s [%#lx] count=%u\n", bp->type == BP_SW ? "sw" : "hw", @@ -662,7 +662,7 @@ static int clone_single_cb(unsigned long key, const void *value, void *data) 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) + if (unlikely(set_hw_bp(new_task, new_bp->hw_bp_slot, new_bp->addr) == -1)) fatal("set_hw_bp"); } } @@ -692,14 +692,14 @@ int breakpoint_clone_all(struct task *clone, struct task *leader) struct breakpoint *breakpoint_get(struct breakpoint *bp) { - if (bp) + if (likely(bp)) ++bp->refcnt; return bp; } int breakpoint_put(struct breakpoint *bp) { - if (bp) { + if (likely(bp)) { assert(bp->refcnt != 0); if (--bp->refcnt) diff --git a/breakpoint.h b/breakpoint.h index f993625..6a2bd0a 100644 --- a/breakpoint.h +++ b/breakpoint.h @@ -31,7 +31,7 @@ #include "sysdep.h" #include "forward.h" -#define BP_REORDER_THRESHOLD 1024U +#define BP_REORDER_THRESHOLD 2048U #define BP_SW 0 #define BP_HW_SCRATCH 1 diff --git a/client/client.c b/client/client.c index f74eed6..750337f 100644 --- a/client/client.c +++ b/client/client.c @@ -224,7 +224,7 @@ static int parse_config(const char *filename) return 0; } -static struct rb_process *pid_rb_search(struct rb_root *root, pid_t pid) +static struct rb_process *pid_rb_search(struct rb_root *root, unsigned int pid) { struct rb_node *node = root->rb_node; @@ -241,7 +241,7 @@ static struct rb_process *pid_rb_search(struct rb_root *root, pid_t pid) return NULL; } -static struct process *pid_rb_delete(struct rb_root *root, pid_t pid) +static struct process *pid_rb_delete(struct rb_root *root, unsigned int pid) { struct rb_process *data = pid_rb_search(root, pid); struct process *process; @@ -289,35 +289,34 @@ static void swap_msg(struct mt_msg *mt_msg) { mt_msg->operation = bswap_16(mt_msg->operation); mt_msg->payload_len = bswap_32(mt_msg->payload_len); - mt_msg->pid = bswap_32(mt_msg->pid); - mt_msg->tid = bswap_32(mt_msg->tid); + mt_msg->pid = bswap_16(mt_msg->pid); } static int socket_read_msg(struct mt_msg *mt_msg, void **payload, unsigned int *swap_endian) { + size_t payload_len; + if (TEMP_FAILURE_RETRY(safe_read(client_fd, mt_msg, sizeof(*mt_msg))) <= 0) return FALSE; - if (mt_msg->operation > 0xff) { - swap_msg(mt_msg); + *swap_endian = mt_msg->operation > 0xff; - *swap_endian = 1; - } - else - *swap_endian = 0; + if (*swap_endian) + swap_msg(mt_msg); + payload_len = mt_msg->payload_len; - if (mt_msg->payload_len) { - *payload = malloc(mt_msg->payload_len); + if (payload_len) { + *payload = malloc(payload_len); - if (TEMP_FAILURE_RETRY(safe_read(client_fd, *payload, mt_msg->payload_len)) <= 0) + if (TEMP_FAILURE_RETRY(safe_read(client_fd, *payload, payload_len)) <= 0) return FALSE; } return TRUE; } -static pid_t pid_payload(struct process *process, void *payload) +static unsigned int pid_payload(struct process *process, void *payload) { struct mt_pid_payload *mt_pid = payload; @@ -369,6 +368,14 @@ static void client_remove_process(struct process *process) free(process); } + +static void store_timer_info(struct memtrace_timer_info *dst, struct memtrace_timer_info *src) +{ + dst->max = bswap_32(src->max); + dst->count = bswap_32(src->count); + dst->culminate = bswap_64(src->culminate); +} + static int client_func(void) { struct mt_msg mt_msg; @@ -393,7 +400,27 @@ static int client_func(void) client_close(); break; case MT_INFO: - memcpy(&mt_info, payload, sizeof(mt_info)); + if (swap_endian) { + struct memtrace_info *p = payload; + + mt_info.version = p->version; + mt_info.mode = p->mode; + mt_info.do_trace = p->do_trace; + mt_info.stack_depth = p->stack_depth; + mt_info.verbose = p->verbose; + + store_timer_info(&mt_info.stop_time, &p->stop_time); + store_timer_info(&mt_info.sw_bp_time, &p->sw_bp_time); + store_timer_info(&mt_info.hw_bp_time, &p->hw_bp_time); + store_timer_info(&mt_info.backtrace_time, &p->backtrace_time); + store_timer_info(&mt_info.reorder_time, &p->reorder_time); + store_timer_info(&mt_info.report_in_time, &p->report_in_time); + store_timer_info(&mt_info.report_out_time, &p->report_out_time); + store_timer_info(&mt_info.skip_bp_time, &p->skip_bp_time); + } + else + memcpy(&mt_info, payload, sizeof(mt_info)); + break; default: fatal("protocol violation 0x%08x", mt_msg.operation); @@ -419,7 +446,6 @@ static int client_func(void) switch(mt_msg.operation) { case MT_MALLOC: case MT_REALLOC: - case MT_REALLOC_FAILED: case MT_MEMALIGN: case MT_POSIX_MEMALIGN: case MT_ALIGNED_ALLOC: @@ -431,6 +457,9 @@ static int client_func(void) case MT_NEW_ARRAY: process_alloc(process, &mt_msg, payload); break; + case MT_REALLOC_DONE: + process_realloc_done(process, &mt_msg, payload); + break; case MT_REALLOC_ENTER: case MT_FREE: case MT_DELETE: @@ -487,16 +516,6 @@ static int client_func(void) return mt_msg.operation; } -void client_show_info(void) -{ - printf("memtrace info:\n"); - printf(" follow fork: %s\n", mt_info.mode & MEMTRACE_SI_FORK ? "yes" : "no"); - printf(" follow exec: %s\n", mt_info.mode & MEMTRACE_SI_EXEC ? "yes" : "no"); - printf(" verbose: %s\n", mt_info.mode & MEMTRACE_SI_VERBOSE ? "yes" : "no"); - printf(" do trace: %s\n", mt_info.do_trace ? "yes" : "no"); - printf(" stack depth: %u\n", mt_info.stack_depth); -} - int client_wait_op(enum mt_operation op) { if (options.logfile) @@ -515,6 +534,52 @@ int client_wait_op(enum mt_operation op) return 0; } +static void show_timer_info(const char *str, struct memtrace_timer_info *info) +{ + if (!info->count) + return; + + printf(" %s\n count: %-9lu max. us: %-6lu culminate us:%-11llu average ns:%llu\n", + str, + (unsigned long)info->count, + (unsigned long)info->max, + (unsigned long long)info->culminate, + (unsigned long long)(info->culminate * 1000) / info->count + ); +} + +void client_show_info(void) +{ + printf("memtrace info:\n"); + printf(" follow fork: %s\n", mt_info.mode & MEMTRACE_SI_FORK ? "yes" : "no"); + printf(" follow exec: %s\n", mt_info.mode & MEMTRACE_SI_EXEC ? "yes" : "no"); + printf(" verbose: %s\n", mt_info.mode & MEMTRACE_SI_VERBOSE ? "yes" : "no"); + printf(" do trace: %s\n", mt_info.do_trace ? "yes" : "no"); + printf(" stack depth: %u\n", mt_info.stack_depth); + + if (mt_info.verbose > 1) { + show_timer_info("threads stop", &mt_info.stop_time); + show_timer_info("breakpoint sw", &mt_info.sw_bp_time); + show_timer_info("breakpoint hw", &mt_info.hw_bp_time); + show_timer_info("backtrace step", &mt_info.backtrace_time); + show_timer_info("reorder", &mt_info.reorder_time); + show_timer_info("report in", &mt_info.report_in_time); + show_timer_info("report out", &mt_info.report_out_time); + show_timer_info("skip breakpoint", &mt_info.skip_bp_time); + } +} + +void client_request_info(void) +{ + if (sock_send_msg(client_fd, MT_INFO, 0, NULL, 0) < 0) { + client_broken(); + return; + } + + if (client_wait_op(MT_INFO) < 0) + return; +} + static int client_iterate_process(struct rb_node *node, void *user) { struct rb_process *data = (struct rb_process *)node; @@ -528,7 +593,7 @@ void client_iterate_processes(int (*func)(struct process *process)) rb_iterate(&pid_table, client_iterate_process, func); } -struct process *client_find_process(pid_t pid) +struct process *client_find_process(unsigned int pid) { struct rb_process *data; @@ -608,6 +673,8 @@ int client_start(void) return -1; } + ioevent_add_input(client_fd, client_func); + if (client_wait_op(MT_INFO) == -1) { fprintf(stderr, "could not talk to server\n"); return -1; @@ -625,8 +692,6 @@ int client_start(void) client_show_info(); - ioevent_add_input(client_fd, client_func); - if (options.interactive) { int old_client_fd = client_fd; @@ -648,7 +713,7 @@ int client_start(void) readline_exit(); } else { - if (pipe(pipefd) == -1) { + if (pipe2(pipefd, O_NONBLOCK | O_CLOEXEC) == -1) { fprintf(stderr, "could not create pipe (%s)", strerror(errno)); return -1; } @@ -713,7 +778,7 @@ int client_send_msg(struct process *process, enum mt_operation op, void *payload if (options.logfile) return -1; - ret = sock_send_msg(client_fd, process->val16(op), process->pid, 0, payload, payload_len); + ret = sock_send_msg(client_fd, process->val16(op), process->pid, payload, payload_len); if (ret < 0) client_broken(); diff --git a/client/client.h b/client/client.h index a53cb99..4da27bb 100644 --- a/client/client.h +++ b/client/client.h @@ -28,9 +28,10 @@ struct process; struct process *client_first_process(void); -struct process *client_find_process(pid_t pid); +struct process *client_find_process(unsigned int pid); void client_iterate_processes(int (*func)(struct process *process)); void client_show_info(void); +void client_request_info(void); int client_wait_op(enum mt_operation op); void client_close(void); int client_send_msg(struct process *process, enum mt_operation op, void *payload, unsigned int payload_len); diff --git a/client/dump.c b/client/dump.c index f5ad268..d648491 100644 --- a/client/dump.c +++ b/client/dump.c @@ -37,6 +37,7 @@ static int dump_term; static FILE *dump_outfile; +static int dump_char; static int rows, cols; static int row, col; @@ -99,12 +100,18 @@ int dump_init(FILE *file) return 0; } +static int dump_getchar(void) +{ + dump_char = getchar(); + return 0; +} + static int dump_pager(void) { struct termios termios; struct termios termios_old; - int c; int len; + ioevent_func oldfunc; len = printf("Press for next line, q for quit and any other for next page\r") - 1; fflush(stdout); @@ -114,14 +121,20 @@ static int dump_pager(void) cfmakeraw(&termios); tcsetattr(0, TCSADRAIN, &termios); - ioevent_wait_input(0, -1); - c = getchar(); + oldfunc = ioevent_set_input_func(0, dump_getchar); + + dump_char = 0; + do { + ioevent_watch(-1); + } while(!dump_char); + + ioevent_set_input_func(0, oldfunc); tcsetattr(0, TCSANOW, &termios_old); printf("%*s\r", len, ""); fflush(stdout); - switch(c) { + switch(dump_char) { case '\03': case 'q': if (col) diff --git a/client/process.c b/client/process.c index 75f3111..9c3193b 100644 --- a/client/process.c +++ b/client/process.c @@ -64,6 +64,7 @@ struct stack { struct rb_stack { struct rb_node node; struct stack *stack; + unsigned long refcnt; unsigned long leaks; unsigned long long n_allocations; unsigned long long total_allocations; @@ -83,6 +84,16 @@ struct map { unsigned int ignore:1; }; +struct realloc_entry { + struct list_head list; + unsigned int pid; + unsigned long addr; + unsigned long size; + unsigned long flags; + struct rb_stack *stack; + enum mt_operation operation; +}; + struct regex_list { regex_t re; struct regex_list *next; @@ -120,8 +131,8 @@ static const char *str_operation(enum mt_operation operation) return "realloc enter"; case MT_REALLOC: return "realloc"; - case MT_REALLOC_FAILED: - return "realloc failed"; + case MT_REALLOC_DONE: + return "realloc done"; case MT_MEMALIGN: return "memalign"; case MT_POSIX_MEMALIGN: @@ -389,9 +400,22 @@ static void stack_resolv(struct process *process, struct stack *stack) } } -static void stack_put(struct stack *stack) +static struct rb_stack *stack_get(struct rb_stack *stack_node) +{ + ++stack_node->refcnt; + ++stack_node->stack->refcnt; + + return stack_node; +} + +static void stack_put(struct rb_stack *stack_node) { - if (--stack->refcnt == 0) { + struct stack *stack = stack_node->stack; + + if (!--stack_node->refcnt) + free(stack_node); + + if (!--stack->refcnt) { if (stack->syms) { unsigned int i; @@ -431,6 +455,7 @@ static struct rb_stack *stack_clone(struct process *process, struct rb_stack *st if (!this) return NULL; + this->refcnt = 0; this->leaks = stack_node->leaks; this->n_allocations = stack_node->n_allocations; this->n_mismatched = stack_node->n_mismatched; @@ -439,7 +464,8 @@ static struct rb_stack *stack_clone(struct process *process, struct rb_stack *st this->bytes_leaked = stack_node->bytes_leaked; this->tsc = stack_node->tsc; this->stack = stack_node->stack; - this->stack->refcnt++; + + stack_get(this); /* Add new node and rebalance tree. */ rb_link_node(&this->node, parent, new); @@ -450,7 +476,7 @@ static struct rb_stack *stack_clone(struct process *process, struct rb_stack *st return this; } -static struct rb_stack *stack_add(struct process *process, pid_t pid, void *addrs, uint32_t stack_size, enum mt_operation operation) +static struct rb_stack *stack_add(struct process *process, unsigned int pid, void *addrs, uint32_t stack_size, enum mt_operation operation) { struct rb_root *root = &process->stack_table; struct rb_node **new = &(root->rb_node), *parent = NULL; @@ -487,7 +513,7 @@ static struct rb_stack *stack_add(struct process *process, pid_t pid, void *addr return NULL; } - stack->refcnt = 1; + stack->refcnt = 0; stack->addrs = malloc(stack_size); stack->size = stack_size; stack->entries = stack_size / process->ptr_size; @@ -497,6 +523,7 @@ static struct rb_stack *stack_add(struct process *process, pid_t pid, void *addr memcpy(stack->addrs, addrs, stack_size); + this->refcnt = 0; this->n_allocations = 0; this->n_mismatched = 0; this->total_allocations = 0; @@ -505,6 +532,8 @@ static struct rb_stack *stack_add(struct process *process, pid_t pid, void *addr this->bytes_leaked = 0; this->stack = stack; + stack_get(this); + stack_resolv(process, stack); /* Add new node and rebalance tree. */ @@ -516,7 +545,7 @@ static struct rb_stack *stack_add(struct process *process, pid_t pid, void *addr return this; } -static void process_dump_stack(struct process *process, struct rb_stack *this, int lflag) +static void dump_stack(struct rb_stack *this, int lflag, unsigned long (*get_ulong)(void *), uint8_t ptr_size) { uint32_t i; void *addrs; @@ -526,7 +555,7 @@ static void process_dump_stack(struct process *process, struct rb_stack *this, i return; for(addrs = stack->addrs, i = 0; i < stack->entries; ++i) { - if (dump_printf(" [0x%lx]", process->get_ulong(addrs))) + if (dump_printf(" [0x%lx]", get_ulong(addrs))) return; if (!stack->syms[i]) { @@ -548,7 +577,7 @@ static void process_dump_stack(struct process *process, struct rb_stack *this, i if (dump_printf("\n") == -1) return; - addrs += process->ptr_size; + addrs += ptr_size; } } @@ -625,6 +654,8 @@ static void process_rb_delete_block(struct process *process, struct rb_block *bl block->stack_node->n_allocations--; + stack_put(block->stack_node); + free(block); } @@ -645,7 +676,7 @@ static int process_rb_insert_block(struct process *process, unsigned long addr, parent = *new; if (addr <= this->addr && addr + n > this->addr) { - if (options.kill || options.verbose > 2) { + if (unlikely(options.kill || options.verbose > 2)) { process_dump_collision(process, this, addr, size, operation); if (options.kill) @@ -671,7 +702,8 @@ static int process_rb_insert_block(struct process *process, unsigned long addr, block->stack_node->n_allocations++; block->stack_node->total_allocations++; block->stack_node->bytes_used += size; - block->stack_node->stack->refcnt++; + + stack_get(block->stack_node); /* Add new node and rebalance tree. */ rb_link_node(&block->node, parent, new); @@ -705,7 +737,7 @@ static struct map *_process_add_map(struct process *process, unsigned long addr, list_add_tail(&map->list, &process->map_list); - /* fixit: it is possible that stack_add() can produce false matches */ + /* fixit: it is now possible that stack_add() produce false matches */ return map; } @@ -774,26 +806,38 @@ static void process_init(struct process *process, unsigned int swap_endian, unsi process->filename = NULL; } +static void realloc_del(struct realloc_entry *re) +{ + stack_put(re->stack); + list_del(&re->list); + free(re); +} + void process_reset_allocations(struct process *process) { struct rb_block *rbb, *rbb_next; - struct rb_stack *rbs, *rbs_next; + struct list_head *it, *next; rbtree_postorder_for_each_entry_safe(rbb, rbb_next, &process->block_table, node) { - process->n_allocations--; + --process->n_allocations; + --rbb->stack_node->n_allocations; + stack_put(rbb->stack_node); free(rbb); } + + if (process->n_allocations) + fatal("invalid allocation count!\n"); + process->block_table = RB_ROOT; - rbtree_postorder_for_each_entry_safe(rbs, rbs_next, &process->stack_table, node) { - stack_put(rbs->stack); - free(rbs); + list_for_each_safe(it, next, &process->realloc_list) { + struct realloc_entry *re = container_of(it, struct realloc_entry, list); + + realloc_del(re); } - process->stack_table = RB_ROOT; process->total_allocations = 0; process->bytes_used = 0; - process->stack_trees = 0; process->leaks = 0; process->leaked_bytes = 0; process->tsc = 0; @@ -801,10 +845,24 @@ void process_reset_allocations(struct process *process) void process_reset(struct process *process) { + struct rb_stack *rbs, *rbs_next; struct list_head *it, *next; process_reset_allocations(process); + rbtree_postorder_for_each_entry_safe(rbs, rbs_next, &process->stack_table, node) { + if (rbs->refcnt != 1) + fatal("unexpected stack tree ref count!\n"); + + stack_put(rbs); + --process->stack_trees; + } + + if (process->stack_trees) + fatal("invalid stack tree count!\n"); + + process->stack_table = RB_ROOT; + list_for_each_safe(it, next, &process->map_list) { struct map *map = container_of(it, struct map, list); @@ -944,29 +1002,36 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb struct rb_stack **arr; unsigned long i; void *data; + unsigned long stack_trees = process->stack_trees; + unsigned long (*get_ulong)(void *) = process->get_ulong; + uint8_t ptr_size = process->ptr_size; if (dump_init(file) == -1) return; - dump_printf("Process dump %d %s\n", process->pid, process->filename ? process->filename : ""); + arr = malloc(sizeof(struct rb_stack *) * stack_trees); + if (!arr) + return; - if (!process->stack_trees) - goto skip; + for(i = 0, data = rb_first(&process->stack_table); data; data = rb_next(data)) { + struct rb_stack *stack_node = container_of(data, struct rb_stack, node); - arr = malloc(sizeof(struct rb_stack *) * process->stack_trees); - if (!arr) - goto skip; + arr[i++] = stack_get(stack_node); + } + + if (stack_trees != i) + fatal("invalid stack tree count!\n"); - for(i = 0, data = rb_first(&process->stack_table); data; data = rb_next(data)) - arr[i++] = container_of(data, struct rb_stack, node); + dump_printf("Process dump %d %s\n", process->pid, process->filename ? process->filename : ""); - assert(i == process->stack_trees); + if (!stack_trees) + goto skip; - qsort(arr, process->stack_trees, sizeof(struct rb_stack *), (void *)sortby); + qsort(arr, stack_trees, sizeof(struct rb_stack *), (void *)sortby); if (file == stderr) { - unsigned long n = process->stack_trees / 2; - unsigned long l = process->stack_trees - 1; + unsigned long n = stack_trees / 2; + unsigned long l = stack_trees - 1; for(i = 0; i < n; ++i) { struct rb_stack *tmp = arr[i]; @@ -976,7 +1041,7 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb } } - for(i = 0; i < process->stack_trees; ++i) { + for(i = 0; i < stack_trees; ++i) { struct rb_stack *stack = arr[i]; if (!skipfunc(stack)) { @@ -1011,11 +1076,15 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb if (dump_printf(" tsc: %llu\n", stack->tsc) == -1) break; - process_dump_stack(process, stack, lflag); + dump_stack(stack, lflag, get_ulong, ptr_size); } } - free(arr); + + for(i = 0; i < stack_trees; ++i) + stack_put(arr[i]); + skip: + free(arr); dump_flush(); return; } @@ -1112,7 +1181,7 @@ void *process_scan(struct process *process, void *leaks, uint32_t payload_len) for(i = 0; i < n; ++i) { struct rb_block *block = process_rb_search(&process->block_table, process->get_ulong(leaks)); - if (!(block->flags & BLOCK_LEAKED)) { + if (block && !(block->flags & BLOCK_LEAKED)) { block->flags |= BLOCK_LEAKED; block->stack_node->leaks++; @@ -1189,7 +1258,7 @@ void process_munmap(struct process *process, struct mt_msg *mt_msg, void *payloa break; if (!is_mmap(block->stack_node->stack->operation)) { - if (options.kill || options.verbose > 2) { + if (unlikely(options.kill || options.verbose > 2)) { fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr); if (options.kill) @@ -1255,7 +1324,6 @@ static int is_sane(struct rb_block *block, enum mt_operation op) switch(block->stack_node->stack->operation) { case MT_MALLOC: case MT_REALLOC: - case MT_REALLOC_FAILED: case MT_MEMALIGN: case MT_POSIX_MEMALIGN: case MT_ALIGNED_ALLOC: @@ -1285,6 +1353,7 @@ void process_free(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 ptr; + unsigned long pid; void *stack_data; unsigned long stack_size; @@ -1295,6 +1364,7 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload) struct mt_alloc_payload_64 *mt_alloc = payload; ptr = process->get_ulong(&mt_alloc->ptr); + pid = process->get_ulong(&mt_alloc->size); stack_data = payload + sizeof(*mt_alloc); stack_size = (payload_len - sizeof(*mt_alloc)); @@ -1303,6 +1373,7 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload) struct mt_alloc_payload_32 *mt_alloc = payload; ptr = process->get_ulong(&mt_alloc->ptr); + pid = process->get_ulong(&mt_alloc->size); stack_data = payload + sizeof(*mt_alloc); stack_size = (payload_len - sizeof(*mt_alloc)); @@ -1313,7 +1384,7 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload) block = process_rb_search(&process->block_table, ptr); if (block) { if (is_mmap(block->stack_node->stack->operation)) { - if (options.kill || options.verbose > 2) { + if (unlikely(options.kill || options.verbose > 2)) { fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr); if (options.kill) @@ -1328,12 +1399,27 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload) stack->tsc = process->tsc++; } + if (mt_msg->operation == MT_REALLOC_ENTER) { + struct realloc_entry *re = malloc(sizeof(*re)); + + re->addr = block->addr; + re->size = block->size; + re->flags = block->flags; + re->operation = block->stack_node->stack->operation; + re->pid = pid; + re->stack = block->stack_node; + + stack_get(re->stack); + + list_add_tail(&re->list, &process->realloc_list); + } + process_rb_delete_block(process, block); } else { if (!process->attached) { - if (options.kill || options.verbose > 2) { - fprintf(stderr, ">>> block %#lx not found pid:%d tid:%d\n", ptr, process->pid, mt_msg->tid); + if (unlikely(options.kill || options.verbose > 2)) { + fprintf(stderr, ">>> block %#lx not found pid:%d\n", ptr, process->pid); if (options.kill) abort(); @@ -1342,6 +1428,46 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload) } } +void process_realloc_done(struct process *process, struct mt_msg *mt_msg, void *payload) +{ + unsigned long ptr; + unsigned long pid; + struct list_head *it; + + if (!process->tracing) + return; + + if (process->is_64bit) { + struct mt_alloc_payload_64 *mt_alloc = payload; + + ptr = process->get_ulong(&mt_alloc->ptr); + pid = process->get_ulong(&mt_alloc->size); + } + else { + struct mt_alloc_payload_32 *mt_alloc = payload; + + ptr = process->get_ulong(&mt_alloc->ptr); + pid = process->get_ulong(&mt_alloc->size); + } + + debug(DEBUG_FUNCTION, "ptr=%#lx ", ptr); + + list_for_each(it, &process->realloc_list) { + struct realloc_entry *re = container_of(it, struct realloc_entry, list); + + if (re->pid == pid) { + if (!ptr) + process_rb_insert_block(process, re->addr, re->size, re->stack, re->flags, re->operation); + + realloc_del(re); + + break; + } + } + + return; +} + void process_alloc(struct process *process, struct mt_msg *mt_msg, void *payload) { struct rb_block *block = NULL; @@ -1379,7 +1505,7 @@ void process_alloc(struct process *process, struct mt_msg *mt_msg, void *payload block = process_rb_search_range(&process->block_table, ptr, size); if (block) { - if (options.kill || options.verbose > 2) { + if (unlikely(options.kill || options.verbose > 2)) { process_dump_collision(process, block, ptr, size, mt_msg->operation); if (options.kill) @@ -1405,7 +1531,7 @@ void process_reinit(struct process *process, unsigned int swap_endian, unsigned process_init(process, swap_endian, is_64bit, attached); } -struct process *process_new(pid_t pid, unsigned int swap_endian, unsigned int tracing) +struct process *process_new(unsigned int pid, unsigned int swap_endian, unsigned int tracing) { struct process *process = malloc(sizeof(*process)); @@ -1416,6 +1542,7 @@ struct process *process_new(pid_t pid, unsigned int swap_endian, unsigned int tr process->block_table = RB_ROOT; process->stack_table = RB_ROOT; INIT_LIST_HEAD(&process->map_list); + INIT_LIST_HEAD(&process->realloc_list); process_init(process, swap_endian, 0, 0); @@ -1537,7 +1664,6 @@ void process_status(struct process *process) " number of open allocations: %lu\n" " total number of allocations: %lu\n" " average allocation: %f bytes\n" - " number of allocators: %lu\n" " number of leaks: %lu\n" " number of leaked bytes: %llu\n" " status: %s\n", @@ -1546,7 +1672,6 @@ void process_status(struct process *process) process->n_allocations, process->total_allocations, process->n_allocations ? (double)process->bytes_used / process->n_allocations : 0.0, - process->stack_trees, process->leaks, process->leaked_bytes, process_get_status(process) diff --git a/client/process.h b/client/process.h index 5c886aa..8a38122 100644 --- a/client/process.h +++ b/client/process.h @@ -53,7 +53,7 @@ struct lib { struct process { enum process_status status; - pid_t pid; + unsigned int pid; char *filename; unsigned long bytes_used; unsigned long n_allocations; @@ -64,6 +64,7 @@ struct process { struct rb_root block_table; struct rb_root stack_table; struct list_head map_list; + struct list_head realloc_list; unsigned long long tsc; unsigned int tracing:1; unsigned int swap_endian:1; @@ -77,7 +78,7 @@ struct process { uint8_t ptr_size; }; -struct process *process_new(pid_t pid, unsigned int swap_endian, unsigned int tracing); +struct process *process_new(unsigned int 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); @@ -98,6 +99,7 @@ void process_munmap(struct process *process, struct mt_msg *msg, void *payload); void process_add_map(struct process *process, void *payload, uint32_t payload_len); void process_del_map(struct process *process, void *payload, uint32_t payload_len); void process_detach(struct process *process); +void process_realloc_done(struct process *process, struct mt_msg *mt_msg, void *payload); unsigned long process_leaks_scan(struct process *process, int mode); diff --git a/client/readline.c b/client/readline.c index a97b7da..8e18afb 100644 --- a/client/readline.c +++ b/client/readline.c @@ -503,7 +503,9 @@ static int do_show_info(struct cmd_opt *cmd, struct cmd_opt *opt, int argc, cons return -1; } + client_request_info(); client_show_info(); + return 0; } diff --git a/common.c b/common.c index ec89ac4..37d1c49 100644 --- a/common.c +++ b/common.c @@ -70,7 +70,7 @@ unsigned long find_block(unsigned long (*get_val)(void *data, unsigned long inde first = 0; last = n; - if (addr < get_val(arr,first)) + if (addr < get_val(arr, first)) return n; if (addr > get_val(arr, last - 1)) @@ -78,18 +78,18 @@ unsigned long find_block(unsigned long (*get_val)(void *data, unsigned long inde do { middle = (first + last) >> 1; + val = get_val(arr, middle); if (addr < val) last = middle; - else if (addr > val) + else + if (addr > val) first = middle + 1; else return middle; - } while (first < last); return n; } - diff --git a/common.h b/common.h index dd26368..ab1bd9c 100644 --- a/common.h +++ b/common.h @@ -58,6 +58,14 @@ (type *)( (char *)__mptr - offsetof(type,member) );}) +#if 1 +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#else +#define likely(x) (x) +#define unlikely(x) (x) +#endif + #define fatal(fmt...) _fatal(__FILE__,__PRETTY_FUNCTION__,__LINE__ , ##fmt),abort() void _fatal(const char *file, const char *func, int line, const char *format, ...) __attribute__ ((format (printf, 4, 5)));; diff --git a/config.h.in b/config.h.in index cd2b5a7..f904bca 100644 --- a/config.h.in +++ b/config.h.in @@ -18,6 +18,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_BFD_H +/* Define to 1 if you have the `clock_gettime' function. */ +#undef HAVE_CLOCK_GETTIME + /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H @@ -60,6 +63,9 @@ /* Define to 1 if you have the `readline' library (-lreadline). */ #undef HAVE_LIBREADLINE +/* Define to 1 if you have the `rt' library (-lrt). */ +#undef HAVE_LIBRT + /* Define to 1 if you have the `selinux' library (-lselinux). */ #undef HAVE_LIBSELINUX diff --git a/configure b/configure index 8862f3a..836ad8e 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-ng 0.4. +# Generated by GNU Autoconf 2.69 for mtrace-ng 0.5. # # Report bugs to . # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='mtrace-ng' PACKAGE_TARNAME='mtrace-ng' -PACKAGE_VERSION='0.4' -PACKAGE_STRING='mtrace-ng 0.4' +PACKAGE_VERSION='0.5' +PACKAGE_STRING='mtrace-ng 0.5' PACKAGE_BUGREPORT='stefani@seibold.net' PACKAGE_URL='' @@ -1329,7 +1329,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-ng 0.4 to adapt to many kinds of systems. +\`configure' configures mtrace-ng 0.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1399,7 +1399,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of mtrace-ng 0.4:";; + short | recursive ) echo "Configuration of mtrace-ng 0.5:";; esac cat <<\_ACEOF @@ -1518,7 +1518,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -mtrace-ng configure 0.4 +mtrace-ng configure 0.5 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2124,7 +2124,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-ng $as_me 0.4, which was +It was created by mtrace-ng $as_me 0.5, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -12006,7 +12006,7 @@ fi # Define the identity of the package. PACKAGE='mtrace-ng' - VERSION='0.4' + VERSION='0.5' cat >>confdefs.h <<_ACEOF @@ -13238,6 +13238,7 @@ for ac_func in \ atexit \ getcwd \ gettimeofday \ + clock_gettime \ memset \ mkdir \ rmdir \ @@ -13260,6 +13261,54 @@ fi done +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +$as_echo_n "checking for clock_gettime in -lrt... " >&6; } +if ${ac_cv_lib_rt_clock_gettime+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (); +int +main () +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_rt_clock_gettime=yes +else + ac_cv_lib_rt_clock_gettime=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBRT 1 +_ACEOF + + LIBS="-lrt $LIBS" + +else + as_fn_error $? "*** librt not found on your system" "$LINENO" 5 + +fi + # # Debugging @@ -13844,7 +13893,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-ng $as_me 0.4, which was +This file was extended by mtrace-ng $as_me 0.5, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13910,7 +13959,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-ng config.status 0.4 +mtrace-ng config.status 0.5 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 8841a84..792ae43 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-ng],[0.4],[stefani@seibold.net]) +AC_INIT([mtrace-ng],[0.5],[stefani@seibold.net]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_SRCDIR(main.c) AC_CONFIG_MACRO_DIR([config/m4]) @@ -227,6 +227,7 @@ AC_CHECK_FUNCS([ \ atexit \ getcwd \ gettimeofday \ + clock_gettime \ memset \ mkdir \ rmdir \ @@ -238,6 +239,9 @@ AC_CHECK_FUNCS([ \ process_vm_readv \ ]) +AC_CHECK_LIB([rt], [clock_gettime],, + [AC_MSG_ERROR([*** librt not found on your system])] +) # # Debugging diff --git a/dwarf.c b/dwarf.c index 4571130..86994c1 100644 --- a/dwarf.c +++ b/dwarf.c @@ -317,88 +317,80 @@ static const uint8_t dwarf_operands[256] = { [DW_OP_call_ref] = OPND1(OFFSET) }; -static int dwarf_access_mem(struct dwarf_addr_space *as, arch_addr_t addr, void *valp, size_t size) +static inline __attribute__((always_inline)) int dwarf_access_mem(struct dwarf_addr_space *as, arch_addr_t addr, void *valp, size_t size) { struct dwarf_cursor *c = &as->cursor; - if (!addr) { + if (unlikely(!addr)) { debug(DEBUG_DWARF, "invalid null memory access"); return -DWARF_EINVAL; } - if (!valp) + if (unlikely(!valp)) return 0; - if (!as) { + if (unlikely(!as)) { memcpy(valp, (void *)addr, size); return 0; } - if (as->addr && as->addr <= addr && addr + size - as->addr <= sizeof(as->val)) { - memcpy(valp, &as->val_bytes[addr - as->addr], size); - return 0; - } - - if (copy_from_proc(c->task, addr, &as->val, sizeof(as->val)) != sizeof(as->val)) { + if (unlikely(copy_from_proc(c->task, addr, valp, size) != (int)size)) { debug(DEBUG_DWARF, "cannot access memory %#lx of pid %d", addr, c->task->pid); return -DWARF_EINVAL; } - as->addr = addr; - memcpy(valp, as->val_bytes, size); - return 0; } -static inline int dwarf_read8(struct dwarf_addr_space *as, arch_addr_t *addr, void *valp) +static inline __attribute__((always_inline)) int dwarf_read8(struct dwarf_addr_space *as, arch_addr_t *addr, void *valp) { int ret; ret = dwarf_access_mem(as, *addr, valp, 1); - if (ret) + if (unlikely(ret)) return ret; *addr += 1; return 0; } -static inline int dwarf_read16(struct dwarf_addr_space *as, arch_addr_t *addr, void *valp) +static inline __attribute__((always_inline)) int dwarf_read16(struct dwarf_addr_space *as, arch_addr_t *addr, void *valp) { int ret; ret = dwarf_access_mem(as, *addr, valp, 2); - if (ret) + if (unlikely(ret)) return ret; *addr += 2; return 0; } -static inline int dwarf_read32(struct dwarf_addr_space *as, arch_addr_t *addr, void *valp) +static inline __attribute__((always_inline)) int dwarf_read32(struct dwarf_addr_space *as, arch_addr_t *addr, void *valp) { int ret; ret = dwarf_access_mem(as, *addr, valp, 4); - if (ret) + if (unlikely(ret)) return ret; *addr += 4; return 0; } -static inline int dwarf_read64(struct dwarf_addr_space *as, arch_addr_t *addr, void *valp) +static inline __attribute__((always_inline)) int dwarf_read64(struct dwarf_addr_space *as, arch_addr_t *addr, void *valp) { int ret; ret = dwarf_access_mem(as, *addr, valp, 8); - if (ret) + if (unlikely(ret)) return ret; *addr += 8; return 0; } -static inline int dwarf_readw(struct dwarf_addr_space *as, arch_addr_t *addr, arch_addr_t *valp, int is_64bit) +static int dwarf_readw(struct dwarf_addr_space *as, arch_addr_t *addr, arch_addr_t *valp, int is_64bit) { int ret; @@ -428,7 +420,7 @@ static int dwarf_read_uleb128(struct dwarf_addr_space *as, arch_addr_t *addr, ar int ret; do { - if ((ret = dwarf_read8(as, addr, &byte)) < 0) + if (unlikely((ret = dwarf_read8(as, addr, &byte)) < 0)) return ret; val |= ((arch_addr_t) byte & 0x7f) << shift; @@ -448,7 +440,7 @@ static int dwarf_read_sleb128(struct dwarf_addr_space *as, arch_addr_t *addr, ar int ret; do { - if ((ret = dwarf_read8(as, addr, &byte)) < 0) + if (unlikely((ret = dwarf_read8(as, addr, &byte)) < 0)) return ret; val |= ((arch_addr_t) byte & 0x7f) << shift; @@ -518,7 +510,7 @@ static int dwarf_read_encoded_pointer(struct dwarf_addr_space *as, int local, *addr = (initial_addr + size - 1) & -size; - if ((ret = dwarf_readw(as, addr, tmp_ptr, is_64bit)) < 0) + if (unlikely((ret = dwarf_readw(as, addr, tmp_ptr, is_64bit)) < 0)) return ret; *valp = tmp.addr; return 0; @@ -526,45 +518,45 @@ static int dwarf_read_encoded_pointer(struct dwarf_addr_space *as, int local, switch (encoding & DW_EH_PE_FORMAT_MASK) { case DW_EH_PE_ptr: - if ((ret = dwarf_readw(as, addr, tmp_ptr, is_64bit)) < 0) + if (unlikely((ret = dwarf_readw(as, addr, tmp_ptr, is_64bit)) < 0)) return ret; val = tmp.addr; break; case DW_EH_PE_uleb128: - if ((ret = dwarf_read_uleb128(as, addr, &val)) < 0) + if (unlikely((ret = dwarf_read_uleb128(as, addr, &val)) < 0)) return ret; break; case DW_EH_PE_udata2: - if ((ret = dwarf_read16(as, addr, tmp_ptr)) < 0) + if (unlikely((ret = dwarf_read16(as, addr, tmp_ptr)) < 0)) return ret; val = tmp.uval16; break; case DW_EH_PE_udata4: - if ((ret = dwarf_read32(as, addr, tmp_ptr)) < 0) + if (unlikely((ret = dwarf_read32(as, addr, tmp_ptr)) < 0)) return ret; val = tmp.uval32; break; case DW_EH_PE_udata8: - if ((ret = dwarf_read64(as, addr, tmp_ptr)) < 0) + if (unlikely((ret = dwarf_read64(as, addr, tmp_ptr)) < 0)) return ret; val = tmp.uval64; break; case DW_EH_PE_sleb128: - if ((ret = dwarf_read_sleb128(as, addr, &val)) < 0) + if (unlikely((ret = dwarf_read_sleb128(as, addr, &val)) < 0)) return ret; break; case DW_EH_PE_sdata2: - if ((ret = dwarf_read16(as, addr, tmp_ptr)) < 0) + if (unlikely((ret = dwarf_read16(as, addr, tmp_ptr)) < 0)) return ret; val = tmp.sval16; break; case DW_EH_PE_sdata4: - if ((ret = dwarf_read32(as, addr, tmp_ptr)) < 0) + if (unlikely((ret = dwarf_read32(as, addr, tmp_ptr)) < 0)) return ret; val = tmp.sval32; break; case DW_EH_PE_sdata8: - if ((ret = dwarf_read64(as, addr, tmp_ptr)) < 0) + if (unlikely((ret = dwarf_read64(as, addr, tmp_ptr)) < 0)) return ret; val = tmp.sval64; break; @@ -610,7 +602,7 @@ static int dwarf_read_encoded_pointer(struct dwarf_addr_space *as, int local, arch_addr_t indirect_addr = val; if (tmp_ptr) { - if ((ret = dwarf_readw(indirect_as, &indirect_addr, &val, is_64bit)) < 0) + if (unlikely((ret = dwarf_readw(indirect_as, &indirect_addr, &val, is_64bit)) < 0)) return ret; } else @@ -652,7 +644,7 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf dci->lsda_encoding = DW_EH_PE_omit; - if ((ret = dwarf_read32(NULL, &addr, &u32val)) < 0) + if (unlikely((ret = dwarf_read32(NULL, &addr, &u32val)) < 0)) return ret; if (u32val != 0xffffffff) { @@ -662,7 +654,7 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf len = u32val; cie_end_addr = addr + len; - if ((ret = dwarf_read32(NULL, &addr, &cie_id)) < 0) + if (unlikely((ret = dwarf_read32(NULL, &addr, &cie_id)) < 0)) return ret; if (cie_id) { @@ -674,13 +666,13 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf /* the CIE is in the 64-bit DWARF format */ uint64_t cie_id; - if ((ret = dwarf_read64(NULL, &addr, &u64val)) < 0) + if (unlikely((ret = dwarf_read64(NULL, &addr, &u64val)) < 0)) return ret; len = u64val; cie_end_addr = addr + len; - if ((ret = dwarf_read64(NULL, &addr, &cie_id)) < 0) + if (unlikely((ret = dwarf_read64(NULL, &addr, &cie_id)) < 0)) return ret; if (cie_id) { @@ -690,7 +682,7 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf } dci->cie_instr_end = cie_end_addr; - if ((ret = dwarf_read8(NULL, &addr, &version)) < 0) + if (unlikely((ret = dwarf_read8(NULL, &addr, &version)) < 0)) return ret; if (version != DWARF_CIE_VERSION && version != DWARF_CIE_VERSION_GCC) { @@ -701,7 +693,7 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf /* read and parse the augmentation string: */ memset(augstr, 0, sizeof(augstr)); for (i = 0;;) { - if ((ret = dwarf_read8(NULL, &addr, &ch)) < 0) + if (unlikely((ret = dwarf_read8(NULL, &addr, &ch)) < 0)) return ret; if (!ch) @@ -711,19 +703,19 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf augstr[i++] = ch; } - if ((ret = dwarf_read_uleb128(NULL, &addr, &dci->code_align)) < 0 || (ret = dwarf_read_sleb128(NULL, &addr, &dci->data_align)) < 0) + if (unlikely((ret = dwarf_read_uleb128(NULL, &addr, &dci->code_align)) < 0 || (ret = dwarf_read_sleb128(NULL, &addr, &dci->data_align)) < 0)) return ret; /* Read the return-address column either as a u8 or as a uleb128. */ if (version == 1) { - if ((ret = dwarf_read8(NULL, &addr, &ch)) < 0) + if (unlikely((ret = dwarf_read8(NULL, &addr, &ch)) < 0)) return ret; dci->ret_addr_column = dwarf_to_regnum(ch); } else { arch_addr_t val; - if ((ret = dwarf_read_uleb128(NULL, &addr, &val)) < 0) + if (unlikely((ret = dwarf_read_uleb128(NULL, &addr, &val)) < 0)) return ret; dci->ret_addr_column = dwarf_to_regnum(val); } @@ -731,7 +723,7 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf i = 0; if (augstr[0] == 'z') { dci->sized_augmentation = 1; - if ((ret = dwarf_read_uleb128(NULL, &addr, &aug_size)) < 0) + if (unlikely((ret = dwarf_read_uleb128(NULL, &addr, &aug_size)) < 0)) return ret; i++; } @@ -740,13 +732,13 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf switch (augstr[i]) { case 'L': /* read the LSDA pointer-encoding format. */ - if ((ret = dwarf_read8(NULL, &addr, &ch)) < 0) + if (unlikely((ret = dwarf_read8(NULL, &addr, &ch)) < 0)) return ret; dci->lsda_encoding = ch; break; case 'R': /* read the FDE pointer-encoding format. */ - if ((ret = dwarf_read8(NULL, &addr, &fde_encoding)) < 0) + if (unlikely((ret = dwarf_read8(NULL, &addr, &fde_encoding)) < 0)) return ret; break; case 'P': @@ -754,9 +746,9 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf uint8_t handler_encoding; /* read the personality-routine pointer-encoding format. */ - if ((ret = dwarf_read8(NULL, &addr, &handler_encoding)) < 0) + if (unlikely((ret = dwarf_read8(NULL, &addr, &handler_encoding)) < 0)) return ret; - if ((ret = dwarf_read_encoded_pointer_local(as, &addr, handler_encoding, NULL, 0)) < 0) + if (unlikely((ret = dwarf_read_encoded_pointer_local(as, &addr, handler_encoding, NULL, 0)) < 0)) break; } case 'S': @@ -791,7 +783,7 @@ static int dwarf_extract_cfi_from_fde(struct dwarf_addr_space *as, void *addrp) struct dwarf_cie_info *dci = &as->cursor.dci; arch_addr_t addr = (arch_addr_t)addrp; - if ((ret = dwarf_read32(NULL, &addr, &u32val)) < 0) + if (unlikely((ret = dwarf_read32(NULL, &addr, &u32val)) < 0)) return ret; if (u32val != 0xffffffff) { @@ -809,7 +801,7 @@ static int dwarf_extract_cfi_from_fde(struct dwarf_addr_space *as, void *addrp) fde_end_addr = addr + u32val; cie_offset_addr = addr; - if ((ret = dwarf_read32(NULL, &addr, &cie_offset32)) < 0) + if (unlikely((ret = dwarf_read32(NULL, &addr, &cie_offset32)) < 0)) return ret; cie_offset = cie_offset32; @@ -819,13 +811,13 @@ static int dwarf_extract_cfi_from_fde(struct dwarf_addr_space *as, void *addrp) /* the FDE is in the 64-bit DWARF format */ - if ((ret = dwarf_read64(NULL, &addr, &u64val)) < 0) + if (unlikely((ret = dwarf_read64(NULL, &addr, &u64val)) < 0)) return ret; fde_end_addr = addr + u64val; cie_offset_addr = addr; - if ((ret = dwarf_read64(NULL, &addr, &cie_offset64)) < 0) + if (unlikely((ret = dwarf_read64(NULL, &addr, &cie_offset64)) < 0)) return ret; cie_offset = cie_offset64; @@ -846,31 +838,32 @@ static int dwarf_extract_cfi_from_fde(struct dwarf_addr_space *as, void *addrp) if ((ret = parse_cie(as, cie_addr, dci)) < 0) return ret; - if ((ret = dwarf_read_encoded_pointer_local(as, &addr, dci->fde_encoding, &dci->start_ip, 0)) < 0) + if (unlikely((ret = dwarf_read_encoded_pointer_local(as, &addr, dci->fde_encoding, &dci->start_ip, 0)) < 0)) return ret; /* IP-range has same encoding as FDE pointers, except that it's always an absolute value: */ - if ((ret = dwarf_read_encoded_pointer_local(as, &addr, dci->fde_encoding & DW_EH_PE_FORMAT_MASK, &dci->ip_range, 0)) < 0) + if (unlikely((ret = dwarf_read_encoded_pointer_local(as, &addr, dci->fde_encoding & DW_EH_PE_FORMAT_MASK, &dci->ip_range, 0)) < 0)) return ret; if (dci->sized_augmentation) { arch_addr_t aug_size; - if ((ret = dwarf_read_uleb128(NULL, &addr, &aug_size)) < 0) + if (unlikely((ret = dwarf_read_uleb128(NULL, &addr, &aug_size)) < 0)) return ret; dci->fde_instr_start = addr + aug_size; } else dci->fde_instr_start = addr; + dci->fde_instr_end = fde_end_addr; - if ((ret = dwarf_read_encoded_pointer_local(as, &addr, dci->lsda_encoding, NULL, dci->start_ip)) < 0) + if (unlikely((ret = dwarf_read_encoded_pointer_local(as, &addr, dci->lsda_encoding, NULL, dci->start_ip)) < 0)) return ret; if (dci->have_abi_marker) { - if ((ret = dwarf_read16(NULL, &addr, &dci->abi)) < 0 || (ret = dwarf_read16(NULL, &addr, &dci->tag)) < 0) + if (unlikely((ret = dwarf_read16(NULL, &addr, &dci->abi)) < 0 || (ret = dwarf_read16(NULL, &addr, &dci->tag)) < 0)) return ret; } @@ -885,34 +878,18 @@ static inline int lib_addr_match(struct libref *libref, arch_addr_t ip) int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip) { struct dwarf_cursor *c = &as->cursor; - struct task *leader; - struct list_head *it; if (c->use_prev_instr) ip -= 1; - if (as->cursor.libref) { - if (lib_addr_match(as->cursor.libref, ip)) + if (likely(c->libref)) { + if (lib_addr_match(c->libref, ip)) return 0; } - leader = c->task->leader; - - as->cursor.libref = NULL; - - list_for_each(it, &leader->libraries_list) { - struct libref *libref = container_of(it, struct library, list)->libref; - - if (lib_addr_match(libref, ip)) { - as->cursor.libref = libref; - break; - } - } - - if (!as->cursor.libref) { - debug(DEBUG_DWARF, "no mapping found for IP %#lx", ip); + c->libref = addr2libref(c->task->leader, ip); + if (!c->libref) return -DWARF_ENOINFO; - } return 0; } @@ -953,7 +930,7 @@ static int dwarf_search_unwind_table(struct dwarf_addr_space *as, arch_addr_t ip struct libref *libref = as->cursor.libref; e = lookup(table_data, table_len, ip - libref->load_addr - libref->seg_offset); - if (!e) { + if (unlikely(!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; @@ -961,7 +938,7 @@ static int dwarf_search_unwind_table(struct dwarf_addr_space *as, arch_addr_t ip 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) + if (unlikely((ret = dwarf_extract_cfi_from_fde(as, fde_addr)) < 0)) return ret; dci->start_ip -= ARCH_ADDR_T(libref->image_addr) - libref->load_addr; @@ -969,7 +946,7 @@ static int dwarf_search_unwind_table(struct dwarf_addr_space *as, arch_addr_t ip if (!as->is_64bit) dci->start_ip &= 0xffffffff; - if (ip < dci->start_ip || ip >= dci->start_ip + dci->ip_range) { + if (unlikely(ip < dci->start_ip || ip >= dci->start_ip + dci->ip_range)) { debug(DEBUG_DWARF, "IP %#lx out of range %#lx-%#lx", ip, dci->start_ip, dci->start_ip + dci->ip_range); return -DWARF_ENOINFO; } @@ -983,7 +960,7 @@ static int dwarf_access_reg(struct dwarf_addr_space *as, unsigned int reg, arch_ int map = dwarf_arch_map_reg(as, reg); - if (map < 0) { + if (unlikely(map < 0)) { debug(DEBUG_DWARF, "could not map register %u", reg); return map; @@ -1021,7 +998,7 @@ static int dwarf_get_reg(struct dwarf_addr_space *as, unsigned int reg, arch_add { struct dwarf_cursor *c = &as->cursor; - if (reg >= as->num_regs) + if (unlikely(reg >= as->num_regs)) return err_inval_reg_num((unsigned int)*valp); if (as->ip_reg == reg) { @@ -1037,17 +1014,17 @@ static int dwarf_get_reg(struct dwarf_addr_space *as, unsigned int reg, arch_add return dwarf_get(as, c->loc[reg], valp); } -static inline int read_regnum(unsigned int num_regs, arch_addr_t *addr, arch_addr_t *valp) +static int read_regnum(unsigned int num_regs, arch_addr_t *addr, arch_addr_t *valp) { int ret; arch_addr_t val; - if ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0) + if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0)) return ret; val = dwarf_to_regnum(val); - if (val >= num_regs) + if (unlikely(val >= num_regs)) return err_inval_reg_num(val); *valp = val; @@ -1086,7 +1063,7 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state * /* Process everything up to and including the current 'ip', including all the DW_CFA_advance_loc instructions. */ while (curr_ip <= ip && *addr < end_addr) { - if ((ret = dwarf_read8(NULL, addr, &op)) < 0) + if (unlikely((ret = dwarf_read8(NULL, addr, &op)) < 0)) return ret; if (op & DWARF_CFA_OPCODE_MASK) { @@ -1098,17 +1075,17 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state * curr_ip += operand * dci->code_align; break; case DW_CFA_advance_loc1: - if ((ret = dwarf_read8(NULL, addr, &u8)) < 0) + if (unlikely((ret = dwarf_read8(NULL, addr, &u8)) < 0)) goto fail; curr_ip += u8 * dci->code_align; break; case DW_CFA_advance_loc2: - if ((ret = dwarf_read16(NULL, addr, &u16)) < 0) + if (unlikely((ret = dwarf_read16(NULL, addr, &u16)) < 0)) goto fail; curr_ip += u16 * dci->code_align; break; case DW_CFA_advance_loc4: - if ((ret = dwarf_read32(NULL, addr, &u32)) < 0) + if (unlikely((ret = dwarf_read32(NULL, addr, &u32)) < 0)) goto fail; curr_ip += u32 * dci->code_align; break; @@ -1118,30 +1095,30 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state * goto fail; case DW_CFA_offset: regnum = dwarf_to_regnum(operand); - if (regnum >= num_regs) { + if (unlikely(regnum >= num_regs)) { debug(DEBUG_DWARF, "Invalid register number %u in DW_cfa_OFFSET", (unsigned int)regnum); ret = -DWARF_EBADREG; goto fail; } - if ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0) + if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0)) goto fail; set_reg(rs_current, regnum, DWARF_WHERE_CFAREL, val * dci->data_align); break; case DW_CFA_offset_extended: - if (((ret = read_regnum(num_regs, addr, ®num)) < 0) - || ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0)) + if (unlikely(((ret = read_regnum(num_regs, addr, ®num)) < 0) + || ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0))) goto fail; set_reg(rs_current, regnum, DWARF_WHERE_CFAREL, val * dci->data_align); break; case DW_CFA_offset_extended_sf: - if (((ret = read_regnum(num_regs, addr, ®num)) < 0) - || ((ret = dwarf_read_sleb128(NULL, addr, &val)) < 0)) + if (unlikely(((ret = read_regnum(num_regs, addr, ®num)) < 0) + || ((ret = dwarf_read_sleb128(NULL, addr, &val)) < 0))) goto fail; set_reg(rs_current, regnum, DWARF_WHERE_CFAREL, val * dci->data_align); break; case DW_CFA_restore: regnum = dwarf_to_regnum(operand); - if (regnum >= num_regs) { + if (unlikely(regnum >= num_regs)) { debug(DEBUG_DWARF, "Invalid register number %u in DW_CFA_restore", (unsigned int)regnum); ret = -DWARF_EINVAL; goto fail; @@ -1149,9 +1126,9 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state * rs_current->reg[regnum] = rs_initial->reg[regnum]; break; case DW_CFA_restore_extended: - if ((ret = dwarf_read_uleb128(NULL, addr, ®num)) < 0) + if (unlikely((ret = dwarf_read_uleb128(NULL, addr, ®num)) < 0)) goto fail; - if (regnum >= num_regs) { + if (unlikely(regnum >= num_regs)) { debug(DEBUG_DWARF, "Invalid register number %u in " "DW_CFA_restore_extended", (unsigned int)regnum); ret = -DWARF_EINVAL; goto fail; @@ -1161,26 +1138,26 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state * case DW_CFA_nop: break; case DW_CFA_set_loc: - if ((ret = dwarf_read_encoded_pointer_local(as, addr, dci->fde_encoding, &curr_ip, c->dci.start_ip)) < 0) + if (unlikely((ret = dwarf_read_encoded_pointer_local(as, addr, dci->fde_encoding, &curr_ip, c->dci.start_ip)) < 0)) goto fail; break; case DW_CFA_undefined: - if ((ret = read_regnum(num_regs, addr, ®num)) < 0) + if (unlikely((ret = read_regnum(num_regs, addr, ®num)) < 0)) goto fail; set_reg(rs_current, regnum, DWARF_WHERE_UNDEF, 0); break; case DW_CFA_same_value: - if ((ret = read_regnum(num_regs, addr, ®num)) < 0) + if (unlikely((ret = read_regnum(num_regs, addr, ®num)) < 0)) goto fail; set_reg(rs_current, regnum, DWARF_WHERE_SAME, 0); break; case DW_CFA_register: - if ((ret = read_regnum(num_regs, addr, ®num)) < 0) + if (unlikely((ret = read_regnum(num_regs, addr, ®num)) < 0)) goto fail; - if ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0) + if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0)) goto fail; n = dwarf_to_regnum(val); - if (n >= num_regs) { + if (unlikely(n >= num_regs)) { debug(DEBUG_DWARF, "Invalid register number value %u in DW_CFA_REGISTER", (unsigned int)val); ret = -DWARF_EBADREG; goto fail; @@ -1194,7 +1171,7 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state * rs_stack = rs_tmp; break; case DW_CFA_restore_state: - if (!rs_stack) { + if (unlikely(!rs_stack)) { debug(DEBUG_DWARF, "register-state stack underflow"); ret = -DWARF_EINVAL; goto fail; @@ -1205,31 +1182,31 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state * free(rs_tmp); break; case DW_CFA_def_cfa: - if (((ret = read_regnum(num_regs, addr, ®num)) < 0) - || ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0)) + if ((unlikely((ret = read_regnum(num_regs, addr, ®num)) < 0) + || ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0))) goto fail; set_reg(rs_current, DWARF_CFA_REG_COLUMN(as), DWARF_WHERE_REG, regnum); set_reg(rs_current, DWARF_CFA_OFF_COLUMN(as), 0, val); /* NOT factored! */ break; case DW_CFA_def_cfa_sf: - if (((ret = read_regnum(num_regs, addr, ®num)) < 0) - || ((ret = dwarf_read_sleb128(NULL, addr, &val)) < 0)) + if (unlikely(((ret = read_regnum(num_regs, addr, ®num)) < 0) + || ((ret = dwarf_read_sleb128(NULL, addr, &val)) < 0))) goto fail; set_reg(rs_current, DWARF_CFA_REG_COLUMN(as), DWARF_WHERE_REG, regnum); set_reg(rs_current, DWARF_CFA_OFF_COLUMN(as), 0, val * dci->data_align); /* factored! */ break; case DW_CFA_def_cfa_register: - if ((ret = read_regnum(num_regs, addr, ®num)) < 0) + if (unlikely((ret = read_regnum(num_regs, addr, ®num)) < 0)) goto fail; set_reg(rs_current, DWARF_CFA_REG_COLUMN(as), DWARF_WHERE_REG, regnum); break; case DW_CFA_def_cfa_offset: - if ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0) + if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0)) goto fail; set_reg(rs_current, DWARF_CFA_OFF_COLUMN(as), 0, val); /* NOT factored! */ break; case DW_CFA_def_cfa_offset_sf: - if ((ret = dwarf_read_sleb128(NULL, addr, &val)) < 0) + if (unlikely((ret = dwarf_read_sleb128(NULL, addr, &val)) < 0)) goto fail; set_reg(rs_current, DWARF_CFA_OFF_COLUMN(as), 0, val * dci->data_align); /* factored! */ break; @@ -1237,19 +1214,19 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state * /* Save the address of the DW_FORM_block for later evaluation. */ set_reg(rs_current, DWARF_CFA_REG_COLUMN(as), DWARF_WHERE_EXPR, *addr); - if ((ret = dwarf_read_uleb128(NULL, addr, &n)) < 0) + if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &n)) < 0)) goto fail; *addr += n; break; case DW_CFA_expression: - if ((ret = read_regnum(num_regs, addr, ®num)) < 0) + if (unlikely((ret = read_regnum(num_regs, addr, ®num)) < 0)) goto fail; /* Save the address of the DW_FORM_block for later evaluation. */ set_reg(rs_current, regnum, DWARF_WHERE_EXPR, *addr); - if ((ret = dwarf_read_uleb128(NULL, addr, &n)) < 0) + if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &n)) < 0)) goto fail; *addr += n; @@ -1261,21 +1238,21 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state * /* Save the address of the DW_FORM_block for later evaluation. */ set_reg(rs_current, regnum, DWARF_WHERE_VAL_EXPR, *addr); - if ((ret = dwarf_read_uleb128(NULL, addr, &n)) < 0) + if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &n)) < 0)) goto fail; *addr += n; break; case DW_CFA_GNU_args_size: - if ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0) + if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0)) goto fail; break; case DW_CFA_GNU_negative_offset_extended: /* A comment in GCC says that this is obsoleted by DW_CFA_offset_extended_sf, but that it's used by older PowerPC code. */ - if (((ret = read_regnum(num_regs, addr, ®num)) < 0) - || ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0)) + if (unlikely(((ret = read_regnum(num_regs, addr, ®num)) < 0) + || ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0))) goto fail; set_reg(rs_current, regnum, DWARF_WHERE_CFAREL, -(val * dci->data_align)); break; @@ -1309,7 +1286,7 @@ static int parse_fde(struct dwarf_addr_space *as, arch_addr_t ip, struct dwarf_r unsigned int i; struct dwarf_reg_state *rs_initial; - if (dci->ret_addr_column >= as->num_regs) { + if (unlikely(dci->ret_addr_column >= as->num_regs)) { debug(DEBUG_DWARF, "Invalid return address column %lu", dci->ret_addr_column); return -DWARF_EBADREG; } @@ -1367,25 +1344,25 @@ static arch_addr_t read_operand(struct dwarf_addr_space *as, arch_addr_t *addr, switch (operand_type) { case VAL8: ret = dwarf_read8(NULL, addr, &tmp.u8); - if (ret < 0) + if (unlikely(ret < 0)) return ret; *valp = tmp.u8; break; case VAL16: ret = dwarf_read16(NULL, addr, &tmp.u16); - if (ret < 0) + if (unlikely(ret < 0)) return ret; *valp = tmp.u16; break; case VAL32: ret = dwarf_read32(NULL, addr, &tmp.u32); - if (ret < 0) + if (unlikely(ret < 0)) return ret; *valp = tmp.u32; break; case VAL64: ret = dwarf_read64(NULL, addr, &tmp.u64); - if (ret < 0) + if (unlikely(ret < 0)) return ret; *valp = tmp.u64; break; @@ -1418,7 +1395,7 @@ static int dwarf_eval_expr(struct dwarf_addr_space *as, arch_addr_t addr, struct #define pop() \ ({ \ - if ((tos - 1) >= MAX_EXPR_STACK_SIZE) \ + if (unlikely((tos - 1) >= MAX_EXPR_STACK_SIZE)) \ { \ debug(DEBUG_DWARF, "Stack underflow"); \ return -DWARF_EINVAL; \ @@ -1429,7 +1406,7 @@ static int dwarf_eval_expr(struct dwarf_addr_space *as, arch_addr_t addr, struct #define push(x) \ do { \ arch_addr_t _x = (x); \ - if (tos >= MAX_EXPR_STACK_SIZE) \ + if (unlikely(tos >= MAX_EXPR_STACK_SIZE)) \ { \ debug(DEBUG_DWARF, "Stack overflow"); \ return -DWARF_EINVAL; \ @@ -1440,7 +1417,7 @@ do { \ #define pick(n) \ ({ \ unsigned int _index = tos - 1 - (n); \ - if (_index >= MAX_EXPR_STACK_SIZE) \ + if (unlikely(_index >= MAX_EXPR_STACK_SIZE)) \ { \ debug(DEBUG_DWARF, "Out-of-stack pick"); \ return -DWARF_EINVAL; \ @@ -1449,7 +1426,7 @@ do { \ }) /* read the length of the expression: */ - if ((ret = dwarf_read_uleb128(NULL, &addr, &len)) < 0) + if (unlikely((ret = dwarf_read_uleb128(NULL, &addr, &len)) < 0)) return ret; end_addr = addr + len; @@ -1457,7 +1434,7 @@ do { \ push(c->cfa); /* push current CFA as required by DWARF spec */ while (addr < end_addr) { - if ((ret = dwarf_read8(NULL, &addr, &opcode)) < 0) + if (unlikely((ret = dwarf_read8(NULL, &addr, &opcode)) < 0)) return ret; operands_signature = dwarf_operands[opcode]; @@ -1475,12 +1452,12 @@ do { \ push(opcode - DW_OP_lit0); break; case DW_OP_breg0 ... DW_OP_breg31: - if ((ret = dwarf_get_reg(as, dwarf_to_regnum(opcode - DW_OP_breg0), &tmp1)) < 0) + if (unlikely((ret = dwarf_get_reg(as, dwarf_to_regnum(opcode - DW_OP_breg0), &tmp1)) < 0)) return ret; push(tmp1 + operand1); break; case DW_OP_bregx: - if ((ret = dwarf_get_reg(as, dwarf_to_regnum(operand1), &tmp1)) < 0) + if (unlikely((ret = dwarf_get_reg(as, dwarf_to_regnum(operand1), &tmp1)) < 0)) return ret; push(tmp1 + operand2); break; @@ -1519,7 +1496,7 @@ do { \ break; case DW_OP_deref: tmp1 = pop(); - if ((ret = dwarf_readw(as, &tmp1, &tmp2, as->is_64bit)) < 0) + if (unlikely((ret = dwarf_readw(as, &tmp1, &tmp2, as->is_64bit)) < 0)) return ret; push(tmp2); break; @@ -1530,18 +1507,18 @@ do { \ debug(DEBUG_DWARF, "Unexpected DW_OP_deref_size size %d", (int)operand1); return -DWARF_EINVAL; case 1: - if ((ret = dwarf_read8(as, &tmp1, &u8)) < 0) + if (unlikely((ret = dwarf_read8(as, &tmp1, &u8)) < 0)) return ret; tmp2 = u8; break; case 2: - if ((ret = dwarf_read16(as, &tmp1, &u16)) < 0) + if (unlikely((ret = dwarf_read16(as, &tmp1, &u16)) < 0)) return ret; tmp2 = u16; break; case 3: case 4: - if ((ret = dwarf_read32(as, &tmp1, &u32)) < 0) + if (unlikely((ret = dwarf_read32(as, &tmp1, &u32)) < 0)) return ret; tmp2 = u32; if (operand1 == 3) { @@ -1556,7 +1533,7 @@ do { \ case 6: case 7: case 8: - if ((ret = dwarf_read64(as, &tmp1, &u64)) < 0) + if (unlikely((ret = dwarf_read64(as, &tmp1, &u64)) < 0)) return ret; tmp2 = u64; if (operand1 != 8) { @@ -1759,7 +1736,7 @@ static int apply_reg_state(struct dwarf_addr_space *as, struct dwarf_reg_state * cfa = c->cfa; } else { - if ((ret = dwarf_get_reg(as, rs->reg[DWARF_CFA_REG_COLUMN(as)].val, &cfa)) < 0) + if (unlikely((ret = dwarf_get_reg(as, rs->reg[DWARF_CFA_REG_COLUMN(as)].val, &cfa)) < 0)) return ret; } cfa += rs->reg[DWARF_CFA_OFF_COLUMN(as)].val; @@ -1772,7 +1749,7 @@ static int apply_reg_state(struct dwarf_addr_space *as, struct dwarf_reg_state * return ret; /* the returned location better be a memory location... */ - if (DWARF_IS_REG_LOC(cfa_loc)) + if (unlikely(DWARF_IS_REG_LOC(cfa_loc))) return -DWARF_EBADFRAME; cfa = DWARF_GET_LOC(cfa_loc); } @@ -1811,7 +1788,7 @@ static int apply_reg_state(struct dwarf_addr_space *as, struct dwarf_reg_state * } else { ret = dwarf_get(as, c->loc[c->ret_addr_column], &ip); - if (ret < 0) + if (unlikely(ret < 0)) return ret; c->ip = ip; } @@ -1853,9 +1830,6 @@ int dwarf_init_unwind(struct dwarf_addr_space *as, struct task *task) c->libref = NULL; c->task = task; - as->addr = 0; - as->val = 0; - memset(&c->dci, 0, sizeof(c->dci)); ret = dwarf_arch_init_unwind(as); @@ -1875,8 +1849,6 @@ void *dwarf_init(int is_64bit) memset(as, 0, sizeof(*as)); as->is_64bit = is_64bit; - as->addr = 0; - as->val = 0; ret = dwarf_arch_init(as); if (ret < 0) { @@ -1912,17 +1884,21 @@ int dwarf_step(struct dwarf_addr_space *as) int ret; struct dwarf_cursor *c = &as->cursor; struct dwarf_reg_state *rs_current; - arch_addr_t ip, cfa; + arch_addr_t ip; +#ifdef GUESS_CALLER + arch_addr_t cfa = c->cfa; +#endif if (!c->valid) return -DWARF_EINVAL; ip = c->ip; - cfa = c->cfa; +#if 0 ret = dwarf_locate_map(as, ip); - if (ret < 0) + if (unlikely(ret < 0)) goto fail; +#endif /* The 'ip' can point either to the previous or next instruction depending on what type of frame we have: normal call or a place @@ -1976,35 +1952,39 @@ int dwarf_step(struct dwarf_addr_space *as) if (ret) { #ifdef GUESS_CALLER - ssize_t n; - unsigned char buf[4096]; + unsigned char buf[512]; + unsigned int off; + arch_addr_t (*getval)(unsigned char *buf); + ssize_t addr_size = DWARF_ADDR_SIZE(as); - 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 (addr_size == 8) + getval = get64val; + else + getval = get32val; - if (addr_size == 8) - getval = get64val; - else - getval = get32val; + for(off = 0; off <= 4096; off += ARRAY_SIZE(buf)) { + size_t i, n; + + n = copy_from_proc(c->task, cfa, &buf, ARRAY_SIZE(buf)); 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)) { + if (unlikely(!dwarf_locate_map(as, ip) && dwarf_arch_check_call(as, ip))) { c->cfa = cfa + i + addr_size; c->ip = ip; + c->ret_addr_column = 0; + + for (i = 0; i < as->num_regs; ++i) + c->loc[i] = DWARF_NULL_LOC; + return 0; } } + + if (unlikely(n < (ssize_t)ARRAY_SIZE(buf))) + break; } #endif debug(DEBUG_DWARF, "error %d", ret); @@ -2015,16 +1995,6 @@ int dwarf_step(struct dwarf_addr_space *as) return ret; } -arch_addr_t dwarf_get_ip(struct dwarf_addr_space *as) -{ - struct dwarf_cursor *c = &as->cursor; - - if (!c->valid) - return ARCH_ADDR_T(0); - - return c->ip; -} - int dwarf_get_unwind_table(struct task *task, struct libref *libref, struct dwarf_eh_frame_hdr *hdr) { arch_addr_t addr, fde_count; @@ -2063,13 +2033,3 @@ int dwarf_get_unwind_table(struct task *task, struct libref *libref, struct dwar 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 b85c9b8..80a83a4 100644 --- a/dwarf.h +++ b/dwarf.h @@ -27,7 +27,9 @@ #include #include "arch.h" +#include "common.h" #include "forward.h" +#include "library.h" #include "mtelf.h" #define DWARF_LOC(r, t) ((struct dwarf_loc){ .val = (r), .type = (t) }) @@ -96,11 +98,6 @@ struct dwarf_cursor { struct dwarf_addr_space { unsigned int is_64bit:1; - arch_addr_t addr; - union { - long val; - unsigned char val_bytes[sizeof(long)]; - }; struct dwarf_cursor cursor; unsigned int ip_reg; unsigned int ret_reg; @@ -113,7 +110,6 @@ void *dwarf_init(int is_64bit); void dwarf_destroy(struct dwarf_addr_space *as); int dwarf_init_unwind(struct dwarf_addr_space *as, struct task *task); int dwarf_step(struct dwarf_addr_space *as); -arch_addr_t dwarf_get_ip(struct dwarf_addr_space *as); int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip); @@ -121,8 +117,6 @@ int dwarf_get(struct dwarf_addr_space *as, struct dwarf_loc loc, arch_addr_t *va 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); @@ -132,11 +126,30 @@ 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); #else -static inline unsigned int dwarf_to_regnum(unsigned int reg) +static inline __attribute__((const)) unsigned int dwarf_to_regnum(unsigned int reg) { return reg; } #endif +static inline arch_addr_t dwarf_get_ip(struct dwarf_addr_space *as) +{ + struct dwarf_cursor *c = &as->cursor; + + if (unlikely(!c->valid)) + return ARCH_ADDR_T(0); + + return c->ip; +} + +static inline int dwarf_location_type(struct dwarf_addr_space *as) +{ + struct libref *libref = as->cursor.libref; + + if (!libref) + return -1; + + return libref->type; +} #endif diff --git a/event.c b/event.c index 1e414e4..c656bd8 100644 --- a/event.c +++ b/event.c @@ -45,10 +45,12 @@ #include "debug.h" #include "event.h" #include "library.h" +#include "main.h" #include "mtrace.h" #include "options.h" #include "report.h" #include "task.h" +#include "timer.h" #include "trace.h" static LIST_HEAD(event_head); @@ -114,7 +116,7 @@ static void handle_clone(struct task *task, enum event_type type) debug(DEBUG_FUNCTION, "pid=%d, newpid=%d", task->pid, newpid); - if (options.verbose) + if (unlikely(options.verbose)) show_clone(task, type); continue_task(task, 0); @@ -152,7 +154,7 @@ static void handle_clone(struct task *task, enum event_type type) static void handle_signal(struct task *task) { - if (options.verbose > 1) { + if (unlikely(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)); } @@ -162,7 +164,7 @@ static void handle_signal(struct task *task) static void show_exit(struct task *task) { - if (options.verbose) + if (unlikely(options.verbose)) fprintf(stderr, "+++ process pid=%d exited (status=%d) +++\n", task->pid, task->event.e_un.ret_val); } @@ -170,7 +172,7 @@ static void show_exit(struct task *task) static void handle_about_exit(struct task *task) { if (task->leader == task) { - if (report_about_exit(task) != -1) { + if (!options.logfile && report_about_exit(task) != -1) { task->about_exit = 1; return; } @@ -193,7 +195,7 @@ static void handle_exit(struct task *task) static void handle_exit_signal(struct task *task) { - if (options.verbose) + if (unlikely(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); if (task->leader == task) { @@ -217,7 +219,7 @@ static void handle_exec(struct task *task) goto untrace; } - if (options.verbose) + if (unlikely(options.verbose)) fprintf(stderr, "+++ process pid=%d exec (%s) +++\n", task->pid, library_execname(task)); continue_task(task, 0); @@ -230,11 +232,19 @@ static void handle_exec(struct task *task) static int handle_call_after(struct task *task, struct breakpoint *bp) { + struct timespec start; + if (!task->breakpoint) return 0; + if (unlikely(options.verbose > 1)) + start_time(&start); + task->libsym->func->report_out(task, task->libsym); + if (unlikely(options.verbose > 1)) + set_timer(&start, &report_out_time); + task->breakpoint = NULL; task->libsym = NULL; @@ -244,20 +254,33 @@ static int handle_call_after(struct task *task, struct breakpoint *bp) static void handle_breakpoint(struct task *task) { struct breakpoint *bp = task->event.e_un.breakpoint; + unsigned int hw = bp->hw; debug(DEBUG_FUNCTION, "pid=%d, addr=%#lx", task->pid, bp->addr); + if (unlikely(options.verbose > 1)) + set_timer(&task->halt_time, hw ? &hw_bp_time : &sw_bp_time); + #if HW_BREAKPOINTS > 1 if (bp->type >= BP_HW) { - if (++bp->hwcnt >= (BP_REORDER_THRESHOLD << bp->hw)) + if (unlikely(++bp->hwcnt >= (BP_REORDER_THRESHOLD << hw))) { + struct timespec start; + + if (unlikely(options.verbose > 1)) + start_time(&start); + reorder_hw_bp(task); + + if (unlikely(options.verbose > 1)) + set_timer(&start, &reorder_time); + } } #endif - if (options.verbose) + if (unlikely(options.verbose)) ++bp->count; - if (bp->deleted) { + if (unlikely(bp->deleted)) { struct breakpoint *nbp = breakpoint_find(task, bp->addr); if (!nbp) @@ -267,26 +290,26 @@ static void handle_breakpoint(struct task *task) goto end; } - if (task->skip_bp == bp) { + if (unlikely(task->skip_bp == bp)) { breakpoint_put(task->skip_bp); task->skip_bp = NULL; skip_breakpoint(task, bp); goto end; } - if (breakpoint_on_hit(task, bp)) { + if (unlikely(breakpoint_on_hit(task, bp))) { continue_task(task, 0); goto end; } - if (bp->libsym && !task->breakpoint) { + if (likely(bp->libsym && !task->breakpoint)) { struct library_symbol *libsym = bp->libsym; save_param_context(task); if (libsym->func->report_out) { task->breakpoint = breakpoint_insert(task, get_return_addr(task), NULL, BP_HW_SCRATCH); - if (task->breakpoint) { + if (likely(task->breakpoint)) { task->libsym = libsym; task->breakpoint->on_hit = handle_call_after; @@ -294,8 +317,17 @@ static void handle_breakpoint(struct task *task) } } - if (libsym->func->report_in) + if (libsym->func->report_in) { + struct timespec start; + + if (unlikely(options.verbose > 1)) + start_time(&start); + libsym->func->report_in(task, libsym); + + if (unlikely(options.verbose > 1)) + set_timer(&start, &report_in_time); + } } if (task->stopped) diff --git a/library.c b/library.c index cd93564..0c34d34 100644 --- a/library.c +++ b/library.c @@ -120,15 +120,18 @@ void library_delete(struct task *task, struct library *lib) struct list_head *it, *next; struct libref *libref = lib->libref; + struct task *leader = task->leader; list_for_each_safe(it, next, &libref->sym_list) { - struct breakpoint *bp = breakpoint_find(task, container_of(it, struct library_symbol, list)->addr); + struct breakpoint *bp = breakpoint_find(leader, container_of(it, struct library_symbol, list)->addr); if (bp) - breakpoint_delete(task, bp); + breakpoint_delete(leader, bp); } list_del(&lib->list); + rb_erase(&lib->rb_node, &leader->libraries_tree); + free(lib); libref_put(libref); @@ -170,7 +173,7 @@ void library_delete_list(struct task *leader, struct list_head *list) debug(DEBUG_FUNCTION, "%s@%#lx", libref->filename, libref->base); - if (options.verbose > 1) + if (unlikely(options.verbose > 1)) 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_delete(leader, lib); @@ -208,6 +211,52 @@ static void library_each_symbol(struct libref *libref, void (*cb)(struct library } } +static inline int lib_addr_match(struct libref *libref, arch_addr_t addr) +{ + return addr >= libref->load_addr && addr < libref->load_addr + libref->load_size; +} + +struct libref *addr2libref(struct task *leader, arch_addr_t addr) +{ + struct rb_node **new = &(leader->libraries_tree.rb_node); + + /* Figure out where to put new node */ + while (*new) { + struct libref *this = container_of(*new, struct library, rb_node)->libref; + + if (lib_addr_match(this, addr)) + return this; + + if (this->load_addr < addr) + new = &((*new)->rb_left); + else + new = &((*new)->rb_right); + } + + return NULL; +} + +static void insert_lib(struct task *leader, struct library *lib) +{ + struct rb_node **new = &(leader->libraries_tree.rb_node), *parent = NULL; + + /* Figure out where to put new node */ + while (*new) { + struct library *this = container_of(*new, struct library, rb_node); + + parent = *new; + + if (this->libref->load_addr < lib->libref->load_addr) + new = &((*new)->rb_left); + else + new = &((*new)->rb_right); + } + + /* Add new node and rebalance tree. */ + rb_link_node(&lib->rb_node, parent, new); + rb_insert_color(&lib->rb_node, &leader->libraries_tree); +} + 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); @@ -225,7 +274,9 @@ static struct library *_library_add(struct task *leader, struct libref *libref) list_add_tail(&lib->list, &leader->libraries_list); - if (options.verbose > 1) + insert_lib(leader, lib); + + if (unlikely(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; @@ -263,6 +314,7 @@ int library_clone_all(struct task *clone, struct task *leader) void library_setup(struct task *leader) { INIT_LIST_HEAD(&leader->libraries_list); + leader->libraries_tree = RB_ROOT; } const char *library_execname(struct task *leader) diff --git a/library.h b/library.h index 7ba7981..84d753a 100644 --- a/library.h +++ b/library.h @@ -30,6 +30,7 @@ #include "sysdep.h" #include "list.h" #include "mtelf.h" +#include "rbtree.h" #define LIBTYPE_LIB 0 #define LIBTYPE_MAIN 1 @@ -89,6 +90,9 @@ struct library { /* link list of libraries associated with the task */ struct list_head list; + /* red/black tree of libraries associated with the task */ + struct rb_node rb_node; + /* pointer to the real library refernce */ struct libref *libref; }; @@ -132,5 +136,8 @@ 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); +/* find library by address */ +struct libref *addr2libref(struct task *leader, arch_addr_t addr); + #endif diff --git a/main.c b/main.c index 36820ae..96c8bd3 100644 --- a/main.c +++ b/main.c @@ -50,6 +50,15 @@ #include "task.h" #include "trace.h" +struct mt_timer stop_time; +struct mt_timer sw_bp_time; +struct mt_timer hw_bp_time; +struct mt_timer backtrace_time; +struct mt_timer reorder_time; +struct mt_timer report_in_time; +struct mt_timer report_out_time; +struct mt_timer skip_bp_time; + static int do_exit; void mtrace_request_exit(void) @@ -57,7 +66,7 @@ void mtrace_request_exit(void) if (do_exit) return; - if (options.verbose) + if (unlikely(options.verbose)) fprintf(stderr, "+++ request exit +++\n"); do_exit = 1; @@ -69,10 +78,10 @@ static void detach_process(struct task *leader) if (!leader) return; - report_detach(leader); - pid_t pid = leader->pid; + report_detach(leader); + while(server_handle_command() != -1) { struct task *task = pid2task(pid); @@ -99,16 +108,13 @@ static void mtrace_init(char **cmd) { struct opt_p_t *opt_p_tmp; - if (os_init()) - exit(EXIT_FAILURE); - if (options.command) { struct task *task = task_create(options.command, cmd); if (!task) exit(EXIT_FAILURE); - if (options.verbose) + if (unlikely(options.verbose)) fprintf(stderr, "+++ process pid=%d created (%s) +++\n", task->pid, library_execname(task)); } @@ -134,6 +140,8 @@ int main(int argc, char *argv[]) { char **cmd = process_options(argc, argv); + init_pid_hash(); + if (options.trace) { if (options.logfile) { if (server_logfile() == -1) @@ -175,10 +183,14 @@ int main(int argc, char *argv[]) #endif } + if (os_init()) + exit(EXIT_FAILURE); + mtrace_init(cmd); mtrace_main(); mtrace_exit(); + report_info(0); report_disconnect(); #if !DISABLE_CLIENT diff --git a/main.h b/main.h index 8e24132..b3f3aaf 100644 --- a/main.h +++ b/main.h @@ -23,7 +23,18 @@ #ifndef _INC_MAIN_H #define _INC_MAIN_H +#include "timer.h" + void mtrace_request_exit(void); +struct mt_timer stop_time; +struct mt_timer sw_bp_time; +struct mt_timer hw_bp_time; +struct mt_timer backtrace_time; +struct mt_timer reorder_time; +struct mt_timer report_in_time; +struct mt_timer report_out_time; +struct mt_timer skip_bp_time; + #endif diff --git a/memtrace.h b/memtrace.h index 0b9770c..b5cbf9c 100644 --- a/memtrace.h +++ b/memtrace.h @@ -31,15 +31,15 @@ #define IS64BIT 0 #endif -#define MEMTRACE_SI_VERSION 5 +#define MEMTRACE_SI_VERSION 6 #define MEMTRACE_SI_FORK 1 #define MEMTRACE_SI_EXEC 2 #define MEMTRACE_SI_VERBOSE 4 enum mt_operation { + MT_INFO = 0, MT_DISCONNECT, - MT_INFO, MT_ADD_MAP, MT_DEL_MAP, MT_ATTACH, @@ -50,7 +50,7 @@ enum mt_operation { MT_NOFOLLOW, MT_MALLOC, MT_REALLOC_ENTER, - MT_REALLOC_FAILED, + MT_REALLOC_DONE, MT_REALLOC, MT_FREE, MT_MMAP, @@ -71,47 +71,62 @@ enum mt_operation { MT_DELETE_ARRAY, }; -struct mt_msg { +struct __attribute__((packed)) mt_msg { uint16_t operation; - uint32_t pid; - uint32_t tid; + uint16_t pid; uint32_t payload_len; }; -struct mt_attached_payload { +struct __attribute__((packed)) mt_attached_payload { uint8_t attached; }; -struct mt_alloc_payload_64 { +struct __attribute__((packed)) mt_alloc_payload_64 { uint64_t ptr; uint64_t size; uint64_t data[0]; }; -struct mt_alloc_payload_32 { +struct __attribute__((packed)) mt_alloc_payload_32 { uint32_t ptr; uint32_t size; uint32_t data[0]; }; -struct mt_pid_payload { +struct __attribute__((packed)) mt_pid_payload { uint32_t pid; }; -struct mt_scan_payload { +struct __attribute__((packed)) mt_scan_payload { uint32_t ptr_size; uint64_t mask; char data[0]; }; -struct memtrace_info { +struct __attribute__((packed)) memtrace_timer_info { + uint32_t max; + uint32_t count; + uint64_t culminate; +}; + +struct __attribute__((packed)) memtrace_info { uint8_t version; uint8_t mode; uint8_t do_trace; uint8_t stack_depth; + uint8_t verbose; + uint8_t unused[3]; + struct memtrace_timer_info stop_time; + struct memtrace_timer_info sw_bp_time; + struct memtrace_timer_info hw_bp_time; + struct memtrace_timer_info backtrace_time; + struct memtrace_timer_info reorder_time; + struct memtrace_timer_info report_in_time; + struct memtrace_timer_info report_out_time; + struct memtrace_timer_info skip_bp_time; }; -struct mt_map_payload { +struct __attribute__((packed)) mt_map_payload { uint64_t addr; uint64_t offset; uint64_t size; diff --git a/mtelf.c b/mtelf.c index c9fece1..cbbb6dd 100644 --- a/mtelf.c +++ b/mtelf.c @@ -191,7 +191,7 @@ static int populate_this_symtab(struct mt_elf *mte, struct libref *libref, Elf_D if (libsym->func->level > func->level) libsym->func = func; } - if (options.verbose > 1) + if (unlikely(options.verbose > 1)) fprintf(stderr, "breakpoint for %s:%s at %#lx\n", libref->filename, func->demangled_name, addr); } @@ -220,6 +220,7 @@ static int populate_symtab(struct mt_elf *mte, struct libref *libref) static inline int elf_map_image(struct mt_elf *mte, void **image_addr) { void *addr; + volatile char *p; addr = mmap(NULL, mte->txt_hdr.p_filesz, PROT_READ, MAP_PRIVATE, mte->fd, mte->txt_hdr.p_offset); if (addr == MAP_FAILED) { @@ -229,6 +230,10 @@ static inline int elf_map_image(struct mt_elf *mte, void **image_addr) *image_addr = addr; + /* prefetch */ + for(p = addr; (void *)p <= addr + mte->txt_hdr.p_filesz; p += PAGE_SIZE) + *p; + return 0; } diff --git a/options.h b/options.h index 676c151..c3ce23a 100644 --- a/options.h +++ b/options.h @@ -24,6 +24,7 @@ #ifndef _INC_OPTIONS_H #define _INC_OPTIONS_H +#include #include #include "config.h" diff --git a/report.c b/report.c index 29059e5..5540644 100644 --- a/report.c +++ b/report.c @@ -34,14 +34,16 @@ #include "common.h" #include "debug.h" #include "library.h" +#include "main.h" #include "memtrace.h" #include "options.h" #include "report.h" #include "server.h" #include "task.h" +#include "timer.h" #include "trace.h" -static int report_alloc64(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, unsigned int depth, struct library_symbol *libsym) +static void report_alloc64(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, unsigned int depth, struct library_symbol *libsym) { unsigned int i = 0; struct mt_alloc_payload_64 *alloc = alloca(sizeof(*alloc) + depth * sizeof(uint64_t)); @@ -53,20 +55,20 @@ static int report_alloc64(struct task *task, enum mt_operation op, unsigned long if (libsym) alloc->data[i++] = libsym->addr; - if (backtrace_init_unwind(task) >= 0) { + if (likely(backtrace_init_unwind(task) >= 0)) { while(i < depth) { - if (backtrace_location_type(task) != LIBTYPE_LOADER) { + if (likely(backtrace_location_type(task) != LIBTYPE_LOADER)) { alloc->data[i] = (uint64_t)backtrace_get_ip(task); - if (!i || alloc->data[i - 1] != alloc->data[i]) { - if (!alloc->data[i]) + if (likely(!i || alloc->data[i - 1] != alloc->data[i])) { + if (unlikely(!alloc->data[i])) break; ++i; } } - if (backtrace_step(task) < 0) + if (unlikely(backtrace_step(task) < 0)) break; } } @@ -74,10 +76,10 @@ static int report_alloc64(struct task *task, enum mt_operation op, unsigned long skip_breakpoint(task, task->event.e_un.breakpoint); - return server_send_msg(op, task->leader->pid, task->pid, alloc, sizeof(*alloc) + i * sizeof(uint64_t)); + server_send_msg(op, task->leader->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, struct library_symbol *libsym) +static void 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)); @@ -89,20 +91,20 @@ static int report_alloc32(struct task *task, enum mt_operation op, unsigned long if (libsym) alloc->data[i++] = libsym->addr; - if (backtrace_init_unwind(task) >= 0) { + if (likely(backtrace_init_unwind(task) >= 0)) { while(i < depth) { - if (backtrace_location_type(task) != LIBTYPE_LOADER) { + if (likely(backtrace_location_type(task) != LIBTYPE_LOADER)) { alloc->data[i] = (uint32_t)backtrace_get_ip(task); - if (!i || alloc->data[i - 1] != alloc->data[i]) { - if (!alloc->data[i]) + if (likely(!i || alloc->data[i - 1] != alloc->data[i])) { + if (unlikely(!alloc->data[i])) break; ++i; } } - if (backtrace_step(task) < 0) + if (unlikely(backtrace_step(task) < 0)) break; } } @@ -110,142 +112,132 @@ static int report_alloc32(struct task *task, enum mt_operation op, unsigned long skip_breakpoint(task, task->event.e_un.breakpoint); - return server_send_msg(op, task->leader->pid, task->pid, alloc, sizeof(*alloc) + i * sizeof(uint32_t)); + server_send_msg(op, task->leader->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, struct library_symbol *libsym) +static void 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; - - if (!server_connected()) - return -1; + return; 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, libsym); + report_alloc64(task, op, ptr, size, depth, libsym); else - return report_alloc32(task, op, ptr, size, depth, libsym); + report_alloc32(task, op, ptr, size, depth, libsym); } -static int _null(struct task *task, struct library_symbol *libsym) +static void _null(struct task *task, struct library_symbol *libsym) { - return 0; } -static int _report_alloc_op(struct task *task, struct library_symbol *libsym, enum mt_operation op) +static void _report_alloc_op(struct task *task, struct library_symbol *libsym, enum mt_operation op) { - if (!server_connected()) - return -1; - unsigned long size = fetch_param(task, 0); unsigned long ret = fetch_retval(task); - return report_alloc(task, op, ret, size, options.bt_depth, libsym); + report_alloc(task, op, ret, size, options.bt_depth, libsym); } -static int _report_malloc(struct task *task, struct library_symbol *libsym) +static void _report_malloc(struct task *task, struct library_symbol *libsym) { - return _report_alloc_op(task, libsym, MT_MALLOC); + _report_alloc_op(task, libsym, MT_MALLOC); } -static int _report_new(struct task *task, struct library_symbol *libsym) +static void _report_new(struct task *task, struct library_symbol *libsym) { - return _report_alloc_op(task, libsym, options.sanity ? MT_NEW : MT_MALLOC); + _report_alloc_op(task, libsym, options.sanity ? MT_NEW : MT_MALLOC); } -static int _report_new_array(struct task *task, struct library_symbol *libsym) +static void _report_new_array(struct task *task, struct library_symbol *libsym) { - return _report_alloc_op(task, libsym, options.sanity ? MT_NEW_ARRAY : MT_MALLOC); + _report_alloc_op(task, libsym, options.sanity ? MT_NEW_ARRAY : MT_MALLOC); } -static int _report_free_op(struct task *task, struct library_symbol *libsym, enum mt_operation op) +static void _report_free_op(struct task *task, struct library_symbol *libsym, enum mt_operation op) { - if (!server_connected()) - return -1; - unsigned long addr = fetch_param(task, 0); - return report_alloc(task, op, addr, 0, options.sanity ? options.bt_depth : 0, NULL); + report_alloc(task, op, addr, 0, options.sanity ? options.bt_depth : 0, NULL); } -static int report_free(struct task *task, struct library_symbol *libsym) +static void report_free(struct task *task, struct library_symbol *libsym) { - return _report_free_op(task, libsym, MT_FREE); + _report_free_op(task, libsym, MT_FREE); } -static int report_delete(struct task *task, struct library_symbol *libsym) +static void report_delete(struct task *task, struct library_symbol *libsym) { - return _report_free_op(task, libsym, options.sanity ? MT_DELETE : MT_FREE); + _report_free_op(task, libsym, options.sanity ? MT_DELETE : MT_FREE); } -static int report_delete_array(struct task *task, struct library_symbol *libsym) +static void report_delete_array(struct task *task, struct library_symbol *libsym) { - return _report_free_op(task, libsym, options.sanity ? MT_DELETE_ARRAY : MT_FREE); + _report_free_op(task, libsym, options.sanity ? MT_DELETE_ARRAY : MT_FREE); } -static int _report_realloc(struct task *task, struct library_symbol *libsym) +static void _report_realloc(struct task *task, struct library_symbol *libsym) { - if (!server_connected()) - return -1; - - unsigned long addr = fetch_param(task, 0); - unsigned long size = fetch_param(task, 1); unsigned long ret = fetch_retval(task); - if (ret) - 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, libsym); + if (ret) { + unsigned long size = fetch_param(task, 1); + + report_alloc(task, MT_REALLOC, ret, size, options.bt_depth, libsym); + } + + if (task_is_64bit(task)) { + struct mt_alloc_payload_64 *alloc = alloca(sizeof(*alloc)); + + alloc->ptr = (uint64_t)ret; + alloc->size = (uint64_t)task->pid; + + server_send_msg(MT_REALLOC_DONE, task->leader->pid, alloc, sizeof(*alloc)); + } + else { + struct mt_alloc_payload_32 *alloc = alloca(sizeof(*alloc)); + + alloc->ptr = (uint32_t)ret; + alloc->size = (uint32_t)task->pid; + + server_send_msg(MT_REALLOC_DONE, task->leader->pid, alloc, sizeof(*alloc)); + } } -static int report_realloc(struct task *task, struct library_symbol *libsym) +static void report_realloc(struct task *task, struct library_symbol *libsym) { - if (!server_connected()) - return -1; - 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, libsym); + report_alloc(task, MT_REALLOC_ENTER, addr, task->pid, options.sanity ? options.bt_depth : 0, libsym); } -static int _report_calloc(struct task *task, struct library_symbol *libsym) +static void _report_calloc(struct task *task, struct library_symbol *libsym) { - if (!server_connected()) - return -1; - 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, libsym); + report_alloc(task, MT_MALLOC, ret, size, options.bt_depth, libsym); } -static int _report_mmap(struct task *task, struct library_symbol *libsym) +static void _report_mmap(struct task *task, struct library_symbol *libsym) { - if (!server_connected()) - return -1; - unsigned long ret = fetch_retval(task); if ((void *)ret == MAP_FAILED) - return 0; + return; unsigned long size = fetch_param(task, 1); - return report_alloc(task, MT_MMAP, ret, size, options.bt_depth, libsym); + report_alloc(task, MT_MMAP, ret, size, options.bt_depth, libsym); } -static int _report_mmap64(struct task *task, struct library_symbol *libsym) +static void _report_mmap64(struct task *task, struct library_symbol *libsym) { - if (!server_connected()) - return -1; - unsigned long ret = fetch_retval(task); if ((void *)ret == MAP_FAILED) - return 0; + return; union { uint64_t l; @@ -264,40 +256,31 @@ 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, libsym); + report_alloc(task, MT_MMAP64, ret, size.l, options.bt_depth, libsym); } -static int report_munmap(struct task *task, struct library_symbol *libsym) +static void report_munmap(struct task *task, struct library_symbol *libsym) { - if (!server_connected()) - return -1; - unsigned long addr = fetch_param(task, 0); unsigned long size = fetch_param(task, 1); - return report_alloc(task, MT_MUNMAP, addr, size, 0, libsym); + report_alloc(task, MT_MUNMAP, addr, size, 0, libsym); } -static int _report_memalign(struct task *task, struct library_symbol *libsym) +static void _report_memalign(struct task *task, struct library_symbol *libsym) { - if (!server_connected()) - return -1; - unsigned long size = fetch_param(task, 1); unsigned long ret = fetch_retval(task); - return report_alloc(task, MT_MEMALIGN, ret, size, options.bt_depth, libsym); + report_alloc(task, MT_MEMALIGN, ret, size, options.bt_depth, libsym); } -static int _report_posix_memalign(struct task *task, struct library_symbol *libsym) +static void _report_posix_memalign(struct task *task, struct library_symbol *libsym) { - if (!server_connected()) - return -1; - unsigned long ret = fetch_retval(task); if (ret) - return 0; + return; unsigned long size = fetch_param(task, 2); unsigned long ptr = fetch_param(task, 0); @@ -313,56 +296,47 @@ 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, libsym); + 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) +static void _report_aligned_alloc(struct task *task, struct library_symbol *libsym) { - if (!server_connected()) - return -1; - 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, libsym); + report_alloc(task, MT_ALIGNED_ALLOC, ret, size, options.bt_depth, libsym); } -static int _report_valloc(struct task *task, struct library_symbol *libsym) +static void _report_valloc(struct task *task, struct library_symbol *libsym) { - if (!server_connected()) - return -1; - unsigned long size = fetch_param(task, 0); unsigned long ret = fetch_retval(task); - return report_alloc(task, MT_VALLOC, ret, size, options.bt_depth, libsym); + report_alloc(task, MT_VALLOC, ret, size, options.bt_depth, libsym); } -static int _report_pvalloc(struct task *task, struct library_symbol *libsym) +static void _report_pvalloc(struct task *task, struct library_symbol *libsym) { - if (!server_connected()) - return -1; - unsigned long size = fetch_param(task, 0); unsigned long ret = fetch_retval(task); return report_alloc(task, MT_PVALLOC, ret, size, options.bt_depth, libsym); } -static int report_mremap(struct task *task, struct library_symbol *libsym) +static void 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, libsym); + report_alloc(task, MT_MUNMAP, addr, size, 0, libsym); } -static int _report_mremap(struct task *task, struct library_symbol *libsym) +static void _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, libsym); + report_alloc(task, MT_MMAP, ret, size, options.bt_depth, libsym); } static const struct function flist[] = { @@ -416,13 +390,14 @@ int _report_map(struct task *task, struct library *lib, enum mt_operation op) 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; memcpy(payload->filename, libref->filename, len); - return server_send_msg(op, task->pid, 0, payload, sizeof(struct mt_map_payload) + len); + return server_send_msg(op, task->pid, payload, sizeof(struct mt_map_payload) + len); } int report_add_map(struct task *task, struct library *lib) @@ -441,6 +416,13 @@ int report_del_map(struct task *task, struct library *lib) return _report_map(task, lib, MT_DEL_MAP); } +static void store_timer_info(struct memtrace_timer_info *info, struct mt_timer *timer) +{ + info->max = timer->max; + info->count = timer->count; + info->culminate = timer->culminate; +} + int report_info(int do_trace) { struct memtrace_info mt_info; @@ -452,6 +434,16 @@ int report_info(int do_trace) mt_info.mode = 0; mt_info.do_trace = do_trace ? 1 : 0; mt_info.stack_depth = options.bt_depth; + mt_info.verbose = options.verbose; + + store_timer_info(&mt_info.stop_time, &stop_time); + store_timer_info(&mt_info.sw_bp_time, &sw_bp_time); + store_timer_info(&mt_info.hw_bp_time, &hw_bp_time); + store_timer_info(&mt_info.backtrace_time, &backtrace_time); + store_timer_info(&mt_info.reorder_time, &reorder_time); + store_timer_info(&mt_info.report_in_time, &report_in_time); + store_timer_info(&mt_info.report_out_time, &report_out_time); + store_timer_info(&mt_info.skip_bp_time, &skip_bp_time); if (options.verbose) mt_info.mode |= MEMTRACE_SI_VERBOSE; @@ -462,7 +454,7 @@ int report_info(int do_trace) if (options.follow) mt_info.mode |= MEMTRACE_SI_FORK; - return server_send_msg(MT_INFO, 0, 0, &mt_info, sizeof(mt_info)); + return server_send_msg(MT_INFO, 0, &mt_info, sizeof(mt_info)); } int report_scan(pid_t pid, const void *data, unsigned int data_len) @@ -470,7 +462,7 @@ int report_scan(pid_t pid, const void *data, unsigned int data_len) if (!server_connected()) return -1; - return server_send_msg(MT_SCAN, pid, 0, data, data_len); + return server_send_msg(MT_SCAN, pid, data, data_len); } int report_attach(struct task *task) @@ -480,7 +472,7 @@ int report_attach(struct task *task) if (!server_connected()) return -1; - return server_send_msg(task_is_64bit(task) ? MT_ATTACH64 : MT_ATTACH, task->pid, 0, &state, sizeof(state)); + return server_send_msg(task_is_64bit(task) ? MT_ATTACH64 : MT_ATTACH, task->pid, &state, sizeof(state)); } int report_fork(struct task *task, struct task *ptask) @@ -490,7 +482,7 @@ int report_fork(struct task *task, struct task *ptask) if (!server_connected()) return -1; - return server_send_msg(MT_FORK, task->pid, 0, &fork_pid, sizeof(fork_pid)); + return server_send_msg(MT_FORK, task->pid, &fork_pid, sizeof(fork_pid)); } int report_exit(struct task *task) @@ -498,7 +490,7 @@ int report_exit(struct task *task) if (!server_connected()) return -1; - return server_send_msg(MT_EXIT, task->pid, 0, NULL, 0); + return server_send_msg(MT_EXIT, task->pid, NULL, 0); } int report_about_exit(struct task *task) @@ -506,7 +498,7 @@ int report_about_exit(struct task *task) if (!server_connected()) return -1; - return server_send_msg(MT_ABOUT_EXIT, task->pid, 0, NULL, 0); + return server_send_msg(MT_ABOUT_EXIT, task->pid, NULL, 0); } int report_nofollow(struct task *task) @@ -514,7 +506,7 @@ int report_nofollow(struct task *task) if (!server_connected()) return -1; - return server_send_msg(MT_NOFOLLOW, task->pid, 0, NULL, 0); + return server_send_msg(MT_NOFOLLOW, task->pid, NULL, 0); } int report_detach(struct task *task) @@ -522,7 +514,7 @@ int report_detach(struct task *task) if (!server_connected()) return -1; - return server_send_msg(MT_DETACH, task->pid, 0, NULL, 0); + return server_send_msg(MT_DETACH, task->pid, NULL, 0); } int report_disconnect(void) @@ -530,7 +522,7 @@ int report_disconnect(void) if (!server_connected()) return -1; - return server_send_msg(MT_DISCONNECT, 0, 0, NULL, 0); + return server_send_msg(MT_DISCONNECT, 0, NULL, 0); } static void report_process(struct task *leader) diff --git a/report.h b/report.h index a21d6fa..03dd6f5 100644 --- a/report.h +++ b/report.h @@ -33,9 +33,9 @@ struct function { /* level for aliased symbol */ unsigned int level; /* report when function is entered */ - int (*report_in)(struct task *task, struct library_symbol *libsym); + void (*report_in)(struct task *task, struct library_symbol *libsym); /* report when function is exited */ - int (*report_out)(struct task *task, struct library_symbol *libsym); + void (*report_out)(struct task *task, struct library_symbol *libsym); }; const struct function *flist_matches_symbol(const char *sym_name); diff --git a/server.c b/server.c index 99aa83c..66003f7 100644 --- a/server.c +++ b/server.c @@ -159,7 +159,7 @@ int server_handle_command(void) if (ret != sizeof(cmd)) { if (ret > 0) { - if (options.verbose) + if (unlikely(options.verbose)) fprintf(stderr, "cmd read wrong size %d\n", ret); } server_close(); @@ -177,7 +177,10 @@ int server_handle_command(void) } if (!cmd.pid) { - server_close(); + if (cmd.operation == MT_INFO) + report_info(1); + else + server_close(); goto finish; } @@ -277,7 +280,7 @@ int server_start(void) fatal("accept (%s)", strerror(errno)); fprintf(stderr, "connected!\n"); - server_mode = MODE_ACCEPTED; + report_info(1); } @@ -341,7 +344,7 @@ int server_start_pair(void) return sv[1]; } -int server_send_msg(enum mt_operation op, uint32_t pid, uint32_t tid, const void *payload, unsigned int payload_len) +int server_send_msg(enum mt_operation op, uint32_t pid, const void *payload, unsigned int payload_len) { if (options.logfile) { struct iovec io[2]; @@ -350,7 +353,6 @@ int server_send_msg(enum mt_operation op, uint32_t pid, uint32_t tid, const void mt_msg.operation = op; mt_msg.pid = pid; - mt_msg.tid = tid; mt_msg.payload_len = payload_len; io[0].iov_base = &mt_msg; @@ -367,7 +369,7 @@ int server_send_msg(enum mt_operation op, uint32_t pid, uint32_t tid, const void return ret; } - return sock_send_msg(server_fd, op, pid, tid, payload, payload_len); + return sock_send_msg(server_fd, op, pid, payload, payload_len); } int server_stop(void) diff --git a/server.h b/server.h index bbeb8f9..30d5ba3 100644 --- a/server.h +++ b/server.h @@ -29,7 +29,7 @@ int server_start(void); 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); +int server_send_msg(enum mt_operation op, uint32_t pid, const void *payload, unsigned int payload_len); int server_handle_command(void); int server_connected(void); int server_stop(void); diff --git a/sysdeps/linux-gnu/Makefile.am b/sysdeps/linux-gnu/Makefile.am index 3c3d7ec..3ac5694 100644 --- a/sysdeps/linux-gnu/Makefile.am +++ b/sysdeps/linux-gnu/Makefile.am @@ -25,7 +25,6 @@ noinst_LTLIBRARIES = \ ../libos.la ___libos_la_SOURCES = \ - backtrace.c \ ioevent.c \ trace.c \ os.c \ diff --git a/sysdeps/linux-gnu/Makefile.in b/sysdeps/linux-gnu/Makefile.in index 25b0d70..3df0b51 100644 --- a/sysdeps/linux-gnu/Makefile.in +++ b/sysdeps/linux-gnu/Makefile.in @@ -125,8 +125,8 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) ___libos_la_DEPENDENCIES = libcpu.la -am____libos_la_OBJECTS = backtrace.lo ioevent.lo trace.lo os.lo \ - proc.lo socket.lo thread.lo +am____libos_la_OBJECTS = ioevent.lo trace.lo os.lo proc.lo socket.lo \ + thread.lo ___libos_la_OBJECTS = $(am____libos_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -368,7 +368,6 @@ noinst_LTLIBRARIES = \ ../libos.la ___libos_la_SOURCES = \ - backtrace.c \ ioevent.c \ trace.c \ os.c \ @@ -441,7 +440,6 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backtrace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ioevent.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc.Plo@am__quote@ diff --git a/sysdeps/linux-gnu/backtrace.c b/sysdeps/linux-gnu/backtrace.c deleted file mode 100644 index ecec7cf..0000000 --- a/sysdeps/linux-gnu/backtrace.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * This file is part of mtrace-ng. - * Copyright (C) 2015 Stefani Seibold - * - * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include "backtrace.h" -#include "dwarf.h" -#include "task.h" - -#include -#include - -int backtrace_init(struct task *task) -{ - assert(task->leader == task); - assert(task->backtrace == NULL); - - task->backtrace = dwarf_init(task->is_64bit); - - return task->backtrace != NULL; -} - -void backtrace_destroy(struct task *task) -{ - assert(task->leader == task); - - if (task->backtrace) { - dwarf_destroy(task->backtrace); - - task->backtrace = NULL; - } -} - -int backtrace_init_unwind(struct task *task) -{ - assert(task->leader); - assert(task->leader->backtrace); - - return dwarf_init_unwind(task->leader->backtrace, task); -} - -unsigned long backtrace_get_ip(struct task *task) -{ - assert(task->leader); - assert(task->leader->backtrace); - - return dwarf_get_ip(task->leader->backtrace); -} - -int backtrace_step(struct task *task) -{ - assert(task->leader); - assert(task->leader->backtrace); - - 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 d6bc5a7..daed0bc 100644 --- a/sysdeps/linux-gnu/ioevent.c +++ b/sysdeps/linux-gnu/ioevent.c @@ -40,7 +40,7 @@ struct io_watch_event *io_watch_event; static unsigned int io_watch_size; static unsigned int io_watch_elems; -static inline void io_watch_set(unsigned int idx, int fd, int (*func)(void)) +static inline void io_watch_set(unsigned int idx, int fd, ioevent_func func) { io_watch_event[idx].func = func; @@ -48,7 +48,7 @@ static inline void io_watch_set(unsigned int idx, int fd, int (*func)(void)) io_watch_poll[idx].events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL; } -int ioevent_add_input(int fd, int (*func)(void)) +int ioevent_add_input(int fd, ioevent_func func) { unsigned int i; @@ -113,6 +113,21 @@ int ioevent_watch(int timeout) return ret; } +ioevent_func ioevent_set_input_func(int fd, ioevent_func func) +{ + unsigned int i; + + for(i = 0; i < io_watch_elems; ++i) { + if (io_watch_poll[i].fd == fd) { + int (*old)(void) = io_watch_event[i].func; + + io_watch_event[i].func = func; + + return old; + } + } + return NULL; +} int ioevent_wait_input(int fd, int timeout) { diff --git a/sysdeps/linux-gnu/ioevent.h b/sysdeps/linux-gnu/ioevent.h index 7741edd..fa5e66d 100644 --- a/sysdeps/linux-gnu/ioevent.h +++ b/sysdeps/linux-gnu/ioevent.h @@ -23,10 +23,13 @@ #ifndef _INC_SYSDEPS_LINUX_GNU_IOEVENT_H #define _INC_SYSDEPS_LINUX_GNU_IOEVENT_H -int ioevent_add_input(int fd, int (*func)(void)); +typedef int (*ioevent_func)(void); + +int ioevent_add_input(int fd, ioevent_func func); int ioevent_del_input(int fd); int ioevent_watch(int timeout); int ioevent_wait_input(int fd, int timeout); +ioevent_func ioevent_set_input_func(int fd, ioevent_func func); #endif diff --git a/sysdeps/linux-gnu/os.c b/sysdeps/linux-gnu/os.c index 002c281..5d68bb7 100644 --- a/sysdeps/linux-gnu/os.c +++ b/sysdeps/linux-gnu/os.c @@ -43,6 +43,7 @@ #endif #include #include +#include #include "backend.h" #include "breakpoint.h" @@ -178,8 +179,8 @@ static struct map *get_writeable_mappings(struct task *task) char filename[PATH_MAX + 2]; char nl; FILE *in; - unsigned int maps_size = 0; - struct map *maps = NULL; + unsigned int maps_size; + struct map *maps; unsigned int map = 0; snprintf(filename, sizeof(filename)-1, "/proc/%d/maps", task->pid); @@ -393,6 +394,8 @@ int os_init(void) const int siglist[] = { SIGSEGV, SIGABRT, SIGTRAP, SIGILL, SIGFPE }; unsigned int i; + prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0); + for(i = 0; i < ARRAY_SIZE(siglist); i++) { act.sa_flags = SA_ONESHOT | SA_SIGINFO; act.sa_sigaction = report_fault; diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c index aa03195..d3821be 100644 --- a/sysdeps/linux-gnu/proc.c +++ b/sysdeps/linux-gnu/proc.c @@ -490,15 +490,16 @@ static int load_debug_struct(struct task *task, arch_addr_t debug_addr, struct l static int rdebug_bp_on_hit(struct task *task, struct breakpoint *bp) { struct lt_r_debug_64 rdbg; + struct task *leader = task->leader; debug(DEBUG_FUNCTION, "pid=%d", task->pid); - if (load_debug_struct(task, task->os.debug_addr, &rdbg) < 0) + if (load_debug_struct(task, leader->os.debug_addr, &rdbg) < 0) return 0; if (rdbg.r_state == RT_CONSISTENT) { debug(DEBUG_FUNCTION, "Linkmap is now consistent"); - switch (task->os.debug_state) { + switch (leader->os.debug_state) { case RT_ADD: linkmap_add(task, &rdbg); break; @@ -510,7 +511,7 @@ static int rdebug_bp_on_hit(struct task *task, struct breakpoint *bp) } } - task->os.debug_state = rdbg.r_state; + leader->os.debug_state = rdbg.r_state; return 0; } @@ -519,10 +520,11 @@ int linkmap_init(struct task *task, arch_addr_t dyn_addr) struct lt_r_debug_64 rdbg; struct breakpoint *bp; arch_addr_t debug_addr; + struct task *leader = task->leader; debug(DEBUG_FUNCTION, "pid=%d, dyn_addr=%#lx", task->pid, dyn_addr); - if (task->os.debug_addr) + if (leader->os.debug_addr) return 0; if (process_find_dynamic_entry_addr(task, dyn_addr, DT_DEBUG, &debug_addr) == -1) { @@ -538,7 +540,7 @@ int linkmap_init(struct task *task, arch_addr_t dyn_addr) arch_addr_t addr = ARCH_ADDR_T(rdbg.r_brk); - bp = breakpoint_new(task, addr, NULL, 0); + bp = breakpoint_new(task, addr, NULL, BP_SW); if (!bp) return -1; @@ -547,7 +549,7 @@ int linkmap_init(struct task *task, arch_addr_t dyn_addr) breakpoint_enable(task, bp); - task->os.debug_addr = debug_addr; + leader->os.debug_addr = debug_addr; if (rdbg.r_state == RT_CONSISTENT) linkmap_add(task, &rdbg); @@ -607,8 +609,10 @@ int process_get_entry(struct task *task, unsigned long *entryp, unsigned long *i int os_task_init(struct task *task) { - task->os.debug_addr = 0; - task->os.debug_state = RT_ADD; + struct task *leader = task->leader; + + leader->os.debug_addr = 0; + leader->os.debug_state = RT_ADD; return 0; } @@ -618,7 +622,9 @@ void os_task_destroy(struct task *task) int os_task_clone(struct task *retp, struct task *task) { - retp->os = task->os; + struct task *leader = task->leader; + + retp->os = leader->os; return 0; } diff --git a/sysdeps/linux-gnu/socket.c b/sysdeps/linux-gnu/socket.c index 4a5c2bb..b157e1b 100644 --- a/sysdeps/linux-gnu/socket.c +++ b/sysdeps/linux-gnu/socket.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include "common.h" #include "socket.h" @@ -64,7 +66,7 @@ ssize_t safe_read(int fd, void *dest, size_t n) return off + n; } -int sock_send_msg(int fd, enum mt_operation op, uint32_t pid, uint32_t tid, const void *payload, unsigned int payload_len) +int sock_send_msg(int fd, enum mt_operation op, uint32_t pid, const void *payload, unsigned int payload_len) { struct mt_msg mt_msg; struct iovec io[2]; @@ -96,12 +98,10 @@ int sock_send_msg(int fd, enum mt_operation op, uint32_t pid, uint32_t tid, cons if (op > 0xff) { mt_msg.pid = bswap_32(pid); - mt_msg.tid = bswap_32(tid); mt_msg.payload_len = bswap_32(payload_len); } else { mt_msg.pid = pid; - mt_msg.tid = tid; mt_msg.payload_len = payload_len; } @@ -215,6 +215,8 @@ int bind_to(const char *node, const char *service) } else { struct addrinfo *rp; + int size = 10 * 1024 * 1024; + static const int one = 1; for (rp = sock_addr(node, service, AI_PASSIVE); rp != NULL; rp = rp->ai_next) { sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); @@ -232,6 +234,12 @@ int bind_to(const char *node, const char *service) if (!rp) return -1; + + if (setsockopt(sfd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)) == -1) + fatal("TCP_NODELAY: %s\n", strerror(errno)); + + if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) == -1) + fatal("SO_SNDBUF: %s\n", strerror(errno)); } return sfd; diff --git a/sysdeps/linux-gnu/socket.h b/sysdeps/linux-gnu/socket.h index 36f0f4b..526b66f 100644 --- a/sysdeps/linux-gnu/socket.h +++ b/sysdeps/linux-gnu/socket.h @@ -35,7 +35,7 @@ ssize_t safe_read(int fd, void *dest, size_t n); int connect_to(const char *node, const char *service); int bind_to(const char *node, const char *service); -int sock_send_msg(int fd, enum mt_operation op, uint32_t pid, uint32_t tid, const void *payload, unsigned int payload_len); +int sock_send_msg(int fd, enum mt_operation op, uint32_t pid, const void *payload, unsigned int payload_len); int create_socket_pair(int sv[2]); int is_named(const char *node); diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c index 2a3b6bc..92f14a9 100644 --- a/sysdeps/linux-gnu/trace.c +++ b/sysdeps/linux-gnu/trace.c @@ -48,8 +48,10 @@ #include "debug.h" #include "event.h" #include "library.h" +#include "main.h" #include "options.h" #include "task.h" +#include "timer.h" static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static volatile pid_t wakeup_pid = -1; @@ -92,7 +94,7 @@ static int _trace_wait(struct task *task, int signum) { int status; - if (TEMP_FAILURE_RETRY(waitpid(task->pid, &status, __WALL)) != task->pid) { + if (unlikely(TEMP_FAILURE_RETRY(waitpid(task->pid, &status, __WALL)) != task->pid)) { fprintf(stderr, "%s pid=%d %s\n", __FUNCTION__, task->pid, strerror(errno)); return -1; } @@ -117,7 +119,7 @@ static int child_event(struct task *task, enum event_type ev) { unsigned long data; - if (ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1) { + if (unlikely(ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1)) { debug(DEBUG_EVENT, "PTRACE_GETEVENTMSG pid=%d %s", task->pid, strerror(errno)); return -1; } @@ -127,7 +129,7 @@ static int child_event(struct task *task, enum event_type ev) if (!pid2task(pid)) { struct task *child = task_new(pid); - if (!child) + if (unlikely(!child)) return -1; if (_trace_wait(child, SIGSTOP)) { @@ -190,7 +192,7 @@ static int _process_event(struct task *task, int status) { unsigned long data; - if (ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1) { + if (unlikely(ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1)) { debug(DEBUG_EVENT, "PTRACE_GETEVENTMSG pid=%d %s", task->pid, strerror(errno)); return -1; } @@ -221,6 +223,9 @@ static void process_event(struct task *task, int status) assert(leader != NULL); + if (unlikely(options.verbose > 1)) + start_time(&task->halt_time); + task->stopped = 1; leader->threads_stopped++; @@ -236,10 +241,10 @@ static void process_event(struct task *task, int status) if (stop_signal == 0) return; - if (stop_signal != SIGTRAP) + if (unlikely(stop_signal != SIGTRAP)) return; - if (fetch_context(task) == -1) { + if (unlikely(fetch_context(task) == -1)) { task->event.type = EVENT_NONE; continue_task(task, 0); return; @@ -252,7 +257,7 @@ 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) { - if (get_hw_bp_state(task, i)) + if (likely(get_hw_bp_state(task, i))) bp = task->hw_bp[i]; break; @@ -262,15 +267,12 @@ static void process_event(struct task *task, int status) if (bp) { assert(bp->type != BP_SW); assert(bp->hw_bp_slot == i); - - if (options.verbose > 1) - ++leader->num_hw_bp; } else #endif { bp = breakpoint_find(leader, ip - DECR_PC_AFTER_BREAK); - if (!bp) { + if (unlikely(!bp)) { task->event.type = EVENT_NONE; continue_task(task, 0); return; @@ -280,9 +282,6 @@ static void process_event(struct task *task, int status) assert(bp->hw == 0); #endif - if (options.verbose > 1) - ++leader->num_sw_bp; - set_instruction_pointer(task, bp->addr); } #if 1 @@ -321,7 +320,7 @@ void trace_me(void) prctl(PR_SET_PDEATHSIG, SIGKILL); - if (ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) { + if (unlikely(ptrace(PTRACE_TRACEME, 0, 0, 0) == -1)) { fprintf(stderr, "PTRACE_TRACEME pid=%d %s\n", getpid(), strerror(errno)); exit(1); } @@ -347,7 +346,7 @@ int untrace_task(struct task *task, int signum) if (!task->stopped) return 0; - if (ptrace(PTRACE_SETOPTIONS, task->pid, 0, (void *)0) == -1) { + if (unlikely(ptrace(PTRACE_SETOPTIONS, task->pid, 0, (void *)0) == -1)) { if (errno != ESRCH) fprintf(stderr, "PTRACE_SETOPTIONS pid=%d %s\n", task->pid, strerror(errno)); ret = -1; @@ -356,7 +355,7 @@ int untrace_task(struct task *task, int signum) signum = fix_signal(task, signum); - if (ptrace(PTRACE_DETACH, task->pid, 0, signum) == -1) { + if (unlikely(ptrace(PTRACE_DETACH, task->pid, 0, signum) == -1)) { if (task->traced) { if (errno != ESRCH) fprintf(stderr, "PTRACE_DETACH pid=%d %s\n", task->pid, strerror(errno)); @@ -381,7 +380,7 @@ int trace_attach(struct task *task) assert(task->traced == 0); - if (ptrace(PTRACE_ATTACH, task->pid, 0, 0) == -1) { + if (unlikely(ptrace(PTRACE_ATTACH, task->pid, 0, 0) == -1)) { if (errno != ESRCH) fprintf(stderr, "PTRACE_ATTACH pid=%d %s\n", task->pid, strerror(errno)); trace_fail_warning(); @@ -402,7 +401,7 @@ int trace_set_options(struct task *task) debug(DEBUG_PROCESS, "pid=%d", task->pid); - if (ptrace(PTRACE_SETOPTIONS, task->pid, 0, (void *)options) == -1) { + if (unlikely(ptrace(PTRACE_SETOPTIONS, task->pid, 0, (void *)options) == -1)) { if (errno != ESRCH) fprintf(stderr, "PTRACE_SETOPTIONS pid=%d %s\n", task->pid, strerror(errno)); return -1; @@ -420,7 +419,7 @@ int continue_task(struct task *task, int signum) task->leader->threads_stopped--; task->stopped = 0; - if (ptrace(PTRACE_CONT, task->pid, 0, fix_signal(task, signum)) == -1) { + if (unlikely(ptrace(PTRACE_CONT, task->pid, 0, fix_signal(task, signum)) == -1)) { if (errno != ESRCH) fprintf(stderr, "PTRACE_CONT pid=%d %s\n", task->pid, strerror(errno)); return -1; @@ -445,10 +444,18 @@ void stop_threads(struct task *task) assert(task->leader != NULL); if (leader->threads != leader->threads_stopped) { + struct timespec start; + + if (unlikely(options.verbose > 1)) + start_time(&start); + each_task(leader, &do_stop_cb, NULL); while (leader->threads != leader->threads_stopped) queue_event(wait_event()); + + if (unlikely(options.verbose > 1)) + set_timer(&start, &stop_time); } } @@ -458,10 +465,10 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task)) int stop_signal; for(;;) { - if (singlestep(task) == -1) + if (unlikely(singlestep(task) == -1)) return -1; - if (TEMP_FAILURE_RETRY(waitpid(task->pid, &status, __WALL)) != task->pid) { + if (unlikely(TEMP_FAILURE_RETRY(waitpid(task->pid, &status, __WALL)) != task->pid)) { fprintf(stderr, "%s waitpid pid=%d %s\n", __FUNCTION__, task->pid, strerror(errno)); return -1; } @@ -471,10 +478,10 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task)) if (stop_signal == -1) return -1; - if (stop_signal == SIGTRAP) + if (likely(stop_signal == SIGTRAP)) return 0; /* check if was a real breakpoint code there */ - if (!stop_signal) { + if (likely(!stop_signal)) { queue_event(task); return 0; } @@ -489,7 +496,7 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task)) #ifndef ARCH_SINGLESTEP static int ptrace_singlestep(struct task *task) { - if (ptrace(PTRACE_SINGLESTEP, task->pid, 0, 0) == -1) { + if (unlikely(ptrace(PTRACE_SINGLESTEP, task->pid, 0, 0) == -1)) { if (errno != ESRCH) fprintf(stderr, "%s PTRACE_SINGLESTEP pid=%d %s\n", __FUNCTION__, task->pid, strerror(errno)); return -1; @@ -510,7 +517,7 @@ struct task *wait_event(void) int pid; pid = waitpid(-1, &status, __WALL); - if (pid == -1) { + if (unlikely(pid == -1)) { if (errno != EINTR) { if (errno == ECHILD) debug(DEBUG_EVENT, "No more traced programs"); @@ -521,7 +528,7 @@ struct task *wait_event(void) } pthread_mutex_lock(&mutex); - if (pid == wakeup_pid) { + if (unlikely(pid == wakeup_pid)) { pid = 0; wakeup_pid = -1; } @@ -531,10 +538,10 @@ struct task *wait_event(void) return NULL; task = pid2task(pid); - if (!task) { + if (unlikely(!task)) { task = task_new(pid); - if (task) + if (likely(task)) trace_setup(task, status, SIGSTOP); return NULL; @@ -591,7 +598,7 @@ ssize_t copy_from_proc(struct task *task, arch_addr_t addr, void *dst, size_t le remote[0].iov_len = len; num_bytes = process_vm_readv(task->pid, local, 1, remote, 1, 0); - if (num_bytes != -1) + if (unlikely(num_bytes != -1)) return num_bytes; if (errno != EFAULT) { @@ -610,7 +617,7 @@ ssize_t copy_from_proc(struct task *task, arch_addr_t addr, void *dst, size_t le while (len) { a.a = ptrace(PTRACE_PEEKTEXT, task->pid, addr, 0); - if (a.a == -1 && errno) { + if (unlikely(a.a == -1 && errno)) { if (num_bytes && errno == EIO) break; return -1; @@ -650,7 +657,7 @@ ssize_t copy_to_proc(struct task *task, arch_addr_t addr, const void *src, size_ n = len; a.a = ptrace(PTRACE_PEEKTEXT, task->pid, addr, 0); - if (a.a == -1 && errno) { + if (unlikely(a.a == -1 && errno)) { if (num_bytes && errno == EIO) break; return -1; @@ -660,7 +667,7 @@ ssize_t copy_to_proc(struct task *task, arch_addr_t addr, const void *src, size_ memcpy(a.c, src, n); a.a = ptrace(PTRACE_POKETEXT, task->pid, addr, a.a); - if (a.a == -1) { + if (unlikely(a.a == -1)) { if (num_bytes && errno == EIO) break; return -1; @@ -690,7 +697,7 @@ ssize_t copy_from_to_proc(struct task *task, arch_addr_t addr, const void *src, while (len) { a.a = ptrace(PTRACE_PEEKTEXT, task->pid, addr, 0); - if (a.a == -1 && errno) { + if (unlikely(a.a == -1 && errno)) { if (num_bytes && errno == EIO) break; return -1; @@ -703,7 +710,7 @@ ssize_t copy_from_to_proc(struct task *task, arch_addr_t addr, const void *src, memcpy(a.c, src, n); a.a = ptrace(PTRACE_POKETEXT, task->pid, addr, a.a); - if (a.a == -1) { + if (unlikely(a.a == -1)) { if (num_bytes && errno == EIO) break; return -1; @@ -738,7 +745,7 @@ ssize_t copy_str_from_proc(struct task *task, arch_addr_t addr, char *dst, size_ while (len) { a.a = ptrace(PTRACE_PEEKTEXT, task->pid, addr, 0); - if (a.a == -1 && errno) { + if (unlikely(a.a == -1 && errno)) { if (num_bytes && errno == EIO) break; return -1; diff --git a/sysdeps/linux-gnu/x86/arch.c b/sysdeps/linux-gnu/x86/arch.c index ff975ea..403da7e 100644 --- a/sysdeps/linux-gnu/x86/arch.c +++ b/sysdeps/linux-gnu/x86/arch.c @@ -43,7 +43,7 @@ int get_hw_bp_state(struct task *task, unsigned int n) errno = 0; ret = ptrace(PTRACE_PEEKUSER, task->pid, offsetof(struct user, u_debugreg[6]), 0); - if (ret == -1 && errno) { + if (unlikely(ret == -1 && errno)) { if (errno != ESRCH) fprintf(stderr, "PTRACE_PEEKUSER u_debugreg[6] pid=%d %s\n", task->pid, strerror(errno)); @@ -59,7 +59,7 @@ static int _apply_hw_bp(struct task *task, uint32_t dr7) task->arch.dr7 = dr7; ret = ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct user, u_debugreg[7]), task->arch.dr7); - if (ret) { + if (unlikely(ret)) { if (errno != ESRCH) { fprintf(stderr, "PTRACE_POKEUSER u_debugreg[7] pid=%d %s\n", task->pid, strerror(errno)); return -1; @@ -89,7 +89,7 @@ static int set_breakpoint_addr(struct task *task, arch_addr_t addr, unsigned int return 0; ret = ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct user, u_debugreg[n]), addr); - if (ret) { + if (unlikely(ret)) { if (errno != ESRCH) { fprintf(stderr, "PTRACE_POKEUSER u_debugreg[%d] pid=%d %s\n", n, task->pid, strerror(errno)); return -1; @@ -167,7 +167,7 @@ int set_hw_bp(struct task *task, unsigned int n, arch_addr_t addr) if (reset_hw_bp(task, n) == -1) return -1; #endif - if (set_breakpoint_addr(task, addr, n) == -1) + if (unlikely(set_breakpoint_addr(task, addr, n) == -1)) return -1; return set_breakpoint_mode(task, diff --git a/sysdeps/linux-gnu/x86/dwarf-x86.c b/sysdeps/linux-gnu/x86/dwarf-x86.c index 78030f5..ff645e8 100644 --- a/sysdeps/linux-gnu/x86/dwarf-x86.c +++ b/sysdeps/linux-gnu/x86/dwarf-x86.c @@ -130,12 +130,12 @@ static const struct arch_reg arch_reg32 = { .bp = DWARF_X86_EBP, }; -static int is_signal_frame(struct dwarf_cursor *c) +static inline int is_signal_frame(struct dwarf_cursor *c) { return c->dci.signal_frame; } -static int is_plt_entry(struct dwarf_addr_space *as) +static inline int is_plt_entry(struct dwarf_addr_space *as) { #if 0 struct dwarf_cursor *c = &as->cursor; @@ -293,13 +293,13 @@ int dwarf_arch_map_reg(struct dwarf_addr_space *as, unsigned int reg) { #ifdef __x86_64__ if (as->is_64bit) { - if (reg >= ARRAY_SIZE(dwarf_to_regnum_map64)) + if (unlikely(reg >= ARRAY_SIZE(dwarf_to_regnum_map64))) return -DWARF_EBADREG; return dwarf_to_regnum_map64[reg]; } #endif - if (reg >= ARRAY_SIZE(dwarf_to_regnum_map32)) + if (unlikely(reg >= ARRAY_SIZE(dwarf_to_regnum_map32))) return -DWARF_EBADREG; return dwarf_to_regnum_map32[reg]; @@ -330,16 +330,16 @@ int dwarf_arch_check_call(struct dwarf_addr_space *as, arch_addr_t ip) struct libref *libref = c->libref; for(p = call_op; p->len; ++p) { - if (ip - ARCH_ADDR_T(libref->load_addr) >= p->off) { + if (likely(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]) + if (unlikely((addr[i] & p->mask[i]) != p->op[i])) break; } - if (i == p->len) + if (unlikely(i == p->len)) return 1; } } diff --git a/task.c b/task.c index 6910eef..5397147 100644 --- a/task.c +++ b/task.c @@ -48,7 +48,7 @@ static LIST_HEAD(list_of_leaders); -static struct rb_root pid_tree = RB_ROOT; +struct pid_hash *pid_hash[PID_HASH_SIZE]; #ifndef OS_HAVE_PROCESS_DATA static inline int os_task_init(struct task *task) @@ -82,45 +82,42 @@ static inline int arch_task_clone(struct task *retp, struct task *task) } #endif -struct task *pid2task(pid_t pid) +static inline void delete_pid(struct task *task) { - struct rb_node **new = &(pid_tree.rb_node); + struct pid_hash *entry = pid_hash[PID_HASH(task->pid)]; + unsigned int i; - /* Figure out where to put new node */ - while (*new) { - struct task *this = container_of(*new, struct task, pid_node); + for(i = 0; i < entry->num; ++i) { + struct task **p = &entry->tasks[i]; - if (this->pid == pid) - return this; - - if (this->pid < pid) - new = &((*new)->rb_left); - else - new = &((*new)->rb_right); + if ((*p)->pid == task->pid) { + entry->num--; + memmove(p, p + 1, (entry->num - i) * sizeof(entry->tasks[0])); + break; + } } - - return NULL; } -static void insert_pid(struct task *task) +static inline void insert_pid(struct task *task) { - struct rb_node **new = &(pid_tree.rb_node), *parent = NULL; + struct pid_hash *entry = pid_hash[PID_HASH(task->pid)]; - /* Figure out where to put new node */ - while (*new) { - struct task *this = container_of(*new, struct task, pid_node); + if (!entry->size) { + entry = malloc(sizeof(*entry) + 8 * sizeof(entry->tasks[0])); + entry->num = 0; + entry->size = 8; - parent = *new; + pid_hash[PID_HASH(task->pid)] = entry; + } + else + if (entry->size == entry->num) { + entry->size += 8; + entry = realloc(entry, sizeof(*entry) + entry->size * sizeof(entry->tasks[0])); - if (this->pid < task->pid) - new = &((*new)->rb_left); - else - new = &((*new)->rb_right); + pid_hash[PID_HASH(task->pid)] = entry; } - /* Add new node and rebalance tree. */ - rb_link_node(&task->pid_node, parent, new); - rb_insert_color(&task->pid_node, &pid_tree); + entry->tasks[entry->num++] = task; } static int leader_setup(struct task *leader) @@ -184,7 +181,7 @@ static int leader_cleanup(struct task *leader) if (--leader->threads) return 0; - + library_clear_all(leader); breakpoint_clear_all(leader); backtrace_destroy(leader); @@ -214,7 +211,7 @@ static void task_destroy(struct task *task) arch_task_destroy(task); os_task_destroy(task); detach_task(task); - rb_erase(&task->pid_node, &pid_tree); + delete_pid(task); if (leader != task) { list_del(&task->task_list); @@ -516,7 +513,7 @@ void open_pid(pid_t pid) task->is_64bit = leader->is_64bit; }; - if (options.verbose) + if (unlikely(options.verbose)) each_task(leader, &show_attached, NULL); return; @@ -575,9 +572,30 @@ int task_list_empty(void) void each_pid(void (*cb)(struct task *task)) { - struct task *task, *next; + unsigned int i; - rbtree_postorder_for_each_entry_safe(task, next, &pid_tree, pid_node) - (*cb)(task); + for(i = 0; i < ARRAY_SIZE(pid_hash); ++i) { + struct pid_hash *entry = pid_hash[i]; + unsigned int n = entry->num; + + if (n) { + struct task **p = alloca(n * sizeof(*p)); + + memcpy(p, entry->tasks, n * sizeof(*p)); + + do { + (*cb)(*p++); + } while(--n); + } + } +} + +void init_pid_hash(void) +{ + static const struct pid_hash preset = { .size = 0, .num = 0 }; + unsigned int i; + + for(i = 0; i < ARRAY_SIZE(pid_hash); ++i) + pid_hash[i] = (void *)&preset; } diff --git a/task.h b/task.h index fa887d3..3b86ce4 100644 --- a/task.h +++ b/task.h @@ -25,6 +25,7 @@ #include "config.h" +#include #include #include "forward.h" @@ -38,36 +39,22 @@ #include "report.h" struct task { - /* red/black tree node for fast pid -> struct task */ - struct rb_node pid_node; - - /* process id */ - pid_t pid; - - /* points to the leader thread of the POSIX.1 task */ - struct task *leader; - /* current pendig event */ struct event event; - unsigned int stopped:1; - unsigned int traced:1; - unsigned int was_stopped:1; unsigned int is_64bit:1; + unsigned int traced:1; unsigned int attached:1; unsigned int deleted:1; unsigned int about_exit:1; + unsigned int was_stopped:1; + unsigned int stopped:1; struct breakpoint *breakpoint; struct library_symbol *libsym; struct context context; /* process context (registers, stack) */ struct context saved_context; /* context for fetch_param() */ - /* os specific task data */ -#ifdef OS_HAVE_PROCESS_DATA - struct os_task_data os; -#endif - /* arch specific task data */ #ifdef TASK_HAVE_PROCESS_DATA struct arch_task_data arch; @@ -76,12 +63,20 @@ struct task { /* pointer to a breakpoint which was interrupt by a signal during skip */ struct breakpoint *skip_bp; +#if HW_BREAKPOINTS > 0 + /* array of active hw breakpoints */ + struct breakpoint *hw_bp[HW_BREAKPOINTS]; +#endif + + /* process id */ + pid_t pid; + + /* points to the leader thread */ + struct task *leader; + /* set in leader: number of stopped threads including the leader */ unsigned int threads_stopped; - unsigned long num_hw_bp; - unsigned long num_sw_bp; - /* set in leader: dictionary of breakpoints */ struct dict *breakpoints; @@ -91,6 +86,9 @@ struct task { /* linked list of libraries, the first entry is the executable itself */ struct list_head libraries_list; + /* red black tree of libraries */ + struct rb_root libraries_tree; + /* Thread chaining to leader */ struct list_head task_list; @@ -100,6 +98,9 @@ struct task { /* struct task chaining. */ struct list_head leader_list; + /* halt time for debugging purpose */ + struct timespec halt_time; + #if HW_BREAKPOINTS > 1 /* set in leader: list of hw breakpoints */ struct list_head hw_bp_list; @@ -108,9 +109,9 @@ struct task { unsigned long hw_bp_num; #endif -#if HW_BREAKPOINTS > 0 - /* array of active hw breakpoints */ - struct breakpoint *hw_bp[HW_BREAKPOINTS]; + /* os specific task data */ +#ifdef OS_HAVE_PROCESS_DATA + struct os_task_data os; #endif }; @@ -122,8 +123,6 @@ struct task *task_create(const char *command, char **argv); void open_pid(pid_t pid); -struct task *pid2task(pid_t pid); - /* Clone the contents of a task */ int task_clone(struct task *task, struct task *newtask); @@ -157,5 +156,37 @@ static inline int task_is_64bit(struct task *task) return task->is_64bit; } +struct pid_hash { + unsigned int num; + unsigned int size; + struct task * tasks[0]; +}; + +#define PID_HASH(pid) ((pid) % ARRAY_SIZE(pid_hash)) +#define PID_HASH_SIZE 256 + +extern struct pid_hash *pid_hash[PID_HASH_SIZE]; + +void init_pid_hash(void); + +static inline struct task *pid2task(pid_t pid) +{ + struct pid_hash *entry = pid_hash[PID_HASH(pid)]; + struct task **p = entry->tasks; + unsigned int n = entry->num; + + while(n) { + struct task *task = *p; + + if (likely(task->pid == pid)) + return task; + + p++; + n--; + } + + return NULL; +} + #endif diff --git a/timer.h b/timer.h new file mode 100644 index 0000000..28c4b26 --- /dev/null +++ b/timer.h @@ -0,0 +1,62 @@ +/* + * This file is part of mtrace-ng. + * Copyright (C) 2015 Stefani Seibold + * + * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef _INC_TIMER_H +#define _INC_TIMER_H + +#include +#include + +struct mt_timer { + unsigned int max; + unsigned int count; + unsigned long long culminate; +}; + +static inline int start_time(struct timespec *ts) +{ + return clock_gettime(CLOCK_THREAD_CPUTIME_ID, ts); +} + +static inline int set_timer(struct timespec *start, struct mt_timer *p) +{ + struct timespec now; + unsigned int usec; + + if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now) == -1) + return -1; + + usec = (now.tv_sec - start->tv_sec) * 1000000L + + (now.tv_nsec - start->tv_nsec + 500L) / 1000; + + if (p->max < usec) + p->max = usec; + + p->culminate += usec; + + ++p->count; + + return 0; +} + +#endif + diff --git a/trace.c b/trace.c index a85157f..afcd9ef 100644 --- a/trace.c +++ b/trace.c @@ -40,6 +40,7 @@ #include "report.h" #include "task.h" #include "library.h" +#include "main.h" int skip_breakpoint(struct task *task, struct breakpoint *bp) { @@ -50,12 +51,20 @@ int skip_breakpoint(struct task *task, struct breakpoint *bp) if (bp->enabled && !bp->hw) { int ret = 0; + struct timespec start; + + if (unlikely(options.verbose > 1)) + start_time(&start); breakpoint_disable(task, bp); ret = do_singlestep(task); breakpoint_enable(task, bp); - if (ret) { - if (ret == 1) { + + if (unlikely(options.verbose > 1)) + set_timer(&start, &skip_bp_time); + + if (unlikely(ret)) { + if (unlikely(ret == 1)) { breakpoint_put(task->skip_bp); task->skip_bp = breakpoint_get(bp); } @@ -105,8 +114,8 @@ void detach_proc(struct task *leader) breakpoint_disable_all(leader); - if (options.verbose > 1) - fprintf(stderr, "+++ process detach pid=%d sw-bp:%lu hw-bp:%lu +++\n", leader->pid, leader->num_sw_bp, leader->num_hw_bp); + if (unlikely(options.verbose > 1)) + fprintf(stderr, "+++ process detach pid=%d +++\n", leader->pid); each_task(leader, &detach_cb, NULL); }