|
From: Luca B. <lu...@ge...> - 2013-01-02 02:38:40
|
The first attempt got bounced because the subscription process didn't get to its end... I started to keeping freya[1] in sync with the main tree (and keep a git mirror on my github[2]) The two essential patches follow, I already renamed configure.in to configure.ac in my tree because of the deprecation warning from autotools. [1] http://webkit.sed.hu/node/29 [2] https://github.com/lu-zero/valgrind/tree/freya |
|
From: Luca B. <lu...@ge...> - 2013-01-02 02:38:41
|
Whitespace cleanup
---
configure.ac | 116 +++++++++++++++++++++++++++++------------------------------
1 file changed, 58 insertions(+), 58 deletions(-)
diff --git a/configure.ac b/configure.ac
index e0fb12d..c590c6a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
##------------------------------------------------------------##
-#
+#
# The multiple-architecture stuff in this file is pretty
# cryptic. Read docs/internals/multiple-architectures.txt
# for at least a partial explanation of what is going on.
@@ -99,7 +99,7 @@ rm $tmpfile
AC_MSG_CHECKING([for a supported version of gcc])
# Obtain the compiler version.
-#
+#
# A few examples of how the ${CC} --version output looks like:
#
# Arch Linux: i686-pc-linux-gnu-gcc (GCC) 4.6.2
@@ -160,12 +160,12 @@ AC_MSG_CHECKING([for a supported CPU])
# Ditto for amd64. It is used for more configuration below, but is not used
# outside this file.
case "${host_cpu}" in
- i?86)
+ i?86)
AC_MSG_RESULT([ok (${host_cpu})])
ARCH_MAX="x86"
;;
- x86_64)
+ x86_64)
AC_MSG_RESULT([ok (${host_cpu})])
ARCH_MAX="amd64"
;;
@@ -206,7 +206,7 @@ case "${host_cpu}" in
ARCH_MAX="mips32"
;;
- *)
+ *)
AC_MSG_RESULT([no (${host_cpu})])
AC_MSG_ERROR([Unsupported host architecture. Sorry])
;;
@@ -224,14 +224,14 @@ esac
# Check if a 64-bit only build has been requested
AC_CACHE_CHECK([for a 64-bit only build], vg_cv_only64bit,
- [AC_ARG_ENABLE(only64bit,
+ [AC_ARG_ENABLE(only64bit,
[ --enable-only64bit do a 64-bit only build],
[vg_cv_only64bit=$enableval],
[vg_cv_only64bit=no])])
# Check if a 32-bit only build has been requested
AC_CACHE_CHECK([for a 32-bit only build], vg_cv_only32bit,
- [AC_ARG_ENABLE(only32bit,
+ [AC_ARG_ENABLE(only32bit,
[ --enable-only32bit do a 32-bit only build],
[vg_cv_only32bit=$enableval],
[vg_cv_only32bit=no])])
@@ -263,17 +263,17 @@ case "${host_os}" in
kernel=`uname -r`
case "${kernel}" in
- 2.6.*|3.*)
+ 2.6.*|3.*)
AC_MSG_RESULT([2.6.x/3.x family (${kernel})])
AC_DEFINE([KERNEL_2_6], 1, [Define to 1 if you're using Linux 2.6.x or Linux 3.x])
;;
- 2.4.*)
+ 2.4.*)
AC_MSG_RESULT([2.4 family (${kernel})])
AC_DEFINE([KERNEL_2_4], 1, [Define to 1 if you're using Linux 2.4.x])
;;
- *)
+ *)
AC_MSG_RESULT([unsupported (${kernel})])
AC_MSG_ERROR([Valgrind works on kernels 2.4, 2.6])
;;
@@ -296,7 +296,7 @@ case "${host_os}" in
# has only one relevant version, the OS version. The `uname` check
# is a good way to get that version (i.e. "Darwin 9.6.0" is Mac OS
# X 10.5.6, and "Darwin 10.x" is Mac OS X 10.6.x Snow Leopard,
- # and possibly "Darwin 11.x" is Mac OS X 10.7.x Lion),
+ # and possibly "Darwin 11.x" is Mac OS X 10.7.x Lion),
# and we don't know of an macros similar to __GLIBC__ to get that info.
#
# XXX: `uname -r` won't do the right thing for cross-compiles, but
@@ -333,14 +333,14 @@ case "${host_os}" in
DEFAULT_SUPP="darwin12.supp ${DEFAULT_SUPP}"
DEFAULT_SUPP="darwin10-drd.supp ${DEFAULT_SUPP}"
;;
- *)
+ *)
AC_MSG_RESULT([unsupported (${kernel})])
AC_MSG_ERROR([Valgrind works on Darwin 10.x and 11.x (Mac OS X 10.6/7)])
;;
esac
;;
- *)
+ *)
AC_MSG_RESULT([no (${host_os})])
AC_MSG_ERROR([Valgrind is operating system specific. Sorry.])
;;
@@ -412,7 +412,7 @@ AC_SUBST(VGCONF_PLATFORM_SEC_CAPS)
AC_MSG_CHECKING([for a supported CPU/OS combination])
-# NB. The load address for a given platform may be specified in more
+# NB. The load address for a given platform may be specified in more
# than one place, in some cases, depending on whether we're doing a biarch,
# 32-bit only or 64-bit only build. eg see case for amd64-linux below.
# Be careful to give consistent values in all subcases. Also, all four
@@ -536,7 +536,7 @@ case "$ARCH_MAX-$VGCONF_OS" in
fi
AC_MSG_RESULT([ok (${ARCH_MAX}-${VGCONF_OS})])
;;
- arm-linux)
+ arm-linux)
VGCONF_ARCH_PRI="arm"
VGCONF_PLATFORM_PRI_CAPS="ARM_LINUX"
VGCONF_PLATFORM_SEC_CAPS=""
@@ -558,7 +558,7 @@ case "$ARCH_MAX-$VGCONF_OS" in
valt_load_address_sec_inner="0xUNSET"
AC_MSG_RESULT([ok (${ARCH_MAX}-${VGCONF_OS})])
;;
- mips32-linux)
+ mips32-linux)
VGCONF_ARCH_PRI="mips32"
VGCONF_PLATFORM_PRI_CAPS="MIPS32_LINUX"
VGCONF_PLATFORM_SEC_CAPS=""
@@ -587,20 +587,20 @@ esac
# Set up VGCONF_ARCHS_INCLUDE_<arch>. Either one or two of these become
# defined.
-AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_X86,
+AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_X86,
test x$VGCONF_PLATFORM_PRI_CAPS = xX86_LINUX \
-o x$VGCONF_PLATFORM_SEC_CAPS = xX86_LINUX \
-o x$VGCONF_PLATFORM_PRI_CAPS = xX86_DARWIN \
-o x$VGCONF_PLATFORM_SEC_CAPS = xX86_DARWIN )
-AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_AMD64,
+AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_AMD64,
test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_LINUX \
-o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_DARWIN )
-AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_PPC32,
- test x$VGCONF_PLATFORM_PRI_CAPS = xPPC32_LINUX \
+AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_PPC32,
+ test x$VGCONF_PLATFORM_PRI_CAPS = xPPC32_LINUX \
-o x$VGCONF_PLATFORM_SEC_CAPS = xPPC32_LINUX )
-AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_PPC64,
+AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_PPC64,
test x$VGCONF_PLATFORM_PRI_CAPS = xPPC64_LINUX )
-AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_ARM,
+AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_ARM,
test x$VGCONF_PLATFORM_PRI_CAPS = xARM_LINUX )
AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_S390X,
test x$VGCONF_PLATFORM_PRI_CAPS = xS390X_LINUX )
@@ -609,17 +609,17 @@ AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_MIPS32,
# Set up VGCONF_PLATFORMS_INCLUDE_<platform>. Either one or two of these
# become defined.
-AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_X86_LINUX,
+AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_X86_LINUX,
test x$VGCONF_PLATFORM_PRI_CAPS = xX86_LINUX \
-o x$VGCONF_PLATFORM_SEC_CAPS = xX86_LINUX)
-AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_AMD64_LINUX,
+AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_AMD64_LINUX,
test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_LINUX)
-AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_PPC32_LINUX,
- test x$VGCONF_PLATFORM_PRI_CAPS = xPPC32_LINUX \
+AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_PPC32_LINUX,
+ test x$VGCONF_PLATFORM_PRI_CAPS = xPPC32_LINUX \
-o x$VGCONF_PLATFORM_SEC_CAPS = xPPC32_LINUX)
-AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_PPC64_LINUX,
+AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_PPC64_LINUX,
test x$VGCONF_PLATFORM_PRI_CAPS = xPPC64_LINUX)
-AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_ARM_LINUX,
+AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_ARM_LINUX,
test x$VGCONF_PLATFORM_PRI_CAPS = xARM_LINUX)
AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_S390X_LINUX,
test x$VGCONF_PLATFORM_PRI_CAPS = xS390X_LINUX \
@@ -627,15 +627,15 @@ AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_S390X_LINUX,
AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_MIPS32_LINUX,
test x$VGCONF_PLATFORM_PRI_CAPS = xMIPS32_LINUX)
-AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_X86_DARWIN,
+AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_X86_DARWIN,
test x$VGCONF_PLATFORM_PRI_CAPS = xX86_DARWIN \
-o x$VGCONF_PLATFORM_SEC_CAPS = xX86_DARWIN)
-AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN,
+AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN,
test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_DARWIN)
# Similarly, set up VGCONF_OS_IS_<os>. Exactly one of these becomes defined.
-# Relies on the assumption that the primary and secondary targets are
+# Relies on the assumption that the primary and secondary targets are
# for the same OS, so therefore only necessary to test the primary.
AM_CONDITIONAL(VGCONF_OS_IS_LINUX,
test x$VGCONF_PLATFORM_PRI_CAPS = xX86_LINUX \
@@ -678,7 +678,7 @@ fi[]dnl
AC_SUBST(VALT_LOAD_ADDRESS_PRI)
AC_SUBST(VALT_LOAD_ADDRESS_SEC)
AC_CACHE_CHECK([for use as an inner Valgrind], vg_cv_inner,
- [AC_ARG_ENABLE(inner,
+ [AC_ARG_ENABLE(inner,
[ --enable-inner enables self-hosting],
[vg_cv_inner=$enableval],
[vg_cv_inner=no])])
@@ -700,7 +700,7 @@ AC_ARG_WITH(pagesize,
[psize=$withval],
[psize=0]
)
-
+
if test "$psize" = "0"; then
psizer=`getconf PAGESIZE`
let "psize=${psizer}/1024"
@@ -731,7 +731,7 @@ mod=`expr $align % 1024`
let "psz=psize*1024*2"
if test "$align" = "-1"; then
- AC_DEFINE([SHM_ALIGNMENT], 2*(1UL << MIPS_PAGE_SHIFT),
+ AC_DEFINE([SHM_ALIGNMENT], 2*(1UL << MIPS_PAGE_SHIFT),
[configured memory alignment 2*PAGE_SIZE])
AC_MSG_RESULT([checking for shared memory alignment... 2*PAGE_SIZE])
elif test "$mod" = "0"; then
@@ -739,9 +739,9 @@ elif test "$mod" = "0"; then
then
AC_MSG_ERROR([Alignment must be >= PAGE_SIZE])
else
- AC_DEFINE_UNQUOTED([SHM_ALIGNMENT], ${align},
+ AC_DEFINE_UNQUOTED([SHM_ALIGNMENT], ${align},
[configured memory alignment 2*PAGE_SIZE])
- AC_MSG_RESULT([checking for shared memory alignment... ${align}])
+ AC_MSG_RESULT([checking for shared memory alignment... ${align}])
fi
else
AC_MSG_ERROR([Alignment % 1024 must be zero])
@@ -1154,7 +1154,7 @@ AC_MSG_RESULT([no])
AC_CHECK_MEMBER([pthread_mutex_t.__m_kind],
[AC_DEFINE([HAVE_PTHREAD_MUTEX_T__M_KIND],
- 1,
+ 1,
[Define to 1 if pthread_mutex_t has a member called __m_kind.])
],
[],
@@ -1202,7 +1202,7 @@ AM_CONDITIONAL([HAS_ALTIVEC], [test x$ac_have_altivec = xyes])
# understands VSX instructions. If either of those doesn't work,
# conclude that we can't do VSX. NOTE: basically this is a kludge
# in that it conflates two things that should be separate -- whether
-# the compiler understands the flag vs whether the assembler
+# the compiler understands the flag vs whether the assembler
# understands the opcodes. This really ought to be cleaned up
# and done properly, like it is for x86/x86_64.
@@ -1719,8 +1719,8 @@ CFLAGS=$safe_CFLAGS
AC_MSG_CHECKING([if x86/amd64 assembler speaks SSE3])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
- do { long long int x;
- __asm__ __volatile__("fisttpq (%0)" : :"r"(&x) ); }
+ do { long long int x;
+ __asm__ __volatile__("fisttpq (%0)" : :"r"(&x) ); }
while (0)
]])], [
ac_have_as_sse3=yes
@@ -1741,7 +1741,7 @@ AC_MSG_CHECKING([if x86/amd64 assembler speaks SSSE3])
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -msse"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
- do { long long int x;
+ do { long long int x;
__asm__ __volatile__(
"pabsb (%0),%%xmm7" : : "r"(&x) : "xmm7" ); }
while (0)
@@ -1808,7 +1808,7 @@ AM_CONDITIONAL(BUILD_VPCLMULQDQ_TESTS, test x$ac_have_as_vpclmulqdq = xyes)
AC_MSG_CHECKING([if x86/amd64 assembler supports 'lzcnt'])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
- do {
+ do {
__asm__ __volatile__("lzcnt %%rax,%%rax" : : : "rax");
} while (0)
]])], [
@@ -1828,11 +1828,11 @@ AM_CONDITIONAL([BUILD_LZCNT_TESTS], [test x$ac_have_as_lzcnt = xyes])
AC_MSG_CHECKING([if x86/amd64 assembler speaks SSE4.2])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
- do { long long int x;
+ do { long long int x;
__asm__ __volatile__(
"crc32q %%r15,%%r15" : : : "r15" );
__asm__ __volatile__(
- "pblendvb (%%rcx), %%xmm11" : : : "memory", "xmm11");
+ "pblendvb (%%rcx), %%xmm11" : : : "memory", "xmm11");
__asm__ __volatile__(
"aesdec %%xmm2, %%xmm1" : : : "xmm2", "xmm1"); }
while (0)
@@ -1853,7 +1853,7 @@ AM_CONDITIONAL(BUILD_SSE42_TESTS, test x$ac_have_as_sse42 = xyes)
AC_MSG_CHECKING([if x86/amd64 assembler speaks AVX])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
- do { long long int x;
+ do { long long int x;
__asm__ __volatile__(
"vmovupd (%%rsp), %%ymm7" : : : "xmm7" );
__asm__ __volatile__(
@@ -1876,7 +1876,7 @@ AM_CONDITIONAL(BUILD_AVX_TESTS, test x$ac_have_as_avx = xyes)
AC_MSG_CHECKING([if x86/amd64 assembler knows the MOVBE insn])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
- do { long long int x;
+ do { long long int x;
__asm__ __volatile__(
"movbe (%%rsp), %%r15" : : : "memory", "r15" ); }
while (0)
@@ -2063,7 +2063,7 @@ fi
#----------------------------------------------------------------------------
# Do we have a useable MPI setup on the primary and/or secondary targets?
# On Linux, by default, assumes mpicc and -m32/-m64
-# Note: this is a kludge in that it assumes the specified mpicc
+# Note: this is a kludge in that it assumes the specified mpicc
# understands -m32/-m64 regardless of what is specified using
# --with-mpicc=.
MPI_CC="mpicc"
@@ -2132,7 +2132,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
int r = MPI_Init(NULL,NULL);
r |= MPI_Type_get_envelope( MPI_INT, &ni, &na, &nd, &comb );
r |= MPI_Finalize();
- return r;
+ return r;
]])], [
ac_have_mpi2_pri=yes
AC_MSG_RESULT([yes, $MPI_CC])
@@ -2169,7 +2169,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
int r = MPI_Init(NULL,NULL);
r |= MPI_Type_get_envelope( MPI_INT, &ni, &na, &nd, &comb );
r |= MPI_Finalize();
- return r;
+ return r;
]])], [
ac_have_mpi2_sec=yes
AC_MSG_RESULT([yes, $MPI_CC])
@@ -2195,7 +2195,7 @@ AM_CONDITIONAL(BUILD_MPIWRAP_SEC, test x$ac_have_mpi2_sec = xyes)
# in a situation (eg) where, on amd64-linux, the test for Boost checks
# for usable 64-bit Boost facilities, but because we are doing a 32-bit
# only build (meaning, the primary target is x86-linux), the build
-# of the regtest programs that use Boost fails, because they are
+# of the regtest programs that use Boost fails, because they are
# build as 32-bit (IN THIS EXAMPLE).
#
# Hence: ALWAYS USE $mflag_primary FOR CONFIGURE TESTS FOR FACILITIES
@@ -2249,7 +2249,7 @@ safe_CFLAGS=$CFLAGS
CFLAGS="-fopenmp $mflag_primary"
AC_LINK_IFELSE([AC_LANG_SOURCE([
-#include <omp.h>
+#include <omp.h>
int main(int argc, char** argv)
{
omp_set_dynamic(0);
@@ -2467,21 +2467,21 @@ AM_CONDITIONAL([HAVE_SHARED_POINTER_ANNOTATION],
# Nb: VEX/Makefile is generated from Makefile.vex.in.
AC_CONFIG_FILES([
- Makefile
+ Makefile
VEX/Makefile:Makefile.vex.in
valgrind.spec
valgrind.pc
glibc-2.X.supp
- docs/Makefile
- tests/Makefile
- tests/vg_regtest
- perf/Makefile
+ docs/Makefile
+ tests/Makefile
+ tests/vg_regtest
+ perf/Makefile
perf/vg_perf
gdbserver_tests/Makefile
- include/Makefile
+ include/Makefile
auxprogs/Makefile
mpi/Makefile
- coregrind/Makefile
+ coregrind/Makefile
memcheck/Makefile
memcheck/tests/Makefile
memcheck/tests/amd64/Makefile
--
1.8.0.2
|
|
From: Luca B. <lu...@ge...> - 2013-01-02 02:38:48
|
From: Horvath Zoltan <zo...@we...>
---
configure.ac | 2 +
freya/Makefile.am | 90 +++
freya/fr_main.c | 1412 +++++++++++++++++++++++++++++++++++++++++++++++
freya/tests/Makefile.am | 0
4 files changed, 1504 insertions(+)
create mode 100644 freya/Makefile.am
create mode 100644 freya/fr_main.c
create mode 100644 freya/tests/Makefile.am
diff --git a/configure.ac b/configure.ac
index c590c6a..4ed3a7c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2482,6 +2482,8 @@ AC_CONFIG_FILES([
auxprogs/Makefile
mpi/Makefile
coregrind/Makefile
+ freya/Makefile
+ freya/tests/Makefile
memcheck/Makefile
memcheck/tests/Makefile
memcheck/tests/amd64/Makefile
diff --git a/freya/Makefile.am b/freya/Makefile.am
new file mode 100644
index 0000000..111d816
--- /dev/null
+++ b/freya/Makefile.am
@@ -0,0 +1,90 @@
+include $(top_srcdir)/Makefile.tool.am
+
+#----------------------------------------------------------------------------
+# freya-<platform>
+#----------------------------------------------------------------------------
+
+noinst_PROGRAMS = freya-@VGCONF_ARCH_PRI@-@VGCONF_OS@
+if VGCONF_HAVE_PLATFORM_SEC
+noinst_PROGRAMS += freya-@VGCONF_ARCH_SEC@-@VGCONF_OS@
+endif
+
+FREYA_SOURCES_COMMON = fr_main.c
+
+freya_@VGCONF_ARCH_PRI@_@VGCONF_OS@_SOURCES = \
+ $(FREYA_SOURCES_COMMON)
+freya_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CPPFLAGS = \
+ $(AM_CPPFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
+freya_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CFLAGS = \
+ $(AM_CFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
+freya_@VGCONF_ARCH_PRI@_@VGCONF_OS@_DEPENDENCIES = \
+ $(TOOL_DEPENDENCIES_@VGCONF_PLATFORM_PRI_CAPS@)
+freya_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDADD = \
+ $(TOOL_LDADD_@VGCONF_PLATFORM_PRI_CAPS@)
+freya_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDFLAGS = \
+ $(TOOL_LDFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
+freya_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LINK = \
+ $(top_builddir)/coregrind/link_tool_exe_@VGCONF_OS@ \
+ @VALT_LOAD_ADDRESS_PRI@ \
+ $(LINK) \
+ $(freya_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CFLAGS) \
+ $(freya_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDFLAGS)
+
+if VGCONF_HAVE_PLATFORM_SEC
+freya_@VGCONF_ARCH_SEC@_@VGCONF_OS@_SOURCES = \
+ $(FREYA_SOURCES_COMMON)
+freya_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CPPFLAGS = \
+ $(AM_CPPFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
+freya_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CFLAGS = \
+ $(AM_CFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
+freya_@VGCONF_ARCH_SEC@_@VGCONF_OS@_DEPENDENCIES = \
+ $(TOOL_DEPENDENCIES_@VGCONF_PLATFORM_SEC_CAPS@)
+freya_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LDADD = \
+ $(TOOL_LDADD_@VGCONF_PLATFORM_SEC_CAPS@)
+freya_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LDFLAGS = \
+ $(TOOL_LDFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
+freya_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LINK = \
+ $(top_builddir)/coregrind/link_tool_exe_@VGCONF_OS@ \
+ @VALT_LOAD_ADDRESS_SEC@ \
+ $(LINK) \
+ $(freya_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CFLAGS) \
+ $(freya_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LDFLAGS)
+endif
+
+#----------------------------------------------------------------------------
+# vgpreload_freya-<platform>.so
+#----------------------------------------------------------------------------
+
+noinst_PROGRAMS += vgpreload_freya-@VGCONF_ARCH_PRI@-@VGCONF_OS@.so
+if VGCONF_HAVE_PLATFORM_SEC
+noinst_PROGRAMS += vgpreload_freya-@VGCONF_ARCH_SEC@-@VGCONF_OS@.so
+endif
+
+if VGCONF_OS_IS_DARWIN
+noinst_DSYMS = $(noinst_PROGRAMS)
+endif
+
+vgpreload_freya_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_SOURCES =
+vgpreload_freya_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_CPPFLAGS = \
+ $(AM_CPPFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
+vgpreload_freya_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_CFLAGS = \
+ $(AM_CFLAGS_@VGCONF_PLATFORM_PRI_CAPS@) $(AM_CFLAGS_PIC)
+vgpreload_freya_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_DEPENDENCIES = \
+ $(LIBREPLACEMALLOC_@VGCONF_PLATFORM_PRI_CAPS@)
+vgpreload_freya_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_LDFLAGS = \
+ $(PRELOAD_LDFLAGS_@VGCONF_PLATFORM_PRI_CAPS@) \
+ $(LIBREPLACEMALLOC_LDFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
+
+if VGCONF_HAVE_PLATFORM_SEC
+vgpreload_freya_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_SOURCES =
+vgpreload_freya_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_CPPFLAGS = \
+ $(AM_CPPFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
+vgpreload_freya_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_CFLAGS = \
+ $(AM_CFLAGS_@VGCONF_PLATFORM_SEC_CAPS@) $(AM_CFLAGS_PIC)
+vgpreload_freya_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_DEPENDENCIES = \
+ $(LIBREPLACEMALLOC_@VGCONF_PLATFORM_SEC_CAPS@)
+vgpreload_freya_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_LDFLAGS = \
+ $(PRELOAD_LDFLAGS_@VGCONF_PLATFORM_SEC_CAPS@) \
+ $(LIBREPLACEMALLOC_LDFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
+endif
+
diff --git a/freya/fr_main.c b/freya/fr_main.c
new file mode 100644
index 0000000..367b675
--- /dev/null
+++ b/freya/fr_main.c
@@ -0,0 +1,1412 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Freya: memory access logger tool. fr_main.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2009 Zoltan Herczeg (University of Szeged)
+ zhe...@in...
+
+ 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., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+
+ Help: http://webkit.sed.hu/node/29
+*/
+
+#include "pub_tool_basics.h"
+
+#include "pub_tool_mallocfree.h"
+#include "pub_tool_replacemalloc.h"
+#include "pub_tool_debuginfo.h"
+#include "pub_tool_stacktrace.h"
+
+#include "pub_tool_tooliface.h"
+#include "pub_tool_threadstate.h"
+#include "pub_tool_options.h"
+#include "pub_tool_machine.h"
+#include "pub_tool_hashtable.h"
+
+#include "pub_tool_libcbase.h"
+#include "pub_tool_libcassert.h"
+#include "pub_tool_libcprint.h"
+#include "pub_tool_vki.h"
+#include "pub_tool_libcfile.h"
+
+static Bool clo_fr_verb = False;
+static Char* clo_config = NULL;
+static Bool clo_mmap = True;
+static Bool clo_cross_free = False;
+static Int clo_trace = 10;
+static Int clo_report = 5;
+static Int clo_min = 0;
+
+// ---------------------------------------------------------------
+// Common types
+// ---------------------------------------------------------------
+
+// Contain an item
+typedef
+ struct _Trace_Block {
+ struct _Trace_Block* parent; // Parent block
+ struct _Trace_Block* next; // Next in the list
+ struct _Trace_Block* first; // First child
+
+ struct _Trace_Block* hash_next; // Next item, who has the same ips
+
+ Int allocs; // Number of allocs
+ Long total; // Total allocated memory
+ Int current; // Current memory allocation
+ Int peak; // Peak memory consumption
+
+ Addr ips; // Stack trace instruction
+ Char* name; // Name of a tree node. Valid only if ips == 0
+ }
+ Trace_Block;
+
+typedef
+ struct _Rule_List {
+ struct _Rule_List* next; // Next item
+ Char* name; // Rule name
+ SizeT name_len; // Length of rule name
+
+ Char* func_name; // Function name
+ SizeT func_name_len; // Length of function name
+
+ Char* path; // Path
+ SizeT path_len; // Length of path
+
+ Trace_Block* parent; // Should be used as parent, or NULL for skip
+ Bool is_namespace; // func_name is namespace or not
+ }
+ Rule_List;
+
+// Syntax (regular expression):
+// ^(-|[0-9]+)[FfNnDdGg][Dd]?;[^;]*(;.+)?$
+
+static Rule_List* rule_head = NULL;
+static Trace_Block* default_parent = NULL;
+
+static Char* default_rule = "[total]+\n";
+
+// ---------------------------------------------------------------
+// Sort and print results
+// ---------------------------------------------------------------
+
+#define NAME_BUFFER_SIZE 128
+#define DIR_BUFFER_SIZE 1024
+static Char fnname_buffer[NAME_BUFFER_SIZE];
+static Char dir_buffer[DIR_BUFFER_SIZE + NAME_BUFFER_SIZE + 1];
+
+#define MAX_TRACE 64
+
+// Head of the trace
+static Trace_Block* trace_head = NULL;
+
+static void fr_print_block(Trace_Block* block)
+{
+ UInt linenum;
+ Bool dirname_available = False;
+
+ if (block->ips) {
+ if (VG_(get_fnname)( block->ips, fnname_buffer, NAME_BUFFER_SIZE ))
+ VG_(printf)("%s ", fnname_buffer);
+
+ if (VG_(get_filename_linenum)( block->ips, dir_buffer + DIR_BUFFER_SIZE, NAME_BUFFER_SIZE, dir_buffer, DIR_BUFFER_SIZE, &dirname_available, &linenum)) {
+ if (!dirname_available)
+ VG_(printf)("(%s:%d)\n", dir_buffer + DIR_BUFFER_SIZE, linenum);
+ else
+ VG_(printf)("(%s/%s:%d)\n", dir_buffer, dir_buffer + DIR_BUFFER_SIZE, linenum);
+ return;
+ }
+
+ if (VG_(get_objname)( block->ips, dir_buffer, DIR_BUFFER_SIZE ))
+ VG_(printf)("(%s)\n", dir_buffer);
+ else
+ VG_(printf)("(Unknown file)\n");
+ } else
+ VG_(printf)("Group: %s\n", block->name);
+}
+
+static void fr_print_bytes(Char* name, Long value)
+{
+ VG_(printf)("%s", name);
+ if (value > 1024 * 1024)
+ VG_(printf)("%lld.%lldMb ", value / (1024 * 1024), (value * 10 / (1024 * 1024)) % 10);
+ else if (value > 1024)
+ VG_(printf)("%lld.%lldKb ", value / 1024, (value * 10 / 1024) % 10);
+ else {
+ VG_(printf)("%lldb ", value);
+ return;
+ }
+ VG_(printf)("(%lldb) ", value);
+}
+
+static void fr_sort_and_dump(Trace_Block* block, Int indent)
+{
+ Int i;
+ Trace_Block* from;
+ Trace_Block* from_prev;
+ Trace_Block* max;
+ Trace_Block* max_prev;
+ Trace_Block* it;
+ Trace_Block* it_prev;
+
+ tl_assert((!block->parent && trace_head == block) || (block->parent && block->parent->first == block));
+
+ if (block->parent && block->next == NULL) {
+ // One child, no need to sort
+ if (block->peak < clo_min)
+ return;
+
+ for (i = 0; i < indent; ++i)
+ VG_(printf)(" ");
+ fr_print_block(block);
+
+ if (block->first)
+ fr_sort_and_dump(block->first, indent + 1);
+ return;
+ }
+
+ // Sort by total (min sort)
+ from_prev = NULL;
+ from = block;
+ while (from) {
+ max_prev = NULL;
+ max = from;
+ it_prev = from;
+ it = from->next;
+ while (it) {
+ if (it->peak > max->peak) {
+ max_prev = it_prev;
+ max = it;
+ }
+ it_prev = it;
+ it = it->next;
+ }
+
+ if (max != from) {
+ if (max != from->next) {
+ tl_assert(max_prev != from);
+ it = max->next;
+ max->next = from->next;
+ from->next = it;
+ max_prev->next = from;
+ } else {
+ tl_assert(max_prev == from);
+ from->next = max->next;
+ max->next = from;
+ }
+
+ if (from_prev)
+ from_prev->next = max;
+ else {
+ if (from->parent)
+ from->parent->first = max;
+ else
+ trace_head = max;
+ block = max;
+ }
+ }
+ from_prev = max;
+ from = max->next;
+ }
+
+ while (block) {
+ if (block->peak < clo_min)
+ return;
+
+ for (i = 0; i < indent; ++i)
+ VG_(printf)(" ");
+
+ VG_(printf)("[%d] ", indent);
+ fr_print_bytes("Peak: ", block->peak);
+ VG_(printf)("Allocs: %d ", block->allocs);
+ fr_print_bytes("Total: ", block->total);
+ if (block->current > 0)
+ fr_print_bytes("Leak: ", block->current);
+ VG_(printf)("\n");
+
+ for (i = 0; i < indent; ++i)
+ VG_(printf)(" ");
+ fr_print_block(block);
+
+ if (block->first)
+ fr_sort_and_dump(block->first, indent + 1);
+
+ block = block->next;
+ }
+}
+
+// ---------------------------------------------------------------
+// Stack tracing
+// ---------------------------------------------------------------
+
+// Nb: first two fields must match core's VgHashNode.
+typedef
+ struct _Trace_Hash {
+ struct _Trace_Hash* next;
+ Addr ips; // Stack trace instruction
+ Int skip; // Type of instruction
+ Trace_Block* block; // Head block
+ Trace_Block* parent; // Default parent block
+ }
+ Trace_Hash;
+
+static VgHashTable trace_hash = NULL;
+
+static void check_address(Addr ips, Trace_Hash* hash_entry)
+{
+ UInt linenum;
+ SizeT fnname_len, dir_len;
+ Bool dirname_available = False;
+ Rule_List* rule_ptr;
+ Char* end;
+ Char* current;
+ Int match;
+
+ // Get function name
+ if (VG_(get_fnname)( ips, fnname_buffer, NAME_BUFFER_SIZE )) {
+ fnname_len = VG_(strlen)(fnname_buffer);
+ } else {
+ fnname_buffer[0] = '\0';
+ fnname_len = 0;
+ }
+
+ // Get directory
+ end = dir_buffer;
+ if (VG_(get_filename_linenum)( ips, dir_buffer + DIR_BUFFER_SIZE + 1, NAME_BUFFER_SIZE, dir_buffer, DIR_BUFFER_SIZE, &dirname_available, &linenum)) {
+ // Concat the names
+ if (dirname_available) {
+ end += VG_(strlen)(dir_buffer);
+ *end++ = '/';
+ VG_(strcpy) (end, dir_buffer + DIR_BUFFER_SIZE + 1);
+ } else
+ VG_(strcpy) (dir_buffer, dir_buffer + DIR_BUFFER_SIZE + 1);
+ } else if (!VG_(get_objname)( ips, dir_buffer, DIR_BUFFER_SIZE + NAME_BUFFER_SIZE ))
+ dir_buffer[0] = '\0';
+
+ while (*end)
+ end++;
+
+ // Search for matching rules
+ rule_ptr = rule_head;
+ while (rule_ptr) {
+ match = (rule_ptr->func_name && rule_ptr->path) ? 2 : 1;
+
+ if (rule_ptr->func_name) {
+ if (rule_ptr->func_name_len <= fnname_len && fnname_buffer[0] == rule_ptr->func_name[0]
+ && VG_(memcmp)(fnname_buffer, rule_ptr->func_name, rule_ptr->func_name_len * sizeof(Char)) == 0) {
+
+ if (!rule_ptr->is_namespace) {
+ if (rule_ptr->func_name_len == fnname_len || fnname_buffer[rule_ptr->func_name_len] == ' ' || fnname_buffer[rule_ptr->func_name_len] == '(')
+ --match;
+ } else {
+ if (fnname_buffer[rule_ptr->func_name_len] == ':' && fnname_buffer[rule_ptr->func_name_len + 1] == ':')
+ --match;
+ }
+ }
+ }
+
+ if (rule_ptr->path && match == 1) {
+ current = end;
+ dir_len = 0;
+
+ while (current >= dir_buffer) {
+ current--;
+ dir_len++;
+
+ while (current >= dir_buffer) {
+ if (*current == '/')
+ break;
+ current--;
+ dir_len++;
+ }
+
+ current++;
+ dir_len--;
+
+ if (rule_ptr->path_len <= dir_len && current[0] == rule_ptr->path[0]
+ && VG_(memcmp)(current, rule_ptr->path, rule_ptr->path_len * sizeof(Char)) == 0
+ && (rule_ptr->path_len == dir_len || current[rule_ptr->path_len] == '/')) {
+ match = 0;
+ break;
+ }
+
+ current--;
+ dir_len++;
+ }
+ }
+
+ if (match == 0) {
+ hash_entry->parent = rule_ptr->parent;
+ if (!rule_ptr->parent)
+ hash_entry->skip = 1;
+ else
+ return;
+ }
+ rule_ptr = rule_ptr->next;
+ }
+
+ hash_entry->parent = default_parent;
+}
+
+static Trace_Block* alloc_trace(ThreadId tid)
+{
+ static Addr ips[MAX_TRACE];
+ static Trace_Hash* hash_entries[MAX_TRACE];
+ Addr* ips_ptr;
+ UInt n_ips, n_ips_count;
+ Trace_Hash* hash_entry;
+ Trace_Hash** hash_entry_ptr;
+ Trace_Hash** max_skip;
+ Trace_Block* parent;
+ Trace_Block* block;
+
+ n_ips = VG_(get_StackTrace)(tid, ips, clo_trace, NULL, NULL, 0);
+ tl_assert(n_ips > 0);
+
+ // Get first non-skiped block
+ ips_ptr = ips;
+ hash_entry_ptr = hash_entries;
+ max_skip = NULL;
+ n_ips_count = n_ips;
+ do {
+ hash_entry = VG_(HT_lookup)(trace_hash, *ips_ptr);
+ if (!hash_entry) {
+ hash_entry = VG_(malloc)("freya.alloc_trace.1", sizeof(Trace_Hash));
+ hash_entry->ips = *ips_ptr;
+ hash_entry->skip = 0;
+ hash_entry->block = NULL;
+ hash_entry->parent = NULL;
+ check_address(*ips_ptr, hash_entry);
+ VG_(HT_add_node)(trace_hash, hash_entry);
+ block = NULL;
+ }
+ *hash_entry_ptr++ = hash_entry;
+ if (hash_entry->skip)
+ max_skip = hash_entry_ptr; // Which is one step ahead
+ n_ips_count--;
+ ips_ptr++;
+ } while (n_ips_count > 0);
+
+ ips_ptr = ips;
+ hash_entry_ptr = hash_entries;
+ if (max_skip) {
+ if (max_skip - hash_entries == n_ips)
+ max_skip--; // At least one should always remain
+ n_ips -= max_skip - hash_entries;
+ ips_ptr += max_skip - hash_entries;
+ hash_entry_ptr += max_skip - hash_entries;
+ }
+
+ if (n_ips > clo_report)
+ n_ips = clo_report;
+
+ tl_assert(n_ips > 0);
+
+ // Insert to the chain
+ parent = (*hash_entry_ptr)->parent;
+ do {
+ hash_entry = *hash_entry_ptr++;
+ block = hash_entry->block;
+ while (block) {
+ tl_assert(block->ips == *ips_ptr);
+ if (block->parent == parent)
+ break;
+ block = block->hash_next;
+ }
+
+ if (!block) {
+ block = VG_(malloc)("freya.alloc_trace.2", sizeof(Trace_Block));
+ block->parent = parent;
+ if (parent) {
+ block->next = parent->first;
+ parent->first = block;
+ } else {
+ block->next = trace_head;
+ trace_head = block;
+ }
+ block->first = NULL;
+
+ block->hash_next = hash_entry->block;
+ hash_entry->block = block;
+
+ block->allocs = 0;
+ block->total = 0;
+ block->current = 0;
+ block->peak = 0;
+ block->ips = *ips_ptr;
+ block->name = NULL;
+ }
+
+ parent = block;
+ n_ips--;
+ ips_ptr++;
+ } while (n_ips > 0);
+
+ return block;
+}
+
+// ---------------------------------------------------------------
+// Tracking alloc operations
+// ---------------------------------------------------------------
+
+// Metadata for heap blocks.
+//
+// Nb: first two fields must match core's VgHashNode.
+typedef
+ struct _HP_Chunk {
+ struct _HP_Chunk* next;
+ Addr data; // Ptr to actual block
+ SizeT req_szB; // Size requested
+ SizeT slop_szB; // Extra bytes given above those requested
+ Trace_Block* block; // Tail block
+ ThreadId tid;
+ }
+ HP_Chunk;
+
+static VgHashTable malloc_list = NULL; // HP_Chunks
+
+static void* new_block ( ThreadId tid, SizeT req_szB, SizeT req_alignB,
+ Bool is_zeroed )
+{
+ void* p;
+ HP_Chunk* hc;
+ SizeT actual_szB, slop_szB;
+ Trace_Block* block;
+
+ if ((SSizeT)req_szB < 0) return NULL;
+
+ // Allocate and zero if necessary
+ p = VG_(cli_malloc)( req_alignB, req_szB );
+ if (!p) {
+ return NULL;
+ }
+ if (is_zeroed) VG_(memset)(p, 0, req_szB);
+ actual_szB = VG_(malloc_usable_size)(p);
+ tl_assert(actual_szB >= req_szB);
+ slop_szB = actual_szB - req_szB;
+
+ // Make new HP_Chunk node, add to malloc_list
+ hc = VG_(malloc)("freya.malloc", sizeof(HP_Chunk));
+ hc->data = (Addr)p;
+ hc->req_szB = req_szB;
+ hc->slop_szB = slop_szB;
+ block = alloc_trace(tid);
+ hc->block = block;
+ hc->tid = tid;
+
+ while (block) {
+ block->allocs ++;
+ block->total += req_szB;
+ block->current += req_szB;
+ if (block->peak < block->current)
+ block->peak = block->current;
+ block = block->parent;
+ }
+
+ VG_(HT_add_node)(malloc_list, hc);
+ return p;
+}
+
+static void cross_thread_free ( ThreadId tid, Trace_Block* block )
+{
+ static Addr ips[MAX_TRACE];
+ Addr* ips_ptr;
+ int n_ips;
+ UInt linenum;
+ Bool dirname_available = False;
+
+ if (!clo_cross_free)
+ return;
+
+ VG_(printf)("Warning: free or realloc on a different thread!\n=== Original alloc ===\n");
+ while (block) {
+ if (block->ips && VG_(get_filename_linenum)( block->ips, dir_buffer + DIR_BUFFER_SIZE, NAME_BUFFER_SIZE, dir_buffer, DIR_BUFFER_SIZE, &dirname_available, &linenum )) {
+ if (!dirname_available)
+ VG_(printf)("(%s:%d)\n", dir_buffer + DIR_BUFFER_SIZE, linenum);
+ else
+ VG_(printf)("(%s/%s:%d)\n", dir_buffer, dir_buffer + DIR_BUFFER_SIZE, linenum);
+ }
+ block = block->parent;
+ }
+
+ VG_(printf)("=== Current free or realloc ===\n");
+ n_ips = VG_(get_StackTrace)(tid, ips, clo_trace, NULL, NULL, 0);
+ tl_assert(n_ips > 0);
+ if (n_ips > clo_trace)
+ n_ips = clo_trace;
+ ips_ptr = ips;
+
+ while (n_ips > 0) {
+ if (VG_(get_filename_linenum)( *ips_ptr, dir_buffer + DIR_BUFFER_SIZE, NAME_BUFFER_SIZE, dir_buffer, DIR_BUFFER_SIZE, &dirname_available, &linenum )) {
+ if (!dirname_available)
+ VG_(printf)("(%s:%d)\n", dir_buffer + DIR_BUFFER_SIZE, linenum);
+ else
+ VG_(printf)("(%s/%s:%d)\n", dir_buffer, dir_buffer + DIR_BUFFER_SIZE, linenum);
+ }
+ --n_ips;
+ ++ips_ptr;
+ }
+
+ VG_(printf)("=== End ===\n");
+}
+
+static void free_block ( ThreadId tid, void* p )
+{
+ // Remove HP_Chunk from malloc_list
+ HP_Chunk* hc = VG_(HT_remove)(malloc_list, (UWord)p);
+ Trace_Block* block;
+
+ if (NULL == hc) {
+ VG_(printf)("Invalid free: %p\n", p);
+ return; // must have been a bogus free()
+ }
+
+ if (tid != hc->tid)
+ cross_thread_free(tid, hc->block);
+
+ block = hc->block;
+ while (block) {
+ block->current -= hc->req_szB;
+ block = block->parent;
+ }
+
+ // Actually free the chunk, and the heap block (if necessary)
+ VG_(free)( hc );
+ VG_(cli_free)( p );
+}
+
+// Nb: --ignore-fn is tricky for realloc. If the block's original alloc was
+// ignored, but the realloc is not requested to be ignored, and we are
+// shrinking the block, then we have to ignore the realloc -- otherwise we
+// could end up with negative heap sizes. This isn't a danger if we are
+// growing such a block, but for consistency (it also simplifies things) we
+// ignore such reallocs as well.
+static void* renew_block ( ThreadId tid, void* p_old, SizeT new_req_szB )
+{
+ HP_Chunk* hc;
+ void* p_new;
+ SizeT old_req_szB, old_slop_szB, new_slop_szB, new_actual_szB;
+ Trace_Block* block;
+
+ // Remove the old block
+ hc = VG_(HT_remove)(malloc_list, (UWord)p_old);
+ if (hc == NULL) {
+ VG_(printf)("Invalid realloc: %p\n", p_old);
+ return NULL; // must have been a bogus realloc()
+ }
+
+ if (tid != hc->tid)
+ cross_thread_free(tid, hc->block);
+
+ block = hc->block;
+ while (block) {
+ block->current -= hc->req_szB;
+ block->allocs ++;
+ block->total += new_req_szB;
+ block->current += new_req_szB;
+ if (block->peak < block->current)
+ block->peak = block->current;
+ block = block->parent;
+ }
+
+ old_req_szB = hc->req_szB;
+ old_slop_szB = hc->slop_szB;
+
+ // Actually do the allocation, if necessary.
+ if (new_req_szB <= old_req_szB + old_slop_szB) {
+ // New size is smaller or same; block not moved.
+ p_new = p_old;
+ new_slop_szB = old_slop_szB + (old_req_szB - new_req_szB);
+
+ } else {
+ // New size is bigger; make new block, copy shared contents, free old.
+ p_new = VG_(cli_malloc)(VG_(clo_alignment), new_req_szB);
+ if (!p_new) {
+ // Nb: if realloc fails, NULL is returned but the old block is not
+ // touched. What an awful function.
+ return NULL;
+ }
+ VG_(memcpy)(p_new, p_old, old_req_szB);
+ VG_(cli_free)(p_old);
+ new_actual_szB = VG_(malloc_usable_size)(p_new);
+ tl_assert(new_actual_szB >= new_req_szB);
+ new_slop_szB = new_actual_szB - new_req_szB;
+ }
+
+ // Update HP_Chunk.
+ hc->data = (Addr)p_new;
+ hc->req_szB = new_req_szB;
+ hc->slop_szB = new_slop_szB;
+ hc->tid = tid;
+
+ // Now insert the new hc (with a possibly new 'data' field) into
+ // malloc_list.
+ VG_(HT_add_node)(malloc_list, hc);
+ return p_new;
+}
+
+// ---------------------------------------------------------------
+// Tracking mmap operations
+// ---------------------------------------------------------------
+
+typedef
+ struct _Mmap_Section {
+ struct _Mmap_Section* next;
+ Addr page_addr;
+ Trace_Block** trace_blocks;
+ // 0 - do nothing
+ // 1 - update on access
+ Char* used_blocks;
+ }
+ Mmap_Section;
+
+// 4G pages
+
+#define PAGE_SIZE 4096
+#define PAGE_NUMBER 1048576
+
+#if VG_WORDSIZE == 4
+
+#define PAGE_OFFSET_DOWN(a) ((a) >> 12)
+#define PAGE_OFFSET_UP(a) (((a) + 4095) >> 12)
+
+static Mmap_Section mmap_section;
+
+#else
+
+#define PAGE_ADDR(a) ((a) & 0xffffffff00000000ll)
+#define PAGE_OFFSET_DOWN(a) (((a) >> 12) & 0xfffff)
+#define PAGE_OFFSET_UP(a) ((((a) + 4095) >> 12) & 0xfffff)
+
+static Mmap_Section* mmap_sections;
+static Mmap_Section* mmap_section_cache;
+
+#endif
+
+static __inline__ void mark_blocks(Trace_Block **trace_blocks_ptr, Trace_Block **trace_blocks_end, Char* used_blocks_ptr, Trace_Block *block_arg)
+{
+ Trace_Block *head_block = *trace_blocks_ptr;
+ SizeT touched = 0;
+
+ if (block_arg) {
+ while (trace_blocks_ptr < trace_blocks_end) {
+ tl_assert(*trace_blocks_ptr == head_block);
+ // Do not overwrite previously mmaped blocks
+ if (!head_block) {
+ *trace_blocks_ptr = block_arg;
+ *used_blocks_ptr = 'x';
+ }
+ trace_blocks_ptr++;
+ used_blocks_ptr++;
+ }
+ } else {
+ while (trace_blocks_ptr < trace_blocks_end) {
+ // X11 workaround...
+ if (*trace_blocks_ptr) {
+ if (!head_block)
+ head_block = *trace_blocks_ptr;
+ tl_assert(*trace_blocks_ptr == head_block);
+ if (!*used_blocks_ptr)
+ touched++;
+ }
+ *trace_blocks_ptr++ = NULL;
+ *used_blocks_ptr++ = '\0';
+ }
+
+ if (head_block && touched > 0) {
+ touched *= PAGE_SIZE;
+ while (head_block) {
+ head_block->current -= touched;
+ head_block = head_block->parent;
+ }
+ }
+ }
+}
+
+static __inline__ Addr page_offset_up(Addr addr)
+{
+ addr = PAGE_OFFSET_UP(addr);
+ return addr ? addr : PAGE_NUMBER;
+}
+
+static __inline__ void mem_map(Addr addr, Addr end_addr, Trace_Block *block_arg)
+{
+ // Must be strictly greater
+ tl_assert(end_addr > addr);
+
+#if VG_WORDSIZE == 4
+ mark_blocks( mmap_section.trace_blocks + PAGE_OFFSET_DOWN(addr),
+ mmap_section.trace_blocks + page_offset_up(end_addr),
+ mmap_section.used_blocks + PAGE_OFFSET_DOWN(addr),
+ block_arg );
+#else
+ Addr current_end_addr;
+ Mmap_Section* mmap_section;
+ Addr page_addr;
+
+ while (addr < end_addr) {
+ page_addr = PAGE_ADDR(addr);
+ current_end_addr = page_addr + 0x100000000ll;
+ if (current_end_addr > end_addr)
+ current_end_addr = end_addr;
+
+ mmap_section = mmap_sections;
+ while (1) {
+ if (mmap_section->page_addr == page_addr)
+ break;
+ if (!mmap_section->next) {
+ mmap_section->next = VG_(calloc)("freya.mem_map.1", 1, sizeof(Mmap_Section));
+ mmap_section = mmap_section->next;
+ mmap_section->next = NULL;
+ mmap_section->page_addr = page_addr;
+ mmap_section->trace_blocks = VG_(calloc)("freya.mem_map.2", PAGE_NUMBER, sizeof(Trace_Block*));
+ mmap_section->used_blocks = VG_(calloc)("freya.fr_post_clo_init.3", PAGE_NUMBER, sizeof(Char));
+ break;
+ }
+ mmap_section = mmap_section->next;
+ }
+
+ mark_blocks( mmap_section->trace_blocks + PAGE_OFFSET_DOWN(addr),
+ mmap_section->trace_blocks + page_offset_up(current_end_addr),
+ mmap_section->used_blocks + PAGE_OFFSET_DOWN(addr),
+ block_arg );
+
+ addr = current_end_addr;
+ }
+#endif
+}
+
+static VG_REGPARM(2) void trace_store(Addr addr, SizeT size)
+{
+ Trace_Block *block;
+
+#if VG_WORDSIZE == 4
+ addr = PAGE_OFFSET_DOWN(addr);
+ if (!mmap_section.used_blocks[addr])
+ return;
+
+ block = mmap_section.trace_blocks[addr];
+ mmap_section.used_blocks[addr] = '\0';
+#else
+ Addr page_addr = PAGE_ADDR(addr);
+ Mmap_Section* mmap_section;
+
+ if (mmap_section_cache->page_addr == page_addr)
+ mmap_section = mmap_section_cache;
+ else {
+ mmap_section = mmap_sections;
+ while (1) {
+ if (mmap_section->page_addr == page_addr)
+ break;
+ mmap_section = mmap_section->next;
+ if (!mmap_section)
+ return;
+ }
+ mmap_section_cache = mmap_section;
+ }
+
+ addr = PAGE_OFFSET_DOWN(addr);
+ if (!mmap_section->used_blocks[addr])
+ return;
+
+ block = mmap_section->trace_blocks[addr];
+ mmap_section->used_blocks[addr] = '\0';
+#endif
+
+ tl_assert(block);
+ do {
+ block->allocs ++;
+ block->total += PAGE_SIZE;
+ block->current += PAGE_SIZE;
+ if (block->peak < block->current)
+ block->peak = block->current;
+ block = block->parent;
+ } while(block);
+}
+
+//------------------------------------------------------------//
+//--- malloc() et al replacement wrappers ---//
+//------------------------------------------------------------//
+
+static void* fr_malloc ( ThreadId tid, SizeT szB )
+{
+ return new_block( tid, szB, VG_(clo_alignment), /*is_zeroed*/False );
+}
+
+static void* fr___builtin_new ( ThreadId tid, SizeT szB )
+{
+ return new_block( tid, szB, VG_(clo_alignment), /*is_zeroed*/False );
+}
+
+static void* fr___builtin_vec_new ( ThreadId tid, SizeT szB )
+{
+ return new_block( tid, szB, VG_(clo_alignment), /*is_zeroed*/False );
+}
+
+static void* fr_calloc ( ThreadId tid, SizeT m, SizeT szB )
+{
+ return new_block( tid, m*szB, VG_(clo_alignment), /*is_zeroed*/True );
+}
+
+static void *fr_memalign ( ThreadId tid, SizeT alignB, SizeT szB )
+{
+ return new_block( tid, szB, alignB, False );
+}
+
+static void fr_free ( ThreadId tid, void* p )
+{
+ free_block( tid, p );
+}
+
+static void fr___builtin_delete ( ThreadId tid, void* p )
+{
+ free_block( tid, p );
+}
+
+static void fr___builtin_vec_delete ( ThreadId tid, void* p )
+{
+ free_block( tid, p );
+}
+
+static void* fr_realloc ( ThreadId tid, void* p_old, SizeT new_szB )
+{
+ return renew_block(tid, p_old, new_szB);
+}
+
+static SizeT fr_malloc_usable_size ( ThreadId tid, void* p )
+{
+ HP_Chunk* hc = VG_(HT_lookup)( malloc_list, (UWord)p );
+
+ return ( hc ? hc->req_szB + hc->slop_szB : 0 );
+}
+
+static void fr_mmap(Addr a, SizeT len, Bool rr, Bool ww, Bool xx, ULong di_handle)
+{
+ if (clo_mmap)
+ mem_map( a, a + len, alloc_trace(VG_(get_running_tid)()) );
+}
+
+static void fr_munmap(Addr a, SizeT len)
+{
+ if (clo_mmap)
+ mem_map( a, a + len, NULL );
+}
+
+// ---------------------------------------------------------------
+// Generator
+// ---------------------------------------------------------------
+
+static Bool fr_process_cmd_line_option(Char* arg)
+{
+ if (VG_BOOL_CLO(arg, "--frverb", clo_fr_verb)) {}
+ else if (VG_STR_CLO(arg, "--config", clo_config)) {}
+ else if (VG_BOOL_CLO(arg, "--mmap", clo_mmap)) {}
+ else if (VG_BOOL_CLO(arg, "--crossfree", clo_cross_free)) {}
+ else if (VG_BINT_CLO(arg, "--trace", clo_trace, 10, MAX_TRACE)) {}
+ else if (VG_BINT_CLO(arg, "--report", clo_report, 5, MAX_TRACE)) {}
+ else if (VG_BINT_CLO(arg, "--min", clo_min, 0, 1024*1024*1024)) {}
+ else
+ return VG_(replacement_malloc_process_cmd_line_option)(arg);
+
+ return True;
+}
+
+static void fr_print_usage(void)
+{
+ VG_(printf) (
+" --frverb=yes verbose freya tool\n"
+" --config=<str> configuration file\n"
+" --mmap=no do not trace mmap allocations\n"
+" --crossfree=yes report cross thread free operations\n"
+" --trace=<number> maximum depth of stack trace [10]\n"
+" --report=<number> report depth of stack trace [5]\n"
+" --min=<number> do not report allocations below this size (in bytes) [0]\n"
+ );
+}
+
+static void fr_print_debug_usage(void)
+{
+ VG_(printf)(
+" (none)\n"
+ );
+}
+
+static
+IRSB* fr_instrument(VgCallbackClosure* closure,
+ IRSB* sbIn,
+ VexGuestLayout* layout,
+ VexGuestExtents* vge,
+ IRType gWordTy, IRType hWordTy)
+{
+ Int i;
+ IRSB* sbOut;
+ IRTypeEnv* tyenv = sbIn->tyenv;
+ IRDirty* di;
+ IRType dataTy;
+ IRExpr** argv;
+ IRCAS* cas;
+
+ // We don't care about mmaps
+ if (!clo_mmap)
+ return sbIn;
+
+ // From lackey tool
+ tl_assert(gWordTy == hWordTy);
+
+ sbOut = deepCopyIRSBExceptStmts(sbIn);
+
+ // Copy verbatim any IR preamble preceding the first IMark
+ i = 0;
+ while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
+ addStmtToIRSB( sbOut, sbIn->stmts[i] );
+ i++;
+ }
+
+ for (/*use current i*/; i < sbIn->stmts_used; i++) {
+ IRStmt* st = sbIn->stmts[i];
+ if (!st || st->tag == Ist_NoOp) continue;
+
+ switch (st->tag) {
+ case Ist_NoOp: // Make compiler happy
+ case Ist_AbiHint:
+ case Ist_Put:
+ case Ist_PutI:
+ case Ist_MBE:
+ case Ist_IMark:
+ case Ist_WrTmp:
+ case Ist_Exit:
+ addStmtToIRSB( sbOut, st );
+ break;
+
+ case Ist_Store:
+ dataTy = typeOfIRExpr( tyenv, st->Ist.Store.data );
+ argv = mkIRExprVec_2( st->Ist.Store.addr, mkIRExpr_HWord( sizeofIRType( dataTy ) ) );
+ di = unsafeIRDirty_0_N(/*regparms*/2, "trace_store", VG_(fnptr_to_fnentry)( trace_store ), argv);
+ addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
+ addStmtToIRSB( sbOut, st );
+ break;
+
+ case Ist_LLSC:
+ if (st->Ist.LLSC.storedata != NULL) {
+ dataTy = typeOfIRExpr( tyenv, st->Ist.LLSC.storedata );
+ argv = mkIRExprVec_2( st->Ist.LLSC.addr, mkIRExpr_HWord( sizeofIRType( dataTy ) ) );
+ di = unsafeIRDirty_0_N(/*regparms*/2, "trace_store", VG_(fnptr_to_fnentry)( trace_store ), argv);
+ addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
+ addStmtToIRSB( sbOut, st );
+ }
+ break;
+
+ case Ist_Dirty:
+ di = st->Ist.Dirty.details;
+ if (di->mFx != Ifx_None) {
+ // This dirty helper accesses memory. Collect the details.
+ tl_assert(di->mAddr != NULL);
+ tl_assert(di->mSize != 0);
+ if (di->mFx == Ifx_Write || di->mFx == Ifx_Modify) {
+ argv = mkIRExprVec_2( di->mAddr, mkIRExpr_HWord( di->mSize ) );
+ di = unsafeIRDirty_0_N( /*regparms*/2, "trace_store", VG_(fnptr_to_fnentry)( trace_store ), argv );
+ addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
+ }
+ } else {
+ tl_assert(di->mAddr == NULL);
+ tl_assert(di->mSize == 0);
+ }
+ addStmtToIRSB( sbOut, st );
+ break;
+
+ case Ist_CAS:
+ cas = st->Ist.CAS.details;
+ tl_assert(cas->addr != NULL);
+ tl_assert(cas->dataLo != NULL);
+ argv = mkIRExprVec_2( cas->addr, mkIRExpr_HWord( sizeofIRType(typeOfIRExpr(tyenv, cas->dataLo)) * (cas->dataHi != NULL ? 2 : 1) ) );
+ di = unsafeIRDirty_0_N( /*regparms*/2, "trace_store", VG_(fnptr_to_fnentry)( trace_store ), argv );
+ addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
+ addStmtToIRSB( sbOut, st );
+ break;
+ }
+ }
+
+ return sbOut;
+}
+
+static void fr_fini(Int exitcode)
+{
+ fr_sort_and_dump(trace_head, 0);
+}
+
+static Char* parse_rule(Char* read_ptr, Rule_List** last_rule_ptr)
+{
+ Rule_List* rule;
+ Rule_List* rule_ptr;
+
+ rule = VG_(malloc)("freya.parse_rule.1", sizeof(Rule_List));
+
+ rule->next = NULL;
+ rule->parent = NULL;
+
+ if (*read_ptr != '-') {
+ rule->name = read_ptr;
+ while (*read_ptr != ' ') {
+ tl_assert2(*read_ptr && *read_ptr != '\n' && *read_ptr != '\r' && *read_ptr != ')', "Rule must start with hypen or a name followed by a space");
+ read_ptr++;
+ }
+ rule->name_len = read_ptr - rule->name;
+ *read_ptr = '\0';
+
+ // Must have a unique name
+ rule_ptr = rule_head;
+ while (rule_ptr) {
+ if (rule_ptr->name_len == rule->name_len && VG_(memcmp)(rule->name, rule_ptr->name, rule->name_len * sizeof(Char)) == 0) {
+ VG_(printf)("Redefined rule %s. Rule names must be unique!\n", rule->name);
+ tl_assert(0);
+ }
+ rule_ptr = rule_ptr->next;
+ }
+ } else {
+ rule->name = NULL;
+ rule->name_len = 0;
+ }
+ read_ptr++;
+
+ // Enque this new rule
+ if (*last_rule_ptr)
+ (*last_rule_ptr)->next = rule;
+ else
+ rule_head = rule;
+ *last_rule_ptr = rule;
+
+ while (*read_ptr == ' ')
+ read_ptr++;
+
+ if (*read_ptr == '(' || *read_ptr == '{') {
+ rule->is_namespace = *read_ptr == '{';
+ read_ptr++;
+
+ rule->func_name = read_ptr;
+ while (!(!rule->is_namespace && *read_ptr == ')') && !(rule->is_namespace && *read_ptr == '}')) {
+ tl_assert2(*read_ptr && *read_ptr != '\n' && *read_ptr != '\r', "unterminated ( or {");
+ read_ptr++;
+ }
+ rule->func_name_len = read_ptr - rule->func_name;
+ tl_assert2(rule->func_name_len > 0, "missing function or namespace name");
+ *read_ptr = '\0';
+ read_ptr++;
+
+ while (*read_ptr == ' ')
+ read_ptr++;
+ } else {
+ rule->func_name = NULL;
+ rule->func_name_len = 0;
+ rule->is_namespace = False;
+ }
+
+ rule->path = read_ptr;
+ while (*read_ptr && *read_ptr != '\n' && *read_ptr != '\r')
+ read_ptr++;
+ rule->path_len = read_ptr - rule->path;
+ if (rule->path_len == 0)
+ rule->path = NULL;
+ else if (*read_ptr) {
+ *read_ptr = '\0';
+ read_ptr++;
+ }
+
+ if (clo_fr_verb)
+ VG_(printf)("Rule: '%s' (%ld) %s: '%s' (%ld) Path: '%s' (%ld)\n",
+ rule->name, rule->name_len,
+ rule->is_namespace ? "Namesp" : "Func", rule->func_name, rule->func_name_len,
+ rule->path, rule->path_len);
+ return read_ptr;
+}
+
+static void search_rule(Trace_Block* block, Char* name, SizeT name_len)
+{
+ Rule_List* rule_ptr;
+
+ rule_ptr = rule_head;
+ while (rule_ptr) {
+ if (rule_ptr->name_len == name_len && rule_ptr->name[0] == name[0]
+ && VG_(memcmp)(rule_ptr->name, name, name_len * sizeof(Char)) == 0) {
+ tl_assert2(!rule_ptr->parent, "Rule is already assigned");
+ rule_ptr->parent = block;
+ return;
+ }
+ rule_ptr = rule_ptr->next;
+ }
+ VG_(printf)("Rule '%s' not found\n", name);
+ tl_assert(0);
+}
+
+static void remove_unused_rules(void)
+{
+ Rule_List* rule_ptr;
+ Rule_List* prev_rule_ptr = NULL;
+
+ rule_ptr = rule_head;
+ while (rule_ptr) {
+ if (rule_ptr->name && !rule_ptr->parent) {
+ // Remove this unused rule
+ if (prev_rule_ptr) {
+ prev_rule_ptr->next = rule_ptr->next;
+ VG_(free)(rule_ptr);
+ rule_ptr = prev_rule_ptr->next;
+ } else {
+ rule_head = rule_ptr->next;
+ VG_(free)(rule_ptr);
+ rule_ptr = rule_head;
+ }
+ } else {
+ prev_rule_ptr = rule_ptr;
+ rule_ptr = rule_ptr->next;
+ }
+ }
+}
+
+static Char* parse_extra_rule(Char* read_ptr, Trace_Block* block)
+{
+ Char* name;
+
+ tl_assert2(block, "the first group cannot be started by {");
+ read_ptr++;
+ name = read_ptr;
+
+ while (*read_ptr != '}') {
+ tl_assert2(*read_ptr && *read_ptr != '\n' && *read_ptr != '\r', "unterminated {");
+ read_ptr++;
+ }
+ tl_assert2(name != read_ptr, "node has no name");
+
+ search_rule(block, name, read_ptr - name);
+ read_ptr++;
+
+ while (*read_ptr == ' ')
+ read_ptr++;
+ tl_assert2(*read_ptr == '\n' || *read_ptr == '\r' || !*read_ptr, "Garbage at the end of the line");
+ return read_ptr;
+}
+
+static void fr_post_clo_init(void)
+{
+ Rule_List* last_rule_ptr = NULL;
+ Char* read_ptr;
+ Trace_Block* block = NULL;
+ Trace_Block* parent = NULL;
+ Int* indents = (int*)dir_buffer;
+ Int indent;
+ Int depth = -1;
+ Bool is_group;
+ SysRes sres;
+ Int fd;
+ OffT file_size;
+
+ if (clo_mmap) {
+#if VG_WORDSIZE == 4
+ mmap_section.next = NULL;
+ mmap_section.page_addr = 0;
+ mmap_section.trace_blocks = VG_(calloc)("freya.fr_post_clo_init.2", PAGE_NUMBER, sizeof(Trace_Block*));
+ mmap_section.used_blocks = VG_(calloc)("freya.fr_post_clo_init.3", PAGE_NUMBER, sizeof(Char));
+#else
+ mmap_sections = VG_(calloc)("freya.fr_post_clo_init.1", 1, sizeof(Mmap_Section));
+ mmap_sections->next = NULL;
+ mmap_sections->page_addr = 0;
+ mmap_sections->trace_blocks = VG_(calloc)("freya.fr_post_clo_init.2", PAGE_NUMBER, sizeof(Trace_Block*));
+ mmap_sections->used_blocks = VG_(calloc)("freya.fr_post_clo_init.3", PAGE_NUMBER, sizeof(Char));
+ mmap_section_cache = mmap_sections;
+#endif
+ }
+
+ read_ptr = NULL;
+ if (clo_config) {
+ sres = VG_(open)(clo_config, VKI_O_RDONLY, 0);
+ if (!sr_isError(sres)) {
+ fd = (Int) sr_Res(sres);
+
+ file_size = VG_(lseek)(fd, 0, VKI_SEEK_END);
+ VG_(lseek)(fd, 0, VKI_SEEK_SET);
+
+ if (clo_fr_verb)
+ VG_(printf)("File '%s' (size: %ld bytes) is successfully opened.\n", clo_config, file_size);
+
+ read_ptr = VG_(malloc)("freya.fr_post_clo_init.3", (file_size + 1) * sizeof(Char));
+ VG_(read)(fd, read_ptr, file_size);
+ read_ptr[file_size] = '\0';
+
+ VG_(close) (fd);
+ }
+ else if (clo_fr_verb)
+ VG_(printf)("Cannot open '%s'. (Fallback to default config)\n", clo_config);
+ }
+ else if (clo_fr_verb)
+ VG_(printf)("No config file provided. (Fallback to default config)\n");
+
+ if (!read_ptr) {
+ // Duplicate
+ read_ptr = VG_(malloc)("freya.fr_post_clo_init.4", (VG_(strlen)(default_rule) + 1) * sizeof(Char));
+ VG_(strcpy)(read_ptr, default_rule);
+ }
+
+ while (*read_ptr) {
+ // Parsing the next line, first skip spaces
+ indent = 0;
+ while (*read_ptr == ' ') {
+ indent++;
+ read_ptr++;
+ }
+
+ // Skip comments and empty lines
+ if (*read_ptr == '#' || *read_ptr == '\r' || *read_ptr == '\n') {
+ while (*read_ptr != '\0' && *read_ptr != '\r' && *read_ptr != '\n')
+ read_ptr++;
+
+ if (*read_ptr) {
+ read_ptr++;
+ continue;
+ }
+ }
+
+ if (*read_ptr == '{') {
+ read_ptr = parse_extra_rule(read_ptr, block);
+ continue;
+ } else if (*read_ptr != '[' && *read_ptr != '(') {
+ read_ptr = parse_rule(read_ptr, &last_rule_ptr);
+ continue;
+ }
+
+ is_group = *read_ptr == '[';
+
+ block = VG_(malloc)("freya.fr_post_clo_init.4", sizeof(Trace_Block));
+ read_ptr++;
+ block->name = read_ptr;
+
+ while (!(!is_group && *read_ptr == ')') && !(is_group && *read_ptr == ']')) {
+ tl_assert2(*read_ptr && *read_ptr != '\n' && *read_ptr != '\r', "unterminated ( or [");
+ read_ptr++;
+ }
+ tl_assert2(block->name != read_ptr, "node has no name");
+
+ *read_ptr = '\0';
+ if (!is_group)
+ search_rule(block, block->name, read_ptr - block->name);
+ read_ptr++;
+
+ if (*read_ptr == '+') {
+ tl_assert2(default_parent == NULL, "Only one default node is allowed");
+ default_parent = block;
+ read_ptr++;
+ }
+
+ while (*read_ptr == ' ')
+ read_ptr++;
+ tl_assert2(*read_ptr == '\n' || *read_ptr == '\r' || !*read_ptr, "Garbage at the end of the line");
+
+ if (clo_fr_verb)
+ VG_(printf)("%s '%s' %s\n", is_group ? "Group:" : "Group & Attach:", block->name, default_parent == block ? "(Default)" : "");
+
+ if (depth >= 0) {
+ if (indents[depth] != indent) {
+ if (indent > indents[depth]) {
+ tl_assert2(depth < 63, "Maximum allowed depth is 63 for the tree");
+ depth++;
+ indents[depth] = indent;
+ if (parent)
+ parent = parent->first;
+ else
+ parent = trace_head;
+ } else {
+ do {
+ tl_assert2(depth != 0, "Wrong tree indentation");
+ depth--;
+ tl_assert(parent);
+ parent = parent->parent;
+ } while (indent != indents[depth]);
+ tl_assert((depth == 0 && !parent) || (depth > 0 && parent));
+ }
+ }
+ } else {
+ // The indentation of the top element
+ tl_assert(!parent);
+ indents[0] = indent;
+ depth = 0;
+ }
+
+ block->parent = parent;
+ if (parent) {
+ block->next = parent->first;
+ parent->first = block;
+ } else {
+ block->next = trace_head;
+ trace_head = block;
+ }
+ block->first = NULL;
+
+ block->hash_next = NULL;
+
+ block->allocs = 0;
+ block->total = 0;
+ block->current = 0;
+ block->peak = 0;
+ block->ips = 0;
+ }
+
+ remove_unused_rules();
+}
+
+static void fr_pre_clo_init(void)
+{
+ VG_(details_name) ("Freya");
+ VG_(details_version) ("0.5");
+ VG_(details_description) ("Memory access logger");
+ VG_(details_copyright_author)(
+ "Copyright (C) 2009, and GNU GPL'd, by Zoltan Herczeg (University of Szeged).");
+ VG_(details_bug_reports_to) (VG_BUGS_TO);
+
+ VG_(basic_tool_funcs) (fr_post_clo_init,
+ fr_instrument,
+ fr_fini);
+
+ // Needs
+ VG_(needs_command_line_options)(fr_process_cmd_line_option,
+ fr_print_usage,
+ fr_print_debug_usage);
+
+ VG_(needs_malloc_replacement) (fr_malloc,
+ fr___builtin_new,
+ fr___builtin_vec_new,
+ fr_memalign,
+ fr_calloc,
+ fr_free,
+ fr___builtin_delete,
+ fr___builtin_vec_delete,
+ fr_realloc,
+ fr_malloc_usable_size,
+ 0 );
+
+ VG_(track_new_mem_mmap) (fr_mmap);
+ VG_(track_die_mem_munmap) (fr_munmap);
+
+ // HP_Chunks.
+ trace_hash = VG_(HT_construct)( "fr.main.1" );
+ malloc_list = VG_(HT_construct)( "fr.main.2" );
+}
+
+VG_DETERMINE_INTERFACE_VERSION(fr_pre_clo_init)
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
diff --git a/freya/tests/Makefile.am b/freya/tests/Makefile.am
new file mode 100644
index 0000000..e69de29
--
1.8.0.2
|