Version 0.2

Lots of performance improvement
Better stack unwind
Bug fixes
This commit is contained in:
Stefani Seibold 2015-10-13 10:18:37 +02:00
parent e8f26940d0
commit d517c6fceb
55 changed files with 2295 additions and 1547 deletions

View File

@ -484,7 +484,7 @@ noinst_HEADERS = \
dist_man1_MANS = mtrace.1
dist_man5_MANS = mtrace.conf.5
dist_doc_DATA = COPYING CREDITS INSTALL README TODO
dist_doc_DATA = COPYING CREDITS INSTALL README TODO HOWTO
EXTRA_DIST =
MAINTAINERCLEANFILES = \
configure \

View File

@ -1,6 +1,6 @@
@%:@! /bin/sh
@%:@ Guess values for system-dependent variables and create Makefiles.
@%:@ Generated by GNU Autoconf 2.69 for mtrace 0.1.
@%:@ Generated by GNU Autoconf 2.69 for mtrace 0.2.
@%:@
@%:@ Report bugs to <stefani@seibold.net>.
@%:@
@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='mtrace'
PACKAGE_TARNAME='mtrace'
PACKAGE_VERSION='0.1'
PACKAGE_STRING='mtrace 0.1'
PACKAGE_VERSION='0.2'
PACKAGE_STRING='mtrace 0.2'
PACKAGE_BUGREPORT='stefani@seibold.net'
PACKAGE_URL=''
@ -1326,7 +1326,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures mtrace 0.1 to adapt to many kinds of systems.
\`configure' configures mtrace 0.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1396,7 +1396,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of mtrace 0.1:";;
short | recursive ) echo "Configuration of mtrace 0.2:";;
esac
cat <<\_ACEOF
@ -1512,7 +1512,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
mtrace configure 0.1
mtrace configure 0.2
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -2118,7 +2118,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by mtrace $as_me 0.1, which was
It was created by mtrace $as_me 0.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -12000,7 +12000,7 @@ fi
# Define the identity of the package.
PACKAGE='mtrace'
VERSION='0.1'
VERSION='0.2'
cat >>confdefs.h <<_ACEOF
@ -12746,6 +12746,8 @@ else
$as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CPPFLAGS="${saved_CPPFLAGS}"
LDFLAGS="${saved_LDFLAGS}"
saved_CFLAGS="${CFLAGS}"
CFLAGS="${CFLAGS} -Wall -Werror"
@ -13206,6 +13208,7 @@ for ac_func in \
strerror \
strtol \
strtoul \
process_vm_readv \
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
@ -13799,7 +13802,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by mtrace $as_me 0.1, which was
This file was extended by mtrace $as_me 0.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -13865,7 +13868,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
mtrace config.status 0.1
mtrace config.status 0.2
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View File

@ -1,6 +1,6 @@
@%:@! /bin/sh
@%:@ Guess values for system-dependent variables and create Makefiles.
@%:@ Generated by GNU Autoconf 2.69 for mtrace 0.1.
@%:@ Generated by GNU Autoconf 2.69 for mtrace 0.2.
@%:@
@%:@ Report bugs to <stefani@seibold.net>.
@%:@
@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='mtrace'
PACKAGE_TARNAME='mtrace'
PACKAGE_VERSION='0.1'
PACKAGE_STRING='mtrace 0.1'
PACKAGE_VERSION='0.2'
PACKAGE_STRING='mtrace 0.2'
PACKAGE_BUGREPORT='stefani@seibold.net'
PACKAGE_URL=''
@ -1326,7 +1326,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures mtrace 0.1 to adapt to many kinds of systems.
\`configure' configures mtrace 0.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1396,7 +1396,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of mtrace 0.1:";;
short | recursive ) echo "Configuration of mtrace 0.2:";;
esac
cat <<\_ACEOF
@ -1512,7 +1512,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
mtrace configure 0.1
mtrace configure 0.2
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -2118,7 +2118,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by mtrace $as_me 0.1, which was
It was created by mtrace $as_me 0.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -12000,7 +12000,7 @@ fi
# Define the identity of the package.
PACKAGE='mtrace'
VERSION='0.1'
VERSION='0.2'
cat >>confdefs.h <<_ACEOF
@ -12746,6 +12746,8 @@ else
$as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CPPFLAGS="${saved_CPPFLAGS}"
LDFLAGS="${saved_LDFLAGS}"
saved_CFLAGS="${CFLAGS}"
CFLAGS="${CFLAGS} -Wall -Werror"
@ -13206,6 +13208,7 @@ for ac_func in \
strerror \
strtol \
strtoul \
process_vm_readv \
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
@ -13799,7 +13802,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by mtrace $as_me 0.1, which was
This file was extended by mtrace $as_me 0.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -13865,7 +13868,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
mtrace config.status 0.1
mtrace config.status 0.2
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View File

@ -1,6 +1,6 @@
@%:@! /bin/sh
@%:@ Guess values for system-dependent variables and create Makefiles.
@%:@ Generated by GNU Autoconf 2.69 for mtrace 0.1.
@%:@ Generated by GNU Autoconf 2.69 for mtrace 0.2.
@%:@
@%:@ Report bugs to <stefani@seibold.net>.
@%:@
@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='mtrace'
PACKAGE_TARNAME='mtrace'
PACKAGE_VERSION='0.1'
PACKAGE_STRING='mtrace 0.1'
PACKAGE_VERSION='0.2'
PACKAGE_STRING='mtrace 0.2'
PACKAGE_BUGREPORT='stefani@seibold.net'
PACKAGE_URL=''
@ -1326,7 +1326,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures mtrace 0.1 to adapt to many kinds of systems.
\`configure' configures mtrace 0.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1396,7 +1396,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of mtrace 0.1:";;
short | recursive ) echo "Configuration of mtrace 0.2:";;
esac
cat <<\_ACEOF
@ -1512,7 +1512,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
mtrace configure 0.1
mtrace configure 0.2
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -2118,7 +2118,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by mtrace $as_me 0.1, which was
It was created by mtrace $as_me 0.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -12000,7 +12000,7 @@ fi
# Define the identity of the package.
PACKAGE='mtrace'
VERSION='0.1'
VERSION='0.2'
cat >>confdefs.h <<_ACEOF
@ -12746,6 +12746,8 @@ else
$as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CPPFLAGS="${saved_CPPFLAGS}"
LDFLAGS="${saved_LDFLAGS}"
saved_CFLAGS="${CFLAGS}"
CFLAGS="${CFLAGS} -Wall -Werror"
@ -13206,6 +13208,7 @@ for ac_func in \
strerror \
strtol \
strtoul \
process_vm_readv \
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
@ -13799,7 +13802,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by mtrace $as_me 0.1, which was
This file was extended by mtrace $as_me 0.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -13865,7 +13868,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
mtrace config.status 0.1
mtrace config.status 0.2
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View File

@ -42,186 +42,186 @@
'configure.ac'
],
{
'LT_AC_PROG_RC' => 1,
'AM_SUBST_NOTMAKE' => 1,
'AC_LTDL_PREOPEN' => 1,
'_LT_AC_LANG_GCJ_CONFIG' => 1,
'_LT_AC_PROG_ECHO_BACKSLASH' => 1,
'AC_LIBTOOL_LANG_CXX_CONFIG' => 1,
'LT_LIB_M' => 1,
'AM_SILENT_RULES' => 1,
'AC_LIBTOOL_SETUP' => 1,
'_LT_AC_TRY_DLOPEN_SELF' => 1,
'AC_PATH_MAGIC' => 1,
'_LT_AC_LOCK' => 1,
'LTOPTIONS_VERSION' => 1,
'_LT_AC_LANG_CXX' => 1,
'_LT_LINKER_BOILERPLATE' => 1,
'AC_LIBTOOL_LANG_GCJ_CONFIG' => 1,
'AM_DISABLE_SHARED' => 1,
'_LT_AC_SYS_LIBPATH_AIX' => 1,
'AC_LIBTOOL_PICMODE' => 1,
'_LT_CC_BASENAME' => 1,
'AC_PROG_LD_RELOAD_FLAG' => 1,
'AC_LIBTOOL_PROG_COMPILER_NO_RTTI' => 1,
'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1,
'_AM_SET_OPTIONS' => 1,
'AC_CHECK_LIBM' => 1,
'AU_DEFUN' => 1,
'_LT_PATH_TOOL_PREFIX' => 1,
'AC_LTDL_DLLIB' => 1,
'AM_PROG_NM' => 1,
'LTDL_INSTALLABLE' => 1,
'AC_LIBTOOL_PROG_CC_C_O' => 1,
'LT_SYS_DLSEARCH_PATH' => 1,
'_AM_PROG_TAR' => 1,
'AC_LTDL_DLSYM_USCORE' => 1,
'_LT_AC_LANG_F77' => 1,
'_AM_PROG_CC_C_O' => 1,
'AM_ENABLE_SHARED' => 1,
'_LT_REQUIRED_DARWIN_CHECKS' => 1,
'AC_LTDL_SHLIBPATH' => 1,
'_LT_AC_TAGVAR' => 1,
'AC_CONFIG_MACRO_DIR' => 1,
'AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE' => 1,
'AC_LIBTOOL_OBJDIR' => 1,
'_LT_COMPILER_BOILERPLATE' => 1,
'AM_ENABLE_STATIC' => 1,
'AM_MISSING_HAS_RUN' => 1,
'AC_LIBTOOL_PROG_LD_SHLIBS' => 1,
'_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1,
'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1,
'_m4_warn' => 1,
'_LT_AC_SHELL_INIT' => 1,
'_LT_WITH_SYSROOT' => 1,
'_LT_DLL_DEF_P' => 1,
'AM_AUX_DIR_EXPAND' => 1,
'AM_RUN_LOG' => 1,
'AC_ENABLE_STATIC' => 1,
'AC_CONFIG_MACRO_DIR' => 1,
'LT_LIB_M' => 1,
'LT_FUNC_DLSYM_USCORE' => 1,
'LT_PATH_NM' => 1,
'LTDL_CONVENIENCE' => 1,
'm4_pattern_allow' => 1,
'_LT_LIBOBJ' => 1,
'LT_OUTPUT' => 1,
'_LT_AC_LANG_RC_CONFIG' => 1,
'AC_LIBTOOL_OBJDIR' => 1,
'AC_LIBLTDL_INSTALLABLE' => 1,
'_LT_COMPILER_OPTION' => 1,
'AM_PROG_INSTALL_SH' => 1,
'_AM_AUTOCONF_VERSION' => 1,
'LT_SYS_DLOPEN_SELF' => 1,
'_AC_AM_CONFIG_HEADER_HOOK' => 1,
'AM_MAKE_INCLUDE' => 1,
'_AM_CONFIG_MACRO_DIRS' => 1,
'LT_PROG_GO' => 1,
'_LT_PROG_ECHO_BACKSLASH' => 1,
'AC_LIBTOOL_LANG_C_CONFIG' => 1,
'_LT_PROG_CXX' => 1,
'AC_LIBTOOL_PROG_COMPILER_PIC' => 1,
'AM_PROG_LD' => 1,
'AM_MISSING_PROG' => 1,
'LTOBSOLETE_VERSION' => 1,
'_AM_PROG_TAR' => 1,
'AC_LTDL_DLLIB' => 1,
'LT_PATH_LD' => 1,
'_LT_AC_TAGVAR' => 1,
'AC_LIBTOOL_PROG_CC_C_O' => 1,
'AC_LTDL_SHLIBEXT' => 1,
'AC_LIBTOOL_F77' => 1,
'm4_include' => 1,
'AM_SET_LEADING_DOT' => 1,
'AC_LIBTOOL_GCJ' => 1,
'_AM_DEPENDENCIES' => 1,
'LT_WITH_LTDL' => 1,
'_LT_AC_TAGCONFIG' => 1,
'_AM_AUTOCONF_VERSION' => 1,
'_LT_PREPARE_SED_QUOTE_VARS' => 1,
'_LT_AC_LANG_CXX_CONFIG' => 1,
'LT_LIB_DLLOAD' => 1,
'AC_LIBTOOL_CONFIG' => 1,
'_LTDL_SETUP' => 1,
'LT_FUNC_DLSYM_USCORE' => 1,
'AM_DISABLE_SHARED' => 1,
'LTSUGAR_VERSION' => 1,
'AM_MISSING_PROG' => 1,
'LT_PROG_GO' => 1,
'LT_AC_PROG_EGREP' => 1,
'_m4_warn' => 1,
'AM_DISABLE_STATIC' => 1,
'AM_PROG_CC_C_O' => 1,
'AC_LIBTOOL_COMPILER_OPTION' => 1,
'LT_SYS_DLOPEN_SELF' => 1,
'AC_LIBTOOL_LANG_C_CONFIG' => 1,
'AC_LTDL_OBJDIR' => 1,
'_LT_PROG_LTMAIN' => 1,
'AC_LIBLTDL_CONVENIENCE' => 1,
'LT_SUPPORTED_TAG' => 1,
'AC_PATH_TOOL_PREFIX' => 1,
'AC_PROG_LD_RELOAD_FLAG' => 1,
'AC_PROG_LIBTOOL' => 1,
'_LT_CC_BASENAME' => 1,
'AC_LIBTOOL_LANG_RC_CONFIG' => 1,
'AC_LIBTOOL_CXX' => 1,
'LT_SYS_MODULE_EXT' => 1,
'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1,
'LTOBSOLETE_VERSION' => 1,
'LT_INIT' => 1,
'LT_FUNC_ARGZ' => 1,
'AC_LIBTOOL_PROG_COMPILER_PIC' => 1,
'AC_DISABLE_FAST_INSTALL' => 1,
'AC_LIBTOOL_GCJ' => 1,
'm4_pattern_allow' => 1,
'AM_PROG_INSTALL_SH' => 1,
'AC_ENABLE_SHARED' => 1,
'AC_LIBTOOL_SYS_LIB_STRIP' => 1,
'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1,
'AC_DISABLE_SHARED' => 1,
'AC_PROG_EGREP' => 1,
'AC_LIBTOOL_LINKER_OPTION' => 1,
'AC_LIBTOOL_FC' => 1,
'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1,
'_AC_PROG_LIBTOOL' => 1,
'LT_PATH_NM' => 1,
'AM_AUX_DIR_EXPAND' => 1,
'include' => 1,
'AC_DISABLE_STATIC' => 1,
'AM_SET_DEPDIR' => 1,
'_AM_MANGLE_OPTION' => 1,
'LT_PROG_GCJ' => 1,
'_AM_SET_OPTIONS' => 1,
'AM_AUTOMAKE_VERSION' => 1,
'_LT_AC_PROG_CXXCPP' => 1,
'_LT_PROG_FC' => 1,
'AC_LIBTOOL_LANG_F77_CONFIG' => 1,
'_LT_PROG_CXX' => 1,
'_LT_AC_CHECK_DLFCN' => 1,
'AM_SANITY_CHECK' => 1,
'AC_LTDL_SYMBOL_USCORE' => 1,
'AC_CONFIG_MACRO_DIR_TRACE' => 1,
'AC_LIBTOOL_RC' => 1,
'AC_LIBTOOL_F77' => 1,
'AM_RUN_LOG' => 1,
'm4_include' => 1,
'AC_DEPLIBS_CHECK_METHOD' => 1,
'LT_PATH_LD' => 1,
'AM_MAINTAINER_MODE' => 1,
'AM_PROG_LIBTOOL' => 1,
'LTDL_INIT' => 1,
'AC_LIBTOOL_DLOPEN_SELF' => 1,
'AM_MAKE_INCLUDE' => 1,
'LTDL_CONVENIENCE' => 1,
'AC_LIB_LTDL' => 1,
'LT_SYS_MODULE_PATH' => 1,
'LT_CMD_MAX_LEN' => 1,
'm4_pattern_forbid' => 1,
'_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1,
'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1,
'AM_PROG_LD' => 1,
'AC_LTDL_SHLIBEXT' => 1,
'AC_LIBTOOL_PROG_COMPILER_NO_RTTI' => 1,
'AC_LIBLTDL_INSTALLABLE' => 1,
'AC_LIBTOOL_DLOPEN' => 1,
'AC_LIBTOOL_PROG_LD_SHLIBS' => 1,
'_AM_CONFIG_MACRO_DIRS' => 1,
'AC_LTDL_ENABLE_INSTALL' => 1,
'AC_ENABLE_FAST_INSTALL' => 1,
'LT_AC_PROG_GCJ' => 1,
'AC_LTDL_SYSSEARCHPATH' => 1,
'AM_MISSING_HAS_RUN' => 1,
'AC_PROG_NM' => 1,
'AM_PROG_INSTALL_STRIP' => 1,
'_AM_SUBST_NOTMAKE' => 1,
'_AM_SET_OPTION' => 1,
'LT_PROG_RC' => 1,
'AM_CONDITIONAL' => 1,
'AC_ENABLE_STATIC' => 1,
'LT_SYS_SYMBOL_USCORE' => 1,
'AM_SET_LEADING_DOT' => 1,
'_LT_COMPILER_OPTION' => 1,
'_LT_LINKER_OPTION' => 1,
'_AM_IF_OPTION' => 1,
'AC_LIBTOOL_WIN32_DLL' => 1,
'_LT_LIBOBJ' => 1,
'AC_DEFUN' => 1,
'LT_AC_PROG_SED' => 1,
'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1,
'AC_WITH_LTDL' => 1,
'_LT_AC_LANG_GCJ' => 1,
'AC_DEFUN_ONCE' => 1,
'AC_LIBTOOL_POSTDEP_PREDEP' => 1,
'_LT_AC_LANG_C_CONFIG' => 1,
'LT_CONFIG_LTDL_DIR' => 1,
'_LT_AC_FILE_LTDLL_C' => 1,
'LTVERSION_VERSION' => 1,
'AC_PROG_LD_GNU' => 1,
'LT_SYS_DLOPEN_DEPLIBS' => 1,
'AC_CHECK_LIBM' => 1,
'AC_LIBTOOL_SYS_DYNAMIC_LINKER' => 1,
'_LT_AC_LANG_F77_CONFIG' => 1,
'_LT_AC_SYS_COMPILER' => 1,
'_LT_DLL_DEF_P' => 1,
'_LT_AC_LANG_CXX_CONFIG' => 1,
'AC_ENABLE_FAST_INSTALL' => 1,
'LT_FUNC_ARGZ' => 1,
'_LTDL_SETUP' => 1,
'_AC_PROG_LIBTOOL' => 1,
'AC_DISABLE_SHARED' => 1,
'AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH' => 1,
'LT_LANG' => 1,
'AC_LIBTOOL_SYS_MAX_CMD_LEN' => 1,
'_LT_PROG_ECHO_BACKSLASH' => 1,
'AC_PROG_LD' => 1,
'AM_INIT_AUTOMAKE' => 1,
'AM_SUBST_NOTMAKE' => 1,
'LT_CONFIG_LTDL_DIR' => 1,
'AM_ENABLE_STATIC' => 1,
'AC_LIBTOOL_LANG_RC_CONFIG' => 1,
'AM_AUTOMAKE_VERSION' => 1,
'_LT_AC_TRY_DLOPEN_SELF' => 1,
'AC_LIBTOOL_SETUP' => 1,
'include' => 1,
'_LT_AC_LANG_F77' => 1,
'AM_PROG_LIBTOOL' => 1,
'AM_DEP_TRACK' => 1,
'_LT_PROG_F77' => 1
'_LT_WITH_SYSROOT' => 1,
'_LT_AC_LANG_C_CONFIG' => 1,
'AM_SET_DEPDIR' => 1,
'AC_LIBTOOL_WIN32_DLL' => 1,
'LT_SYS_MODULE_EXT' => 1,
'LT_CMD_MAX_LEN' => 1,
'AC_LIBTOOL_CONFIG' => 1,
'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1,
'AC_DEPLIBS_CHECK_METHOD' => 1,
'AC_PATH_TOOL_PREFIX' => 1,
'AC_LIBTOOL_LINKER_OPTION' => 1,
'LTDL_INSTALLABLE' => 1,
'AM_PROG_NM' => 1,
'AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE' => 1,
'LT_AC_PROG_RC' => 1,
'AM_SILENT_RULES' => 1,
'LT_SYS_MODULE_PATH' => 1,
'AC_LIBTOOL_LANG_F77_CONFIG' => 1,
'AM_INIT_AUTOMAKE' => 1,
'AC_LIBLTDL_CONVENIENCE' => 1,
'_LT_AC_LANG_F77_CONFIG' => 1,
'LTDL_INIT' => 1,
'AM_DISABLE_STATIC' => 1,
'_LT_AC_PROG_CXXCPP' => 1,
'_LT_PATH_TOOL_PREFIX' => 1,
'_LT_PREPARE_SED_QUOTE_VARS' => 1,
'LT_SUPPORTED_TAG' => 1,
'AC_DISABLE_STATIC' => 1,
'AC_LTDL_SHLIBPATH' => 1,
'AC_LIBTOOL_POSTDEP_PREDEP' => 1,
'AC_ENABLE_SHARED' => 1,
'm4_pattern_forbid' => 1,
'AC_LTDL_SYMBOL_USCORE' => 1,
'AC_LIBTOOL_SYS_MAX_CMD_LEN' => 1,
'AC_LTDL_ENABLE_INSTALL' => 1,
'LT_AC_PROG_GCJ' => 1,
'LT_LANG' => 1,
'_LT_AC_FILE_LTDLL_C' => 1,
'AM_CONDITIONAL' => 1,
'AC_PROG_LD_GNU' => 1,
'_LT_LINKER_OPTION' => 1,
'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1,
'LTOPTIONS_VERSION' => 1,
'AC_PATH_MAGIC' => 1,
'_LT_AC_TAGCONFIG' => 1,
'LT_INIT' => 1,
'_AM_IF_OPTION' => 1,
'AC_LIBTOOL_SYS_DYNAMIC_LINKER' => 1,
'AC_CONFIG_MACRO_DIR_TRACE' => 1,
'AC_LIBTOOL_PICMODE' => 1,
'_LT_PROG_LTMAIN' => 1,
'_LT_AC_PROG_ECHO_BACKSLASH' => 1,
'AC_LIBTOOL_LANG_CXX_CONFIG' => 1,
'AM_ENABLE_SHARED' => 1,
'AC_LIBTOOL_DLOPEN' => 1,
'_LT_AC_CHECK_DLFCN' => 1,
'_LT_AC_LANG_GCJ' => 1,
'_LT_LINKER_BOILERPLATE' => 1,
'_LT_PROG_FC' => 1,
'_LT_AC_SYS_COMPILER' => 1,
'AM_PROG_CC_C_O' => 1,
'LT_AC_PROG_EGREP' => 1,
'LT_SYS_DLOPEN_DEPLIBS' => 1,
'_AM_SET_OPTION' => 1,
'AC_LIBTOOL_SYS_LIB_STRIP' => 1,
'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1,
'LT_LIB_DLLOAD' => 1,
'AC_LTDL_DLSYM_USCORE' => 1,
'AC_LIBTOOL_DLOPEN_SELF' => 1,
'AM_MAINTAINER_MODE' => 1,
'_AM_PROG_CC_C_O' => 1,
'AC_LIBTOOL_FC' => 1,
'_LT_PROG_F77' => 1,
'LT_AC_PROG_SED' => 1,
'AC_LIBTOOL_COMPILER_OPTION' => 1,
'AC_LIB_LTDL' => 1,
'_LT_AC_SYS_LIBPATH_AIX' => 1,
'_AM_SUBST_NOTMAKE' => 1,
'AC_PROG_NM' => 1,
'LTVERSION_VERSION' => 1,
'AC_WITH_LTDL' => 1,
'AC_DEFUN' => 1,
'_LT_AC_LANG_GCJ_CONFIG' => 1,
'LT_SYS_SYMBOL_USCORE' => 1,
'AC_LTDL_SYSSEARCHPATH' => 1,
'AC_PROG_LD' => 1,
'_LT_AC_LANG_CXX' => 1,
'_LT_COMPILER_BOILERPLATE' => 1,
'AC_LIBTOOL_RC' => 1,
'AC_LTDL_OBJDIR' => 1,
'LT_SYS_DLSEARCH_PATH' => 1,
'_LT_REQUIRED_DARWIN_CHECKS' => 1,
'AC_LIBTOOL_LANG_GCJ_CONFIG' => 1,
'AM_PROG_INSTALL_STRIP' => 1,
'_AM_MANGLE_OPTION' => 1,
'AC_DISABLE_FAST_INSTALL' => 1,
'_LT_AC_LOCK' => 1,
'AC_PROG_LIBTOOL' => 1,
'LT_PROG_RC' => 1,
'AC_PROG_EGREP' => 1,
'AC_LTDL_PREOPEN' => 1,
'AM_SANITY_CHECK' => 1,
'_LT_AC_LANG_RC_CONFIG' => 1,
'LT_PROG_GCJ' => 1,
'AC_LIBTOOL_CXX' => 1
}
], 'Autom4te::Request' ),
bless( [
@ -263,186 +263,186 @@
'configure.ac'
],
{
'AC_LIBTOOL_SETUP' => 1,
'_LT_AC_TRY_DLOPEN_SELF' => 1,
'AC_PATH_MAGIC' => 1,
'AC_LIBTOOL_LANG_CXX_CONFIG' => 1,
'LT_LIB_M' => 1,
'AM_SILENT_RULES' => 1,
'_LT_AC_LANG_GCJ_CONFIG' => 1,
'_LT_AC_PROG_ECHO_BACKSLASH' => 1,
'LT_AC_PROG_RC' => 1,
'AM_SUBST_NOTMAKE' => 1,
'AC_LTDL_PREOPEN' => 1,
'AC_LIBTOOL_PROG_CC_C_O' => 1,
'LT_SYS_DLSEARCH_PATH' => 1,
'AC_LTDL_DLSYM_USCORE' => 1,
'_AM_PROG_TAR' => 1,
'_AM_PROG_CC_C_O' => 1,
'_LT_AC_LANG_F77' => 1,
'AM_ENABLE_SHARED' => 1,
'_LT_REQUIRED_DARWIN_CHECKS' => 1,
'AM_PROG_NM' => 1,
'LTDL_INSTALLABLE' => 1,
'_LT_AC_SYS_LIBPATH_AIX' => 1,
'AC_LIBTOOL_PICMODE' => 1,
'AU_DEFUN' => 1,
'_LT_PATH_TOOL_PREFIX' => 1,
'AC_LTDL_DLLIB' => 1,
'_LT_AC_LOCK' => 1,
'_LT_AC_LANG_CXX' => 1,
'LTOPTIONS_VERSION' => 1,
'AC_LIBTOOL_LANG_GCJ_CONFIG' => 1,
'_LT_LINKER_BOILERPLATE' => 1,
'AM_DISABLE_SHARED' => 1,
'AM_MISSING_PROG' => 1,
'LT_PROG_GO' => 1,
'LT_AC_PROG_EGREP' => 1,
'_m4_warn' => 1,
'_LT_AC_TAGCONFIG' => 1,
'LT_WITH_LTDL' => 1,
'_AM_AUTOCONF_VERSION' => 1,
'_LT_PREPARE_SED_QUOTE_VARS' => 1,
'_LT_AC_LANG_CXX_CONFIG' => 1,
'LT_LIB_DLLOAD' => 1,
'AC_LIBTOOL_CONFIG' => 1,
'_LTDL_SETUP' => 1,
'LTSUGAR_VERSION' => 1,
'LT_FUNC_DLSYM_USCORE' => 1,
'AM_ENABLE_STATIC' => 1,
'_LT_WITH_SYSROOT' => 1,
'_LT_AC_SHELL_INIT' => 1,
'LT_OUTPUT' => 1,
'_LT_AC_LANG_RC_CONFIG' => 1,
'_AC_AM_CONFIG_HEADER_HOOK' => 1,
'_AM_DEPENDENCIES' => 1,
'AC_LTDL_SHLIBPATH' => 1,
'_LT_AC_TAGVAR' => 1,
'AC_CONFIG_MACRO_DIR' => 1,
'AC_LIBTOOL_OBJDIR' => 1,
'AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE' => 1,
'_LT_COMPILER_BOILERPLATE' => 1,
'AC_DISABLE_SHARED' => 1,
'AC_LIBTOOL_LINKER_OPTION' => 1,
'AC_PROG_EGREP' => 1,
'AC_LIBTOOL_FC' => 1,
'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1,
'AM_PROG_INSTALL_SH' => 1,
'm4_pattern_allow' => 1,
'AC_ENABLE_SHARED' => 1,
'AC_LIBTOOL_SYS_LIB_STRIP' => 1,
'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1,
'AC_LIBTOOL_CXX' => 1,
'LT_SYS_MODULE_EXT' => 1,
'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1,
'LTOBSOLETE_VERSION' => 1,
'LT_FUNC_ARGZ' => 1,
'LT_INIT' => 1,
'AC_LIBTOOL_PROG_COMPILER_PIC' => 1,
'AC_LIBTOOL_GCJ' => 1,
'AC_DISABLE_FAST_INSTALL' => 1,
'AM_PROG_CC_C_O' => 1,
'AM_DISABLE_STATIC' => 1,
'AC_LIBTOOL_COMPILER_OPTION' => 1,
'AC_LIBTOOL_LANG_C_CONFIG' => 1,
'LT_SYS_DLOPEN_SELF' => 1,
'LT_SUPPORTED_TAG' => 1,
'AC_LIBLTDL_CONVENIENCE' => 1,
'AC_PATH_TOOL_PREFIX' => 1,
'_LT_PROG_LTMAIN' => 1,
'AC_LTDL_OBJDIR' => 1,
'AC_PROG_LD_RELOAD_FLAG' => 1,
'_LT_CC_BASENAME' => 1,
'AC_PROG_LIBTOOL' => 1,
'AC_LIBTOOL_LANG_RC_CONFIG' => 1,
'AM_RUN_LOG' => 1,
'AC_DEPLIBS_CHECK_METHOD' => 1,
'm4_include' => 1,
'LT_PATH_LD' => 1,
'AM_PROG_LIBTOOL' => 1,
'AM_MAINTAINER_MODE' => 1,
'_LT_PROG_CXX' => 1,
'_LT_AC_CHECK_DLFCN' => 1,
'AM_SANITY_CHECK' => 1,
'AC_LTDL_SYMBOL_USCORE' => 1,
'AC_CONFIG_MACRO_DIR_TRACE' => 1,
'AC_LIBTOOL_RC' => 1,
'AC_LIBTOOL_F77' => 1,
'_LT_AC_PROG_CXXCPP' => 1,
'_LT_PROG_FC' => 1,
'AC_LIBTOOL_LANG_F77_CONFIG' => 1,
'_AC_PROG_LIBTOOL' => 1,
'LT_PATH_NM' => 1,
'AM_AUX_DIR_EXPAND' => 1,
'include' => 1,
'AC_DISABLE_STATIC' => 1,
'AM_SET_DEPDIR' => 1,
'_AM_MANGLE_OPTION' => 1,
'AM_AUTOMAKE_VERSION' => 1,
'_AM_SET_OPTIONS' => 1,
'LT_PROG_GCJ' => 1,
'AC_LTDL_SHLIBEXT' => 1,
'AC_LIBTOOL_PROG_COMPILER_NO_RTTI' => 1,
'AC_LIBLTDL_INSTALLABLE' => 1,
'AC_LIBTOOL_DLOPEN' => 1,
'AC_LIBTOOL_PROG_LD_SHLIBS' => 1,
'_AM_CONFIG_MACRO_DIRS' => 1,
'_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1,
'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1,
'AM_PROG_LD' => 1,
'LT_SYS_MODULE_PATH' => 1,
'LT_CMD_MAX_LEN' => 1,
'm4_pattern_forbid' => 1,
'LTDL_INIT' => 1,
'AC_LIBTOOL_DLOPEN_SELF' => 1,
'AM_MAKE_INCLUDE' => 1,
'LTDL_CONVENIENCE' => 1,
'AC_LIB_LTDL' => 1,
'AC_PROG_NM' => 1,
'AM_PROG_INSTALL_STRIP' => 1,
'_AM_SUBST_NOTMAKE' => 1,
'_AM_SET_OPTION' => 1,
'LT_PROG_RC' => 1,
'AM_CONDITIONAL' => 1,
'AC_ENABLE_STATIC' => 1,
'AM_MISSING_HAS_RUN' => 1,
'AC_LTDL_SYSSEARCHPATH' => 1,
'AC_LTDL_ENABLE_INSTALL' => 1,
'AC_ENABLE_FAST_INSTALL' => 1,
'LT_AC_PROG_GCJ' => 1,
'_LT_AC_LANG_F77_CONFIG' => 1,
'_LT_DLL_DEF_P' => 1,
'_LT_AC_SYS_COMPILER' => 1,
'AC_LIBTOOL_SYS_MAX_CMD_LEN' => 1,
'LT_LANG' => 1,
'AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH' => 1,
'AM_PROG_NM' => 1,
'AM_INIT_AUTOMAKE' => 1,
'AC_PROG_LD' => 1,
'_LT_PROG_ECHO_BACKSLASH' => 1,
'_LT_PROG_F77' => 1,
'AM_DEP_TRACK' => 1,
'_LT_AC_FILE_LTDLL_C' => 1,
'LTVERSION_VERSION' => 1,
'AC_PROG_LD_GNU' => 1,
'LT_SYS_DLOPEN_DEPLIBS' => 1,
'AC_CHECK_LIBM' => 1,
'AC_LIBTOOL_SYS_DYNAMIC_LINKER' => 1,
'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1,
'AC_WITH_LTDL' => 1,
'_LT_AC_LANG_GCJ' => 1,
'AC_DEFUN_ONCE' => 1,
'AM_SILENT_RULES' => 1,
'LT_SYS_MODULE_PATH' => 1,
'AC_LIBTOOL_LANG_F77_CONFIG' => 1,
'LT_AC_PROG_RC' => 1,
'_LT_PREPARE_SED_QUOTE_VARS' => 1,
'LT_SUPPORTED_TAG' => 1,
'AM_DISABLE_STATIC' => 1,
'_LT_AC_PROG_CXXCPP' => 1,
'_LT_PATH_TOOL_PREFIX' => 1,
'LTDL_INIT' => 1,
'AC_LIBLTDL_CONVENIENCE' => 1,
'_LT_AC_LANG_F77_CONFIG' => 1,
'm4_pattern_forbid' => 1,
'AC_ENABLE_SHARED' => 1,
'AC_LTDL_SYMBOL_USCORE' => 1,
'AC_LIBTOOL_POSTDEP_PREDEP' => 1,
'_LT_AC_LANG_C_CONFIG' => 1,
'LT_CONFIG_LTDL_DIR' => 1,
'LT_SYS_SYMBOL_USCORE' => 1,
'AM_SET_LEADING_DOT' => 1,
'_LT_COMPILER_OPTION' => 1,
'AC_LTDL_SHLIBPATH' => 1,
'AC_DISABLE_STATIC' => 1,
'AC_LTDL_ENABLE_INSTALL' => 1,
'LT_AC_PROG_GCJ' => 1,
'AC_LIBTOOL_SYS_MAX_CMD_LEN' => 1,
'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1,
'_LT_LINKER_OPTION' => 1,
'AM_CONDITIONAL' => 1,
'AC_PROG_LD_GNU' => 1,
'LT_LANG' => 1,
'_LT_AC_FILE_LTDLL_C' => 1,
'_AM_IF_OPTION' => 1,
'AC_LIBTOOL_WIN32_DLL' => 1,
'_LT_LIBOBJ' => 1,
'LT_INIT' => 1,
'_LT_AC_TAGCONFIG' => 1,
'AC_PATH_MAGIC' => 1,
'LTOPTIONS_VERSION' => 1,
'_LT_AC_CHECK_DLFCN' => 1,
'AC_LIBTOOL_DLOPEN' => 1,
'_LT_PROG_LTMAIN' => 1,
'AC_LIBTOOL_PICMODE' => 1,
'_LT_AC_PROG_ECHO_BACKSLASH' => 1,
'AC_LIBTOOL_LANG_CXX_CONFIG' => 1,
'AM_ENABLE_SHARED' => 1,
'AC_LIBTOOL_SYS_DYNAMIC_LINKER' => 1,
'AC_CONFIG_MACRO_DIR_TRACE' => 1,
'_LT_PROG_FC' => 1,
'_LT_LINKER_BOILERPLATE' => 1,
'_LT_AC_LANG_GCJ' => 1,
'AC_LTDL_DLSYM_USCORE' => 1,
'AC_LIBTOOL_SYS_LIB_STRIP' => 1,
'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1,
'LT_LIB_DLLOAD' => 1,
'LT_SYS_DLOPEN_DEPLIBS' => 1,
'LT_AC_PROG_EGREP' => 1,
'AM_PROG_CC_C_O' => 1,
'_AM_SET_OPTION' => 1,
'_LT_AC_SYS_COMPILER' => 1,
'AC_PROG_NM' => 1,
'LTVERSION_VERSION' => 1,
'AC_DEFUN' => 1,
'LT_AC_PROG_SED' => 1
'AC_WITH_LTDL' => 1,
'AC_LIB_LTDL' => 1,
'_LT_AC_SYS_LIBPATH_AIX' => 1,
'_AM_SUBST_NOTMAKE' => 1,
'_LT_PROG_F77' => 1,
'LT_AC_PROG_SED' => 1,
'AC_LIBTOOL_COMPILER_OPTION' => 1,
'AM_MAINTAINER_MODE' => 1,
'AC_LIBTOOL_DLOPEN_SELF' => 1,
'_AM_PROG_CC_C_O' => 1,
'AC_LIBTOOL_FC' => 1,
'AC_PROG_LD' => 1,
'_LT_AC_LANG_CXX' => 1,
'AC_LTDL_SYSSEARCHPATH' => 1,
'LT_SYS_SYMBOL_USCORE' => 1,
'_LT_AC_LANG_GCJ_CONFIG' => 1,
'_LT_COMPILER_BOILERPLATE' => 1,
'_AM_MANGLE_OPTION' => 1,
'AM_PROG_INSTALL_STRIP' => 1,
'AC_LIBTOOL_LANG_GCJ_CONFIG' => 1,
'_LT_REQUIRED_DARWIN_CHECKS' => 1,
'LT_SYS_DLSEARCH_PATH' => 1,
'AC_LTDL_OBJDIR' => 1,
'AC_LIBTOOL_RC' => 1,
'LT_PROG_RC' => 1,
'AC_PROG_EGREP' => 1,
'AC_PROG_LIBTOOL' => 1,
'_LT_AC_LOCK' => 1,
'AC_DISABLE_FAST_INSTALL' => 1,
'AC_LIBTOOL_CXX' => 1,
'_LT_AC_LANG_RC_CONFIG' => 1,
'LT_PROG_GCJ' => 1,
'AC_LTDL_PREOPEN' => 1,
'AM_SANITY_CHECK' => 1,
'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1,
'_AM_SET_OPTIONS' => 1,
'AC_CHECK_LIBM' => 1,
'AC_PROG_LD_RELOAD_FLAG' => 1,
'AC_LIBTOOL_PROG_COMPILER_NO_RTTI' => 1,
'_LT_CC_BASENAME' => 1,
'_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1,
'AU_DEFUN' => 1,
'AC_LIBTOOL_PROG_LD_SHLIBS' => 1,
'AM_MISSING_HAS_RUN' => 1,
'LT_LIB_M' => 1,
'LT_FUNC_DLSYM_USCORE' => 1,
'AC_ENABLE_STATIC' => 1,
'AM_RUN_LOG' => 1,
'AC_CONFIG_MACRO_DIR' => 1,
'_m4_warn' => 1,
'AM_AUX_DIR_EXPAND' => 1,
'_LT_DLL_DEF_P' => 1,
'_LT_AC_SHELL_INIT' => 1,
'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1,
'm4_pattern_allow' => 1,
'LTDL_CONVENIENCE' => 1,
'LT_PATH_NM' => 1,
'AC_LIBLTDL_INSTALLABLE' => 1,
'AC_LIBTOOL_OBJDIR' => 1,
'LT_OUTPUT' => 1,
'_LT_LIBOBJ' => 1,
'LT_SYS_DLOPEN_SELF' => 1,
'_AC_AM_CONFIG_HEADER_HOOK' => 1,
'AM_MAKE_INCLUDE' => 1,
'AM_PROG_INSTALL_SH' => 1,
'_AM_AUTOCONF_VERSION' => 1,
'_LT_COMPILER_OPTION' => 1,
'AM_PROG_LD' => 1,
'AM_MISSING_PROG' => 1,
'_LT_PROG_CXX' => 1,
'AC_LIBTOOL_PROG_COMPILER_PIC' => 1,
'AC_LIBTOOL_LANG_C_CONFIG' => 1,
'_AM_CONFIG_MACRO_DIRS' => 1,
'LT_PROG_GO' => 1,
'_LT_PROG_ECHO_BACKSLASH' => 1,
'AC_LTDL_DLLIB' => 1,
'_AM_PROG_TAR' => 1,
'LTOBSOLETE_VERSION' => 1,
'_LT_AC_TAGVAR' => 1,
'LT_PATH_LD' => 1,
'AM_DISABLE_SHARED' => 1,
'_AM_DEPENDENCIES' => 1,
'LT_WITH_LTDL' => 1,
'AC_DEFUN_ONCE' => 1,
'LTSUGAR_VERSION' => 1,
'AC_LIBTOOL_GCJ' => 1,
'm4_include' => 1,
'AC_LIBTOOL_F77' => 1,
'AM_SET_LEADING_DOT' => 1,
'AC_LIBTOOL_PROG_CC_C_O' => 1,
'AC_LTDL_SHLIBEXT' => 1,
'LT_FUNC_ARGZ' => 1,
'_LTDL_SETUP' => 1,
'_LT_AC_LANG_CXX_CONFIG' => 1,
'AC_ENABLE_FAST_INSTALL' => 1,
'AC_DISABLE_SHARED' => 1,
'AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH' => 1,
'_AC_PROG_LIBTOOL' => 1,
'AM_AUTOMAKE_VERSION' => 1,
'_LT_AC_TRY_DLOPEN_SELF' => 1,
'AC_LIBTOOL_SETUP' => 1,
'AM_ENABLE_STATIC' => 1,
'AC_LIBTOOL_LANG_RC_CONFIG' => 1,
'AM_SUBST_NOTMAKE' => 1,
'LT_CONFIG_LTDL_DIR' => 1,
'AM_PROG_LIBTOOL' => 1,
'include' => 1,
'_LT_AC_LANG_F77' => 1,
'LT_SYS_MODULE_EXT' => 1,
'LT_CMD_MAX_LEN' => 1,
'AM_SET_DEPDIR' => 1,
'AC_LIBTOOL_WIN32_DLL' => 1,
'_LT_AC_LANG_C_CONFIG' => 1,
'_LT_WITH_SYSROOT' => 1,
'AM_DEP_TRACK' => 1,
'AC_PATH_TOOL_PREFIX' => 1,
'LTDL_INSTALLABLE' => 1,
'AC_LIBTOOL_LINKER_OPTION' => 1,
'AC_DEPLIBS_CHECK_METHOD' => 1,
'AC_LIBTOOL_CONFIG' => 1,
'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1
}
], 'Autom4te::Request' ),
bless( [
@ -457,65 +457,65 @@
'configure.ac'
],
{
'_AM_COND_IF' => 1,
'AM_PROG_AR' => 1,
'AC_CONFIG_HEADERS' => 1,
'AC_SUBST_TRACE' => 1,
'AM_INIT_AUTOMAKE' => 1,
'AM_POT_TOOLS' => 1,
'AM_PROG_CXX_C_O' => 1,
'm4_pattern_allow' => 1,
'AC_FC_SRCEXT' => 1,
'AC_CONFIG_SUBDIRS' => 1,
'AC_REQUIRE_AUX_FILE' => 1,
'AM_ENABLE_MULTILIB' => 1,
'LT_INIT' => 1,
'AM_GNU_GETTEXT' => 1,
'_AM_COND_ELSE' => 1,
'LT_CONFIG_LTDL_DIR' => 1,
'AC_CANONICAL_HOST' => 1,
'AC_CANONICAL_BUILD' => 1,
'm4_pattern_forbid' => 1,
'AM_PROG_MKDIR_P' => 1,
'_AM_COND_ENDIF' => 1,
'_AM_MAKEFILE_INCLUDE' => 1,
'LT_SUPPORTED_TAG' => 1,
'AM_PROG_CC_C_O' => 1,
'm4_sinclude' => 1,
'AM_PROG_FC_C_O' => 1,
'AM_PROG_F77_C_O' => 1,
'AC_PROG_LIBTOOL' => 1,
'AC_FC_PP_DEFINE' => 1,
'AH_OUTPUT' => 1,
'AC_SUBST' => 1,
'_AM_SUBST_NOTMAKE' => 1,
'AM_PROG_MOC' => 1,
'AC_CANONICAL_TARGET' => 1,
'_m4_warn' => 1,
'AM_MAINTAINER_MODE' => 1,
'AM_MAKEFILE_INCLUDE' => 1,
'AC_CANONICAL_SYSTEM' => 1,
'AM_CONDITIONAL' => 1,
'AM_NLS' => 1,
'AM_PATH_GUILE' => 1,
'm4_include' => 1,
'AM_EXTRA_RECURSIVE_TARGETS' => 1,
'AC_CONFIG_LINKS' => 1,
'AM_GNU_GETTEXT' => 1,
'include' => 1,
'AC_CONFIG_HEADERS' => 1,
'AM_GNU_GETTEXT_INTL_SUBDIR' => 1,
'_AM_COND_ENDIF' => 1,
'AC_DEFINE_TRACE_LITERAL' => 1,
'AM_PROG_AR' => 1,
'AC_CONFIG_LIBOBJ_DIR' => 1,
'LT_CONFIG_LTDL_DIR' => 1,
'AC_CONFIG_AUX_DIR' => 1,
'AM_AUTOMAKE_VERSION' => 1,
'AM_POT_TOOLS' => 1,
'AM_PROG_FC_C_O' => 1,
'AH_OUTPUT' => 1,
'AM_ENABLE_MULTILIB' => 1,
'AC_SUBST_TRACE' => 1,
'_LT_AC_TAGCONFIG' => 1,
'AC_FC_FREEFORM' => 1,
'AC_CONFIG_AUX_DIR' => 1,
'AM_SILENT_RULES' => 1,
'AM_PROG_MOC' => 1,
'AC_CANONICAL_SYSTEM' => 1,
'sinclude' => 1,
'AM_XGETTEXT_OPTION' => 1,
'AC_PROG_LIBTOOL' => 1,
'LT_INIT' => 1,
'AM_NLS' => 1,
'm4_include' => 1,
'AM_PROG_CC_C_O' => 1,
'AM_PROG_CXX_C_O' => 1,
'_AM_MAKEFILE_INCLUDE' => 1,
'AM_INIT_AUTOMAKE' => 1,
'AC_LIBSOURCE' => 1,
'_AM_COND_ELSE' => 1,
'AM_SILENT_RULES' => 1,
'AC_CONFIG_LINKS' => 1,
'AM_EXTRA_RECURSIVE_TARGETS' => 1,
'AC_CONFIG_SUBDIRS' => 1,
'AC_INIT' => 1,
'AC_FC_PP_SRCEXT' => 1,
'AC_CANONICAL_HOST' => 1,
'AC_REQUIRE_AUX_FILE' => 1,
'AM_XGETTEXT_OPTION' => 1,
'AC_CANONICAL_TARGET' => 1,
'AM_PROG_MKDIR_P' => 1,
'AC_FC_SRCEXT' => 1,
'm4_sinclude' => 1,
'm4_pattern_forbid' => 1,
'm4_pattern_allow' => 1,
'AC_CANONICAL_BUILD' => 1,
'AC_CONFIG_FILES' => 1,
'AM_GNU_GETTEXT_INTL_SUBDIR' => 1,
'include' => 1,
'AC_CONFIG_LIBOBJ_DIR' => 1,
'AC_DEFINE_TRACE_LITERAL' => 1,
'AM_AUTOMAKE_VERSION' => 1,
'AC_LIBSOURCE' => 1
'AM_PROG_F77_C_O' => 1,
'AC_FC_PP_SRCEXT' => 1,
'_m4_warn' => 1,
'AM_MAINTAINER_MODE' => 1,
'AM_PATH_GUILE' => 1,
'LT_SUPPORTED_TAG' => 1,
'AC_SUBST' => 1,
'AC_FC_PP_DEFINE' => 1,
'_AM_COND_IF' => 1,
'_AM_SUBST_NOTMAKE' => 1
}
], 'Autom4te::Request' )
);

View File

@ -2729,29 +2729,29 @@ m4trace:configure.ac:130: -1- m4_pattern_allow([^HAVE_LIBREADLINE$])
m4trace:configure.ac:136: -1- m4_pattern_allow([^HAVE_SELINUX_SELINUX_H$])
m4trace:configure.ac:137: -1- m4_pattern_allow([^HAVE_LIBSELINUX$])
m4trace:configure.ac:146: -1- m4_pattern_allow([^HAVE_ELF_C_READ_MMAP$])
m4trace:configure.ac:159: -1- m4_pattern_allow([^ELF_HASH_TAKES_CHARP$])
m4trace:configure.ac:194: -1- m4_pattern_allow([^uid_t$])
m4trace:configure.ac:194: -1- m4_pattern_allow([^gid_t$])
m4trace:configure.ac:196: -1- m4_pattern_allow([^pid_t$])
m4trace:configure.ac:197: -1- m4_pattern_allow([^size_t$])
m4trace:configure.ac:198: -1- m4_pattern_allow([^SIZEOF_LONG$])
m4trace:configure.ac:202: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_VFORK_H$])
m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$])
m4trace:configure.ac:203: -1- m4_pattern_allow([^vfork$])
m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_WORKING_FORK$])
m4trace:configure.ac:233: -1- m4_pattern_allow([^DEBUG$])
m4trace:configure.ac:247: -1- m4_pattern_allow([^AM_CPPFLAGS$])
m4trace:configure.ac:248: -1- m4_pattern_allow([^AM_CFLAGS$])
m4trace:configure.ac:249: -1- m4_pattern_allow([^AM_LDFLAGS$])
m4trace:configure.ac:250: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$])
m4trace:configure.ac:261: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:261: -1- m4_pattern_allow([^LTLIBOBJS$])
m4trace:configure.ac:261: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])
m4trace:configure.ac:261: -1- m4_pattern_allow([^am__EXEEXT_TRUE$])
m4trace:configure.ac:261: -1- m4_pattern_allow([^am__EXEEXT_FALSE$])
m4trace:configure.ac:261: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE])
m4trace:configure.ac:261: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE])
m4trace:configure.ac:261: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"])
m4trace:configure.ac:261: -1- _LT_PROG_LTMAIN
m4trace:configure.ac:261: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS
m4trace:configure.ac:161: -1- m4_pattern_allow([^ELF_HASH_TAKES_CHARP$])
m4trace:configure.ac:196: -1- m4_pattern_allow([^uid_t$])
m4trace:configure.ac:196: -1- m4_pattern_allow([^gid_t$])
m4trace:configure.ac:198: -1- m4_pattern_allow([^pid_t$])
m4trace:configure.ac:199: -1- m4_pattern_allow([^size_t$])
m4trace:configure.ac:200: -1- m4_pattern_allow([^SIZEOF_LONG$])
m4trace:configure.ac:204: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_VFORK_H$])
m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$])
m4trace:configure.ac:205: -1- m4_pattern_allow([^vfork$])
m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_WORKING_FORK$])
m4trace:configure.ac:236: -1- m4_pattern_allow([^DEBUG$])
m4trace:configure.ac:250: -1- m4_pattern_allow([^AM_CPPFLAGS$])
m4trace:configure.ac:251: -1- m4_pattern_allow([^AM_CFLAGS$])
m4trace:configure.ac:252: -1- m4_pattern_allow([^AM_LDFLAGS$])
m4trace:configure.ac:253: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$])
m4trace:configure.ac:264: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:264: -1- m4_pattern_allow([^LTLIBOBJS$])
m4trace:configure.ac:264: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])
m4trace:configure.ac:264: -1- m4_pattern_allow([^am__EXEEXT_TRUE$])
m4trace:configure.ac:264: -1- m4_pattern_allow([^am__EXEEXT_FALSE$])
m4trace:configure.ac:264: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE])
m4trace:configure.ac:264: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE])
m4trace:configure.ac:264: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"])
m4trace:configure.ac:264: -1- _LT_PROG_LTMAIN
m4trace:configure.ac:264: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS

View File

@ -2729,29 +2729,29 @@ m4trace:configure.ac:130: -1- m4_pattern_allow([^HAVE_LIBREADLINE$])
m4trace:configure.ac:136: -1- m4_pattern_allow([^HAVE_SELINUX_SELINUX_H$])
m4trace:configure.ac:137: -1- m4_pattern_allow([^HAVE_LIBSELINUX$])
m4trace:configure.ac:146: -1- m4_pattern_allow([^HAVE_ELF_C_READ_MMAP$])
m4trace:configure.ac:159: -1- m4_pattern_allow([^ELF_HASH_TAKES_CHARP$])
m4trace:configure.ac:194: -1- m4_pattern_allow([^uid_t$])
m4trace:configure.ac:194: -1- m4_pattern_allow([^gid_t$])
m4trace:configure.ac:196: -1- m4_pattern_allow([^pid_t$])
m4trace:configure.ac:197: -1- m4_pattern_allow([^size_t$])
m4trace:configure.ac:198: -1- m4_pattern_allow([^SIZEOF_LONG$])
m4trace:configure.ac:202: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_VFORK_H$])
m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$])
m4trace:configure.ac:203: -1- m4_pattern_allow([^vfork$])
m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_WORKING_FORK$])
m4trace:configure.ac:233: -1- m4_pattern_allow([^DEBUG$])
m4trace:configure.ac:247: -1- m4_pattern_allow([^AM_CPPFLAGS$])
m4trace:configure.ac:248: -1- m4_pattern_allow([^AM_CFLAGS$])
m4trace:configure.ac:249: -1- m4_pattern_allow([^AM_LDFLAGS$])
m4trace:configure.ac:250: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$])
m4trace:configure.ac:261: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:261: -1- m4_pattern_allow([^LTLIBOBJS$])
m4trace:configure.ac:261: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])
m4trace:configure.ac:261: -1- m4_pattern_allow([^am__EXEEXT_TRUE$])
m4trace:configure.ac:261: -1- m4_pattern_allow([^am__EXEEXT_FALSE$])
m4trace:configure.ac:261: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE])
m4trace:configure.ac:261: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE])
m4trace:configure.ac:261: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"])
m4trace:configure.ac:261: -1- _LT_PROG_LTMAIN
m4trace:configure.ac:261: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS
m4trace:configure.ac:161: -1- m4_pattern_allow([^ELF_HASH_TAKES_CHARP$])
m4trace:configure.ac:196: -1- m4_pattern_allow([^uid_t$])
m4trace:configure.ac:196: -1- m4_pattern_allow([^gid_t$])
m4trace:configure.ac:198: -1- m4_pattern_allow([^pid_t$])
m4trace:configure.ac:199: -1- m4_pattern_allow([^size_t$])
m4trace:configure.ac:200: -1- m4_pattern_allow([^SIZEOF_LONG$])
m4trace:configure.ac:204: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_VFORK_H$])
m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$])
m4trace:configure.ac:205: -1- m4_pattern_allow([^vfork$])
m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_WORKING_FORK$])
m4trace:configure.ac:236: -1- m4_pattern_allow([^DEBUG$])
m4trace:configure.ac:250: -1- m4_pattern_allow([^AM_CPPFLAGS$])
m4trace:configure.ac:251: -1- m4_pattern_allow([^AM_CFLAGS$])
m4trace:configure.ac:252: -1- m4_pattern_allow([^AM_LDFLAGS$])
m4trace:configure.ac:253: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$])
m4trace:configure.ac:264: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:264: -1- m4_pattern_allow([^LTLIBOBJS$])
m4trace:configure.ac:264: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])
m4trace:configure.ac:264: -1- m4_pattern_allow([^am__EXEEXT_TRUE$])
m4trace:configure.ac:264: -1- m4_pattern_allow([^am__EXEEXT_FALSE$])
m4trace:configure.ac:264: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE])
m4trace:configure.ac:264: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE])
m4trace:configure.ac:264: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"])
m4trace:configure.ac:264: -1- _LT_PROG_LTMAIN
m4trace:configure.ac:264: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS

View File

@ -3,7 +3,7 @@ m4trace:aclocal.m4:1190: -1- m4_include([config/m4/ltoptions.m4])
m4trace:aclocal.m4:1191: -1- m4_include([config/m4/ltsugar.m4])
m4trace:aclocal.m4:1192: -1- m4_include([config/m4/ltversion.m4])
m4trace:aclocal.m4:1193: -1- m4_include([config/m4/lt~obsolete.m4])
m4trace:configure.ac:27: -1- AC_INIT([mtrace], [0.1], [stefani@seibold.net])
m4trace:configure.ac:27: -1- AC_INIT([mtrace], [0.2], [stefani@seibold.net])
m4trace:configure.ac:27: -1- m4_pattern_forbid([^_?A[CHUM]_])
m4trace:configure.ac:27: -1- m4_pattern_forbid([_AC_])
m4trace:configure.ac:27: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section `AC_LIBOBJ vs LIBOBJS'])
@ -559,122 +559,124 @@ m4trace:configure.ac:146: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ELF_C_READ_MMAP])
m4trace:configure.ac:146: -1- m4_pattern_allow([^HAVE_ELF_C_READ_MMAP$])
m4trace:configure.ac:146: -1- AH_OUTPUT([HAVE_ELF_C_READ_MMAP], [/* we have read mmap support */
@%:@undef HAVE_ELF_C_READ_MMAP])
m4trace:configure.ac:159: -1- AC_DEFINE_TRACE_LITERAL([ELF_HASH_TAKES_CHARP])
m4trace:configure.ac:159: -1- m4_pattern_allow([^ELF_HASH_TAKES_CHARP$])
m4trace:configure.ac:159: -1- AH_OUTPUT([ELF_HASH_TAKES_CHARP], [/* elf_hash() takes char* (as opposed to unsigned char *) */
m4trace:configure.ac:161: -1- AC_DEFINE_TRACE_LITERAL([ELF_HASH_TAKES_CHARP])
m4trace:configure.ac:161: -1- m4_pattern_allow([^ELF_HASH_TAKES_CHARP$])
m4trace:configure.ac:161: -1- AH_OUTPUT([ELF_HASH_TAKES_CHARP], [/* elf_hash() takes char* (as opposed to unsigned char *) */
@%:@undef ELF_HASH_TAKES_CHARP])
m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_FCNTL_H], [/* Define to 1 if you have the <fcntl.h> header file. */
m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_FCNTL_H], [/* Define to 1 if you have the <fcntl.h> header file. */
@%:@undef HAVE_FCNTL_H])
m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_LIMITS_H], [/* Define to 1 if you have the <limits.h> header file. */
m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_LIMITS_H], [/* Define to 1 if you have the <limits.h> header file. */
@%:@undef HAVE_LIMITS_H])
m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_STDDEF_H], [/* Define to 1 if you have the <stddef.h> header file. */
m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_STDDEF_H], [/* Define to 1 if you have the <stddef.h> header file. */
@%:@undef HAVE_STDDEF_H])
m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the <stdint.h> header file. */
m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the <stdint.h> header file. */
@%:@undef HAVE_STDINT_H])
m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the <stdlib.h> header file. */
m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the <stdlib.h> header file. */
@%:@undef HAVE_STDLIB_H])
m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the <string.h> header file. */
m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the <string.h> header file. */
@%:@undef HAVE_STRING_H])
m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_SYS_IOCTL_H], [/* Define to 1 if you have the <sys/ioctl.h> header file. */
m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_SYS_IOCTL_H], [/* Define to 1 if you have the <sys/ioctl.h> header file. */
@%:@undef HAVE_SYS_IOCTL_H])
m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_SYS_PARAM_H], [/* Define to 1 if you have the <sys/param.h> header file. */
m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_SYS_PARAM_H], [/* Define to 1 if you have the <sys/param.h> header file. */
@%:@undef HAVE_SYS_PARAM_H])
m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_SYS_TIME_H], [/* Define to 1 if you have the <sys/time.h> header file. */
m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_SYS_TIME_H], [/* Define to 1 if you have the <sys/time.h> header file. */
@%:@undef HAVE_SYS_TIME_H])
m4trace:configure.ac:180: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the <unistd.h> header file. */
m4trace:configure.ac:182: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the <unistd.h> header file. */
@%:@undef HAVE_UNISTD_H])
m4trace:configure.ac:194: -1- AC_DEFINE_TRACE_LITERAL([uid_t])
m4trace:configure.ac:194: -1- m4_pattern_allow([^uid_t$])
m4trace:configure.ac:194: -1- AH_OUTPUT([uid_t], [/* Define to `int\' if <sys/types.h> doesn\'t define. */
m4trace:configure.ac:196: -1- AC_DEFINE_TRACE_LITERAL([uid_t])
m4trace:configure.ac:196: -1- m4_pattern_allow([^uid_t$])
m4trace:configure.ac:196: -1- AH_OUTPUT([uid_t], [/* Define to `int\' if <sys/types.h> doesn\'t define. */
@%:@undef uid_t])
m4trace:configure.ac:194: -1- AC_DEFINE_TRACE_LITERAL([gid_t])
m4trace:configure.ac:194: -1- m4_pattern_allow([^gid_t$])
m4trace:configure.ac:194: -1- AH_OUTPUT([gid_t], [/* Define to `int\' if <sys/types.h> doesn\'t define. */
m4trace:configure.ac:196: -1- AC_DEFINE_TRACE_LITERAL([gid_t])
m4trace:configure.ac:196: -1- m4_pattern_allow([^gid_t$])
m4trace:configure.ac:196: -1- AH_OUTPUT([gid_t], [/* Define to `int\' if <sys/types.h> doesn\'t define. */
@%:@undef gid_t])
m4trace:configure.ac:195: -1- AH_OUTPUT([inline], [/* Define to `__inline__\' or `__inline\' if that\'s what the C compiler
m4trace:configure.ac:197: -1- AH_OUTPUT([inline], [/* Define to `__inline__\' or `__inline\' if that\'s what the C compiler
calls it, or to nothing if \'inline\' is not supported under any name. */
#ifndef __cplusplus
#undef inline
#endif])
m4trace:configure.ac:196: -1- AC_DEFINE_TRACE_LITERAL([pid_t])
m4trace:configure.ac:196: -1- m4_pattern_allow([^pid_t$])
m4trace:configure.ac:196: -1- AH_OUTPUT([pid_t], [/* Define to `int\' if <sys/types.h> does not define. */
m4trace:configure.ac:198: -1- AC_DEFINE_TRACE_LITERAL([pid_t])
m4trace:configure.ac:198: -1- m4_pattern_allow([^pid_t$])
m4trace:configure.ac:198: -1- AH_OUTPUT([pid_t], [/* Define to `int\' if <sys/types.h> does not define. */
@%:@undef pid_t])
m4trace:configure.ac:197: -1- AC_DEFINE_TRACE_LITERAL([size_t])
m4trace:configure.ac:197: -1- m4_pattern_allow([^size_t$])
m4trace:configure.ac:197: -1- AH_OUTPUT([size_t], [/* Define to `unsigned int\' if <sys/types.h> does not define. */
m4trace:configure.ac:199: -1- AC_DEFINE_TRACE_LITERAL([size_t])
m4trace:configure.ac:199: -1- m4_pattern_allow([^size_t$])
m4trace:configure.ac:199: -1- AH_OUTPUT([size_t], [/* Define to `unsigned int\' if <sys/types.h> does not define. */
@%:@undef size_t])
m4trace:configure.ac:198: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_LONG])
m4trace:configure.ac:198: -1- m4_pattern_allow([^SIZEOF_LONG$])
m4trace:configure.ac:198: -1- AH_OUTPUT([SIZEOF_LONG], [/* The size of `long\', as computed by sizeof. */
m4trace:configure.ac:200: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_LONG])
m4trace:configure.ac:200: -1- m4_pattern_allow([^SIZEOF_LONG$])
m4trace:configure.ac:200: -1- AH_OUTPUT([SIZEOF_LONG], [/* The size of `long\', as computed by sizeof. */
@%:@undef SIZEOF_LONG])
m4trace:configure.ac:202: -1- AC_LIBSOURCE([error.h])
m4trace:configure.ac:202: -1- AC_LIBSOURCE([error.c])
m4trace:configure.ac:202: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS error.$ac_objext"])
m4trace:configure.ac:202: -1- AC_SUBST_TRACE([LIB@&t@OBJS])
m4trace:configure.ac:202: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:202: -1- AC_LIBSOURCE([error.c])
m4trace:configure.ac:203: -1- AH_OUTPUT([HAVE_VFORK_H], [/* Define to 1 if you have the <vfork.h> header file. */
m4trace:configure.ac:204: -1- AC_LIBSOURCE([error.h])
m4trace:configure.ac:204: -1- AC_LIBSOURCE([error.c])
m4trace:configure.ac:204: -1- AC_SUBST([LIB@&t@OBJS], ["$LIB@&t@OBJS error.$ac_objext"])
m4trace:configure.ac:204: -1- AC_SUBST_TRACE([LIB@&t@OBJS])
m4trace:configure.ac:204: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:204: -1- AC_LIBSOURCE([error.c])
m4trace:configure.ac:205: -1- AH_OUTPUT([HAVE_VFORK_H], [/* Define to 1 if you have the <vfork.h> header file. */
@%:@undef HAVE_VFORK_H])
m4trace:configure.ac:203: -1- AC_DEFINE_TRACE_LITERAL([HAVE_VFORK_H])
m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_VFORK_H$])
m4trace:configure.ac:203: -1- AH_OUTPUT([HAVE_FORK], [/* Define to 1 if you have the `fork\' function. */
m4trace:configure.ac:205: -1- AC_DEFINE_TRACE_LITERAL([HAVE_VFORK_H])
m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_VFORK_H$])
m4trace:configure.ac:205: -1- AH_OUTPUT([HAVE_FORK], [/* Define to 1 if you have the `fork\' function. */
@%:@undef HAVE_FORK])
m4trace:configure.ac:203: -1- AH_OUTPUT([HAVE_VFORK], [/* Define to 1 if you have the `vfork\' function. */
m4trace:configure.ac:205: -1- AH_OUTPUT([HAVE_VFORK], [/* Define to 1 if you have the `vfork\' function. */
@%:@undef HAVE_VFORK])
m4trace:configure.ac:203: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WORKING_VFORK])
m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$])
m4trace:configure.ac:203: -1- AH_OUTPUT([HAVE_WORKING_VFORK], [/* Define to 1 if `vfork\' works. */
m4trace:configure.ac:205: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WORKING_VFORK])
m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$])
m4trace:configure.ac:205: -1- AH_OUTPUT([HAVE_WORKING_VFORK], [/* Define to 1 if `vfork\' works. */
@%:@undef HAVE_WORKING_VFORK])
m4trace:configure.ac:203: -1- AC_DEFINE_TRACE_LITERAL([vfork])
m4trace:configure.ac:203: -1- m4_pattern_allow([^vfork$])
m4trace:configure.ac:203: -1- AH_OUTPUT([vfork], [/* Define as `fork\' if `vfork\' does not work. */
m4trace:configure.ac:205: -1- AC_DEFINE_TRACE_LITERAL([vfork])
m4trace:configure.ac:205: -1- m4_pattern_allow([^vfork$])
m4trace:configure.ac:205: -1- AH_OUTPUT([vfork], [/* Define as `fork\' if `vfork\' does not work. */
@%:@undef vfork])
m4trace:configure.ac:203: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WORKING_FORK])
m4trace:configure.ac:203: -1- m4_pattern_allow([^HAVE_WORKING_FORK$])
m4trace:configure.ac:203: -1- AH_OUTPUT([HAVE_WORKING_FORK], [/* Define to 1 if `fork\' works. */
m4trace:configure.ac:205: -1- AC_DEFINE_TRACE_LITERAL([HAVE_WORKING_FORK])
m4trace:configure.ac:205: -1- m4_pattern_allow([^HAVE_WORKING_FORK$])
m4trace:configure.ac:205: -1- AH_OUTPUT([HAVE_WORKING_FORK], [/* Define to 1 if `fork\' works. */
@%:@undef HAVE_WORKING_FORK])
m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_ALARM], [/* Define to 1 if you have the `alarm\' function. */
m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_ALARM], [/* Define to 1 if you have the `alarm\' function. */
@%:@undef HAVE_ALARM])
m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_ATEXIT], [/* Define to 1 if you have the `atexit\' function. */
m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_ATEXIT], [/* Define to 1 if you have the `atexit\' function. */
@%:@undef HAVE_ATEXIT])
m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_GETCWD], [/* Define to 1 if you have the `getcwd\' function. */
m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_GETCWD], [/* Define to 1 if you have the `getcwd\' function. */
@%:@undef HAVE_GETCWD])
m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_GETTIMEOFDAY], [/* Define to 1 if you have the `gettimeofday\' function. */
m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_GETTIMEOFDAY], [/* Define to 1 if you have the `gettimeofday\' function. */
@%:@undef HAVE_GETTIMEOFDAY])
m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_MEMSET], [/* Define to 1 if you have the `memset\' function. */
m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_MEMSET], [/* Define to 1 if you have the `memset\' function. */
@%:@undef HAVE_MEMSET])
m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_MKDIR], [/* Define to 1 if you have the `mkdir\' function. */
m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_MKDIR], [/* Define to 1 if you have the `mkdir\' function. */
@%:@undef HAVE_MKDIR])
m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_RMDIR], [/* Define to 1 if you have the `rmdir\' function. */
m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_RMDIR], [/* Define to 1 if you have the `rmdir\' function. */
@%:@undef HAVE_RMDIR])
m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_STRCHR], [/* Define to 1 if you have the `strchr\' function. */
m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_STRCHR], [/* Define to 1 if you have the `strchr\' function. */
@%:@undef HAVE_STRCHR])
m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_STRDUP], [/* Define to 1 if you have the `strdup\' function. */
m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_STRDUP], [/* Define to 1 if you have the `strdup\' function. */
@%:@undef HAVE_STRDUP])
m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_STRERROR], [/* Define to 1 if you have the `strerror\' function. */
m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_STRERROR], [/* Define to 1 if you have the `strerror\' function. */
@%:@undef HAVE_STRERROR])
m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_STRTOL], [/* Define to 1 if you have the `strtol\' function. */
m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_STRTOL], [/* Define to 1 if you have the `strtol\' function. */
@%:@undef HAVE_STRTOL])
m4trace:configure.ac:204: -1- AH_OUTPUT([HAVE_STRTOUL], [/* Define to 1 if you have the `strtoul\' function. */
m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_STRTOUL], [/* Define to 1 if you have the `strtoul\' function. */
@%:@undef HAVE_STRTOUL])
m4trace:configure.ac:233: -1- AC_DEFINE_TRACE_LITERAL([DEBUG])
m4trace:configure.ac:233: -1- m4_pattern_allow([^DEBUG$])
m4trace:configure.ac:233: -1- AH_OUTPUT([DEBUG], [/* debugging */
m4trace:configure.ac:206: -1- AH_OUTPUT([HAVE_PROCESS_VM_READV], [/* Define to 1 if you have the `process_vm_readv\' function. */
@%:@undef HAVE_PROCESS_VM_READV])
m4trace:configure.ac:236: -1- AC_DEFINE_TRACE_LITERAL([DEBUG])
m4trace:configure.ac:236: -1- m4_pattern_allow([^DEBUG$])
m4trace:configure.ac:236: -1- AH_OUTPUT([DEBUG], [/* debugging */
@%:@undef DEBUG])
m4trace:configure.ac:247: -1- AC_SUBST([AM_CPPFLAGS])
m4trace:configure.ac:247: -1- AC_SUBST_TRACE([AM_CPPFLAGS])
m4trace:configure.ac:247: -1- m4_pattern_allow([^AM_CPPFLAGS$])
m4trace:configure.ac:248: -1- AC_SUBST([AM_CFLAGS])
m4trace:configure.ac:248: -1- AC_SUBST_TRACE([AM_CFLAGS])
m4trace:configure.ac:248: -1- m4_pattern_allow([^AM_CFLAGS$])
m4trace:configure.ac:249: -1- AC_SUBST([AM_LDFLAGS])
m4trace:configure.ac:249: -1- AC_SUBST_TRACE([AM_LDFLAGS])
m4trace:configure.ac:249: -1- m4_pattern_allow([^AM_LDFLAGS$])
m4trace:configure.ac:250: -1- AC_SUBST([libelf_LD_LIBRARY_PATH])
m4trace:configure.ac:250: -1- AC_SUBST_TRACE([libelf_LD_LIBRARY_PATH])
m4trace:configure.ac:250: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$])
m4trace:configure.ac:252: -1- AC_CONFIG_FILES([
m4trace:configure.ac:250: -1- AC_SUBST([AM_CPPFLAGS])
m4trace:configure.ac:250: -1- AC_SUBST_TRACE([AM_CPPFLAGS])
m4trace:configure.ac:250: -1- m4_pattern_allow([^AM_CPPFLAGS$])
m4trace:configure.ac:251: -1- AC_SUBST([AM_CFLAGS])
m4trace:configure.ac:251: -1- AC_SUBST_TRACE([AM_CFLAGS])
m4trace:configure.ac:251: -1- m4_pattern_allow([^AM_CFLAGS$])
m4trace:configure.ac:252: -1- AC_SUBST([AM_LDFLAGS])
m4trace:configure.ac:252: -1- AC_SUBST_TRACE([AM_LDFLAGS])
m4trace:configure.ac:252: -1- m4_pattern_allow([^AM_LDFLAGS$])
m4trace:configure.ac:253: -1- AC_SUBST([libelf_LD_LIBRARY_PATH])
m4trace:configure.ac:253: -1- AC_SUBST_TRACE([libelf_LD_LIBRARY_PATH])
m4trace:configure.ac:253: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$])
m4trace:configure.ac:255: -1- AC_CONFIG_FILES([
Makefile
client/Makefile
sysdeps/Makefile
@ -683,30 +685,30 @@ m4trace:configure.ac:252: -1- AC_CONFIG_FILES([
sysdeps/linux-gnu/ppc/Makefile
sysdeps/linux-gnu/arm/Makefile
])
m4trace:configure.ac:261: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs])
m4trace:configure.ac:261: -1- AC_SUBST_TRACE([LIB@&t@OBJS])
m4trace:configure.ac:261: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:261: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs])
m4trace:configure.ac:261: -1- AC_SUBST_TRACE([LTLIBOBJS])
m4trace:configure.ac:261: -1- m4_pattern_allow([^LTLIBOBJS$])
m4trace:configure.ac:261: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])
m4trace:configure.ac:261: -1- AC_SUBST([am__EXEEXT_TRUE])
m4trace:configure.ac:261: -1- AC_SUBST_TRACE([am__EXEEXT_TRUE])
m4trace:configure.ac:261: -1- m4_pattern_allow([^am__EXEEXT_TRUE$])
m4trace:configure.ac:261: -1- AC_SUBST([am__EXEEXT_FALSE])
m4trace:configure.ac:261: -1- AC_SUBST_TRACE([am__EXEEXT_FALSE])
m4trace:configure.ac:261: -1- m4_pattern_allow([^am__EXEEXT_FALSE$])
m4trace:configure.ac:261: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE])
m4trace:configure.ac:261: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE])
m4trace:configure.ac:261: -1- AC_SUBST_TRACE([top_builddir])
m4trace:configure.ac:261: -1- AC_SUBST_TRACE([top_build_prefix])
m4trace:configure.ac:261: -1- AC_SUBST_TRACE([srcdir])
m4trace:configure.ac:261: -1- AC_SUBST_TRACE([abs_srcdir])
m4trace:configure.ac:261: -1- AC_SUBST_TRACE([top_srcdir])
m4trace:configure.ac:261: -1- AC_SUBST_TRACE([abs_top_srcdir])
m4trace:configure.ac:261: -1- AC_SUBST_TRACE([builddir])
m4trace:configure.ac:261: -1- AC_SUBST_TRACE([abs_builddir])
m4trace:configure.ac:261: -1- AC_SUBST_TRACE([abs_top_builddir])
m4trace:configure.ac:261: -1- AC_SUBST_TRACE([INSTALL])
m4trace:configure.ac:261: -1- AC_SUBST_TRACE([MKDIR_P])
m4trace:configure.ac:261: -1- AC_REQUIRE_AUX_FILE([ltmain.sh])
m4trace:configure.ac:264: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs])
m4trace:configure.ac:264: -1- AC_SUBST_TRACE([LIB@&t@OBJS])
m4trace:configure.ac:264: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:264: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs])
m4trace:configure.ac:264: -1- AC_SUBST_TRACE([LTLIBOBJS])
m4trace:configure.ac:264: -1- m4_pattern_allow([^LTLIBOBJS$])
m4trace:configure.ac:264: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])
m4trace:configure.ac:264: -1- AC_SUBST([am__EXEEXT_TRUE])
m4trace:configure.ac:264: -1- AC_SUBST_TRACE([am__EXEEXT_TRUE])
m4trace:configure.ac:264: -1- m4_pattern_allow([^am__EXEEXT_TRUE$])
m4trace:configure.ac:264: -1- AC_SUBST([am__EXEEXT_FALSE])
m4trace:configure.ac:264: -1- AC_SUBST_TRACE([am__EXEEXT_FALSE])
m4trace:configure.ac:264: -1- m4_pattern_allow([^am__EXEEXT_FALSE$])
m4trace:configure.ac:264: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE])
m4trace:configure.ac:264: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE])
m4trace:configure.ac:264: -1- AC_SUBST_TRACE([top_builddir])
m4trace:configure.ac:264: -1- AC_SUBST_TRACE([top_build_prefix])
m4trace:configure.ac:264: -1- AC_SUBST_TRACE([srcdir])
m4trace:configure.ac:264: -1- AC_SUBST_TRACE([abs_srcdir])
m4trace:configure.ac:264: -1- AC_SUBST_TRACE([top_srcdir])
m4trace:configure.ac:264: -1- AC_SUBST_TRACE([abs_top_srcdir])
m4trace:configure.ac:264: -1- AC_SUBST_TRACE([builddir])
m4trace:configure.ac:264: -1- AC_SUBST_TRACE([abs_builddir])
m4trace:configure.ac:264: -1- AC_SUBST_TRACE([abs_top_builddir])
m4trace:configure.ac:264: -1- AC_SUBST_TRACE([INSTALL])
m4trace:configure.ac:264: -1- AC_SUBST_TRACE([MKDIR_P])
m4trace:configure.ac:264: -1- AC_REQUIRE_AUX_FILE([ltmain.sh])

View File

@ -84,6 +84,10 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task));
* function returns. */
arch_addr_t get_return_addr(struct task *task);
#if HW_BREAKPOINTS > 0
/* returns true if the hw breakpoint is pendig */
int get_hw_bp_state(struct task *task, unsigned int n);
/* set instruction hw breakpoint */
int set_hw_bp(struct task *task, unsigned int n, arch_addr_t addr);
@ -92,6 +96,7 @@ int reset_hw_bp(struct task *task, unsigned int n);
/* remove all instruction hw breakpoints */
int reset_all_hw_bp(struct task *task);
#endif
/* save the process context (state, registers, stack pointer) */
int fetch_context(struct task *task);

View File

@ -40,5 +40,8 @@ unsigned long backtrace_get_ip(struct task *task);
/* step to next backtrace given task */
int backtrace_step(struct task *task);
/* get backtrace location type of given task */
int backtrace_location_type(struct task *task);
#endif

View File

@ -34,6 +34,7 @@
#include "debug.h"
#include "library.h"
#include "mtelf.h"
#include "options.h"
#include "report.h"
#include "task.h"
#include "trace.h"
@ -98,24 +99,12 @@ struct breakpoint *breakpoint_find(struct task *task, arch_addr_t addr)
}
#if HW_BREAKPOINTS > 0
#if HW_BREAKPOINTS > 1
static int find_hw_bp_slot(struct task *leader)
{
int i;
for(i = HW_BP_SCRATCH_SLOT + 1; i < HW_BREAKPOINTS; ++i)
if ((leader->hw_bp_mask & (1 << i)) == 0)
return i;
return -1;
}
#endif
static void enable_hw_bp(struct task *task, struct breakpoint *bp)
{
unsigned int slot = bp->hw_bp_slot;
if (bp->hw_bp_slot != HW_BP_SCRATCH_SLOT)
assert(task->hw_bp[slot] == NULL);
assert(bp->type != BP_SW);
assert(bp->type < BP_HW || task->hw_bp[slot] == NULL);
task->hw_bp[slot] = bp;
@ -123,29 +112,6 @@ static void enable_hw_bp(struct task *task, struct breakpoint *bp)
fatal("set_hw_bp");
}
void breakpoint_hw_clone(struct task *task)
{
unsigned int i;
struct task *leader = task->leader;
if (leader == task)
return;
for(i = HW_BP_SCRATCH_SLOT + 1; i < HW_BREAKPOINTS; ++i) {
if ((leader->hw_bp_mask & (1 << i)) == 0) {
assert(task->hw_bp[i] == NULL);
continue;
}
if (leader->hw_bp[i]) {
assert(leader->hw_bp[i]->enabled);
assert(leader->hw_bp[i]->hw_bp_slot == i);
enable_hw_bp(task, leader->hw_bp[i]);
}
}
}
static void disable_hw_bp(struct task *task, struct breakpoint *bp)
{
unsigned int slot = bp->hw_bp_slot;
@ -155,33 +121,175 @@ static void disable_hw_bp(struct task *task, struct breakpoint *bp)
assert(task->hw_bp[slot] == bp);
task->hw_bp[slot] = NULL;
if (reset_hw_bp(task, slot) == -1)
fatal("reset_hw_bp");
task->hw_bp[slot] = NULL;
}
#if HW_BREAKPOINTS > 1
static void enable_hw_bp_cb(struct task *task, void *data)
{
enable_hw_bp(task, data);
}
static void disable_hw_bp_cb(struct task *task, void *data)
{
disable_hw_bp(task, data);
}
static void hw2sw_bp(struct task *leader, struct breakpoint *bp)
{
each_task(leader, disable_hw_bp_cb, bp);
bp->hw = 0;
enable_sw_breakpoint(leader, bp);
}
static int hw_bp_sort(const void *a, const void *b)
{
const struct breakpoint *p = *(const struct breakpoint **)a;
const struct breakpoint *q = *(const struct breakpoint **)b;
if (p->type != q->type)
return (p->type == BP_HW) ? -1 : 1;
return (int)(q->hwcnt - p->hwcnt);
}
void reorder_hw_bp(struct task *task)
{
struct task *leader = task->leader;
struct list_head *it;
struct breakpoint *bp_list[leader->hw_bp_num + 1];
struct breakpoint *bp;
struct breakpoint **p;
unsigned long hw_bp_set = 0;
unsigned int i;
unsigned int n;
if (!leader->hw_bp_num)
return;
n = 0;
list_for_each(it, &leader->hw_bp_list) {
bp = container_of(it, struct breakpoint, link_list);
if (bp->enabled) {
assert(n < leader->hw_bp_num);
bp_list[n++] = bp;
}
}
qsort(bp_list, n, sizeof(*bp_list), hw_bp_sort);
for(i = 0; i < n; ++i) {
bp_list[i]->hwcnt = (i < HW_BREAKPOINTS - 1) ? BP_REORDER_THRESHOLD >> (i + 4) : 0;
}
if (n > HW_BREAKPOINTS - 1)
n = HW_BREAKPOINTS - 1;
p = bp_list;
for(i = 0; i < n; ++i) {
if (bp_list[i]->hw) {
assert(bp_list[i]->hw_bp_slot != HW_BP_SCRATCH_SLOT);
assert(bp_list[i]->hw_bp_slot < HW_BREAKPOINTS);
assert((hw_bp_set & 1 << bp_list[i]->hw_bp_slot) == 0);
hw_bp_set |= 1 << bp_list[i]->hw_bp_slot;
}
else
*p++ = bp_list[i];
}
*p = NULL;
i = HW_BP_SCRATCH_SLOT + 1;
for(p = bp_list; (bp = *p); ++p) {
while(hw_bp_set & (1 << i))
++i;
stop_threads(leader);
disable_sw_breakpoint(leader, bp);
if (leader->hw_bp[i])
hw2sw_bp(leader, leader->hw_bp[i]);
bp->hw_bp_slot = i;
bp->hw = 1;
each_task(leader, enable_hw_bp_cb, bp);
++i;
}
}
static int insert_hw_bp_slot(struct task *task, struct breakpoint *bp)
{
struct task *leader = task->leader;
unsigned int i;
for(i = HW_BP_SCRATCH_SLOT + 1; i < HW_BREAKPOINTS; ++i) {
if (!leader->hw_bp[i])
break;
if (bp->type == BP_HW && leader->hw_bp[i]->type == BP_AUTO) {
stop_threads(leader);
hw2sw_bp(leader, leader->hw_bp[i]);
break;
}
}
if (i >= HW_BREAKPOINTS)
return 1;
bp->hwcnt = 0;
bp->enabled = 1;
bp->hw_bp_slot = i;
bp->hw = 1;
each_task(leader, enable_hw_bp_cb, bp);
return 0;
}
void breakpoint_hw_clone(struct task *task)
{
unsigned int i;
struct task *leader = task->leader;
if (leader == task)
return;
for(i = HW_BP_SCRATCH_SLOT + 1; i < HW_BREAKPOINTS; ++i) {
if (!leader->hw_bp[i]) {
assert(task->hw_bp[i] == NULL);
continue;
}
assert(leader->hw_bp[i]->enabled);
assert(leader->hw_bp[i]->hw_bp_slot == i);
enable_hw_bp(task, leader->hw_bp[i]);
}
}
void breakpoint_hw_destroy(struct task *task)
{
unsigned int i;
for(i = 0; i < HW_BREAKPOINTS; ++i) {
if (task->hw_bp[i]) {
assert(task->hw_bp[i]->hw_bp_slot == i);
task->hw_bp[i] = NULL;
}
}
for(i = 0; i < HW_BREAKPOINTS; ++i)
task->hw_bp[i] = NULL;
reset_all_hw_bp(task);
}
#endif
void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp)
{
if (bp->deleted)
return;
if (bp->type == SW_BP)
if (bp->type != BP_HW_SCRATCH)
return;
assert(bp->hw_bp_slot == HW_BP_SCRATCH_SLOT);
@ -190,17 +298,12 @@ void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp)
enable_hw_bp(task, bp);
}
static void enable_hw_bp_cb(struct task *task, void *data)
{
enable_hw_bp(task, data);
}
void disable_scratch_hw_bp(struct task *task, struct breakpoint *bp)
{
if (bp->deleted)
return;
if (bp->type == SW_BP)
if (bp->type != BP_HW_SCRATCH)
return;
assert(bp->hw_bp_slot == HW_BP_SCRATCH_SLOT);
@ -208,11 +311,6 @@ void disable_scratch_hw_bp(struct task *task, struct breakpoint *bp)
disable_hw_bp(task, bp);
}
static void disable_hw_bp_cb(struct task *task, void *data)
{
disable_hw_bp(task, data);
}
static void remove_hw_scratch_bp_cb(struct task *task, void *data)
{
if (task->hw_bp[HW_BP_SCRATCH_SLOT] == data) {
@ -239,29 +337,30 @@ struct breakpoint *breakpoint_new_ext(struct task *task, arch_addr_t addr, struc
bp->deleted = 0;
bp->ext = ext;
bp->refcnt = 1;
bp->count = 0;
#if HW_BREAKPOINTS > 1
bp->hwcnt = 0;
#endif
bp->type = bp_type;
INIT_LIST_HEAD(&bp->link_list);
switch(bp_type) {
case HW_BP_SCRATCH:
case BP_HW_SCRATCH:
#if HW_BREAKPOINTS > 0
bp->type = HW_BP_SCRATCH;
bp->hw_bp_slot = HW_BP_SCRATCH_SLOT;
bp->hw = 1;
break;
#endif
case HW_BP:
case BP_AUTO:
case BP_HW:
#if HW_BREAKPOINTS > 1
{
int slot = find_hw_bp_slot(leader);
if (slot > 0) {
leader->hw_bp_mask |= (1 << slot);
bp->type = HW_BP;
bp->hw_bp_slot = slot;
break;
}
}
list_add_tail(&bp->link_list, &leader->hw_bp_list);
leader->hw_bp_num++;
#endif
case SW_BP:
bp->type = SW_BP;
case BP_SW:
memset(bp->orig_value, 0, sizeof(bp->orig_value));
bp->hw = 0;
}
if (dict_add(leader->breakpoints, (unsigned long)addr, bp) < 0) {
@ -289,17 +388,21 @@ void breakpoint_enable(struct task *task, struct breakpoint *bp)
debug(DEBUG_PROCESS, "pid=%d, addr=%#lx", task->pid, bp->addr);
if (!bp->enabled) {
stop_threads(task);
#if HW_BREAKPOINTS > 0
if (bp->type != SW_BP) {
if (bp->type == HW_BP)
each_task(task->leader, enable_hw_bp_cb, bp);
if (bp->type == BP_HW_SCRATCH) {
bp->enabled = 1;
return;
}
#if HW_BREAKPOINTS > 1
if (bp->type >= BP_HW) {
if (!insert_hw_bp_slot(task, bp))
return;
}
else
#endif
{
enable_sw_breakpoint(task, bp);
}
#endif
stop_threads(task);
bp->hw = 0;
enable_sw_breakpoint(task, bp);
bp->enabled = 1;
}
}
@ -312,19 +415,29 @@ void breakpoint_disable(struct task *task, struct breakpoint *bp)
debug(DEBUG_PROCESS, "pid=%d, addr=%#lx", task->pid, bp->addr);
if (bp->enabled) {
stop_threads(task);
#if HW_BREAKPOINTS > 0
if (bp->type != SW_BP) {
if (bp->type == HW_BP)
each_task(task->leader, disable_hw_bp_cb, bp);
if (bp->hw) {
struct task *leader = task->leader;
#if HW_BREAKPOINTS > 1
if (bp->type != BP_HW_SCRATCH) {
assert(bp->hw_bp_slot != HW_BP_SCRATCH_SLOT);
each_task(leader, disable_hw_bp_cb, bp);
bp->hw = 0;
}
else
each_task(task->leader, remove_hw_scratch_bp_cb, bp);
}
else
#endif
{
disable_sw_breakpoint(task, bp);
{
assert(bp->hw_bp_slot == HW_BP_SCRATCH_SLOT);
each_task(leader, remove_hw_scratch_bp_cb, bp);
}
bp->enabled = 0;
return;
}
#endif
stop_threads(task);
disable_sw_breakpoint(task, bp);
bp->enabled = 0;
}
}
@ -359,24 +472,29 @@ void breakpoint_delete(struct task *task, struct breakpoint *bp)
breakpoint_disable(task, bp);
#if HW_BREAKPOINTS > 0
if (bp->type != SW_BP) {
unsigned int slot = bp->hw_bp_slot;
#if HW_BREAKPOINTS > 1
if (bp->type >= BP_HW) {
list_del(&bp->link_list);
if (bp->type == HW_BP) {
assert(slot != HW_BP_SCRATCH_SLOT);
leader->hw_bp_mask &= ~(1 << slot);
}
else
assert(slot == HW_BP_SCRATCH_SLOT);
leader->hw_bp_num--;
}
#endif
bp->deleted = 1;
dict_remove_entry(leader->breakpoints, (unsigned long)bp->addr);
breakpoint_unref(bp);
if (options.verbose > 1 && bp->libsym) {
fprintf(stderr,
"delete %s breakpoint %s:%s [%#lx] count=%u\n",
bp->type == BP_SW ? "sw" : "hw",
bp->libsym->libref->filename,
bp->libsym->func->demangled_name,
bp->addr,
bp->count);
}
bp->deleted = 1;
bp->libsym = NULL;
breakpoint_put(bp);
}
static int enable_nonlocked_bp_cb(unsigned long key, const void *value, void *data)
@ -419,6 +537,7 @@ void breakpoint_disable_all_nonlocked(struct task *leader)
if (leader->breakpoints)
dict_apply_to_all(leader->breakpoints, disable_nonlocked_bp_cb, leader);
leader->attached = 1;
}
static int enable_bp_cb(unsigned long key, const void *value, void *data)
@ -459,11 +578,15 @@ void breakpoint_disable_all(struct task *leader)
if (leader->breakpoints)
dict_apply_to_all(leader->breakpoints, disable_bp_cb, leader);
leader->attached = 1;
}
static int destroy_breakpoint_cb(unsigned long key, const void *value, void *data)
{
free((struct breakpoint *)value);
struct breakpoint *bp = (struct breakpoint *)value;
struct task *leader = (struct task *)data;
breakpoint_delete(leader, bp);
return 0;
}
@ -471,6 +594,7 @@ void breakpoint_clear_all(struct task *leader)
{
if (leader->breakpoints) {
dict_apply_to_all(leader->breakpoints, &destroy_breakpoint_cb, leader);
assert(leader->hw_bp_num == 0);
dict_clear(leader->breakpoints);
leader->breakpoints = NULL;
}
@ -487,49 +611,66 @@ static int clone_single_cb(unsigned long key, const void *value, void *data)
{
struct breakpoint *bp = (struct breakpoint *)value;
struct task *new_task = (struct task *)data;
struct library_symbol *libsym = bp->libsym ? find_symbol(new_task, bp->libsym->addr) : NULL;
size_t ext = bp->ext;
if (bp->deleted)
return 0;
#if HW_BREAKPOINTS > 0
if (bp->type == BP_HW_SCRATCH) {
assert(bp->hw_bp_slot == HW_BP_SCRATCH_SLOT);
if (bp->hw)
return 0;
}
#endif
struct breakpoint *new_bp = malloc(sizeof(*new_bp) + ext);
if (!new_bp)
goto fail1;
new_bp->libsym = libsym;
new_bp->libsym = bp->libsym;
new_bp->addr = bp->addr;
new_bp->on_hit = bp->on_hit;
new_bp->enabled = bp->enabled;
new_bp->locked = bp->locked;
new_bp->hw = bp->hw;
new_bp->type = bp->type;
new_bp->ext = ext;
new_bp->refcnt = 1;
new_bp->deleted = 0;
new_bp->count = 0;
#if HW_BREAKPOINTS > 0
if (new_bp->type != SW_BP) {
#if HW_BREAKPOINTS > 1
new_bp->hwcnt = 0;
if (new_bp->type >= BP_HW) {
list_add_tail(&new_bp->link_list, &new_task->hw_bp_list);
new_task->hw_bp_num++;
}
else
INIT_LIST_HEAD(&new_bp->link_list);
if (new_bp->hw) {
new_bp->hw_bp_slot = bp->hw_bp_slot;
if (bp->type == HW_BP) {
assert(new_bp->hw_bp_slot != HW_BP_SCRATCH_SLOT);
assert(new_bp->hw_bp_slot != HW_BP_SCRATCH_SLOT);
new_task->hw_bp[new_bp->hw_bp_slot] = new_bp;
new_task->hw_bp[new_bp->hw_bp_slot] = new_bp;
if (new_bp->enabled) {
if (set_hw_bp(new_task, new_bp->hw_bp_slot, new_bp->addr) == -1)
fatal("set_hw_bp");
}
if (new_bp->enabled) {
if (set_hw_bp(new_task, new_bp->hw_bp_slot, new_bp->addr) == -1)
fatal("set_hw_bp");
}
else
assert(new_bp->hw_bp_slot == HW_BP_SCRATCH_SLOT);
}
else
#endif
memcpy(new_bp->orig_value, bp->orig_value, sizeof(bp->orig_value));
memcpy(new_bp->orig_value, bp->orig_value, sizeof(bp->orig_value));
if (ext)
memcpy((void *)new_bp + ext, (void *)bp + ext, ext);
if (dict_add(new_task->leader->breakpoints, (unsigned long)new_bp->addr, new_bp) < 0) {
if (dict_add(new_task->breakpoints, (unsigned long)new_bp->addr, new_bp) < 0) {
fprintf(stderr, "couldn't enter breakpoint %lx to dictionary\n", new_bp->addr);
goto fail2;
}
@ -546,3 +687,23 @@ int breakpoint_clone_all(struct task *clone, struct task *leader)
return dict_apply_to_all(leader->breakpoints, &clone_single_cb, clone);
}
struct breakpoint *breakpoint_get(struct breakpoint *bp)
{
if (bp)
++bp->refcnt;
return bp;
}
int breakpoint_put(struct breakpoint *bp)
{
if (bp) {
assert(bp->refcnt != 0);
if (--bp->refcnt)
return 0;
free(bp);
}
return 1;
}

View File

@ -26,34 +26,42 @@
#include <stdlib.h>
#include "arch.h"
#include "list.h"
#include "sysdep.h"
#include "forward.h"
#define SW_BP 0
#define HW_BP 1
#define HW_BP_SCRATCH 2
#define BP_REORDER_THRESHOLD 1024U
#define BP_SW 0
#define BP_HW_SCRATCH 1
#define BP_HW 2
#define BP_AUTO 3
struct breakpoint {
arch_addr_t addr;
#if HW_BREAKPOINTS > 1
unsigned int hwcnt;
#endif
unsigned int refcnt;
unsigned int count;
unsigned int ext:8;
unsigned int type:2;
unsigned int enabled:1;
unsigned int locked:1;
unsigned int deleted:1;
unsigned int type:2;
unsigned int ext:8;
unsigned int refcnt;
int (*on_hit)(struct task *task, struct breakpoint *bp);
struct library_symbol *libsym;
unsigned int hw:1;
union {
unsigned char orig_value[BREAKPOINT_LENGTH];
#if HW_BREAKPOINTS > 0
unsigned int hw_bp_slot;
#endif
};
int (*on_hit)(struct task *task, struct breakpoint *bp);
arch_addr_t addr;
struct library_symbol *libsym;
struct list_head link_list;
};
/* setup the basic breakpoint support for a given leader */
@ -92,9 +100,6 @@ struct breakpoint *breakpoint_find(struct task *leader, arch_addr_t addr);
#if HW_BREAKPOINTS > 0
void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp);
void disable_scratch_hw_bp(struct task *task, struct breakpoint *bp);
void breakpoint_hw_clone(struct task *task);
void breakpoint_hw_destroy(struct task *task);
#else
static inline void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp)
{
@ -103,7 +108,14 @@ static inline void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp
static inline void disable_scratch_hw_bp(struct task *task, struct breakpoint *bp)
{
}
#endif
#if HW_BREAKPOINTS > 1
void reorder_hw_bp(struct task *task);
void breakpoint_hw_clone(struct task *task);
void breakpoint_hw_destroy(struct task *task);
#else
static inline void breakpoint_hw_clone(struct task *task)
{
}
@ -113,22 +125,9 @@ static inline void breakpoint_hw_destroy(struct task *task)
}
#endif
static inline struct breakpoint *breakpoint_ref(struct breakpoint *bp)
{
if (bp)
++bp->refcnt;
return bp;
}
struct breakpoint *breakpoint_get(struct breakpoint *bp);
static inline int breakpoint_unref(struct breakpoint *bp)
{
if (bp) {
if (--bp->refcnt)
return 0;
free(bp);
}
return 1;
}
int breakpoint_put(struct breakpoint *bp);
#endif

View File

@ -25,10 +25,13 @@
#include <execinfo.h>
#include <link.h>
#include <stdio.h>
#include <string.h>
#include "binfile.h"
#include "process.h"
static LIST_HEAD(list_of_binfiles);
/* These variables are used to pass information between
translate_addresses and find_address_in_section. */
struct sym_info {
@ -50,7 +53,7 @@ static long slurp_symtab(struct bin_file *binfile)
return 0;
storage = bfd_get_symtab_upper_bound(binfile->abfd);
if (storage == 0) {
if (!storage) {
storage = bfd_get_dynamic_symtab_upper_bound(binfile->abfd);
dynamic = TRUE;
}
@ -98,19 +101,34 @@ static void find_address_in_section(bfd *abfd, asection *section, void *data __a
psi->found = bfd_find_nearest_line(abfd, section, psi->syms, psi->pc - vma, &psi->filename, &psi->functionname, &psi->line);
}
char *bin_file_lookup(struct bin_file *binfile, bfd_vma addr, unsigned long off)
struct rb_sym *bin_file_lookup(struct bin_file *binfile, bfd_vma addr, unsigned long off, const char *filename)
{
struct sym_info si = { 0 };
char *ret_buf = NULL;
char *sym_buf = NULL;
struct rb_root *root = &binfile->sym_table;
struct rb_node **new = &(root->rb_node), *parent = NULL;
struct rb_sym *this;
if (!binfile)
return NULL;
if (!binfile->abfd)
return NULL;
/* Figure out where to put new node */
while (*new) {
this = container_of(*new, struct rb_sym, node);
if (!binfile->syms)
return NULL;
parent = *new;
if (addr < this->addr)
new = &((*new)->rb_left);
else
if (addr > this->addr)
new = &((*new)->rb_right);
else {
bin_file_sym_get(this);
return this;
}
}
si.pc = (binfile->abfd->flags & EXEC_P) ? addr : addr - off;
si.syms = binfile->syms;
@ -120,8 +138,8 @@ char *bin_file_lookup(struct bin_file *binfile, bfd_vma addr, unsigned long off)
bfd_map_over_sections(binfile->abfd, find_address_in_section, &si);
if (!si.found) {
if (asprintf(&ret_buf, "%s", bfd_get_filename(binfile->abfd)) == -1)
ret_buf = NULL;
if (asprintf(&sym_buf, "%s", filename) == -1)
sym_buf = NULL;
} else {
const char *name;
@ -141,16 +159,16 @@ char *bin_file_lookup(struct bin_file *binfile, bfd_vma addr, unsigned long off)
name = alloc;
}
if (ret_buf)
free(ret_buf);
if (sym_buf)
free(sym_buf);
if (si.line) {
if (asprintf(&ret_buf, "%s:%u %s", si.filename ? si.filename : bfd_get_filename(binfile->abfd), si.line, name) == -1)
ret_buf = NULL;
if (asprintf(&sym_buf, "%s:%u %s", si.filename ? si.filename : filename, si.line, name) == -1)
sym_buf = NULL;
}
else {
if (asprintf(&ret_buf, "%s %s", si.filename ? si.filename : bfd_get_filename(binfile->abfd), name) == -1)
ret_buf = NULL;
if (asprintf(&sym_buf, "%s %s", si.filename ? si.filename : filename, name) == -1)
sym_buf = NULL;
}
if (alloc)
@ -160,72 +178,119 @@ char *bin_file_lookup(struct bin_file *binfile, bfd_vma addr, unsigned long off)
} while (si.found);
}
return ret_buf;
this = malloc(sizeof(*this));
if (!this)
return NULL;
this->addr = addr;
this->sym = sym_buf;
this->refcnt = 1;
this->binfile = binfile;
++binfile->refcnt;
/* Add new node and rebalance tree. */
rb_link_node(&this->node, parent, new);
rb_insert_color(&this->node, root);
return this;
}
struct bin_file *bin_file_new(const char *filename)
struct bin_file *bin_file_open(const char *filename)
{
bfd *abfd;
char **matching;
struct bin_file *binfile;
struct list_head *it;
if (!filename)
return NULL;
list_for_each(it, &list_of_binfiles) {
binfile = container_of(it, struct bin_file, list);
if (!strcmp(filename, binfile->filename)) {
bin_file_get(binfile);
return binfile;
}
}
binfile = malloc(sizeof(struct bin_file));
if (!binfile)
return NULL;
abfd = bfd_openr(filename, NULL);
if (!abfd)
binfile->filename = strdup(filename);
binfile->refcnt = 1;
binfile->sym_table = RB_ROOT;
binfile->abfd = bfd_openr(binfile->filename, NULL);
if (!binfile->abfd)
goto error;
/* Decompress sections. */
// abfd->flags |= BFD_DECOMPRESS;
if (bfd_check_format(abfd, bfd_archive))
if (bfd_check_format(binfile->abfd, bfd_archive))
goto error;
if (!bfd_check_format_matches(abfd, bfd_object, &matching))
if (!bfd_check_format_matches(binfile->abfd, bfd_object, &matching))
goto error;
binfile->abfd = abfd;
if (slurp_symtab(binfile) <= 0)
goto error;
binfile->refcnt = 1;
list_add_tail(&binfile->list, &list_of_binfiles);
return binfile;
error:
if (abfd)
bfd_close(abfd);
if (binfile->abfd)
bfd_close(binfile->abfd);
free(binfile->filename);
free(binfile);
return NULL;
}
struct bin_file *bin_file_clone(struct bin_file *binfile)
void bin_file_get(struct bin_file *binfile)
{
if (!binfile)
return NULL;
binfile->refcnt++;
return binfile;
++binfile->refcnt;
}
void bin_file_free(struct bin_file *binfile)
void bin_file_put(struct bin_file *binfile)
{
if (!binfile)
return;
if (--binfile->refcnt > 0)
return;
if (!--binfile->refcnt) {
list_del(&binfile->list);
if (binfile->syms)
free(binfile->syms);
if (binfile->syms)
free(binfile->syms);
if (binfile->abfd)
bfd_close(binfile->abfd);
if (binfile->abfd)
bfd_close(binfile->abfd);
free(binfile->filename);
free(binfile);
}
}
void bin_file_sym_get(struct rb_sym *sym)
{
struct bin_file *binfile = sym->binfile;
++sym->refcnt;
++binfile->refcnt;
}
void bin_file_sym_put(struct rb_sym *sym)
{
struct bin_file *binfile = sym->binfile;
if (!--sym->refcnt) {
free(sym->sym);
if (!binfile)
return;
rb_erase(&sym->node, &binfile->sym_table);
}
bin_file_put(binfile);
}

View File

@ -24,16 +24,31 @@
#define _INC_CLIENT_BINFILE_H
#include "bfdinc.h"
#include "list.h"
#include "rbtree.h"
struct bin_file {
bfd *abfd;
asymbol **syms;
unsigned int refcnt;
struct rb_sym {
struct rb_node node;
bfd_vma addr;
char *sym;
struct bin_file *binfile;
unsigned long refcnt;
};
struct bin_file *bin_file_new(const char *filename);
struct bin_file *bin_file_clone(struct bin_file *binfile);
void bin_file_free(struct bin_file *binfile);
char *bin_file_lookup(struct bin_file *binfile, bfd_vma addr, unsigned long off);
struct bin_file {
struct list_head list;
bfd *abfd;
asymbol **syms;
struct rb_root sym_table;
unsigned long refcnt;
char *filename;
};
struct bin_file *bin_file_open(const char *filename);
void bin_file_put(struct bin_file *binfile);
void bin_file_get(struct bin_file *binfile);
struct rb_sym *bin_file_lookup(struct bin_file *binfile, bfd_vma addr, unsigned long off, const char *filename);
void bin_file_sym_get(struct rb_sym *sym);
void bin_file_sym_put(struct rb_sym *sym);
#endif

View File

@ -306,6 +306,7 @@ static int socket_read_msg(struct mt_msg *mt_msg, void **payload, unsigned int *
else
*swap_endian = 0;
if (mt_msg->payload_len) {
*payload = malloc(mt_msg->payload_len);
@ -333,8 +334,10 @@ static unsigned int attached_payload(void *payload)
void client_close(void)
{
if (client_fd != -1) {
ioevent_del_input(client_fd);
shutdown(client_fd, SHUT_RDWR);
if (thread) {
ioevent_del_input(client_fd);
shutdown(client_fd, SHUT_RDWR);
}
close(client_fd);
client_fd = -1;
}
@ -343,11 +346,29 @@ void client_close(void)
static void client_broken(void)
{
if (client_fd != -1) {
fprintf(stderr, "connection lost\n");
if (!options.logfile)
fprintf(stderr, "connection lost\n");
client_close();
}
}
static void client_add_process(struct process *process)
{
if (!first_pid)
first_pid = process->pid;
process_rb_insert(&pid_table, process);
}
static void client_remove_process(struct process *process)
{
process = pid_rb_delete(&pid_table, process->pid);
if (process)
free(process);
}
static int client_func(void)
{
struct mt_msg mt_msg;
@ -365,7 +386,10 @@ static int client_func(void)
switch(mt_msg.operation) {
case MT_DISCONNECT:
sock_send_msg(client_fd, MT_DISCONNECT, 0, 0, NULL, 0);
if (!options.trace && !options.logfile) {
printf("server disconnected\n");
fflush(stdout);
}
client_close();
break;
case MT_INFO:
@ -433,7 +457,8 @@ static int client_func(void)
process_exit(process);
break;
case MT_NOFOLLOW:
process_delete(process);
process_reset(process);
client_remove_process(process);
break;
case MT_SCAN:
process_scan(process, payload, mt_msg.payload_len);
@ -470,6 +495,9 @@ void client_show_info(void)
int client_wait_op(enum mt_operation op)
{
if (options.logfile)
return -1;
for(;;) {
if (client_fd == -1)
return -1;
@ -483,22 +511,6 @@ int client_wait_op(enum mt_operation op)
return 0;
}
static int client_release_process(struct rb_node *node, void *user)
{
struct rb_process *data = (struct rb_process *)node;
process_delete(data->process);
free(data);
return 0;
}
void client_finalize()
{
client_close();
rb_iterate(&pid_table, client_release_process, NULL);
}
static int client_iterate_process(struct rb_node *node, void *user)
{
struct rb_process *data = (struct rb_process *)node;
@ -529,23 +541,6 @@ struct process *client_first_process(void)
return client_find_process(first_pid);
}
void client_add_process(struct process *process)
{
if (!first_pid)
first_pid = process->pid;
process_rb_insert(&pid_table, process);
}
void client_remove_process(struct process *process)
{
process = pid_rb_delete(&pid_table, process->pid);
if (process)
free(process);
}
static int client_init(int do_trace)
{
struct opt_F_t *p;
@ -602,14 +597,17 @@ int client_start(void)
if (client_init(0) < 0)
return -1;
client_fd = connect_to(options.client, options.port);
client_fd = connect_to(options.address, options.port);
if (client_fd == -1) {
fprintf(stderr, "could not connect: %s:%s\n", options.client, options.port);
fprintf(stderr, "could not connect: %s\n", options.address);
return -1;
}
client_wait_op(MT_INFO);
if (client_wait_op(MT_INFO) == -1) {
fprintf(stderr, "could not talk to server\n");
return -1;
}
if (mt_info.version != MEMTRACE_SI_VERSION) {
fprintf(stderr,
@ -626,6 +624,8 @@ int client_start(void)
ioevent_add_input(client_fd, client_func);
if (options.interactive) {
int old_client_fd = client_fd;
signal(SIGINT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
@ -634,6 +634,13 @@ int client_start(void)
while(ioevent_watch(-1) != -1)
;
if (client_fd == -1) {
ioevent_del_input(old_client_fd);
while(ioevent_watch(-1) != -1)
;
}
readline_exit();
}
else {
@ -697,7 +704,12 @@ int client_start_pair(int handle)
int client_send_msg(struct process *process, enum mt_operation op, void *payload, unsigned int payload_len)
{
int ret = sock_send_msg(client_fd, process->val16(op), process->pid, 0, payload, payload_len);
int ret;
if (options.logfile)
return -1;
ret = sock_send_msg(client_fd, process->val16(op), process->pid, 0, payload, payload_len);
if (ret < 0)
client_broken();
@ -709,16 +721,63 @@ int client_connected(void)
if (client_fd != -1)
return 1;
printf("connection lost\n");
return 0;
}
int client_stop(void)
{
if (thread)
if (thread) {
thread_join(thread);
thread = NULL;
}
client_close();
return 0;
}
int client_logfile(void)
{
const char spin[4] = "|/-\\";
unsigned int i;
const unsigned int spindepth = 14;
thread = NULL;
if (client_init(1) < 0)
return -1;
client_fd = open(options.logfile, O_RDONLY);
if (client_fd == -1)
fatal("could not open logfile: %s", options.logfile);
printf("processing logfile `%s'... ", options.logfile);
fflush(stdout);
for(i = 0; client_fd != -1; ++i) {
if ((i & ((1 << spindepth) - 1)) == 0) {
printf("\b%c", spin[(i >> spindepth) & (ARRAY_SIZE(spin) - 1)]);
fflush(stdout);
}
client_func();
}
printf("\bdone\n");
fflush(stdout);
if (options.interactive) {
client_show_info();
signal(SIGINT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
readline_init();
while(ioevent_watch(-1) != -1)
;
readline_exit();
}
return 0;
}

View File

@ -27,13 +27,9 @@
struct process;
void client_finalize();
struct process *client_first_process(void);
struct process *client_find_process(pid_t pid);
void client_iterate_processes(int (*func)(struct process *process));
void client_add_process(struct process *process);
void client_remove_process(struct process *process);
void client_show_info(void);
int client_wait_op(enum mt_operation op);
void client_close(void);
@ -42,6 +38,7 @@ int client_connected(void);
int client_start(void);
int client_start_pair(int handle);
int client_stop(void);
int client_logfile(void);
#endif

View File

@ -56,7 +56,7 @@ struct stack {
void *addrs;
uint32_t size;
uint32_t entries;
char **syms;
struct rb_sym **syms;
enum mt_operation operation;
unsigned int ignore:1;
};
@ -78,7 +78,6 @@ struct map {
unsigned long addr;
unsigned long size;
char *filename;
char *realpath;
struct bin_file *binfile;
unsigned int ignore:1;
};
@ -284,7 +283,6 @@ static struct map *open_map(struct process *process, bfd_vma addr)
return map;
p = options.opt_b;
if (!p)
p = &opt_b_default;
@ -294,53 +292,54 @@ static struct map *open_map(struct process *process, bfd_vma addr)
while(len && (p->pathname)[len - 1] == '/')
--len;
for(fname = map->filename; *fname == '/'; ++fname)
;
fname = map->filename;
do {
if (asprintf(&realpath, "%.*s/%s", len, p->pathname, fname) == -1) {
if (asprintf(&realpath, "%.*s%s%s", len, p->pathname, *p->pathname ? "/" : "", fname) == -1) {
map->ignore = 1;
return map;
}
if (!access(realpath, R_OK)) {
map->binfile = bin_file_new(realpath);
if (map->binfile) {
map->realpath = realpath;
return map;
}
}
if (!access(realpath, R_OK))
map->binfile = bin_file_open(realpath);
free(realpath);
if (map->binfile)
return map;
fname = strchr(fname + 1, '/');
} while(fname++);
p = p->next;
} while(p);
fprintf(stderr, "file `%s' not found!\n", map->filename);
map->ignore = 1;
return map;
}
static char *resolv_address(struct process *process, bfd_vma addr)
static struct rb_sym *resolv_address(struct process *process, bfd_vma addr)
{
char *sym;
struct rb_sym *sym;
struct map *map = open_map(process, addr);
if (!map)
return NULL;
if (map->binfile) {
sym = bin_file_lookup(map->binfile, addr, map->addr);
if (sym)
return sym;
sym = bin_file_lookup(map->binfile, addr, map->addr, map->filename);
if (!sym) {
sym = malloc(sizeof(*sym));
if (!sym)
return NULL;
sym->addr = addr;
sym->sym = strdup(map->filename);
sym->refcnt = 1;
sym->binfile = NULL;
}
if (asprintf(&sym, "%s", map->filename) == -1)
return NULL;
return sym;
}
@ -368,7 +367,7 @@ static void stack_resolv(struct process *process, struct stack *stack)
struct regex_list *p;
for(p = regex_ignore_list; p; p = p->next)
if (stack->syms[i] && !regexec(&p->re, stack->syms[i], 0, NULL, 0)) {
if (stack->syms[i] && !regexec(&p->re, stack->syms[i]->sym, 0, NULL, 0)) {
stack->ignore = 1;
break;
}
@ -379,14 +378,14 @@ static void stack_resolv(struct process *process, struct stack *stack)
}
}
static void stack_unref(struct stack *stack)
static void stack_put(struct stack *stack)
{
if (--stack->refcnt == 0) {
if (stack->syms) {
unsigned int i;
for(i = 0; i < stack->entries; ++i)
free(stack->syms[i]);
bin_file_sym_put(stack->syms[i]);
free(stack->syms);
}
@ -459,8 +458,11 @@ static struct rb_stack *stack_add(struct process *process, pid_t pid, void *addr
else
if (ret > 0)
new = &((*new)->rb_right);
else
else {
assert(this->stack->operation == operation);
return this;
}
}
this = malloc(sizeof(*this));
@ -511,7 +513,7 @@ static void process_dump_stack(struct process *process, struct rb_stack *this)
return;
for(addrs = stack->addrs, i = 0; i < stack->entries; ++i) {
if (dump_printf(" [0x%lx] %s\n", process->get_ulong(addrs), stack->syms[i] ? stack->syms[i] : "?") == -1)
if (dump_printf(" [0x%lx] %s\n", process->get_ulong(addrs), stack->syms[i] ? stack->syms[i]->sym : "?") == -1)
return;
addrs += process->ptr_size;
@ -648,7 +650,7 @@ static int process_rb_insert_block(struct process *process, unsigned long addr,
return 0;
}
static struct map *_process_add_map(struct process *process, unsigned long addr, unsigned long offset, unsigned long size, const char *filename, size_t len)
static struct map *_process_add_map(struct process *process, unsigned long addr, unsigned long offset, unsigned long size, const char *filename, size_t len, struct bin_file *binfile)
{
struct map *map = malloc(sizeof(*map));
@ -656,10 +658,12 @@ static struct map *_process_add_map(struct process *process, unsigned long addr,
map->offset = offset;
map->size = size;
map->filename = malloc(len + 1);
map->realpath = NULL;
map->binfile = NULL;
map->binfile = binfile;
map->ignore = 0;
if (binfile)
bin_file_get(binfile);
safe_strncpy(map->filename, filename, len + 1);
if (list_empty(&process->map_list)) {
@ -669,7 +673,7 @@ static struct map *_process_add_map(struct process *process, unsigned long addr,
list_add_tail(&map->list, &process->map_list);
/* fixit: stack_add() can produce now false matches */
/* fixit: it is possible that stack_add() can produce false matches */
return map;
}
@ -682,18 +686,16 @@ void process_add_map(struct process *process, void *payload, uint32_t payload_le
uint64_t offset = process->val64(mt_map->offset);
uint64_t size = process->val64(mt_map->size);
_process_add_map(process, addr, offset, size, mt_map->filename, payload_len - sizeof(*mt_map));
_process_add_map(process, addr, offset, size, mt_map->filename, payload_len - sizeof(*mt_map), NULL);
}
static void _process_del_map(struct map *map)
{
bin_file_free(map->binfile);
bin_file_put(map->binfile);
list_del(&map->list);
free(map->filename);
free(map->realpath);
free(map->binfile);
free(map);
}
@ -752,7 +754,7 @@ void process_reset_allocations(struct process *process)
process->block_table = RB_ROOT;
rbtree_postorder_for_each_entry_safe(rbs, rbs_next, &process->stack_table, node) {
stack_unref(rbs->stack);
stack_put(rbs->stack);
free(rbs);
}
process->stack_table = RB_ROOT;
@ -765,7 +767,7 @@ void process_reset_allocations(struct process *process)
process->tsc = 0;
}
static void process_reset(struct process *process)
void process_reset(struct process *process)
{
struct list_head *it, *next;
@ -808,10 +810,13 @@ void process_duplicate(struct process *process, struct process *copy)
rb_iterate(&copy->block_table, process_rb_duplicate_block, process);
assert(copy->bytes_used == process->bytes_used);
assert(copy->n_allocations == process->n_allocations);
list_for_each(it, &copy->map_list) {
struct map *map = container_of(it, struct map, list);
_process_add_map(process, map->addr, map->offset, map->size, map->filename, strlen(map->filename));
_process_add_map(process, map->addr, map->offset, map->size, map->filename, strlen(map->filename), map->binfile);
}
process->total_allocations = copy->total_allocations;
@ -916,7 +921,7 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb
assert(i == process->stack_trees);
qsort(arr, process->stack_trees, sizeof(struct stack *), (void *)sortby);
qsort(arr, process->stack_trees, sizeof(struct rb_stack *), (void *)sortby);
if (file == stderr) {
unsigned long n = process->stack_trees / 2;
@ -933,7 +938,7 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb
for(i = 0; i < process->stack_trees; ++i) {
struct rb_stack *stack = arr[i];
if (!stack->stack->ignore && !skipfunc(stack)) {
if (!skipfunc(stack)) {
if (dump_printf(
"Stack (%s):\n"
" bytes used: %llu\n"
@ -1232,7 +1237,7 @@ void process_alloc(struct process *process, struct mt_msg *mt_msg, void *payload
{
struct rb_block *block = NULL;
uint32_t payload_len = mt_msg->payload_len;
unsigned long *stack_data;
void *stack_data;
unsigned long stack_size;
unsigned long ptr;
unsigned long size;
@ -1343,11 +1348,10 @@ void process_exit(struct process *process)
{
process_set_status(process, MT_PROCESS_EXIT);
if (options.client || (!options.client && !options.verbose))
fprintf(stderr, "+++ process %d exited +++\n", process->pid);
if (!options.interactive)
process_dump_sortby(process);
else
fprintf(stderr, "+++ process %d exited +++\n", process->pid);
}
void process_about_exit(struct process *process)
@ -1373,12 +1377,6 @@ void process_detach(struct process *process)
client_send_msg(process, MT_DETACH, NULL, 0);
}
void process_delete(struct process *process)
{
process_reset(process);
free(process);
}
void process_set_status(struct process *process, enum process_status status)
{
process->status = status;
@ -1457,6 +1455,9 @@ static void set_block(struct rb_block *block, void *data)
struct block_helper *bh = data;
unsigned long addr;
if (block->stack_node->stack->ignore)
return;
if ((block->flags & bh->fmask) != 0)
return;

View File

@ -78,11 +78,11 @@ struct process {
};
struct process *process_new(pid_t pid, unsigned int swap_endian, unsigned int tracing);
void process_reset(struct process *process);
void process_reset_allocations(struct process *process);
void process_reinit(struct process *process, unsigned int swap_endian, unsigned int is_64bit, unsigned int attached);
void process_set_clone(struct process *process, struct process *clone);
struct process *process_clone_of(struct process *process);
void process_delete(struct process *process);
void process_duplicate(struct process *process, struct process *copy);
void process_run(struct process *process, const char *libpath, const char *path, char **args);
void process_set_status(struct process *process, enum process_status status);

View File

@ -437,10 +437,12 @@ finish:
free(argv);
free(linedup);
if (quit)
rl_callback_handler_remove();
return;
}
static void split_search_patch(const char *str)
{
struct opt_b_t *opt_b_last = NULL;
@ -870,6 +872,7 @@ void readline_init(void)
void readline_exit(void)
{
rl_callback_handler_remove();
if (!quit)
rl_callback_handler_remove();
}

View File

@ -75,6 +75,9 @@
/* Define to 1 if you have the `mkdir' function. */
#undef HAVE_MKDIR
/* Define to 1 if you have the `process_vm_readv' function. */
#undef HAVE_PROCESS_VM_READV
/* Define to 1 if you have the <pthread.h> header file. */
#undef HAVE_PTHREAD_H

View File

@ -2,7 +2,7 @@
# Attempt to guess a canonical system name.
# Copyright 1992-2015 Free Software Foundation, Inc.
timestamp='2015-03-04'
timestamp='2015-07-03'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@ -221,7 +221,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
release='-gnu'
;;
*)
release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
;;
esac
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
@ -1049,7 +1049,7 @@ EOF
X86_64_ABI=x32
fi
fi
echo x86_64-unknown-linux-gnu${X86_64_ABI}
echo ${UNAME_MACHINE}-pc-linux-${LIBC}${X86_64_ABI}
exit ;;
xtensa*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}

View File

@ -2,7 +2,7 @@
# Configuration validation subroutine script.
# Copyright 1992-2015 Free Software Foundation, Inc.
timestamp='2015-03-08'
timestamp='2015-07-28'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@ -255,6 +255,7 @@ case $basic_machine in
| arc | arceb \
| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
| avr | avr32 \
| ba \
| be32 | be64 \
| bfin \
| c4x | c8051 | clipper \
@ -376,6 +377,7 @@ case $basic_machine in
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* | avr32-* \
| ba-* \
| be32-* | be64-* \
| bfin-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* \
@ -428,12 +430,13 @@ case $basic_machine in
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
| pyramid-* \
| riscv32-* | riscv64-* \
| rl78-* | romp-* | rs6000-* | rx-* \
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
| sparclite-* \
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
| tahoe-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tile*-* \

23
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for mtrace 0.1.
# Generated by GNU Autoconf 2.69 for mtrace 0.2.
#
# Report bugs to <stefani@seibold.net>.
#
@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='mtrace'
PACKAGE_TARNAME='mtrace'
PACKAGE_VERSION='0.1'
PACKAGE_STRING='mtrace 0.1'
PACKAGE_VERSION='0.2'
PACKAGE_STRING='mtrace 0.2'
PACKAGE_BUGREPORT='stefani@seibold.net'
PACKAGE_URL=''
@ -1326,7 +1326,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures mtrace 0.1 to adapt to many kinds of systems.
\`configure' configures mtrace 0.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1396,7 +1396,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of mtrace 0.1:";;
short | recursive ) echo "Configuration of mtrace 0.2:";;
esac
cat <<\_ACEOF
@ -1512,7 +1512,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
mtrace configure 0.1
mtrace configure 0.2
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -2118,7 +2118,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by mtrace $as_me 0.1, which was
It was created by mtrace $as_me 0.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -12000,7 +12000,7 @@ fi
# Define the identity of the package.
PACKAGE='mtrace'
VERSION='0.1'
VERSION='0.2'
cat >>confdefs.h <<_ACEOF
@ -12746,6 +12746,8 @@ else
$as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CPPFLAGS="${saved_CPPFLAGS}"
LDFLAGS="${saved_LDFLAGS}"
saved_CFLAGS="${CFLAGS}"
CFLAGS="${CFLAGS} -Wall -Werror"
@ -13206,6 +13208,7 @@ for ac_func in \
strerror \
strtol \
strtoul \
process_vm_readv \
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
@ -13799,7 +13802,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by mtrace $as_me 0.1, which was
This file was extended by mtrace $as_me 0.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -13865,7 +13868,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
mtrace config.status 0.1
mtrace config.status 0.2
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View File

@ -24,7 +24,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.65)
AC_INIT([mtrace],[0.1],[stefani@seibold.net])
AC_INIT([mtrace],[0.2],[stefani@seibold.net])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR(main.c)
AC_CONFIG_MACRO_DIR([config/m4])
@ -152,6 +152,8 @@ int main () {
AC_DEFINE([HAVE_ELF_C_READ_MMAP], [1], [we have read mmap support])
AC_MSG_RESULT([yes])],[
AC_MSG_RESULT([no])])
CPPFLAGS="${saved_CPPFLAGS}"
LDFLAGS="${saved_LDFLAGS}"
saved_CFLAGS="${CFLAGS}"
CFLAGS="${CFLAGS} -Wall -Werror"
@ -214,6 +216,7 @@ AC_CHECK_FUNCS([ \
strerror \
strtol \
strtoul \
process_vm_readv \
])

137
dwarf.c
View File

@ -470,7 +470,7 @@ static int dwarf_read_encoded_pointer(struct dwarf_addr_space *as, int local,
{
struct dwarf_addr_space *indirect_as = as;
arch_addr_t val, initial_addr = *addr;
arch_addr_t gp = as->cursor.lib->gp;
arch_addr_t gp = as->cursor.libref->gp;
int is_64bit = as->is_64bit;
void *tmp_ptr;
int ret;
@ -486,12 +486,12 @@ static int dwarf_read_encoded_pointer(struct dwarf_addr_space *as, int local,
#ifdef DEBUG
struct dwarf_cursor *c = &as->cursor;
struct library *lib = c->lib;
struct libref *libref = c->libref;
if (*addr < ARCH_ADDR_T(lib->image_addr))
fatal("invalid access mem: addr %#lx < %p", *addr, lib->image_addr);
if (*addr >= ARCH_ADDR_T(lib->image_addr + lib->load_size))
fatal("invalid access mem: addr %#lx >= %p", *addr, lib->image_addr + lib->load_size);
if (*addr < ARCH_ADDR_T(libref->image_addr))
fatal("invalid access mem: addr %#lx < %p", *addr, libref->image_addr);
if (*addr >= ARCH_ADDR_T(libref->image_addr + libref->load_size))
fatal("invalid access mem: addr %#lx >= %p", *addr, libref->image_addr + libref->load_size);
#endif
memset(&tmp, 0, sizeof(tmp));
@ -877,9 +877,9 @@ static int dwarf_extract_cfi_from_fde(struct dwarf_addr_space *as, void *addrp)
return 0;
}
static inline int lib_addr_match(struct library *lib, arch_addr_t ip)
static inline int lib_addr_match(struct libref *libref, arch_addr_t ip)
{
return ip >= lib->load_addr && ip < lib->load_addr + lib->load_size;
return ip >= libref->load_addr && ip < libref->load_addr + libref->load_size;
}
int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip)
@ -888,25 +888,28 @@ int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip)
struct task *leader;
struct list_head *it;
if (as->cursor.lib) {
if (lib_addr_match(as->cursor.lib, ip))
if (c->use_prev_instr)
ip -= 1;
if (as->cursor.libref) {
if (lib_addr_match(as->cursor.libref, ip))
return 0;
}
leader = c->task->leader;
as->cursor.lib = NULL;
as->cursor.libref = NULL;
list_for_each(it, &leader->libraries_list) {
struct library *lib = container_of(it, struct library, list);
struct libref *libref = container_of(it, struct library, list)->libref;
if (lib_addr_match(lib, ip)) {
as->cursor.lib = lib;
if (lib_addr_match(libref, ip)) {
as->cursor.libref = libref;
break;
}
}
if (!as->cursor.lib) {
if (!as->cursor.libref) {
debug(DEBUG_DWARF, "no mapping found for IP %#lx", ip);
return -DWARF_ENOINFO;
}
@ -947,21 +950,21 @@ static int dwarf_search_unwind_table(struct dwarf_addr_space *as, arch_addr_t ip
void *fde_addr;
int ret;
struct dwarf_cie_info *dci = &as->cursor.dci;
struct library *lib = as->cursor.lib;
struct libref *libref = as->cursor.libref;
e = lookup(table_data, table_len, ip - lib->load_addr - lib->seg_offset);
e = lookup(table_data, table_len, ip - libref->load_addr - libref->seg_offset);
if (!e) {
/* IP is inside this table's range, but there is no explicit unwind info. */
debug(DEBUG_DWARF, "no unwind info found for IP %#lx", ip);
return -DWARF_ENOINFO;
}
fde_addr = lib->image_addr - lib->load_offset + e->fde_offset + lib->seg_offset;
fde_addr = libref->image_addr - libref->load_offset + e->fde_offset + libref->seg_offset;
if ((ret = dwarf_extract_cfi_from_fde(as, fde_addr)) < 0)
return ret;
dci->start_ip -= ARCH_ADDR_T(lib->image_addr) - lib->load_addr;
dci->start_ip -= ARCH_ADDR_T(libref->image_addr) - libref->load_addr;
if (!as->is_64bit)
dci->start_ip &= 0xffffffff;
@ -1824,10 +1827,10 @@ static int apply_reg_state(struct dwarf_addr_space *as, struct dwarf_reg_state *
static int fetch_proc_info(struct dwarf_addr_space *as, arch_addr_t ip)
{
struct dwarf_cursor *c = &as->cursor;
struct library *lib = c->lib;
struct libref *libref = c->libref;
int ret;
ret = dwarf_search_unwind_table(as, ip, lib->table_data, lib->table_len);
ret = dwarf_search_unwind_table(as, ip, libref->table_data, libref->table_len);
if (ret < 0)
return ret;
@ -1840,13 +1843,14 @@ static int fetch_proc_info(struct dwarf_addr_space *as, arch_addr_t ip)
int dwarf_init_unwind(struct dwarf_addr_space *as, struct task *task)
{
struct dwarf_cursor *c = &as->cursor;
int ret;
c->cfa = 0;
c->ip = 0;
c->ret_addr_column = 0;
c->use_prev_instr = 0;
c->valid = 1;
c->lib = NULL;
c->libref = NULL;
c->task = task;
as->addr = 0;
@ -1854,7 +1858,11 @@ int dwarf_init_unwind(struct dwarf_addr_space *as, struct task *task)
memset(&c->dci, 0, sizeof(c->dci));
return dwarf_arch_init_unwind(as);
ret = dwarf_arch_init_unwind(as);
if (!ret)
ret = dwarf_locate_map(as, c->ip);
return ret;
}
void *dwarf_init(int is_64bit)
@ -1887,6 +1895,18 @@ void dwarf_destroy(struct dwarf_addr_space *as)
free(as);
}
#ifdef GUESS_CALLER
static arch_addr_t get32val(unsigned char *buf)
{
return *(uint32_t *)buf;
}
static arch_addr_t get64val(unsigned char *buf)
{
return *(uint64_t *)buf;
}
#endif
int dwarf_step(struct dwarf_addr_space *as)
{
int ret;
@ -1900,6 +1920,10 @@ int dwarf_step(struct dwarf_addr_space *as)
ip = c->ip;
cfa = c->cfa;
ret = dwarf_locate_map(as, ip);
if (ret < 0)
goto fail;
/* The 'ip' can point either to the previous or next instruction
depending on what type of frame we have: normal call or a place
to resume execution (e.g. after signal frame).
@ -1918,10 +1942,6 @@ int dwarf_step(struct dwarf_addr_space *as)
if (c->use_prev_instr)
--ip;
ret = dwarf_locate_map(as, ip);
if (ret < 0)
goto fail;
ret = fetch_proc_info(as, ip);
if (ret < 0)
goto fail;
@ -1936,34 +1956,57 @@ int dwarf_step(struct dwarf_addr_space *as)
if (ret < 0)
goto fail;
return 0;
ret = dwarf_locate_map(as, c->ip);
if (ret < 0)
goto fail;
return 0;
fail:
c->ip = ip;
if (ret == -DWARF_ENOINFO) {
debug(DEBUG_DWARF, "try arch specific step");
ret = dwarf_arch_step(as);
if (!ret) {
if (dwarf_locate_map(as, c->use_prev_instr ? c->ip - 1 : c->ip))
if (dwarf_locate_map(as, c->ip) < 0)
ret = -DWARF_ENOINFO;
}
}
if (ret) {
unsigned int i;
#ifdef GUESS_CALLER
ssize_t n;
unsigned char buf[4096];
for(i = 0; i < 16; ++i) {
if (dwarf_readw(as, &cfa, &ip, as->is_64bit))
break;
n = copy_from_proc(c->task, cfa, &buf, ARRAY_SIZE(buf));
if (n > 0) {
arch_addr_t (*getval)(unsigned char *buf);
ssize_t i;
ssize_t addr_size = DWARF_ADDR_SIZE(as);
if (!dwarf_locate_map(as, ip)) {
c->cfa = cfa;
c->ip = ip;
if (addr_size == 8)
getval = get64val;
else
getval = get32val;
return 0;
for(i = 0; i + addr_size <= n ; i += addr_size) {
ip = getval(&buf[i]);
#if 0
if (c->ip - ip < 16384)
continue;
#endif
if (!dwarf_locate_map(as, ip) && dwarf_arch_check_call(as, ip)) {
c->cfa = cfa + i + addr_size;
c->ip = ip;
return 0;
}
}
}
#endif
debug(DEBUG_DWARF, "error %d", ret);
c->valid = 0;
@ -1982,7 +2025,7 @@ arch_addr_t dwarf_get_ip(struct dwarf_addr_space *as)
return c->ip;
}
int dwarf_get_unwind_table(struct task *task, struct library *lib, struct dwarf_eh_frame_hdr *hdr)
int dwarf_get_unwind_table(struct task *task, struct libref *libref, struct dwarf_eh_frame_hdr *hdr)
{
arch_addr_t addr, fde_count;
int ret;
@ -1991,7 +2034,7 @@ int dwarf_get_unwind_table(struct task *task, struct library *lib, struct dwarf_
memset(&tmp_as, 0, sizeof(tmp_as));
tmp_as.is_64bit = task->is_64bit;
tmp_as.cursor.lib = lib;
tmp_as.cursor.libref = libref;
tmp_as.cursor.task = task;
if (hdr->version != DW_EH_VERSION) {
@ -2014,9 +2057,19 @@ int dwarf_get_unwind_table(struct task *task, struct library *lib, struct dwarf_
return -DWARF_EINVAL;
}
lib->table_data = (void *)addr;
lib->table_len = fde_count;
libref->table_data = (void *)addr;
libref->table_len = fde_count;
return 0;
}
int dwarf_location_type(struct dwarf_addr_space *as)
{
struct libref *libref = as->cursor.libref;
if (!libref)
return -1;
return libref->type;
}

View File

@ -89,7 +89,7 @@ struct dwarf_cursor {
arch_addr_t ret_addr_column; /* column for return-address */
unsigned int use_prev_instr:1; /* use previous (= call) or current (= signal) instruction? */
unsigned int valid:1;
struct library *lib;
struct libref *libref;
struct dwarf_cie_info dci;
struct dwarf_loc *loc;
};
@ -119,12 +119,15 @@ int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip);
int dwarf_get(struct dwarf_addr_space *as, struct dwarf_loc loc, arch_addr_t *valp);
int dwarf_get_unwind_table(struct task *task, struct library *lib, struct dwarf_eh_frame_hdr *hdr);
int dwarf_get_unwind_table(struct task *task, struct libref *libref, struct dwarf_eh_frame_hdr *hdr);
int dwarf_location_type(struct dwarf_addr_space *as);
int dwarf_arch_init(struct dwarf_addr_space *as);
int dwarf_arch_init_unwind(struct dwarf_addr_space *as);
int dwarf_arch_step(struct dwarf_addr_space *as);
int dwarf_arch_map_reg(struct dwarf_addr_space *as, unsigned int reg);
int dwarf_arch_check_call(struct dwarf_addr_space *as, arch_addr_t ip);
#ifdef DWARF_TO_REGNUM
unsigned int dwarf_to_regnum(unsigned int reg);

90
event.c
View File

@ -61,12 +61,6 @@ void queue_event(struct task *task)
}
}
void wait_for_event(struct task *task)
{
while(task->event.type == EVENT_NONE)
queue_event(wait_event());
}
struct task *next_event(void)
{
if (!list_empty(&event_head)) {
@ -113,7 +107,7 @@ static void show_clone(struct task *task, enum event_type type)
fprintf(stderr, "+++ process pid=%d %s (newpid=%d) +++\n", task->pid, str, task->event.e_un.newpid);
}
static struct task *handle_clone(struct task *task, enum event_type type)
static void handle_clone(struct task *task, enum event_type type)
{
struct task *newtask;
int newpid = task->event.e_un.newpid;
@ -135,7 +129,7 @@ static struct task *handle_clone(struct task *task, enum event_type type)
if (!options.follow) {
remove_proc(newtask);
return task;
return;
}
report_fork(newtask, task);
@ -147,21 +141,23 @@ static struct task *handle_clone(struct task *task, enum event_type type)
continue_task(newtask, newtask->event.e_un.signum);
return task;
return;
fail:
fprintf(stderr,
"Error during init of tracing process %d\n"
"This process won't be traced.\n",
newpid
);
return task;
}
static struct task *handle_signal(struct task *task)
static void handle_signal(struct task *task)
{
if (options.verbose > 1) {
if (task->event.e_un.signum && (task->event.e_un.signum != SIGSTOP || !task->was_stopped))
fprintf(stderr, "+++ process pid=%d signal %d: %s +++\n", task->pid, task->event.e_un.signum, strsignal(task->event.e_un.signum));
}
continue_task(task, task->event.e_un.signum);
return task;
}
static void show_exit(struct task *task)
@ -171,17 +167,18 @@ static void show_exit(struct task *task)
}
static struct task *handle_about_exit(struct task *task)
static void handle_about_exit(struct task *task)
{
if (task->leader == task)
report_about_exit(task);
else
continue_task(task, 0);
return task;
if (task->leader == task) {
if (report_about_exit(task) != -1) {
task->about_exit = 1;
return;
}
}
continue_task(task, 0);
}
static struct task *handle_exit(struct task *task)
static void handle_exit(struct task *task)
{
show_exit(task);
@ -189,13 +186,12 @@ static struct task *handle_exit(struct task *task)
report_exit(task);
remove_proc(task);
}
else
else {
remove_task(task);
return NULL;
}
}
static struct task *handle_exit_signal(struct task *task)
static void handle_exit_signal(struct task *task)
{
if (options.verbose)
fprintf(stderr, "+++ process pid=%d killed by signal %s (%d) +++\n", task->pid, strsignal(task->event.e_un.signum), task->event.e_un.signum);
@ -204,13 +200,12 @@ static struct task *handle_exit_signal(struct task *task)
report_exit(task);
remove_proc(task);
}
else
else {
remove_task(task);
return NULL;
}
}
static struct task *handle_exec(struct task *task)
static void handle_exec(struct task *task)
{
debug(DEBUG_FUNCTION, "pid=%d", task->pid);
@ -226,12 +221,11 @@ static struct task *handle_exec(struct task *task)
fprintf(stderr, "+++ process pid=%d exec (%s) +++\n", task->pid, library_execname(task));
continue_task(task, 0);
return task;
return;
nofollow:
report_nofollow(task);
untrace:
remove_proc(task);
return NULL;
}
static int handle_call_after(struct task *task, struct breakpoint *bp)
@ -247,12 +241,22 @@ static int handle_call_after(struct task *task, struct breakpoint *bp)
return 0;
}
static struct task *handle_breakpoint(struct task *task)
static void handle_breakpoint(struct task *task)
{
struct breakpoint *bp = task->event.e_un.breakpoint;
debug(DEBUG_FUNCTION, "pid=%d, addr=%#lx", task->pid, bp->addr);
#if HW_BREAKPOINTS > 1
if (bp->type >= BP_HW) {
if (++bp->hwcnt >= (BP_REORDER_THRESHOLD << bp->hw))
reorder_hw_bp(task);
}
#endif
if (options.verbose)
++bp->count;
if (bp->deleted) {
struct breakpoint *nbp = breakpoint_find(task, bp->addr);
@ -264,7 +268,7 @@ static struct task *handle_breakpoint(struct task *task)
}
if (task->skip_bp == bp) {
breakpoint_unref(task->skip_bp);
breakpoint_put(task->skip_bp);
task->skip_bp = NULL;
skip_breakpoint(task, bp);
goto end;
@ -281,7 +285,7 @@ static struct task *handle_breakpoint(struct task *task)
save_param_context(task);
if (libsym->func->report_out) {
task->breakpoint = breakpoint_insert(task, get_return_addr(task), NULL, HW_BP_SCRATCH);
task->breakpoint = breakpoint_insert(task, get_return_addr(task), NULL, BP_HW_SCRATCH);
if (task->breakpoint) {
task->libsym = libsym;
task->breakpoint->on_hit = handle_call_after;
@ -298,9 +302,7 @@ static struct task *handle_breakpoint(struct task *task)
skip_breakpoint(task, bp);
end:
breakpoint_unref(bp);
return task;
breakpoint_put(bp);
}
int handle_event(void)
@ -322,33 +324,33 @@ int handle_event(void)
break;
case EVENT_SIGNAL:
debug(DEBUG_EVENT_HANDLER, "pid=%d, event signal %d", task->pid, event->e_un.signum);
task = handle_signal(task);
handle_signal(task);
break;
case EVENT_ABOUT_EXIT:
debug(DEBUG_EVENT_HANDLER, "pid=%d, event exit %d", task->pid, event->e_un.ret_val);
task = handle_about_exit(task);
handle_about_exit(task);
break;
case EVENT_EXIT:
debug(DEBUG_EVENT_HANDLER, "pid=%d, event exit %d", task->pid, event->e_un.ret_val);
task = handle_exit(task);
handle_exit(task);
break;
case EVENT_EXIT_SIGNAL:
debug(DEBUG_EVENT_HANDLER, "pid=%d, event exit signal %d", task->pid, event->e_un.signum);
task = handle_exit_signal(task);
handle_exit_signal(task);
break;
case EVENT_FORK:
case EVENT_VFORK:
case EVENT_CLONE:
debug(DEBUG_EVENT_HANDLER, "pid=%d, event clone (%u)", task->pid, event->e_un.newpid);
task = handle_clone(task, type);
handle_clone(task, type);
break;
case EVENT_EXEC:
debug(DEBUG_EVENT_HANDLER, "pid=%d, event exec()", task->pid);
task = handle_exec(task);
handle_exec(task);
break;
case EVENT_BREAKPOINT:
debug(DEBUG_EVENT_HANDLER, "pid=%d, event breakpoint %#lx", task->pid, event->e_un.breakpoint->addr);
task = handle_breakpoint(task);
handle_breakpoint(task);
break;
default:
fprintf(stderr, "Error! unknown event?\n");

View File

@ -53,7 +53,6 @@ struct event {
void init_event(struct task *task);
void remove_event(struct task *task);
struct task *next_event(void);
void wait_for_event(struct task *task);
void queue_event(struct task *task);
int handle_event(void);

View File

@ -28,6 +28,7 @@
struct event;
struct task;
struct breakpoint;
struct libref;
struct library;
struct library_symbol;
struct mt_elf;

238
library.c
View File

@ -38,126 +38,107 @@
#include "server.h"
#include "task.h"
struct library_symbol *library_symbol_new(struct library *lib, arch_addr_t addr, const struct function *func)
struct libref *libref_new(unsigned int type)
{
struct libref *libref = malloc(sizeof(*libref));
if (!libref)
return NULL;
memset(libref, 0, sizeof(*libref));
libref->refcnt = 0;
libref->type = type;
INIT_LIST_HEAD(&libref->sym_list);
return libref;
}
void libref_delete(struct libref *libref)
{
struct list_head *it, *next;
list_for_each_safe(it, next, &libref->sym_list) {
struct library_symbol *sym = container_of(it, struct library_symbol, list);
list_del(&sym->list);
free(sym);
}
if (libref->image_addr)
munmap(libref->image_addr, libref->load_size);
free((void *)libref->filename);
free(libref);
}
static void libref_put(struct libref *libref)
{
assert(libref->refcnt != 0);
if (!--libref->refcnt)
libref_delete(libref);
}
static struct libref *libref_get(struct libref *libref)
{
assert(libref);
++libref->refcnt;
return libref;
}
void libref_set_filename(struct libref *libref, const char *new_name)
{
free((void *)libref->filename);
libref->filename = new_name ? strdup(new_name) : NULL;
}
struct library_symbol *library_symbol_new(struct libref *libref, arch_addr_t addr, const struct function *func)
{
struct library_symbol *libsym = malloc(sizeof(*libsym));
if (!libsym)
return NULL;
INIT_LIST_HEAD(&libsym->list);
libsym->lib = NULL;
libsym->libref = libref;
libsym->func = func;
libsym->addr = addr;
list_add_tail(&libsym->list, &lib->sym_list);
list_add_tail(&libsym->list, &libref->sym_list);
return libsym;
}
static void library_symbol_destroy(struct task *task, struct library_symbol *libsym)
{
struct breakpoint *bp = breakpoint_find(task, libsym->addr);
if (bp)
breakpoint_delete(task, bp);
list_del(&libsym->list);
free(libsym);
}
static struct library_symbol *library_symbol_clone(struct library *lib, struct library_symbol *libsym)
{
struct library_symbol *retp = library_symbol_new(lib, libsym->addr, libsym->func);
if (!retp)
return NULL;
return retp;
}
struct library *library_new(void)
{
struct library *lib = malloc(sizeof(*lib));
if (lib == NULL)
return NULL;
memset(lib, 0, sizeof(*lib));
INIT_LIST_HEAD(&lib->list);
INIT_LIST_HEAD(&lib->sym_list);
return lib;
}
void library_destroy(struct task *task, struct library *lib)
void library_delete(struct task *task, struct library *lib)
{
if (lib == NULL)
return;
struct list_head *it, *next;
struct libref *libref = lib->libref;
list_for_each_safe(it, next, &lib->sym_list) {
struct library_symbol *sym = container_of(it, struct library_symbol, list);
list_for_each_safe(it, next, &libref->sym_list) {
struct breakpoint *bp = breakpoint_find(task, container_of(it, struct library_symbol, list)->addr);
library_symbol_destroy(task, sym);
if (bp)
breakpoint_delete(task, bp);
}
list_del(&lib->list);
if (lib->image_addr)
munmap(lib->image_addr, lib->load_size);
free(lib);
libref_put(libref);
}
void library_set_filename(struct library *lib, const char *new_name)
{
free((void *)lib->filename);
lib->filename = new_name ? strdup(new_name) : NULL;
}
static struct library *library_clone(struct task *clone, struct library *lib)
{
struct list_head *it;
struct library *retp = library_new();
if (!retp)
return NULL;
library_set_filename(retp, lib->filename);
retp->key = lib->key;
/* Clone symbols. */
list_for_each(it, &lib->sym_list) {
if (!library_symbol_clone(retp, container_of(it, struct library_symbol, list)))
goto fail;
}
return retp;
fail:
/* Release what we managed to allocate. */
library_destroy(clone, retp);
return NULL;
}
static void library_each_symbol(struct library *lib, void (*cb)(struct library_symbol *, void *), void *data)
{
struct list_head *it, *next;
list_for_each_safe(it, next, &lib->sym_list) {
struct library_symbol *sym = container_of(it, struct library_symbol, list);
(*cb) (sym, data);
}
}
struct library_symbol *library_find_symbol(struct library *lib, arch_addr_t addr)
struct library_symbol *library_find_symbol(struct libref *libref, arch_addr_t addr)
{
struct list_head *it;
list_for_each(it, &lib->sym_list) {
list_for_each(it, &libref->sym_list) {
struct library_symbol *sym = container_of(it, struct library_symbol, list);
if (sym->addr == addr)
@ -166,21 +147,6 @@ struct library_symbol *library_find_symbol(struct library *lib, arch_addr_t addr
return NULL;
}
struct library_symbol *find_symbol(struct task *leader, arch_addr_t addr)
{
/* Clone symbols first so that we can clone and relink breakpoints. */
struct list_head *it;
list_for_each(it, &leader->libraries_list) {
struct library *lib = container_of(it, struct library, list);
struct library_symbol *libsym = library_find_symbol(lib, addr);
if (libsym)
return libsym;
}
return NULL;
}
struct library *library_find_with_key(struct list_head *list, arch_addr_t key)
{
struct list_head *it;
@ -188,7 +154,7 @@ struct library *library_find_with_key(struct list_head *list, arch_addr_t key)
list_for_each(it, list) {
struct library *lib = container_of(it, struct library, list);
if (lib->key == key)
if (lib->libref->key == key)
return lib;
}
return NULL;
@ -200,13 +166,14 @@ void library_delete_list(struct task *leader, struct list_head *list)
list_for_each_safe(it, next, list) {
struct library *lib = container_of(it, struct library, list);
struct libref *libref = lib->libref;
debug(DEBUG_FUNCTION, "%s@%#lx", lib->filename, lib->base);
debug(DEBUG_FUNCTION, "%s@%#lx", libref->filename, libref->base);
if (options.verbose > 1)
fprintf(stderr, "+++ library del pid=%d %s@%#lx %#lx-%#lx +++\n", leader->pid, lib->filename, lib->base, lib->load_addr, lib->load_addr + lib->load_size);
fprintf(stderr, "+++ library del pid=%d %s@%#lx %#lx-%#lx +++\n", leader->pid, libref->filename, libref->base, libref->load_addr, libref->load_addr + libref->load_size);
library_destroy(leader, lib);
library_delete(leader, lib);
}
}
@ -222,7 +189,7 @@ static void cb_breakpoint_for_symbol(struct library_symbol *libsym, void *data)
bp->libsym = libsym;
return;
}
bp = breakpoint_new(task, addr, libsym, libsym->func->hw_bp_min <= HW_BREAKPOINTS ? HW_BP : SW_BP);
bp = breakpoint_new(task, addr, libsym, BP_AUTO);
if (!bp)
fprintf(stderr, "Couldn't insert breakpoint for %s to %d: %s", libsym->func->name, task->pid, strerror(errno));
@ -230,21 +197,50 @@ static void cb_breakpoint_for_symbol(struct library_symbol *libsym, void *data)
breakpoint_enable(task, bp);
}
void library_add(struct task *leader, struct library *lib)
static void library_each_symbol(struct libref *libref, void (*cb)(struct library_symbol *, void *), void *data)
{
struct list_head *it, *next;
list_for_each_safe(it, next, &libref->sym_list) {
struct library_symbol *sym = container_of(it, struct library_symbol, list);
(*cb) (sym, data);
}
}
static struct library *_library_add(struct task *leader, struct libref *libref)
{
debug(DEBUG_PROCESS, "%s@%#lx to pid=%d", libref->filename, libref->base, leader->pid);
assert(leader->leader == leader);
debug(DEBUG_PROCESS, "%s@%#lx to pid=%d", lib->filename, lib->base, leader->pid);
struct library *lib = malloc(sizeof(*lib));
if (options.verbose > 1)
fprintf(stderr, "+++ library add pid=%d %s@%#lx %#lx-%#lx +++\n", leader->pid, lib->filename, lib->base, lib->load_addr, lib->load_addr + lib->load_size);
if (lib == NULL)
return NULL;
/* Insert breakpoints for all active symbols. */
library_each_symbol(lib, cb_breakpoint_for_symbol, leader);
memset(lib, 0, sizeof(*lib));
lib->libref = libref_get(libref);
list_add_tail(&lib->list, &leader->libraries_list);
if (options.verbose > 1)
fprintf(stderr, "+++ library add pid=%d %s@%#lx %#lx-%#lx +++\n", leader->pid, libref->filename, libref->base, libref->load_addr, libref->load_addr + libref->load_size);
return lib;
}
struct library *library_add(struct task *leader, struct libref *libref)
{
struct library *lib = _library_add(leader, libref);
/* Insert breakpoints for all active symbols. */
library_each_symbol(libref, cb_breakpoint_for_symbol, leader);
report_add_map(leader, lib);
return lib;
}
void library_clear_all(struct task *leader)
@ -258,12 +254,8 @@ int library_clone_all(struct task *clone, struct task *leader)
list_for_each(it, &leader->libraries_list) {
struct library *lib = container_of(it, struct library, list);
struct library *nlibp = library_clone(clone, lib);
if (!nlibp)
return -1;
list_add_tail(&nlibp->list, &clone->libraries_list);
_library_add(clone, lib->libref);
}
return 0;
}
@ -278,6 +270,6 @@ const char *library_execname(struct task *leader)
if (list_empty(&leader->libraries_list))
return NULL;
return container_of(leader->libraries_list.next, struct library, list)->filename;
return container_of(leader->libraries_list.next, struct library, list)->libref->filename;
}

View File

@ -31,21 +31,18 @@
#include "list.h"
#include "mtelf.h"
#define LIBTYPE_LIB 0
#define LIBTYPE_MAIN 1
#define LIBTYPE_LOADER 2
struct library_symbol {
struct list_head list;
struct library *lib;
struct libref *libref;
const struct function *func;
arch_addr_t addr;
};
struct library_symbol *library_symbol_new(struct library *lib, arch_addr_t addr, const struct function *func);
struct library {
struct list_head list;
/* Symbols associated with the library. This includes a
* symbols that don't have a breakpoint attached (yet). */
struct list_head sym_list;
struct libref {
/* Unique key. Two library objects are considered equal, if
* they have the same key. */
arch_addr_t key;
@ -74,24 +71,36 @@ struct library {
unsigned long seg_offset;
void *table_data;
unsigned long table_len;
unsigned int type;
#ifdef __arm__
void *exidx_data;
unsigned long exidx_len;
#endif
unsigned int refcnt;
/* Symbols associated with the library. This includes a
* symbols that don't have a breakpoint attached (yet). */
struct list_head sym_list;
};
/* Init LIB. */
struct library *library_new(void);
struct library {
/* link list of libraries associated with the task */
struct list_head list;
/* Destroy library. Doesn't free LIB itself. Symbols are destroyed
* and freed. */
void library_destroy(struct task *leader, struct library *lib);
/* pointer to the real library refernce */
struct libref *libref;
};
/* Set library filename. Frees the old name if necessary. */
void library_set_filename(struct library *lib, const char *new_name);
/* create a new symbol */
struct library_symbol *library_symbol_new(struct libref *libref, arch_addr_t addr, const struct function *func);
/* Delete library. Symbols are destroyed and freed. */
void library_delete(struct task *leader, struct library *lib);
/* Add a library to the list of the thread leader libraries. */
void library_add(struct task *leader, struct library *lib);
struct library *library_add(struct task *leader, struct libref *libref);
/* delete a given list of libraries */
void library_delete_list(struct task *leader, struct list_head *list);
@ -109,13 +118,19 @@ void library_setup(struct task *leader);
const char *library_execname(struct task *leader);
/* Iterate through list of symbols of library. */
struct library_symbol *library_find_symbol(struct library *lib, arch_addr_t addr);
struct library_symbol *library_find_symbol(struct libref *libref, arch_addr_t addr);
/* find a library with a given key */
struct library *library_find_with_key(struct list_head *list, arch_addr_t key);
/* Iterate through list all symbols of leader task. */
struct library_symbol *find_symbol(struct task *leader, arch_addr_t addr);
/* create a library reference. */
struct libref *libref_new(unsigned int type);
/* delete a library reference. */
void libref_delete(struct libref *libref);
/* Set library filename. Frees the old name if necessary. */
void libref_set_filename(struct libref *libref, const char *new_name);
#endif

54
main.c
View File

@ -64,15 +64,15 @@ void mtrace_request_exit(void)
wait_event_wakeup();
}
static void dump_process(struct task *leader)
static void detach_process(struct task *leader)
{
if (!leader)
return;
pid_t pid = leader->pid;
report_detach(leader);
pid_t pid = leader->pid;
while(server_handle_command() != -1) {
struct task *task = pid2task(pid);
@ -88,12 +88,7 @@ static void mtrace_exit(void)
{
if (!options.interactive) {
each_process(stop_threads);
while(server_connected()) {
if (task_list_empty())
break;
dump_process(get_first_process());
}
each_process(detach_process);
}
each_process(remove_proc);
@ -139,26 +134,37 @@ int main(int argc, char *argv[])
{
char **cmd = process_options(argc, argv);
if (options.client) {
if (options.trace) {
if (options.logfile) {
if (server_logfile() == -1)
exit(EXIT_FAILURE);
}
else
if (options.server) {
if (server_start() == -1)
exit(EXIT_FAILURE);
}
else {
int ret = server_start_pair();
if (ret == -1)
exit(EXIT_FAILURE);
if (client_start_pair(ret))
exit(EXIT_FAILURE);
}
}
else {
if (options.logfile) {
if (client_logfile() == -1)
exit(EXIT_FAILURE);
}
else
if (client_start() == -1)
exit(EXIT_FAILURE);
return 0;
}
if (options.server) {
if (server_start() == -1)
exit(EXIT_FAILURE);
}
else {
int ret = server_start_pair();
if (ret == -1)
exit(EXIT_FAILURE);
if (client_start_pair(ret))
exit(EXIT_FAILURE);
}
mtrace_init(cmd);
mtrace_main();
mtrace_exit();

142
mtelf.c
View File

@ -146,7 +146,7 @@ static void read_symbol_table(struct mt_elf *mte, const char *filename, Elf_Scn
*strsp = data->d_buf;
}
static int populate_this_symtab(struct mt_elf *mte, struct library *lib, Elf_Data *symtab, const char *strtab, size_t size)
static int populate_this_symtab(struct mt_elf *mte, struct libref *libref, Elf_Data *symtab, const char *strtab, size_t size)
{
size_t i;
@ -177,9 +177,9 @@ static int populate_this_symtab(struct mt_elf *mte, struct library *lib, Elf_Dat
arch_addr_t addr = ARCH_ADDR_T(sym.st_value + mte->bias);
struct library_symbol *libsym = library_find_symbol(lib, addr);
struct library_symbol *libsym = library_find_symbol(libref, addr);
if (!libsym) {
struct library_symbol *libsym = library_symbol_new(lib, addr, func);
struct library_symbol *libsym = library_symbol_new(libref, addr, func);
if (!libsym) {
fprintf(stderr, "couldn't init symbol: %s%s\n", name, func->name);
@ -191,21 +191,30 @@ static int populate_this_symtab(struct mt_elf *mte, struct library *lib, Elf_Dat
if (libsym->func->level > func->level)
libsym->func = func;
}
if (options.verbose > 1)
fprintf(stderr, "breakpoint for %s:%s at %#lx\n", libref->filename, func->demangled_name, addr);
}
return 0;
}
static int populate_symtab(struct mt_elf *mte, struct library *lib)
static int populate_symtab(struct mt_elf *mte, struct libref *libref)
{
struct opt_O_t *p;
for(p = options.opt_O; p; p = p->next) {
if (!strcmp(p->pathname, libref->filename))
return 0;
}
if (mte->symtab != NULL && mte->strtab != NULL) {
int status = populate_this_symtab(mte, lib, mte->symtab, mte->strtab, mte->symtab_count);
int status = populate_this_symtab(mte, libref, mte->symtab, mte->strtab, mte->symtab_count);
if (status < 0)
return status;
}
return populate_this_symtab(mte, lib, mte->dynsym, mte->dynstr, mte->dynsym_count);
return populate_this_symtab(mte, libref, mte->dynsym, mte->dynstr, mte->dynsym_count);
}
static inline int elf_map_image(struct mt_elf *mte, void **image_addr)
@ -223,32 +232,32 @@ static inline int elf_map_image(struct mt_elf *mte, void **image_addr)
return 0;
}
static int elf_lib_init(struct mt_elf *mte, struct task *task, struct library *lib)
static int elf_lib_init(struct mt_elf *mte, struct task *task, struct libref *libref)
{
if (elf_map_image(mte, &lib->image_addr))
if (elf_map_image(mte, &libref->image_addr))
return -1;
lib->base = ARCH_ADDR_T(mte->base_addr);
lib->entry = ARCH_ADDR_T(mte->entry_addr);
lib->load_offset = mte->txt_hdr.p_offset;
lib->load_addr = mte->txt_hdr.p_vaddr + mte->bias;
lib->load_size = mte->txt_hdr.p_filesz;
lib->seg_offset = mte->eh_hdr.p_offset;
lib->gp = mte->pltgot;
libref->base = ARCH_ADDR_T(mte->base_addr);
libref->entry = ARCH_ADDR_T(mte->entry_addr);
libref->load_offset = mte->txt_hdr.p_offset;
libref->load_addr = mte->txt_hdr.p_vaddr + mte->bias;
libref->load_size = mte->txt_hdr.p_filesz;
libref->seg_offset = mte->eh_hdr.p_offset;
libref->gp = mte->pltgot;
#ifdef __arm__
if (mte->exidx_hdr.p_filesz) {
lib->exidx_data = lib->image_addr + mte->exidx_hdr.p_offset;
lib->exidx_len = mte->exidx_hdr.p_memsz;
libref->exidx_data = libref->image_addr + mte->exidx_hdr.p_offset;
libref->exidx_len = mte->exidx_hdr.p_memsz;
}
#endif
if (mte->eh_hdr.p_filesz && mte->dyn_addr) {
if (dwarf_get_unwind_table(task, lib, (struct dwarf_eh_frame_hdr *)(lib->image_addr - lib->load_offset + mte->eh_hdr.p_offset)) < 0)
if (dwarf_get_unwind_table(task, libref, (struct dwarf_eh_frame_hdr *)(libref->image_addr - libref->load_offset + mte->eh_hdr.p_offset)) < 0)
return -1;
}
if (populate_symtab(mte, lib) < 0)
if (populate_symtab(mte, libref) < 0)
return -1;
return 0;
@ -370,12 +379,12 @@ static int elf_read(struct mt_elf *mte, struct task *task, const char *filename,
return 0;
}
int elf_read_library(struct task *task, struct library *lib, const char *filename, GElf_Addr bias)
int elf_read_library(struct task *task, struct libref *libref, const char *filename, GElf_Addr bias)
{
struct mt_elf mte = { };
int ret;
library_set_filename(lib, filename);
libref_set_filename(libref, filename);
if (elf_read(&mte, task, filename, bias) == -1)
return -1;
@ -383,7 +392,7 @@ int elf_read_library(struct task *task, struct library *lib, const char *filenam
mte.bias = bias;
mte.entry_addr = mte.ehdr.e_entry + bias;
ret = elf_lib_init(&mte, task, lib);
ret = elf_lib_init(&mte, task, libref);
close_elf(&mte);
@ -456,7 +465,7 @@ static int entry_breakpoint_on_hit(struct task *task, struct breakpoint *a)
return 1;
}
struct library *elf_read_main_binary(struct task *task)
struct libref *elf_read_main_binary(struct task *task)
{
char fname[PATH_MAX];
int ret;
@ -464,14 +473,14 @@ struct library *elf_read_main_binary(struct task *task)
struct mt_elf mte = { };
unsigned long entry;
unsigned long base;
struct library *lib;
struct libref *libref;
filename = pid2name(task->pid);
if (!filename)
return NULL;
lib = library_new();
if (lib == NULL)
libref = libref_new(LIBTYPE_MAIN);
if (libref == NULL)
goto fail1;
ret = readlink(filename, fname, sizeof(fname) - 1);
@ -480,7 +489,7 @@ struct library *elf_read_main_binary(struct task *task)
fname[ret] = 0;
library_set_filename(lib, strdup(fname));
libref_set_filename(libref, fname);
if (elf_read(&mte, task, filename, 0) == -1)
goto fail3;
@ -497,57 +506,90 @@ struct library *elf_read_main_binary(struct task *task)
mte.bias = (GElf_Addr) (uintptr_t) entry - mte.ehdr.e_entry;
mte.entry_addr = (GElf_Addr) (uintptr_t) entry;
if (elf_lib_init(&mte, task, lib))
libref->key = ARCH_ADDR_T(mte.bias);
if (elf_lib_init(&mte, task, libref))
goto fail3;
close_elf(&mte);
report_attach(task);
library_add(task, lib);
if (!linkmap_init(task, ARCH_ADDR_T(mte.dyn_addr)))
return lib;
library_add(task, libref);
if (!mte.interp)
return lib;
return libref;
struct mt_elf mte_ld = { };
copy_str_from_proc(task, ARCH_ADDR_T(mte.interp), fname, sizeof(fname));
if (!elf_read(&mte_ld, task, fname, (GElf_Addr)base)) {
struct libref *libref;
libref = libref_new(LIBTYPE_LOADER);
if (libref == NULL)
goto fail4;
libref_set_filename(libref, fname);
mte_ld.bias = (GElf_Addr)base;
mte_ld.entry_addr = mte_ld.ehdr.e_entry + (GElf_Addr)base;
arch_addr_t addr = find_solib_break(&mte_ld);
if (!addr)
addr = ARCH_ADDR_T(entry);
libref->key = ARCH_ADDR_T(mte_ld.bias);
struct entry_breakpoint *entry_bp = (void *)breakpoint_new_ext(task, addr, NULL, 0, sizeof(*entry_bp) - sizeof(entry_bp->breakpoint));
if (!entry_bp)
ret = elf_lib_init(&mte_ld, task, libref);
if (!ret) {
library_add(task, libref);
if (linkmap_init(task, ARCH_ADDR_T(mte.dyn_addr))) {
arch_addr_t addr = find_solib_break(&mte_ld);
if (!addr)
addr = ARCH_ADDR_T(entry);
struct entry_breakpoint *entry_bp = (void *)breakpoint_new_ext(task, addr, NULL, 0, sizeof(*entry_bp) - sizeof(entry_bp->breakpoint));
if (!entry_bp)
fprintf(stderr,
"Couldn't initialize entry breakpoint for PID %d.\n"
"Tracing events may be missed.\n",
task->pid
);
else {
entry_bp->breakpoint.on_hit = entry_breakpoint_on_hit;
entry_bp->breakpoint.locked = 1;
entry_bp->dyn_addr = ARCH_ADDR_T(mte.dyn_addr);
breakpoint_enable(task, &entry_bp->breakpoint);
}
}
}
else {
fprintf(stderr,
"Couldn't initialize entry breakpoint for PID %d.\n"
"Some tracing events may be missed.\n",
"Couldn't read dynamic loader `%s` for PID %d.\n"
"Tracing events may be missed.\n",
fname,
task->pid
);
else {
entry_bp->breakpoint.on_hit = entry_breakpoint_on_hit;
entry_bp->breakpoint.locked = 1;
entry_bp->dyn_addr = ARCH_ADDR_T(mte.dyn_addr);
breakpoint_enable(task, &entry_bp->breakpoint);
}
fail4:
close_elf(&mte_ld);
}
else {
fprintf(stderr,
"Couldn't open dynamic loader `%s` for PID %d.\n"
"Tracing events may be missed.\n",
fname,
task->pid
);
}
close_elf(&mte_ld);
return lib;
return libref;
fail3:
close_elf(&mte);
fail2:
library_destroy(task, lib);
libref_delete(libref);
fail1:
free(filename);
return lib;
return libref;
}

View File

@ -58,10 +58,10 @@ struct elf_image {
size_t size; /* (file-) size of the image */
};
int elf_read_library(struct task *task, struct library *lib, const char *filename, GElf_Addr bias);
int elf_read_library(struct task *task, struct libref *libref, const char *filename, GElf_Addr bias);
/* Create a library object representing the main binary. */
struct library *elf_read_main_binary(struct task *task);
struct libref *elf_read_main_binary(struct task *task);
#endif

126
mtrace.1
View File

@ -16,7 +16,7 @@
.\" Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
.\" 02110-1301 USA
.\"
.TH MTRACE "1" "May 2015" "" "User Commands"
.TH MTRACE "12" "Oct 2015" "" "User Commands"
.SH NAME
mtrace \- A dynamic memory allocation tracer
.SH SYNOPSIS
@ -24,14 +24,14 @@ mtrace \- A dynamic memory allocation tracer
.\" ---------------------------------------------------------------------------
.\"
.PP
.B mtrace
.BR mtrace " \-t|\-\-trace
.\"
.\" Output formatting:
.\"
[\-d|\-\-depth \fIlevel\fR]
[\-F|\-\-config \fIfile\fR]
[\-F|\-\-config \fIfilename\fR]
[\-S|\-\-sort \fIoption\fR]
[\-o|\-\-output \fIfile\fR]
[\-o|\-\-output \fIfilename\fR]
.\"
.\" Various:
.\"
@ -39,8 +39,11 @@ mtrace \- A dynamic memory allocation tracer
[\-b|\-\-binpath \fIpath\fR]
[\-C|\-\-cwd \fIpath\fR]
[\-D|\-\-debug \fImask\fR]
[\-i|\-\-interactive]
[\-l|\-\-logfile \fIfilename\fR]
[\-n|\-\-nocpp]
[\-u \fIusername\fR]
[\-O|\-\-omit \fIfilename\fR]
[\-u|\-\-user \fIusername\fR]
[\-v|\-\-verbose]
.\"
.\" What processes to trace:
@ -53,42 +56,22 @@ mtrace \- A dynamic memory allocation tracer
.\" ---------------------------------------------------------------------------
.\"
.PP
.BR mtrace " \-c|\-\-client addr"
[\-P|\-\-port num]
[\-i|\-\-interactive]
.\"
.\" Output formatting:
.\"
[\-b|\-\-binpath \fIpath\fR]
[\-F|\-\-config \fIfile\fR]
[\-S|\-\-sort \fIoption\fR]
[\-o|\-\-output \fIfilenfR]
.\"
.\" Various:
.\"
[\-a|\-\-autoscan]
[\-D|\-\-debug \fImask\fR]
[\-v|\-\-verbose]
.\"
.\" ---------------------------------------------------------------------------
.\"
.PP
.BR mtrace " \-s|\-\-server"
[\-P|\-\-port num]
[\-l|\-\-listen addr]
.BR mtrace " \-t|\-\-trace \-r|\-\-remote \fIaddr\fR"
[\-P|\-\-port \fInum\fR]
[\-w|\-\-wait]
.\"
.\" Output formatting:
.\"
[\-d|\-\-depth \fIlevel\fR]
[\-o|\-\-output \fIfile\fR]
.\"
.\" Various:
.\"
[\-C|\-\-cwd \fIpath\fR]
[\-D|\-\-debug \fImask\fR]
[\-l|\-\-logfile \fIfilename\fR]
[\-n|\-\-nocpp]
[\-u \fIusername\fR]
[\-O|\-\-omit \fIfilename\fR]
[\-u|\-\-user \fIusername\fR]
[\-v|\-\-verbose]
.\"
.\" What processes to trace:
@ -101,30 +84,25 @@ mtrace \- A dynamic memory allocation tracer
.\" ---------------------------------------------------------------------------
.\"
.PP
.B mtrace -i|\-\-interactive
.BR mtrace
[\-r|\-\-remote \fIaddr\fR]
[\-P|\-\-port \fInum\fR]
.\"
.\" Output formatting:
.\"
[\-d|\-\-depth \fIlevel\fR]
[\-F|\-\-config \fIfile\fR]
[\-F|\-\-config \fIfilename\fR]
[\-S|\-\-sort \fIoption\fR]
[\-o|\-\-output \fIfilename\fR]
.\"
.\" Various:
.\"
[\-a|\-\-autoscan]
[\-b|\-\-binpath \fIpath\fR]
[\-C|\-\-cwd]
[\-D|\-\-debug \fImask\fR]
[\-n|\-\-nocpp]
[\-u \fIusername\fR]
[\-i|\-\-interactive]
[\-l|\-\-logfile \fIfilename\fR]
[\-v|\-\-verbose]
.\"
.\" What processes to trace:
.\"
[\-e|\-\-follow\-exec]
[\-f|\-\-follow\-fork]
[\-p|\-\-pid \fIpid\fR]
.\"
.\" ---------------------------------------------------------------------------
.\"
.PP
@ -154,7 +132,7 @@ writable memory mappings of the program against the pointer of an allocation.
If the memory address will be not found during a scan there is a high change
for a missing reference and therefore for a memory leak.
The following funtions will be intercepted:
The following functions will be intercepted:
.in +4
.nf
@ -226,13 +204,7 @@ of the binary to the search path. If the binary is not found it will strip
down the leading directory of the remote path and try again until no more
leading directory is found. It is possible to add several binary search paths
by passing more than one \-b option.
.IP "\-c, \-\-client \fIaddr\fR"
Run
.B mtrace
as client and connect to a socket. If addr begins with / or . it will assumed
a named socket, otherwise it will be passed to getaddrinfo(3), which handles
any kind of hostname, IPv4 or IPv6 addresses.
.IP "\-C, \-\-cwd \fIpath\fR"
.IP "\-c, \-\-cwd \fIpath\fR"
This option is valid in any mode except the client mode. Its used for locating
libraries for an attached process which are linked with relative paths. In this
case
@ -249,12 +221,12 @@ to see what can be used. This option is only available when
was build with --enable-debug.
.IP "\-d, \-\-depth \fIlevel\fR"
Do backtrace of \fIlevel\fR stack frames for each memory allocation function.
.IP "\-e, \-\-follow-exec"
Trace processes as they are created by one of the currently traced processes as
a result of execve(2) system call.
.IP "\-f, \-\-follow-fork"
Trace child processes as they are created by one of the currently traced
processes as a result of the fork(2) system call.
.IP "\-f, \-\-follow-exec"
Trace processes as they are created by one of the currently traced processes as
a result of execve(2) system call.
.IP "\-F, \-\-config \fIpath"
Set the config file. For a detailed description of this file see
mtrace.conf(5). It is possible to pass several config files by passing more
@ -266,24 +238,31 @@ $XDG_CONFIG_HOME/mtrace,
SYSCONFDIR/mtrace.conf,
/etc/mtrace.conf
.IP "\-h, \-\-help"
Show a summary of the options to mtrace and exit.
Show a summary of the options to \fBmtrace\fR and exit.
.IP "\-i, \-\-interactive"
Enables the interactive mode for client or when attaching to a process. See
the section \fBINTERACTIVE MODE\fR to learn more about the interactive commands
in this mode.
.IP "\-k, \-\-kill"
Kill mtrace in case of a bookkeeping error. This options is for
Kill \fBmtrace\fR in case of a bookkeeping error. This options is intended for
.B mtrace
development only!
.IP "\-l, \-\-listen \fIaddr"
Listen on socket path or address in server mode. If addr begins with / or . it
will assumed a named socket, otherwise it will be passed to getaddrinfo(3),
which handles any kind of hostname, IPv4 or IPv6 addresses.
.IP "\-O, \-\-omit \fIfilename"
Do not place any dynamic memory interception breakpoints in the given file.
This is usefull when a library offers memory allocation functions which does
only forward the calls. Use of this option can improve the trace performace in
this case. It is possible to omit several files by passing more than one
\-O option.
.IP "\-o, \-\-output \fIfilename"
Write the trace output to the file \fIfilename\fR rather than to stderr. When
passing this option the output will be written in reserve order in opposite the
stderr output. So the highest value of the sort order is at the beginning of
the file and the lowest at the end of the file.
.IP "\-l, \-\-logfile \fIfilename"
Use a given logfile instead of a socket connection. In trace mode all data will
be written into the logfile. In the non trace mode the data will be retrieved
from the logfile. This option can improve the performance of the trace
since the trace will be split into to different actions.
.IP "\-n, \-\-nocpp"
Disable the trace of C++ allocation operators. This is safe and faster for libstdc++,
since this library does call malloc() and free() inside the allocation operators.
@ -294,11 +273,13 @@ It is possible to attach to several processes by passing more than one
\-p option.
.IP "\-P, \-\-port \fInum"
Set the port number for client or server mode. The default port number is 4576.
.IP "\-s, \-\-server"
Run mtrace in server mode. This is mostly needed for remote cross architecture
trace or when running an interactive client. If no \-l and \-P option is passed
to the sever mode, the server will listen on any address using port 4576.
.IP "\-S, \-\-sortby keyword"
.IP "\-r, \-\-remote \fIaddr"
Run \fBmtrace\fR in remote mode. Use \fIaddr\fR as socket path or address. If
\fIaddr\fR begins with / or . it will assumed a named socket, otherwise it
will be passed to getaddrinfo(3), which handles any kind of hostname, IPv4 or
IPv6 addresses. If this option is passed in conjunction with -t, mtrace will be
execute in server mode, otherwise in client mode.
.IP "\-s, \-\-sortby keyword"
Sort the output of the stack backtraces by keyword. Valid keywords are:
.RS
@ -349,7 +330,11 @@ Sort by the pseudo time stamp counter. Each stack backtrace will get an increme
Sort by number of bytes in use of all open allocations.
.RE
.RE
.IP "\-u \fIusername"
.IP "\-t, \-\-trace"
Run \fBmtrace\fR in trace mode. In this mode all attached processes will run under
the control of \fBmtrace\fR and all dynamic memory function calls will be traced.
If this options is not given, \fBmtrace\fR will run in client mode.
.IP "\-u, \-\-user \fIusername\fR"
Run command with the userid, groupid and supplementary groups of
.IR username .
This option is only useful when running as root and enables the
@ -358,7 +343,7 @@ correct execution of setuid and/or setgid binaries.
Be verbose and display more details about what going on. This option can be
repeated for a more detailed view.
.IP "\-V, \-\-version"
Show the version number of mtrace and exit.
Show the version number of \fBmtrace\fR and exit.
.IP "\-w, \-\-wait"
This option stops the execution of the traced processes until a client is
connected to the server. So this option is only valid in server mode.
@ -481,12 +466,12 @@ Start allocation tracing.
Show allocation status.
.IP "stop \fIpid\fR"
Stop allocation tracing. Note that in this state the \fIscan\fR command can
Stop allocation tracing. Note that in this state a \fIscan\fR command can
not performed.
.SH BUGS
It only works on Linux for X86, X86_64, ARM 32 and PowerPC 32. No Hardware
Breakpoint support on ARM and PowerPC. No ARM Thumb support. See TODO file
It only works on Linux for X86, X86_64, ARM 32 and PowerPC 32. No Hardware
Breakpoint support on ARM and PowerPC. No ARM Thumb support. See TODO file
for more open issues.
.LP
.PP
@ -505,4 +490,5 @@ See mtrace.conf(5) for details on the syntax of this file.
Stefani Seibold <stefani@seibold.net>
.SH "SEE ALSO"
.BR mtrace.conf(5),
.BR ptrace(2)
.BR ptrace(2),
.BR perf(1)

270
options.c
View File

@ -46,16 +46,19 @@
#endif
#define MIN_STACK 4
#define MAX_STACK 128
#define MAX_STACK 64
#define DEFAULT_STACK 15
#define DEFAULT_PORT 4576
static char *sockdef;
struct options_t options;
static struct opt_F_t *opt_F_last;
static struct opt_p_t *opt_p_last;
static struct opt_b_t *opt_b_last;
static struct opt_O_t *opt_O_last;
static char *progname; /* Program name (`mtrace') */
@ -74,8 +77,7 @@ static void usage(void)
"\n"
" -a, --autoscan scan memory on exit of a traced program\n"
" -b, --binpath=path binary search path (may be repeated)\n"
" -c, --client=addr connect to socket (path or address)\n"
" -C, --cwd=path use as current working directory for traced process\n"
" -c, --cwd=path use as current working directory for traced process\n"
#ifdef DEBUG
" -D, --debug=MASK enable debugging (see -Dh or --debug=help)\n"
" -Dh, --debug=help show help on debugging\n"
@ -86,15 +88,17 @@ static void usage(void)
" -f, --follow-fork trace forked children\n"
" -h, --help display this help and exit\n"
" -i, --interactive interactive client mode\n"
" -O, --omit=FILE do not place breakpoint in this file\n"
" -k, --kill abort mtrace on unexpected error conditon\n"
" -l, --listen listen on socket path or address in server mode\n"
" -l, --logfile use log file instead of socket connection\n"
" -n, --nocpp disable trace of c++ allocation operators (faster for libstdc++)\n"
" -o, --output=FILE write the trace output to file with given name\n"
" -p, --pid=PID attach to the process with the process ID pid (may be repeated)\n"
" -P, --port=PORT socket port (default: " STR(DEFAULT_PORT) ")\n"
" -s, --server server mode\n"
" -S, --sort-by=type sort dump by type:\n"
" -r, --remote=addr remote use address (path, address or host)\n"
" -s, --sort-by=type sort dump by type:\n"
" allocations, average, bytes-leaked, leaks, stacks, total, tsc, usage\n"
" -t, --trace trace mode\n"
" -u, --user=USERNAME run command with the userid, groupid of username\n"
" -V, --version output version information and exit\n"
" -v, --verbose verbose mode (repeat for higher verbosity)\n"
@ -228,8 +232,8 @@ static int parse_int(const char *optarg, char opt, int min, int max)
{
char *endptr;
long int l = strtol(optarg, &endptr, 0);
if (l < min || (max != 0 && l > max)
|| *optarg == 0 || *endptr != 0) {
if (l < min || (max != 0 && l > max) || *optarg == 0 || *endptr != 0) {
const char *fmt = max != 0 ? "Invalid argument to -%c: '%s'. Use integer %d..%d.\n" : "Invalid argument to -%c: '%s'. Use integer >=%d.\n";
fprintf(stderr, fmt, opt, optarg, min, max);
exit(1);
@ -240,6 +244,10 @@ static int parse_int(const char *optarg, char opt, int min, int max)
char **process_options(int argc, char **argv)
{
char *output = NULL;
char *cwd = NULL;
if (!sockdef)
asprintf(&sockdef, "/tmp/mtrace%u.sock", getuid());
progname = argv[0];
@ -252,15 +260,17 @@ char **process_options(int argc, char **argv)
options.interactive = 0;
options.verbose = 0;
options.wait = 0;
options.client = NULL;
options.address = NULL;
options.trace = 0;
options.server = 0;
options.listen = NULL;
options.logfile = NULL;
options.user = NULL;
options.command = NULL;
options.cwd = -1;
options.opt_p = NULL;
options.opt_F = NULL;
options.opt_b = NULL;
options.opt_O = NULL;
options.sort_by = -1;
options.debug = 0;
options.kill = 0;
@ -272,9 +282,8 @@ char **process_options(int argc, char **argv)
static const struct option long_options[] = {
{ "auto_scan", 0, 0, 'a' },
{ "binpath", 1, 0, 'b' },
{ "client", 1, 0, 'c' },
{ "config", 1, 0, 'F' },
{ "cwd", 1, 0, 'C' },
{ "cwd", 1, 0, 'c' },
{ "debug", 1, 0, 'D' },
{ "depth", 1, 0, 'd' },
{ "help", 0, 0, 'h' },
@ -282,22 +291,25 @@ char **process_options(int argc, char **argv)
{ "follow-exec", 0, 0, 'e' },
{ "interactive", 0, 0, 'i' },
{ "kill", 0, 0, 'k' },
{ "listen", 1, 0, 'l' },
{ "logfile", 1, 0, 'l' },
{ "nocpp", 1, 0, 'n' },
{ "output", 1, 0, 'o' },
{ "omit", 1, 0, 'O' },
{ "pid", 1, 0, 'p' },
{ "port", 1, 0, 'P' },
{ "server", 0, 0, 's' },
{ "sort-by", 1, 0, 'S' },
{ "remote", 1, 0, 'r' },
{ "sort-by", 1, 0, 's' },
{ "trace", 0, 0, 't' },
{ "user", 1, 0, 'u' },
{ "version", 0, 0, 'V' },
{ "verbose", 0, 0, 'v' },
{ "wait", 0, 0, 'w' },
{ 0, 0, 0, 0 }
};
c = getopt_long(argc, argv,
"+aefhiknsVvw"
"b:c:C:D:F:l:o:p:P:u:d:S:",
"+aefhikLntVvw"
"b:c:d:D:F:l:o:O:p:P:r:s:u:",
long_options,
&option_index);
@ -328,15 +340,10 @@ char **process_options(int argc, char **argv)
break;
}
case 'c':
options.client = optarg;
cwd = optarg;
break;
case 'C':
options.cwd = open(optarg, O_RDONLY|O_DIRECTORY);
if (options.cwd == -1) {
fprintf(stderr, "%s: `%s' %s\n", progname, optarg, strerror(errno));
exit(1);
}
case 'd':
options.bt_depth = parse_int(optarg, 'd', 1, 0);
break;
case 'D':
{
@ -354,28 +361,52 @@ char **process_options(int argc, char **argv)
#endif
break;
}
case 'e':
options.follow_exec = 1;
break;
case 'f':
options.follow = 1;
break;
case 'F':
if (add_opt_F(strdup(optarg)) == -1) {
if (add_opt_F(optarg) == -1) {
fprintf(stderr, "config file not found %s\n", optarg);
exit(1);
}
break;
case 'h':
usage();
exit(0);
case 'i':
options.interactive = 1;
break;
case 'k':
options.kill = 1;
break;
case 'l':
options.listen = optarg;
options.logfile = optarg;
break;
case 'o':
output = optarg;
break;
case 'O':
{
struct opt_O_t *tmp = malloc(sizeof(*tmp));
if (!tmp) {
fprintf(stderr, "%s\n", strerror(errno));
exit(1);
}
tmp->pathname = strdup(optarg);
tmp->next = NULL;
if (opt_O_last)
opt_O_last->next = tmp;
opt_O_last = tmp;
if (!options.opt_O)
options.opt_O = tmp;
break;
}
case 'n':
options.nocpp = 1;
break;
@ -401,37 +432,10 @@ char **process_options(int argc, char **argv)
case 'P':
options.port = optarg;
break;
case 'u':
options.user = optarg;
break;
case 'V':
printf("mtrace version " PACKAGE_VERSION ".\n"
"Copyright (C) 2015 Stefani Seibold <stefani@seibold.net>.\n"
"\n"
"This software was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany.\n"
"\n"
"This is free software; see the GNU General Public Licence\n"
"version 2 or later for copying conditions. There is NO warranty.\n");
exit(0);
case 'd':
options.bt_depth = parse_int(optarg, 'd', 1, 0);
break;
case 'e':
options.follow_exec = 1;
break;
case 'k':
options.kill = 1;
break;
case 'v':
options.verbose++;
break;
case 'w':
options.wait = 1;
case 'r':
options.address = optarg;
break;
case 's':
options.server = 1;
break;
case 'S':
if (!strncmp(optarg, "allocations", 2))
options.sort_by = OPT_SORT_ALLOCATIONS;
else
@ -460,6 +464,27 @@ char **process_options(int argc, char **argv)
exit(1);
}
break;
case 't':
options.trace = 1;
break;
case 'u':
options.user = optarg;
break;
case 'V':
printf("mtrace version " PACKAGE_VERSION ".\n"
"Copyright (C) 2015 Stefani Seibold <stefani@seibold.net>.\n"
"\n"
"This software was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany.\n"
"\n"
"This is free software; see the GNU General Public Licence\n"
"version 2 or later for copying conditions. There is NO warranty.\n");
exit(0);
case 'v':
options.verbose++;
break;
case 'w':
options.wait = 1;
break;
default:
err_usage();
}
@ -471,68 +496,118 @@ char **process_options(int argc, char **argv)
if (argc > 0)
options.command = search_for_command(argv[0]);
if (options.sort_by == OPT_SORT_LEAKS || options.sort_by == OPT_SORT_BYTES_LEAKED)
options.auto_scan = 1;
if (!options.client && !options.opt_p && argc < 1) {
fprintf(stderr, "%s: too few arguments\n", progname);
if (options.address && options.logfile) {
fprintf(stderr, "%s: either logfile or remote address is valid\n", progname);
err_usage();
}
if (!options.server && options.listen) {
fprintf(stderr, "%s: listen mode can only valid in server mode\n", progname);
err_usage();
}
if (options.trace) {
if (!options.opt_p && !options.command) {
fprintf(stderr, "%s: trace requires -p or executable\n", progname);
err_usage();
}
if (options.client && (options.opt_p || argc > 0)) {
fprintf(stderr, "%s: client mode does not require -p nor executable\n", progname);
err_usage();
}
if (options.auto_scan) {
fprintf(stderr, "%s: scan option can not passed in when trace mode\n", progname);
err_usage();
}
if (options.client && options.nocpp) {
fprintf(stderr, "%s: client mode does not require -n\n", progname);
err_usage();
}
if (options.sort_by != -1) {
fprintf(stderr, "%s: sort-by can not passed in trace mode\n", progname);
err_usage();
}
if (options.client && options.server) {
fprintf(stderr, "%s: choose between client and server mode\n", progname);
err_usage();
}
if (options.opt_b) {
fprintf(stderr, "%s: binpath can only used in client mode\n", progname);
err_usage();
}
if (options.opt_b && !options.client) {
fprintf(stderr, "%s: binpath can only used in client mode\n", progname);
err_usage();
if (options.address) {
if (!strcmp(options.address, "."))
options.address = sockdef;
options.server = 1;
}
}
else {
if (options.opt_p || options.command) {
fprintf(stderr, "%s: client mode does not require -p nor executable\n", progname);
err_usage();
}
if (options.nocpp) {
fprintf(stderr, "%s: client mode does not require -n\n", progname);
err_usage();
}
if (options.user) {
fprintf(stderr, "%s: user can only passed in trace mode\n", progname);
err_usage();
}
if (!options.address)
options.address = sockdef;
}
if (options.interactive) {
if ((!options.client && !options.opt_p) || options.command) {
fprintf(stderr, "%s: interactive mode can only invoked in -p or -c mode\n", progname);
if (options.server) {
fprintf(stderr, "%s: interactive mode not available in server mode\n", progname);
err_usage();
}
output = NULL;
if (options.auto_scan)
if (options.trace) {
if (options.command) {
fprintf(stderr, "%s: cannot execute process and interactive console at the same time in trace mode\n", progname);
err_usage();
}
if (!options.opt_p) {
fprintf(stderr, "%s: interactive console requieres -p in trace mode\n", progname);
err_usage();
}
}
if (options.auto_scan) {
fprintf(stderr, "%s: auto scan ignored in interactive mode\n", progname);
options.auto_scan = 0;
}
if (options.sort_by != -1) {
fprintf(stderr, "%s: sort-by ignored in interactive mode\n", progname);
options.sort_by = -1;
}
}
if (options.auto_scan && options.server) {
fprintf(stderr, "%s: scan option can not passed in -s mode\n", progname);
err_usage();
if (output) {
if (options.interactive) {
fprintf(stderr, "%s: output not valid in interactive mode\n", progname);
err_usage();
}
if (options.logfile) {
fprintf(stderr, "%s: either logfile or output is valid\n", progname);
err_usage();
}
if (options.server) {
fprintf(stderr, "%s: output not valid in server mode\n", progname);
err_usage();
}
}
if (options.port) {
if (!options.client && !options.server) {
fprintf(stderr, "%s: Port only valid in client or server mode \n", progname);
if (!options.address) {
fprintf(stderr, "%s: port only valid in client or trace mode\n", progname);
err_usage();
}
}
else
options.port = STR(DEFAULT_PORT);
if (options.sort_by != -1 && options.server) {
fprintf(stderr, "%s: sort-by can not passed in -s mode\n", progname);
err_usage();
}
if (options.sort_by == OPT_SORT_LEAKS || options.sort_by == OPT_SORT_BYTES_LEAKED)
options.auto_scan = 1;
if (options.bt_depth < MIN_STACK)
options.bt_depth = MIN_STACK;
@ -554,6 +629,15 @@ char **process_options(int argc, char **argv)
fcntl(fileno(options.output), F_SETFD, FD_CLOEXEC);
}
if (cwd) {
options.cwd = open(cwd, O_RDONLY|O_DIRECTORY);
if (options.cwd == -1) {
fprintf(stderr, "%s: `%s' %s\n", progname, optarg, strerror(errno));
exit(1);
}
}
return &argv[0];
}

View File

@ -55,6 +55,11 @@ struct opt_b_t {
struct opt_b_t *next;
};
struct opt_O_t {
char *pathname;
struct opt_O_t *next;
};
struct options_t {
int auto_scan; /* scan memory on every exit of a trace program */
int bt_depth; /* how may levels of stack frames to show */
@ -62,10 +67,11 @@ struct options_t {
int follow_exec; /* follow exec system calls */
int interactive; /* interactive mode */
FILE *output; /* output to a specific file */
int server; /* server mode flag */
int trace; /* trace mode flag */
int kill; /* kill on errors */
char *listen; /* server listen on socket path or address */
char *client; /* connect to socket path or address */
int server; /* true for server listen */
char *logfile; /* logfile path */
char *address; /* connect to socket path or address */
char *user; /* -u: username to run command as */
int verbose; /* verbose mode */
int wait; /* wait for client connection */
@ -75,6 +81,7 @@ struct options_t {
struct opt_p_t *opt_p; /* attach to process with a given pid */
struct opt_F_t *opt_F; /* alternate configuration file(s) */
struct opt_b_t *opt_b; /* binary search path(s) */
struct opt_O_t *opt_O; /* omits path list */
int sort_by; /* sort dump in non interative and non server mode */
int debug; /* debug */
int nocpp; /* disable trace of c++ allocation operators */

153
report.c
View File

@ -25,6 +25,9 @@
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "backend.h"
#include "backtrace.h"
@ -38,25 +41,32 @@
#include "task.h"
#include "trace.h"
static int report_alloc64(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth)
static int report_alloc64(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, unsigned int depth, struct library_symbol *libsym)
{
int i = 0;
unsigned int i = 0;
struct mt_alloc_payload_64 *alloc = alloca(sizeof(*alloc) + depth * sizeof(uint64_t));
alloc->ptr = (uint64_t)ptr;
alloc->size = (uint64_t)size;
if (depth && backtrace_init_unwind(task) >= 0) {
do {
alloc->data[i] = (uint64_t)backtrace_get_ip(task);
if (!alloc->data[i])
break;
if (depth) {
alloc->data[i++] = libsym->addr;
++i;
if (backtrace_init_unwind(task) >= 0) {
while(i < depth) {
if (backtrace_location_type(task) != LIBTYPE_LOADER) {
alloc->data[i] = (uint64_t)backtrace_get_ip(task);
if (backtrace_step(task) < 0)
break;
} while(i < depth);
if (!alloc->data[i])
break;
++i;
}
if (backtrace_step(task) < 0)
break;
}
}
}
skip_breakpoint(task, task->event.e_un.breakpoint);
@ -64,7 +74,7 @@ static int report_alloc64(struct task *task, enum mt_operation op, unsigned long
return server_send_msg(op, task->leader->pid, task->pid, alloc, sizeof(*alloc) + i * sizeof(uint64_t));
}
static int report_alloc32(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth)
static int report_alloc32(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth, struct library_symbol *libsym)
{
int i = 0;
struct mt_alloc_payload_32 *alloc = alloca(sizeof(*alloc) + depth * sizeof(uint32_t));
@ -72,17 +82,24 @@ static int report_alloc32(struct task *task, enum mt_operation op, unsigned long
alloc->ptr = (uint32_t)ptr;
alloc->size = (uint32_t)size;
if (depth && backtrace_init_unwind(task) >= 0) {
do {
alloc->data[i] = (uint32_t)backtrace_get_ip(task);
if (!alloc->data[i])
break;
if (depth) {
alloc->data[i++] = libsym->addr;
++i;
if (backtrace_init_unwind(task) >= 0) {
while(i < depth) {
if (backtrace_location_type(task) != LIBTYPE_LOADER) {
alloc->data[i] = (uint32_t)backtrace_get_ip(task);
if (backtrace_step(task) < 0)
break;
} while(i < depth);
if (!alloc->data[i])
break;
++i;
}
if (backtrace_step(task) < 0)
break;
}
}
}
skip_breakpoint(task, task->event.e_un.breakpoint);
@ -90,7 +107,7 @@ static int report_alloc32(struct task *task, enum mt_operation op, unsigned long
return server_send_msg(op, task->leader->pid, task->pid, alloc, sizeof(*alloc) + i * sizeof(uint32_t));
}
static int report_alloc(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth)
static int report_alloc(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth, struct library_symbol *libsym)
{
if (!ptr)
return 0;
@ -101,9 +118,9 @@ static int report_alloc(struct task *task, enum mt_operation op, unsigned long p
debug(DEBUG_FUNCTION, "%d [%d]: %#lx %lu", op, task->pid, ptr, size);
if (task_is_64bit(task))
return report_alloc64(task, op, ptr, size, depth);
return report_alloc64(task, op, ptr, size, depth, libsym);
else
return report_alloc32(task, op, ptr, size, depth);
return report_alloc32(task, op, ptr, size, depth, libsym);
}
static int _null(struct task *task, struct library_symbol *libsym)
@ -119,7 +136,7 @@ static int _report_malloc(struct task *task, struct library_symbol *libsym)
unsigned long size = fetch_param(task, 0);
unsigned long ret = fetch_retval(task);
return report_alloc(task, MT_MALLOC, ret, size, options.bt_depth);
return report_alloc(task, MT_MALLOC, ret, size, options.bt_depth, libsym);
}
static int report_free(struct task *task, struct library_symbol *libsym)
@ -129,7 +146,7 @@ static int report_free(struct task *task, struct library_symbol *libsym)
unsigned long addr = fetch_param(task, 0);
return report_alloc(task, MT_FREE, addr, 0, 0);
return report_alloc(task, MT_FREE, addr, 0, 0, libsym);
}
static int _report_realloc(struct task *task, struct library_symbol *libsym)
@ -142,9 +159,9 @@ static int _report_realloc(struct task *task, struct library_symbol *libsym)
unsigned long ret = fetch_retval(task);
if (ret)
return report_alloc(task, MT_REALLOC, ret, size, options.bt_depth);
return report_alloc(task, MT_REALLOC, ret, size, options.bt_depth, libsym);
else
return report_alloc(task, MT_REALLOC_FAILED, addr, 1, options.bt_depth);
return report_alloc(task, MT_REALLOC_FAILED, addr, 1, options.bt_depth, libsym);
}
static int report_realloc(struct task *task, struct library_symbol *libsym)
@ -155,7 +172,7 @@ static int report_realloc(struct task *task, struct library_symbol *libsym)
unsigned long addr = fetch_param(task, 0);
unsigned long size = fetch_param(task, 1);
return report_alloc(task, MT_REALLOC_ENTER, addr, size, options.bt_depth);
return report_alloc(task, MT_REALLOC_ENTER, addr, size, options.bt_depth, libsym);
}
static int _report_calloc(struct task *task, struct library_symbol *libsym)
@ -166,7 +183,7 @@ static int _report_calloc(struct task *task, struct library_symbol *libsym)
unsigned long size = fetch_param(task, 0) * fetch_param(task, 1);
unsigned long ret = fetch_retval(task);
return report_alloc(task, MT_MALLOC, ret, size, options.bt_depth);
return report_alloc(task, MT_MALLOC, ret, size, options.bt_depth, libsym);
}
static int _report_mmap(struct task *task, struct library_symbol *libsym)
@ -181,7 +198,7 @@ static int _report_mmap(struct task *task, struct library_symbol *libsym)
unsigned long size = fetch_param(task, 1);
return report_alloc(task, MT_MMAP, ret, size, options.bt_depth);
return report_alloc(task, MT_MMAP, ret, size, options.bt_depth, libsym);
}
static int _report_mmap64(struct task *task, struct library_symbol *libsym)
@ -211,7 +228,7 @@ static int _report_mmap64(struct task *task, struct library_symbol *libsym)
else
size.l = fetch_param(task, 1);
return report_alloc(task, MT_MMAP64, ret, size.l, options.bt_depth);
return report_alloc(task, MT_MMAP64, ret, size.l, options.bt_depth, libsym);
}
static int report_munmap(struct task *task, struct library_symbol *libsym)
@ -222,7 +239,7 @@ static int report_munmap(struct task *task, struct library_symbol *libsym)
unsigned long addr = fetch_param(task, 0);
unsigned long size = fetch_param(task, 1);
return report_alloc(task, MT_MUNMAP, addr, size, 0);
return report_alloc(task, MT_MUNMAP, addr, size, 0, libsym);
}
static int _report_memalign(struct task *task, struct library_symbol *libsym)
@ -233,7 +250,7 @@ static int _report_memalign(struct task *task, struct library_symbol *libsym)
unsigned long size = fetch_param(task, 1);
unsigned long ret = fetch_retval(task);
return report_alloc(task, MT_MEMALIGN, ret, size, options.bt_depth);
return report_alloc(task, MT_MEMALIGN, ret, size, options.bt_depth, libsym);
}
static int _report_posix_memalign(struct task *task, struct library_symbol *libsym)
@ -260,7 +277,7 @@ static int _report_posix_memalign(struct task *task, struct library_symbol *libs
new_ptr = tmp;
}
return report_alloc(task, MT_POSIX_MEMALIGN, new_ptr, size, options.bt_depth);
return report_alloc(task, MT_POSIX_MEMALIGN, new_ptr, size, options.bt_depth, libsym);
}
static int _report_aligned_alloc(struct task *task, struct library_symbol *libsym)
@ -271,7 +288,7 @@ static int _report_aligned_alloc(struct task *task, struct library_symbol *libsy
unsigned long size = fetch_param(task, 1);
unsigned long ret = fetch_retval(task);
return report_alloc(task, MT_ALIGNED_ALLOC, ret, size, options.bt_depth);
return report_alloc(task, MT_ALIGNED_ALLOC, ret, size, options.bt_depth, libsym);
}
static int _report_valloc(struct task *task, struct library_symbol *libsym)
@ -282,7 +299,7 @@ static int _report_valloc(struct task *task, struct library_symbol *libsym)
unsigned long size = fetch_param(task, 0);
unsigned long ret = fetch_retval(task);
return report_alloc(task, MT_VALLOC, ret, size, options.bt_depth);
return report_alloc(task, MT_VALLOC, ret, size, options.bt_depth, libsym);
}
static int _report_pvalloc(struct task *task, struct library_symbol *libsym)
@ -293,7 +310,7 @@ static int _report_pvalloc(struct task *task, struct library_symbol *libsym)
unsigned long size = fetch_param(task, 0);
unsigned long ret = fetch_retval(task);
return report_alloc(task, MT_PVALLOC, ret, size, options.bt_depth);
return report_alloc(task, MT_PVALLOC, ret, size, options.bt_depth, libsym);
}
static int report_mremap(struct task *task, struct library_symbol *libsym)
@ -301,7 +318,7 @@ static int report_mremap(struct task *task, struct library_symbol *libsym)
unsigned long addr = fetch_param(task, 0);
unsigned long size = fetch_param(task, 1);
return report_alloc(task, MT_MUNMAP, addr, size, 0);
return report_alloc(task, MT_MUNMAP, addr, size, 0, libsym);
}
static int _report_mremap(struct task *task, struct library_symbol *libsym)
@ -309,33 +326,33 @@ static int _report_mremap(struct task *task, struct library_symbol *libsym)
unsigned long size = fetch_param(task, 2);
unsigned long ret = fetch_retval(task);
return report_alloc(task, MT_MMAP, ret, size, options.bt_depth);
return report_alloc(task, MT_MMAP, ret, size, options.bt_depth, libsym);
}
static const struct function flist[] = {
{ "malloc", 0, 2, NULL, _report_malloc },
{ "free", 0, 3, report_free, NULL },
{ "realloc", 0, 4, report_realloc, _report_realloc },
{ "calloc", 0, 5, NULL, _report_calloc },
{ "posix_memalign", 0, 6, NULL, _report_posix_memalign },
{ "mmap", 0, 7, NULL, _report_mmap },
{ "mmap64", 1, 8, NULL, _report_mmap64 },
{ "munmap", 0, 9, report_munmap, _null },
{ "memalign", 0, 10, NULL, _report_memalign },
{ "aligned_alloc", 1, 11, NULL, _report_aligned_alloc },
{ "valloc", 1, 12, NULL, _report_valloc },
{ "pvalloc", 1, 13, NULL, _report_pvalloc },
{ "mremap", 0, 14, report_mremap, _report_mremap },
{ "cfree", 1, 15, report_free, NULL },
{ "malloc", "malloc", 0, NULL, _report_malloc },
{ "free", "free", 0, report_free, NULL },
{ "realloc", "realloc", 0, report_realloc, _report_realloc },
{ "calloc", "calloc", 0, NULL, _report_calloc },
{ "posix_memalign", "posix_memalign", 0, NULL, _report_posix_memalign },
{ "mmap", "mmap", 0, NULL, _report_mmap },
{ "mmap64", "mmap64", 1, NULL, _report_mmap64 },
{ "munmap", "munmap", 0, report_munmap, _null },
{ "memalign", "memalign", 0, NULL, _report_memalign },
{ "aligned_alloc", "aligned_alloc", 1, NULL, _report_aligned_alloc },
{ "valloc", "valloc", 1, NULL, _report_valloc },
{ "pvalloc", "pvalloc", 1, NULL, _report_pvalloc },
{ "mremap", "mremap", 0, report_mremap, _report_mremap },
{ "cfree", "cfree", 1, report_free, NULL },
{ "_Znwm", 1, 17, NULL, _report_malloc }, /* operator new(unsigned long) */
{ "_Znam", 1, 18, NULL, _report_malloc }, /* operator new[](unsigned long) */
{ "_ZnwmRKSt9nothrow_t", 1, 19, NULL, _report_malloc }, /* operator new(unsigned long, std::nothrow_t const&) */
{ "_ZnamRKSt9nothrow_t", 1, 20, NULL, _report_malloc }, /* operator new[](unsigned long, std::nothrow_t const& */
{ "_ZdlPv", 1, 21, report_free, NULL }, /* operator delete(void*) */
{ "_ZdaPv", 1, 22, report_free, NULL }, /* operator delete[](void*) */
{ "_ZdlPvRKSt9nothrow_t", 1, 23, report_free, NULL }, /* operator delete(void*, std::nothrow_t const&) */
{ "_ZdaPvRKSt9nothrow_t", 1, 24, report_free, NULL }, /* operator delete[](void*, std::nothrow_t const&) */
{ "new(unsigned long)", "_Znwm", 1, NULL, _report_malloc },
{ "new[](unsigned long)", "_Znam", 1, NULL, _report_malloc },
{ "new(unsigned long, std::nothrow_t const&)", "_ZnwmRKSt9nothrow_t", 1, NULL, _report_malloc },
{ "new[](unsigned long, std::nothrow_t const&)", "_ZnamRKSt9nothrow_t", 1, NULL, _report_malloc },
{ "delete(void*)", "_ZdlPv", 1, report_free, NULL },
{ "delete[](void*)", "_ZdaPv", 1, report_free, NULL },
{ "delete(void*, std::nothrow_t const&)", "_ZdlPvRKSt9nothrow_t", 1, report_free, NULL },
{ "delete[](void*, std::nothrow_t const&)", "_ZdaPvRKSt9nothrow_t", 1, report_free, NULL },
};
const struct function *flist_matches_symbol(const char *sym_name)
@ -354,14 +371,14 @@ const struct function *flist_matches_symbol(const char *sym_name)
int _report_map(struct task *task, struct library *lib, enum mt_operation op)
{
size_t len = strlen(lib->filename) + 1;
struct libref *libref = lib->libref;
size_t len = strlen(libref->filename) + 1;
struct mt_map_payload *payload = alloca(sizeof(struct mt_map_payload) + len);
payload->addr = libref->load_addr;
payload->offset = libref->load_offset;
payload->size = libref->load_size;
payload->addr = lib->load_addr;
payload->offset = lib->load_offset;
payload->size = lib->load_size;
memcpy(payload->filename, lib->filename, len);
memcpy(payload->filename, libref->filename, len);
return server_send_msg(op, task->pid, 0, payload, sizeof(struct mt_map_payload) + len);
}

View File

@ -26,12 +26,12 @@
#include "forward.h"
struct function {
/* symbol name */
const char *demangled_name;
/* symbol name */
const char *name;
/* level for aliased symbol */
unsigned int level;
/* minimum number of hw breakpoints for using a hw bp */
unsigned int hw_bp_min;
/* report when function is entered */
int (*report_in)(struct task *task, struct library_symbol *libsym);
/* report when function is exited */

View File

@ -30,6 +30,7 @@
#include <unistd.h>
#include <sys/sysinfo.h>
#include <semaphore.h>
#include <netinet/tcp.h>
#include "backend.h"
#include "breakpoint.h"
@ -83,10 +84,13 @@ int server_connected(void)
static void server_close(void)
{
if (server_connected()) {
shutdown(server_fd, SHUT_RDWR);
if (!options.logfile)
shutdown(server_fd, SHUT_RDWR);
close(server_fd);
server_fd = -1;
each_process(&stop_trace);
each_pid(&fix_about_exit);
}
}
@ -94,10 +98,11 @@ int server_poll(void)
{
int ret = 0;
if (command_pending) {
ret = server_handle_command();
if (options.server)
if (options.trace)
ret = 0;
command_pending = 0;
@ -119,10 +124,15 @@ int server_handle_command(void)
{
int ret;
struct mt_msg cmd;
void *payload = NULL;
void *payload;
struct task *task;
unsigned int mode = server_mode;
unsigned int mode;
if (options.logfile)
return -1;
payload = NULL;
mode = server_mode;
server_mode = MODE_NONE;
switch(mode) {
@ -154,7 +164,7 @@ int server_handle_command(void)
}
server_close();
return options.server ? 0: -1;
return options.trace ? 0: -1;
}
if (cmd.payload_len) {
@ -250,27 +260,25 @@ int server_start(void)
if (!thread)
return -1;
listen_fd = bind_to(options.listen, options.port);
server_mode = MODE_NONE;
listen_fd = bind_to(options.address, options.port);
if (listen_fd < 0)
fatal("colud not bind socket: %s:%s", options.listen, options.port);
fatal("could not bind socket: %s", options.address);
if (listen(listen_fd, 1) < 0)
fatal("listen (%s)", strerror(errno));
if (options.wait) {
fprintf(stderr, "waiting for client connection...\n");
fprintf(stderr, "waiting for client connection... ");
server_fd = TEMP_FAILURE_RETRY(accept(listen_fd, NULL, 0));
if (server_fd < 0)
fatal("accept (%s)", strerror(errno));
fprintf(stderr, "connected!\n");
server_mode = MODE_ACCEPTED;
report_info(1);
report_processes();
each_process(&start_trace);
}
else {
each_process(&stop_trace);
}
sem_init(&sem, 0, 1);
@ -308,6 +316,9 @@ int server_start_pair(void)
{
int sv[2];
server_mode = MODE_NONE;
listen_fd = -1;
thread = thread_new();
if (!thread)
return -1;
@ -332,20 +343,45 @@ int server_start_pair(void)
int server_send_msg(enum mt_operation op, uint32_t pid, uint32_t tid, const void *payload, unsigned int payload_len)
{
if (options.logfile) {
struct iovec io[2];
struct mt_msg mt_msg;
int ret;
mt_msg.operation = op;
mt_msg.pid = pid;
mt_msg.tid = tid;
mt_msg.payload_len = payload_len;
io[0].iov_base = &mt_msg;
io[0].iov_len = sizeof(mt_msg);
io[1].iov_base = (void *)payload;
io[1].iov_len = payload_len;
ret = writev(server_fd, io, ARRAY_SIZE(io));
if ((size_t)ret != io[0].iov_len + io[1].iov_len)
return -1;
return ret;
}
return sock_send_msg(server_fd, op, pid, tid, payload, payload_len);
}
int server_stop(void)
{
thread_cancel(thread);
if (thread)
thread_join(thread);
server_close();
if (listen_fd != -1) {
if (is_named(options.listen))
unlink(options.listen);
thread_cancel(thread);
if (thread)
thread_join(thread);
if (is_named(options.address))
unlink(options.address);
close(listen_fd);
listen_fd = -1;
}
@ -353,3 +389,14 @@ int server_stop(void)
return 0;
}
int server_logfile(void)
{
listen_fd = -1;
server_fd = open(options.logfile, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
if (server_fd == -1)
fatal("could not open logfile: %s", options.logfile);
return 0;
}

View File

@ -34,6 +34,7 @@ int server_handle_command(void);
int server_connected(void);
int server_stop(void);
int server_poll(void);
int server_logfile(void);
#endif

View File

@ -176,12 +176,12 @@ static inline int access_mem(struct dwarf_addr_space *as, arch_addr_t addr, void
#ifdef DEBUG
if (as) {
struct dwarf_cursor *c = &as->cursor;
struct library *lib = c->lib;
struct libref *libref = c->libref;
if (addr < ARCH_ADDR_T(lib->image_addr))
fatal("invalid access mem: addr %#lx < %p", addr, lib->image_addr);
if (addr >= ARCH_ADDR_T(lib->image_addr + lib->load_size))
fatal("invalid access mem: addr %#lx >= %p", addr, lib->image_addr + lib->load_size);
if (addr < ARCH_ADDR_T(libref->image_addr))
fatal("invalid access mem: addr %#lx < %p", addr, libref->image_addr);
if (addr >= ARCH_ADDR_T(libref->image_addr + libref->load_size))
fatal("invalid access mem: addr %#lx >= %p", addr, libref->image_addr + libref->load_size);
}
#endif
@ -506,8 +506,8 @@ static int arm_exidx_extract(struct dwarf_addr_space *as, arch_addr_t entry, uin
static unsigned long arm_search_unwind_table(struct dwarf_addr_space *as, arch_addr_t ip, void *exidx_data, unsigned long exidx_len)
{
struct dwarf_cursor *c = &as->cursor;
struct library *lib = c->lib;
unsigned long map_offset = (unsigned long)lib->image_addr + lib->load_offset - lib->load_addr;
struct libref *libref = c->libref;
unsigned long map_offset = (unsigned long)libref->image_addr + libref->load_offset - libref->load_addr;
unsigned long lo, hi, e, f;
arch_addr_t val;
@ -542,12 +542,12 @@ static unsigned long arm_search_unwind_table(struct dwarf_addr_space *as, arch_a
static int arm_exidx_step(struct dwarf_addr_space *as)
{
struct dwarf_cursor *c = &as->cursor;
struct library *lib = c->lib;
struct libref *libref = c->libref;
arch_addr_t old_ip, old_cfa, entry;
uint8_t buf[32];
int ret;
if (!lib)
if (!libref)
return -DWARF_ENOINFO;
old_ip = c->ip;
@ -556,7 +556,7 @@ static int arm_exidx_step(struct dwarf_addr_space *as)
/* mark PC unsaved */
c->loc[DWARF_ARM_PC] = DWARF_NULL_LOC;
entry = arm_search_unwind_table(as, c->ip, lib->exidx_data, lib->exidx_len);
entry = arm_search_unwind_table(as, c->ip, libref->exidx_data, libref->exidx_len);
if (!entry)
return -DWARF_ENOINFO;
@ -646,3 +646,8 @@ int dwarf_arch_step(struct dwarf_addr_space *as)
return -DWARF_EBADFRAME;
}
int dwarf_arch_check_call(struct dwarf_addr_space *as, arch_addr_t ip)
{
return 1;
}

View File

@ -72,3 +72,11 @@ int backtrace_step(struct task *task)
return dwarf_step(task->leader->backtrace);
}
int backtrace_location_type(struct task *task)
{
assert(task->leader);
assert(task->leader->backtrace);
return dwarf_location_type(task->leader->backtrace);
}

View File

@ -24,6 +24,7 @@
#include <errno.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

View File

@ -269,3 +269,8 @@ unsigned int dwarf_to_regnum(unsigned int num)
return ~0;
}
int dwarf_arch_check_call(struct dwarf_addr_space *as, arch_addr_t ip)
{
return 1;
}

View File

@ -413,22 +413,22 @@ static void linkmap_add(struct task *task, struct lt_r_debug_64 *dbg)
)
continue;
struct library *lib = library_new();
struct libref *libref = libref_new(LIBTYPE_LIB);
if (!lib) {
if (!libref) {
fprintf(stderr, "Couldn't instance library object %s\n", lib_name);
continue;
}
if (elf_read_library(task, lib, lib_name, rlm.l_addr) < 0) {
library_destroy(task, lib);
if (elf_read_library(task, libref, lib_name, rlm.l_addr) < 0) {
libref_delete(libref);
fprintf(stderr, "Couldn't load ELF object %s\n", lib_name);
continue;
}
lib->key = ARCH_ADDR_T(rlm.l_addr);
libref->key = ARCH_ADDR_T(rlm.l_addr);
library_add(task, lib);
library_add(task, libref);
}
return;

View File

@ -113,13 +113,16 @@ int sock_send_msg(int fd, enum mt_operation op, uint32_t pid, uint32_t tid, cons
return ret;
}
static int sock_unix(const char *path, struct sock_u_descr *descr)
static int sock_unix(const char *path, struct sock_u_descr *descr, int create)
{
struct stat statbuf;
if (stat(path, &statbuf) >= 0) {
if (!S_ISSOCK(statbuf.st_mode))
return -1;
if (create)
unlink(path);
}
descr->addr.sun_family = AF_UNIX;
@ -160,7 +163,7 @@ int connect_to(const char *node, const char *service)
if (*node == '/' || *node == '.') {
struct sock_u_descr descr;
sfd = sock_unix(node, &descr);
sfd = sock_unix(node, &descr, 0);
if (sfd == -1)
return -1;
@ -201,7 +204,7 @@ int bind_to(const char *node, const char *service)
if (is_named(node)) {
struct sock_u_descr descr;
sfd = sock_unix(node, &descr);
sfd = sock_unix(node, &descr, 1);
if (sfd == -1)
return -1;
@ -218,6 +221,9 @@ int bind_to(const char *node, const char *service)
if (sfd == -1)
continue;
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1)))
fatal("setsockopt (%s)", strerror(errno));
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
break;
@ -228,9 +234,6 @@ int bind_to(const char *node, const char *service)
return -1;
}
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1)))
fatal("setsockopt (%s)", strerror(errno));
return sfd;
}

View File

@ -37,6 +37,7 @@
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/prctl.h>
#include <sys/uio.h>
#ifdef HAVE_LIBSELINUX
#include <selinux/selinux.h>
@ -124,7 +125,7 @@ static int child_event(struct task *task, enum event_type ev)
int pid = data;
if (!pid2task(pid)) {
struct task *child = task_new(pid, 0);
struct task *child = task_new(pid);
if (!child)
return -1;
@ -235,7 +236,7 @@ static void process_event(struct task *task, int status)
if (stop_signal == 0)
return;
if (stop_signal != SIGTRAP && stop_signal != SIGSEGV && stop_signal != SIGILL)
if (stop_signal != SIGTRAP)
return;
if (fetch_context(task) == -1) {
@ -251,14 +252,15 @@ static void process_event(struct task *task, int status)
for(i = 0; i < HW_BREAKPOINTS; ++i) {
if (task->hw_bp[i] && task->hw_bp[i]->addr == ip) {
/* todo: check if this was really a hw bp */
bp = task->hw_bp[i];
if (get_hw_bp_state(task, i))
bp = task->hw_bp[i];
break;
}
}
if (bp) {
assert(bp->type != SW_BP);
assert(bp->type != BP_SW);
assert(bp->hw_bp_slot == i);
if (options.verbose > 1)
@ -268,9 +270,15 @@ static void process_event(struct task *task, int status)
#endif
{
bp = breakpoint_find(leader, ip - DECR_PC_AFTER_BREAK);
if (!bp)
if (!bp) {
task->event.type = EVENT_NONE;
continue_task(task, 0);
return;
assert(bp->type == SW_BP);
}
#if HW_BREAKPOINTS > 0
assert(bp->type != BP_HW_SCRATCH);
assert(bp->hw == 0);
#endif
if (options.verbose > 1)
++leader->num_sw_bp;
@ -284,7 +292,7 @@ static void process_event(struct task *task, int status)
return;
#endif
task->event.type = EVENT_BREAKPOINT;
task->event.e_un.breakpoint = breakpoint_ref(bp);
task->event.e_un.breakpoint = breakpoint_get(bp);
debug(DEBUG_EVENT, "BREAKPOINT: pid=%d, addr=%#lx", task->pid, task->event.e_un.breakpoint->addr);
@ -344,7 +352,6 @@ int untrace_task(struct task *task, int signum)
fprintf(stderr, "PTRACE_SETOPTIONS pid=%d %s\n", task->pid, strerror(errno));
ret = -1;
goto skip;
}
signum = fix_signal(task, signum);
@ -525,7 +532,7 @@ struct task *wait_event(void)
task = pid2task(pid);
if (!task) {
task = task_new(pid, 0);
task = task_new(pid);
if (task)
trace_setup(task, status, SIGSTOP);
@ -552,16 +559,53 @@ void wait_event_wakeup(void)
pthread_mutex_unlock(&mutex);
}
#ifndef HAVE_PROCESS_VM_READV
static ssize_t process_vm_readv(pid_t pid, const struct iovec *local_iov, unsigned long liovcnt, const struct iovec *remote_iov, unsigned long riovcnt, unsigned long flags)
{
#ifdef __NR_process_vm_readv
return syscall(__NR_process_vm_readv, pid, local_iov, liovcnt, remote_iov, riovcnt, flags);
#else
errno = ENOSYS;
return -1;
#endif
}
#endif
ssize_t copy_from_proc(struct task *task, arch_addr_t addr, void *dst, size_t len)
{
static int process_vm_call_nosys;
ssize_t num_bytes;
size_t n;
union {
long a;
char c[sizeof(long)];
} a;
ssize_t num_bytes = 0;
size_t n = sizeof(a.a);
if (len > sizeof(a) && !process_vm_call_nosys) {
struct iovec local[1];
struct iovec remote[1];
local[0].iov_base = dst;
local[0].iov_len = len;
remote[0].iov_base = (void *)addr;
remote[0].iov_len = len;
num_bytes = process_vm_readv(task->pid, local, 1, remote, 1, 0);
if (num_bytes != -1)
return num_bytes;
if (errno != EFAULT) {
if (errno != ENOSYS) {
fprintf(stderr, "%s pid=%d process_vm_readv: %s\n", __FUNCTION__, task->pid, strerror(errno));
return -1;
}
process_vm_call_nosys = 1;
}
}
num_bytes = 0;
n = sizeof(a.a);
errno = 0;
while (len) {
@ -589,13 +633,15 @@ ssize_t copy_from_proc(struct task *task, arch_addr_t addr, void *dst, size_t le
ssize_t copy_to_proc(struct task *task, arch_addr_t addr, const void *src, size_t len)
{
ssize_t num_bytes;
size_t n;
union {
long a;
char c[sizeof(long)];
} a;
ssize_t num_bytes = 0;
size_t n = sizeof(a.a);
num_bytes = 0;
n = sizeof(a.a);
while (len) {
if (n > len) {

View File

@ -37,6 +37,21 @@
#define BP_RW 2
#define BP_W 4
int get_hw_bp_state(struct task *task, unsigned int n)
{
long ret;
errno = 0;
ret = ptrace(PTRACE_PEEKUSER, task->pid, offsetof(struct user, u_debugreg[6]), 0);
if (ret == -1 && errno) {
if (errno != ESRCH)
fprintf(stderr, "PTRACE_PEEKUSER u_debugreg[6] pid=%d %s\n", task->pid, strerror(errno));
return 0;
}
return (ret & (1 << n)) != 0;
}
static int _apply_hw_bp(struct task *task, uint32_t dr7)
{
long ret;

View File

@ -28,6 +28,7 @@
#include <stddef.h>
#include <sys/user.h>
#include <sys/ptrace.h>
#include <linux/unistd.h>
#define BREAKPOINT_VALUE { 0xcc }
#define BREAKPOINT_LENGTH 1
@ -40,8 +41,21 @@
#ifdef __x86_64__
#define MT_ELFCLASS2 ELFCLASS64
#define MT_ELF_MACHINE2 EM_X86_64
#ifndef __NR_process_vm_readv
#define __NR_process_vm_readv 310
#endif
#else /* __x86_64__ */
#ifndef __NR_process_vm_readv
#define __NR_process_vm_readv 347
#endif
#endif /* __x86_64__ */
#define GUESS_CALLER
#define HW_BREAKPOINTS 4
#define TASK_HAVE_PROCESS_DATA

View File

@ -31,6 +31,7 @@
#include "backend.h"
#include "debug.h"
#include "dwarf.h"
#include "library.h"
#include "task.h"
struct arch_reg {
@ -266,7 +267,7 @@ int dwarf_arch_step(struct dwarf_addr_space *as)
c->loc[arch_reg->bp] = DWARF_MEM_LOC(rbp);
c->loc[arch_reg->ip] = DWARF_MEM_LOC(rbp + DWARF_ADDR_SIZE(as));
c->cfa = rbp + DWARF_ADDR_SIZE(as) * 2;
c->use_prev_instr = 1;
c->use_prev_instr = 0;
}
}
@ -304,3 +305,45 @@ int dwarf_arch_map_reg(struct dwarf_addr_space *as, unsigned int reg)
return dwarf_to_regnum_map32[reg];
}
static struct call_op {
unsigned int off;
unsigned int len;
unsigned char *mask;
unsigned char *op;
} call_op[] =
{
{ 5, 1, (unsigned char [1]){ 0xff }, (unsigned char [1]){ 0xe8 } }, /* call */
{ 3, 2, (unsigned char [2]){ 0xff, 0xff }, (unsigned char [2]){ 0xff, 0x14 } }, /* call *(sp) */
{ 2, 2, (unsigned char [2]){ 0xff, 0xfc }, (unsigned char [2]){ 0xff, 0x10 } }, /* call *(reg) */
{ 4, 2, (unsigned char [2]){ 0xff, 0xff }, (unsigned char [2]){ 0xff, 0x54 } }, /* call *off8(reg, idx, scale) */
{ 3, 2, (unsigned char [2]){ 0xff, 0xfc }, (unsigned char [2]){ 0xff, 0x50 } }, /* call *off8 */
{ 7, 2, (unsigned char [2]){ 0xff, 0xff }, (unsigned char [2]){ 0xff, 0x94 } }, /* call *off32(reg, idx, scale) */
{ 6, 2, (unsigned char [2]){ 0xff, 0xfc }, (unsigned char [2]){ 0xff, 0x90 } }, /* call *off32 */
{ 2, 2, (unsigned char [2]){ 0xff, 0xfc }, (unsigned char [2]){ 0xff, 0xd0 } }, /* call *reg */
{ 0 }
};
int dwarf_arch_check_call(struct dwarf_addr_space *as, arch_addr_t ip)
{
static struct call_op *p;
struct dwarf_cursor *c = &as->cursor;
struct libref *libref = c->libref;
for(p = call_op; p->len; ++p) {
if (ip - ARCH_ADDR_T(libref->load_addr) >= p->off) {
unsigned int i;
unsigned char *addr = libref->image_addr + ip - p->off - libref->load_addr;
for(i = 0; i < call_op[i].len; ++i) {
if ((addr[i] & p->mask[i]) != p->op[i])
break;
}
if (i == p->len)
return 1;
}
}
return 0;
}

60
task.c
View File

@ -42,6 +42,7 @@
#include "library.h"
#include "mtelf.h"
#include "report.h"
#include "server.h"
#include "task.h"
#include "trace.h"
@ -130,7 +131,7 @@ static int leader_setup(struct task *leader)
return backtrace_init(leader);
}
static int task_init(struct task *task, int attached)
static int task_init(struct task *task)
{
pid_t tgid;
@ -163,7 +164,7 @@ static int task_init(struct task *task, int attached)
list_add_tail(&task->task_list, &task->leader->task_list);
}
task->attached = attached;
task->attached = 1;
if (arch_task_init(task) < 0)
return -1;
@ -171,6 +172,8 @@ static int task_init(struct task *task, int attached)
if (os_task_init(task) < 0)
return -1;
breakpoint_hw_destroy(task);
return 0;
}
@ -186,6 +189,8 @@ static int leader_cleanup(struct task *leader)
breakpoint_clear_all(leader);
backtrace_destroy(leader);
list_del(&leader->leader_list);
return 1;
}
@ -194,7 +199,6 @@ static void leader_release(struct task *leader)
if (!leader_cleanup(leader))
return;
list_del(&leader->leader_list);
free(leader);
}
@ -220,7 +224,7 @@ static void task_destroy(struct task *task)
leader_release(leader);
}
struct task *task_new(pid_t pid, int traced)
struct task *task_new(pid_t pid)
{
struct task *task = malloc(sizeof(*task));
@ -230,16 +234,19 @@ struct task *task_new(pid_t pid, int traced)
memset(task, 0, sizeof(*task));
task->pid = pid;
task->traced = traced;
task->stopped = traced;
task->traced = 0;
task->stopped = 0;
task->was_stopped = 0;
INIT_LIST_HEAD(&task->task_list);
INIT_LIST_HEAD(&task->leader_list);
#if HW_BREAKPOINTS > 1
INIT_LIST_HEAD(&task->hw_bp_list);
#endif
library_setup(task);
if (task_init(task, 1) < 0)
if (task_init(task) < 0)
goto fail1;
init_event(task);
@ -257,7 +264,7 @@ static void remove_task_cb(struct task *task, void *data)
if (task != data) {
debug(DEBUG_FUNCTION, "clear pid=%d from leader pid=%d", task->pid, task->leader->pid);
remove_task(task);
task_destroy(task);
}
}
@ -265,21 +272,23 @@ int process_exec(struct task *task)
{
struct task *leader = task->leader;
leader->threads_stopped--;
breakpoint_disable_all(leader);
each_task(leader, &remove_task_cb, leader);
breakpoint_disable_all(leader);
os_task_destroy(leader);
arch_task_destroy(leader);
leader_cleanup(leader);
if (task_init(leader, 0) < 0)
assert(leader->threads == 0);
if (task_init(leader) < 0)
goto fail;
assert(leader->leader == leader);
if (server_connected())
task->attached = 0;
leader->threads_stopped++;
assert(leader->leader == leader);
assert(leader->threads_stopped == 1);
if (leader_setup(leader) < 0)
goto fail;
@ -311,7 +320,7 @@ struct task *task_create(const char *command, char **argv)
_exit(EXIT_FAILURE);
}
task = task_new(pid, 0);
task = task_new(pid);
if (!task)
goto fail2;
@ -321,6 +330,9 @@ struct task *task_create(const char *command, char **argv)
if (trace_set_options(task) < 0)
goto fail2;
if (server_connected())
task->attached = 0;
if (leader_setup(task) < 0)
goto fail1;
@ -344,6 +356,7 @@ int task_clone(struct task *task, struct task *newtask)
assert(newtask->backtrace == NULL);
newtask->is_64bit = task->is_64bit;
newtask->attached = task->attached;
breakpoint_hw_clone(newtask);
@ -374,6 +387,7 @@ int task_fork(struct task *task, struct task *newtask)
newtask->libsym = task->libsym;
newtask->context = task->context;
newtask->attached = task->attached;
if (task->breakpoint)
newtask->breakpoint = breakpoint_find(newtask, newtask->breakpoint->addr);
@ -381,7 +395,7 @@ int task_fork(struct task *task, struct task *newtask)
newtask->breakpoint = NULL;
if (task->skip_bp)
newtask->skip_bp = breakpoint_ref(breakpoint_find(newtask, newtask->skip_bp->addr));
newtask->skip_bp = breakpoint_get(breakpoint_find(newtask, newtask->skip_bp->addr));
else
newtask->skip_bp = NULL;
@ -401,7 +415,7 @@ fail:
void task_reset_bp(struct task *task)
{
breakpoint_unref(task->skip_bp);
breakpoint_put(task->skip_bp);
task->breakpoint = NULL;
task->skip_bp = NULL;
@ -413,7 +427,7 @@ static struct task *open_one_pid(pid_t pid)
debug(DEBUG_PROCESS, "pid=%d", pid);
task = task_new(pid, 0);
task = task_new(pid);
if (task == NULL)
goto fail1;
@ -425,7 +439,7 @@ static struct task *open_one_pid(pid_t pid)
return task;
fail2:
remove_task(task);
task_destroy(task);
fail1:
return NULL;
}
@ -513,14 +527,6 @@ fail1:
remove_proc(leader);
}
struct task *get_first_process(void)
{
if (list_empty(&list_of_leaders))
return NULL;
return container_of(list_of_leaders.next, struct task, leader_list);
}
void each_process(void (*cb)(struct task *task))
{
struct list_head *it, *next;

25
task.h
View File

@ -56,6 +56,7 @@ struct task {
unsigned int is_64bit:1;
unsigned int attached:1;
unsigned int deleted:1;
unsigned int about_exit:1;
struct breakpoint *breakpoint;
struct library_symbol *libsym;
@ -75,9 +76,6 @@ struct task {
/* pointer to a breakpoint which was interrupt by a signal during skip */
struct breakpoint *skip_bp;
/* array of addresses of hw breakpoints */
struct breakpoint *hw_bp[HW_BREAKPOINTS];
/* set in leader: number of stopped threads including the leader */
unsigned int threads_stopped;
@ -99,16 +97,26 @@ struct task {
/* set in leader: number of threads including the leader */
unsigned int threads;
/* only used in leader: bit mask for used hw breakpoints */
unsigned long hw_bp_mask;
/* struct task chaining. */
struct list_head leader_list;
#if HW_BREAKPOINTS > 1
/* set in leader: list of hw breakpoints */
struct list_head hw_bp_list;
/* set in leader: number of registered hw breakpoints */
unsigned long hw_bp_num;
#endif
#if HW_BREAKPOINTS > 0
/* array of active hw breakpoints */
struct breakpoint *hw_bp[HW_BREAKPOINTS];
#endif
};
int process_exec(struct task *task);
struct task *task_new(pid_t pid, int traced);
struct task *task_new(pid_t pid);
struct task *task_create(const char *command, char **argv);
@ -125,9 +133,6 @@ int task_fork(struct task *task, struct task *newtask);
/* reset all breakpoints for task */
void task_reset_bp(struct task *task);
/* get first process of leader list */
struct task *get_first_process(void);
/* Iterate through the leader tasks that mtrace currently traces. */
void each_process(void (*cb)(struct task *task));

18
trace.c
View File

@ -48,7 +48,7 @@ int skip_breakpoint(struct task *task, struct breakpoint *bp)
if (task->event.type != EVENT_NONE)
return 1;
if (bp->enabled && bp->type == SW_BP) {
if (bp->enabled && !bp->hw) {
int ret = 0;
breakpoint_disable(task, bp);
@ -56,8 +56,8 @@ int skip_breakpoint(struct task *task, struct breakpoint *bp)
breakpoint_enable(task, bp);
if (ret) {
if (ret == 1) {
breakpoint_unref(task->skip_bp);
task->skip_bp = breakpoint_ref(bp);
breakpoint_put(task->skip_bp);
task->skip_bp = breakpoint_get(bp);
}
return ret;
}
@ -67,6 +67,15 @@ int skip_breakpoint(struct task *task, struct breakpoint *bp)
return 0;
}
void fix_about_exit(struct task *task)
{
if (task->about_exit) {
task->about_exit = 0;
continue_task(task, 0);
}
}
void detach_task(struct task *task)
{
int sig = 0;
@ -77,10 +86,11 @@ void detach_task(struct task *task)
sig = task->event.e_un.signum;
else
if (task->event.type == EVENT_BREAKPOINT)
breakpoint_unref(task->event.e_un.breakpoint);
breakpoint_put(task->event.e_un.breakpoint);
remove_event(task);
breakpoint_hw_destroy(task);
fix_about_exit(task);
untrace_task(task, sig);
}

View File

@ -25,6 +25,7 @@
#include "forward.h"
void fix_about_exit(struct task *task);
void detach_task(struct task *task);
void detach_proc(struct task *leader);
int skip_breakpoint(struct task *task, struct breakpoint *bp);