new version 0.5

performance improvements and optimizations
bug fixes
advanced monitoring
This commit is contained in:
Stefani Seibold 2015-11-22 10:24:06 +01:00
parent 3df912ba51
commit 3aed8a6e6b
53 changed files with 1875 additions and 1211 deletions

View File

@ -1,7 +1,7 @@
Mtrace Mtrace
------ ------
mtrace-ng is an interactive dynamic memory tracer, debugger and statistical analyses tool for C and C++, which intercepts, records and reports all kinds of dynamic memory allocations. mtrace-ng is a dynamic memory tracer, debugger and statistical analyses tool for C and C++, which intercepts, records and reports all kinds of dynamic memory allocations.
It supports the developer to get statistics about the memory usage and finding memory leaks in an arbitrate program. Since mtrace-ng is using breakpoints for tracing the program, there is no need of modification of the source code nor any recompilation. It supports the developer to get statistics about the memory usage and finding memory leaks in an arbitrate program. Since mtrace-ng is using breakpoints for tracing the program, there is no need of modification of the source code nor any recompilation.

2
TODO
View File

@ -2,7 +2,5 @@ ppc single step enhancement
arm thumb support arm thumb support
dwarf debug support dwarf debug support
arm & ppc hw bp support arm & ppc hw bp support
dwarf caching
invalid stack trace cache for unmapped libraries invalid stack trace cache for unmapped libraries
restore REALLOC_TRY when realloc fails
mremap revamp mremap revamp

View File

@ -1,6 +1,6 @@
@%:@! /bin/sh @%:@! /bin/sh
@%:@ Guess values for system-dependent variables and create Makefiles. @%:@ Guess values for system-dependent variables and create Makefiles.
@%:@ Generated by GNU Autoconf 2.69 for mtrace-ng 0.4. @%:@ Generated by GNU Autoconf 2.69 for mtrace-ng 0.5.
@%:@ @%:@
@%:@ Report bugs to <stefani@seibold.net>. @%:@ Report bugs to <stefani@seibold.net>.
@%:@ @%:@
@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='mtrace-ng' PACKAGE_NAME='mtrace-ng'
PACKAGE_TARNAME='mtrace-ng' PACKAGE_TARNAME='mtrace-ng'
PACKAGE_VERSION='0.4' PACKAGE_VERSION='0.5'
PACKAGE_STRING='mtrace-ng 0.4' PACKAGE_STRING='mtrace-ng 0.5'
PACKAGE_BUGREPORT='stefani@seibold.net' PACKAGE_BUGREPORT='stefani@seibold.net'
PACKAGE_URL='' PACKAGE_URL=''
@ -1329,7 +1329,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # 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. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures mtrace-ng 0.4 to adapt to many kinds of systems. \`configure' configures mtrace-ng 0.5 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1399,7 +1399,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of mtrace-ng 0.4:";; short | recursive ) echo "Configuration of mtrace-ng 0.5:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1518,7 +1518,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
mtrace-ng configure 0.4 mtrace-ng configure 0.5
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
@ -2124,7 +2124,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by mtrace-ng $as_me 0.4, which was It was created by mtrace-ng $as_me 0.5, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@ -12006,7 +12006,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='mtrace-ng' PACKAGE='mtrace-ng'
VERSION='0.4' VERSION='0.5'
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
@ -13238,6 +13238,7 @@ for ac_func in \
atexit \ atexit \
getcwd \ getcwd \
gettimeofday \ gettimeofday \
clock_gettime \
memset \ memset \
mkdir \ mkdir \
rmdir \ rmdir \
@ -13260,6 +13261,54 @@ fi
done done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
$as_echo_n "checking for clock_gettime in -lrt... " >&6; }
if ${ac_cv_lib_rt_clock_gettime+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lrt $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char clock_gettime ();
int
main ()
{
return clock_gettime ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_rt_clock_gettime=yes
else
ac_cv_lib_rt_clock_gettime=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5
$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then :
cat >>confdefs.h <<_ACEOF
@%:@define HAVE_LIBRT 1
_ACEOF
LIBS="-lrt $LIBS"
else
as_fn_error $? "*** librt not found on your system" "$LINENO" 5
fi
# #
# Debugging # Debugging
@ -13844,7 +13893,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by mtrace-ng $as_me 0.4, which was This file was extended by mtrace-ng $as_me 0.5, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -13910,7 +13959,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
mtrace-ng config.status 0.4 mtrace-ng config.status 0.5
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

@ -1,6 +1,6 @@
@%:@! /bin/sh @%:@! /bin/sh
@%:@ Guess values for system-dependent variables and create Makefiles. @%:@ Guess values for system-dependent variables and create Makefiles.
@%:@ Generated by GNU Autoconf 2.69 for mtrace-ng 0.4. @%:@ Generated by GNU Autoconf 2.69 for mtrace-ng 0.5.
@%:@ @%:@
@%:@ Report bugs to <stefani@seibold.net>. @%:@ Report bugs to <stefani@seibold.net>.
@%:@ @%:@
@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='mtrace-ng' PACKAGE_NAME='mtrace-ng'
PACKAGE_TARNAME='mtrace-ng' PACKAGE_TARNAME='mtrace-ng'
PACKAGE_VERSION='0.4' PACKAGE_VERSION='0.5'
PACKAGE_STRING='mtrace-ng 0.4' PACKAGE_STRING='mtrace-ng 0.5'
PACKAGE_BUGREPORT='stefani@seibold.net' PACKAGE_BUGREPORT='stefani@seibold.net'
PACKAGE_URL='' PACKAGE_URL=''
@ -1329,7 +1329,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # 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. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures mtrace-ng 0.4 to adapt to many kinds of systems. \`configure' configures mtrace-ng 0.5 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1399,7 +1399,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of mtrace-ng 0.4:";; short | recursive ) echo "Configuration of mtrace-ng 0.5:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1518,7 +1518,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
mtrace-ng configure 0.4 mtrace-ng configure 0.5
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
@ -2124,7 +2124,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by mtrace-ng $as_me 0.4, which was It was created by mtrace-ng $as_me 0.5, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@ -12006,7 +12006,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='mtrace-ng' PACKAGE='mtrace-ng'
VERSION='0.4' VERSION='0.5'
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
@ -13238,6 +13238,7 @@ for ac_func in \
atexit \ atexit \
getcwd \ getcwd \
gettimeofday \ gettimeofday \
clock_gettime \
memset \ memset \
mkdir \ mkdir \
rmdir \ rmdir \
@ -13260,6 +13261,54 @@ fi
done done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
$as_echo_n "checking for clock_gettime in -lrt... " >&6; }
if ${ac_cv_lib_rt_clock_gettime+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lrt $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char clock_gettime ();
int
main ()
{
return clock_gettime ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_rt_clock_gettime=yes
else
ac_cv_lib_rt_clock_gettime=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5
$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then :
cat >>confdefs.h <<_ACEOF
@%:@define HAVE_LIBRT 1
_ACEOF
LIBS="-lrt $LIBS"
else
as_fn_error $? "*** librt not found on your system" "$LINENO" 5
fi
# #
# Debugging # Debugging
@ -13844,7 +13893,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by mtrace-ng $as_me 0.4, which was This file was extended by mtrace-ng $as_me 0.5, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -13910,7 +13959,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
mtrace-ng config.status 0.4 mtrace-ng config.status 0.5
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

@ -1,6 +1,6 @@
@%:@! /bin/sh @%:@! /bin/sh
@%:@ Guess values for system-dependent variables and create Makefiles. @%:@ Guess values for system-dependent variables and create Makefiles.
@%:@ Generated by GNU Autoconf 2.69 for mtrace-ng 0.4. @%:@ Generated by GNU Autoconf 2.69 for mtrace-ng 0.5.
@%:@ @%:@
@%:@ Report bugs to <stefani@seibold.net>. @%:@ Report bugs to <stefani@seibold.net>.
@%:@ @%:@
@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='mtrace-ng' PACKAGE_NAME='mtrace-ng'
PACKAGE_TARNAME='mtrace-ng' PACKAGE_TARNAME='mtrace-ng'
PACKAGE_VERSION='0.4' PACKAGE_VERSION='0.5'
PACKAGE_STRING='mtrace-ng 0.4' PACKAGE_STRING='mtrace-ng 0.5'
PACKAGE_BUGREPORT='stefani@seibold.net' PACKAGE_BUGREPORT='stefani@seibold.net'
PACKAGE_URL='' PACKAGE_URL=''
@ -1329,7 +1329,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # 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. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures mtrace-ng 0.4 to adapt to many kinds of systems. \`configure' configures mtrace-ng 0.5 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1399,7 +1399,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of mtrace-ng 0.4:";; short | recursive ) echo "Configuration of mtrace-ng 0.5:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1518,7 +1518,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
mtrace-ng configure 0.4 mtrace-ng configure 0.5
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
@ -2124,7 +2124,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by mtrace-ng $as_me 0.4, which was It was created by mtrace-ng $as_me 0.5, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@ -12006,7 +12006,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='mtrace-ng' PACKAGE='mtrace-ng'
VERSION='0.4' VERSION='0.5'
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
@ -13238,6 +13238,7 @@ for ac_func in \
atexit \ atexit \
getcwd \ getcwd \
gettimeofday \ gettimeofday \
clock_gettime \
memset \ memset \
mkdir \ mkdir \
rmdir \ rmdir \
@ -13260,6 +13261,54 @@ fi
done done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
$as_echo_n "checking for clock_gettime in -lrt... " >&6; }
if ${ac_cv_lib_rt_clock_gettime+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lrt $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char clock_gettime ();
int
main ()
{
return clock_gettime ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_rt_clock_gettime=yes
else
ac_cv_lib_rt_clock_gettime=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5
$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then :
cat >>confdefs.h <<_ACEOF
@%:@define HAVE_LIBRT 1
_ACEOF
LIBS="-lrt $LIBS"
else
as_fn_error $? "*** librt not found on your system" "$LINENO" 5
fi
# #
# Debugging # Debugging
@ -13844,7 +13893,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by mtrace-ng $as_me 0.4, which was This file was extended by mtrace-ng $as_me 0.5, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -13910,7 +13959,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
mtrace-ng config.status 0.4 mtrace-ng config.status 0.5
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

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

View File

@ -2746,18 +2746,19 @@ m4trace:configure.ac:224: -1- m4_pattern_allow([^HAVE_VFORK_H$])
m4trace:configure.ac:224: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$]) m4trace:configure.ac:224: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$])
m4trace:configure.ac:224: -1- m4_pattern_allow([^vfork$]) m4trace:configure.ac:224: -1- m4_pattern_allow([^vfork$])
m4trace:configure.ac:224: -1- m4_pattern_allow([^HAVE_WORKING_FORK$]) m4trace:configure.ac:224: -1- m4_pattern_allow([^HAVE_WORKING_FORK$])
m4trace:configure.ac:255: -1- m4_pattern_allow([^DEBUG$]) m4trace:configure.ac:242: -1- m4_pattern_allow([^HAVE_LIBRT$])
m4trace:configure.ac:269: -1- m4_pattern_allow([^AM_CPPFLAGS$]) m4trace:configure.ac:259: -1- m4_pattern_allow([^DEBUG$])
m4trace:configure.ac:270: -1- m4_pattern_allow([^AM_CFLAGS$]) m4trace:configure.ac:273: -1- m4_pattern_allow([^AM_CPPFLAGS$])
m4trace:configure.ac:271: -1- m4_pattern_allow([^AM_LDFLAGS$]) m4trace:configure.ac:274: -1- m4_pattern_allow([^AM_CFLAGS$])
m4trace:configure.ac:272: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$]) m4trace:configure.ac:275: -1- m4_pattern_allow([^AM_LDFLAGS$])
m4trace:configure.ac:283: -1- m4_pattern_allow([^LIB@&t@OBJS$]) m4trace:configure.ac:276: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$])
m4trace:configure.ac:283: -1- m4_pattern_allow([^LTLIBOBJS$]) m4trace:configure.ac:287: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:283: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) m4trace:configure.ac:287: -1- m4_pattern_allow([^LTLIBOBJS$])
m4trace:configure.ac:283: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) m4trace:configure.ac:287: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])
m4trace:configure.ac:283: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) m4trace:configure.ac:287: -1- m4_pattern_allow([^am__EXEEXT_TRUE$])
m4trace:configure.ac:283: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) m4trace:configure.ac:287: -1- m4_pattern_allow([^am__EXEEXT_FALSE$])
m4trace:configure.ac:283: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) m4trace:configure.ac:287: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE])
m4trace:configure.ac:283: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"]) m4trace:configure.ac:287: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE])
m4trace:configure.ac:283: -1- _LT_PROG_LTMAIN m4trace:configure.ac:287: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"])
m4trace:configure.ac:283: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS m4trace:configure.ac:287: -1- _LT_PROG_LTMAIN
m4trace:configure.ac:287: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS

View File

@ -2746,18 +2746,19 @@ m4trace:configure.ac:224: -1- m4_pattern_allow([^HAVE_VFORK_H$])
m4trace:configure.ac:224: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$]) m4trace:configure.ac:224: -1- m4_pattern_allow([^HAVE_WORKING_VFORK$])
m4trace:configure.ac:224: -1- m4_pattern_allow([^vfork$]) m4trace:configure.ac:224: -1- m4_pattern_allow([^vfork$])
m4trace:configure.ac:224: -1- m4_pattern_allow([^HAVE_WORKING_FORK$]) m4trace:configure.ac:224: -1- m4_pattern_allow([^HAVE_WORKING_FORK$])
m4trace:configure.ac:255: -1- m4_pattern_allow([^DEBUG$]) m4trace:configure.ac:242: -1- m4_pattern_allow([^HAVE_LIBRT$])
m4trace:configure.ac:269: -1- m4_pattern_allow([^AM_CPPFLAGS$]) m4trace:configure.ac:259: -1- m4_pattern_allow([^DEBUG$])
m4trace:configure.ac:270: -1- m4_pattern_allow([^AM_CFLAGS$]) m4trace:configure.ac:273: -1- m4_pattern_allow([^AM_CPPFLAGS$])
m4trace:configure.ac:271: -1- m4_pattern_allow([^AM_LDFLAGS$]) m4trace:configure.ac:274: -1- m4_pattern_allow([^AM_CFLAGS$])
m4trace:configure.ac:272: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$]) m4trace:configure.ac:275: -1- m4_pattern_allow([^AM_LDFLAGS$])
m4trace:configure.ac:283: -1- m4_pattern_allow([^LIB@&t@OBJS$]) m4trace:configure.ac:276: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$])
m4trace:configure.ac:283: -1- m4_pattern_allow([^LTLIBOBJS$]) m4trace:configure.ac:287: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:283: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) m4trace:configure.ac:287: -1- m4_pattern_allow([^LTLIBOBJS$])
m4trace:configure.ac:283: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) m4trace:configure.ac:287: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])
m4trace:configure.ac:283: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) m4trace:configure.ac:287: -1- m4_pattern_allow([^am__EXEEXT_TRUE$])
m4trace:configure.ac:283: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) m4trace:configure.ac:287: -1- m4_pattern_allow([^am__EXEEXT_FALSE$])
m4trace:configure.ac:283: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) m4trace:configure.ac:287: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE])
m4trace:configure.ac:283: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"]) m4trace:configure.ac:287: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE])
m4trace:configure.ac:283: -1- _LT_PROG_LTMAIN m4trace:configure.ac:287: -1- _AC_AM_CONFIG_HEADER_HOOK(["$ac_file"])
m4trace:configure.ac:283: -1- _AM_OUTPUT_DEPENDENCY_COMMANDS m4trace:configure.ac:287: -1- _LT_PROG_LTMAIN
m4trace:configure.ac:287: -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:1191: -1- m4_include([config/m4/ltsugar.m4])
m4trace:aclocal.m4:1192: -1- m4_include([config/m4/ltversion.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:aclocal.m4:1193: -1- m4_include([config/m4/lt~obsolete.m4])
m4trace:configure.ac:27: -1- AC_INIT([mtrace-ng], [0.4], [stefani@seibold.net]) m4trace:configure.ac:27: -1- AC_INIT([mtrace-ng], [0.5], [stefani@seibold.net])
m4trace:configure.ac:27: -1- m4_pattern_forbid([^_?A[CHUM]_]) m4trace:configure.ac:27: -1- m4_pattern_forbid([^_?A[CHUM]_])
m4trace:configure.ac:27: -1- m4_pattern_forbid([_AC_]) 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']) m4trace:configure.ac:27: -1- m4_pattern_forbid([^LIBOBJS$], [do not use LIBOBJS directly, use AC_LIBOBJ (see section `AC_LIBOBJ vs LIBOBJS'])
@ -655,6 +655,8 @@ m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_GETCWD], [/* Define to 1 if you ha
@%:@undef HAVE_GETCWD]) @%:@undef HAVE_GETCWD])
m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_GETTIMEOFDAY], [/* Define to 1 if you have the `gettimeofday\' function. */ m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_GETTIMEOFDAY], [/* Define to 1 if you have the `gettimeofday\' function. */
@%:@undef HAVE_GETTIMEOFDAY]) @%:@undef HAVE_GETTIMEOFDAY])
m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_CLOCK_GETTIME], [/* Define to 1 if you have the `clock_gettime\' function. */
@%:@undef HAVE_CLOCK_GETTIME])
m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_MEMSET], [/* Define to 1 if you have the `memset\' function. */ m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_MEMSET], [/* Define to 1 if you have the `memset\' function. */
@%:@undef HAVE_MEMSET]) @%:@undef HAVE_MEMSET])
m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_MKDIR], [/* Define to 1 if you have the `mkdir\' function. */ m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_MKDIR], [/* Define to 1 if you have the `mkdir\' function. */
@ -673,23 +675,27 @@ m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_STRTOUL], [/* Define to 1 if you h
@%:@undef HAVE_STRTOUL]) @%:@undef HAVE_STRTOUL])
m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_PROCESS_VM_READV], [/* Define to 1 if you have the `process_vm_readv\' function. */ m4trace:configure.ac:225: -1- AH_OUTPUT([HAVE_PROCESS_VM_READV], [/* Define to 1 if you have the `process_vm_readv\' function. */
@%:@undef HAVE_PROCESS_VM_READV]) @%:@undef HAVE_PROCESS_VM_READV])
m4trace:configure.ac:255: -1- AC_DEFINE_TRACE_LITERAL([DEBUG]) m4trace:configure.ac:242: -1- AH_OUTPUT([HAVE_LIBRT], [/* Define to 1 if you have the `rt\' library (-lrt). */
m4trace:configure.ac:255: -1- m4_pattern_allow([^DEBUG$]) @%:@undef HAVE_LIBRT])
m4trace:configure.ac:255: -1- AH_OUTPUT([DEBUG], [/* debugging */ m4trace:configure.ac:242: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBRT])
m4trace:configure.ac:242: -1- m4_pattern_allow([^HAVE_LIBRT$])
m4trace:configure.ac:259: -1- AC_DEFINE_TRACE_LITERAL([DEBUG])
m4trace:configure.ac:259: -1- m4_pattern_allow([^DEBUG$])
m4trace:configure.ac:259: -1- AH_OUTPUT([DEBUG], [/* debugging */
@%:@undef DEBUG]) @%:@undef DEBUG])
m4trace:configure.ac:269: -1- AC_SUBST([AM_CPPFLAGS]) m4trace:configure.ac:273: -1- AC_SUBST([AM_CPPFLAGS])
m4trace:configure.ac:269: -1- AC_SUBST_TRACE([AM_CPPFLAGS]) m4trace:configure.ac:273: -1- AC_SUBST_TRACE([AM_CPPFLAGS])
m4trace:configure.ac:269: -1- m4_pattern_allow([^AM_CPPFLAGS$]) m4trace:configure.ac:273: -1- m4_pattern_allow([^AM_CPPFLAGS$])
m4trace:configure.ac:270: -1- AC_SUBST([AM_CFLAGS]) m4trace:configure.ac:274: -1- AC_SUBST([AM_CFLAGS])
m4trace:configure.ac:270: -1- AC_SUBST_TRACE([AM_CFLAGS]) m4trace:configure.ac:274: -1- AC_SUBST_TRACE([AM_CFLAGS])
m4trace:configure.ac:270: -1- m4_pattern_allow([^AM_CFLAGS$]) m4trace:configure.ac:274: -1- m4_pattern_allow([^AM_CFLAGS$])
m4trace:configure.ac:271: -1- AC_SUBST([AM_LDFLAGS]) m4trace:configure.ac:275: -1- AC_SUBST([AM_LDFLAGS])
m4trace:configure.ac:271: -1- AC_SUBST_TRACE([AM_LDFLAGS]) m4trace:configure.ac:275: -1- AC_SUBST_TRACE([AM_LDFLAGS])
m4trace:configure.ac:271: -1- m4_pattern_allow([^AM_LDFLAGS$]) m4trace:configure.ac:275: -1- m4_pattern_allow([^AM_LDFLAGS$])
m4trace:configure.ac:272: -1- AC_SUBST([libelf_LD_LIBRARY_PATH]) m4trace:configure.ac:276: -1- AC_SUBST([libelf_LD_LIBRARY_PATH])
m4trace:configure.ac:272: -1- AC_SUBST_TRACE([libelf_LD_LIBRARY_PATH]) m4trace:configure.ac:276: -1- AC_SUBST_TRACE([libelf_LD_LIBRARY_PATH])
m4trace:configure.ac:272: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$]) m4trace:configure.ac:276: -1- m4_pattern_allow([^libelf_LD_LIBRARY_PATH$])
m4trace:configure.ac:274: -1- AC_CONFIG_FILES([ m4trace:configure.ac:278: -1- AC_CONFIG_FILES([
Makefile Makefile
client/Makefile client/Makefile
sysdeps/Makefile sysdeps/Makefile
@ -698,30 +704,30 @@ m4trace:configure.ac:274: -1- AC_CONFIG_FILES([
sysdeps/linux-gnu/ppc/Makefile sysdeps/linux-gnu/ppc/Makefile
sysdeps/linux-gnu/arm/Makefile sysdeps/linux-gnu/arm/Makefile
]) ])
m4trace:configure.ac:283: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs]) m4trace:configure.ac:287: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs])
m4trace:configure.ac:283: -1- AC_SUBST_TRACE([LIB@&t@OBJS]) m4trace:configure.ac:287: -1- AC_SUBST_TRACE([LIB@&t@OBJS])
m4trace:configure.ac:283: -1- m4_pattern_allow([^LIB@&t@OBJS$]) m4trace:configure.ac:287: -1- m4_pattern_allow([^LIB@&t@OBJS$])
m4trace:configure.ac:283: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs]) m4trace:configure.ac:287: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs])
m4trace:configure.ac:283: -1- AC_SUBST_TRACE([LTLIBOBJS]) m4trace:configure.ac:287: -1- AC_SUBST_TRACE([LTLIBOBJS])
m4trace:configure.ac:283: -1- m4_pattern_allow([^LTLIBOBJS$]) m4trace:configure.ac:287: -1- m4_pattern_allow([^LTLIBOBJS$])
m4trace:configure.ac:283: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"]) m4trace:configure.ac:287: -1- AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])
m4trace:configure.ac:283: -1- AC_SUBST([am__EXEEXT_TRUE]) m4trace:configure.ac:287: -1- AC_SUBST([am__EXEEXT_TRUE])
m4trace:configure.ac:283: -1- AC_SUBST_TRACE([am__EXEEXT_TRUE]) m4trace:configure.ac:287: -1- AC_SUBST_TRACE([am__EXEEXT_TRUE])
m4trace:configure.ac:283: -1- m4_pattern_allow([^am__EXEEXT_TRUE$]) m4trace:configure.ac:287: -1- m4_pattern_allow([^am__EXEEXT_TRUE$])
m4trace:configure.ac:283: -1- AC_SUBST([am__EXEEXT_FALSE]) m4trace:configure.ac:287: -1- AC_SUBST([am__EXEEXT_FALSE])
m4trace:configure.ac:283: -1- AC_SUBST_TRACE([am__EXEEXT_FALSE]) m4trace:configure.ac:287: -1- AC_SUBST_TRACE([am__EXEEXT_FALSE])
m4trace:configure.ac:283: -1- m4_pattern_allow([^am__EXEEXT_FALSE$]) m4trace:configure.ac:287: -1- m4_pattern_allow([^am__EXEEXT_FALSE$])
m4trace:configure.ac:283: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE]) m4trace:configure.ac:287: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_TRUE])
m4trace:configure.ac:283: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE]) m4trace:configure.ac:287: -1- _AM_SUBST_NOTMAKE([am__EXEEXT_FALSE])
m4trace:configure.ac:283: -1- AC_SUBST_TRACE([top_builddir]) m4trace:configure.ac:287: -1- AC_SUBST_TRACE([top_builddir])
m4trace:configure.ac:283: -1- AC_SUBST_TRACE([top_build_prefix]) m4trace:configure.ac:287: -1- AC_SUBST_TRACE([top_build_prefix])
m4trace:configure.ac:283: -1- AC_SUBST_TRACE([srcdir]) m4trace:configure.ac:287: -1- AC_SUBST_TRACE([srcdir])
m4trace:configure.ac:283: -1- AC_SUBST_TRACE([abs_srcdir]) m4trace:configure.ac:287: -1- AC_SUBST_TRACE([abs_srcdir])
m4trace:configure.ac:283: -1- AC_SUBST_TRACE([top_srcdir]) m4trace:configure.ac:287: -1- AC_SUBST_TRACE([top_srcdir])
m4trace:configure.ac:283: -1- AC_SUBST_TRACE([abs_top_srcdir]) m4trace:configure.ac:287: -1- AC_SUBST_TRACE([abs_top_srcdir])
m4trace:configure.ac:283: -1- AC_SUBST_TRACE([builddir]) m4trace:configure.ac:287: -1- AC_SUBST_TRACE([builddir])
m4trace:configure.ac:283: -1- AC_SUBST_TRACE([abs_builddir]) m4trace:configure.ac:287: -1- AC_SUBST_TRACE([abs_builddir])
m4trace:configure.ac:283: -1- AC_SUBST_TRACE([abs_top_builddir]) m4trace:configure.ac:287: -1- AC_SUBST_TRACE([abs_top_builddir])
m4trace:configure.ac:283: -1- AC_SUBST_TRACE([INSTALL]) m4trace:configure.ac:287: -1- AC_SUBST_TRACE([INSTALL])
m4trace:configure.ac:283: -1- AC_SUBST_TRACE([MKDIR_P]) m4trace:configure.ac:287: -1- AC_SUBST_TRACE([MKDIR_P])
m4trace:configure.ac:283: -1- AC_REQUIRE_AUX_FILE([ltmain.sh]) m4trace:configure.ac:287: -1- AC_REQUIRE_AUX_FILE([ltmain.sh])

View File

@ -23,25 +23,82 @@
#ifndef _INC_BACKTRACE_H #ifndef _INC_BACKTRACE_H
#define _INC_BACKTRACE_H #define _INC_BACKTRACE_H
#include <assert.h>
#include "dwarf.h"
#include "main.h"
#include "options.h"
#include "task.h" #include "task.h"
#include "timer.h"
/* init backtrace for given leader task */ /* init backtrace for given leader task */
int backtrace_init(struct task *task); static inline int backtrace_init(struct task *task)
{
assert(task->leader == task);
assert(task->backtrace == NULL);
task->backtrace = dwarf_init(task->is_64bit);
return task->backtrace != NULL;
}
/* destroy backtrace for given leader task */ /* destroy backtrace for given leader task */
void backtrace_destroy(struct task *task); static inline void backtrace_destroy(struct task *task)
{
assert(task->leader == task);
if (task->backtrace) {
dwarf_destroy(task->backtrace);
task->backtrace = NULL;
}
}
/* start backtrace for given task */ /* start backtrace for given task */
int backtrace_init_unwind(struct task *task); static inline int backtrace_init_unwind(struct task *task)
{
assert(task->leader);
assert(task->leader->backtrace);
return dwarf_init_unwind(task->leader->backtrace, task);
}
/* get backtrace IP address for given task */ /* get backtrace IP address for given task */
unsigned long backtrace_get_ip(struct task *task); static inline unsigned long backtrace_get_ip(struct task *task)
{
assert(task->leader);
assert(task->leader->backtrace);
return dwarf_get_ip(task->leader->backtrace);
}
/* step to next backtrace given task */ /* step to next backtrace given task */
int backtrace_step(struct task *task); static inline int backtrace_step(struct task *task)
{
int ret;
struct timespec start;
assert(task->leader);
assert(task->leader->backtrace);
if (unlikely(options.verbose > 1))
start_time(&start);
ret = dwarf_step(task->leader->backtrace);
if (unlikely(options.verbose > 1))
set_timer(&start, &backtrace_time);
return ret;
}
/* get backtrace location type of given task */ /* get backtrace location type of given task */
int backtrace_location_type(struct task *task); static inline int backtrace_location_type(struct task *task)
{
assert(task->leader);
assert(task->leader->backtrace);
return dwarf_location_type(task->leader->backtrace);
}
#endif #endif

View File

@ -108,7 +108,7 @@ static void enable_hw_bp(struct task *task, struct breakpoint *bp)
task->hw_bp[slot] = bp; task->hw_bp[slot] = bp;
if (set_hw_bp(task, slot, bp->addr) == -1) if (unlikely(set_hw_bp(task, slot, bp->addr) == -1))
fatal("set_hw_bp"); fatal("set_hw_bp");
} }
@ -116,12 +116,12 @@ static void disable_hw_bp(struct task *task, struct breakpoint *bp)
{ {
unsigned int slot = bp->hw_bp_slot; unsigned int slot = bp->hw_bp_slot;
if (!task->hw_bp[slot]) if (unlikely(!task->hw_bp[slot]))
return; return;
assert(task->hw_bp[slot] == bp); assert(task->hw_bp[slot] == bp);
if (reset_hw_bp(task, slot) == -1) if (unlikely(reset_hw_bp(task, slot) == -1))
fatal("reset_hw_bp"); fatal("reset_hw_bp");
task->hw_bp[slot] = NULL; task->hw_bp[slot] = NULL;
@ -286,10 +286,10 @@ void breakpoint_hw_destroy(struct task *task)
void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp) void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp)
{ {
if (bp->deleted) if (unlikely(bp->deleted))
return; return;
if (bp->type != BP_HW_SCRATCH) if (unlikely(bp->type != BP_HW_SCRATCH))
return; return;
assert(bp->hw_bp_slot == HW_BP_SCRATCH_SLOT); assert(bp->hw_bp_slot == HW_BP_SCRATCH_SLOT);
@ -300,10 +300,10 @@ void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp)
void disable_scratch_hw_bp(struct task *task, struct breakpoint *bp) void disable_scratch_hw_bp(struct task *task, struct breakpoint *bp)
{ {
if (bp->deleted) if (unlikely(bp->deleted))
return; return;
if (bp->type != BP_HW_SCRATCH) if (unlikely(bp->type != BP_HW_SCRATCH))
return; return;
assert(bp->hw_bp_slot == HW_BP_SCRATCH_SLOT); assert(bp->hw_bp_slot == HW_BP_SCRATCH_SLOT);
@ -385,12 +385,12 @@ struct breakpoint *breakpoint_new(struct task *task, arch_addr_t addr, struct li
void breakpoint_enable(struct task *task, struct breakpoint *bp) void breakpoint_enable(struct task *task, struct breakpoint *bp)
{ {
if (bp->deleted) if (unlikely(bp->deleted))
return; return;
debug(DEBUG_PROCESS, "pid=%d, addr=%#lx", task->pid, bp->addr); debug(DEBUG_PROCESS, "pid=%d, addr=%#lx", task->pid, bp->addr);
if (!bp->enabled) { if (likely(!bp->enabled)) {
#if HW_BREAKPOINTS > 0 #if HW_BREAKPOINTS > 0
if (bp->type == BP_HW_SCRATCH) { if (bp->type == BP_HW_SCRATCH) {
bp->enabled = 1; bp->enabled = 1;
@ -412,12 +412,12 @@ void breakpoint_enable(struct task *task, struct breakpoint *bp)
void breakpoint_disable(struct task *task, struct breakpoint *bp) void breakpoint_disable(struct task *task, struct breakpoint *bp)
{ {
if (bp->deleted) if (unlikely(bp->deleted))
return; return;
debug(DEBUG_PROCESS, "pid=%d, addr=%#lx", task->pid, bp->addr); debug(DEBUG_PROCESS, "pid=%d, addr=%#lx", task->pid, bp->addr);
if (bp->enabled) { if (likely(bp->enabled)) {
#if HW_BREAKPOINTS > 0 #if HW_BREAKPOINTS > 0
if (bp->hw) { if (bp->hw) {
struct task *leader = task->leader; struct task *leader = task->leader;
@ -449,13 +449,13 @@ struct breakpoint *breakpoint_insert(struct task *task, arch_addr_t addr, struct
{ {
debug(DEBUG_FUNCTION, "pid=%d, addr=%lx, symbol=%s", task->pid, addr, libsym ? libsym->func->name : "NULL"); debug(DEBUG_FUNCTION, "pid=%d, addr=%lx, symbol=%s", task->pid, addr, libsym ? libsym->func->name : "NULL");
if (!addr) if (unlikely(!addr))
return NULL; return NULL;
struct breakpoint *bp = breakpoint_find(task, addr); struct breakpoint *bp = breakpoint_find(task, addr);
if (!bp) { if (unlikely(!bp)) {
bp = breakpoint_new(task, addr, libsym, type); bp = breakpoint_new(task, addr, libsym, type);
if (!bp) if (unlikely(!bp))
return NULL; return NULL;
} }
@ -484,7 +484,7 @@ void breakpoint_delete(struct task *task, struct breakpoint *bp)
#endif #endif
dict_remove_entry(leader->breakpoints, (unsigned long)bp->addr); dict_remove_entry(leader->breakpoints, (unsigned long)bp->addr);
if (options.verbose > 1 && bp->libsym) { if (unlikely(options.verbose > 1 && bp->libsym)) {
fprintf(stderr, fprintf(stderr,
"delete %s breakpoint %s:%s [%#lx] count=%u\n", "delete %s breakpoint %s:%s [%#lx] count=%u\n",
bp->type == BP_SW ? "sw" : "hw", bp->type == BP_SW ? "sw" : "hw",
@ -662,7 +662,7 @@ static int clone_single_cb(unsigned long key, const void *value, void *data)
new_task->hw_bp[new_bp->hw_bp_slot] = new_bp; new_task->hw_bp[new_bp->hw_bp_slot] = new_bp;
if (new_bp->enabled) { if (new_bp->enabled) {
if (set_hw_bp(new_task, new_bp->hw_bp_slot, new_bp->addr) == -1) if (unlikely(set_hw_bp(new_task, new_bp->hw_bp_slot, new_bp->addr) == -1))
fatal("set_hw_bp"); fatal("set_hw_bp");
} }
} }
@ -692,14 +692,14 @@ int breakpoint_clone_all(struct task *clone, struct task *leader)
struct breakpoint *breakpoint_get(struct breakpoint *bp) struct breakpoint *breakpoint_get(struct breakpoint *bp)
{ {
if (bp) if (likely(bp))
++bp->refcnt; ++bp->refcnt;
return bp; return bp;
} }
int breakpoint_put(struct breakpoint *bp) int breakpoint_put(struct breakpoint *bp)
{ {
if (bp) { if (likely(bp)) {
assert(bp->refcnt != 0); assert(bp->refcnt != 0);
if (--bp->refcnt) if (--bp->refcnt)

View File

@ -31,7 +31,7 @@
#include "sysdep.h" #include "sysdep.h"
#include "forward.h" #include "forward.h"
#define BP_REORDER_THRESHOLD 1024U #define BP_REORDER_THRESHOLD 2048U
#define BP_SW 0 #define BP_SW 0
#define BP_HW_SCRATCH 1 #define BP_HW_SCRATCH 1

View File

@ -224,7 +224,7 @@ static int parse_config(const char *filename)
return 0; return 0;
} }
static struct rb_process *pid_rb_search(struct rb_root *root, pid_t pid) static struct rb_process *pid_rb_search(struct rb_root *root, unsigned int pid)
{ {
struct rb_node *node = root->rb_node; struct rb_node *node = root->rb_node;
@ -241,7 +241,7 @@ static struct rb_process *pid_rb_search(struct rb_root *root, pid_t pid)
return NULL; return NULL;
} }
static struct process *pid_rb_delete(struct rb_root *root, pid_t pid) static struct process *pid_rb_delete(struct rb_root *root, unsigned int pid)
{ {
struct rb_process *data = pid_rb_search(root, pid); struct rb_process *data = pid_rb_search(root, pid);
struct process *process; struct process *process;
@ -289,35 +289,34 @@ static void swap_msg(struct mt_msg *mt_msg)
{ {
mt_msg->operation = bswap_16(mt_msg->operation); mt_msg->operation = bswap_16(mt_msg->operation);
mt_msg->payload_len = bswap_32(mt_msg->payload_len); mt_msg->payload_len = bswap_32(mt_msg->payload_len);
mt_msg->pid = bswap_32(mt_msg->pid); mt_msg->pid = bswap_16(mt_msg->pid);
mt_msg->tid = bswap_32(mt_msg->tid);
} }
static int socket_read_msg(struct mt_msg *mt_msg, void **payload, unsigned int *swap_endian) static int socket_read_msg(struct mt_msg *mt_msg, void **payload, unsigned int *swap_endian)
{ {
size_t payload_len;
if (TEMP_FAILURE_RETRY(safe_read(client_fd, mt_msg, sizeof(*mt_msg))) <= 0) if (TEMP_FAILURE_RETRY(safe_read(client_fd, mt_msg, sizeof(*mt_msg))) <= 0)
return FALSE; return FALSE;
if (mt_msg->operation > 0xff) { *swap_endian = mt_msg->operation > 0xff;
if (*swap_endian)
swap_msg(mt_msg); swap_msg(mt_msg);
*swap_endian = 1; payload_len = mt_msg->payload_len;
}
else
*swap_endian = 0;
if (payload_len) {
*payload = malloc(payload_len);
if (mt_msg->payload_len) { if (TEMP_FAILURE_RETRY(safe_read(client_fd, *payload, payload_len)) <= 0)
*payload = malloc(mt_msg->payload_len);
if (TEMP_FAILURE_RETRY(safe_read(client_fd, *payload, mt_msg->payload_len)) <= 0)
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
} }
static pid_t pid_payload(struct process *process, void *payload) static unsigned int pid_payload(struct process *process, void *payload)
{ {
struct mt_pid_payload *mt_pid = payload; struct mt_pid_payload *mt_pid = payload;
@ -369,6 +368,14 @@ static void client_remove_process(struct process *process)
free(process); free(process);
} }
static void store_timer_info(struct memtrace_timer_info *dst, struct memtrace_timer_info *src)
{
dst->max = bswap_32(src->max);
dst->count = bswap_32(src->count);
dst->culminate = bswap_64(src->culminate);
}
static int client_func(void) static int client_func(void)
{ {
struct mt_msg mt_msg; struct mt_msg mt_msg;
@ -393,7 +400,27 @@ static int client_func(void)
client_close(); client_close();
break; break;
case MT_INFO: case MT_INFO:
if (swap_endian) {
struct memtrace_info *p = payload;
mt_info.version = p->version;
mt_info.mode = p->mode;
mt_info.do_trace = p->do_trace;
mt_info.stack_depth = p->stack_depth;
mt_info.verbose = p->verbose;
store_timer_info(&mt_info.stop_time, &p->stop_time);
store_timer_info(&mt_info.sw_bp_time, &p->sw_bp_time);
store_timer_info(&mt_info.hw_bp_time, &p->hw_bp_time);
store_timer_info(&mt_info.backtrace_time, &p->backtrace_time);
store_timer_info(&mt_info.reorder_time, &p->reorder_time);
store_timer_info(&mt_info.report_in_time, &p->report_in_time);
store_timer_info(&mt_info.report_out_time, &p->report_out_time);
store_timer_info(&mt_info.skip_bp_time, &p->skip_bp_time);
}
else
memcpy(&mt_info, payload, sizeof(mt_info)); memcpy(&mt_info, payload, sizeof(mt_info));
break; break;
default: default:
fatal("protocol violation 0x%08x", mt_msg.operation); fatal("protocol violation 0x%08x", mt_msg.operation);
@ -419,7 +446,6 @@ static int client_func(void)
switch(mt_msg.operation) { switch(mt_msg.operation) {
case MT_MALLOC: case MT_MALLOC:
case MT_REALLOC: case MT_REALLOC:
case MT_REALLOC_FAILED:
case MT_MEMALIGN: case MT_MEMALIGN:
case MT_POSIX_MEMALIGN: case MT_POSIX_MEMALIGN:
case MT_ALIGNED_ALLOC: case MT_ALIGNED_ALLOC:
@ -431,6 +457,9 @@ static int client_func(void)
case MT_NEW_ARRAY: case MT_NEW_ARRAY:
process_alloc(process, &mt_msg, payload); process_alloc(process, &mt_msg, payload);
break; break;
case MT_REALLOC_DONE:
process_realloc_done(process, &mt_msg, payload);
break;
case MT_REALLOC_ENTER: case MT_REALLOC_ENTER:
case MT_FREE: case MT_FREE:
case MT_DELETE: case MT_DELETE:
@ -487,16 +516,6 @@ static int client_func(void)
return mt_msg.operation; return mt_msg.operation;
} }
void client_show_info(void)
{
printf("memtrace info:\n");
printf(" follow fork: %s\n", mt_info.mode & MEMTRACE_SI_FORK ? "yes" : "no");
printf(" follow exec: %s\n", mt_info.mode & MEMTRACE_SI_EXEC ? "yes" : "no");
printf(" verbose: %s\n", mt_info.mode & MEMTRACE_SI_VERBOSE ? "yes" : "no");
printf(" do trace: %s\n", mt_info.do_trace ? "yes" : "no");
printf(" stack depth: %u\n", mt_info.stack_depth);
}
int client_wait_op(enum mt_operation op) int client_wait_op(enum mt_operation op)
{ {
if (options.logfile) if (options.logfile)
@ -515,6 +534,52 @@ int client_wait_op(enum mt_operation op)
return 0; return 0;
} }
static void show_timer_info(const char *str, struct memtrace_timer_info *info)
{
if (!info->count)
return;
printf(" %s\n count: %-9lu max. us: %-6lu culminate us:%-11llu average ns:%llu\n",
str,
(unsigned long)info->count,
(unsigned long)info->max,
(unsigned long long)info->culminate,
(unsigned long long)(info->culminate * 1000) / info->count
);
}
void client_show_info(void)
{
printf("memtrace info:\n");
printf(" follow fork: %s\n", mt_info.mode & MEMTRACE_SI_FORK ? "yes" : "no");
printf(" follow exec: %s\n", mt_info.mode & MEMTRACE_SI_EXEC ? "yes" : "no");
printf(" verbose: %s\n", mt_info.mode & MEMTRACE_SI_VERBOSE ? "yes" : "no");
printf(" do trace: %s\n", mt_info.do_trace ? "yes" : "no");
printf(" stack depth: %u\n", mt_info.stack_depth);
if (mt_info.verbose > 1) {
show_timer_info("threads stop", &mt_info.stop_time);
show_timer_info("breakpoint sw", &mt_info.sw_bp_time);
show_timer_info("breakpoint hw", &mt_info.hw_bp_time);
show_timer_info("backtrace step", &mt_info.backtrace_time);
show_timer_info("reorder", &mt_info.reorder_time);
show_timer_info("report in", &mt_info.report_in_time);
show_timer_info("report out", &mt_info.report_out_time);
show_timer_info("skip breakpoint", &mt_info.skip_bp_time);
}
}
void client_request_info(void)
{
if (sock_send_msg(client_fd, MT_INFO, 0, NULL, 0) < 0) {
client_broken();
return;
}
if (client_wait_op(MT_INFO) < 0)
return;
}
static int client_iterate_process(struct rb_node *node, void *user) static int client_iterate_process(struct rb_node *node, void *user)
{ {
struct rb_process *data = (struct rb_process *)node; struct rb_process *data = (struct rb_process *)node;
@ -528,7 +593,7 @@ void client_iterate_processes(int (*func)(struct process *process))
rb_iterate(&pid_table, client_iterate_process, func); rb_iterate(&pid_table, client_iterate_process, func);
} }
struct process *client_find_process(pid_t pid) struct process *client_find_process(unsigned int pid)
{ {
struct rb_process *data; struct rb_process *data;
@ -608,6 +673,8 @@ int client_start(void)
return -1; return -1;
} }
ioevent_add_input(client_fd, client_func);
if (client_wait_op(MT_INFO) == -1) { if (client_wait_op(MT_INFO) == -1) {
fprintf(stderr, "could not talk to server\n"); fprintf(stderr, "could not talk to server\n");
return -1; return -1;
@ -625,8 +692,6 @@ int client_start(void)
client_show_info(); client_show_info();
ioevent_add_input(client_fd, client_func);
if (options.interactive) { if (options.interactive) {
int old_client_fd = client_fd; int old_client_fd = client_fd;
@ -648,7 +713,7 @@ int client_start(void)
readline_exit(); readline_exit();
} }
else { else {
if (pipe(pipefd) == -1) { if (pipe2(pipefd, O_NONBLOCK | O_CLOEXEC) == -1) {
fprintf(stderr, "could not create pipe (%s)", strerror(errno)); fprintf(stderr, "could not create pipe (%s)", strerror(errno));
return -1; return -1;
} }
@ -713,7 +778,7 @@ int client_send_msg(struct process *process, enum mt_operation op, void *payload
if (options.logfile) if (options.logfile)
return -1; return -1;
ret = sock_send_msg(client_fd, process->val16(op), process->pid, 0, payload, payload_len); ret = sock_send_msg(client_fd, process->val16(op), process->pid, payload, payload_len);
if (ret < 0) if (ret < 0)
client_broken(); client_broken();

View File

@ -28,9 +28,10 @@
struct process; struct process;
struct process *client_first_process(void); struct process *client_first_process(void);
struct process *client_find_process(pid_t pid); struct process *client_find_process(unsigned int pid);
void client_iterate_processes(int (*func)(struct process *process)); void client_iterate_processes(int (*func)(struct process *process));
void client_show_info(void); void client_show_info(void);
void client_request_info(void);
int client_wait_op(enum mt_operation op); int client_wait_op(enum mt_operation op);
void client_close(void); void client_close(void);
int client_send_msg(struct process *process, enum mt_operation op, void *payload, unsigned int payload_len); int client_send_msg(struct process *process, enum mt_operation op, void *payload, unsigned int payload_len);

View File

@ -37,6 +37,7 @@
static int dump_term; static int dump_term;
static FILE *dump_outfile; static FILE *dump_outfile;
static int dump_char;
static int rows, cols; static int rows, cols;
static int row, col; static int row, col;
@ -99,12 +100,18 @@ int dump_init(FILE *file)
return 0; return 0;
} }
static int dump_getchar(void)
{
dump_char = getchar();
return 0;
}
static int dump_pager(void) static int dump_pager(void)
{ {
struct termios termios; struct termios termios;
struct termios termios_old; struct termios termios_old;
int c;
int len; int len;
ioevent_func oldfunc;
len = printf("Press <space> for next line, q for quit and any other for next page\r") - 1; len = printf("Press <space> for next line, q for quit and any other for next page\r") - 1;
fflush(stdout); fflush(stdout);
@ -114,14 +121,20 @@ static int dump_pager(void)
cfmakeraw(&termios); cfmakeraw(&termios);
tcsetattr(0, TCSADRAIN, &termios); tcsetattr(0, TCSADRAIN, &termios);
ioevent_wait_input(0, -1); oldfunc = ioevent_set_input_func(0, dump_getchar);
c = getchar();
dump_char = 0;
do {
ioevent_watch(-1);
} while(!dump_char);
ioevent_set_input_func(0, oldfunc);
tcsetattr(0, TCSANOW, &termios_old); tcsetattr(0, TCSANOW, &termios_old);
printf("%*s\r", len, ""); printf("%*s\r", len, "");
fflush(stdout); fflush(stdout);
switch(c) { switch(dump_char) {
case '\03': case '\03':
case 'q': case 'q':
if (col) if (col)

View File

@ -64,6 +64,7 @@ struct stack {
struct rb_stack { struct rb_stack {
struct rb_node node; struct rb_node node;
struct stack *stack; struct stack *stack;
unsigned long refcnt;
unsigned long leaks; unsigned long leaks;
unsigned long long n_allocations; unsigned long long n_allocations;
unsigned long long total_allocations; unsigned long long total_allocations;
@ -83,6 +84,16 @@ struct map {
unsigned int ignore:1; unsigned int ignore:1;
}; };
struct realloc_entry {
struct list_head list;
unsigned int pid;
unsigned long addr;
unsigned long size;
unsigned long flags;
struct rb_stack *stack;
enum mt_operation operation;
};
struct regex_list { struct regex_list {
regex_t re; regex_t re;
struct regex_list *next; struct regex_list *next;
@ -120,8 +131,8 @@ static const char *str_operation(enum mt_operation operation)
return "realloc enter"; return "realloc enter";
case MT_REALLOC: case MT_REALLOC:
return "realloc"; return "realloc";
case MT_REALLOC_FAILED: case MT_REALLOC_DONE:
return "realloc failed"; return "realloc done";
case MT_MEMALIGN: case MT_MEMALIGN:
return "memalign"; return "memalign";
case MT_POSIX_MEMALIGN: case MT_POSIX_MEMALIGN:
@ -389,9 +400,22 @@ static void stack_resolv(struct process *process, struct stack *stack)
} }
} }
static void stack_put(struct stack *stack) static struct rb_stack *stack_get(struct rb_stack *stack_node)
{ {
if (--stack->refcnt == 0) { ++stack_node->refcnt;
++stack_node->stack->refcnt;
return stack_node;
}
static void stack_put(struct rb_stack *stack_node)
{
struct stack *stack = stack_node->stack;
if (!--stack_node->refcnt)
free(stack_node);
if (!--stack->refcnt) {
if (stack->syms) { if (stack->syms) {
unsigned int i; unsigned int i;
@ -431,6 +455,7 @@ static struct rb_stack *stack_clone(struct process *process, struct rb_stack *st
if (!this) if (!this)
return NULL; return NULL;
this->refcnt = 0;
this->leaks = stack_node->leaks; this->leaks = stack_node->leaks;
this->n_allocations = stack_node->n_allocations; this->n_allocations = stack_node->n_allocations;
this->n_mismatched = stack_node->n_mismatched; this->n_mismatched = stack_node->n_mismatched;
@ -439,7 +464,8 @@ static struct rb_stack *stack_clone(struct process *process, struct rb_stack *st
this->bytes_leaked = stack_node->bytes_leaked; this->bytes_leaked = stack_node->bytes_leaked;
this->tsc = stack_node->tsc; this->tsc = stack_node->tsc;
this->stack = stack_node->stack; this->stack = stack_node->stack;
this->stack->refcnt++;
stack_get(this);
/* Add new node and rebalance tree. */ /* Add new node and rebalance tree. */
rb_link_node(&this->node, parent, new); rb_link_node(&this->node, parent, new);
@ -450,7 +476,7 @@ static struct rb_stack *stack_clone(struct process *process, struct rb_stack *st
return this; return this;
} }
static struct rb_stack *stack_add(struct process *process, pid_t pid, void *addrs, uint32_t stack_size, enum mt_operation operation) static struct rb_stack *stack_add(struct process *process, unsigned int pid, void *addrs, uint32_t stack_size, enum mt_operation operation)
{ {
struct rb_root *root = &process->stack_table; struct rb_root *root = &process->stack_table;
struct rb_node **new = &(root->rb_node), *parent = NULL; struct rb_node **new = &(root->rb_node), *parent = NULL;
@ -487,7 +513,7 @@ static struct rb_stack *stack_add(struct process *process, pid_t pid, void *addr
return NULL; return NULL;
} }
stack->refcnt = 1; stack->refcnt = 0;
stack->addrs = malloc(stack_size); stack->addrs = malloc(stack_size);
stack->size = stack_size; stack->size = stack_size;
stack->entries = stack_size / process->ptr_size; stack->entries = stack_size / process->ptr_size;
@ -497,6 +523,7 @@ static struct rb_stack *stack_add(struct process *process, pid_t pid, void *addr
memcpy(stack->addrs, addrs, stack_size); memcpy(stack->addrs, addrs, stack_size);
this->refcnt = 0;
this->n_allocations = 0; this->n_allocations = 0;
this->n_mismatched = 0; this->n_mismatched = 0;
this->total_allocations = 0; this->total_allocations = 0;
@ -505,6 +532,8 @@ static struct rb_stack *stack_add(struct process *process, pid_t pid, void *addr
this->bytes_leaked = 0; this->bytes_leaked = 0;
this->stack = stack; this->stack = stack;
stack_get(this);
stack_resolv(process, stack); stack_resolv(process, stack);
/* Add new node and rebalance tree. */ /* Add new node and rebalance tree. */
@ -516,7 +545,7 @@ static struct rb_stack *stack_add(struct process *process, pid_t pid, void *addr
return this; return this;
} }
static void process_dump_stack(struct process *process, struct rb_stack *this, int lflag) static void dump_stack(struct rb_stack *this, int lflag, unsigned long (*get_ulong)(void *), uint8_t ptr_size)
{ {
uint32_t i; uint32_t i;
void *addrs; void *addrs;
@ -526,7 +555,7 @@ static void process_dump_stack(struct process *process, struct rb_stack *this, i
return; return;
for(addrs = stack->addrs, i = 0; i < stack->entries; ++i) { for(addrs = stack->addrs, i = 0; i < stack->entries; ++i) {
if (dump_printf(" [0x%lx]", process->get_ulong(addrs))) if (dump_printf(" [0x%lx]", get_ulong(addrs)))
return; return;
if (!stack->syms[i]) { if (!stack->syms[i]) {
@ -548,7 +577,7 @@ static void process_dump_stack(struct process *process, struct rb_stack *this, i
if (dump_printf("\n") == -1) if (dump_printf("\n") == -1)
return; return;
addrs += process->ptr_size; addrs += ptr_size;
} }
} }
@ -625,6 +654,8 @@ static void process_rb_delete_block(struct process *process, struct rb_block *bl
block->stack_node->n_allocations--; block->stack_node->n_allocations--;
stack_put(block->stack_node);
free(block); free(block);
} }
@ -645,7 +676,7 @@ static int process_rb_insert_block(struct process *process, unsigned long addr,
parent = *new; parent = *new;
if (addr <= this->addr && addr + n > this->addr) { if (addr <= this->addr && addr + n > this->addr) {
if (options.kill || options.verbose > 2) { if (unlikely(options.kill || options.verbose > 2)) {
process_dump_collision(process, this, addr, size, operation); process_dump_collision(process, this, addr, size, operation);
if (options.kill) if (options.kill)
@ -671,7 +702,8 @@ static int process_rb_insert_block(struct process *process, unsigned long addr,
block->stack_node->n_allocations++; block->stack_node->n_allocations++;
block->stack_node->total_allocations++; block->stack_node->total_allocations++;
block->stack_node->bytes_used += size; block->stack_node->bytes_used += size;
block->stack_node->stack->refcnt++;
stack_get(block->stack_node);
/* Add new node and rebalance tree. */ /* Add new node and rebalance tree. */
rb_link_node(&block->node, parent, new); rb_link_node(&block->node, parent, new);
@ -705,7 +737,7 @@ static struct map *_process_add_map(struct process *process, unsigned long addr,
list_add_tail(&map->list, &process->map_list); list_add_tail(&map->list, &process->map_list);
/* fixit: it is possible that stack_add() can produce false matches */ /* fixit: it is now possible that stack_add() produce false matches */
return map; return map;
} }
@ -774,26 +806,38 @@ static void process_init(struct process *process, unsigned int swap_endian, unsi
process->filename = NULL; process->filename = NULL;
} }
static void realloc_del(struct realloc_entry *re)
{
stack_put(re->stack);
list_del(&re->list);
free(re);
}
void process_reset_allocations(struct process *process) void process_reset_allocations(struct process *process)
{ {
struct rb_block *rbb, *rbb_next; struct rb_block *rbb, *rbb_next;
struct rb_stack *rbs, *rbs_next; struct list_head *it, *next;
rbtree_postorder_for_each_entry_safe(rbb, rbb_next, &process->block_table, node) { rbtree_postorder_for_each_entry_safe(rbb, rbb_next, &process->block_table, node) {
process->n_allocations--; --process->n_allocations;
--rbb->stack_node->n_allocations;
stack_put(rbb->stack_node);
free(rbb); free(rbb);
} }
if (process->n_allocations)
fatal("invalid allocation count!\n");
process->block_table = RB_ROOT; process->block_table = RB_ROOT;
rbtree_postorder_for_each_entry_safe(rbs, rbs_next, &process->stack_table, node) { list_for_each_safe(it, next, &process->realloc_list) {
stack_put(rbs->stack); struct realloc_entry *re = container_of(it, struct realloc_entry, list);
free(rbs);
realloc_del(re);
} }
process->stack_table = RB_ROOT;
process->total_allocations = 0; process->total_allocations = 0;
process->bytes_used = 0; process->bytes_used = 0;
process->stack_trees = 0;
process->leaks = 0; process->leaks = 0;
process->leaked_bytes = 0; process->leaked_bytes = 0;
process->tsc = 0; process->tsc = 0;
@ -801,10 +845,24 @@ void process_reset_allocations(struct process *process)
void process_reset(struct process *process) void process_reset(struct process *process)
{ {
struct rb_stack *rbs, *rbs_next;
struct list_head *it, *next; struct list_head *it, *next;
process_reset_allocations(process); process_reset_allocations(process);
rbtree_postorder_for_each_entry_safe(rbs, rbs_next, &process->stack_table, node) {
if (rbs->refcnt != 1)
fatal("unexpected stack tree ref count!\n");
stack_put(rbs);
--process->stack_trees;
}
if (process->stack_trees)
fatal("invalid stack tree count!\n");
process->stack_table = RB_ROOT;
list_for_each_safe(it, next, &process->map_list) { list_for_each_safe(it, next, &process->map_list) {
struct map *map = container_of(it, struct map, list); struct map *map = container_of(it, struct map, list);
@ -944,29 +1002,36 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb
struct rb_stack **arr; struct rb_stack **arr;
unsigned long i; unsigned long i;
void *data; void *data;
unsigned long stack_trees = process->stack_trees;
unsigned long (*get_ulong)(void *) = process->get_ulong;
uint8_t ptr_size = process->ptr_size;
if (dump_init(file) == -1) if (dump_init(file) == -1)
return; return;
arr = malloc(sizeof(struct rb_stack *) * stack_trees);
if (!arr)
return;
for(i = 0, data = rb_first(&process->stack_table); data; data = rb_next(data)) {
struct rb_stack *stack_node = container_of(data, struct rb_stack, node);
arr[i++] = stack_get(stack_node);
}
if (stack_trees != i)
fatal("invalid stack tree count!\n");
dump_printf("Process dump %d %s\n", process->pid, process->filename ? process->filename : "<unknown>"); dump_printf("Process dump %d %s\n", process->pid, process->filename ? process->filename : "<unknown>");
if (!process->stack_trees) if (!stack_trees)
goto skip; goto skip;
arr = malloc(sizeof(struct rb_stack *) * process->stack_trees); qsort(arr, stack_trees, sizeof(struct rb_stack *), (void *)sortby);
if (!arr)
goto skip;
for(i = 0, data = rb_first(&process->stack_table); data; data = rb_next(data))
arr[i++] = container_of(data, struct rb_stack, node);
assert(i == process->stack_trees);
qsort(arr, process->stack_trees, sizeof(struct rb_stack *), (void *)sortby);
if (file == stderr) { if (file == stderr) {
unsigned long n = process->stack_trees / 2; unsigned long n = stack_trees / 2;
unsigned long l = process->stack_trees - 1; unsigned long l = stack_trees - 1;
for(i = 0; i < n; ++i) { for(i = 0; i < n; ++i) {
struct rb_stack *tmp = arr[i]; struct rb_stack *tmp = arr[i];
@ -976,7 +1041,7 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb
} }
} }
for(i = 0; i < process->stack_trees; ++i) { for(i = 0; i < stack_trees; ++i) {
struct rb_stack *stack = arr[i]; struct rb_stack *stack = arr[i];
if (!skipfunc(stack)) { if (!skipfunc(stack)) {
@ -1011,11 +1076,15 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb
if (dump_printf(" tsc: %llu\n", stack->tsc) == -1) if (dump_printf(" tsc: %llu\n", stack->tsc) == -1)
break; break;
process_dump_stack(process, stack, lflag); dump_stack(stack, lflag, get_ulong, ptr_size);
} }
} }
free(arr);
for(i = 0; i < stack_trees; ++i)
stack_put(arr[i]);
skip: skip:
free(arr);
dump_flush(); dump_flush();
return; return;
} }
@ -1112,7 +1181,7 @@ void *process_scan(struct process *process, void *leaks, uint32_t payload_len)
for(i = 0; i < n; ++i) { for(i = 0; i < n; ++i) {
struct rb_block *block = process_rb_search(&process->block_table, process->get_ulong(leaks)); struct rb_block *block = process_rb_search(&process->block_table, process->get_ulong(leaks));
if (!(block->flags & BLOCK_LEAKED)) { if (block && !(block->flags & BLOCK_LEAKED)) {
block->flags |= BLOCK_LEAKED; block->flags |= BLOCK_LEAKED;
block->stack_node->leaks++; block->stack_node->leaks++;
@ -1189,7 +1258,7 @@ void process_munmap(struct process *process, struct mt_msg *mt_msg, void *payloa
break; break;
if (!is_mmap(block->stack_node->stack->operation)) { if (!is_mmap(block->stack_node->stack->operation)) {
if (options.kill || options.verbose > 2) { if (unlikely(options.kill || options.verbose > 2)) {
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr); fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
if (options.kill) if (options.kill)
@ -1255,7 +1324,6 @@ static int is_sane(struct rb_block *block, enum mt_operation op)
switch(block->stack_node->stack->operation) { switch(block->stack_node->stack->operation) {
case MT_MALLOC: case MT_MALLOC:
case MT_REALLOC: case MT_REALLOC:
case MT_REALLOC_FAILED:
case MT_MEMALIGN: case MT_MEMALIGN:
case MT_POSIX_MEMALIGN: case MT_POSIX_MEMALIGN:
case MT_ALIGNED_ALLOC: case MT_ALIGNED_ALLOC:
@ -1285,6 +1353,7 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload)
struct rb_block *block = NULL; struct rb_block *block = NULL;
uint32_t payload_len = mt_msg->payload_len; uint32_t payload_len = mt_msg->payload_len;
unsigned long ptr; unsigned long ptr;
unsigned long pid;
void *stack_data; void *stack_data;
unsigned long stack_size; unsigned long stack_size;
@ -1295,6 +1364,7 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload)
struct mt_alloc_payload_64 *mt_alloc = payload; struct mt_alloc_payload_64 *mt_alloc = payload;
ptr = process->get_ulong(&mt_alloc->ptr); ptr = process->get_ulong(&mt_alloc->ptr);
pid = process->get_ulong(&mt_alloc->size);
stack_data = payload + sizeof(*mt_alloc); stack_data = payload + sizeof(*mt_alloc);
stack_size = (payload_len - sizeof(*mt_alloc)); stack_size = (payload_len - sizeof(*mt_alloc));
@ -1303,6 +1373,7 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload)
struct mt_alloc_payload_32 *mt_alloc = payload; struct mt_alloc_payload_32 *mt_alloc = payload;
ptr = process->get_ulong(&mt_alloc->ptr); ptr = process->get_ulong(&mt_alloc->ptr);
pid = process->get_ulong(&mt_alloc->size);
stack_data = payload + sizeof(*mt_alloc); stack_data = payload + sizeof(*mt_alloc);
stack_size = (payload_len - sizeof(*mt_alloc)); stack_size = (payload_len - sizeof(*mt_alloc));
@ -1313,7 +1384,7 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload)
block = process_rb_search(&process->block_table, ptr); block = process_rb_search(&process->block_table, ptr);
if (block) { if (block) {
if (is_mmap(block->stack_node->stack->operation)) { if (is_mmap(block->stack_node->stack->operation)) {
if (options.kill || options.verbose > 2) { if (unlikely(options.kill || options.verbose > 2)) {
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr); fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
if (options.kill) if (options.kill)
@ -1328,12 +1399,27 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload)
stack->tsc = process->tsc++; stack->tsc = process->tsc++;
} }
if (mt_msg->operation == MT_REALLOC_ENTER) {
struct realloc_entry *re = malloc(sizeof(*re));
re->addr = block->addr;
re->size = block->size;
re->flags = block->flags;
re->operation = block->stack_node->stack->operation;
re->pid = pid;
re->stack = block->stack_node;
stack_get(re->stack);
list_add_tail(&re->list, &process->realloc_list);
}
process_rb_delete_block(process, block); process_rb_delete_block(process, block);
} }
else { else {
if (!process->attached) { if (!process->attached) {
if (options.kill || options.verbose > 2) { if (unlikely(options.kill || options.verbose > 2)) {
fprintf(stderr, ">>> block %#lx not found pid:%d tid:%d\n", ptr, process->pid, mt_msg->tid); fprintf(stderr, ">>> block %#lx not found pid:%d\n", ptr, process->pid);
if (options.kill) if (options.kill)
abort(); abort();
@ -1342,6 +1428,46 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload)
} }
} }
void process_realloc_done(struct process *process, struct mt_msg *mt_msg, void *payload)
{
unsigned long ptr;
unsigned long pid;
struct list_head *it;
if (!process->tracing)
return;
if (process->is_64bit) {
struct mt_alloc_payload_64 *mt_alloc = payload;
ptr = process->get_ulong(&mt_alloc->ptr);
pid = process->get_ulong(&mt_alloc->size);
}
else {
struct mt_alloc_payload_32 *mt_alloc = payload;
ptr = process->get_ulong(&mt_alloc->ptr);
pid = process->get_ulong(&mt_alloc->size);
}
debug(DEBUG_FUNCTION, "ptr=%#lx ", ptr);
list_for_each(it, &process->realloc_list) {
struct realloc_entry *re = container_of(it, struct realloc_entry, list);
if (re->pid == pid) {
if (!ptr)
process_rb_insert_block(process, re->addr, re->size, re->stack, re->flags, re->operation);
realloc_del(re);
break;
}
}
return;
}
void process_alloc(struct process *process, struct mt_msg *mt_msg, void *payload) void process_alloc(struct process *process, struct mt_msg *mt_msg, void *payload)
{ {
struct rb_block *block = NULL; struct rb_block *block = NULL;
@ -1379,7 +1505,7 @@ void process_alloc(struct process *process, struct mt_msg *mt_msg, void *payload
block = process_rb_search_range(&process->block_table, ptr, size); block = process_rb_search_range(&process->block_table, ptr, size);
if (block) { if (block) {
if (options.kill || options.verbose > 2) { if (unlikely(options.kill || options.verbose > 2)) {
process_dump_collision(process, block, ptr, size, mt_msg->operation); process_dump_collision(process, block, ptr, size, mt_msg->operation);
if (options.kill) if (options.kill)
@ -1405,7 +1531,7 @@ void process_reinit(struct process *process, unsigned int swap_endian, unsigned
process_init(process, swap_endian, is_64bit, attached); process_init(process, swap_endian, is_64bit, attached);
} }
struct process *process_new(pid_t pid, unsigned int swap_endian, unsigned int tracing) struct process *process_new(unsigned int pid, unsigned int swap_endian, unsigned int tracing)
{ {
struct process *process = malloc(sizeof(*process)); struct process *process = malloc(sizeof(*process));
@ -1416,6 +1542,7 @@ struct process *process_new(pid_t pid, unsigned int swap_endian, unsigned int tr
process->block_table = RB_ROOT; process->block_table = RB_ROOT;
process->stack_table = RB_ROOT; process->stack_table = RB_ROOT;
INIT_LIST_HEAD(&process->map_list); INIT_LIST_HEAD(&process->map_list);
INIT_LIST_HEAD(&process->realloc_list);
process_init(process, swap_endian, 0, 0); process_init(process, swap_endian, 0, 0);
@ -1537,7 +1664,6 @@ void process_status(struct process *process)
" number of open allocations: %lu\n" " number of open allocations: %lu\n"
" total number of allocations: %lu\n" " total number of allocations: %lu\n"
" average allocation: %f bytes\n" " average allocation: %f bytes\n"
" number of allocators: %lu\n"
" number of leaks: %lu\n" " number of leaks: %lu\n"
" number of leaked bytes: %llu\n" " number of leaked bytes: %llu\n"
" status: %s\n", " status: %s\n",
@ -1546,7 +1672,6 @@ void process_status(struct process *process)
process->n_allocations, process->n_allocations,
process->total_allocations, process->total_allocations,
process->n_allocations ? (double)process->bytes_used / process->n_allocations : 0.0, process->n_allocations ? (double)process->bytes_used / process->n_allocations : 0.0,
process->stack_trees,
process->leaks, process->leaks,
process->leaked_bytes, process->leaked_bytes,
process_get_status(process) process_get_status(process)

View File

@ -53,7 +53,7 @@ struct lib {
struct process { struct process {
enum process_status status; enum process_status status;
pid_t pid; unsigned int pid;
char *filename; char *filename;
unsigned long bytes_used; unsigned long bytes_used;
unsigned long n_allocations; unsigned long n_allocations;
@ -64,6 +64,7 @@ struct process {
struct rb_root block_table; struct rb_root block_table;
struct rb_root stack_table; struct rb_root stack_table;
struct list_head map_list; struct list_head map_list;
struct list_head realloc_list;
unsigned long long tsc; unsigned long long tsc;
unsigned int tracing:1; unsigned int tracing:1;
unsigned int swap_endian:1; unsigned int swap_endian:1;
@ -77,7 +78,7 @@ struct process {
uint8_t ptr_size; uint8_t ptr_size;
}; };
struct process *process_new(pid_t pid, unsigned int swap_endian, unsigned int tracing); struct process *process_new(unsigned int pid, unsigned int swap_endian, unsigned int tracing);
void process_reset(struct process *process); void process_reset(struct process *process);
void process_reset_allocations(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_reinit(struct process *process, unsigned int swap_endian, unsigned int is_64bit, unsigned int attached);
@ -98,6 +99,7 @@ void process_munmap(struct process *process, struct mt_msg *msg, void *payload);
void process_add_map(struct process *process, void *payload, uint32_t payload_len); void process_add_map(struct process *process, void *payload, uint32_t payload_len);
void process_del_map(struct process *process, void *payload, uint32_t payload_len); void process_del_map(struct process *process, void *payload, uint32_t payload_len);
void process_detach(struct process *process); void process_detach(struct process *process);
void process_realloc_done(struct process *process, struct mt_msg *mt_msg, void *payload);
unsigned long process_leaks_scan(struct process *process, int mode); unsigned long process_leaks_scan(struct process *process, int mode);

View File

@ -503,7 +503,9 @@ static int do_show_info(struct cmd_opt *cmd, struct cmd_opt *opt, int argc, cons
return -1; return -1;
} }
client_request_info();
client_show_info(); client_show_info();
return 0; return 0;
} }

View File

@ -78,18 +78,18 @@ unsigned long find_block(unsigned long (*get_val)(void *data, unsigned long inde
do { do {
middle = (first + last) >> 1; middle = (first + last) >> 1;
val = get_val(arr, middle); val = get_val(arr, middle);
if (addr < val) if (addr < val)
last = middle; last = middle;
else if (addr > val) else
if (addr > val)
first = middle + 1; first = middle + 1;
else else
return middle; return middle;
} while (first < last); } while (first < last);
return n; return n;
} }

View File

@ -58,6 +58,14 @@
(type *)( (char *)__mptr - offsetof(type,member) );}) (type *)( (char *)__mptr - offsetof(type,member) );})
#if 1
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
#define likely(x) (x)
#define unlikely(x) (x)
#endif
#define fatal(fmt...) _fatal(__FILE__,__PRETTY_FUNCTION__,__LINE__ , ##fmt),abort() #define fatal(fmt...) _fatal(__FILE__,__PRETTY_FUNCTION__,__LINE__ , ##fmt),abort()
void _fatal(const char *file, const char *func, int line, const char *format, ...) __attribute__ ((format (printf, 4, 5)));; void _fatal(const char *file, const char *func, int line, const char *format, ...) __attribute__ ((format (printf, 4, 5)));;

View File

@ -18,6 +18,9 @@
/* Define to 1 if you have the <bfd.h> header file. */ /* Define to 1 if you have the <bfd.h> header file. */
#undef HAVE_BFD_H #undef HAVE_BFD_H
/* Define to 1 if you have the `clock_gettime' function. */
#undef HAVE_CLOCK_GETTIME
/* Define to 1 if you have the <dlfcn.h> header file. */ /* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H #undef HAVE_DLFCN_H
@ -60,6 +63,9 @@
/* Define to 1 if you have the `readline' library (-lreadline). */ /* Define to 1 if you have the `readline' library (-lreadline). */
#undef HAVE_LIBREADLINE #undef HAVE_LIBREADLINE
/* Define to 1 if you have the `rt' library (-lrt). */
#undef HAVE_LIBRT
/* Define to 1 if you have the `selinux' library (-lselinux). */ /* Define to 1 if you have the `selinux' library (-lselinux). */
#undef HAVE_LIBSELINUX #undef HAVE_LIBSELINUX

69
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for mtrace-ng 0.4. # Generated by GNU Autoconf 2.69 for mtrace-ng 0.5.
# #
# Report bugs to <stefani@seibold.net>. # Report bugs to <stefani@seibold.net>.
# #
@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='mtrace-ng' PACKAGE_NAME='mtrace-ng'
PACKAGE_TARNAME='mtrace-ng' PACKAGE_TARNAME='mtrace-ng'
PACKAGE_VERSION='0.4' PACKAGE_VERSION='0.5'
PACKAGE_STRING='mtrace-ng 0.4' PACKAGE_STRING='mtrace-ng 0.5'
PACKAGE_BUGREPORT='stefani@seibold.net' PACKAGE_BUGREPORT='stefani@seibold.net'
PACKAGE_URL='' PACKAGE_URL=''
@ -1329,7 +1329,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # 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. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures mtrace-ng 0.4 to adapt to many kinds of systems. \`configure' configures mtrace-ng 0.5 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1399,7 +1399,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of mtrace-ng 0.4:";; short | recursive ) echo "Configuration of mtrace-ng 0.5:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1518,7 +1518,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
mtrace-ng configure 0.4 mtrace-ng configure 0.5
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
@ -2124,7 +2124,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by mtrace-ng $as_me 0.4, which was It was created by mtrace-ng $as_me 0.5, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@ -12006,7 +12006,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='mtrace-ng' PACKAGE='mtrace-ng'
VERSION='0.4' VERSION='0.5'
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
@ -13238,6 +13238,7 @@ for ac_func in \
atexit \ atexit \
getcwd \ getcwd \
gettimeofday \ gettimeofday \
clock_gettime \
memset \ memset \
mkdir \ mkdir \
rmdir \ rmdir \
@ -13260,6 +13261,54 @@ fi
done done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
$as_echo_n "checking for clock_gettime in -lrt... " >&6; }
if ${ac_cv_lib_rt_clock_gettime+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lrt $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char clock_gettime ();
int
main ()
{
return clock_gettime ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_rt_clock_gettime=yes
else
ac_cv_lib_rt_clock_gettime=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5
$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_LIBRT 1
_ACEOF
LIBS="-lrt $LIBS"
else
as_fn_error $? "*** librt not found on your system" "$LINENO" 5
fi
# #
# Debugging # Debugging
@ -13844,7 +13893,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by mtrace-ng $as_me 0.4, which was This file was extended by mtrace-ng $as_me 0.5, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -13910,7 +13959,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
mtrace-ng config.status 0.4 mtrace-ng config.status 0.5
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

@ -24,7 +24,7 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
AC_PREREQ(2.65) AC_PREREQ(2.65)
AC_INIT([mtrace-ng],[0.4],[stefani@seibold.net]) AC_INIT([mtrace-ng],[0.5],[stefani@seibold.net])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR(main.c) AC_CONFIG_SRCDIR(main.c)
AC_CONFIG_MACRO_DIR([config/m4]) AC_CONFIG_MACRO_DIR([config/m4])
@ -227,6 +227,7 @@ AC_CHECK_FUNCS([ \
atexit \ atexit \
getcwd \ getcwd \
gettimeofday \ gettimeofday \
clock_gettime \
memset \ memset \
mkdir \ mkdir \
rmdir \ rmdir \
@ -238,6 +239,9 @@ AC_CHECK_FUNCS([ \
process_vm_readv \ process_vm_readv \
]) ])
AC_CHECK_LIB([rt], [clock_gettime],,
[AC_MSG_ERROR([*** librt not found on your system])]
)
# #
# Debugging # Debugging

320
dwarf.c
View File

@ -317,88 +317,80 @@ static const uint8_t dwarf_operands[256] = {
[DW_OP_call_ref] = OPND1(OFFSET) [DW_OP_call_ref] = OPND1(OFFSET)
}; };
static int dwarf_access_mem(struct dwarf_addr_space *as, arch_addr_t addr, void *valp, size_t size) static inline __attribute__((always_inline)) int dwarf_access_mem(struct dwarf_addr_space *as, arch_addr_t addr, void *valp, size_t size)
{ {
struct dwarf_cursor *c = &as->cursor; struct dwarf_cursor *c = &as->cursor;
if (!addr) { if (unlikely(!addr)) {
debug(DEBUG_DWARF, "invalid null memory access"); debug(DEBUG_DWARF, "invalid null memory access");
return -DWARF_EINVAL; return -DWARF_EINVAL;
} }
if (!valp) if (unlikely(!valp))
return 0; return 0;
if (!as) { if (unlikely(!as)) {
memcpy(valp, (void *)addr, size); memcpy(valp, (void *)addr, size);
return 0; return 0;
} }
if (as->addr && as->addr <= addr && addr + size - as->addr <= sizeof(as->val)) { if (unlikely(copy_from_proc(c->task, addr, valp, size) != (int)size)) {
memcpy(valp, &as->val_bytes[addr - as->addr], size);
return 0;
}
if (copy_from_proc(c->task, addr, &as->val, sizeof(as->val)) != sizeof(as->val)) {
debug(DEBUG_DWARF, "cannot access memory %#lx of pid %d", addr, c->task->pid); debug(DEBUG_DWARF, "cannot access memory %#lx of pid %d", addr, c->task->pid);
return -DWARF_EINVAL; return -DWARF_EINVAL;
} }
as->addr = addr;
memcpy(valp, as->val_bytes, size);
return 0; return 0;
} }
static inline int dwarf_read8(struct dwarf_addr_space *as, arch_addr_t *addr, void *valp) static inline __attribute__((always_inline)) int dwarf_read8(struct dwarf_addr_space *as, arch_addr_t *addr, void *valp)
{ {
int ret; int ret;
ret = dwarf_access_mem(as, *addr, valp, 1); ret = dwarf_access_mem(as, *addr, valp, 1);
if (ret) if (unlikely(ret))
return ret; return ret;
*addr += 1; *addr += 1;
return 0; return 0;
} }
static inline int dwarf_read16(struct dwarf_addr_space *as, arch_addr_t *addr, void *valp) static inline __attribute__((always_inline)) int dwarf_read16(struct dwarf_addr_space *as, arch_addr_t *addr, void *valp)
{ {
int ret; int ret;
ret = dwarf_access_mem(as, *addr, valp, 2); ret = dwarf_access_mem(as, *addr, valp, 2);
if (ret) if (unlikely(ret))
return ret; return ret;
*addr += 2; *addr += 2;
return 0; return 0;
} }
static inline int dwarf_read32(struct dwarf_addr_space *as, arch_addr_t *addr, void *valp) static inline __attribute__((always_inline)) int dwarf_read32(struct dwarf_addr_space *as, arch_addr_t *addr, void *valp)
{ {
int ret; int ret;
ret = dwarf_access_mem(as, *addr, valp, 4); ret = dwarf_access_mem(as, *addr, valp, 4);
if (ret) if (unlikely(ret))
return ret; return ret;
*addr += 4; *addr += 4;
return 0; return 0;
} }
static inline int dwarf_read64(struct dwarf_addr_space *as, arch_addr_t *addr, void *valp) static inline __attribute__((always_inline)) int dwarf_read64(struct dwarf_addr_space *as, arch_addr_t *addr, void *valp)
{ {
int ret; int ret;
ret = dwarf_access_mem(as, *addr, valp, 8); ret = dwarf_access_mem(as, *addr, valp, 8);
if (ret) if (unlikely(ret))
return ret; return ret;
*addr += 8; *addr += 8;
return 0; return 0;
} }
static inline int dwarf_readw(struct dwarf_addr_space *as, arch_addr_t *addr, arch_addr_t *valp, int is_64bit) static int dwarf_readw(struct dwarf_addr_space *as, arch_addr_t *addr, arch_addr_t *valp, int is_64bit)
{ {
int ret; int ret;
@ -428,7 +420,7 @@ static int dwarf_read_uleb128(struct dwarf_addr_space *as, arch_addr_t *addr, ar
int ret; int ret;
do { do {
if ((ret = dwarf_read8(as, addr, &byte)) < 0) if (unlikely((ret = dwarf_read8(as, addr, &byte)) < 0))
return ret; return ret;
val |= ((arch_addr_t) byte & 0x7f) << shift; val |= ((arch_addr_t) byte & 0x7f) << shift;
@ -448,7 +440,7 @@ static int dwarf_read_sleb128(struct dwarf_addr_space *as, arch_addr_t *addr, ar
int ret; int ret;
do { do {
if ((ret = dwarf_read8(as, addr, &byte)) < 0) if (unlikely((ret = dwarf_read8(as, addr, &byte)) < 0))
return ret; return ret;
val |= ((arch_addr_t) byte & 0x7f) << shift; val |= ((arch_addr_t) byte & 0x7f) << shift;
@ -518,7 +510,7 @@ static int dwarf_read_encoded_pointer(struct dwarf_addr_space *as, int local,
*addr = (initial_addr + size - 1) & -size; *addr = (initial_addr + size - 1) & -size;
if ((ret = dwarf_readw(as, addr, tmp_ptr, is_64bit)) < 0) if (unlikely((ret = dwarf_readw(as, addr, tmp_ptr, is_64bit)) < 0))
return ret; return ret;
*valp = tmp.addr; *valp = tmp.addr;
return 0; return 0;
@ -526,45 +518,45 @@ static int dwarf_read_encoded_pointer(struct dwarf_addr_space *as, int local,
switch (encoding & DW_EH_PE_FORMAT_MASK) { switch (encoding & DW_EH_PE_FORMAT_MASK) {
case DW_EH_PE_ptr: case DW_EH_PE_ptr:
if ((ret = dwarf_readw(as, addr, tmp_ptr, is_64bit)) < 0) if (unlikely((ret = dwarf_readw(as, addr, tmp_ptr, is_64bit)) < 0))
return ret; return ret;
val = tmp.addr; val = tmp.addr;
break; break;
case DW_EH_PE_uleb128: case DW_EH_PE_uleb128:
if ((ret = dwarf_read_uleb128(as, addr, &val)) < 0) if (unlikely((ret = dwarf_read_uleb128(as, addr, &val)) < 0))
return ret; return ret;
break; break;
case DW_EH_PE_udata2: case DW_EH_PE_udata2:
if ((ret = dwarf_read16(as, addr, tmp_ptr)) < 0) if (unlikely((ret = dwarf_read16(as, addr, tmp_ptr)) < 0))
return ret; return ret;
val = tmp.uval16; val = tmp.uval16;
break; break;
case DW_EH_PE_udata4: case DW_EH_PE_udata4:
if ((ret = dwarf_read32(as, addr, tmp_ptr)) < 0) if (unlikely((ret = dwarf_read32(as, addr, tmp_ptr)) < 0))
return ret; return ret;
val = tmp.uval32; val = tmp.uval32;
break; break;
case DW_EH_PE_udata8: case DW_EH_PE_udata8:
if ((ret = dwarf_read64(as, addr, tmp_ptr)) < 0) if (unlikely((ret = dwarf_read64(as, addr, tmp_ptr)) < 0))
return ret; return ret;
val = tmp.uval64; val = tmp.uval64;
break; break;
case DW_EH_PE_sleb128: case DW_EH_PE_sleb128:
if ((ret = dwarf_read_sleb128(as, addr, &val)) < 0) if (unlikely((ret = dwarf_read_sleb128(as, addr, &val)) < 0))
return ret; return ret;
break; break;
case DW_EH_PE_sdata2: case DW_EH_PE_sdata2:
if ((ret = dwarf_read16(as, addr, tmp_ptr)) < 0) if (unlikely((ret = dwarf_read16(as, addr, tmp_ptr)) < 0))
return ret; return ret;
val = tmp.sval16; val = tmp.sval16;
break; break;
case DW_EH_PE_sdata4: case DW_EH_PE_sdata4:
if ((ret = dwarf_read32(as, addr, tmp_ptr)) < 0) if (unlikely((ret = dwarf_read32(as, addr, tmp_ptr)) < 0))
return ret; return ret;
val = tmp.sval32; val = tmp.sval32;
break; break;
case DW_EH_PE_sdata8: case DW_EH_PE_sdata8:
if ((ret = dwarf_read64(as, addr, tmp_ptr)) < 0) if (unlikely((ret = dwarf_read64(as, addr, tmp_ptr)) < 0))
return ret; return ret;
val = tmp.sval64; val = tmp.sval64;
break; break;
@ -610,7 +602,7 @@ static int dwarf_read_encoded_pointer(struct dwarf_addr_space *as, int local,
arch_addr_t indirect_addr = val; arch_addr_t indirect_addr = val;
if (tmp_ptr) { if (tmp_ptr) {
if ((ret = dwarf_readw(indirect_as, &indirect_addr, &val, is_64bit)) < 0) if (unlikely((ret = dwarf_readw(indirect_as, &indirect_addr, &val, is_64bit)) < 0))
return ret; return ret;
} }
else else
@ -652,7 +644,7 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf
dci->lsda_encoding = DW_EH_PE_omit; dci->lsda_encoding = DW_EH_PE_omit;
if ((ret = dwarf_read32(NULL, &addr, &u32val)) < 0) if (unlikely((ret = dwarf_read32(NULL, &addr, &u32val)) < 0))
return ret; return ret;
if (u32val != 0xffffffff) { if (u32val != 0xffffffff) {
@ -662,7 +654,7 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf
len = u32val; len = u32val;
cie_end_addr = addr + len; cie_end_addr = addr + len;
if ((ret = dwarf_read32(NULL, &addr, &cie_id)) < 0) if (unlikely((ret = dwarf_read32(NULL, &addr, &cie_id)) < 0))
return ret; return ret;
if (cie_id) { if (cie_id) {
@ -674,13 +666,13 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf
/* the CIE is in the 64-bit DWARF format */ /* the CIE is in the 64-bit DWARF format */
uint64_t cie_id; uint64_t cie_id;
if ((ret = dwarf_read64(NULL, &addr, &u64val)) < 0) if (unlikely((ret = dwarf_read64(NULL, &addr, &u64val)) < 0))
return ret; return ret;
len = u64val; len = u64val;
cie_end_addr = addr + len; cie_end_addr = addr + len;
if ((ret = dwarf_read64(NULL, &addr, &cie_id)) < 0) if (unlikely((ret = dwarf_read64(NULL, &addr, &cie_id)) < 0))
return ret; return ret;
if (cie_id) { if (cie_id) {
@ -690,7 +682,7 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf
} }
dci->cie_instr_end = cie_end_addr; dci->cie_instr_end = cie_end_addr;
if ((ret = dwarf_read8(NULL, &addr, &version)) < 0) if (unlikely((ret = dwarf_read8(NULL, &addr, &version)) < 0))
return ret; return ret;
if (version != DWARF_CIE_VERSION && version != DWARF_CIE_VERSION_GCC) { if (version != DWARF_CIE_VERSION && version != DWARF_CIE_VERSION_GCC) {
@ -701,7 +693,7 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf
/* read and parse the augmentation string: */ /* read and parse the augmentation string: */
memset(augstr, 0, sizeof(augstr)); memset(augstr, 0, sizeof(augstr));
for (i = 0;;) { for (i = 0;;) {
if ((ret = dwarf_read8(NULL, &addr, &ch)) < 0) if (unlikely((ret = dwarf_read8(NULL, &addr, &ch)) < 0))
return ret; return ret;
if (!ch) if (!ch)
@ -711,19 +703,19 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf
augstr[i++] = ch; augstr[i++] = ch;
} }
if ((ret = dwarf_read_uleb128(NULL, &addr, &dci->code_align)) < 0 || (ret = dwarf_read_sleb128(NULL, &addr, &dci->data_align)) < 0) if (unlikely((ret = dwarf_read_uleb128(NULL, &addr, &dci->code_align)) < 0 || (ret = dwarf_read_sleb128(NULL, &addr, &dci->data_align)) < 0))
return ret; return ret;
/* Read the return-address column either as a u8 or as a uleb128. */ /* Read the return-address column either as a u8 or as a uleb128. */
if (version == 1) { if (version == 1) {
if ((ret = dwarf_read8(NULL, &addr, &ch)) < 0) if (unlikely((ret = dwarf_read8(NULL, &addr, &ch)) < 0))
return ret; return ret;
dci->ret_addr_column = dwarf_to_regnum(ch); dci->ret_addr_column = dwarf_to_regnum(ch);
} }
else { else {
arch_addr_t val; arch_addr_t val;
if ((ret = dwarf_read_uleb128(NULL, &addr, &val)) < 0) if (unlikely((ret = dwarf_read_uleb128(NULL, &addr, &val)) < 0))
return ret; return ret;
dci->ret_addr_column = dwarf_to_regnum(val); dci->ret_addr_column = dwarf_to_regnum(val);
} }
@ -731,7 +723,7 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf
i = 0; i = 0;
if (augstr[0] == 'z') { if (augstr[0] == 'z') {
dci->sized_augmentation = 1; dci->sized_augmentation = 1;
if ((ret = dwarf_read_uleb128(NULL, &addr, &aug_size)) < 0) if (unlikely((ret = dwarf_read_uleb128(NULL, &addr, &aug_size)) < 0))
return ret; return ret;
i++; i++;
} }
@ -740,13 +732,13 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf
switch (augstr[i]) { switch (augstr[i]) {
case 'L': case 'L':
/* read the LSDA pointer-encoding format. */ /* read the LSDA pointer-encoding format. */
if ((ret = dwarf_read8(NULL, &addr, &ch)) < 0) if (unlikely((ret = dwarf_read8(NULL, &addr, &ch)) < 0))
return ret; return ret;
dci->lsda_encoding = ch; dci->lsda_encoding = ch;
break; break;
case 'R': case 'R':
/* read the FDE pointer-encoding format. */ /* read the FDE pointer-encoding format. */
if ((ret = dwarf_read8(NULL, &addr, &fde_encoding)) < 0) if (unlikely((ret = dwarf_read8(NULL, &addr, &fde_encoding)) < 0))
return ret; return ret;
break; break;
case 'P': case 'P':
@ -754,9 +746,9 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf
uint8_t handler_encoding; uint8_t handler_encoding;
/* read the personality-routine pointer-encoding format. */ /* read the personality-routine pointer-encoding format. */
if ((ret = dwarf_read8(NULL, &addr, &handler_encoding)) < 0) if (unlikely((ret = dwarf_read8(NULL, &addr, &handler_encoding)) < 0))
return ret; return ret;
if ((ret = dwarf_read_encoded_pointer_local(as, &addr, handler_encoding, NULL, 0)) < 0) if (unlikely((ret = dwarf_read_encoded_pointer_local(as, &addr, handler_encoding, NULL, 0)) < 0))
break; break;
} }
case 'S': case 'S':
@ -791,7 +783,7 @@ static int dwarf_extract_cfi_from_fde(struct dwarf_addr_space *as, void *addrp)
struct dwarf_cie_info *dci = &as->cursor.dci; struct dwarf_cie_info *dci = &as->cursor.dci;
arch_addr_t addr = (arch_addr_t)addrp; arch_addr_t addr = (arch_addr_t)addrp;
if ((ret = dwarf_read32(NULL, &addr, &u32val)) < 0) if (unlikely((ret = dwarf_read32(NULL, &addr, &u32val)) < 0))
return ret; return ret;
if (u32val != 0xffffffff) { if (u32val != 0xffffffff) {
@ -809,7 +801,7 @@ static int dwarf_extract_cfi_from_fde(struct dwarf_addr_space *as, void *addrp)
fde_end_addr = addr + u32val; fde_end_addr = addr + u32val;
cie_offset_addr = addr; cie_offset_addr = addr;
if ((ret = dwarf_read32(NULL, &addr, &cie_offset32)) < 0) if (unlikely((ret = dwarf_read32(NULL, &addr, &cie_offset32)) < 0))
return ret; return ret;
cie_offset = cie_offset32; cie_offset = cie_offset32;
@ -819,13 +811,13 @@ static int dwarf_extract_cfi_from_fde(struct dwarf_addr_space *as, void *addrp)
/* the FDE is in the 64-bit DWARF format */ /* the FDE is in the 64-bit DWARF format */
if ((ret = dwarf_read64(NULL, &addr, &u64val)) < 0) if (unlikely((ret = dwarf_read64(NULL, &addr, &u64val)) < 0))
return ret; return ret;
fde_end_addr = addr + u64val; fde_end_addr = addr + u64val;
cie_offset_addr = addr; cie_offset_addr = addr;
if ((ret = dwarf_read64(NULL, &addr, &cie_offset64)) < 0) if (unlikely((ret = dwarf_read64(NULL, &addr, &cie_offset64)) < 0))
return ret; return ret;
cie_offset = cie_offset64; cie_offset = cie_offset64;
@ -846,31 +838,32 @@ static int dwarf_extract_cfi_from_fde(struct dwarf_addr_space *as, void *addrp)
if ((ret = parse_cie(as, cie_addr, dci)) < 0) if ((ret = parse_cie(as, cie_addr, dci)) < 0)
return ret; return ret;
if ((ret = dwarf_read_encoded_pointer_local(as, &addr, dci->fde_encoding, &dci->start_ip, 0)) < 0) if (unlikely((ret = dwarf_read_encoded_pointer_local(as, &addr, dci->fde_encoding, &dci->start_ip, 0)) < 0))
return ret; return ret;
/* IP-range has same encoding as FDE pointers, except that it's /* IP-range has same encoding as FDE pointers, except that it's
always an absolute value: */ always an absolute value: */
if ((ret = dwarf_read_encoded_pointer_local(as, &addr, dci->fde_encoding & DW_EH_PE_FORMAT_MASK, &dci->ip_range, 0)) < 0) if (unlikely((ret = dwarf_read_encoded_pointer_local(as, &addr, dci->fde_encoding & DW_EH_PE_FORMAT_MASK, &dci->ip_range, 0)) < 0))
return ret; return ret;
if (dci->sized_augmentation) { if (dci->sized_augmentation) {
arch_addr_t aug_size; arch_addr_t aug_size;
if ((ret = dwarf_read_uleb128(NULL, &addr, &aug_size)) < 0) if (unlikely((ret = dwarf_read_uleb128(NULL, &addr, &aug_size)) < 0))
return ret; return ret;
dci->fde_instr_start = addr + aug_size; dci->fde_instr_start = addr + aug_size;
} }
else else
dci->fde_instr_start = addr; dci->fde_instr_start = addr;
dci->fde_instr_end = fde_end_addr; dci->fde_instr_end = fde_end_addr;
if ((ret = dwarf_read_encoded_pointer_local(as, &addr, dci->lsda_encoding, NULL, dci->start_ip)) < 0) if (unlikely((ret = dwarf_read_encoded_pointer_local(as, &addr, dci->lsda_encoding, NULL, dci->start_ip)) < 0))
return ret; return ret;
if (dci->have_abi_marker) { if (dci->have_abi_marker) {
if ((ret = dwarf_read16(NULL, &addr, &dci->abi)) < 0 || (ret = dwarf_read16(NULL, &addr, &dci->tag)) < 0) if (unlikely((ret = dwarf_read16(NULL, &addr, &dci->abi)) < 0 || (ret = dwarf_read16(NULL, &addr, &dci->tag)) < 0))
return ret; return ret;
} }
@ -885,34 +878,18 @@ static inline int lib_addr_match(struct libref *libref, arch_addr_t ip)
int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip) int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip)
{ {
struct dwarf_cursor *c = &as->cursor; struct dwarf_cursor *c = &as->cursor;
struct task *leader;
struct list_head *it;
if (c->use_prev_instr) if (c->use_prev_instr)
ip -= 1; ip -= 1;
if (as->cursor.libref) { if (likely(c->libref)) {
if (lib_addr_match(as->cursor.libref, ip)) if (lib_addr_match(c->libref, ip))
return 0; return 0;
} }
leader = c->task->leader; c->libref = addr2libref(c->task->leader, ip);
if (!c->libref)
as->cursor.libref = NULL;
list_for_each(it, &leader->libraries_list) {
struct libref *libref = container_of(it, struct library, list)->libref;
if (lib_addr_match(libref, ip)) {
as->cursor.libref = libref;
break;
}
}
if (!as->cursor.libref) {
debug(DEBUG_DWARF, "no mapping found for IP %#lx", ip);
return -DWARF_ENOINFO; return -DWARF_ENOINFO;
}
return 0; return 0;
} }
@ -953,7 +930,7 @@ static int dwarf_search_unwind_table(struct dwarf_addr_space *as, arch_addr_t ip
struct libref *libref = as->cursor.libref; struct libref *libref = as->cursor.libref;
e = lookup(table_data, table_len, ip - libref->load_addr - libref->seg_offset); e = lookup(table_data, table_len, ip - libref->load_addr - libref->seg_offset);
if (!e) { if (unlikely(!e)) {
/* IP is inside this table's range, but there is no explicit unwind info. */ /* 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); debug(DEBUG_DWARF, "no unwind info found for IP %#lx", ip);
return -DWARF_ENOINFO; return -DWARF_ENOINFO;
@ -961,7 +938,7 @@ static int dwarf_search_unwind_table(struct dwarf_addr_space *as, arch_addr_t ip
fde_addr = libref->image_addr - libref->load_offset + e->fde_offset + libref->seg_offset; fde_addr = libref->image_addr - libref->load_offset + e->fde_offset + libref->seg_offset;
if ((ret = dwarf_extract_cfi_from_fde(as, fde_addr)) < 0) if (unlikely((ret = dwarf_extract_cfi_from_fde(as, fde_addr)) < 0))
return ret; return ret;
dci->start_ip -= ARCH_ADDR_T(libref->image_addr) - libref->load_addr; dci->start_ip -= ARCH_ADDR_T(libref->image_addr) - libref->load_addr;
@ -969,7 +946,7 @@ static int dwarf_search_unwind_table(struct dwarf_addr_space *as, arch_addr_t ip
if (!as->is_64bit) if (!as->is_64bit)
dci->start_ip &= 0xffffffff; dci->start_ip &= 0xffffffff;
if (ip < dci->start_ip || ip >= dci->start_ip + dci->ip_range) { if (unlikely(ip < dci->start_ip || ip >= dci->start_ip + dci->ip_range)) {
debug(DEBUG_DWARF, "IP %#lx out of range %#lx-%#lx", ip, dci->start_ip, dci->start_ip + dci->ip_range); debug(DEBUG_DWARF, "IP %#lx out of range %#lx-%#lx", ip, dci->start_ip, dci->start_ip + dci->ip_range);
return -DWARF_ENOINFO; return -DWARF_ENOINFO;
} }
@ -983,7 +960,7 @@ static int dwarf_access_reg(struct dwarf_addr_space *as, unsigned int reg, arch_
int map = dwarf_arch_map_reg(as, reg); int map = dwarf_arch_map_reg(as, reg);
if (map < 0) { if (unlikely(map < 0)) {
debug(DEBUG_DWARF, "could not map register %u", reg); debug(DEBUG_DWARF, "could not map register %u", reg);
return map; return map;
@ -1021,7 +998,7 @@ static int dwarf_get_reg(struct dwarf_addr_space *as, unsigned int reg, arch_add
{ {
struct dwarf_cursor *c = &as->cursor; struct dwarf_cursor *c = &as->cursor;
if (reg >= as->num_regs) if (unlikely(reg >= as->num_regs))
return err_inval_reg_num((unsigned int)*valp); return err_inval_reg_num((unsigned int)*valp);
if (as->ip_reg == reg) { if (as->ip_reg == reg) {
@ -1037,17 +1014,17 @@ static int dwarf_get_reg(struct dwarf_addr_space *as, unsigned int reg, arch_add
return dwarf_get(as, c->loc[reg], valp); return dwarf_get(as, c->loc[reg], valp);
} }
static inline int read_regnum(unsigned int num_regs, arch_addr_t *addr, arch_addr_t *valp) static int read_regnum(unsigned int num_regs, arch_addr_t *addr, arch_addr_t *valp)
{ {
int ret; int ret;
arch_addr_t val; arch_addr_t val;
if ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0) if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0))
return ret; return ret;
val = dwarf_to_regnum(val); val = dwarf_to_regnum(val);
if (val >= num_regs) if (unlikely(val >= num_regs))
return err_inval_reg_num(val); return err_inval_reg_num(val);
*valp = val; *valp = val;
@ -1086,7 +1063,7 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state *
/* Process everything up to and including the current 'ip', /* Process everything up to and including the current 'ip',
including all the DW_CFA_advance_loc instructions. */ including all the DW_CFA_advance_loc instructions. */
while (curr_ip <= ip && *addr < end_addr) { while (curr_ip <= ip && *addr < end_addr) {
if ((ret = dwarf_read8(NULL, addr, &op)) < 0) if (unlikely((ret = dwarf_read8(NULL, addr, &op)) < 0))
return ret; return ret;
if (op & DWARF_CFA_OPCODE_MASK) { if (op & DWARF_CFA_OPCODE_MASK) {
@ -1098,17 +1075,17 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state *
curr_ip += operand * dci->code_align; curr_ip += operand * dci->code_align;
break; break;
case DW_CFA_advance_loc1: case DW_CFA_advance_loc1:
if ((ret = dwarf_read8(NULL, addr, &u8)) < 0) if (unlikely((ret = dwarf_read8(NULL, addr, &u8)) < 0))
goto fail; goto fail;
curr_ip += u8 * dci->code_align; curr_ip += u8 * dci->code_align;
break; break;
case DW_CFA_advance_loc2: case DW_CFA_advance_loc2:
if ((ret = dwarf_read16(NULL, addr, &u16)) < 0) if (unlikely((ret = dwarf_read16(NULL, addr, &u16)) < 0))
goto fail; goto fail;
curr_ip += u16 * dci->code_align; curr_ip += u16 * dci->code_align;
break; break;
case DW_CFA_advance_loc4: case DW_CFA_advance_loc4:
if ((ret = dwarf_read32(NULL, addr, &u32)) < 0) if (unlikely((ret = dwarf_read32(NULL, addr, &u32)) < 0))
goto fail; goto fail;
curr_ip += u32 * dci->code_align; curr_ip += u32 * dci->code_align;
break; break;
@ -1118,30 +1095,30 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state *
goto fail; goto fail;
case DW_CFA_offset: case DW_CFA_offset:
regnum = dwarf_to_regnum(operand); regnum = dwarf_to_regnum(operand);
if (regnum >= num_regs) { if (unlikely(regnum >= num_regs)) {
debug(DEBUG_DWARF, "Invalid register number %u in DW_cfa_OFFSET", (unsigned int)regnum); debug(DEBUG_DWARF, "Invalid register number %u in DW_cfa_OFFSET", (unsigned int)regnum);
ret = -DWARF_EBADREG; ret = -DWARF_EBADREG;
goto fail; goto fail;
} }
if ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0) if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0))
goto fail; goto fail;
set_reg(rs_current, regnum, DWARF_WHERE_CFAREL, val * dci->data_align); set_reg(rs_current, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
break; break;
case DW_CFA_offset_extended: case DW_CFA_offset_extended:
if (((ret = read_regnum(num_regs, addr, &regnum)) < 0) if (unlikely(((ret = read_regnum(num_regs, addr, &regnum)) < 0)
|| ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0)) || ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0)))
goto fail; goto fail;
set_reg(rs_current, regnum, DWARF_WHERE_CFAREL, val * dci->data_align); set_reg(rs_current, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
break; break;
case DW_CFA_offset_extended_sf: case DW_CFA_offset_extended_sf:
if (((ret = read_regnum(num_regs, addr, &regnum)) < 0) if (unlikely(((ret = read_regnum(num_regs, addr, &regnum)) < 0)
|| ((ret = dwarf_read_sleb128(NULL, addr, &val)) < 0)) || ((ret = dwarf_read_sleb128(NULL, addr, &val)) < 0)))
goto fail; goto fail;
set_reg(rs_current, regnum, DWARF_WHERE_CFAREL, val * dci->data_align); set_reg(rs_current, regnum, DWARF_WHERE_CFAREL, val * dci->data_align);
break; break;
case DW_CFA_restore: case DW_CFA_restore:
regnum = dwarf_to_regnum(operand); regnum = dwarf_to_regnum(operand);
if (regnum >= num_regs) { if (unlikely(regnum >= num_regs)) {
debug(DEBUG_DWARF, "Invalid register number %u in DW_CFA_restore", (unsigned int)regnum); debug(DEBUG_DWARF, "Invalid register number %u in DW_CFA_restore", (unsigned int)regnum);
ret = -DWARF_EINVAL; ret = -DWARF_EINVAL;
goto fail; goto fail;
@ -1149,9 +1126,9 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state *
rs_current->reg[regnum] = rs_initial->reg[regnum]; rs_current->reg[regnum] = rs_initial->reg[regnum];
break; break;
case DW_CFA_restore_extended: case DW_CFA_restore_extended:
if ((ret = dwarf_read_uleb128(NULL, addr, &regnum)) < 0) if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &regnum)) < 0))
goto fail; goto fail;
if (regnum >= num_regs) { if (unlikely(regnum >= num_regs)) {
debug(DEBUG_DWARF, "Invalid register number %u in " "DW_CFA_restore_extended", (unsigned int)regnum); debug(DEBUG_DWARF, "Invalid register number %u in " "DW_CFA_restore_extended", (unsigned int)regnum);
ret = -DWARF_EINVAL; ret = -DWARF_EINVAL;
goto fail; goto fail;
@ -1161,26 +1138,26 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state *
case DW_CFA_nop: case DW_CFA_nop:
break; break;
case DW_CFA_set_loc: case DW_CFA_set_loc:
if ((ret = dwarf_read_encoded_pointer_local(as, addr, dci->fde_encoding, &curr_ip, c->dci.start_ip)) < 0) if (unlikely((ret = dwarf_read_encoded_pointer_local(as, addr, dci->fde_encoding, &curr_ip, c->dci.start_ip)) < 0))
goto fail; goto fail;
break; break;
case DW_CFA_undefined: case DW_CFA_undefined:
if ((ret = read_regnum(num_regs, addr, &regnum)) < 0) if (unlikely((ret = read_regnum(num_regs, addr, &regnum)) < 0))
goto fail; goto fail;
set_reg(rs_current, regnum, DWARF_WHERE_UNDEF, 0); set_reg(rs_current, regnum, DWARF_WHERE_UNDEF, 0);
break; break;
case DW_CFA_same_value: case DW_CFA_same_value:
if ((ret = read_regnum(num_regs, addr, &regnum)) < 0) if (unlikely((ret = read_regnum(num_regs, addr, &regnum)) < 0))
goto fail; goto fail;
set_reg(rs_current, regnum, DWARF_WHERE_SAME, 0); set_reg(rs_current, regnum, DWARF_WHERE_SAME, 0);
break; break;
case DW_CFA_register: case DW_CFA_register:
if ((ret = read_regnum(num_regs, addr, &regnum)) < 0) if (unlikely((ret = read_regnum(num_regs, addr, &regnum)) < 0))
goto fail; goto fail;
if ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0) if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0))
goto fail; goto fail;
n = dwarf_to_regnum(val); n = dwarf_to_regnum(val);
if (n >= num_regs) { if (unlikely(n >= num_regs)) {
debug(DEBUG_DWARF, "Invalid register number value %u in DW_CFA_REGISTER", (unsigned int)val); debug(DEBUG_DWARF, "Invalid register number value %u in DW_CFA_REGISTER", (unsigned int)val);
ret = -DWARF_EBADREG; ret = -DWARF_EBADREG;
goto fail; goto fail;
@ -1194,7 +1171,7 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state *
rs_stack = rs_tmp; rs_stack = rs_tmp;
break; break;
case DW_CFA_restore_state: case DW_CFA_restore_state:
if (!rs_stack) { if (unlikely(!rs_stack)) {
debug(DEBUG_DWARF, "register-state stack underflow"); debug(DEBUG_DWARF, "register-state stack underflow");
ret = -DWARF_EINVAL; ret = -DWARF_EINVAL;
goto fail; goto fail;
@ -1205,31 +1182,31 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state *
free(rs_tmp); free(rs_tmp);
break; break;
case DW_CFA_def_cfa: case DW_CFA_def_cfa:
if (((ret = read_regnum(num_regs, addr, &regnum)) < 0) if ((unlikely((ret = read_regnum(num_regs, addr, &regnum)) < 0)
|| ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0)) || ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0)))
goto fail; goto fail;
set_reg(rs_current, DWARF_CFA_REG_COLUMN(as), DWARF_WHERE_REG, regnum); set_reg(rs_current, DWARF_CFA_REG_COLUMN(as), DWARF_WHERE_REG, regnum);
set_reg(rs_current, DWARF_CFA_OFF_COLUMN(as), 0, val); /* NOT factored! */ set_reg(rs_current, DWARF_CFA_OFF_COLUMN(as), 0, val); /* NOT factored! */
break; break;
case DW_CFA_def_cfa_sf: case DW_CFA_def_cfa_sf:
if (((ret = read_regnum(num_regs, addr, &regnum)) < 0) if (unlikely(((ret = read_regnum(num_regs, addr, &regnum)) < 0)
|| ((ret = dwarf_read_sleb128(NULL, addr, &val)) < 0)) || ((ret = dwarf_read_sleb128(NULL, addr, &val)) < 0)))
goto fail; goto fail;
set_reg(rs_current, DWARF_CFA_REG_COLUMN(as), DWARF_WHERE_REG, regnum); set_reg(rs_current, DWARF_CFA_REG_COLUMN(as), DWARF_WHERE_REG, regnum);
set_reg(rs_current, DWARF_CFA_OFF_COLUMN(as), 0, val * dci->data_align); /* factored! */ set_reg(rs_current, DWARF_CFA_OFF_COLUMN(as), 0, val * dci->data_align); /* factored! */
break; break;
case DW_CFA_def_cfa_register: case DW_CFA_def_cfa_register:
if ((ret = read_regnum(num_regs, addr, &regnum)) < 0) if (unlikely((ret = read_regnum(num_regs, addr, &regnum)) < 0))
goto fail; goto fail;
set_reg(rs_current, DWARF_CFA_REG_COLUMN(as), DWARF_WHERE_REG, regnum); set_reg(rs_current, DWARF_CFA_REG_COLUMN(as), DWARF_WHERE_REG, regnum);
break; break;
case DW_CFA_def_cfa_offset: case DW_CFA_def_cfa_offset:
if ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0) if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0))
goto fail; goto fail;
set_reg(rs_current, DWARF_CFA_OFF_COLUMN(as), 0, val); /* NOT factored! */ set_reg(rs_current, DWARF_CFA_OFF_COLUMN(as), 0, val); /* NOT factored! */
break; break;
case DW_CFA_def_cfa_offset_sf: case DW_CFA_def_cfa_offset_sf:
if ((ret = dwarf_read_sleb128(NULL, addr, &val)) < 0) if (unlikely((ret = dwarf_read_sleb128(NULL, addr, &val)) < 0))
goto fail; goto fail;
set_reg(rs_current, DWARF_CFA_OFF_COLUMN(as), 0, val * dci->data_align); /* factored! */ set_reg(rs_current, DWARF_CFA_OFF_COLUMN(as), 0, val * dci->data_align); /* factored! */
break; break;
@ -1237,19 +1214,19 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state *
/* Save the address of the DW_FORM_block for later evaluation. */ /* Save the address of the DW_FORM_block for later evaluation. */
set_reg(rs_current, DWARF_CFA_REG_COLUMN(as), DWARF_WHERE_EXPR, *addr); set_reg(rs_current, DWARF_CFA_REG_COLUMN(as), DWARF_WHERE_EXPR, *addr);
if ((ret = dwarf_read_uleb128(NULL, addr, &n)) < 0) if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &n)) < 0))
goto fail; goto fail;
*addr += n; *addr += n;
break; break;
case DW_CFA_expression: case DW_CFA_expression:
if ((ret = read_regnum(num_regs, addr, &regnum)) < 0) if (unlikely((ret = read_regnum(num_regs, addr, &regnum)) < 0))
goto fail; goto fail;
/* Save the address of the DW_FORM_block for later evaluation. */ /* Save the address of the DW_FORM_block for later evaluation. */
set_reg(rs_current, regnum, DWARF_WHERE_EXPR, *addr); set_reg(rs_current, regnum, DWARF_WHERE_EXPR, *addr);
if ((ret = dwarf_read_uleb128(NULL, addr, &n)) < 0) if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &n)) < 0))
goto fail; goto fail;
*addr += n; *addr += n;
@ -1261,21 +1238,21 @@ static int run_cfi_program(struct dwarf_addr_space *as, struct dwarf_reg_state *
/* Save the address of the DW_FORM_block for later evaluation. */ /* Save the address of the DW_FORM_block for later evaluation. */
set_reg(rs_current, regnum, DWARF_WHERE_VAL_EXPR, *addr); set_reg(rs_current, regnum, DWARF_WHERE_VAL_EXPR, *addr);
if ((ret = dwarf_read_uleb128(NULL, addr, &n)) < 0) if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &n)) < 0))
goto fail; goto fail;
*addr += n; *addr += n;
break; break;
case DW_CFA_GNU_args_size: case DW_CFA_GNU_args_size:
if ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0) if (unlikely((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0))
goto fail; goto fail;
break; break;
case DW_CFA_GNU_negative_offset_extended: case DW_CFA_GNU_negative_offset_extended:
/* A comment in GCC says that this is obsoleted by /* A comment in GCC says that this is obsoleted by
DW_CFA_offset_extended_sf, but that it's used by older DW_CFA_offset_extended_sf, but that it's used by older
PowerPC code. */ PowerPC code. */
if (((ret = read_regnum(num_regs, addr, &regnum)) < 0) if (unlikely(((ret = read_regnum(num_regs, addr, &regnum)) < 0)
|| ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0)) || ((ret = dwarf_read_uleb128(NULL, addr, &val)) < 0)))
goto fail; goto fail;
set_reg(rs_current, regnum, DWARF_WHERE_CFAREL, -(val * dci->data_align)); set_reg(rs_current, regnum, DWARF_WHERE_CFAREL, -(val * dci->data_align));
break; break;
@ -1309,7 +1286,7 @@ static int parse_fde(struct dwarf_addr_space *as, arch_addr_t ip, struct dwarf_r
unsigned int i; unsigned int i;
struct dwarf_reg_state *rs_initial; struct dwarf_reg_state *rs_initial;
if (dci->ret_addr_column >= as->num_regs) { if (unlikely(dci->ret_addr_column >= as->num_regs)) {
debug(DEBUG_DWARF, "Invalid return address column %lu", dci->ret_addr_column); debug(DEBUG_DWARF, "Invalid return address column %lu", dci->ret_addr_column);
return -DWARF_EBADREG; return -DWARF_EBADREG;
} }
@ -1367,25 +1344,25 @@ static arch_addr_t read_operand(struct dwarf_addr_space *as, arch_addr_t *addr,
switch (operand_type) { switch (operand_type) {
case VAL8: case VAL8:
ret = dwarf_read8(NULL, addr, &tmp.u8); ret = dwarf_read8(NULL, addr, &tmp.u8);
if (ret < 0) if (unlikely(ret < 0))
return ret; return ret;
*valp = tmp.u8; *valp = tmp.u8;
break; break;
case VAL16: case VAL16:
ret = dwarf_read16(NULL, addr, &tmp.u16); ret = dwarf_read16(NULL, addr, &tmp.u16);
if (ret < 0) if (unlikely(ret < 0))
return ret; return ret;
*valp = tmp.u16; *valp = tmp.u16;
break; break;
case VAL32: case VAL32:
ret = dwarf_read32(NULL, addr, &tmp.u32); ret = dwarf_read32(NULL, addr, &tmp.u32);
if (ret < 0) if (unlikely(ret < 0))
return ret; return ret;
*valp = tmp.u32; *valp = tmp.u32;
break; break;
case VAL64: case VAL64:
ret = dwarf_read64(NULL, addr, &tmp.u64); ret = dwarf_read64(NULL, addr, &tmp.u64);
if (ret < 0) if (unlikely(ret < 0))
return ret; return ret;
*valp = tmp.u64; *valp = tmp.u64;
break; break;
@ -1418,7 +1395,7 @@ static int dwarf_eval_expr(struct dwarf_addr_space *as, arch_addr_t addr, struct
#define pop() \ #define pop() \
({ \ ({ \
if ((tos - 1) >= MAX_EXPR_STACK_SIZE) \ if (unlikely((tos - 1) >= MAX_EXPR_STACK_SIZE)) \
{ \ { \
debug(DEBUG_DWARF, "Stack underflow"); \ debug(DEBUG_DWARF, "Stack underflow"); \
return -DWARF_EINVAL; \ return -DWARF_EINVAL; \
@ -1429,7 +1406,7 @@ static int dwarf_eval_expr(struct dwarf_addr_space *as, arch_addr_t addr, struct
#define push(x) \ #define push(x) \
do { \ do { \
arch_addr_t _x = (x); \ arch_addr_t _x = (x); \
if (tos >= MAX_EXPR_STACK_SIZE) \ if (unlikely(tos >= MAX_EXPR_STACK_SIZE)) \
{ \ { \
debug(DEBUG_DWARF, "Stack overflow"); \ debug(DEBUG_DWARF, "Stack overflow"); \
return -DWARF_EINVAL; \ return -DWARF_EINVAL; \
@ -1440,7 +1417,7 @@ do { \
#define pick(n) \ #define pick(n) \
({ \ ({ \
unsigned int _index = tos - 1 - (n); \ unsigned int _index = tos - 1 - (n); \
if (_index >= MAX_EXPR_STACK_SIZE) \ if (unlikely(_index >= MAX_EXPR_STACK_SIZE)) \
{ \ { \
debug(DEBUG_DWARF, "Out-of-stack pick"); \ debug(DEBUG_DWARF, "Out-of-stack pick"); \
return -DWARF_EINVAL; \ return -DWARF_EINVAL; \
@ -1449,7 +1426,7 @@ do { \
}) })
/* read the length of the expression: */ /* read the length of the expression: */
if ((ret = dwarf_read_uleb128(NULL, &addr, &len)) < 0) if (unlikely((ret = dwarf_read_uleb128(NULL, &addr, &len)) < 0))
return ret; return ret;
end_addr = addr + len; end_addr = addr + len;
@ -1457,7 +1434,7 @@ do { \
push(c->cfa); /* push current CFA as required by DWARF spec */ push(c->cfa); /* push current CFA as required by DWARF spec */
while (addr < end_addr) { while (addr < end_addr) {
if ((ret = dwarf_read8(NULL, &addr, &opcode)) < 0) if (unlikely((ret = dwarf_read8(NULL, &addr, &opcode)) < 0))
return ret; return ret;
operands_signature = dwarf_operands[opcode]; operands_signature = dwarf_operands[opcode];
@ -1475,12 +1452,12 @@ do { \
push(opcode - DW_OP_lit0); push(opcode - DW_OP_lit0);
break; break;
case DW_OP_breg0 ... DW_OP_breg31: case DW_OP_breg0 ... DW_OP_breg31:
if ((ret = dwarf_get_reg(as, dwarf_to_regnum(opcode - DW_OP_breg0), &tmp1)) < 0) if (unlikely((ret = dwarf_get_reg(as, dwarf_to_regnum(opcode - DW_OP_breg0), &tmp1)) < 0))
return ret; return ret;
push(tmp1 + operand1); push(tmp1 + operand1);
break; break;
case DW_OP_bregx: case DW_OP_bregx:
if ((ret = dwarf_get_reg(as, dwarf_to_regnum(operand1), &tmp1)) < 0) if (unlikely((ret = dwarf_get_reg(as, dwarf_to_regnum(operand1), &tmp1)) < 0))
return ret; return ret;
push(tmp1 + operand2); push(tmp1 + operand2);
break; break;
@ -1519,7 +1496,7 @@ do { \
break; break;
case DW_OP_deref: case DW_OP_deref:
tmp1 = pop(); tmp1 = pop();
if ((ret = dwarf_readw(as, &tmp1, &tmp2, as->is_64bit)) < 0) if (unlikely((ret = dwarf_readw(as, &tmp1, &tmp2, as->is_64bit)) < 0))
return ret; return ret;
push(tmp2); push(tmp2);
break; break;
@ -1530,18 +1507,18 @@ do { \
debug(DEBUG_DWARF, "Unexpected DW_OP_deref_size size %d", (int)operand1); debug(DEBUG_DWARF, "Unexpected DW_OP_deref_size size %d", (int)operand1);
return -DWARF_EINVAL; return -DWARF_EINVAL;
case 1: case 1:
if ((ret = dwarf_read8(as, &tmp1, &u8)) < 0) if (unlikely((ret = dwarf_read8(as, &tmp1, &u8)) < 0))
return ret; return ret;
tmp2 = u8; tmp2 = u8;
break; break;
case 2: case 2:
if ((ret = dwarf_read16(as, &tmp1, &u16)) < 0) if (unlikely((ret = dwarf_read16(as, &tmp1, &u16)) < 0))
return ret; return ret;
tmp2 = u16; tmp2 = u16;
break; break;
case 3: case 3:
case 4: case 4:
if ((ret = dwarf_read32(as, &tmp1, &u32)) < 0) if (unlikely((ret = dwarf_read32(as, &tmp1, &u32)) < 0))
return ret; return ret;
tmp2 = u32; tmp2 = u32;
if (operand1 == 3) { if (operand1 == 3) {
@ -1556,7 +1533,7 @@ do { \
case 6: case 6:
case 7: case 7:
case 8: case 8:
if ((ret = dwarf_read64(as, &tmp1, &u64)) < 0) if (unlikely((ret = dwarf_read64(as, &tmp1, &u64)) < 0))
return ret; return ret;
tmp2 = u64; tmp2 = u64;
if (operand1 != 8) { if (operand1 != 8) {
@ -1759,7 +1736,7 @@ static int apply_reg_state(struct dwarf_addr_space *as, struct dwarf_reg_state *
cfa = c->cfa; cfa = c->cfa;
} }
else { else {
if ((ret = dwarf_get_reg(as, rs->reg[DWARF_CFA_REG_COLUMN(as)].val, &cfa)) < 0) if (unlikely((ret = dwarf_get_reg(as, rs->reg[DWARF_CFA_REG_COLUMN(as)].val, &cfa)) < 0))
return ret; return ret;
} }
cfa += rs->reg[DWARF_CFA_OFF_COLUMN(as)].val; cfa += rs->reg[DWARF_CFA_OFF_COLUMN(as)].val;
@ -1772,7 +1749,7 @@ static int apply_reg_state(struct dwarf_addr_space *as, struct dwarf_reg_state *
return ret; return ret;
/* the returned location better be a memory location... */ /* the returned location better be a memory location... */
if (DWARF_IS_REG_LOC(cfa_loc)) if (unlikely(DWARF_IS_REG_LOC(cfa_loc)))
return -DWARF_EBADFRAME; return -DWARF_EBADFRAME;
cfa = DWARF_GET_LOC(cfa_loc); cfa = DWARF_GET_LOC(cfa_loc);
} }
@ -1811,7 +1788,7 @@ static int apply_reg_state(struct dwarf_addr_space *as, struct dwarf_reg_state *
} }
else { else {
ret = dwarf_get(as, c->loc[c->ret_addr_column], &ip); ret = dwarf_get(as, c->loc[c->ret_addr_column], &ip);
if (ret < 0) if (unlikely(ret < 0))
return ret; return ret;
c->ip = ip; c->ip = ip;
} }
@ -1853,9 +1830,6 @@ int dwarf_init_unwind(struct dwarf_addr_space *as, struct task *task)
c->libref = NULL; c->libref = NULL;
c->task = task; c->task = task;
as->addr = 0;
as->val = 0;
memset(&c->dci, 0, sizeof(c->dci)); memset(&c->dci, 0, sizeof(c->dci));
ret = dwarf_arch_init_unwind(as); ret = dwarf_arch_init_unwind(as);
@ -1875,8 +1849,6 @@ void *dwarf_init(int is_64bit)
memset(as, 0, sizeof(*as)); memset(as, 0, sizeof(*as));
as->is_64bit = is_64bit; as->is_64bit = is_64bit;
as->addr = 0;
as->val = 0;
ret = dwarf_arch_init(as); ret = dwarf_arch_init(as);
if (ret < 0) { if (ret < 0) {
@ -1912,17 +1884,21 @@ int dwarf_step(struct dwarf_addr_space *as)
int ret; int ret;
struct dwarf_cursor *c = &as->cursor; struct dwarf_cursor *c = &as->cursor;
struct dwarf_reg_state *rs_current; struct dwarf_reg_state *rs_current;
arch_addr_t ip, cfa; arch_addr_t ip;
#ifdef GUESS_CALLER
arch_addr_t cfa = c->cfa;
#endif
if (!c->valid) if (!c->valid)
return -DWARF_EINVAL; return -DWARF_EINVAL;
ip = c->ip; ip = c->ip;
cfa = c->cfa;
#if 0
ret = dwarf_locate_map(as, ip); ret = dwarf_locate_map(as, ip);
if (ret < 0) if (unlikely(ret < 0))
goto fail; goto fail;
#endif
/* The 'ip' can point either to the previous or next instruction /* The 'ip' can point either to the previous or next instruction
depending on what type of frame we have: normal call or a place depending on what type of frame we have: normal call or a place
@ -1976,13 +1952,9 @@ fail:
if (ret) { if (ret) {
#ifdef GUESS_CALLER #ifdef GUESS_CALLER
ssize_t n; unsigned char buf[512];
unsigned char buf[4096]; unsigned int off;
n = copy_from_proc(c->task, cfa, &buf, ARRAY_SIZE(buf));
if (n > 0) {
arch_addr_t (*getval)(unsigned char *buf); arch_addr_t (*getval)(unsigned char *buf);
ssize_t i;
ssize_t addr_size = DWARF_ADDR_SIZE(as); ssize_t addr_size = DWARF_ADDR_SIZE(as);
if (addr_size == 8) if (addr_size == 8)
@ -1990,21 +1962,29 @@ fail:
else else
getval = get32val; getval = get32val;
for(off = 0; off <= 4096; off += ARRAY_SIZE(buf)) {
size_t i, n;
n = copy_from_proc(c->task, cfa, &buf, ARRAY_SIZE(buf));
for(i = 0; i + addr_size <= n ; i += addr_size) { for(i = 0; i + addr_size <= n ; i += addr_size) {
ip = getval(&buf[i]); ip = getval(&buf[i]);
#if 0 if (unlikely(!dwarf_locate_map(as, ip) && dwarf_arch_check_call(as, ip))) {
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->cfa = cfa + i + addr_size;
c->ip = ip; c->ip = ip;
c->ret_addr_column = 0;
for (i = 0; i < as->num_regs; ++i)
c->loc[i] = DWARF_NULL_LOC;
return 0; return 0;
} }
} }
if (unlikely(n < (ssize_t)ARRAY_SIZE(buf)))
break;
} }
#endif #endif
debug(DEBUG_DWARF, "error %d", ret); debug(DEBUG_DWARF, "error %d", ret);
@ -2015,16 +1995,6 @@ fail:
return ret; return ret;
} }
arch_addr_t dwarf_get_ip(struct dwarf_addr_space *as)
{
struct dwarf_cursor *c = &as->cursor;
if (!c->valid)
return ARCH_ADDR_T(0);
return c->ip;
}
int dwarf_get_unwind_table(struct task *task, struct libref *libref, struct dwarf_eh_frame_hdr *hdr) int dwarf_get_unwind_table(struct task *task, struct libref *libref, struct dwarf_eh_frame_hdr *hdr)
{ {
arch_addr_t addr, fde_count; arch_addr_t addr, fde_count;
@ -2063,13 +2033,3 @@ int dwarf_get_unwind_table(struct task *task, struct libref *libref, struct dwar
return 0; return 0;
} }
int dwarf_location_type(struct dwarf_addr_space *as)
{
struct libref *libref = as->cursor.libref;
if (!libref)
return -1;
return libref->type;
}

31
dwarf.h
View File

@ -27,7 +27,9 @@
#include <stdint.h> #include <stdint.h>
#include "arch.h" #include "arch.h"
#include "common.h"
#include "forward.h" #include "forward.h"
#include "library.h"
#include "mtelf.h" #include "mtelf.h"
#define DWARF_LOC(r, t) ((struct dwarf_loc){ .val = (r), .type = (t) }) #define DWARF_LOC(r, t) ((struct dwarf_loc){ .val = (r), .type = (t) })
@ -96,11 +98,6 @@ struct dwarf_cursor {
struct dwarf_addr_space { struct dwarf_addr_space {
unsigned int is_64bit:1; unsigned int is_64bit:1;
arch_addr_t addr;
union {
long val;
unsigned char val_bytes[sizeof(long)];
};
struct dwarf_cursor cursor; struct dwarf_cursor cursor;
unsigned int ip_reg; unsigned int ip_reg;
unsigned int ret_reg; unsigned int ret_reg;
@ -113,7 +110,6 @@ void *dwarf_init(int is_64bit);
void dwarf_destroy(struct dwarf_addr_space *as); void dwarf_destroy(struct dwarf_addr_space *as);
int dwarf_init_unwind(struct dwarf_addr_space *as, struct task *task); int dwarf_init_unwind(struct dwarf_addr_space *as, struct task *task);
int dwarf_step(struct dwarf_addr_space *as); int dwarf_step(struct dwarf_addr_space *as);
arch_addr_t dwarf_get_ip(struct dwarf_addr_space *as);
int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip); int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip);
@ -121,8 +117,6 @@ int dwarf_get(struct dwarf_addr_space *as, struct dwarf_loc loc, arch_addr_t *va
int dwarf_get_unwind_table(struct task *task, struct libref *libref, struct dwarf_eh_frame_hdr *hdr); int dwarf_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(struct dwarf_addr_space *as);
int dwarf_arch_init_unwind(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_step(struct dwarf_addr_space *as);
@ -132,11 +126,30 @@ int dwarf_arch_check_call(struct dwarf_addr_space *as, arch_addr_t ip);
#ifdef DWARF_TO_REGNUM #ifdef DWARF_TO_REGNUM
unsigned int dwarf_to_regnum(unsigned int reg); unsigned int dwarf_to_regnum(unsigned int reg);
#else #else
static inline unsigned int dwarf_to_regnum(unsigned int reg) static inline __attribute__((const)) unsigned int dwarf_to_regnum(unsigned int reg)
{ {
return reg; return reg;
} }
#endif #endif
static inline arch_addr_t dwarf_get_ip(struct dwarf_addr_space *as)
{
struct dwarf_cursor *c = &as->cursor;
if (unlikely(!c->valid))
return ARCH_ADDR_T(0);
return c->ip;
}
static inline int dwarf_location_type(struct dwarf_addr_space *as)
{
struct libref *libref = as->cursor.libref;
if (!libref)
return -1;
return libref->type;
}
#endif #endif

60
event.c
View File

@ -45,10 +45,12 @@
#include "debug.h" #include "debug.h"
#include "event.h" #include "event.h"
#include "library.h" #include "library.h"
#include "main.h"
#include "mtrace.h" #include "mtrace.h"
#include "options.h" #include "options.h"
#include "report.h" #include "report.h"
#include "task.h" #include "task.h"
#include "timer.h"
#include "trace.h" #include "trace.h"
static LIST_HEAD(event_head); static LIST_HEAD(event_head);
@ -114,7 +116,7 @@ static void handle_clone(struct task *task, enum event_type type)
debug(DEBUG_FUNCTION, "pid=%d, newpid=%d", task->pid, newpid); debug(DEBUG_FUNCTION, "pid=%d, newpid=%d", task->pid, newpid);
if (options.verbose) if (unlikely(options.verbose))
show_clone(task, type); show_clone(task, type);
continue_task(task, 0); continue_task(task, 0);
@ -152,7 +154,7 @@ fail:
static void handle_signal(struct task *task) static void handle_signal(struct task *task)
{ {
if (options.verbose > 1) { if (unlikely(options.verbose > 1)) {
if (task->event.e_un.signum && (task->event.e_un.signum != SIGSTOP || !task->was_stopped)) 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)); fprintf(stderr, "+++ process pid=%d signal %d: %s +++\n", task->pid, task->event.e_un.signum, strsignal(task->event.e_un.signum));
} }
@ -162,7 +164,7 @@ static void handle_signal(struct task *task)
static void show_exit(struct task *task) static void show_exit(struct task *task)
{ {
if (options.verbose) if (unlikely(options.verbose))
fprintf(stderr, "+++ process pid=%d exited (status=%d) +++\n", task->pid, task->event.e_un.ret_val); fprintf(stderr, "+++ process pid=%d exited (status=%d) +++\n", task->pid, task->event.e_un.ret_val);
} }
@ -170,7 +172,7 @@ static void show_exit(struct task *task)
static void handle_about_exit(struct task *task) static void handle_about_exit(struct task *task)
{ {
if (task->leader == task) { if (task->leader == task) {
if (report_about_exit(task) != -1) { if (!options.logfile && report_about_exit(task) != -1) {
task->about_exit = 1; task->about_exit = 1;
return; return;
} }
@ -193,7 +195,7 @@ static void handle_exit(struct task *task)
static void handle_exit_signal(struct task *task) static void handle_exit_signal(struct task *task)
{ {
if (options.verbose) if (unlikely(options.verbose))
fprintf(stderr, "+++ process pid=%d killed by signal %s (%d) +++\n", task->pid, strsignal(task->event.e_un.signum), task->event.e_un.signum); fprintf(stderr, "+++ process pid=%d killed by signal %s (%d) +++\n", task->pid, strsignal(task->event.e_un.signum), task->event.e_un.signum);
if (task->leader == task) { if (task->leader == task) {
@ -217,7 +219,7 @@ static void handle_exec(struct task *task)
goto untrace; goto untrace;
} }
if (options.verbose) if (unlikely(options.verbose))
fprintf(stderr, "+++ process pid=%d exec (%s) +++\n", task->pid, library_execname(task)); fprintf(stderr, "+++ process pid=%d exec (%s) +++\n", task->pid, library_execname(task));
continue_task(task, 0); continue_task(task, 0);
@ -230,11 +232,19 @@ untrace:
static int handle_call_after(struct task *task, struct breakpoint *bp) static int handle_call_after(struct task *task, struct breakpoint *bp)
{ {
struct timespec start;
if (!task->breakpoint) if (!task->breakpoint)
return 0; return 0;
if (unlikely(options.verbose > 1))
start_time(&start);
task->libsym->func->report_out(task, task->libsym); task->libsym->func->report_out(task, task->libsym);
if (unlikely(options.verbose > 1))
set_timer(&start, &report_out_time);
task->breakpoint = NULL; task->breakpoint = NULL;
task->libsym = NULL; task->libsym = NULL;
@ -244,20 +254,33 @@ static int handle_call_after(struct task *task, struct breakpoint *bp)
static void handle_breakpoint(struct task *task) static void handle_breakpoint(struct task *task)
{ {
struct breakpoint *bp = task->event.e_un.breakpoint; struct breakpoint *bp = task->event.e_un.breakpoint;
unsigned int hw = bp->hw;
debug(DEBUG_FUNCTION, "pid=%d, addr=%#lx", task->pid, bp->addr); debug(DEBUG_FUNCTION, "pid=%d, addr=%#lx", task->pid, bp->addr);
if (unlikely(options.verbose > 1))
set_timer(&task->halt_time, hw ? &hw_bp_time : &sw_bp_time);
#if HW_BREAKPOINTS > 1 #if HW_BREAKPOINTS > 1
if (bp->type >= BP_HW) { if (bp->type >= BP_HW) {
if (++bp->hwcnt >= (BP_REORDER_THRESHOLD << bp->hw)) if (unlikely(++bp->hwcnt >= (BP_REORDER_THRESHOLD << hw))) {
struct timespec start;
if (unlikely(options.verbose > 1))
start_time(&start);
reorder_hw_bp(task); reorder_hw_bp(task);
if (unlikely(options.verbose > 1))
set_timer(&start, &reorder_time);
}
} }
#endif #endif
if (options.verbose) if (unlikely(options.verbose))
++bp->count; ++bp->count;
if (bp->deleted) { if (unlikely(bp->deleted)) {
struct breakpoint *nbp = breakpoint_find(task, bp->addr); struct breakpoint *nbp = breakpoint_find(task, bp->addr);
if (!nbp) if (!nbp)
@ -267,26 +290,26 @@ static void handle_breakpoint(struct task *task)
goto end; goto end;
} }
if (task->skip_bp == bp) { if (unlikely(task->skip_bp == bp)) {
breakpoint_put(task->skip_bp); breakpoint_put(task->skip_bp);
task->skip_bp = NULL; task->skip_bp = NULL;
skip_breakpoint(task, bp); skip_breakpoint(task, bp);
goto end; goto end;
} }
if (breakpoint_on_hit(task, bp)) { if (unlikely(breakpoint_on_hit(task, bp))) {
continue_task(task, 0); continue_task(task, 0);
goto end; goto end;
} }
if (bp->libsym && !task->breakpoint) { if (likely(bp->libsym && !task->breakpoint)) {
struct library_symbol *libsym = bp->libsym; struct library_symbol *libsym = bp->libsym;
save_param_context(task); save_param_context(task);
if (libsym->func->report_out) { if (libsym->func->report_out) {
task->breakpoint = breakpoint_insert(task, get_return_addr(task), NULL, BP_HW_SCRATCH); task->breakpoint = breakpoint_insert(task, get_return_addr(task), NULL, BP_HW_SCRATCH);
if (task->breakpoint) { if (likely(task->breakpoint)) {
task->libsym = libsym; task->libsym = libsym;
task->breakpoint->on_hit = handle_call_after; task->breakpoint->on_hit = handle_call_after;
@ -294,8 +317,17 @@ static void handle_breakpoint(struct task *task)
} }
} }
if (libsym->func->report_in) if (libsym->func->report_in) {
struct timespec start;
if (unlikely(options.verbose > 1))
start_time(&start);
libsym->func->report_in(task, libsym); libsym->func->report_in(task, libsym);
if (unlikely(options.verbose > 1))
set_timer(&start, &report_in_time);
}
} }
if (task->stopped) if (task->stopped)

View File

@ -120,15 +120,18 @@ void library_delete(struct task *task, struct library *lib)
struct list_head *it, *next; struct list_head *it, *next;
struct libref *libref = lib->libref; struct libref *libref = lib->libref;
struct task *leader = task->leader;
list_for_each_safe(it, next, &libref->sym_list) { list_for_each_safe(it, next, &libref->sym_list) {
struct breakpoint *bp = breakpoint_find(task, container_of(it, struct library_symbol, list)->addr); struct breakpoint *bp = breakpoint_find(leader, container_of(it, struct library_symbol, list)->addr);
if (bp) if (bp)
breakpoint_delete(task, bp); breakpoint_delete(leader, bp);
} }
list_del(&lib->list); list_del(&lib->list);
rb_erase(&lib->rb_node, &leader->libraries_tree);
free(lib); free(lib);
libref_put(libref); libref_put(libref);
@ -170,7 +173,7 @@ void library_delete_list(struct task *leader, struct list_head *list)
debug(DEBUG_FUNCTION, "%s@%#lx", libref->filename, libref->base); debug(DEBUG_FUNCTION, "%s@%#lx", libref->filename, libref->base);
if (options.verbose > 1) if (unlikely(options.verbose > 1))
fprintf(stderr, "+++ library del pid=%d %s@%#lx %#lx-%#lx +++\n", leader->pid, libref->filename, libref->base, libref->load_addr, libref->load_addr + libref->load_size); fprintf(stderr, "+++ library del pid=%d %s@%#lx %#lx-%#lx +++\n", leader->pid, libref->filename, libref->base, libref->load_addr, libref->load_addr + libref->load_size);
library_delete(leader, lib); library_delete(leader, lib);
@ -208,6 +211,52 @@ static void library_each_symbol(struct libref *libref, void (*cb)(struct library
} }
} }
static inline int lib_addr_match(struct libref *libref, arch_addr_t addr)
{
return addr >= libref->load_addr && addr < libref->load_addr + libref->load_size;
}
struct libref *addr2libref(struct task *leader, arch_addr_t addr)
{
struct rb_node **new = &(leader->libraries_tree.rb_node);
/* Figure out where to put new node */
while (*new) {
struct libref *this = container_of(*new, struct library, rb_node)->libref;
if (lib_addr_match(this, addr))
return this;
if (this->load_addr < addr)
new = &((*new)->rb_left);
else
new = &((*new)->rb_right);
}
return NULL;
}
static void insert_lib(struct task *leader, struct library *lib)
{
struct rb_node **new = &(leader->libraries_tree.rb_node), *parent = NULL;
/* Figure out where to put new node */
while (*new) {
struct library *this = container_of(*new, struct library, rb_node);
parent = *new;
if (this->libref->load_addr < lib->libref->load_addr)
new = &((*new)->rb_left);
else
new = &((*new)->rb_right);
}
/* Add new node and rebalance tree. */
rb_link_node(&lib->rb_node, parent, new);
rb_insert_color(&lib->rb_node, &leader->libraries_tree);
}
static struct library *_library_add(struct task *leader, struct libref *libref) 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); debug(DEBUG_PROCESS, "%s@%#lx to pid=%d", libref->filename, libref->base, leader->pid);
@ -225,7 +274,9 @@ static struct library *_library_add(struct task *leader, struct libref *libref)
list_add_tail(&lib->list, &leader->libraries_list); list_add_tail(&lib->list, &leader->libraries_list);
if (options.verbose > 1) insert_lib(leader, lib);
if (unlikely(options.verbose > 1))
fprintf(stderr, "+++ library add pid=%d %s@%#lx %#lx-%#lx +++\n", leader->pid, libref->filename, libref->base, libref->load_addr, libref->load_addr + libref->load_size); 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; return lib;
@ -263,6 +314,7 @@ int library_clone_all(struct task *clone, struct task *leader)
void library_setup(struct task *leader) void library_setup(struct task *leader)
{ {
INIT_LIST_HEAD(&leader->libraries_list); INIT_LIST_HEAD(&leader->libraries_list);
leader->libraries_tree = RB_ROOT;
} }
const char *library_execname(struct task *leader) const char *library_execname(struct task *leader)

View File

@ -30,6 +30,7 @@
#include "sysdep.h" #include "sysdep.h"
#include "list.h" #include "list.h"
#include "mtelf.h" #include "mtelf.h"
#include "rbtree.h"
#define LIBTYPE_LIB 0 #define LIBTYPE_LIB 0
#define LIBTYPE_MAIN 1 #define LIBTYPE_MAIN 1
@ -89,6 +90,9 @@ struct library {
/* link list of libraries associated with the task */ /* link list of libraries associated with the task */
struct list_head list; struct list_head list;
/* red/black tree of libraries associated with the task */
struct rb_node rb_node;
/* pointer to the real library refernce */ /* pointer to the real library refernce */
struct libref *libref; struct libref *libref;
}; };
@ -132,5 +136,8 @@ void libref_delete(struct libref *libref);
/* Set library filename. Frees the old name if necessary. */ /* Set library filename. Frees the old name if necessary. */
void libref_set_filename(struct libref *libref, const char *new_name); void libref_set_filename(struct libref *libref, const char *new_name);
/* find library by address */
struct libref *addr2libref(struct task *leader, arch_addr_t addr);
#endif #endif

26
main.c
View File

@ -50,6 +50,15 @@
#include "task.h" #include "task.h"
#include "trace.h" #include "trace.h"
struct mt_timer stop_time;
struct mt_timer sw_bp_time;
struct mt_timer hw_bp_time;
struct mt_timer backtrace_time;
struct mt_timer reorder_time;
struct mt_timer report_in_time;
struct mt_timer report_out_time;
struct mt_timer skip_bp_time;
static int do_exit; static int do_exit;
void mtrace_request_exit(void) void mtrace_request_exit(void)
@ -57,7 +66,7 @@ void mtrace_request_exit(void)
if (do_exit) if (do_exit)
return; return;
if (options.verbose) if (unlikely(options.verbose))
fprintf(stderr, "+++ request exit +++\n"); fprintf(stderr, "+++ request exit +++\n");
do_exit = 1; do_exit = 1;
@ -69,10 +78,10 @@ static void detach_process(struct task *leader)
if (!leader) if (!leader)
return; return;
report_detach(leader);
pid_t pid = leader->pid; pid_t pid = leader->pid;
report_detach(leader);
while(server_handle_command() != -1) { while(server_handle_command() != -1) {
struct task *task = pid2task(pid); struct task *task = pid2task(pid);
@ -99,16 +108,13 @@ static void mtrace_init(char **cmd)
{ {
struct opt_p_t *opt_p_tmp; struct opt_p_t *opt_p_tmp;
if (os_init())
exit(EXIT_FAILURE);
if (options.command) { if (options.command) {
struct task *task = task_create(options.command, cmd); struct task *task = task_create(options.command, cmd);
if (!task) if (!task)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
if (options.verbose) if (unlikely(options.verbose))
fprintf(stderr, "+++ process pid=%d created (%s) +++\n", task->pid, library_execname(task)); fprintf(stderr, "+++ process pid=%d created (%s) +++\n", task->pid, library_execname(task));
} }
@ -134,6 +140,8 @@ int main(int argc, char *argv[])
{ {
char **cmd = process_options(argc, argv); char **cmd = process_options(argc, argv);
init_pid_hash();
if (options.trace) { if (options.trace) {
if (options.logfile) { if (options.logfile) {
if (server_logfile() == -1) if (server_logfile() == -1)
@ -175,10 +183,14 @@ int main(int argc, char *argv[])
#endif #endif
} }
if (os_init())
exit(EXIT_FAILURE);
mtrace_init(cmd); mtrace_init(cmd);
mtrace_main(); mtrace_main();
mtrace_exit(); mtrace_exit();
report_info(0);
report_disconnect(); report_disconnect();
#if !DISABLE_CLIENT #if !DISABLE_CLIENT

11
main.h
View File

@ -23,7 +23,18 @@
#ifndef _INC_MAIN_H #ifndef _INC_MAIN_H
#define _INC_MAIN_H #define _INC_MAIN_H
#include "timer.h"
void mtrace_request_exit(void); void mtrace_request_exit(void);
struct mt_timer stop_time;
struct mt_timer sw_bp_time;
struct mt_timer hw_bp_time;
struct mt_timer backtrace_time;
struct mt_timer reorder_time;
struct mt_timer report_in_time;
struct mt_timer report_out_time;
struct mt_timer skip_bp_time;
#endif #endif

View File

@ -31,15 +31,15 @@
#define IS64BIT 0 #define IS64BIT 0
#endif #endif
#define MEMTRACE_SI_VERSION 5 #define MEMTRACE_SI_VERSION 6
#define MEMTRACE_SI_FORK 1 #define MEMTRACE_SI_FORK 1
#define MEMTRACE_SI_EXEC 2 #define MEMTRACE_SI_EXEC 2
#define MEMTRACE_SI_VERBOSE 4 #define MEMTRACE_SI_VERBOSE 4
enum mt_operation { enum mt_operation {
MT_INFO = 0,
MT_DISCONNECT, MT_DISCONNECT,
MT_INFO,
MT_ADD_MAP, MT_ADD_MAP,
MT_DEL_MAP, MT_DEL_MAP,
MT_ATTACH, MT_ATTACH,
@ -50,7 +50,7 @@ enum mt_operation {
MT_NOFOLLOW, MT_NOFOLLOW,
MT_MALLOC, MT_MALLOC,
MT_REALLOC_ENTER, MT_REALLOC_ENTER,
MT_REALLOC_FAILED, MT_REALLOC_DONE,
MT_REALLOC, MT_REALLOC,
MT_FREE, MT_FREE,
MT_MMAP, MT_MMAP,
@ -71,47 +71,62 @@ enum mt_operation {
MT_DELETE_ARRAY, MT_DELETE_ARRAY,
}; };
struct mt_msg { struct __attribute__((packed)) mt_msg {
uint16_t operation; uint16_t operation;
uint32_t pid; uint16_t pid;
uint32_t tid;
uint32_t payload_len; uint32_t payload_len;
}; };
struct mt_attached_payload { struct __attribute__((packed)) mt_attached_payload {
uint8_t attached; uint8_t attached;
}; };
struct mt_alloc_payload_64 { struct __attribute__((packed)) mt_alloc_payload_64 {
uint64_t ptr; uint64_t ptr;
uint64_t size; uint64_t size;
uint64_t data[0]; uint64_t data[0];
}; };
struct mt_alloc_payload_32 { struct __attribute__((packed)) mt_alloc_payload_32 {
uint32_t ptr; uint32_t ptr;
uint32_t size; uint32_t size;
uint32_t data[0]; uint32_t data[0];
}; };
struct mt_pid_payload { struct __attribute__((packed)) mt_pid_payload {
uint32_t pid; uint32_t pid;
}; };
struct mt_scan_payload { struct __attribute__((packed)) mt_scan_payload {
uint32_t ptr_size; uint32_t ptr_size;
uint64_t mask; uint64_t mask;
char data[0]; char data[0];
}; };
struct memtrace_info { struct __attribute__((packed)) memtrace_timer_info {
uint32_t max;
uint32_t count;
uint64_t culminate;
};
struct __attribute__((packed)) memtrace_info {
uint8_t version; uint8_t version;
uint8_t mode; uint8_t mode;
uint8_t do_trace; uint8_t do_trace;
uint8_t stack_depth; uint8_t stack_depth;
uint8_t verbose;
uint8_t unused[3];
struct memtrace_timer_info stop_time;
struct memtrace_timer_info sw_bp_time;
struct memtrace_timer_info hw_bp_time;
struct memtrace_timer_info backtrace_time;
struct memtrace_timer_info reorder_time;
struct memtrace_timer_info report_in_time;
struct memtrace_timer_info report_out_time;
struct memtrace_timer_info skip_bp_time;
}; };
struct mt_map_payload { struct __attribute__((packed)) mt_map_payload {
uint64_t addr; uint64_t addr;
uint64_t offset; uint64_t offset;
uint64_t size; uint64_t size;

View File

@ -191,7 +191,7 @@ static int populate_this_symtab(struct mt_elf *mte, struct libref *libref, Elf_D
if (libsym->func->level > func->level) if (libsym->func->level > func->level)
libsym->func = func; libsym->func = func;
} }
if (options.verbose > 1) if (unlikely(options.verbose > 1))
fprintf(stderr, "breakpoint for %s:%s at %#lx\n", libref->filename, func->demangled_name, addr); fprintf(stderr, "breakpoint for %s:%s at %#lx\n", libref->filename, func->demangled_name, addr);
} }
@ -220,6 +220,7 @@ static int populate_symtab(struct mt_elf *mte, struct libref *libref)
static inline int elf_map_image(struct mt_elf *mte, void **image_addr) static inline int elf_map_image(struct mt_elf *mte, void **image_addr)
{ {
void *addr; void *addr;
volatile char *p;
addr = mmap(NULL, mte->txt_hdr.p_filesz, PROT_READ, MAP_PRIVATE, mte->fd, mte->txt_hdr.p_offset); addr = mmap(NULL, mte->txt_hdr.p_filesz, PROT_READ, MAP_PRIVATE, mte->fd, mte->txt_hdr.p_offset);
if (addr == MAP_FAILED) { if (addr == MAP_FAILED) {
@ -229,6 +230,10 @@ static inline int elf_map_image(struct mt_elf *mte, void **image_addr)
*image_addr = addr; *image_addr = addr;
/* prefetch */
for(p = addr; (void *)p <= addr + mte->txt_hdr.p_filesz; p += PAGE_SIZE)
*p;
return 0; return 0;
} }

View File

@ -24,6 +24,7 @@
#ifndef _INC_OPTIONS_H #ifndef _INC_OPTIONS_H
#define _INC_OPTIONS_H #define _INC_OPTIONS_H
#include <stdio.h>
#include <sys/types.h> #include <sys/types.h>
#include "config.h" #include "config.h"

242
report.c
View File

@ -34,14 +34,16 @@
#include "common.h" #include "common.h"
#include "debug.h" #include "debug.h"
#include "library.h" #include "library.h"
#include "main.h"
#include "memtrace.h" #include "memtrace.h"
#include "options.h" #include "options.h"
#include "report.h" #include "report.h"
#include "server.h" #include "server.h"
#include "task.h" #include "task.h"
#include "timer.h"
#include "trace.h" #include "trace.h"
static int report_alloc64(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, unsigned int depth, struct library_symbol *libsym) static void report_alloc64(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, unsigned int depth, struct library_symbol *libsym)
{ {
unsigned int i = 0; unsigned int i = 0;
struct mt_alloc_payload_64 *alloc = alloca(sizeof(*alloc) + depth * sizeof(uint64_t)); struct mt_alloc_payload_64 *alloc = alloca(sizeof(*alloc) + depth * sizeof(uint64_t));
@ -53,20 +55,20 @@ static int report_alloc64(struct task *task, enum mt_operation op, unsigned long
if (libsym) if (libsym)
alloc->data[i++] = libsym->addr; alloc->data[i++] = libsym->addr;
if (backtrace_init_unwind(task) >= 0) { if (likely(backtrace_init_unwind(task) >= 0)) {
while(i < depth) { while(i < depth) {
if (backtrace_location_type(task) != LIBTYPE_LOADER) { if (likely(backtrace_location_type(task) != LIBTYPE_LOADER)) {
alloc->data[i] = (uint64_t)backtrace_get_ip(task); alloc->data[i] = (uint64_t)backtrace_get_ip(task);
if (!i || alloc->data[i - 1] != alloc->data[i]) { if (likely(!i || alloc->data[i - 1] != alloc->data[i])) {
if (!alloc->data[i]) if (unlikely(!alloc->data[i]))
break; break;
++i; ++i;
} }
} }
if (backtrace_step(task) < 0) if (unlikely(backtrace_step(task) < 0))
break; break;
} }
} }
@ -74,10 +76,10 @@ static int report_alloc64(struct task *task, enum mt_operation op, unsigned long
skip_breakpoint(task, task->event.e_un.breakpoint); skip_breakpoint(task, task->event.e_un.breakpoint);
return server_send_msg(op, task->leader->pid, task->pid, alloc, sizeof(*alloc) + i * sizeof(uint64_t)); server_send_msg(op, task->leader->pid, alloc, sizeof(*alloc) + i * sizeof(uint64_t));
} }
static int report_alloc32(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth, struct library_symbol *libsym) static void report_alloc32(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth, struct library_symbol *libsym)
{ {
int i = 0; int i = 0;
struct mt_alloc_payload_32 *alloc = alloca(sizeof(*alloc) + depth * sizeof(uint32_t)); struct mt_alloc_payload_32 *alloc = alloca(sizeof(*alloc) + depth * sizeof(uint32_t));
@ -89,20 +91,20 @@ static int report_alloc32(struct task *task, enum mt_operation op, unsigned long
if (libsym) if (libsym)
alloc->data[i++] = libsym->addr; alloc->data[i++] = libsym->addr;
if (backtrace_init_unwind(task) >= 0) { if (likely(backtrace_init_unwind(task) >= 0)) {
while(i < depth) { while(i < depth) {
if (backtrace_location_type(task) != LIBTYPE_LOADER) { if (likely(backtrace_location_type(task) != LIBTYPE_LOADER)) {
alloc->data[i] = (uint32_t)backtrace_get_ip(task); alloc->data[i] = (uint32_t)backtrace_get_ip(task);
if (!i || alloc->data[i - 1] != alloc->data[i]) { if (likely(!i || alloc->data[i - 1] != alloc->data[i])) {
if (!alloc->data[i]) if (unlikely(!alloc->data[i]))
break; break;
++i; ++i;
} }
} }
if (backtrace_step(task) < 0) if (unlikely(backtrace_step(task) < 0))
break; break;
} }
} }
@ -110,142 +112,132 @@ static int report_alloc32(struct task *task, enum mt_operation op, unsigned long
skip_breakpoint(task, task->event.e_un.breakpoint); skip_breakpoint(task, task->event.e_un.breakpoint);
return server_send_msg(op, task->leader->pid, task->pid, alloc, sizeof(*alloc) + i * sizeof(uint32_t)); server_send_msg(op, task->leader->pid, alloc, sizeof(*alloc) + i * sizeof(uint32_t));
} }
static int report_alloc(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth, struct library_symbol *libsym) static void report_alloc(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth, struct library_symbol *libsym)
{ {
if (!ptr) if (!ptr)
return 0; return;
if (!server_connected())
return -1;
debug(DEBUG_FUNCTION, "%d [%d]: %#lx %lu", op, task->pid, ptr, size); debug(DEBUG_FUNCTION, "%d [%d]: %#lx %lu", op, task->pid, ptr, size);
if (task_is_64bit(task)) if (task_is_64bit(task))
return report_alloc64(task, op, ptr, size, depth, libsym); report_alloc64(task, op, ptr, size, depth, libsym);
else else
return report_alloc32(task, op, ptr, size, depth, libsym); report_alloc32(task, op, ptr, size, depth, libsym);
} }
static int _null(struct task *task, struct library_symbol *libsym) static void _null(struct task *task, struct library_symbol *libsym)
{ {
return 0;
} }
static int _report_alloc_op(struct task *task, struct library_symbol *libsym, enum mt_operation op) static void _report_alloc_op(struct task *task, struct library_symbol *libsym, enum mt_operation op)
{ {
if (!server_connected())
return -1;
unsigned long size = fetch_param(task, 0); unsigned long size = fetch_param(task, 0);
unsigned long ret = fetch_retval(task); unsigned long ret = fetch_retval(task);
return report_alloc(task, op, ret, size, options.bt_depth, libsym); report_alloc(task, op, ret, size, options.bt_depth, libsym);
} }
static int _report_malloc(struct task *task, struct library_symbol *libsym) static void _report_malloc(struct task *task, struct library_symbol *libsym)
{ {
return _report_alloc_op(task, libsym, MT_MALLOC); _report_alloc_op(task, libsym, MT_MALLOC);
} }
static int _report_new(struct task *task, struct library_symbol *libsym) static void _report_new(struct task *task, struct library_symbol *libsym)
{ {
return _report_alloc_op(task, libsym, options.sanity ? MT_NEW : MT_MALLOC); _report_alloc_op(task, libsym, options.sanity ? MT_NEW : MT_MALLOC);
} }
static int _report_new_array(struct task *task, struct library_symbol *libsym) static void _report_new_array(struct task *task, struct library_symbol *libsym)
{ {
return _report_alloc_op(task, libsym, options.sanity ? MT_NEW_ARRAY : MT_MALLOC); _report_alloc_op(task, libsym, options.sanity ? MT_NEW_ARRAY : MT_MALLOC);
} }
static int _report_free_op(struct task *task, struct library_symbol *libsym, enum mt_operation op) static void _report_free_op(struct task *task, struct library_symbol *libsym, enum mt_operation op)
{ {
if (!server_connected())
return -1;
unsigned long addr = fetch_param(task, 0); unsigned long addr = fetch_param(task, 0);
return report_alloc(task, op, addr, 0, options.sanity ? options.bt_depth : 0, NULL); report_alloc(task, op, addr, 0, options.sanity ? options.bt_depth : 0, NULL);
} }
static int report_free(struct task *task, struct library_symbol *libsym) static void report_free(struct task *task, struct library_symbol *libsym)
{ {
return _report_free_op(task, libsym, MT_FREE); _report_free_op(task, libsym, MT_FREE);
} }
static int report_delete(struct task *task, struct library_symbol *libsym) static void report_delete(struct task *task, struct library_symbol *libsym)
{ {
return _report_free_op(task, libsym, options.sanity ? MT_DELETE : MT_FREE); _report_free_op(task, libsym, options.sanity ? MT_DELETE : MT_FREE);
} }
static int report_delete_array(struct task *task, struct library_symbol *libsym) static void report_delete_array(struct task *task, struct library_symbol *libsym)
{ {
return _report_free_op(task, libsym, options.sanity ? MT_DELETE_ARRAY : MT_FREE); _report_free_op(task, libsym, options.sanity ? MT_DELETE_ARRAY : MT_FREE);
} }
static int _report_realloc(struct task *task, struct library_symbol *libsym) static void _report_realloc(struct task *task, struct library_symbol *libsym)
{ {
if (!server_connected())
return -1;
unsigned long addr = fetch_param(task, 0);
unsigned long size = fetch_param(task, 1);
unsigned long ret = fetch_retval(task); unsigned long ret = fetch_retval(task);
if (ret) if (ret) {
return report_alloc(task, MT_REALLOC, ret, size, options.bt_depth, libsym);
else
return report_alloc(task, MT_REALLOC_FAILED, addr, 1, options.bt_depth, libsym);
}
static int report_realloc(struct task *task, struct library_symbol *libsym)
{
if (!server_connected())
return -1;
unsigned long addr = fetch_param(task, 0);
unsigned long size = fetch_param(task, 1); unsigned long size = fetch_param(task, 1);
return report_alloc(task, MT_REALLOC_ENTER, addr, size, options.bt_depth, libsym); report_alloc(task, MT_REALLOC, ret, size, options.bt_depth, libsym);
} }
static int _report_calloc(struct task *task, struct library_symbol *libsym) if (task_is_64bit(task)) {
{ struct mt_alloc_payload_64 *alloc = alloca(sizeof(*alloc));
if (!server_connected())
return -1;
alloc->ptr = (uint64_t)ret;
alloc->size = (uint64_t)task->pid;
server_send_msg(MT_REALLOC_DONE, task->leader->pid, alloc, sizeof(*alloc));
}
else {
struct mt_alloc_payload_32 *alloc = alloca(sizeof(*alloc));
alloc->ptr = (uint32_t)ret;
alloc->size = (uint32_t)task->pid;
server_send_msg(MT_REALLOC_DONE, task->leader->pid, alloc, sizeof(*alloc));
}
}
static void report_realloc(struct task *task, struct library_symbol *libsym)
{
unsigned long addr = fetch_param(task, 0);
report_alloc(task, MT_REALLOC_ENTER, addr, task->pid, options.sanity ? options.bt_depth : 0, libsym);
}
static void _report_calloc(struct task *task, struct library_symbol *libsym)
{
unsigned long size = fetch_param(task, 0) * fetch_param(task, 1); unsigned long size = fetch_param(task, 0) * fetch_param(task, 1);
unsigned long ret = fetch_retval(task); unsigned long ret = fetch_retval(task);
return report_alloc(task, MT_MALLOC, ret, size, options.bt_depth, libsym); report_alloc(task, MT_MALLOC, ret, size, options.bt_depth, libsym);
} }
static int _report_mmap(struct task *task, struct library_symbol *libsym) static void _report_mmap(struct task *task, struct library_symbol *libsym)
{ {
if (!server_connected())
return -1;
unsigned long ret = fetch_retval(task); unsigned long ret = fetch_retval(task);
if ((void *)ret == MAP_FAILED) if ((void *)ret == MAP_FAILED)
return 0; return;
unsigned long size = fetch_param(task, 1); unsigned long size = fetch_param(task, 1);
return report_alloc(task, MT_MMAP, ret, size, options.bt_depth, libsym); report_alloc(task, MT_MMAP, ret, size, options.bt_depth, libsym);
} }
static int _report_mmap64(struct task *task, struct library_symbol *libsym) static void _report_mmap64(struct task *task, struct library_symbol *libsym)
{ {
if (!server_connected())
return -1;
unsigned long ret = fetch_retval(task); unsigned long ret = fetch_retval(task);
if ((void *)ret == MAP_FAILED) if ((void *)ret == MAP_FAILED)
return 0; return;
union { union {
uint64_t l; uint64_t l;
@ -264,40 +256,31 @@ static int _report_mmap64(struct task *task, struct library_symbol *libsym)
else else
size.l = fetch_param(task, 1); size.l = fetch_param(task, 1);
return report_alloc(task, MT_MMAP64, ret, size.l, options.bt_depth, libsym); report_alloc(task, MT_MMAP64, ret, size.l, options.bt_depth, libsym);
} }
static int report_munmap(struct task *task, struct library_symbol *libsym) static void report_munmap(struct task *task, struct library_symbol *libsym)
{ {
if (!server_connected())
return -1;
unsigned long addr = fetch_param(task, 0); unsigned long addr = fetch_param(task, 0);
unsigned long size = fetch_param(task, 1); unsigned long size = fetch_param(task, 1);
return report_alloc(task, MT_MUNMAP, addr, size, 0, libsym); report_alloc(task, MT_MUNMAP, addr, size, 0, libsym);
} }
static int _report_memalign(struct task *task, struct library_symbol *libsym) static void _report_memalign(struct task *task, struct library_symbol *libsym)
{ {
if (!server_connected())
return -1;
unsigned long size = fetch_param(task, 1); unsigned long size = fetch_param(task, 1);
unsigned long ret = fetch_retval(task); unsigned long ret = fetch_retval(task);
return report_alloc(task, MT_MEMALIGN, ret, size, options.bt_depth, libsym); report_alloc(task, MT_MEMALIGN, ret, size, options.bt_depth, libsym);
} }
static int _report_posix_memalign(struct task *task, struct library_symbol *libsym) static void _report_posix_memalign(struct task *task, struct library_symbol *libsym)
{ {
if (!server_connected())
return -1;
unsigned long ret = fetch_retval(task); unsigned long ret = fetch_retval(task);
if (ret) if (ret)
return 0; return;
unsigned long size = fetch_param(task, 2); unsigned long size = fetch_param(task, 2);
unsigned long ptr = fetch_param(task, 0); unsigned long ptr = fetch_param(task, 0);
@ -313,56 +296,47 @@ static int _report_posix_memalign(struct task *task, struct library_symbol *libs
new_ptr = tmp; new_ptr = tmp;
} }
return report_alloc(task, MT_POSIX_MEMALIGN, new_ptr, size, options.bt_depth, libsym); report_alloc(task, MT_POSIX_MEMALIGN, new_ptr, size, options.bt_depth, libsym);
} }
static int _report_aligned_alloc(struct task *task, struct library_symbol *libsym) static void _report_aligned_alloc(struct task *task, struct library_symbol *libsym)
{ {
if (!server_connected())
return -1;
unsigned long size = fetch_param(task, 1); unsigned long size = fetch_param(task, 1);
unsigned long ret = fetch_retval(task); unsigned long ret = fetch_retval(task);
return report_alloc(task, MT_ALIGNED_ALLOC, ret, size, options.bt_depth, libsym); report_alloc(task, MT_ALIGNED_ALLOC, ret, size, options.bt_depth, libsym);
} }
static int _report_valloc(struct task *task, struct library_symbol *libsym) static void _report_valloc(struct task *task, struct library_symbol *libsym)
{ {
if (!server_connected())
return -1;
unsigned long size = fetch_param(task, 0); unsigned long size = fetch_param(task, 0);
unsigned long ret = fetch_retval(task); unsigned long ret = fetch_retval(task);
return report_alloc(task, MT_VALLOC, ret, size, options.bt_depth, libsym); report_alloc(task, MT_VALLOC, ret, size, options.bt_depth, libsym);
} }
static int _report_pvalloc(struct task *task, struct library_symbol *libsym) static void _report_pvalloc(struct task *task, struct library_symbol *libsym)
{ {
if (!server_connected())
return -1;
unsigned long size = fetch_param(task, 0); unsigned long size = fetch_param(task, 0);
unsigned long ret = fetch_retval(task); unsigned long ret = fetch_retval(task);
return report_alloc(task, MT_PVALLOC, ret, size, options.bt_depth, libsym); return report_alloc(task, MT_PVALLOC, ret, size, options.bt_depth, libsym);
} }
static int report_mremap(struct task *task, struct library_symbol *libsym) static void report_mremap(struct task *task, struct library_symbol *libsym)
{ {
unsigned long addr = fetch_param(task, 0); unsigned long addr = fetch_param(task, 0);
unsigned long size = fetch_param(task, 1); unsigned long size = fetch_param(task, 1);
return report_alloc(task, MT_MUNMAP, addr, size, 0, libsym); report_alloc(task, MT_MUNMAP, addr, size, 0, libsym);
} }
static int _report_mremap(struct task *task, struct library_symbol *libsym) static void _report_mremap(struct task *task, struct library_symbol *libsym)
{ {
unsigned long size = fetch_param(task, 2); unsigned long size = fetch_param(task, 2);
unsigned long ret = fetch_retval(task); unsigned long ret = fetch_retval(task);
return report_alloc(task, MT_MMAP, ret, size, options.bt_depth, libsym); report_alloc(task, MT_MMAP, ret, size, options.bt_depth, libsym);
} }
static const struct function flist[] = { static const struct function flist[] = {
@ -416,13 +390,14 @@ int _report_map(struct task *task, struct library *lib, enum mt_operation op)
struct libref *libref = lib->libref; struct libref *libref = lib->libref;
size_t len = strlen(libref->filename) + 1; size_t len = strlen(libref->filename) + 1;
struct mt_map_payload *payload = alloca(sizeof(struct mt_map_payload) + len); struct mt_map_payload *payload = alloca(sizeof(struct mt_map_payload) + len);
payload->addr = libref->load_addr; payload->addr = libref->load_addr;
payload->offset = libref->load_offset; payload->offset = libref->load_offset;
payload->size = libref->load_size; payload->size = libref->load_size;
memcpy(payload->filename, libref->filename, len); memcpy(payload->filename, libref->filename, len);
return server_send_msg(op, task->pid, 0, payload, sizeof(struct mt_map_payload) + len); return server_send_msg(op, task->pid, payload, sizeof(struct mt_map_payload) + len);
} }
int report_add_map(struct task *task, struct library *lib) int report_add_map(struct task *task, struct library *lib)
@ -441,6 +416,13 @@ int report_del_map(struct task *task, struct library *lib)
return _report_map(task, lib, MT_DEL_MAP); return _report_map(task, lib, MT_DEL_MAP);
} }
static void store_timer_info(struct memtrace_timer_info *info, struct mt_timer *timer)
{
info->max = timer->max;
info->count = timer->count;
info->culminate = timer->culminate;
}
int report_info(int do_trace) int report_info(int do_trace)
{ {
struct memtrace_info mt_info; struct memtrace_info mt_info;
@ -452,6 +434,16 @@ int report_info(int do_trace)
mt_info.mode = 0; mt_info.mode = 0;
mt_info.do_trace = do_trace ? 1 : 0; mt_info.do_trace = do_trace ? 1 : 0;
mt_info.stack_depth = options.bt_depth; mt_info.stack_depth = options.bt_depth;
mt_info.verbose = options.verbose;
store_timer_info(&mt_info.stop_time, &stop_time);
store_timer_info(&mt_info.sw_bp_time, &sw_bp_time);
store_timer_info(&mt_info.hw_bp_time, &hw_bp_time);
store_timer_info(&mt_info.backtrace_time, &backtrace_time);
store_timer_info(&mt_info.reorder_time, &reorder_time);
store_timer_info(&mt_info.report_in_time, &report_in_time);
store_timer_info(&mt_info.report_out_time, &report_out_time);
store_timer_info(&mt_info.skip_bp_time, &skip_bp_time);
if (options.verbose) if (options.verbose)
mt_info.mode |= MEMTRACE_SI_VERBOSE; mt_info.mode |= MEMTRACE_SI_VERBOSE;
@ -462,7 +454,7 @@ int report_info(int do_trace)
if (options.follow) if (options.follow)
mt_info.mode |= MEMTRACE_SI_FORK; mt_info.mode |= MEMTRACE_SI_FORK;
return server_send_msg(MT_INFO, 0, 0, &mt_info, sizeof(mt_info)); return server_send_msg(MT_INFO, 0, &mt_info, sizeof(mt_info));
} }
int report_scan(pid_t pid, const void *data, unsigned int data_len) int report_scan(pid_t pid, const void *data, unsigned int data_len)
@ -470,7 +462,7 @@ int report_scan(pid_t pid, const void *data, unsigned int data_len)
if (!server_connected()) if (!server_connected())
return -1; return -1;
return server_send_msg(MT_SCAN, pid, 0, data, data_len); return server_send_msg(MT_SCAN, pid, data, data_len);
} }
int report_attach(struct task *task) int report_attach(struct task *task)
@ -480,7 +472,7 @@ int report_attach(struct task *task)
if (!server_connected()) if (!server_connected())
return -1; return -1;
return server_send_msg(task_is_64bit(task) ? MT_ATTACH64 : MT_ATTACH, task->pid, 0, &state, sizeof(state)); return server_send_msg(task_is_64bit(task) ? MT_ATTACH64 : MT_ATTACH, task->pid, &state, sizeof(state));
} }
int report_fork(struct task *task, struct task *ptask) int report_fork(struct task *task, struct task *ptask)
@ -490,7 +482,7 @@ int report_fork(struct task *task, struct task *ptask)
if (!server_connected()) if (!server_connected())
return -1; return -1;
return server_send_msg(MT_FORK, task->pid, 0, &fork_pid, sizeof(fork_pid)); return server_send_msg(MT_FORK, task->pid, &fork_pid, sizeof(fork_pid));
} }
int report_exit(struct task *task) int report_exit(struct task *task)
@ -498,7 +490,7 @@ int report_exit(struct task *task)
if (!server_connected()) if (!server_connected())
return -1; return -1;
return server_send_msg(MT_EXIT, task->pid, 0, NULL, 0); return server_send_msg(MT_EXIT, task->pid, NULL, 0);
} }
int report_about_exit(struct task *task) int report_about_exit(struct task *task)
@ -506,7 +498,7 @@ int report_about_exit(struct task *task)
if (!server_connected()) if (!server_connected())
return -1; return -1;
return server_send_msg(MT_ABOUT_EXIT, task->pid, 0, NULL, 0); return server_send_msg(MT_ABOUT_EXIT, task->pid, NULL, 0);
} }
int report_nofollow(struct task *task) int report_nofollow(struct task *task)
@ -514,7 +506,7 @@ int report_nofollow(struct task *task)
if (!server_connected()) if (!server_connected())
return -1; return -1;
return server_send_msg(MT_NOFOLLOW, task->pid, 0, NULL, 0); return server_send_msg(MT_NOFOLLOW, task->pid, NULL, 0);
} }
int report_detach(struct task *task) int report_detach(struct task *task)
@ -522,7 +514,7 @@ int report_detach(struct task *task)
if (!server_connected()) if (!server_connected())
return -1; return -1;
return server_send_msg(MT_DETACH, task->pid, 0, NULL, 0); return server_send_msg(MT_DETACH, task->pid, NULL, 0);
} }
int report_disconnect(void) int report_disconnect(void)
@ -530,7 +522,7 @@ int report_disconnect(void)
if (!server_connected()) if (!server_connected())
return -1; return -1;
return server_send_msg(MT_DISCONNECT, 0, 0, NULL, 0); return server_send_msg(MT_DISCONNECT, 0, NULL, 0);
} }
static void report_process(struct task *leader) static void report_process(struct task *leader)

View File

@ -33,9 +33,9 @@ struct function {
/* level for aliased symbol */ /* level for aliased symbol */
unsigned int level; unsigned int level;
/* report when function is entered */ /* report when function is entered */
int (*report_in)(struct task *task, struct library_symbol *libsym); void (*report_in)(struct task *task, struct library_symbol *libsym);
/* report when function is exited */ /* report when function is exited */
int (*report_out)(struct task *task, struct library_symbol *libsym); void (*report_out)(struct task *task, struct library_symbol *libsym);
}; };
const struct function *flist_matches_symbol(const char *sym_name); const struct function *flist_matches_symbol(const char *sym_name);

View File

@ -159,7 +159,7 @@ int server_handle_command(void)
if (ret != sizeof(cmd)) { if (ret != sizeof(cmd)) {
if (ret > 0) { if (ret > 0) {
if (options.verbose) if (unlikely(options.verbose))
fprintf(stderr, "cmd read wrong size %d\n", ret); fprintf(stderr, "cmd read wrong size %d\n", ret);
} }
server_close(); server_close();
@ -177,6 +177,9 @@ int server_handle_command(void)
} }
if (!cmd.pid) { if (!cmd.pid) {
if (cmd.operation == MT_INFO)
report_info(1);
else
server_close(); server_close();
goto finish; goto finish;
} }
@ -277,7 +280,7 @@ int server_start(void)
fatal("accept (%s)", strerror(errno)); fatal("accept (%s)", strerror(errno));
fprintf(stderr, "connected!\n"); fprintf(stderr, "connected!\n");
server_mode = MODE_ACCEPTED;
report_info(1); report_info(1);
} }
@ -341,7 +344,7 @@ int server_start_pair(void)
return sv[1]; return sv[1];
} }
int server_send_msg(enum mt_operation op, uint32_t pid, uint32_t tid, const void *payload, unsigned int payload_len) int server_send_msg(enum mt_operation op, uint32_t pid, const void *payload, unsigned int payload_len)
{ {
if (options.logfile) { if (options.logfile) {
struct iovec io[2]; struct iovec io[2];
@ -350,7 +353,6 @@ int server_send_msg(enum mt_operation op, uint32_t pid, uint32_t tid, const void
mt_msg.operation = op; mt_msg.operation = op;
mt_msg.pid = pid; mt_msg.pid = pid;
mt_msg.tid = tid;
mt_msg.payload_len = payload_len; mt_msg.payload_len = payload_len;
io[0].iov_base = &mt_msg; io[0].iov_base = &mt_msg;
@ -367,7 +369,7 @@ int server_send_msg(enum mt_operation op, uint32_t pid, uint32_t tid, const void
return ret; return ret;
} }
return sock_send_msg(server_fd, op, pid, tid, payload, payload_len); return sock_send_msg(server_fd, op, pid, payload, payload_len);
} }
int server_stop(void) int server_stop(void)

View File

@ -29,7 +29,7 @@
int server_start(void); int server_start(void);
int server_start_pair(void); int server_start_pair(void);
int server_send_msg(enum mt_operation op, uint32_t pid, uint32_t tid, const void *payload, unsigned int payload_len); int server_send_msg(enum mt_operation op, uint32_t pid, const void *payload, unsigned int payload_len);
int server_handle_command(void); int server_handle_command(void);
int server_connected(void); int server_connected(void);
int server_stop(void); int server_stop(void);

View File

@ -25,7 +25,6 @@ noinst_LTLIBRARIES = \
../libos.la ../libos.la
___libos_la_SOURCES = \ ___libos_la_SOURCES = \
backtrace.c \
ioevent.c \ ioevent.c \
trace.c \ trace.c \
os.c \ os.c \

View File

@ -125,8 +125,8 @@ CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES = CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES) LTLIBRARIES = $(noinst_LTLIBRARIES)
___libos_la_DEPENDENCIES = libcpu.la ___libos_la_DEPENDENCIES = libcpu.la
am____libos_la_OBJECTS = backtrace.lo ioevent.lo trace.lo os.lo \ am____libos_la_OBJECTS = ioevent.lo trace.lo os.lo proc.lo socket.lo \
proc.lo socket.lo thread.lo thread.lo
___libos_la_OBJECTS = $(am____libos_la_OBJECTS) ___libos_la_OBJECTS = $(am____libos_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@) AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@ -368,7 +368,6 @@ noinst_LTLIBRARIES = \
../libos.la ../libos.la
___libos_la_SOURCES = \ ___libos_la_SOURCES = \
backtrace.c \
ioevent.c \ ioevent.c \
trace.c \ trace.c \
os.c \ os.c \
@ -441,7 +440,6 @@ mostlyclean-compile:
distclean-compile: distclean-compile:
-rm -f *.tab.c -rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backtrace.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ioevent.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ioevent.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc.Plo@am__quote@

View File

@ -1,82 +0,0 @@
/*
* This file is part of mtrace-ng.
* Copyright (C) 2015 Stefani Seibold <stefani@seibold.net>
*
* This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include "backtrace.h"
#include "dwarf.h"
#include "task.h"
#include <assert.h>
#include <stdio.h>
int backtrace_init(struct task *task)
{
assert(task->leader == task);
assert(task->backtrace == NULL);
task->backtrace = dwarf_init(task->is_64bit);
return task->backtrace != NULL;
}
void backtrace_destroy(struct task *task)
{
assert(task->leader == task);
if (task->backtrace) {
dwarf_destroy(task->backtrace);
task->backtrace = NULL;
}
}
int backtrace_init_unwind(struct task *task)
{
assert(task->leader);
assert(task->leader->backtrace);
return dwarf_init_unwind(task->leader->backtrace, task);
}
unsigned long backtrace_get_ip(struct task *task)
{
assert(task->leader);
assert(task->leader->backtrace);
return dwarf_get_ip(task->leader->backtrace);
}
int backtrace_step(struct task *task)
{
assert(task->leader);
assert(task->leader->backtrace);
return dwarf_step(task->leader->backtrace);
}
int backtrace_location_type(struct task *task)
{
assert(task->leader);
assert(task->leader->backtrace);
return dwarf_location_type(task->leader->backtrace);
}

View File

@ -40,7 +40,7 @@ struct io_watch_event *io_watch_event;
static unsigned int io_watch_size; static unsigned int io_watch_size;
static unsigned int io_watch_elems; static unsigned int io_watch_elems;
static inline void io_watch_set(unsigned int idx, int fd, int (*func)(void)) static inline void io_watch_set(unsigned int idx, int fd, ioevent_func func)
{ {
io_watch_event[idx].func = func; io_watch_event[idx].func = func;
@ -48,7 +48,7 @@ static inline void io_watch_set(unsigned int idx, int fd, int (*func)(void))
io_watch_poll[idx].events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL; io_watch_poll[idx].events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
} }
int ioevent_add_input(int fd, int (*func)(void)) int ioevent_add_input(int fd, ioevent_func func)
{ {
unsigned int i; unsigned int i;
@ -113,6 +113,21 @@ int ioevent_watch(int timeout)
return ret; return ret;
} }
ioevent_func ioevent_set_input_func(int fd, ioevent_func func)
{
unsigned int i;
for(i = 0; i < io_watch_elems; ++i) {
if (io_watch_poll[i].fd == fd) {
int (*old)(void) = io_watch_event[i].func;
io_watch_event[i].func = func;
return old;
}
}
return NULL;
}
int ioevent_wait_input(int fd, int timeout) int ioevent_wait_input(int fd, int timeout)
{ {

View File

@ -23,10 +23,13 @@
#ifndef _INC_SYSDEPS_LINUX_GNU_IOEVENT_H #ifndef _INC_SYSDEPS_LINUX_GNU_IOEVENT_H
#define _INC_SYSDEPS_LINUX_GNU_IOEVENT_H #define _INC_SYSDEPS_LINUX_GNU_IOEVENT_H
int ioevent_add_input(int fd, int (*func)(void)); typedef int (*ioevent_func)(void);
int ioevent_add_input(int fd, ioevent_func func);
int ioevent_del_input(int fd); int ioevent_del_input(int fd);
int ioevent_watch(int timeout); int ioevent_watch(int timeout);
int ioevent_wait_input(int fd, int timeout); int ioevent_wait_input(int fd, int timeout);
ioevent_func ioevent_set_input_func(int fd, ioevent_func func);
#endif #endif

View File

@ -43,6 +43,7 @@
#endif #endif
#include <pwd.h> #include <pwd.h>
#include <grp.h> #include <grp.h>
#include <sys/prctl.h>
#include "backend.h" #include "backend.h"
#include "breakpoint.h" #include "breakpoint.h"
@ -178,8 +179,8 @@ static struct map *get_writeable_mappings(struct task *task)
char filename[PATH_MAX + 2]; char filename[PATH_MAX + 2];
char nl; char nl;
FILE *in; FILE *in;
unsigned int maps_size = 0; unsigned int maps_size;
struct map *maps = NULL; struct map *maps;
unsigned int map = 0; unsigned int map = 0;
snprintf(filename, sizeof(filename)-1, "/proc/%d/maps", task->pid); snprintf(filename, sizeof(filename)-1, "/proc/%d/maps", task->pid);
@ -393,6 +394,8 @@ int os_init(void)
const int siglist[] = { SIGSEGV, SIGABRT, SIGTRAP, SIGILL, SIGFPE }; const int siglist[] = { SIGSEGV, SIGABRT, SIGTRAP, SIGILL, SIGFPE };
unsigned int i; unsigned int i;
prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
for(i = 0; i < ARRAY_SIZE(siglist); i++) { for(i = 0; i < ARRAY_SIZE(siglist); i++) {
act.sa_flags = SA_ONESHOT | SA_SIGINFO; act.sa_flags = SA_ONESHOT | SA_SIGINFO;
act.sa_sigaction = report_fault; act.sa_sigaction = report_fault;

View File

@ -490,15 +490,16 @@ static int load_debug_struct(struct task *task, arch_addr_t debug_addr, struct l
static int rdebug_bp_on_hit(struct task *task, struct breakpoint *bp) static int rdebug_bp_on_hit(struct task *task, struct breakpoint *bp)
{ {
struct lt_r_debug_64 rdbg; struct lt_r_debug_64 rdbg;
struct task *leader = task->leader;
debug(DEBUG_FUNCTION, "pid=%d", task->pid); debug(DEBUG_FUNCTION, "pid=%d", task->pid);
if (load_debug_struct(task, task->os.debug_addr, &rdbg) < 0) if (load_debug_struct(task, leader->os.debug_addr, &rdbg) < 0)
return 0; return 0;
if (rdbg.r_state == RT_CONSISTENT) { if (rdbg.r_state == RT_CONSISTENT) {
debug(DEBUG_FUNCTION, "Linkmap is now consistent"); debug(DEBUG_FUNCTION, "Linkmap is now consistent");
switch (task->os.debug_state) { switch (leader->os.debug_state) {
case RT_ADD: case RT_ADD:
linkmap_add(task, &rdbg); linkmap_add(task, &rdbg);
break; break;
@ -510,7 +511,7 @@ static int rdebug_bp_on_hit(struct task *task, struct breakpoint *bp)
} }
} }
task->os.debug_state = rdbg.r_state; leader->os.debug_state = rdbg.r_state;
return 0; return 0;
} }
@ -519,10 +520,11 @@ int linkmap_init(struct task *task, arch_addr_t dyn_addr)
struct lt_r_debug_64 rdbg; struct lt_r_debug_64 rdbg;
struct breakpoint *bp; struct breakpoint *bp;
arch_addr_t debug_addr; arch_addr_t debug_addr;
struct task *leader = task->leader;
debug(DEBUG_FUNCTION, "pid=%d, dyn_addr=%#lx", task->pid, dyn_addr); debug(DEBUG_FUNCTION, "pid=%d, dyn_addr=%#lx", task->pid, dyn_addr);
if (task->os.debug_addr) if (leader->os.debug_addr)
return 0; return 0;
if (process_find_dynamic_entry_addr(task, dyn_addr, DT_DEBUG, &debug_addr) == -1) { if (process_find_dynamic_entry_addr(task, dyn_addr, DT_DEBUG, &debug_addr) == -1) {
@ -538,7 +540,7 @@ int linkmap_init(struct task *task, arch_addr_t dyn_addr)
arch_addr_t addr = ARCH_ADDR_T(rdbg.r_brk); arch_addr_t addr = ARCH_ADDR_T(rdbg.r_brk);
bp = breakpoint_new(task, addr, NULL, 0); bp = breakpoint_new(task, addr, NULL, BP_SW);
if (!bp) if (!bp)
return -1; return -1;
@ -547,7 +549,7 @@ int linkmap_init(struct task *task, arch_addr_t dyn_addr)
breakpoint_enable(task, bp); breakpoint_enable(task, bp);
task->os.debug_addr = debug_addr; leader->os.debug_addr = debug_addr;
if (rdbg.r_state == RT_CONSISTENT) if (rdbg.r_state == RT_CONSISTENT)
linkmap_add(task, &rdbg); linkmap_add(task, &rdbg);
@ -607,8 +609,10 @@ done:
int os_task_init(struct task *task) int os_task_init(struct task *task)
{ {
task->os.debug_addr = 0; struct task *leader = task->leader;
task->os.debug_state = RT_ADD;
leader->os.debug_addr = 0;
leader->os.debug_state = RT_ADD;
return 0; return 0;
} }
@ -618,7 +622,9 @@ void os_task_destroy(struct task *task)
int os_task_clone(struct task *retp, struct task *task) int os_task_clone(struct task *retp, struct task *task)
{ {
retp->os = task->os; struct task *leader = task->leader;
retp->os = leader->os;
return 0; return 0;
} }

View File

@ -32,6 +32,8 @@
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include "common.h" #include "common.h"
#include "socket.h" #include "socket.h"
@ -64,7 +66,7 @@ ssize_t safe_read(int fd, void *dest, size_t n)
return off + n; return off + n;
} }
int sock_send_msg(int fd, enum mt_operation op, uint32_t pid, uint32_t tid, const void *payload, unsigned int payload_len) int sock_send_msg(int fd, enum mt_operation op, uint32_t pid, const void *payload, unsigned int payload_len)
{ {
struct mt_msg mt_msg; struct mt_msg mt_msg;
struct iovec io[2]; struct iovec io[2];
@ -96,12 +98,10 @@ int sock_send_msg(int fd, enum mt_operation op, uint32_t pid, uint32_t tid, cons
if (op > 0xff) { if (op > 0xff) {
mt_msg.pid = bswap_32(pid); mt_msg.pid = bswap_32(pid);
mt_msg.tid = bswap_32(tid);
mt_msg.payload_len = bswap_32(payload_len); mt_msg.payload_len = bswap_32(payload_len);
} }
else { else {
mt_msg.pid = pid; mt_msg.pid = pid;
mt_msg.tid = tid;
mt_msg.payload_len = payload_len; mt_msg.payload_len = payload_len;
} }
@ -215,6 +215,8 @@ int bind_to(const char *node, const char *service)
} }
else { else {
struct addrinfo *rp; struct addrinfo *rp;
int size = 10 * 1024 * 1024;
static const int one = 1;
for (rp = sock_addr(node, service, AI_PASSIVE); rp != NULL; rp = rp->ai_next) { for (rp = sock_addr(node, service, AI_PASSIVE); rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
@ -232,6 +234,12 @@ int bind_to(const char *node, const char *service)
if (!rp) if (!rp)
return -1; return -1;
if (setsockopt(sfd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)) == -1)
fatal("TCP_NODELAY: %s\n", strerror(errno));
if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) == -1)
fatal("SO_SNDBUF: %s\n", strerror(errno));
} }
return sfd; return sfd;

View File

@ -35,7 +35,7 @@
ssize_t safe_read(int fd, void *dest, size_t n); ssize_t safe_read(int fd, void *dest, size_t n);
int connect_to(const char *node, const char *service); int connect_to(const char *node, const char *service);
int bind_to(const char *node, const char *service); int bind_to(const char *node, const char *service);
int sock_send_msg(int fd, enum mt_operation op, uint32_t pid, uint32_t tid, const void *payload, unsigned int payload_len); int sock_send_msg(int fd, enum mt_operation op, uint32_t pid, const void *payload, unsigned int payload_len);
int create_socket_pair(int sv[2]); int create_socket_pair(int sv[2]);
int is_named(const char *node); int is_named(const char *node);

View File

@ -48,8 +48,10 @@
#include "debug.h" #include "debug.h"
#include "event.h" #include "event.h"
#include "library.h" #include "library.h"
#include "main.h"
#include "options.h" #include "options.h"
#include "task.h" #include "task.h"
#include "timer.h"
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static volatile pid_t wakeup_pid = -1; static volatile pid_t wakeup_pid = -1;
@ -92,7 +94,7 @@ static int _trace_wait(struct task *task, int signum)
{ {
int status; int status;
if (TEMP_FAILURE_RETRY(waitpid(task->pid, &status, __WALL)) != task->pid) { if (unlikely(TEMP_FAILURE_RETRY(waitpid(task->pid, &status, __WALL)) != task->pid)) {
fprintf(stderr, "%s pid=%d %s\n", __FUNCTION__, task->pid, strerror(errno)); fprintf(stderr, "%s pid=%d %s\n", __FUNCTION__, task->pid, strerror(errno));
return -1; return -1;
} }
@ -117,7 +119,7 @@ static int child_event(struct task *task, enum event_type ev)
{ {
unsigned long data; unsigned long data;
if (ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1) { if (unlikely(ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1)) {
debug(DEBUG_EVENT, "PTRACE_GETEVENTMSG pid=%d %s", task->pid, strerror(errno)); debug(DEBUG_EVENT, "PTRACE_GETEVENTMSG pid=%d %s", task->pid, strerror(errno));
return -1; return -1;
} }
@ -127,7 +129,7 @@ static int child_event(struct task *task, enum event_type ev)
if (!pid2task(pid)) { if (!pid2task(pid)) {
struct task *child = task_new(pid); struct task *child = task_new(pid);
if (!child) if (unlikely(!child))
return -1; return -1;
if (_trace_wait(child, SIGSTOP)) { if (_trace_wait(child, SIGSTOP)) {
@ -190,7 +192,7 @@ static int _process_event(struct task *task, int status)
{ {
unsigned long data; unsigned long data;
if (ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1) { if (unlikely(ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1)) {
debug(DEBUG_EVENT, "PTRACE_GETEVENTMSG pid=%d %s", task->pid, strerror(errno)); debug(DEBUG_EVENT, "PTRACE_GETEVENTMSG pid=%d %s", task->pid, strerror(errno));
return -1; return -1;
} }
@ -221,6 +223,9 @@ static void process_event(struct task *task, int status)
assert(leader != NULL); assert(leader != NULL);
if (unlikely(options.verbose > 1))
start_time(&task->halt_time);
task->stopped = 1; task->stopped = 1;
leader->threads_stopped++; leader->threads_stopped++;
@ -236,10 +241,10 @@ static void process_event(struct task *task, int status)
if (stop_signal == 0) if (stop_signal == 0)
return; return;
if (stop_signal != SIGTRAP) if (unlikely(stop_signal != SIGTRAP))
return; return;
if (fetch_context(task) == -1) { if (unlikely(fetch_context(task) == -1)) {
task->event.type = EVENT_NONE; task->event.type = EVENT_NONE;
continue_task(task, 0); continue_task(task, 0);
return; return;
@ -252,7 +257,7 @@ static void process_event(struct task *task, int status)
for(i = 0; i < HW_BREAKPOINTS; ++i) { for(i = 0; i < HW_BREAKPOINTS; ++i) {
if (task->hw_bp[i] && task->hw_bp[i]->addr == ip) { if (task->hw_bp[i] && task->hw_bp[i]->addr == ip) {
if (get_hw_bp_state(task, i)) if (likely(get_hw_bp_state(task, i)))
bp = task->hw_bp[i]; bp = task->hw_bp[i];
break; break;
@ -262,15 +267,12 @@ static void process_event(struct task *task, int status)
if (bp) { if (bp) {
assert(bp->type != BP_SW); assert(bp->type != BP_SW);
assert(bp->hw_bp_slot == i); assert(bp->hw_bp_slot == i);
if (options.verbose > 1)
++leader->num_hw_bp;
} }
else else
#endif #endif
{ {
bp = breakpoint_find(leader, ip - DECR_PC_AFTER_BREAK); bp = breakpoint_find(leader, ip - DECR_PC_AFTER_BREAK);
if (!bp) { if (unlikely(!bp)) {
task->event.type = EVENT_NONE; task->event.type = EVENT_NONE;
continue_task(task, 0); continue_task(task, 0);
return; return;
@ -280,9 +282,6 @@ static void process_event(struct task *task, int status)
assert(bp->hw == 0); assert(bp->hw == 0);
#endif #endif
if (options.verbose > 1)
++leader->num_sw_bp;
set_instruction_pointer(task, bp->addr); set_instruction_pointer(task, bp->addr);
} }
#if 1 #if 1
@ -321,7 +320,7 @@ void trace_me(void)
prctl(PR_SET_PDEATHSIG, SIGKILL); prctl(PR_SET_PDEATHSIG, SIGKILL);
if (ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) { if (unlikely(ptrace(PTRACE_TRACEME, 0, 0, 0) == -1)) {
fprintf(stderr, "PTRACE_TRACEME pid=%d %s\n", getpid(), strerror(errno)); fprintf(stderr, "PTRACE_TRACEME pid=%d %s\n", getpid(), strerror(errno));
exit(1); exit(1);
} }
@ -347,7 +346,7 @@ int untrace_task(struct task *task, int signum)
if (!task->stopped) if (!task->stopped)
return 0; return 0;
if (ptrace(PTRACE_SETOPTIONS, task->pid, 0, (void *)0) == -1) { if (unlikely(ptrace(PTRACE_SETOPTIONS, task->pid, 0, (void *)0) == -1)) {
if (errno != ESRCH) if (errno != ESRCH)
fprintf(stderr, "PTRACE_SETOPTIONS pid=%d %s\n", task->pid, strerror(errno)); fprintf(stderr, "PTRACE_SETOPTIONS pid=%d %s\n", task->pid, strerror(errno));
ret = -1; ret = -1;
@ -356,7 +355,7 @@ int untrace_task(struct task *task, int signum)
signum = fix_signal(task, signum); signum = fix_signal(task, signum);
if (ptrace(PTRACE_DETACH, task->pid, 0, signum) == -1) { if (unlikely(ptrace(PTRACE_DETACH, task->pid, 0, signum) == -1)) {
if (task->traced) { if (task->traced) {
if (errno != ESRCH) if (errno != ESRCH)
fprintf(stderr, "PTRACE_DETACH pid=%d %s\n", task->pid, strerror(errno)); fprintf(stderr, "PTRACE_DETACH pid=%d %s\n", task->pid, strerror(errno));
@ -381,7 +380,7 @@ int trace_attach(struct task *task)
assert(task->traced == 0); assert(task->traced == 0);
if (ptrace(PTRACE_ATTACH, task->pid, 0, 0) == -1) { if (unlikely(ptrace(PTRACE_ATTACH, task->pid, 0, 0) == -1)) {
if (errno != ESRCH) if (errno != ESRCH)
fprintf(stderr, "PTRACE_ATTACH pid=%d %s\n", task->pid, strerror(errno)); fprintf(stderr, "PTRACE_ATTACH pid=%d %s\n", task->pid, strerror(errno));
trace_fail_warning(); trace_fail_warning();
@ -402,7 +401,7 @@ int trace_set_options(struct task *task)
debug(DEBUG_PROCESS, "pid=%d", task->pid); debug(DEBUG_PROCESS, "pid=%d", task->pid);
if (ptrace(PTRACE_SETOPTIONS, task->pid, 0, (void *)options) == -1) { if (unlikely(ptrace(PTRACE_SETOPTIONS, task->pid, 0, (void *)options) == -1)) {
if (errno != ESRCH) if (errno != ESRCH)
fprintf(stderr, "PTRACE_SETOPTIONS pid=%d %s\n", task->pid, strerror(errno)); fprintf(stderr, "PTRACE_SETOPTIONS pid=%d %s\n", task->pid, strerror(errno));
return -1; return -1;
@ -420,7 +419,7 @@ int continue_task(struct task *task, int signum)
task->leader->threads_stopped--; task->leader->threads_stopped--;
task->stopped = 0; task->stopped = 0;
if (ptrace(PTRACE_CONT, task->pid, 0, fix_signal(task, signum)) == -1) { if (unlikely(ptrace(PTRACE_CONT, task->pid, 0, fix_signal(task, signum)) == -1)) {
if (errno != ESRCH) if (errno != ESRCH)
fprintf(stderr, "PTRACE_CONT pid=%d %s\n", task->pid, strerror(errno)); fprintf(stderr, "PTRACE_CONT pid=%d %s\n", task->pid, strerror(errno));
return -1; return -1;
@ -445,10 +444,18 @@ void stop_threads(struct task *task)
assert(task->leader != NULL); assert(task->leader != NULL);
if (leader->threads != leader->threads_stopped) { if (leader->threads != leader->threads_stopped) {
struct timespec start;
if (unlikely(options.verbose > 1))
start_time(&start);
each_task(leader, &do_stop_cb, NULL); each_task(leader, &do_stop_cb, NULL);
while (leader->threads != leader->threads_stopped) while (leader->threads != leader->threads_stopped)
queue_event(wait_event()); queue_event(wait_event());
if (unlikely(options.verbose > 1))
set_timer(&start, &stop_time);
} }
} }
@ -458,10 +465,10 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task))
int stop_signal; int stop_signal;
for(;;) { for(;;) {
if (singlestep(task) == -1) if (unlikely(singlestep(task) == -1))
return -1; return -1;
if (TEMP_FAILURE_RETRY(waitpid(task->pid, &status, __WALL)) != task->pid) { if (unlikely(TEMP_FAILURE_RETRY(waitpid(task->pid, &status, __WALL)) != task->pid)) {
fprintf(stderr, "%s waitpid pid=%d %s\n", __FUNCTION__, task->pid, strerror(errno)); fprintf(stderr, "%s waitpid pid=%d %s\n", __FUNCTION__, task->pid, strerror(errno));
return -1; return -1;
} }
@ -471,10 +478,10 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task))
if (stop_signal == -1) if (stop_signal == -1)
return -1; return -1;
if (stop_signal == SIGTRAP) if (likely(stop_signal == SIGTRAP))
return 0; /* check if was a real breakpoint code there */ return 0; /* check if was a real breakpoint code there */
if (!stop_signal) { if (likely(!stop_signal)) {
queue_event(task); queue_event(task);
return 0; return 0;
} }
@ -489,7 +496,7 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task))
#ifndef ARCH_SINGLESTEP #ifndef ARCH_SINGLESTEP
static int ptrace_singlestep(struct task *task) static int ptrace_singlestep(struct task *task)
{ {
if (ptrace(PTRACE_SINGLESTEP, task->pid, 0, 0) == -1) { if (unlikely(ptrace(PTRACE_SINGLESTEP, task->pid, 0, 0) == -1)) {
if (errno != ESRCH) if (errno != ESRCH)
fprintf(stderr, "%s PTRACE_SINGLESTEP pid=%d %s\n", __FUNCTION__, task->pid, strerror(errno)); fprintf(stderr, "%s PTRACE_SINGLESTEP pid=%d %s\n", __FUNCTION__, task->pid, strerror(errno));
return -1; return -1;
@ -510,7 +517,7 @@ struct task *wait_event(void)
int pid; int pid;
pid = waitpid(-1, &status, __WALL); pid = waitpid(-1, &status, __WALL);
if (pid == -1) { if (unlikely(pid == -1)) {
if (errno != EINTR) { if (errno != EINTR) {
if (errno == ECHILD) if (errno == ECHILD)
debug(DEBUG_EVENT, "No more traced programs"); debug(DEBUG_EVENT, "No more traced programs");
@ -521,7 +528,7 @@ struct task *wait_event(void)
} }
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
if (pid == wakeup_pid) { if (unlikely(pid == wakeup_pid)) {
pid = 0; pid = 0;
wakeup_pid = -1; wakeup_pid = -1;
} }
@ -531,10 +538,10 @@ struct task *wait_event(void)
return NULL; return NULL;
task = pid2task(pid); task = pid2task(pid);
if (!task) { if (unlikely(!task)) {
task = task_new(pid); task = task_new(pid);
if (task) if (likely(task))
trace_setup(task, status, SIGSTOP); trace_setup(task, status, SIGSTOP);
return NULL; return NULL;
@ -591,7 +598,7 @@ ssize_t copy_from_proc(struct task *task, arch_addr_t addr, void *dst, size_t le
remote[0].iov_len = len; remote[0].iov_len = len;
num_bytes = process_vm_readv(task->pid, local, 1, remote, 1, 0); num_bytes = process_vm_readv(task->pid, local, 1, remote, 1, 0);
if (num_bytes != -1) if (unlikely(num_bytes != -1))
return num_bytes; return num_bytes;
if (errno != EFAULT) { if (errno != EFAULT) {
@ -610,7 +617,7 @@ ssize_t copy_from_proc(struct task *task, arch_addr_t addr, void *dst, size_t le
while (len) { while (len) {
a.a = ptrace(PTRACE_PEEKTEXT, task->pid, addr, 0); a.a = ptrace(PTRACE_PEEKTEXT, task->pid, addr, 0);
if (a.a == -1 && errno) { if (unlikely(a.a == -1 && errno)) {
if (num_bytes && errno == EIO) if (num_bytes && errno == EIO)
break; break;
return -1; return -1;
@ -650,7 +657,7 @@ ssize_t copy_to_proc(struct task *task, arch_addr_t addr, const void *src, size_
n = len; n = len;
a.a = ptrace(PTRACE_PEEKTEXT, task->pid, addr, 0); a.a = ptrace(PTRACE_PEEKTEXT, task->pid, addr, 0);
if (a.a == -1 && errno) { if (unlikely(a.a == -1 && errno)) {
if (num_bytes && errno == EIO) if (num_bytes && errno == EIO)
break; break;
return -1; return -1;
@ -660,7 +667,7 @@ ssize_t copy_to_proc(struct task *task, arch_addr_t addr, const void *src, size_
memcpy(a.c, src, n); memcpy(a.c, src, n);
a.a = ptrace(PTRACE_POKETEXT, task->pid, addr, a.a); a.a = ptrace(PTRACE_POKETEXT, task->pid, addr, a.a);
if (a.a == -1) { if (unlikely(a.a == -1)) {
if (num_bytes && errno == EIO) if (num_bytes && errno == EIO)
break; break;
return -1; return -1;
@ -690,7 +697,7 @@ ssize_t copy_from_to_proc(struct task *task, arch_addr_t addr, const void *src,
while (len) { while (len) {
a.a = ptrace(PTRACE_PEEKTEXT, task->pid, addr, 0); a.a = ptrace(PTRACE_PEEKTEXT, task->pid, addr, 0);
if (a.a == -1 && errno) { if (unlikely(a.a == -1 && errno)) {
if (num_bytes && errno == EIO) if (num_bytes && errno == EIO)
break; break;
return -1; return -1;
@ -703,7 +710,7 @@ ssize_t copy_from_to_proc(struct task *task, arch_addr_t addr, const void *src,
memcpy(a.c, src, n); memcpy(a.c, src, n);
a.a = ptrace(PTRACE_POKETEXT, task->pid, addr, a.a); a.a = ptrace(PTRACE_POKETEXT, task->pid, addr, a.a);
if (a.a == -1) { if (unlikely(a.a == -1)) {
if (num_bytes && errno == EIO) if (num_bytes && errno == EIO)
break; break;
return -1; return -1;
@ -738,7 +745,7 @@ ssize_t copy_str_from_proc(struct task *task, arch_addr_t addr, char *dst, size_
while (len) { while (len) {
a.a = ptrace(PTRACE_PEEKTEXT, task->pid, addr, 0); a.a = ptrace(PTRACE_PEEKTEXT, task->pid, addr, 0);
if (a.a == -1 && errno) { if (unlikely(a.a == -1 && errno)) {
if (num_bytes && errno == EIO) if (num_bytes && errno == EIO)
break; break;
return -1; return -1;

View File

@ -43,7 +43,7 @@ int get_hw_bp_state(struct task *task, unsigned int n)
errno = 0; errno = 0;
ret = ptrace(PTRACE_PEEKUSER, task->pid, offsetof(struct user, u_debugreg[6]), 0); ret = ptrace(PTRACE_PEEKUSER, task->pid, offsetof(struct user, u_debugreg[6]), 0);
if (ret == -1 && errno) { if (unlikely(ret == -1 && errno)) {
if (errno != ESRCH) if (errno != ESRCH)
fprintf(stderr, "PTRACE_PEEKUSER u_debugreg[6] pid=%d %s\n", task->pid, strerror(errno)); fprintf(stderr, "PTRACE_PEEKUSER u_debugreg[6] pid=%d %s\n", task->pid, strerror(errno));
@ -59,7 +59,7 @@ static int _apply_hw_bp(struct task *task, uint32_t dr7)
task->arch.dr7 = dr7; task->arch.dr7 = dr7;
ret = ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct user, u_debugreg[7]), task->arch.dr7); ret = ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct user, u_debugreg[7]), task->arch.dr7);
if (ret) { if (unlikely(ret)) {
if (errno != ESRCH) { if (errno != ESRCH) {
fprintf(stderr, "PTRACE_POKEUSER u_debugreg[7] pid=%d %s\n", task->pid, strerror(errno)); fprintf(stderr, "PTRACE_POKEUSER u_debugreg[7] pid=%d %s\n", task->pid, strerror(errno));
return -1; return -1;
@ -89,7 +89,7 @@ static int set_breakpoint_addr(struct task *task, arch_addr_t addr, unsigned int
return 0; return 0;
ret = ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct user, u_debugreg[n]), addr); ret = ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct user, u_debugreg[n]), addr);
if (ret) { if (unlikely(ret)) {
if (errno != ESRCH) { if (errno != ESRCH) {
fprintf(stderr, "PTRACE_POKEUSER u_debugreg[%d] pid=%d %s\n", n, task->pid, strerror(errno)); fprintf(stderr, "PTRACE_POKEUSER u_debugreg[%d] pid=%d %s\n", n, task->pid, strerror(errno));
return -1; return -1;
@ -167,7 +167,7 @@ int set_hw_bp(struct task *task, unsigned int n, arch_addr_t addr)
if (reset_hw_bp(task, n) == -1) if (reset_hw_bp(task, n) == -1)
return -1; return -1;
#endif #endif
if (set_breakpoint_addr(task, addr, n) == -1) if (unlikely(set_breakpoint_addr(task, addr, n) == -1))
return -1; return -1;
return set_breakpoint_mode(task, return set_breakpoint_mode(task,

View File

@ -130,12 +130,12 @@ static const struct arch_reg arch_reg32 = {
.bp = DWARF_X86_EBP, .bp = DWARF_X86_EBP,
}; };
static int is_signal_frame(struct dwarf_cursor *c) static inline int is_signal_frame(struct dwarf_cursor *c)
{ {
return c->dci.signal_frame; return c->dci.signal_frame;
} }
static int is_plt_entry(struct dwarf_addr_space *as) static inline int is_plt_entry(struct dwarf_addr_space *as)
{ {
#if 0 #if 0
struct dwarf_cursor *c = &as->cursor; struct dwarf_cursor *c = &as->cursor;
@ -293,13 +293,13 @@ int dwarf_arch_map_reg(struct dwarf_addr_space *as, unsigned int reg)
{ {
#ifdef __x86_64__ #ifdef __x86_64__
if (as->is_64bit) { if (as->is_64bit) {
if (reg >= ARRAY_SIZE(dwarf_to_regnum_map64)) if (unlikely(reg >= ARRAY_SIZE(dwarf_to_regnum_map64)))
return -DWARF_EBADREG; return -DWARF_EBADREG;
return dwarf_to_regnum_map64[reg]; return dwarf_to_regnum_map64[reg];
} }
#endif #endif
if (reg >= ARRAY_SIZE(dwarf_to_regnum_map32)) if (unlikely(reg >= ARRAY_SIZE(dwarf_to_regnum_map32)))
return -DWARF_EBADREG; return -DWARF_EBADREG;
return dwarf_to_regnum_map32[reg]; return dwarf_to_regnum_map32[reg];
@ -330,16 +330,16 @@ int dwarf_arch_check_call(struct dwarf_addr_space *as, arch_addr_t ip)
struct libref *libref = c->libref; struct libref *libref = c->libref;
for(p = call_op; p->len; ++p) { for(p = call_op; p->len; ++p) {
if (ip - ARCH_ADDR_T(libref->load_addr) >= p->off) { if (likely(ip - ARCH_ADDR_T(libref->load_addr) >= p->off)) {
unsigned int i; unsigned int i;
unsigned char *addr = libref->image_addr + ip - p->off - libref->load_addr; unsigned char *addr = libref->image_addr + ip - p->off - libref->load_addr;
for(i = 0; i < call_op[i].len; ++i) { for(i = 0; i < call_op[i].len; ++i) {
if ((addr[i] & p->mask[i]) != p->op[i]) if (unlikely((addr[i] & p->mask[i]) != p->op[i]))
break; break;
} }
if (i == p->len) if (unlikely(i == p->len))
return 1; return 1;
} }
} }

86
task.c
View File

@ -48,7 +48,7 @@
static LIST_HEAD(list_of_leaders); static LIST_HEAD(list_of_leaders);
static struct rb_root pid_tree = RB_ROOT; struct pid_hash *pid_hash[PID_HASH_SIZE];
#ifndef OS_HAVE_PROCESS_DATA #ifndef OS_HAVE_PROCESS_DATA
static inline int os_task_init(struct task *task) static inline int os_task_init(struct task *task)
@ -82,45 +82,42 @@ static inline int arch_task_clone(struct task *retp, struct task *task)
} }
#endif #endif
struct task *pid2task(pid_t pid) static inline void delete_pid(struct task *task)
{ {
struct rb_node **new = &(pid_tree.rb_node); struct pid_hash *entry = pid_hash[PID_HASH(task->pid)];
unsigned int i;
/* Figure out where to put new node */ for(i = 0; i < entry->num; ++i) {
while (*new) { struct task **p = &entry->tasks[i];
struct task *this = container_of(*new, struct task, pid_node);
if (this->pid == pid) if ((*p)->pid == task->pid) {
return this; entry->num--;
memmove(p, p + 1, (entry->num - i) * sizeof(entry->tasks[0]));
if (this->pid < pid) break;
new = &((*new)->rb_left); }
else }
new = &((*new)->rb_right);
} }
return NULL; static inline void insert_pid(struct task *task)
}
static void insert_pid(struct task *task)
{ {
struct rb_node **new = &(pid_tree.rb_node), *parent = NULL; struct pid_hash *entry = pid_hash[PID_HASH(task->pid)];
/* Figure out where to put new node */ if (!entry->size) {
while (*new) { entry = malloc(sizeof(*entry) + 8 * sizeof(entry->tasks[0]));
struct task *this = container_of(*new, struct task, pid_node); entry->num = 0;
entry->size = 8;
parent = *new; pid_hash[PID_HASH(task->pid)] = entry;
}
if (this->pid < task->pid)
new = &((*new)->rb_left);
else else
new = &((*new)->rb_right); if (entry->size == entry->num) {
entry->size += 8;
entry = realloc(entry, sizeof(*entry) + entry->size * sizeof(entry->tasks[0]));
pid_hash[PID_HASH(task->pid)] = entry;
} }
/* Add new node and rebalance tree. */ entry->tasks[entry->num++] = task;
rb_link_node(&task->pid_node, parent, new);
rb_insert_color(&task->pid_node, &pid_tree);
} }
static int leader_setup(struct task *leader) static int leader_setup(struct task *leader)
@ -214,7 +211,7 @@ static void task_destroy(struct task *task)
arch_task_destroy(task); arch_task_destroy(task);
os_task_destroy(task); os_task_destroy(task);
detach_task(task); detach_task(task);
rb_erase(&task->pid_node, &pid_tree); delete_pid(task);
if (leader != task) { if (leader != task) {
list_del(&task->task_list); list_del(&task->task_list);
@ -516,7 +513,7 @@ void open_pid(pid_t pid)
task->is_64bit = leader->is_64bit; task->is_64bit = leader->is_64bit;
}; };
if (options.verbose) if (unlikely(options.verbose))
each_task(leader, &show_attached, NULL); each_task(leader, &show_attached, NULL);
return; return;
@ -575,9 +572,30 @@ int task_list_empty(void)
void each_pid(void (*cb)(struct task *task)) void each_pid(void (*cb)(struct task *task))
{ {
struct task *task, *next; unsigned int i;
rbtree_postorder_for_each_entry_safe(task, next, &pid_tree, pid_node) for(i = 0; i < ARRAY_SIZE(pid_hash); ++i) {
(*cb)(task); struct pid_hash *entry = pid_hash[i];
unsigned int n = entry->num;
if (n) {
struct task **p = alloca(n * sizeof(*p));
memcpy(p, entry->tasks, n * sizeof(*p));
do {
(*cb)(*p++);
} while(--n);
}
}
}
void init_pid_hash(void)
{
static const struct pid_hash preset = { .size = 0, .num = 0 };
unsigned int i;
for(i = 0; i < ARRAY_SIZE(pid_hash); ++i)
pid_hash[i] = (void *)&preset;
} }

81
task.h
View File

@ -25,6 +25,7 @@
#include "config.h" #include "config.h"
#include <time.h>
#include <sys/time.h> #include <sys/time.h>
#include "forward.h" #include "forward.h"
@ -38,36 +39,22 @@
#include "report.h" #include "report.h"
struct task { struct task {
/* red/black tree node for fast pid -> struct task */
struct rb_node pid_node;
/* process id */
pid_t pid;
/* points to the leader thread of the POSIX.1 task */
struct task *leader;
/* current pendig event */ /* current pendig event */
struct event event; struct event event;
unsigned int stopped:1;
unsigned int traced:1;
unsigned int was_stopped:1;
unsigned int is_64bit:1; unsigned int is_64bit:1;
unsigned int traced:1;
unsigned int attached:1; unsigned int attached:1;
unsigned int deleted:1; unsigned int deleted:1;
unsigned int about_exit:1; unsigned int about_exit:1;
unsigned int was_stopped:1;
unsigned int stopped:1;
struct breakpoint *breakpoint; struct breakpoint *breakpoint;
struct library_symbol *libsym; struct library_symbol *libsym;
struct context context; /* process context (registers, stack) */ struct context context; /* process context (registers, stack) */
struct context saved_context; /* context for fetch_param() */ struct context saved_context; /* context for fetch_param() */
/* os specific task data */
#ifdef OS_HAVE_PROCESS_DATA
struct os_task_data os;
#endif
/* arch specific task data */ /* arch specific task data */
#ifdef TASK_HAVE_PROCESS_DATA #ifdef TASK_HAVE_PROCESS_DATA
struct arch_task_data arch; struct arch_task_data arch;
@ -76,12 +63,20 @@ struct task {
/* pointer to a breakpoint which was interrupt by a signal during skip */ /* pointer to a breakpoint which was interrupt by a signal during skip */
struct breakpoint *skip_bp; struct breakpoint *skip_bp;
#if HW_BREAKPOINTS > 0
/* array of active hw breakpoints */
struct breakpoint *hw_bp[HW_BREAKPOINTS];
#endif
/* process id */
pid_t pid;
/* points to the leader thread */
struct task *leader;
/* set in leader: number of stopped threads including the leader */ /* set in leader: number of stopped threads including the leader */
unsigned int threads_stopped; unsigned int threads_stopped;
unsigned long num_hw_bp;
unsigned long num_sw_bp;
/* set in leader: dictionary of breakpoints */ /* set in leader: dictionary of breakpoints */
struct dict *breakpoints; struct dict *breakpoints;
@ -91,6 +86,9 @@ struct task {
/* linked list of libraries, the first entry is the executable itself */ /* linked list of libraries, the first entry is the executable itself */
struct list_head libraries_list; struct list_head libraries_list;
/* red black tree of libraries */
struct rb_root libraries_tree;
/* Thread chaining to leader */ /* Thread chaining to leader */
struct list_head task_list; struct list_head task_list;
@ -100,6 +98,9 @@ struct task {
/* struct task chaining. */ /* struct task chaining. */
struct list_head leader_list; struct list_head leader_list;
/* halt time for debugging purpose */
struct timespec halt_time;
#if HW_BREAKPOINTS > 1 #if HW_BREAKPOINTS > 1
/* set in leader: list of hw breakpoints */ /* set in leader: list of hw breakpoints */
struct list_head hw_bp_list; struct list_head hw_bp_list;
@ -108,9 +109,9 @@ struct task {
unsigned long hw_bp_num; unsigned long hw_bp_num;
#endif #endif
#if HW_BREAKPOINTS > 0 /* os specific task data */
/* array of active hw breakpoints */ #ifdef OS_HAVE_PROCESS_DATA
struct breakpoint *hw_bp[HW_BREAKPOINTS]; struct os_task_data os;
#endif #endif
}; };
@ -122,8 +123,6 @@ struct task *task_create(const char *command, char **argv);
void open_pid(pid_t pid); void open_pid(pid_t pid);
struct task *pid2task(pid_t pid);
/* Clone the contents of a task */ /* Clone the contents of a task */
int task_clone(struct task *task, struct task *newtask); int task_clone(struct task *task, struct task *newtask);
@ -157,5 +156,37 @@ static inline int task_is_64bit(struct task *task)
return task->is_64bit; return task->is_64bit;
} }
struct pid_hash {
unsigned int num;
unsigned int size;
struct task * tasks[0];
};
#define PID_HASH(pid) ((pid) % ARRAY_SIZE(pid_hash))
#define PID_HASH_SIZE 256
extern struct pid_hash *pid_hash[PID_HASH_SIZE];
void init_pid_hash(void);
static inline struct task *pid2task(pid_t pid)
{
struct pid_hash *entry = pid_hash[PID_HASH(pid)];
struct task **p = entry->tasks;
unsigned int n = entry->num;
while(n) {
struct task *task = *p;
if (likely(task->pid == pid))
return task;
p++;
n--;
}
return NULL;
}
#endif #endif

62
timer.h Normal file
View File

@ -0,0 +1,62 @@
/*
* This file is part of mtrace-ng.
* Copyright (C) 2015 Stefani Seibold <stefani@seibold.net>
*
* This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich/Germany.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifndef _INC_TIMER_H
#define _INC_TIMER_H
#include <time.h>
#include <sys/time.h>
struct mt_timer {
unsigned int max;
unsigned int count;
unsigned long long culminate;
};
static inline int start_time(struct timespec *ts)
{
return clock_gettime(CLOCK_THREAD_CPUTIME_ID, ts);
}
static inline int set_timer(struct timespec *start, struct mt_timer *p)
{
struct timespec now;
unsigned int usec;
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now) == -1)
return -1;
usec = (now.tv_sec - start->tv_sec) * 1000000L +
(now.tv_nsec - start->tv_nsec + 500L) / 1000;
if (p->max < usec)
p->max = usec;
p->culminate += usec;
++p->count;
return 0;
}
#endif

17
trace.c
View File

@ -40,6 +40,7 @@
#include "report.h" #include "report.h"
#include "task.h" #include "task.h"
#include "library.h" #include "library.h"
#include "main.h"
int skip_breakpoint(struct task *task, struct breakpoint *bp) int skip_breakpoint(struct task *task, struct breakpoint *bp)
{ {
@ -50,12 +51,20 @@ int skip_breakpoint(struct task *task, struct breakpoint *bp)
if (bp->enabled && !bp->hw) { if (bp->enabled && !bp->hw) {
int ret = 0; int ret = 0;
struct timespec start;
if (unlikely(options.verbose > 1))
start_time(&start);
breakpoint_disable(task, bp); breakpoint_disable(task, bp);
ret = do_singlestep(task); ret = do_singlestep(task);
breakpoint_enable(task, bp); breakpoint_enable(task, bp);
if (ret) {
if (ret == 1) { if (unlikely(options.verbose > 1))
set_timer(&start, &skip_bp_time);
if (unlikely(ret)) {
if (unlikely(ret == 1)) {
breakpoint_put(task->skip_bp); breakpoint_put(task->skip_bp);
task->skip_bp = breakpoint_get(bp); task->skip_bp = breakpoint_get(bp);
} }
@ -105,8 +114,8 @@ void detach_proc(struct task *leader)
breakpoint_disable_all(leader); breakpoint_disable_all(leader);
if (options.verbose > 1) if (unlikely(options.verbose > 1))
fprintf(stderr, "+++ process detach pid=%d sw-bp:%lu hw-bp:%lu +++\n", leader->pid, leader->num_sw_bp, leader->num_hw_bp); fprintf(stderr, "+++ process detach pid=%d +++\n", leader->pid);
each_task(leader, &detach_cb, NULL); each_task(leader, &detach_cb, NULL);
} }