summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcsilvers <csilvers@6b5cf1ce-ec42-a296-1ba9-69fdba395a50>2011-07-16 01:07:10 +0000
committercsilvers <csilvers@6b5cf1ce-ec42-a296-1ba9-69fdba395a50>2011-07-16 01:07:10 +0000
commit100c38c1a225446c1bbeeaac117902d0fbebfefe (patch)
tree0880fc86d5db8c110ae469f0d702a44db1b4b5ef
parent8c7d2289d24f7a49f1f6f60d4a6eaee06fa04c60 (diff)
downloadgperftools-100c38c1a225446c1bbeeaac117902d0fbebfefe.tar.gz
Fri Jul 15 16:10:51 2011 Google Inc. <opensource@google.com>
* google-perftools: version 1.8 release * PORTING: (Disabled) support for patching mmap on freebsd (chapp...) * PORTING: Support volatile __malloc_hook for glibc 2.14 (csilvers) * PORTING: Use _asm rdtsc and __rdtsc to get cycleclock in windows (koda) * PORTING: Fix fd vs. HANDLE compiler error on cygwin (csilvers) * PORTING: Do not test memalign or double-linking on OS X (csilvers) * PORTING: Actually enable TLS on windows (jontra) * PORTING: Some work to compile under Native Client (krasin) * PORTING: deal with pthread_once w/o -pthread on freebsd (csilvers) * Rearrange libc-overriding to make it easier to port (csilvers) * Display source locations in pprof disassembly (sanjay) * BUGFIX: Actually initialize allocator name (mec) * BUGFIX: Keep track of 'overhead' bytes in malloc reporting (csilvers) * Allow ignoring one object twice in the leak checker (glider) * BUGFIX: top10 in pprof should print 10 lines, not 11 (rsc) * Refactor vdso source files (tipp) * Some documentation cleanups * Document MAX_TOTAL_THREAD_CACHE_SIZE <= 1Gb (nsethi) * Add MallocExtension::GetOwnership(ptr) (csilvers) * BUGFIX: We were leaving out a needed $(top_srcdir) in the Makefile * PORTING: Support getting argv0 on OS X * Add 'weblist' command to pprof: like 'list' but html (sanjay) * Improve source listing in pprof (sanjay) * Cap cache sizes to reduce fragmentation (ruemmler) * Improve performance by capping or increasing sizes (ruemmler) * Add M{,un}mapReplacmenet hooks into MallocHook (ribrdb) * Refactored system allocator logic (gangren) * Include cleanups (csilvers) * Add TCMALLOC_SMALL_BUT_SLOW support (ruemmler) * Clarify that tcmalloc stats are MiB (robinson) * Remove support for non-tcmalloc debugallocation (blount) * Add a new test: malloc_hook_test (csilvers) * Change the configure script to be more crosstool-friendly (mcgrathr) * PORTING: leading-underscore changes to support win64 (csilvers) * Improve debugallocation tc_malloc_size (csilvers) * Extend atomicops.h and cyceclock to use ARM V6+ optimized code (sanek) * Change malloc-hook to use a list-like structure (llib) * Add flag to use MAP_PRIVATE in memfs_malloc (gangren) * Windows support for pprof: nul and /usr/bin/file (csilvers) * TESTING: add test on strdup to tcmalloc_test (csilvers) * Augment heap-checker to deal with no-inode maps (csilvers) * Count .dll/.dylib as shared libs in heap-checker (csilvers) * Disable sys_futex for arm; it's not always reliable (sanek) * PORTING: change lots of windows/port.h macros to functions * BUGFIX: Generate correct version# in tcmalloc.h on windows (csilvers) * PORTING: Some casting to make solaris happier about types (csilvers) * TESTING: Disable debugallocation_test in 'minimal' mode (csilvers) * Rewrite debugallocation to be more modular (csilvers) * Don't try to run the heap-checker under valgrind (ppluzhnikov) * BUGFIX: Make focused stat %'s relative, not absolute (sanjay) * BUGFIX: Don't use '//' comments in a C file (csilvers) * Quiet new-gcc compiler warnings via -Wno-unused-result, etc (csilvers) git-svn-id: http://gperftools.googlecode.com/svn/trunk@110 6b5cf1ce-ec42-a296-1ba9-69fdba395a50
-rw-r--r--ChangeLog55
-rw-r--r--Makefile.am68
-rw-r--r--Makefile.in633
-rw-r--r--NEWS35
-rw-r--r--README22
-rwxr-xr-xconfigure166
-rw-r--r--configure.ac47
-rw-r--r--doc/heapprofile.html5
-rw-r--r--doc/tcmalloc.html2
-rwxr-xr-xgoogle-perftools.sln8
-rw-r--r--packages/deb/changelog8
-rw-r--r--src/base/atomicops-internals-windows.h127
-rw-r--r--src/base/atomicops.h2
-rw-r--r--src/base/cycleclock.h18
-rw-r--r--src/base/elf_mem_image.cc432
-rw-r--r--src/base/elf_mem_image.h134
-rw-r--r--src/base/low_level_alloc.cc2
-rw-r--r--src/base/spinlock_internal.cc2
-rw-r--r--src/base/vdso_support.cc388
-rw-r--r--src/base/vdso_support.h109
-rw-r--r--src/central_freelist.cc46
-rw-r--r--src/central_freelist.h35
-rw-r--r--src/common.cc35
-rw-r--r--src/common.h13
-rw-r--r--src/config.h.in9
-rw-r--r--src/debugallocation.cc51
-rw-r--r--src/google/heap-checker.h3
-rw-r--r--src/google/malloc_extension.h23
-rw-r--r--src/google/malloc_extension_c.h12
-rw-r--r--src/google/malloc_hook.h13
-rw-r--r--src/heap-checker.cc8
-rw-r--r--src/libc_override.h90
-rw-r--r--src/libc_override_gcc_and_weak.h99
-rw-r--r--src/libc_override_glibc.h148
-rw-r--r--src/libc_override_osx.h257
-rw-r--r--src/libc_override_redefine.h93
-rw-r--r--src/malloc_extension.cc23
-rw-r--r--src/malloc_hook-inl.h2
-rw-r--r--src/malloc_hook.cc197
-rw-r--r--src/malloc_hook_mmap_freebsd.h111
-rw-r--r--src/malloc_hook_mmap_linux.h223
-rw-r--r--src/maybe_threads.cc20
-rw-r--r--src/memfs_malloc.cc85
-rw-r--r--src/memory_region_map.cc4
-rwxr-xr-xsrc/pprof407
-rw-r--r--src/profile-handler.cc8
-rw-r--r--src/profiler.cc8
-rw-r--r--src/stack_trace_table.h2
-rw-r--r--src/stacktrace.cc11
-rw-r--r--src/stacktrace_config.h7
-rw-r--r--src/stacktrace_nacl-inl.h37
-rw-r--r--src/symbolize.cc43
-rw-r--r--src/system-alloc.cc6
-rw-r--r--src/system-alloc.h2
-rw-r--r--src/tcmalloc.cc205
-rw-r--r--src/tests/debugallocation_test.cc6
-rw-r--r--src/tests/malloc_extension_c_test.c8
-rw-r--r--src/tests/malloc_extension_test.cc20
-rw-r--r--src/tests/malloc_hook_test.cc35
-rw-r--r--src/tests/profiler_unittest.cc4
-rw-r--r--src/tests/system-alloc_unittest.cc24
-rw-r--r--src/tests/tcmalloc_unittest.cc136
-rw-r--r--src/thread_cache.cc51
-rw-r--r--src/windows/config.h22
-rw-r--r--src/windows/google/tcmalloc.h.in9
-rw-r--r--src/windows/mingw.h4
-rw-r--r--src/windows/port.cc4
-rw-r--r--src/windows/port.h10
-rwxr-xr-xvsprojects/current_allocated_bytes_test/current_allocated_bytes_test.vcproj1
-rwxr-xr-xvsprojects/malloc_hook_test/malloc_hook_test.vcproj1
70 files changed, 3456 insertions, 1478 deletions
diff --git a/ChangeLog b/ChangeLog
index ee43193..c439360 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,58 @@
+Fri Jul 15 16:10:51 2011 Google Inc. <opensource@google.com>
+
+ * google-perftools: version 1.8 release
+ * PORTING: (Disabled) support for patching mmap on freebsd (chapp...)
+ * PORTING: Support volatile __malloc_hook for glibc 2.14 (csilvers)
+ * PORTING: Use _asm rdtsc and __rdtsc to get cycleclock in windows (koda)
+ * PORTING: Fix fd vs. HANDLE compiler error on cygwin (csilvers)
+ * PORTING: Do not test memalign or double-linking on OS X (csilvers)
+ * PORTING: Actually enable TLS on windows (jontra)
+ * PORTING: Some work to compile under Native Client (krasin)
+ * PORTING: deal with pthread_once w/o -pthread on freebsd (csilvers)
+ * Rearrange libc-overriding to make it easier to port (csilvers)
+ * Display source locations in pprof disassembly (sanjay)
+ * BUGFIX: Actually initialize allocator name (mec)
+ * BUGFIX: Keep track of 'overhead' bytes in malloc reporting (csilvers)
+ * Allow ignoring one object twice in the leak checker (glider)
+ * BUGFIX: top10 in pprof should print 10 lines, not 11 (rsc)
+ * Refactor vdso source files (tipp)
+ * Some documentation cleanups
+ * Document MAX_TOTAL_THREAD_CACHE_SIZE <= 1Gb (nsethi)
+ * Add MallocExtension::GetOwnership(ptr) (csilvers)
+ * BUGFIX: We were leaving out a needed $(top_srcdir) in the Makefile
+ * PORTING: Support getting argv0 on OS X
+ * Add 'weblist' command to pprof: like 'list' but html (sanjay)
+ * Improve source listing in pprof (sanjay)
+ * Cap cache sizes to reduce fragmentation (ruemmler)
+ * Improve performance by capping or increasing sizes (ruemmler)
+ * Add M{,un}mapReplacmenet hooks into MallocHook (ribrdb)
+ * Refactored system allocator logic (gangren)
+ * Include cleanups (csilvers)
+ * Add TCMALLOC_SMALL_BUT_SLOW support (ruemmler)
+ * Clarify that tcmalloc stats are MiB (robinson)
+ * Remove support for non-tcmalloc debugallocation (blount)
+ * Add a new test: malloc_hook_test (csilvers)
+ * Change the configure script to be more crosstool-friendly (mcgrathr)
+ * PORTING: leading-underscore changes to support win64 (csilvers)
+ * Improve debugallocation tc_malloc_size (csilvers)
+ * Extend atomicops.h and cyceclock to use ARM V6+ optimized code (sanek)
+ * Change malloc-hook to use a list-like structure (llib)
+ * Add flag to use MAP_PRIVATE in memfs_malloc (gangren)
+ * Windows support for pprof: nul and /usr/bin/file (csilvers)
+ * TESTING: add test on strdup to tcmalloc_test (csilvers)
+ * Augment heap-checker to deal with no-inode maps (csilvers)
+ * Count .dll/.dylib as shared libs in heap-checker (csilvers)
+ * Disable sys_futex for arm; it's not always reliable (sanek)
+ * PORTING: change lots of windows/port.h macros to functions
+ * BUGFIX: Generate correct version# in tcmalloc.h on windows (csilvers)
+ * PORTING: Some casting to make solaris happier about types (csilvers)
+ * TESTING: Disable debugallocation_test in 'minimal' mode (csilvers)
+ * Rewrite debugallocation to be more modular (csilvers)
+ * Don't try to run the heap-checker under valgrind (ppluzhnikov)
+ * BUGFIX: Make focused stat %'s relative, not absolute (sanjay)
+ * BUGFIX: Don't use '//' comments in a C file (csilvers)
+ * Quiet new-gcc compiler warnings via -Wno-unused-result, etc (csilvers)
+
Fri Feb 04 15:54:31 2011 Google Inc. <opensource@google.com>
* google-perftools: version 1.7 release
diff --git a/Makefile.am b/Makefile.am
index 5eb4d42..2020fab 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -30,6 +30,9 @@ AM_CXXFLAGS += -Wall -Wwrite-strings -Woverloaded-virtual \
-fno-builtin-memalign -fno-builtin-posix_memalign \
-fno-builtin-valloc -fno-builtin-pvalloc
endif GCC
+if HAVE_W_NO_UNUSED_RESULT
+AM_CXXFLAGS += -Wno-unused-result
+endif HAVE_W_NO_UNUSED_RESULT
# The -no-undefined flag allows libtool to generate shared libraries for
# Cygwin and MinGW. LIBSTDCXX_LA_LINKER_FLAG is used to fix a Solaris bug.
@@ -255,11 +258,13 @@ LOW_LEVEL_ALLOC_UNITTEST_INCLUDES = src/base/low_level_alloc.h \
src/google/malloc_hook.h \
src/google/malloc_hook_c.h \
src/malloc_hook-inl.h \
+ src/malloc_hook_mmap_linux.h \
+ src/malloc_hook_mmap_freebsd.h \
$(SPINLOCK_INCLUDES) \
$(LOGGING_INCLUDES)
low_level_alloc_unittest_SOURCES = src/base/low_level_alloc.cc \
src/malloc_hook.cc \
- src/maybe_threads.cc \
+ $(MAYBE_THREADS_CC) \
src/tests/low_level_alloc_unittest.cc \
$(LOW_LEVEL_ALLOC_UNITTEST_INCLUDES)
# By default, MallocHook takes stack traces for use by the heap-checker.
@@ -286,11 +291,14 @@ if WITH_STACK_TRACE
S_STACKTRACE_INCLUDES = src/stacktrace_config.h \
src/stacktrace_generic-inl.h \
src/stacktrace_libunwind-inl.h \
+ src/stacktrace_nacl-inl.h \
src/stacktrace_powerpc-inl.h \
src/stacktrace_x86_64-inl.h \
src/stacktrace_x86-inl.h \
src/stacktrace_win32-inl.h \
+ src/base/elf_mem_image.h \
src/base/vdso_support.h
+
SG_STACKTRACE_INCLUDES = src/google/stacktrace.h
STACKTRACE_INCLUDES = $(S_STACKTRACE_INCLUDES) $(SG_STACKTRACE_INCLUDES)
googleinclude_HEADERS += $(SG_STACKTRACE_INCLUDES)
@@ -298,6 +306,7 @@ googleinclude_HEADERS += $(SG_STACKTRACE_INCLUDES)
### Making the library
noinst_LTLIBRARIES += libstacktrace.la
libstacktrace_la_SOURCES = src/stacktrace.cc \
+ src/base/elf_mem_image.cc \
src/base/vdso_support.cc \
$(STACKTRACE_INCLUDES)
libstacktrace_la_LIBADD = $(UNWIND_LIBS) $(LIBSPINLOCK)
@@ -363,6 +372,11 @@ S_TCMALLOC_MINIMAL_INCLUDES = src/common.h \
src/sampler.h \
src/central_freelist.h \
src/linked_list.h \
+ src/libc_override.h \
+ src/libc_override_gcc_and_weak.h \
+ src/libc_override_glibc.h \
+ src/libc_override_osx.h \
+ src/libc_override_redefine.h \
src/page_heap.h \
src/page_heap_allocator.h \
src/span.h \
@@ -372,6 +386,8 @@ S_TCMALLOC_MINIMAL_INCLUDES = src/common.h \
src/stack_trace_table.h \
src/base/thread_annotations.h \
src/malloc_hook-inl.h \
+ src/malloc_hook_mmap_linux.h \
+ src/malloc_hook_mmap_freebsd.h \
src/maybe_threads.h
SG_TCMALLOC_MINIMAL_INCLUDES = src/google/malloc_hook.h \
src/google/malloc_hook_c.h \
@@ -442,6 +458,8 @@ LIBS_TO_WEAKEN += libtcmalloc_minimal.la
## src/google/malloc_hook.h \
## src/google/malloc_hook_c.h \
## src/malloc_hook-inl.h \
+## src/malloc_hook_mmap_linux.h \
+## src/malloc_hook_mmap_freebsd.h \
## src/base/basictypes.h \
## src/maybe_threads.h
## malloc_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
@@ -597,6 +615,7 @@ endif !ENABLE_STATIC
endif !MINGW
if !MINGW
+if !OSX
TESTS += memalign_unittest
memalign_unittest_SOURCES = src/tests/memalign_unittest.cc \
src/tcmalloc.h \
@@ -605,6 +624,7 @@ memalign_unittest_SOURCES = src/tests/memalign_unittest.cc \
memalign_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
memalign_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
memalign_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
+endif !OSX
endif !MINGW
TESTS += page_heap_test
@@ -727,11 +747,15 @@ malloc_extension_debug_test_CXXFLAGS = $(malloc_extension_test_CXXFLAGS)
malloc_extension_debug_test_LDFLAGS = $(malloc_extension_test_LDFLAGS)
malloc_extension_debug_test_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS)
+if !MINGW
+if !OSX
TESTS += memalign_debug_unittest
memalign_debug_unittest_SOURCES = $(memalign_unittest_SOURCES)
memalign_debug_unittest_CXXFLAGS = $(memalign_unittest_CXXFLAGS)
memalign_debug_unittest_LDFLAGS = $(memalign_unittest_LDFLAGS)
memalign_debug_unittest_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS)
+endif !OSX
+endif !MINGW
TESTS += realloc_debug_unittest
realloc_debug_unittest_SOURCES = $(realloc_unittest_SOURCES)
@@ -852,14 +876,15 @@ tcmalloc_unittest_LDADD = $(LIBTCMALLOC) liblogging.la $(PTHREAD_LIBS)
# This makes sure it's safe to link in both tcmalloc and
# tcmalloc_minimal. (One would never do this on purpose, but perhaps
# by accident...) When we can compile libprofiler, we also link it in
-# to make sure that works too.
-
-TESTS += tcmalloc_both_unittest
-tcmalloc_both_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
- src/tests/testutil.h src/tests/testutil.cc \
- $(TCMALLOC_UNITTEST_INCLUDES)
-tcmalloc_both_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-tcmalloc_both_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+# to make sure that works too. NOTE: On OS X, it's *not* safe to
+# link both in (we end up with two copies of every global var, and
+# the code tends to pick one arbitrarily), so don't run the test there.
+# (We define these outside the 'if' because they're reused below.)
+tcmalloc_both_unittest_srcs = src/tests/tcmalloc_unittest.cc \
+ src/tests/testutil.h src/tests/testutil.cc \
+ $(TCMALLOC_UNITTEST_INCLUDES)
+tcmalloc_both_unittest_cflags = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+tcmalloc_both_unittest_lflags = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
if WITH_CPU_PROFILER
# We want libtcmalloc last on the link line, but due to a bug in
# libtool involving convenience libs, they need to come last on the
@@ -868,12 +893,19 @@ if WITH_CPU_PROFILER
# We also put pthreads after tcmalloc, because some pthread
# implementations define their own malloc, and we need to go on the
# first linkline to make sure our malloc 'wins'.
-tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
- libprofiler.la liblogging.la $(PTHREAD_LIBS)
+tcmalloc_both_unittest_ladd = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
+ libprofiler.la liblogging.la $(PTHREAD_LIBS)
else
-tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
- liblogging.la $(PTHREAD_LIBS)
+tcmalloc_both_unittest_ladd = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
+ liblogging.la $(PTHREAD_LIBS)
endif !WITH_CPU_PROFILER
+if !OSX
+TESTS += tcmalloc_both_unittest
+tcmalloc_both_unittest_SOURCES = $(tcmalloc_both_unittest_srcs)
+tcmalloc_both_unittest_CXXFLAGS = $(tcmalloc_both_unittest_cflags)
+tcmalloc_both_unittest_LDFLAGS = $(tcmalloc_both_unittest_lflags)
+tcmalloc_both_unittest_LDADD = $(tcmalloc_both_unittest_ladd)
+endif !OSX
TESTS += tcmalloc_large_unittest
tcmalloc_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc
@@ -1221,9 +1253,9 @@ libtcmalloc_and_profiler_la_LDFLAGS = $(PTHREAD_CFLAGS) \
libtcmalloc_and_profiler_la_LIBADD = $(libtcmalloc_la_LIBADD)
TESTS += tcmalloc_and_profiler_unittest
-tcmalloc_and_profiler_unittest_SOURCES = $(tcmalloc_both_unittest_SOURCES)
-tcmalloc_and_profiler_unittest_CXXFLAGS = $(tcmalloc_both_unittest_CXXFLAGS)
-tcmalloc_and_profiler_unittest_LDFLAGS = $(tcmalloc_both_unittest_LDFLAGS)
+tcmalloc_and_profiler_unittest_SOURCES = $(tcmalloc_both_unittest_srcs)
+tcmalloc_and_profiler_unittest_CXXFLAGS = $(tcmalloc_both_unittest_cflags)
+tcmalloc_and_profiler_unittest_LDFLAGS = $(tcmalloc_both_unittest_lflags)
tcmalloc_and_profiler_unittest_LDADD = libtcmalloc_and_profiler.la
LIBS_TO_WEAKEN += libtcmalloc_and_profiler.la
@@ -1269,8 +1301,8 @@ libtcmalloc.pc: Makefile packages/rpm/rpm.spec
echo '' >> "$@".tmp
echo 'Name: $(PACKAGE)' >> "$@".tmp
echo 'Version: $(VERSION)' >> "$@".tmp
- -grep '^Summary:' packages/rpm/rpm.spec | sed s/^Summary:/Description:/ | head -n1 >> "$@".tmp
- -grep '^URL: ' packages/rpm/rpm.spec >> "$@".tmp
+ -grep '^Summary:' $(top_srcdir)/packages/rpm/rpm.spec | sed s/^Summary:/Description:/ | head -n1 >> "$@".tmp
+ -grep '^URL: ' $(top_srcdir)/packages/rpm/rpm.spec >> "$@".tmp
echo 'Requires:' >> "$@".tmp
echo 'Libs: -L$${libdir} -ltcmalloc' >> "$@".tmp
echo 'Libs.private: $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)' >> "$@".tmp
diff --git a/Makefile.in b/Makefile.in
index a7e27e9..f3aa67e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -58,41 +58,42 @@ host_triplet = @host@
@GCC_TRUE@ -fno-builtin-memalign -fno-builtin-posix_memalign \
@GCC_TRUE@ -fno-builtin-valloc -fno-builtin-pvalloc
+@HAVE_W_NO_UNUSED_RESULT_TRUE@am__append_3 = -Wno-unused-result
# These are x86-specific, having to do with frame-pointers. In
# particular, some x86_64 systems do not insert frame pointers by
# default (all i386 systems that I know of, do. I don't know about
# non-x86 chips). We need to tell perftools what to do about that.
-@ENABLE_FRAME_POINTERS_TRUE@@X86_64_AND_NO_FP_BY_DEFAULT_TRUE@am__append_3 = -fno-omit-frame-pointer
-@ENABLE_FRAME_POINTERS_FALSE@@X86_64_AND_NO_FP_BY_DEFAULT_TRUE@am__append_4 = -DNO_FRAME_POINTER
-@MINGW_TRUE@am__append_5 = -Wl,-u__tcmalloc
+@ENABLE_FRAME_POINTERS_TRUE@@X86_64_AND_NO_FP_BY_DEFAULT_TRUE@am__append_4 = -fno-omit-frame-pointer
+@ENABLE_FRAME_POINTERS_FALSE@@X86_64_AND_NO_FP_BY_DEFAULT_TRUE@am__append_5 = -DNO_FRAME_POINTER
+@MINGW_TRUE@am__append_6 = -Wl,-u__tcmalloc
noinst_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
$(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \
- $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_24)
+ $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_28)
bin_PROGRAMS =
-@MINGW_TRUE@am__append_6 = libwindows.la libspinlock.la
+@MINGW_TRUE@am__append_7 = libwindows.la libspinlock.la
# We also need to tell mingw that sysinfo.cc needs shlwapi.lib.
# (We do this via a #pragma for msvc, but need to do it here for mingw).
-@MINGW_TRUE@am__append_7 = -lshlwapi
-@MINGW_FALSE@am__append_8 = libspinlock.la
-@WITH_STACK_TRACE_TRUE@am__append_9 = $(SG_STACKTRACE_INCLUDES)
+@MINGW_TRUE@am__append_8 = -lshlwapi
+@MINGW_FALSE@am__append_9 = libspinlock.la
+@WITH_STACK_TRACE_TRUE@am__append_10 = $(SG_STACKTRACE_INCLUDES)
### Making the library
-@WITH_STACK_TRACE_TRUE@am__append_10 = libstacktrace.la
+@WITH_STACK_TRACE_TRUE@am__append_11 = libstacktrace.la
### Unittests
-@WITH_STACK_TRACE_TRUE@am__append_11 = stacktrace_unittest
+@WITH_STACK_TRACE_TRUE@am__append_12 = stacktrace_unittest
### Documentation
-@WITH_STACK_TRACE_TRUE@am__append_12 = doc/pprof_remote_servers.html
+@WITH_STACK_TRACE_TRUE@am__append_13 = doc/pprof_remote_servers.html
# Let unittests find pprof if they need to run it
-@WITH_STACK_TRACE_TRUE@am__append_13 = PPROF_PATH=$(top_srcdir)/src/pprof
+@WITH_STACK_TRACE_TRUE@am__append_14 = PPROF_PATH=$(top_srcdir)/src/pprof
# On MSVC, we need our own versions of addr2line and nm to work with pprof.
# This is a slight abuse of WINDOWS_PROJECTS, but not much
-@WITH_STACK_TRACE_TRUE@am__append_14 = \
+@WITH_STACK_TRACE_TRUE@am__append_15 = \
@WITH_STACK_TRACE_TRUE@ vsprojects/nm-pdb/nm-pdb.vcproj \
@WITH_STACK_TRACE_TRUE@ vsprojects/addr2line-pdb/addr2line-pdb.vcproj \
@WITH_STACK_TRACE_TRUE@ src/windows/nm-pdb.c \
@@ -104,41 +105,41 @@ bin_PROGRAMS =
# libraries anyway (so can't be LD_PRELOADed) -- in fact, anybody who
# chooses not to build shared libraries won't be able to run this test.
# TODO(csilvers): figure out how to nix ".exe" or otherwise work under mingw
-@ENABLE_STATIC_FALSE@@MINGW_FALSE@am__append_15 = maybe_threads_unittest.sh$(EXEEXT)
-@ENABLE_STATIC_FALSE@@MINGW_FALSE@am__append_16 = $(maybe_threads_unittest_sh_SOURCES)
-@MINGW_TRUE@am__append_17 = src/windows/port.h src/windows/port.cc
-@MINGW_FALSE@am__append_18 = system_alloc_unittest
+@ENABLE_STATIC_FALSE@@MINGW_FALSE@am__append_16 = maybe_threads_unittest.sh$(EXEEXT)
+@ENABLE_STATIC_FALSE@@MINGW_FALSE@am__append_17 = $(maybe_threads_unittest_sh_SOURCES)
+@MINGW_TRUE@am__append_18 = src/windows/port.h src/windows/port.cc
+@MINGW_FALSE@am__append_19 = system_alloc_unittest
# This doesn't work with static linkage, because libtcmalloc.a isn't
# happy with C linkage (it misses the stdc++ library). Likewise with
# mingw, which links foo.a even though it doesn't set ENABLE_STATIC.
# TODO(csilvers): set enable_static=true in configure.ac:36?
-@ENABLE_STATIC_FALSE@@MINGW_FALSE@am__append_19 = malloc_extension_c_test
+@ENABLE_STATIC_FALSE@@MINGW_FALSE@am__append_20 = malloc_extension_c_test
# -ansi here is just to help ensure the code is bog-standard C.
-@ENABLE_STATIC_FALSE@@GCC_TRUE@@MINGW_FALSE@am__append_20 = -ansi
-@MINGW_FALSE@am__append_21 = memalign_unittest
+@ENABLE_STATIC_FALSE@@GCC_TRUE@@MINGW_FALSE@am__append_21 = -ansi
+@MINGW_FALSE@@OSX_FALSE@am__append_22 = memalign_unittest
### ------- tcmalloc_minimal_debug (thread-caching malloc with debugallocation)
# Like tcmalloc.cc, debugallocation.cc needs exceptions to fulfill its
# API. Luckily, we can reuse everything else from tcmalloc_minimal.
-@WITH_DEBUGALLOC_TRUE@am__append_22 = libtcmalloc_minimal_debug.la
@WITH_DEBUGALLOC_TRUE@am__append_23 = libtcmalloc_minimal_debug.la
+@WITH_DEBUGALLOC_TRUE@am__append_24 = libtcmalloc_minimal_debug.la
### Unittests
-@WITH_DEBUGALLOC_TRUE@am__append_24 = tcmalloc_minimal_debug_unittest \
-@WITH_DEBUGALLOC_TRUE@ malloc_extension_debug_test \
-@WITH_DEBUGALLOC_TRUE@ memalign_debug_unittest \
-@WITH_DEBUGALLOC_TRUE@ realloc_debug_unittest
+@WITH_DEBUGALLOC_TRUE@am__append_25 = tcmalloc_minimal_debug_unittest \
+@WITH_DEBUGALLOC_TRUE@ malloc_extension_debug_test
+@MINGW_FALSE@@OSX_FALSE@@WITH_DEBUGALLOC_TRUE@am__append_26 = memalign_debug_unittest
+@WITH_DEBUGALLOC_TRUE@am__append_27 = realloc_debug_unittest
# debugallocation_test checks that we print a proper stacktrace when
# debug-allocs fail, so we can't run it if we don't have stacktrace info.
-@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@am__append_25 = debugallocation_test.sh$(EXEEXT)
-@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@am__append_26 = $(debugallocation_test_sh_SOURCES)
+@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@am__append_28 = debugallocation_test.sh$(EXEEXT)
+@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@am__append_29 = $(debugallocation_test_sh_SOURCES)
# This is the sub-program used by debugallocation_test.sh
-@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@am__append_27 = debugallocation_test
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_28 = $(SG_TCMALLOC_INCLUDES)
+@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@am__append_30 = debugallocation_test
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_31 = $(SG_TCMALLOC_INCLUDES)
### Making the library
@@ -146,21 +147,17 @@ bin_PROGRAMS =
# for all files in this library -- except tcmalloc.cc which needs them
# to fulfill its API. Automake doesn't allow per-file CXXFLAGS, so we need
# to separate into two libraries.
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_29 = libtcmalloc_internal.la
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_30 = libtcmalloc.la
-@WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_31 = $(HEAP_CHECKER_SOURCES)
-@WITH_HEAP_CHECKER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_32 = -DNO_HEAP_CHECK
-@WITH_HEAP_CHECKER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_33 = -DNO_HEAP_CHECK
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_34 = libtcmalloc.la
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_32 = libtcmalloc_internal.la
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_33 = libtcmalloc.la
+@WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_34 = $(HEAP_CHECKER_SOURCES)
+@WITH_HEAP_CHECKER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_35 = -DNO_HEAP_CHECK
+@WITH_HEAP_CHECKER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_36 = -DNO_HEAP_CHECK
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_37 = libtcmalloc.la
### Unittests
-
-# This makes sure it's safe to link in both tcmalloc and
-# tcmalloc_minimal. (One would never do this on purpose, but perhaps
-# by accident...) When we can compile libprofiler, we also link it in
-# to make sure that works too.
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_35 = tcmalloc_unittest \
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_both_unittest \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_38 = tcmalloc_unittest
+@OSX_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_39 = tcmalloc_both_unittest
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_40 = \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_large_unittest \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ raw_printer_test \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampler_test \
@@ -170,74 +167,74 @@ bin_PROGRAMS =
# on, which it's not by default. Use the "standard" value of 2^19.
# These unittests often need to run binaries. They're in the current dir
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_36 = TCMALLOC_SAMPLE_PARAMETER=524288 \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_41 = TCMALLOC_SAMPLE_PARAMETER=524288 \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ BINDIR=. \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ TMPDIR=/tmp/perftools
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_37 = vsprojects/sampler_test/sampler_test.vcproj
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_38 = $(sampling_test_sh_SOURCES)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_42 = vsprojects/sampler_test/sampler_test.vcproj
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_43 = $(sampling_test_sh_SOURCES)
# This is the sub-program used by sampling_test.sh
# The -g is so pprof can get symbol information.
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_39 = sampling_test
-@WITH_HEAP_PROFILER_TRUE@am__append_40 = heap-profiler_unittest.sh$(EXEEXT)
-@WITH_HEAP_PROFILER_TRUE@am__append_41 = $(heap_profiler_unittest_sh_SOURCES)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_44 = sampling_test
+@WITH_HEAP_PROFILER_TRUE@am__append_45 = heap-profiler_unittest.sh$(EXEEXT)
+@WITH_HEAP_PROFILER_TRUE@am__append_46 = $(heap_profiler_unittest_sh_SOURCES)
# These are sub-programs used by heap-profiler_unittest.sh
-@WITH_HEAP_PROFILER_TRUE@am__append_42 = heap-profiler_unittest
-@WITH_HEAP_CHECKER_TRUE@am__append_43 = \
+@WITH_HEAP_PROFILER_TRUE@am__append_47 = heap-profiler_unittest
+@WITH_HEAP_CHECKER_TRUE@am__append_48 = \
@WITH_HEAP_CHECKER_TRUE@ heap-checker_unittest.sh$(EXEEXT) \
@WITH_HEAP_CHECKER_TRUE@ heap-checker-death_unittest.sh$(EXEEXT)
-@WITH_HEAP_CHECKER_TRUE@am__append_44 = \
+@WITH_HEAP_CHECKER_TRUE@am__append_49 = \
@WITH_HEAP_CHECKER_TRUE@ $(heap_checker_unittest_sh_SOURCES) \
@WITH_HEAP_CHECKER_TRUE@ $(top_srcdir)/$(heap_checker_death_unittest_sh_SOURCES)
# These are sub-programs used by heap-checker_unittest.sh
-@WITH_HEAP_CHECKER_TRUE@am__append_45 = heap-checker_unittest
+@WITH_HEAP_CHECKER_TRUE@am__append_50 = heap-checker_unittest
### Documentation (above and beyond tcmalloc_minimal documentation)
-@WITH_HEAP_PROFILER_TRUE@am__append_46 = doc/heapprofile.html doc/heap-example1.png
-@WITH_HEAP_CHECKER_TRUE@am__append_47 = doc/heap_checker.html
+@WITH_HEAP_PROFILER_TRUE@am__append_51 = doc/heapprofile.html doc/heap-example1.png
+@WITH_HEAP_CHECKER_TRUE@am__append_52 = doc/heap_checker.html
### ------- tcmalloc with debugallocation
-@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_48 = libtcmalloc_debug.la
-@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_49 = libtcmalloc_debug.la
+@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_53 = libtcmalloc_debug.la
+@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_54 = libtcmalloc_debug.la
### Unittests
-@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_50 = tcmalloc_debug_unittest \
+@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_55 = tcmalloc_debug_unittest \
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampler_debug_test \
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_debug_test.sh$(EXEEXT)
# This is the sub-program using by sampling_debug_test.sh
# The -g is so pprof can get symbol information.
-@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_51 = sampling_debug_test
-@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am__append_52 = heap-profiler_debug_unittest.sh$(EXEEXT)
+@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_56 = sampling_debug_test
+@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am__append_57 = heap-profiler_debug_unittest.sh$(EXEEXT)
# These are sub-programs used by heap-profiler_debug_unittest.sh
-@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am__append_53 = heap-profiler_debug_unittest
-@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am__append_54 = heap-checker_debug_unittest.sh$(EXEEXT)
+@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am__append_58 = heap-profiler_debug_unittest
+@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am__append_59 = heap-checker_debug_unittest.sh$(EXEEXT)
# These are sub-programs used by heap-checker_debug_unittest.sh
-@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am__append_55 = heap-checker_debug_unittest
-@WITH_CPU_PROFILER_TRUE@am__append_56 = $(SG_CPU_PROFILER_INCLUDES)
+@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am__append_60 = heap-checker_debug_unittest
+@WITH_CPU_PROFILER_TRUE@am__append_61 = $(SG_CPU_PROFILER_INCLUDES)
### Making the library
-@WITH_CPU_PROFILER_TRUE@am__append_57 = libprofiler.la
+@WITH_CPU_PROFILER_TRUE@am__append_62 = libprofiler.la
### Unittests
-@WITH_CPU_PROFILER_TRUE@am__append_58 = getpc_test \
+@WITH_CPU_PROFILER_TRUE@am__append_63 = getpc_test \
@WITH_CPU_PROFILER_TRUE@ profiledata_unittest \
@WITH_CPU_PROFILER_TRUE@ profile_handler_unittest \
@WITH_CPU_PROFILER_TRUE@ profiler_unittest.sh$(EXEEXT)
-@WITH_CPU_PROFILER_TRUE@am__append_59 = $(profiler_unittest_sh_SOURCES)
+@WITH_CPU_PROFILER_TRUE@am__append_64 = $(profiler_unittest_sh_SOURCES)
# These are sub-programs used by profiler_unittest.sh
-@WITH_CPU_PROFILER_TRUE@am__append_60 = profiler1_unittest profiler2_unittest profiler3_unittest \
+@WITH_CPU_PROFILER_TRUE@am__append_65 = profiler1_unittest profiler2_unittest profiler3_unittest \
@WITH_CPU_PROFILER_TRUE@ profiler4_unittest
@WITH_CPU_PROFILER_FALSE@profiler2_unittest_DEPENDENCIES =
### Documentation
-@WITH_CPU_PROFILER_TRUE@am__append_61 = doc/cpuprofile.html \
+@WITH_CPU_PROFILER_TRUE@am__append_66 = doc/cpuprofile.html \
@WITH_CPU_PROFILER_TRUE@ doc/cpuprofile-fileformat.html \
@WITH_CPU_PROFILER_TRUE@ doc/pprof-test-big.gif \
@WITH_CPU_PROFILER_TRUE@ doc/pprof-test.gif \
@@ -252,9 +249,9 @@ bin_PROGRAMS =
# works fine for .so files, it does not for .a files. The easiest way
# around this -- and I've tried a bunch of the hard ways -- is to just
# to create another set of libraries that has both functionality in it.
-@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_62 = libtcmalloc_and_profiler.la
-@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_63 = tcmalloc_and_profiler_unittest
-@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_64 = libtcmalloc_and_profiler.la
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_67 = libtcmalloc_and_profiler.la
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_68 = tcmalloc_and_profiler_unittest
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__append_69 = libtcmalloc_and_profiler.la
DIST_COMMON = README $(am__configure_deps) $(am__dist_doc_DATA_DIST) \
$(am__googleinclude_HEADERS_DIST) $(dist_man_MANS) \
$(noinst_HEADERS) $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
@@ -361,15 +358,18 @@ libspinlock_la_OBJECTS = $(am_libspinlock_la_OBJECTS)
@WITH_STACK_TRACE_TRUE@ $(am__DEPENDENCIES_1) \
@WITH_STACK_TRACE_TRUE@ $(am__DEPENDENCIES_2)
am__libstacktrace_la_SOURCES_DIST = src/stacktrace.cc \
- src/base/vdso_support.cc src/stacktrace_config.h \
- src/stacktrace_generic-inl.h src/stacktrace_libunwind-inl.h \
+ src/base/elf_mem_image.cc src/base/vdso_support.cc \
+ src/stacktrace_config.h src/stacktrace_generic-inl.h \
+ src/stacktrace_libunwind-inl.h src/stacktrace_nacl-inl.h \
src/stacktrace_powerpc-inl.h src/stacktrace_x86_64-inl.h \
src/stacktrace_x86-inl.h src/stacktrace_win32-inl.h \
- src/base/vdso_support.h src/google/stacktrace.h
+ src/base/elf_mem_image.h src/base/vdso_support.h \
+ src/google/stacktrace.h
@WITH_STACK_TRACE_TRUE@am__objects_4 = $(am__objects_1) \
@WITH_STACK_TRACE_TRUE@ $(am__objects_1)
@WITH_STACK_TRACE_TRUE@am_libstacktrace_la_OBJECTS = stacktrace.lo \
-@WITH_STACK_TRACE_TRUE@ vdso_support.lo $(am__objects_4)
+@WITH_STACK_TRACE_TRUE@ elf_mem_image.lo vdso_support.lo \
+@WITH_STACK_TRACE_TRUE@ $(am__objects_4)
libstacktrace_la_OBJECTS = $(am_libstacktrace_la_OBJECTS)
@WITH_STACK_TRACE_TRUE@am_libstacktrace_la_rpath =
libsysinfo_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
@@ -394,22 +394,26 @@ am__libtcmalloc_la_SOURCES_DIST = src/tcmalloc.cc src/common.h \
src/base/atomicops-internals-arm-v6plus.h src/tcmalloc_guard.h \
src/base/commandlineflags.h src/base/basictypes.h \
src/pagemap.h src/sampler.h src/central_freelist.h \
- src/linked_list.h src/page_heap.h src/page_heap_allocator.h \
- src/span.h src/static_vars.h src/symbolize.h \
- src/thread_cache.h src/stack_trace_table.h \
- src/base/thread_annotations.h src/malloc_hook-inl.h \
- src/maybe_threads.h src/base/logging.h \
- src/base/dynamic_annotations.h src/third_party/valgrind.h \
- src/addressmap-inl.h src/raw_printer.h src/base/elfcore.h \
- src/base/googleinit.h src/base/linux_syscall_support.h \
- src/base/linuxthreads.h src/base/stl_allocator.h \
- src/base/sysinfo.h src/base/thread_lister.h \
- src/heap-profile-table.h src/google/malloc_hook.h \
- src/google/malloc_hook_c.h src/google/malloc_extension.h \
- src/google/malloc_extension_c.h src/google/stacktrace.h \
- src/google/heap-profiler.h src/google/heap-checker.h \
- src/base/thread_lister.c src/base/linuxthreads.cc \
- src/heap-checker.cc src/heap-checker-bcad.cc
+ src/linked_list.h src/libc_override.h \
+ src/libc_override_gcc_and_weak.h src/libc_override_glibc.h \
+ src/libc_override_osx.h src/libc_override_redefine.h \
+ src/page_heap.h src/page_heap_allocator.h src/span.h \
+ src/static_vars.h src/symbolize.h src/thread_cache.h \
+ src/stack_trace_table.h src/base/thread_annotations.h \
+ src/malloc_hook-inl.h src/malloc_hook_mmap_linux.h \
+ src/malloc_hook_mmap_freebsd.h src/maybe_threads.h \
+ src/base/logging.h src/base/dynamic_annotations.h \
+ src/third_party/valgrind.h src/addressmap-inl.h \
+ src/raw_printer.h src/base/elfcore.h src/base/googleinit.h \
+ src/base/linux_syscall_support.h src/base/linuxthreads.h \
+ src/base/stl_allocator.h src/base/sysinfo.h \
+ src/base/thread_lister.h src/heap-profile-table.h \
+ src/google/malloc_hook.h src/google/malloc_hook_c.h \
+ src/google/malloc_extension.h src/google/malloc_extension_c.h \
+ src/google/stacktrace.h src/google/heap-profiler.h \
+ src/google/heap-checker.h src/base/thread_lister.c \
+ src/base/linuxthreads.cc src/heap-checker.cc \
+ src/heap-checker-bcad.cc
@MINGW_FALSE@am__objects_5 = libtcmalloc_la-tcmalloc.lo
am__objects_6 = $(am__objects_1)
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_7 = $(am__objects_6) \
@@ -448,22 +452,26 @@ am__libtcmalloc_and_profiler_la_SOURCES_DIST = src/tcmalloc.cc \
src/base/atomicops-internals-arm-v6plus.h src/tcmalloc_guard.h \
src/base/commandlineflags.h src/base/basictypes.h \
src/pagemap.h src/sampler.h src/central_freelist.h \
- src/linked_list.h src/page_heap.h src/page_heap_allocator.h \
- src/span.h src/static_vars.h src/symbolize.h \
- src/thread_cache.h src/stack_trace_table.h \
- src/base/thread_annotations.h src/malloc_hook-inl.h \
- src/maybe_threads.h src/base/logging.h \
- src/base/dynamic_annotations.h src/third_party/valgrind.h \
- src/addressmap-inl.h src/raw_printer.h src/base/elfcore.h \
- src/base/googleinit.h src/base/linux_syscall_support.h \
- src/base/linuxthreads.h src/base/stl_allocator.h \
- src/base/sysinfo.h src/base/thread_lister.h \
- src/heap-profile-table.h src/google/malloc_hook.h \
- src/google/malloc_hook_c.h src/google/malloc_extension.h \
- src/google/malloc_extension_c.h src/google/stacktrace.h \
- src/google/heap-profiler.h src/google/heap-checker.h \
- src/base/thread_lister.c src/base/linuxthreads.cc \
- src/heap-checker.cc src/heap-checker-bcad.cc src/profiler.cc \
+ src/linked_list.h src/libc_override.h \
+ src/libc_override_gcc_and_weak.h src/libc_override_glibc.h \
+ src/libc_override_osx.h src/libc_override_redefine.h \
+ src/page_heap.h src/page_heap_allocator.h src/span.h \
+ src/static_vars.h src/symbolize.h src/thread_cache.h \
+ src/stack_trace_table.h src/base/thread_annotations.h \
+ src/malloc_hook-inl.h src/malloc_hook_mmap_linux.h \
+ src/malloc_hook_mmap_freebsd.h src/maybe_threads.h \
+ src/base/logging.h src/base/dynamic_annotations.h \
+ src/third_party/valgrind.h src/addressmap-inl.h \
+ src/raw_printer.h src/base/elfcore.h src/base/googleinit.h \
+ src/base/linux_syscall_support.h src/base/linuxthreads.h \
+ src/base/stl_allocator.h src/base/sysinfo.h \
+ src/base/thread_lister.h src/heap-profile-table.h \
+ src/google/malloc_hook.h src/google/malloc_hook_c.h \
+ src/google/malloc_extension.h src/google/malloc_extension_c.h \
+ src/google/stacktrace.h src/google/heap-profiler.h \
+ src/google/heap-checker.h src/base/thread_lister.c \
+ src/base/linuxthreads.cc src/heap-checker.cc \
+ src/heap-checker-bcad.cc src/profiler.cc \
src/profile-handler.cc src/profiledata.cc src/profiledata.h \
src/profile-handler.h src/getpc.h src/base/simple_mutex.h \
src/google/profiler.h
@@ -505,20 +513,24 @@ am__libtcmalloc_debug_la_SOURCES_DIST = src/debugallocation.cc \
src/base/atomicops-internals-arm-v6plus.h src/tcmalloc_guard.h \
src/base/commandlineflags.h src/base/basictypes.h \
src/pagemap.h src/sampler.h src/central_freelist.h \
- src/linked_list.h src/page_heap.h src/page_heap_allocator.h \
- src/span.h src/static_vars.h src/symbolize.h \
- src/thread_cache.h src/stack_trace_table.h \
- src/base/thread_annotations.h src/malloc_hook-inl.h \
- src/maybe_threads.h src/base/logging.h \
- src/base/dynamic_annotations.h src/third_party/valgrind.h \
- src/addressmap-inl.h src/raw_printer.h src/base/elfcore.h \
- src/base/googleinit.h src/base/linux_syscall_support.h \
- src/base/linuxthreads.h src/base/stl_allocator.h \
- src/base/sysinfo.h src/base/thread_lister.h \
- src/heap-profile-table.h src/google/malloc_hook.h \
- src/google/malloc_hook_c.h src/google/malloc_extension.h \
- src/google/malloc_extension_c.h src/google/stacktrace.h \
- src/google/heap-profiler.h src/google/heap-checker.h
+ src/linked_list.h src/libc_override.h \
+ src/libc_override_gcc_and_weak.h src/libc_override_glibc.h \
+ src/libc_override_osx.h src/libc_override_redefine.h \
+ src/page_heap.h src/page_heap_allocator.h src/span.h \
+ src/static_vars.h src/symbolize.h src/thread_cache.h \
+ src/stack_trace_table.h src/base/thread_annotations.h \
+ src/malloc_hook-inl.h src/malloc_hook_mmap_linux.h \
+ src/malloc_hook_mmap_freebsd.h src/maybe_threads.h \
+ src/base/logging.h src/base/dynamic_annotations.h \
+ src/third_party/valgrind.h src/addressmap-inl.h \
+ src/raw_printer.h src/base/elfcore.h src/base/googleinit.h \
+ src/base/linux_syscall_support.h src/base/linuxthreads.h \
+ src/base/stl_allocator.h src/base/sysinfo.h \
+ src/base/thread_lister.h src/heap-profile-table.h \
+ src/google/malloc_hook.h src/google/malloc_hook_c.h \
+ src/google/malloc_extension.h src/google/malloc_extension_c.h \
+ src/google/stacktrace.h src/google/heap-profiler.h \
+ src/google/heap-checker.h
@WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_17 = thread_lister.lo \
@WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_debug_la-linuxthreads.lo \
@WITH_HEAP_CHECKER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libtcmalloc_debug_la-heap-checker.lo \
@@ -552,23 +564,26 @@ am__libtcmalloc_internal_la_SOURCES_DIST = src/common.cc \
src/base/atomicops-internals-arm-v6plus.h src/tcmalloc_guard.h \
src/base/commandlineflags.h src/base/basictypes.h \
src/pagemap.h src/sampler.h src/central_freelist.h \
- src/linked_list.h src/page_heap.h src/page_heap_allocator.h \
- src/span.h src/static_vars.h src/symbolize.h \
- src/thread_cache.h src/stack_trace_table.h \
- src/base/thread_annotations.h src/malloc_hook-inl.h \
- src/maybe_threads.h src/google/malloc_hook.h \
- src/google/malloc_hook_c.h src/google/malloc_extension.h \
- src/google/malloc_extension_c.h src/google/stacktrace.h \
- src/base/logging.h src/base/dynamic_annotations.h \
- src/third_party/valgrind.h src/addressmap-inl.h \
- src/raw_printer.h src/base/elfcore.h src/base/googleinit.h \
- src/base/linux_syscall_support.h src/base/linuxthreads.h \
- src/base/stl_allocator.h src/base/sysinfo.h \
- src/base/thread_lister.h src/heap-profile-table.h \
- src/google/heap-profiler.h src/google/heap-checker.h \
- src/base/low_level_alloc.cc src/heap-profile-table.cc \
- src/heap-profiler.cc src/raw_printer.cc \
- src/memory_region_map.cc
+ src/linked_list.h src/libc_override.h \
+ src/libc_override_gcc_and_weak.h src/libc_override_glibc.h \
+ src/libc_override_osx.h src/libc_override_redefine.h \
+ src/page_heap.h src/page_heap_allocator.h src/span.h \
+ src/static_vars.h src/symbolize.h src/thread_cache.h \
+ src/stack_trace_table.h src/base/thread_annotations.h \
+ src/malloc_hook-inl.h src/malloc_hook_mmap_linux.h \
+ src/malloc_hook_mmap_freebsd.h src/maybe_threads.h \
+ src/google/malloc_hook.h src/google/malloc_hook_c.h \
+ src/google/malloc_extension.h src/google/malloc_extension_c.h \
+ src/google/stacktrace.h src/base/logging.h \
+ src/base/dynamic_annotations.h src/third_party/valgrind.h \
+ src/addressmap-inl.h src/raw_printer.h src/base/elfcore.h \
+ src/base/googleinit.h src/base/linux_syscall_support.h \
+ src/base/linuxthreads.h src/base/stl_allocator.h \
+ src/base/sysinfo.h src/base/thread_lister.h \
+ src/heap-profile-table.h src/google/heap-profiler.h \
+ src/google/heap-checker.h src/base/low_level_alloc.cc \
+ src/heap-profile-table.cc src/heap-profiler.cc \
+ src/raw_printer.cc src/memory_region_map.cc
@MINGW_FALSE@am__objects_18 = libtcmalloc_internal_la-system-alloc.lo
@MINGW_FALSE@am__objects_19 = \
@MINGW_FALSE@ libtcmalloc_internal_la-maybe_threads.lo
@@ -615,13 +630,17 @@ am__libtcmalloc_minimal_la_SOURCES_DIST = src/tcmalloc.cc src/common.h \
src/base/atomicops-internals-arm-v6plus.h src/tcmalloc_guard.h \
src/base/commandlineflags.h src/base/basictypes.h \
src/pagemap.h src/sampler.h src/central_freelist.h \
- src/linked_list.h src/page_heap.h src/page_heap_allocator.h \
- src/span.h src/static_vars.h src/symbolize.h \
- src/thread_cache.h src/stack_trace_table.h \
- src/base/thread_annotations.h src/malloc_hook-inl.h \
- src/maybe_threads.h src/google/malloc_hook.h \
- src/google/malloc_hook_c.h src/google/malloc_extension.h \
- src/google/malloc_extension_c.h src/google/stacktrace.h
+ src/linked_list.h src/libc_override.h \
+ src/libc_override_gcc_and_weak.h src/libc_override_glibc.h \
+ src/libc_override_osx.h src/libc_override_redefine.h \
+ src/page_heap.h src/page_heap_allocator.h src/span.h \
+ src/static_vars.h src/symbolize.h src/thread_cache.h \
+ src/stack_trace_table.h src/base/thread_annotations.h \
+ src/malloc_hook-inl.h src/malloc_hook_mmap_linux.h \
+ src/malloc_hook_mmap_freebsd.h src/maybe_threads.h \
+ src/google/malloc_hook.h src/google/malloc_hook_c.h \
+ src/google/malloc_extension.h src/google/malloc_extension_c.h \
+ src/google/stacktrace.h
@MINGW_FALSE@am__objects_22 = libtcmalloc_minimal_la-tcmalloc.lo
am_libtcmalloc_minimal_la_OBJECTS = $(am__objects_22) \
$(am__objects_20)
@@ -645,13 +664,17 @@ am__libtcmalloc_minimal_debug_la_SOURCES_DIST = \
src/base/atomicops-internals-arm-v6plus.h src/tcmalloc_guard.h \
src/base/commandlineflags.h src/base/basictypes.h \
src/pagemap.h src/sampler.h src/central_freelist.h \
- src/linked_list.h src/page_heap.h src/page_heap_allocator.h \
- src/span.h src/static_vars.h src/symbolize.h \
- src/thread_cache.h src/stack_trace_table.h \
- src/base/thread_annotations.h src/malloc_hook-inl.h \
- src/maybe_threads.h src/google/malloc_hook.h \
- src/google/malloc_hook_c.h src/google/malloc_extension.h \
- src/google/malloc_extension_c.h src/google/stacktrace.h
+ src/linked_list.h src/libc_override.h \
+ src/libc_override_gcc_and_weak.h src/libc_override_glibc.h \
+ src/libc_override_osx.h src/libc_override_redefine.h \
+ src/page_heap.h src/page_heap_allocator.h src/span.h \
+ src/static_vars.h src/symbolize.h src/thread_cache.h \
+ src/stack_trace_table.h src/base/thread_annotations.h \
+ src/malloc_hook-inl.h src/malloc_hook_mmap_linux.h \
+ src/malloc_hook_mmap_freebsd.h src/maybe_threads.h \
+ src/google/malloc_hook.h src/google/malloc_hook_c.h \
+ src/google/malloc_extension.h src/google/malloc_extension_c.h \
+ src/google/stacktrace.h
@WITH_DEBUGALLOC_TRUE@am_libtcmalloc_minimal_debug_la_OBJECTS = libtcmalloc_minimal_debug_la-debugallocation.lo \
@WITH_DEBUGALLOC_TRUE@ $(am__objects_20)
libtcmalloc_minimal_debug_la_OBJECTS = \
@@ -680,13 +703,17 @@ am__libtcmalloc_minimal_internal_la_SOURCES_DIST = src/common.cc \
src/base/atomicops-internals-arm-v6plus.h src/tcmalloc_guard.h \
src/base/commandlineflags.h src/base/basictypes.h \
src/pagemap.h src/sampler.h src/central_freelist.h \
- src/linked_list.h src/page_heap.h src/page_heap_allocator.h \
- src/span.h src/static_vars.h src/symbolize.h \
- src/thread_cache.h src/stack_trace_table.h \
- src/base/thread_annotations.h src/malloc_hook-inl.h \
- src/maybe_threads.h src/google/malloc_hook.h \
- src/google/malloc_hook_c.h src/google/malloc_extension.h \
- src/google/malloc_extension_c.h src/google/stacktrace.h
+ src/linked_list.h src/libc_override.h \
+ src/libc_override_gcc_and_weak.h src/libc_override_glibc.h \
+ src/libc_override_osx.h src/libc_override_redefine.h \
+ src/page_heap.h src/page_heap_allocator.h src/span.h \
+ src/static_vars.h src/symbolize.h src/thread_cache.h \
+ src/stack_trace_table.h src/base/thread_annotations.h \
+ src/malloc_hook-inl.h src/malloc_hook_mmap_linux.h \
+ src/malloc_hook_mmap_freebsd.h src/maybe_threads.h \
+ src/google/malloc_hook.h src/google/malloc_hook_c.h \
+ src/google/malloc_extension.h src/google/malloc_extension_c.h \
+ src/google/stacktrace.h
@MINGW_FALSE@am__objects_23 = \
@MINGW_FALSE@ libtcmalloc_minimal_internal_la-system-alloc.lo
@MINGW_FALSE@am__objects_24 = \
@@ -742,34 +769,34 @@ binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
@ENABLE_STATIC_FALSE@@MINGW_FALSE@am__EXEEXT_10 = maybe_threads_unittest.sh$(EXEEXT)
@MINGW_FALSE@am__EXEEXT_11 = system_alloc_unittest$(EXEEXT)
@ENABLE_STATIC_FALSE@@MINGW_FALSE@am__EXEEXT_12 = malloc_extension_c_test$(EXEEXT)
-@MINGW_FALSE@am__EXEEXT_13 = memalign_unittest$(EXEEXT)
+@MINGW_FALSE@@OSX_FALSE@am__EXEEXT_13 = memalign_unittest$(EXEEXT)
@WITH_DEBUGALLOC_TRUE@am__EXEEXT_14 = tcmalloc_minimal_debug_unittest$(EXEEXT) \
-@WITH_DEBUGALLOC_TRUE@ malloc_extension_debug_test$(EXEEXT) \
-@WITH_DEBUGALLOC_TRUE@ memalign_debug_unittest$(EXEEXT) \
-@WITH_DEBUGALLOC_TRUE@ realloc_debug_unittest$(EXEEXT)
-@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@am__EXEEXT_15 = debugallocation_test.sh$(EXEEXT)
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_16 = tcmalloc_unittest$(EXEEXT) \
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_both_unittest$(EXEEXT) \
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_large_unittest$(EXEEXT) \
+@WITH_DEBUGALLOC_TRUE@ malloc_extension_debug_test$(EXEEXT)
+@MINGW_FALSE@@OSX_FALSE@@WITH_DEBUGALLOC_TRUE@am__EXEEXT_15 = memalign_debug_unittest$(EXEEXT)
+@WITH_DEBUGALLOC_TRUE@am__EXEEXT_16 = realloc_debug_unittest$(EXEEXT)
+@WITH_DEBUGALLOC_TRUE@@WITH_STACK_TRACE_TRUE@am__EXEEXT_17 = debugallocation_test.sh$(EXEEXT)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_18 = tcmalloc_unittest$(EXEEXT)
+@OSX_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_19 = tcmalloc_both_unittest$(EXEEXT)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_20 = tcmalloc_large_unittest$(EXEEXT) \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ raw_printer_test$(EXEEXT) \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampler_test$(EXEEXT) \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_test.sh$(EXEEXT)
-@WITH_HEAP_PROFILER_TRUE@am__EXEEXT_17 = \
+@WITH_HEAP_PROFILER_TRUE@am__EXEEXT_21 = \
@WITH_HEAP_PROFILER_TRUE@ heap-profiler_unittest.sh$(EXEEXT)
-@WITH_HEAP_CHECKER_TRUE@am__EXEEXT_18 = \
+@WITH_HEAP_CHECKER_TRUE@am__EXEEXT_22 = \
@WITH_HEAP_CHECKER_TRUE@ heap-checker_unittest.sh$(EXEEXT) \
@WITH_HEAP_CHECKER_TRUE@ heap-checker-death_unittest.sh$(EXEEXT)
-@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_19 = tcmalloc_debug_unittest$(EXEEXT) \
+@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_23 = tcmalloc_debug_unittest$(EXEEXT) \
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampler_debug_test$(EXEEXT) \
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ sampling_debug_test.sh$(EXEEXT)
-@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am__EXEEXT_20 = heap-profiler_debug_unittest.sh$(EXEEXT)
-@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am__EXEEXT_21 = heap-checker_debug_unittest.sh$(EXEEXT)
-@WITH_CPU_PROFILER_TRUE@am__EXEEXT_22 = getpc_test$(EXEEXT) \
+@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_TRUE@am__EXEEXT_24 = heap-profiler_debug_unittest.sh$(EXEEXT)
+@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_CHECKER_TRUE@am__EXEEXT_25 = heap-checker_debug_unittest.sh$(EXEEXT)
+@WITH_CPU_PROFILER_TRUE@am__EXEEXT_26 = getpc_test$(EXEEXT) \
@WITH_CPU_PROFILER_TRUE@ profiledata_unittest$(EXEEXT) \
@WITH_CPU_PROFILER_TRUE@ profile_handler_unittest$(EXEEXT) \
@WITH_CPU_PROFILER_TRUE@ profiler_unittest.sh$(EXEEXT)
-@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_23 = tcmalloc_and_profiler_unittest$(EXEEXT)
-am__EXEEXT_24 = low_level_alloc_unittest$(EXEEXT) \
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__EXEEXT_27 = tcmalloc_and_profiler_unittest$(EXEEXT)
+am__EXEEXT_28 = low_level_alloc_unittest$(EXEEXT) \
atomicops_unittest$(EXEEXT) $(am__EXEEXT_9) \
tcmalloc_minimal_unittest$(EXEEXT) \
tcmalloc_minimal_large_unittest$(EXEEXT) $(am__EXEEXT_10) \
@@ -784,7 +811,9 @@ am__EXEEXT_24 = low_level_alloc_unittest$(EXEEXT) \
thread_dealloc_unittest$(EXEEXT) $(am__EXEEXT_14) \
$(am__EXEEXT_15) $(am__EXEEXT_16) $(am__EXEEXT_17) \
$(am__EXEEXT_18) $(am__EXEEXT_19) $(am__EXEEXT_20) \
- $(am__EXEEXT_21) $(am__EXEEXT_22) $(am__EXEEXT_23)
+ $(am__EXEEXT_21) $(am__EXEEXT_22) $(am__EXEEXT_23) \
+ $(am__EXEEXT_24) $(am__EXEEXT_25) $(am__EXEEXT_26) \
+ $(am__EXEEXT_27)
PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
am__addressmap_unittest_SOURCES_DIST = \
src/tests/addressmap_unittest.cc src/addressmap-inl.h \
@@ -913,7 +942,8 @@ am__low_level_alloc_unittest_SOURCES_DIST = \
src/maybe_threads.cc src/tests/low_level_alloc_unittest.cc \
src/base/low_level_alloc.h src/base/basictypes.h \
src/google/malloc_hook.h src/google/malloc_hook_c.h \
- src/malloc_hook-inl.h src/base/spinlock.h \
+ src/malloc_hook-inl.h src/malloc_hook_mmap_linux.h \
+ src/malloc_hook_mmap_freebsd.h src/base/spinlock.h \
src/base/spinlock_internal.h src/base/atomicops.h \
src/base/atomicops-internals-macosx.h \
src/base/atomicops-internals-linuxppc.h \
@@ -926,13 +956,15 @@ am__low_level_alloc_unittest_SOURCES_DIST = \
src/base/atomicops-internals-arm-v6plus.h src/base/logging.h \
src/base/commandlineflags.h src/base/dynamic_annotations.h \
src/third_party/valgrind.h
-am__objects_29 = $(am__objects_1) $(am__objects_1)
+@MINGW_FALSE@am__objects_29 = \
+@MINGW_FALSE@ low_level_alloc_unittest-maybe_threads.$(OBJEXT)
+am__objects_30 = $(am__objects_1) $(am__objects_1)
am_low_level_alloc_unittest_OBJECTS = \
low_level_alloc_unittest-low_level_alloc.$(OBJEXT) \
low_level_alloc_unittest-malloc_hook.$(OBJEXT) \
- low_level_alloc_unittest-maybe_threads.$(OBJEXT) \
+ $(am__objects_29) \
low_level_alloc_unittest-low_level_alloc_unittest.$(OBJEXT) \
- $(am__objects_29)
+ $(am__objects_30)
low_level_alloc_unittest_OBJECTS = \
$(am_low_level_alloc_unittest_OBJECTS)
low_level_alloc_unittest_DEPENDENCIES = $(am__DEPENDENCIES_2)
@@ -949,10 +981,10 @@ am__malloc_extension_debug_test_SOURCES_DIST = \
src/tests/malloc_extension_test.cc src/config_for_unittests.h \
src/base/logging.h src/google/malloc_extension.h \
src/google/malloc_extension_c.h
-am__objects_30 = \
+am__objects_31 = \
malloc_extension_debug_test-malloc_extension_test.$(OBJEXT)
@WITH_DEBUGALLOC_TRUE@am_malloc_extension_debug_test_OBJECTS = \
-@WITH_DEBUGALLOC_TRUE@ $(am__objects_30)
+@WITH_DEBUGALLOC_TRUE@ $(am__objects_31)
malloc_extension_debug_test_OBJECTS = \
$(am_malloc_extension_debug_test_OBJECTS)
@WITH_DEBUGALLOC_TRUE@malloc_extension_debug_test_DEPENDENCIES = \
@@ -985,24 +1017,22 @@ am__memalign_debug_unittest_SOURCES_DIST = \
src/tests/memalign_unittest.cc src/tcmalloc.h \
src/config_for_unittests.h src/tests/testutil.h \
src/tests/testutil.cc
-@MINGW_FALSE@am__objects_31 = memalign_debug_unittest-memalign_unittest.$(OBJEXT) \
-@MINGW_FALSE@ memalign_debug_unittest-testutil.$(OBJEXT)
-@WITH_DEBUGALLOC_TRUE@am_memalign_debug_unittest_OBJECTS = \
-@WITH_DEBUGALLOC_TRUE@ $(am__objects_31)
+@MINGW_FALSE@@OSX_FALSE@am__objects_32 = memalign_debug_unittest-memalign_unittest.$(OBJEXT) \
+@MINGW_FALSE@@OSX_FALSE@ memalign_debug_unittest-testutil.$(OBJEXT)
+@MINGW_FALSE@@OSX_FALSE@@WITH_DEBUGALLOC_TRUE@am_memalign_debug_unittest_OBJECTS = $(am__objects_32)
memalign_debug_unittest_OBJECTS = \
$(am_memalign_debug_unittest_OBJECTS)
-@WITH_DEBUGALLOC_TRUE@memalign_debug_unittest_DEPENDENCIES = \
-@WITH_DEBUGALLOC_TRUE@ libtcmalloc_minimal_debug.la \
-@WITH_DEBUGALLOC_TRUE@ $(am__DEPENDENCIES_1)
+@MINGW_FALSE@@OSX_FALSE@@WITH_DEBUGALLOC_TRUE@memalign_debug_unittest_DEPENDENCIES = libtcmalloc_minimal_debug.la \
+@MINGW_FALSE@@OSX_FALSE@@WITH_DEBUGALLOC_TRUE@ $(am__DEPENDENCIES_1)
am__memalign_unittest_SOURCES_DIST = src/tests/memalign_unittest.cc \
src/tcmalloc.h src/config_for_unittests.h src/tests/testutil.h \
src/tests/testutil.cc
-@MINGW_FALSE@am_memalign_unittest_OBJECTS = \
-@MINGW_FALSE@ memalign_unittest-memalign_unittest.$(OBJEXT) \
-@MINGW_FALSE@ memalign_unittest-testutil.$(OBJEXT)
+@MINGW_FALSE@@OSX_FALSE@am_memalign_unittest_OBJECTS = memalign_unittest-memalign_unittest.$(OBJEXT) \
+@MINGW_FALSE@@OSX_FALSE@ memalign_unittest-testutil.$(OBJEXT)
memalign_unittest_OBJECTS = $(am_memalign_unittest_OBJECTS)
-@MINGW_FALSE@memalign_unittest_DEPENDENCIES = $(am__DEPENDENCIES_5) \
-@MINGW_FALSE@ $(am__DEPENDENCIES_1)
+@MINGW_FALSE@@OSX_FALSE@memalign_unittest_DEPENDENCIES = \
+@MINGW_FALSE@@OSX_FALSE@ $(am__DEPENDENCIES_5) \
+@MINGW_FALSE@@OSX_FALSE@ $(am__DEPENDENCIES_1)
am_packed_cache_test_OBJECTS = \
packed_cache_test-packed-cache_test.$(OBJEXT)
packed_cache_test_OBJECTS = $(am_packed_cache_test_OBJECTS)
@@ -1039,31 +1069,31 @@ profiledata_unittest_OBJECTS = $(am_profiledata_unittest_OBJECTS)
am__profiler1_unittest_SOURCES_DIST = src/tests/profiler_unittest.cc \
src/tests/testutil.h src/tests/testutil.cc \
src/config_for_unittests.h src/google/profiler.h
-@WITH_CPU_PROFILER_TRUE@am__objects_32 = profiler1_unittest-profiler_unittest.$(OBJEXT) \
+@WITH_CPU_PROFILER_TRUE@am__objects_33 = profiler1_unittest-profiler_unittest.$(OBJEXT) \
@WITH_CPU_PROFILER_TRUE@ profiler1_unittest-testutil.$(OBJEXT) \
@WITH_CPU_PROFILER_TRUE@ $(am__objects_1)
@WITH_CPU_PROFILER_TRUE@am_profiler1_unittest_OBJECTS = \
-@WITH_CPU_PROFILER_TRUE@ $(am__objects_32)
+@WITH_CPU_PROFILER_TRUE@ $(am__objects_33)
profiler1_unittest_OBJECTS = $(am_profiler1_unittest_OBJECTS)
@WITH_CPU_PROFILER_TRUE@profiler1_unittest_DEPENDENCIES = \
@WITH_CPU_PROFILER_TRUE@ $(am__DEPENDENCIES_7)
am__profiler2_unittest_SOURCES_DIST = src/tests/profiler_unittest.cc \
src/tests/testutil.h src/tests/testutil.cc \
src/config_for_unittests.h src/google/profiler.h
-@WITH_CPU_PROFILER_TRUE@am__objects_33 = profiler2_unittest-profiler_unittest.$(OBJEXT) \
+@WITH_CPU_PROFILER_TRUE@am__objects_34 = profiler2_unittest-profiler_unittest.$(OBJEXT) \
@WITH_CPU_PROFILER_TRUE@ profiler2_unittest-testutil.$(OBJEXT) \
@WITH_CPU_PROFILER_TRUE@ $(am__objects_1)
@WITH_CPU_PROFILER_TRUE@am_profiler2_unittest_OBJECTS = \
-@WITH_CPU_PROFILER_TRUE@ $(am__objects_33)
+@WITH_CPU_PROFILER_TRUE@ $(am__objects_34)
profiler2_unittest_OBJECTS = $(am_profiler2_unittest_OBJECTS)
am__profiler3_unittest_SOURCES_DIST = src/tests/profiler_unittest.cc \
src/tests/testutil.h src/tests/testutil.cc \
src/config_for_unittests.h src/google/profiler.h
-@WITH_CPU_PROFILER_TRUE@am__objects_34 = profiler3_unittest-profiler_unittest.$(OBJEXT) \
+@WITH_CPU_PROFILER_TRUE@am__objects_35 = profiler3_unittest-profiler_unittest.$(OBJEXT) \
@WITH_CPU_PROFILER_TRUE@ profiler3_unittest-testutil.$(OBJEXT) \
@WITH_CPU_PROFILER_TRUE@ $(am__objects_1)
@WITH_CPU_PROFILER_TRUE@am_profiler3_unittest_OBJECTS = \
-@WITH_CPU_PROFILER_TRUE@ $(am__objects_34)
+@WITH_CPU_PROFILER_TRUE@ $(am__objects_35)
profiler3_unittest_OBJECTS = $(am_profiler3_unittest_OBJECTS)
@WITH_CPU_PROFILER_TRUE@profiler3_unittest_DEPENDENCIES = \
@WITH_CPU_PROFILER_TRUE@ $(am__DEPENDENCIES_7) \
@@ -1071,11 +1101,11 @@ profiler3_unittest_OBJECTS = $(am_profiler3_unittest_OBJECTS)
am__profiler4_unittest_SOURCES_DIST = src/tests/profiler_unittest.cc \
src/tests/testutil.h src/tests/testutil.cc \
src/config_for_unittests.h src/google/profiler.h
-@WITH_CPU_PROFILER_TRUE@am__objects_35 = profiler4_unittest-profiler_unittest.$(OBJEXT) \
+@WITH_CPU_PROFILER_TRUE@am__objects_36 = profiler4_unittest-profiler_unittest.$(OBJEXT) \
@WITH_CPU_PROFILER_TRUE@ profiler4_unittest-testutil.$(OBJEXT) \
@WITH_CPU_PROFILER_TRUE@ $(am__objects_1)
@WITH_CPU_PROFILER_TRUE@am_profiler4_unittest_OBJECTS = \
-@WITH_CPU_PROFILER_TRUE@ $(am__objects_35)
+@WITH_CPU_PROFILER_TRUE@ $(am__objects_36)
profiler4_unittest_OBJECTS = $(am_profiler4_unittest_OBJECTS)
am__profiler_unittest_sh_SOURCES_DIST = \
src/tests/profiler_unittest.sh
@@ -1091,9 +1121,9 @@ raw_printer_test_OBJECTS = $(am_raw_printer_test_OBJECTS)
am__realloc_debug_unittest_SOURCES_DIST = \
src/tests/realloc_unittest.cc src/config_for_unittests.h \
src/base/logging.h
-am__objects_36 = realloc_debug_unittest-realloc_unittest.$(OBJEXT)
+am__objects_37 = realloc_debug_unittest-realloc_unittest.$(OBJEXT)
@WITH_DEBUGALLOC_TRUE@am_realloc_debug_unittest_OBJECTS = \
-@WITH_DEBUGALLOC_TRUE@ $(am__objects_36)
+@WITH_DEBUGALLOC_TRUE@ $(am__objects_37)
realloc_debug_unittest_OBJECTS = $(am_realloc_debug_unittest_OBJECTS)
@WITH_DEBUGALLOC_TRUE@realloc_debug_unittest_DEPENDENCIES = \
@WITH_DEBUGALLOC_TRUE@ libtcmalloc_minimal_debug.la \
@@ -1105,8 +1135,8 @@ realloc_unittest_DEPENDENCIES = $(am__DEPENDENCIES_5) \
$(am__DEPENDENCIES_1)
am__sampler_debug_test_SOURCES_DIST = src/tests/sampler_test.cc \
src/config_for_unittests.h
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_37 = sampler_debug_test-sampler_test.$(OBJEXT)
-@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_sampler_debug_test_OBJECTS = $(am__objects_37)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_38 = sampler_debug_test-sampler_test.$(OBJEXT)
+@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_sampler_debug_test_OBJECTS = $(am__objects_38)
sampler_debug_test_OBJECTS = $(am_sampler_debug_test_OBJECTS)
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampler_debug_test_DEPENDENCIES = libtcmalloc_debug.la \
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1)
@@ -1120,9 +1150,9 @@ sampler_test_OBJECTS = $(am_sampler_test_OBJECTS)
am__sampling_debug_test_SOURCES_DIST = src/tests/sampling_test.cc \
src/config_for_unittests.h src/base/logging.h \
src/google/malloc_extension.h
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_38 = sampling_debug_test-sampling_test.$(OBJEXT) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_39 = sampling_debug_test-sampling_test.$(OBJEXT) \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_1)
-@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_sampling_debug_test_OBJECTS = $(am__objects_38)
+@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_sampling_debug_test_OBJECTS = $(am__objects_39)
sampling_debug_test_OBJECTS = $(am_sampling_debug_test_OBJECTS)
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@sampling_debug_test_DEPENDENCIES = libtcmalloc_debug.la \
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1)
@@ -1152,16 +1182,17 @@ am__stacktrace_unittest_SOURCES_DIST = \
src/tests/stacktrace_unittest.cc src/config_for_unittests.h \
src/base/commandlineflags.h src/stacktrace_config.h \
src/stacktrace_generic-inl.h src/stacktrace_libunwind-inl.h \
- src/stacktrace_powerpc-inl.h src/stacktrace_x86_64-inl.h \
- src/stacktrace_x86-inl.h src/stacktrace_win32-inl.h \
+ src/stacktrace_nacl-inl.h src/stacktrace_powerpc-inl.h \
+ src/stacktrace_x86_64-inl.h src/stacktrace_x86-inl.h \
+ src/stacktrace_win32-inl.h src/base/elf_mem_image.h \
src/base/vdso_support.h src/google/stacktrace.h \
src/base/logging.h src/base/basictypes.h \
src/base/dynamic_annotations.h src/third_party/valgrind.h
-@WITH_STACK_TRACE_TRUE@am__objects_39 = $(am__objects_4) \
+@WITH_STACK_TRACE_TRUE@am__objects_40 = $(am__objects_4) \
@WITH_STACK_TRACE_TRUE@ $(am__objects_1)
@WITH_STACK_TRACE_TRUE@am_stacktrace_unittest_OBJECTS = \
@WITH_STACK_TRACE_TRUE@ stacktrace_unittest.$(OBJEXT) \
-@WITH_STACK_TRACE_TRUE@ $(am__objects_39)
+@WITH_STACK_TRACE_TRUE@ $(am__objects_40)
stacktrace_unittest_OBJECTS = $(am_stacktrace_unittest_OBJECTS)
@WITH_STACK_TRACE_TRUE@stacktrace_unittest_DEPENDENCIES = \
@WITH_STACK_TRACE_TRUE@ libstacktrace.la liblogging.la
@@ -1175,10 +1206,10 @@ am__tcmalloc_and_profiler_unittest_SOURCES_DIST = \
src/tests/tcmalloc_unittest.cc src/tests/testutil.h \
src/tests/testutil.cc src/config_for_unittests.h \
src/google/malloc_extension.h
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_40 = tcmalloc_and_profiler_unittest-tcmalloc_unittest.$(OBJEXT) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_41 = tcmalloc_and_profiler_unittest-tcmalloc_unittest.$(OBJEXT) \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_and_profiler_unittest-testutil.$(OBJEXT) \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_1)
-@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_tcmalloc_and_profiler_unittest_OBJECTS = $(am__objects_40)
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_tcmalloc_and_profiler_unittest_OBJECTS = $(am__objects_41)
tcmalloc_and_profiler_unittest_OBJECTS = \
$(am_tcmalloc_and_profiler_unittest_OBJECTS)
@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_and_profiler_unittest_DEPENDENCIES = libtcmalloc_and_profiler.la
@@ -1186,27 +1217,29 @@ am__tcmalloc_both_unittest_SOURCES_DIST = \
src/tests/tcmalloc_unittest.cc src/tests/testutil.h \
src/tests/testutil.cc src/config_for_unittests.h \
src/google/malloc_extension.h
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_tcmalloc_both_unittest_OBJECTS = tcmalloc_both_unittest-tcmalloc_unittest.$(OBJEXT) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_42 = tcmalloc_both_unittest-tcmalloc_unittest.$(OBJEXT) \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_both_unittest-testutil.$(OBJEXT) \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_1)
+@OSX_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_tcmalloc_both_unittest_OBJECTS = $(am__objects_42)
tcmalloc_both_unittest_OBJECTS = $(am_tcmalloc_both_unittest_OBJECTS)
-@WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_DEPENDENCIES = $(am__DEPENDENCIES_6) \
+@WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__DEPENDENCIES_8 = $(am__DEPENDENCIES_6) \
@WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_5) \
@WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ liblogging.la \
@WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1)
-@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_DEPENDENCIES = $(am__DEPENDENCIES_6) \
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__DEPENDENCIES_8 = $(am__DEPENDENCIES_6) \
@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_5) \
@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libprofiler.la \
@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ liblogging.la \
@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__DEPENDENCIES_1)
+@OSX_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_DEPENDENCIES = $(am__DEPENDENCIES_8)
am__tcmalloc_debug_unittest_SOURCES_DIST = \
src/tests/tcmalloc_unittest.cc src/tcmalloc.h \
src/tests/testutil.h src/tests/testutil.cc \
src/config_for_unittests.h src/google/malloc_extension.h
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_41 = tcmalloc_debug_unittest-tcmalloc_unittest.$(OBJEXT) \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am__objects_43 = tcmalloc_debug_unittest-tcmalloc_unittest.$(OBJEXT) \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ tcmalloc_debug_unittest-testutil.$(OBJEXT) \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__objects_1)
-@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_tcmalloc_debug_unittest_OBJECTS = $(am__objects_41)
+@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@am_tcmalloc_debug_unittest_OBJECTS = $(am__objects_43)
tcmalloc_debug_unittest_OBJECTS = \
$(am_tcmalloc_debug_unittest_OBJECTS)
@WITH_DEBUGALLOC_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_debug_unittest_DEPENDENCIES = libtcmalloc_debug.la \
@@ -1223,12 +1256,12 @@ am__tcmalloc_minimal_debug_unittest_SOURCES_DIST = \
src/tests/tcmalloc_unittest.cc src/tests/testutil.h \
src/tests/testutil.cc src/config_for_unittests.h \
src/google/malloc_extension.h
-am__objects_42 = \
+am__objects_44 = \
tcmalloc_minimal_debug_unittest-tcmalloc_unittest.$(OBJEXT) \
tcmalloc_minimal_debug_unittest-testutil.$(OBJEXT) \
$(am__objects_1)
@WITH_DEBUGALLOC_TRUE@am_tcmalloc_minimal_debug_unittest_OBJECTS = \
-@WITH_DEBUGALLOC_TRUE@ $(am__objects_42)
+@WITH_DEBUGALLOC_TRUE@ $(am__objects_44)
tcmalloc_minimal_debug_unittest_OBJECTS = \
$(am_tcmalloc_minimal_debug_unittest_OBJECTS)
@WITH_DEBUGALLOC_TRUE@tcmalloc_minimal_debug_unittest_DEPENDENCIES = \
@@ -1505,6 +1538,8 @@ GCC_TRUE = @GCC_TRUE@
GREP = @GREP@
HAVE_OBJCOPY_WEAKEN_FALSE = @HAVE_OBJCOPY_WEAKEN_FALSE@
HAVE_OBJCOPY_WEAKEN_TRUE = @HAVE_OBJCOPY_WEAKEN_TRUE@
+HAVE_W_NO_UNUSED_RESULT_FALSE = @HAVE_W_NO_UNUSED_RESULT_FALSE@
+HAVE_W_NO_UNUSED_RESULT_TRUE = @HAVE_W_NO_UNUSED_RESULT_TRUE@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
@@ -1528,6 +1563,8 @@ NMEDIT = @NMEDIT@
OBJCOPY = @OBJCOPY@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
+OSX_FALSE = @OSX_FALSE@
+OSX_TRUE = @OSX_TRUE@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
@@ -1627,7 +1664,8 @@ ACLOCAL_AMFLAGS = -I m4
AM_CPPFLAGS = -I$(top_srcdir)/src $(am__append_1)
# This is mostly based on configure options
-AM_CXXFLAGS = $(am__append_2) $(am__append_3) $(am__append_4)
+AM_CXXFLAGS = $(am__append_2) $(am__append_3) $(am__append_4) \
+ $(am__append_5)
# The -no-undefined flag allows libtool to generate shared libraries for
# Cygwin and MinGW. LIBSTDCXX_LA_LINKER_FLAG is used to fix a Solaris bug.
@@ -1646,7 +1684,7 @@ AM_LDFLAGS = -no-undefined $(LIBSTDCXX_LA_LINKER_FLAG)
# accomplishes its tasks via patching, leaving no work for the linker
# to identify, so the linker will ignore libtcmalloc by default unless
# we explicitly create a dependency via -u.
-TCMALLOC_FLAGS = $(am__append_5)
+TCMALLOC_FLAGS = $(am__append_6)
@HAVE_OBJCOPY_WEAKEN_FALSE@WEAKEN = :
# If we have objcopy, make malloc/free/etc weak symbols. That way folks
@@ -1664,15 +1702,15 @@ TCMALLOC_FLAGS = $(am__append_5)
@HAVE_OBJCOPY_WEAKEN_TRUE@ -W __Znwm -W __ZnwmRKSt9nothrow_t -W __Znam -W __ZnamRKSt9nothrow_t \
@HAVE_OBJCOPY_WEAKEN_TRUE@ -W __ZdlPv -W __ZdaPv
-LIBS_TO_WEAKEN = libtcmalloc_minimal.la $(am__append_23) \
- $(am__append_34) $(am__append_49) $(am__append_64)
+LIBS_TO_WEAKEN = libtcmalloc_minimal.la $(am__append_24) \
+ $(am__append_37) $(am__append_54) $(am__append_69)
googleincludedir = $(includedir)/google
# The .h files you want to install (that is, .h files that people
# who install this package can include in their own applications.)
# We'll add to this later, on a library-by-library basis
-googleinclude_HEADERS = $(am__append_9) \
- $(SG_TCMALLOC_MINIMAL_INCLUDES) $(am__append_28) \
- $(am__append_56)
+googleinclude_HEADERS = $(am__append_10) \
+ $(SG_TCMALLOC_MINIMAL_INCLUDES) $(am__append_31) \
+ $(am__append_61)
# tcmalloc.h is a special case, because it's a .h.in file
nodist_googleinclude_HEADERS = src/google/tcmalloc.h
noinst_HEADERS = src/google/tcmalloc.h.in
@@ -1689,7 +1727,7 @@ noinst_HEADERS = src/google/tcmalloc.h.in
# end of the world.
dist_doc_DATA = AUTHORS COPYING ChangeLog INSTALL NEWS README \
README_windows.txt TODO doc/index.html doc/designstyle.css \
- $(am__append_12) doc/tcmalloc.html doc/overview.gif \
+ $(am__append_13) doc/tcmalloc.html doc/overview.gif \
doc/pageheap.gif doc/spanmap.gif doc/threadheap.gif \
doc/t-test1.times.txt \
doc/tcmalloc-opspercpusec.vs.threads.1024.bytes.png \
@@ -1714,13 +1752,13 @@ dist_doc_DATA = AUTHORS COPYING ChangeLog INSTALL NEWS README \
doc/tcmalloc-opspersec.vs.size.5.threads.png \
doc/tcmalloc-opspersec.vs.size.8.threads.png doc/overview.dot \
doc/pageheap.dot doc/spanmap.dot doc/threadheap.dot \
- $(am__append_46) $(am__append_47) $(am__append_61)
+ $(am__append_51) $(am__append_52) $(am__append_66)
# The libraries (.so's) you want to install
# We'll add to this later, on a library-by-library basis
-lib_LTLIBRARIES = libtcmalloc_minimal.la $(am__append_22) \
- $(am__append_30) $(am__append_48) $(am__append_57) \
- $(am__append_62)
+lib_LTLIBRARIES = libtcmalloc_minimal.la $(am__append_23) \
+ $(am__append_33) $(am__append_53) $(am__append_62) \
+ $(am__append_67)
# This is for 'convenience libraries' -- basically just a container for sources
### Making the library
@@ -1729,12 +1767,12 @@ lib_LTLIBRARIES = libtcmalloc_minimal.la $(am__append_22) \
# for all files in this library -- except tcmalloc.cc which needs them
# to fulfill its API. Automake doesn't allow per-file CXXFLAGS, so we need
# to separate into two libraries.
-noinst_LTLIBRARIES = liblogging.la libsysinfo.la $(am__append_6) \
- $(am__append_8) $(am__append_10) \
- libtcmalloc_minimal_internal.la $(am__append_29)
+noinst_LTLIBRARIES = liblogging.la libsysinfo.la $(am__append_7) \
+ $(am__append_9) $(am__append_11) \
+ libtcmalloc_minimal_internal.la $(am__append_32)
WINDOWS_PROJECTS = google-perftools.sln \
vsprojects/low_level_alloc_unittest/low_level_alloc_unittest.vcproj \
- $(am__append_14) \
+ $(am__append_15) \
vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcproj \
vsprojects/tcmalloc_minimal_unittest/tcmalloc_minimal_unittest.vcproj \
vsprojects/tmu-static/tmu-static.vcproj \
@@ -1751,7 +1789,7 @@ WINDOWS_PROJECTS = google-perftools.sln \
vsprojects/realloc_unittest/realloc_unittest.vcproj \
vsprojects/stack_trace_table_test/stack_trace_table_test.vcproj \
vsprojects/thread_dealloc_unittest/thread_dealloc_unittest.vcproj \
- $(am__append_37)
+ $(am__append_42)
# unittests you want to run when people type 'make check'.
# Note: tests cannot take any arguments!
@@ -1770,25 +1808,26 @@ WINDOWS_PROJECTS = google-perftools.sln \
# standard libc! At least, in some situations, some of the time.
# These all tests components of tcmalloc_minimal
-TESTS = low_level_alloc_unittest atomicops_unittest $(am__append_11) \
+TESTS = low_level_alloc_unittest atomicops_unittest $(am__append_12) \
tcmalloc_minimal_unittest tcmalloc_minimal_large_unittest \
- $(am__append_15) addressmap_unittest $(am__append_18) \
+ $(am__append_16) addressmap_unittest $(am__append_19) \
packed_cache_test frag_unittest markidle_unittest \
current_allocated_bytes_test malloc_hook_test \
- malloc_extension_test $(am__append_19) $(am__append_21) \
+ malloc_extension_test $(am__append_20) $(am__append_22) \
page_heap_test pagemap_unittest realloc_unittest \
stack_trace_table_test thread_dealloc_unittest \
- $(am__append_24) $(am__append_25) $(am__append_35) \
- $(am__append_40) $(am__append_43) $(am__append_50) \
- $(am__append_52) $(am__append_54) $(am__append_58) \
- $(am__append_63)
+ $(am__append_25) $(am__append_26) $(am__append_27) \
+ $(am__append_28) $(am__append_38) $(am__append_39) \
+ $(am__append_40) $(am__append_45) $(am__append_48) \
+ $(am__append_55) $(am__append_57) $(am__append_59) \
+ $(am__append_63) $(am__append_68)
# TESTS_ENVIRONMENT sets environment variables for when you run unittest.
# We always get "srcdir" set for free.
# We'll add to this later, on a library-by-library basis.
-TESTS_ENVIRONMENT = $(am__append_13) $(am__append_36)
+TESTS_ENVIRONMENT = $(am__append_14) $(am__append_41)
# All script tests should be added here
-noinst_SCRIPTS = $(am__append_16) $(am__append_26) $(am__append_38) \
- $(am__append_41) $(am__append_44) $(am__append_59)
+noinst_SCRIPTS = $(am__append_17) $(am__append_29) $(am__append_43) \
+ $(am__append_46) $(am__append_49) $(am__append_64)
# This is my own var, used for extra libraries I make that I need installed
EXTRA_INSTALL =
@@ -1816,7 +1855,7 @@ SYSINFO_INCLUDES = src/base/sysinfo.h \
libsysinfo_la_SOURCES = src/base/sysinfo.cc \
$(SYSINFO_INCLUDES)
-libsysinfo_la_LIBADD = $(NANOSLEEP_LIBS) $(am__append_7)
+libsysinfo_la_LIBADD = $(NANOSLEEP_LIBS) $(am__append_8)
# For MinGW, we use also have to use libwindows Luckily, we need the
# windows.a library in exactly the same place we need spinlock.a
@@ -1891,12 +1930,14 @@ LOW_LEVEL_ALLOC_UNITTEST_INCLUDES = src/base/low_level_alloc.h \
src/google/malloc_hook.h \
src/google/malloc_hook_c.h \
src/malloc_hook-inl.h \
+ src/malloc_hook_mmap_linux.h \
+ src/malloc_hook_mmap_freebsd.h \
$(SPINLOCK_INCLUDES) \
$(LOGGING_INCLUDES)
low_level_alloc_unittest_SOURCES = src/base/low_level_alloc.cc \
src/malloc_hook.cc \
- src/maybe_threads.cc \
+ $(MAYBE_THREADS_CC) \
src/tests/low_level_alloc_unittest.cc \
$(LOW_LEVEL_ALLOC_UNITTEST_INCLUDES)
@@ -1921,15 +1962,18 @@ atomicops_unittest_LDADD = $(LIBSPINLOCK)
@WITH_STACK_TRACE_TRUE@S_STACKTRACE_INCLUDES = src/stacktrace_config.h \
@WITH_STACK_TRACE_TRUE@ src/stacktrace_generic-inl.h \
@WITH_STACK_TRACE_TRUE@ src/stacktrace_libunwind-inl.h \
+@WITH_STACK_TRACE_TRUE@ src/stacktrace_nacl-inl.h \
@WITH_STACK_TRACE_TRUE@ src/stacktrace_powerpc-inl.h \
@WITH_STACK_TRACE_TRUE@ src/stacktrace_x86_64-inl.h \
@WITH_STACK_TRACE_TRUE@ src/stacktrace_x86-inl.h \
@WITH_STACK_TRACE_TRUE@ src/stacktrace_win32-inl.h \
+@WITH_STACK_TRACE_TRUE@ src/base/elf_mem_image.h \
@WITH_STACK_TRACE_TRUE@ src/base/vdso_support.h
@WITH_STACK_TRACE_TRUE@SG_STACKTRACE_INCLUDES = src/google/stacktrace.h
@WITH_STACK_TRACE_TRUE@STACKTRACE_INCLUDES = $(S_STACKTRACE_INCLUDES) $(SG_STACKTRACE_INCLUDES)
@WITH_STACK_TRACE_TRUE@libstacktrace_la_SOURCES = src/stacktrace.cc \
+@WITH_STACK_TRACE_TRUE@ src/base/elf_mem_image.cc \
@WITH_STACK_TRACE_TRUE@ src/base/vdso_support.cc \
@WITH_STACK_TRACE_TRUE@ $(STACKTRACE_INCLUDES)
@@ -1972,6 +2016,11 @@ S_TCMALLOC_MINIMAL_INCLUDES = src/common.h \
src/sampler.h \
src/central_freelist.h \
src/linked_list.h \
+ src/libc_override.h \
+ src/libc_override_gcc_and_weak.h \
+ src/libc_override_glibc.h \
+ src/libc_override_osx.h \
+ src/libc_override_redefine.h \
src/page_heap.h \
src/page_heap_allocator.h \
src/span.h \
@@ -1981,6 +2030,8 @@ S_TCMALLOC_MINIMAL_INCLUDES = src/common.h \
src/stack_trace_table.h \
src/base/thread_annotations.h \
src/malloc_hook-inl.h \
+ src/malloc_hook_mmap_linux.h \
+ src/malloc_hook_mmap_freebsd.h \
src/maybe_threads.h
SG_TCMALLOC_MINIMAL_INCLUDES = src/google/malloc_hook.h \
@@ -2055,7 +2106,7 @@ ADDRESSMAP_UNITTEST_INCLUDES = src/addressmap-inl.h \
$(LOGGING_INCLUDES)
addressmap_unittest_SOURCES = src/tests/addressmap_unittest.cc \
- $(ADDRESSMAP_UNITTEST_INCLUDES) $(am__append_17)
+ $(ADDRESSMAP_UNITTEST_INCLUDES) $(am__append_18)
addressmap_unittest_CXXFLAGS = -g $(AM_CXXFLAGS)
addressmap_unittest_LDADD = liblogging.la
@MINGW_FALSE@system_alloc_unittest_SOURCES = src/config_for_unittests.h \
@@ -2110,17 +2161,17 @@ malloc_extension_test_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
@ENABLE_STATIC_FALSE@@MINGW_FALSE@malloc_extension_c_test_CFLAGS = \
@ENABLE_STATIC_FALSE@@MINGW_FALSE@ $(PTHREAD_CFLAGS) \
@ENABLE_STATIC_FALSE@@MINGW_FALSE@ $(AM_CFLAGS) \
-@ENABLE_STATIC_FALSE@@MINGW_FALSE@ $(am__append_20)
+@ENABLE_STATIC_FALSE@@MINGW_FALSE@ $(am__append_21)
@ENABLE_STATIC_FALSE@@MINGW_FALSE@malloc_extension_c_test_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
@ENABLE_STATIC_FALSE@@MINGW_FALSE@malloc_extension_c_test_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
-@MINGW_FALSE@memalign_unittest_SOURCES = src/tests/memalign_unittest.cc \
-@MINGW_FALSE@ src/tcmalloc.h \
-@MINGW_FALSE@ src/config_for_unittests.h \
-@MINGW_FALSE@ src/tests/testutil.h src/tests/testutil.cc
-
-@MINGW_FALSE@memalign_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-@MINGW_FALSE@memalign_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
-@MINGW_FALSE@memalign_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
+@MINGW_FALSE@@OSX_FALSE@memalign_unittest_SOURCES = src/tests/memalign_unittest.cc \
+@MINGW_FALSE@@OSX_FALSE@ src/tcmalloc.h \
+@MINGW_FALSE@@OSX_FALSE@ src/config_for_unittests.h \
+@MINGW_FALSE@@OSX_FALSE@ src/tests/testutil.h src/tests/testutil.cc
+
+@MINGW_FALSE@@OSX_FALSE@memalign_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@MINGW_FALSE@@OSX_FALSE@memalign_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+@MINGW_FALSE@@OSX_FALSE@memalign_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
page_heap_test_SOURCES = src/tests/page_heap_test.cc \
src/config_for_unittests.h \
src/base/logging.h \
@@ -2179,10 +2230,10 @@ thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
@WITH_DEBUGALLOC_TRUE@malloc_extension_debug_test_CXXFLAGS = $(malloc_extension_test_CXXFLAGS)
@WITH_DEBUGALLOC_TRUE@malloc_extension_debug_test_LDFLAGS = $(malloc_extension_test_LDFLAGS)
@WITH_DEBUGALLOC_TRUE@malloc_extension_debug_test_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS)
-@WITH_DEBUGALLOC_TRUE@memalign_debug_unittest_SOURCES = $(memalign_unittest_SOURCES)
-@WITH_DEBUGALLOC_TRUE@memalign_debug_unittest_CXXFLAGS = $(memalign_unittest_CXXFLAGS)
-@WITH_DEBUGALLOC_TRUE@memalign_debug_unittest_LDFLAGS = $(memalign_unittest_LDFLAGS)
-@WITH_DEBUGALLOC_TRUE@memalign_debug_unittest_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS)
+@MINGW_FALSE@@OSX_FALSE@@WITH_DEBUGALLOC_TRUE@memalign_debug_unittest_SOURCES = $(memalign_unittest_SOURCES)
+@MINGW_FALSE@@OSX_FALSE@@WITH_DEBUGALLOC_TRUE@memalign_debug_unittest_CXXFLAGS = $(memalign_unittest_CXXFLAGS)
+@MINGW_FALSE@@OSX_FALSE@@WITH_DEBUGALLOC_TRUE@memalign_debug_unittest_LDFLAGS = $(memalign_unittest_LDFLAGS)
+@MINGW_FALSE@@OSX_FALSE@@WITH_DEBUGALLOC_TRUE@memalign_debug_unittest_LDADD = libtcmalloc_minimal_debug.la $(PTHREAD_LIBS)
@WITH_DEBUGALLOC_TRUE@realloc_debug_unittest_SOURCES = $(realloc_unittest_SOURCES)
@WITH_DEBUGALLOC_TRUE@realloc_debug_unittest_CXXFLAGS = $(realloc_unittest_CXXFLAGS)
@WITH_DEBUGALLOC_TRUE@realloc_debug_unittest_LDFLAGS = $(realloc_unittest_LDFLAGS)
@@ -2226,17 +2277,17 @@ thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(PTHREAD_CFLAGS) -DNDEBUG \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(AM_CXXFLAGS) \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(NO_EXCEPTIONS) \
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_32)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_35)
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_internal_la_LDFLAGS = $(PTHREAD_CFLAGS)
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_internal_la_LIBADD = libstacktrace.la $(PTHREAD_LIBS)
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_SOURCES = \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(TCMALLOC_CC) \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(TCMALLOC_INCLUDES) \
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_31)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_34)
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_CXXFLAGS = \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(PTHREAD_CFLAGS) -DNDEBUG \
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(AM_CXXFLAGS) \
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_33)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(am__append_36)
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_LDFLAGS = $(PTHREAD_CFLAGS) -version-info @TCMALLOC_SO_VERSION@
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_la_LIBADD = libtcmalloc_internal.la $(PTHREAD_LIBS)
@WITH_HEAP_CHECKER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@HEAP_CHECKER_SOURCES =
@@ -2269,14 +2320,22 @@ thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
# implementations define their own malloc, and we need to go on the
# first linkline to make sure our malloc 'wins'.
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_unittest_LDADD = $(LIBTCMALLOC) liblogging.la $(PTHREAD_LIBS)
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/tests/testutil.h src/tests/testutil.cc \
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(TCMALLOC_UNITTEST_INCLUDES)
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
-@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
-@WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
-@WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ liblogging.la $(PTHREAD_LIBS)
+# This makes sure it's safe to link in both tcmalloc and
+# tcmalloc_minimal. (One would never do this on purpose, but perhaps
+# by accident...) When we can compile libprofiler, we also link it in
+# to make sure that works too. NOTE: On OS X, it's *not* safe to
+# link both in (we end up with two copies of every global var, and
+# the code tends to pick one arbitrarily), so don't run the test there.
+# (We define these outside the 'if' because they're reused below.)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_srcs = src/tests/tcmalloc_unittest.cc \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ src/tests/testutil.h src/tests/testutil.cc \
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ $(TCMALLOC_UNITTEST_INCLUDES)
+
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_cflags = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
+@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_lflags = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
+@WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_ladd = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
+@WITH_CPU_PROFILER_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ liblogging.la $(PTHREAD_LIBS)
# We want libtcmalloc last on the link line, but due to a bug in
# libtool involving convenience libs, they need to come last on the
@@ -2285,9 +2344,13 @@ thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
# We also put pthreads after tcmalloc, because some pthread
# implementations define their own malloc, and we need to go on the
# first linkline to make sure our malloc 'wins'.
-@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_LDADD = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
-@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libprofiler.la liblogging.la $(PTHREAD_LIBS)
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_ladd = $(LIBTCMALLOC) $(LIBTCMALLOC_MINIMAL) \
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@ libprofiler.la liblogging.la $(PTHREAD_LIBS)
+@OSX_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_SOURCES = $(tcmalloc_both_unittest_srcs)
+@OSX_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_CXXFLAGS = $(tcmalloc_both_unittest_cflags)
+@OSX_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_LDFLAGS = $(tcmalloc_both_unittest_lflags)
+@OSX_FALSE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_both_unittest_LDADD = $(tcmalloc_both_unittest_ladd)
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_large_unittest_SOURCES = src/tests/tcmalloc_large_unittest.cc
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_large_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_large_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
@@ -2475,9 +2538,9 @@ thread_dealloc_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
# libstacktrace.la, which we already get via libtcmalloc. Trying to
# specify it twice causes link-time duplicate-definition errors. :-(
@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@libtcmalloc_and_profiler_la_LIBADD = $(libtcmalloc_la_LIBADD)
-@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_and_profiler_unittest_SOURCES = $(tcmalloc_both_unittest_SOURCES)
-@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_and_profiler_unittest_CXXFLAGS = $(tcmalloc_both_unittest_CXXFLAGS)
-@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_and_profiler_unittest_LDFLAGS = $(tcmalloc_both_unittest_LDFLAGS)
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_and_profiler_unittest_SOURCES = $(tcmalloc_both_unittest_srcs)
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_and_profiler_unittest_CXXFLAGS = $(tcmalloc_both_unittest_cflags)
+@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_and_profiler_unittest_LDFLAGS = $(tcmalloc_both_unittest_lflags)
@WITH_CPU_PROFILER_TRUE@@WITH_HEAP_PROFILER_OR_CHECKER_TRUE@tcmalloc_and_profiler_unittest_LDADD = libtcmalloc_and_profiler.la
# http://linux.die.net/man/1/pkg-config, http://pkg-config.freedesktop.org/wiki
@@ -2865,6 +2928,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/current_allocated_bytes_test-current_allocated_bytes_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debugallocation_test-debugallocation_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynamic_annotations.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf_mem_image.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/frag_unittest-frag_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getpc_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heap_checker_debug_unittest-heap-checker_unittest.Po@am__quote@
@@ -3121,6 +3185,13 @@ stacktrace.lo: src/stacktrace.cc
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o stacktrace.lo `test -f 'src/stacktrace.cc' || echo '$(srcdir)/'`src/stacktrace.cc
+elf_mem_image.lo: src/base/elf_mem_image.cc
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT elf_mem_image.lo -MD -MP -MF "$(DEPDIR)/elf_mem_image.Tpo" -c -o elf_mem_image.lo `test -f 'src/base/elf_mem_image.cc' || echo '$(srcdir)/'`src/base/elf_mem_image.cc; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/elf_mem_image.Tpo" "$(DEPDIR)/elf_mem_image.Plo"; else rm -f "$(DEPDIR)/elf_mem_image.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/base/elf_mem_image.cc' object='elf_mem_image.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o elf_mem_image.lo `test -f 'src/base/elf_mem_image.cc' || echo '$(srcdir)/'`src/base/elf_mem_image.cc
+
vdso_support.lo: src/base/vdso_support.cc
@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT vdso_support.lo -MD -MP -MF "$(DEPDIR)/vdso_support.Tpo" -c -o vdso_support.lo `test -f 'src/base/vdso_support.cc' || echo '$(srcdir)/'`src/base/vdso_support.cc; \
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/vdso_support.Tpo" "$(DEPDIR)/vdso_support.Plo"; else rm -f "$(DEPDIR)/vdso_support.Tpo"; exit 1; fi
@@ -5014,8 +5085,8 @@ libtcmalloc.pc: Makefile packages/rpm/rpm.spec
echo '' >> "$@".tmp
echo 'Name: $(PACKAGE)' >> "$@".tmp
echo 'Version: $(VERSION)' >> "$@".tmp
- -grep '^Summary:' packages/rpm/rpm.spec | sed s/^Summary:/Description:/ | head -n1 >> "$@".tmp
- -grep '^URL: ' packages/rpm/rpm.spec >> "$@".tmp
+ -grep '^Summary:' $(top_srcdir)/packages/rpm/rpm.spec | sed s/^Summary:/Description:/ | head -n1 >> "$@".tmp
+ -grep '^URL: ' $(top_srcdir)/packages/rpm/rpm.spec >> "$@".tmp
echo 'Requires:' >> "$@".tmp
echo 'Libs: -L$${libdir} -ltcmalloc' >> "$@".tmp
echo 'Libs.private: $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)' >> "$@".tmp
diff --git a/NEWS b/NEWS
index 62a2f62..52bb1fb 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,35 @@
-== 7 February 2011 ==
+== 15 July 2011 ==
+
+I've just released perftools 1.8
+
+Of the many changes in this release, a good number pertain to porting.
+I've revamped OS X support to use the malloc-zone framework; it should
+now Just Work to link in tcmalloc, without needing
+`DYLD_FORCE_FLAT_NAMESPACE` or the like. (This is a pretty major
+change, so please feel free to report feedback at
+google-perftools@googlegroups.com.) 64-bit Windows support is also
+improved, as is ARM support, and the hooks are in place to improve
+FreeBSD support as well.
+
+On the other hand, I'm seeing hanging tests on Cygwin. I see the same
+hanging even with (the old) perftools 1.7, so I'm guessing this is
+either a problem specific to my Cygwin installation, or nobody is
+trying to use perftools under Cygwin. If you can reproduce the
+problem, and even better have a solution, you can report it at
+google-perftools@googlegroups.com.
+
+Internal changes include several performance and space-saving tweaks.
+One is user-visible (but in "stealth mode", and otherwise
+undocumented): you can compile with `-DTCMALLOC_SMALL_BUT_SLOW`. In
+this mode, tcmalloc will use less memory overhead, at the cost of
+running (likely not noticeably) slower.
+
+There are many other changes as well, too numerous to recount here,
+but present in the
+[http://google-perftools.googlecode.com/svn/tags/perftools-1.8/ChangeLog ChangeLog].
+
+
+=== 7 February 2011 ===
Thanks to endlessr..., who
[http://code.google.com/p/google-perftools/issues/detail?id=307 identified]
@@ -9,7 +40,7 @@ some aggressive optimizations used in MSVC 10. I'll fix the test, but in
the meantime, feel free to use perftools even when compiled under MSVC
10.
-== 4 February 2011 ==
+=== 4 February 2011 ===
I've just released perftools 1.7
diff --git a/README b/README
index 21b18d5..204562a 100644
--- a/README
+++ b/README
@@ -204,28 +204,6 @@ that error. To fix it, just comment out (or delete) the line
in your config.h file before building.
-OS X ISSUES
------------
-
-You may need to set the environment variable DYLD_FORCE_FLAT_NAMESPACE
-to use perftools with OS X. Because of how OS X does symbol binding,
-libc routines will use libc malloc even when the binary is linked with
--ltcmalloc. This is not usually a problem, but becomes one if the
-application is responsible for freeing that memory: the application
-will use tcmalloc's free() to try to free memory allocated with libc's
-malloc(), which will cause no end of confusion.
-
-One (or both) of these workaround may fix the problem:
- DYLD_FORCE_FLAT_NAMESPACE=1 myapp
- DYLD_INSERT_LIBRARIES=path/to/libtcmalloc.dylib myapp
-
-The best solution may depend on the version of OS X being used.
-Neither solution is likely to work if you dlopen() libraries from
-within your application. If you have any experience with this, we'd
-appreciate you sharing it at
- http://groups.google.com/group/google-perftools
-
-
64-BIT ISSUES
-------------
diff --git a/configure b/configure
index 6e8fb4d..9f19ef0 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.65 for google-perftools 1.7.
+# Generated by GNU Autoconf 2.65 for google-perftools 1.8.
#
# Report bugs to <opensource@google.com>.
#
@@ -701,8 +701,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='google-perftools'
PACKAGE_TARNAME='google-perftools'
-PACKAGE_VERSION='1.7'
-PACKAGE_STRING='google-perftools 1.7'
+PACKAGE_VERSION='1.8'
+PACKAGE_STRING='google-perftools 1.8'
PACKAGE_BUGREPORT='opensource@google.com'
PACKAGE_URL=''
@@ -758,6 +758,8 @@ WITH_HEAP_PROFILER_FALSE
WITH_HEAP_PROFILER_TRUE
WITH_CPU_PROFILER_FALSE
WITH_CPU_PROFILER_TRUE
+OSX_FALSE
+OSX_TRUE
MINGW_FALSE
MINGW_TRUE
PTHREAD_CFLAGS
@@ -766,6 +768,8 @@ PTHREAD_CC
acx_pthread_config
LIBSTDCXX_LA_LINKER_FLAG
NANOSLEEP_LIBS
+HAVE_W_NO_UNUSED_RESULT_FALSE
+HAVE_W_NO_UNUSED_RESULT_TRUE
X86_64_AND_NO_FP_BY_DEFAULT_FALSE
X86_64_AND_NO_FP_BY_DEFAULT_TRUE
ENABLE_FRAME_POINTERS_FALSE
@@ -1468,7 +1472,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures google-perftools 1.7 to adapt to many kinds of systems.
+\`configure' configures google-perftools 1.8 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1539,7 +1543,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of google-perftools 1.7:";;
+ short | recursive ) echo "Configuration of google-perftools 1.8:";;
esac
cat <<\_ACEOF
@@ -1649,7 +1653,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-google-perftools configure 1.7
+google-perftools configure 1.8
generated by GNU Autoconf 2.65
Copyright (C) 2009 Free Software Foundation, Inc.
@@ -2234,7 +2238,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by google-perftools $as_me 1.7, which was
+It was created by google-perftools $as_me 1.8, which was
generated by GNU Autoconf 2.65. Invocation command line was
$ $0 $@
@@ -2586,8 +2590,8 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
# Update this value for every release! (A:B:C will map to foo.so.(A-C).C.B)
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
-TCMALLOC_SO_VERSION=1:0:1
-PROFILER_SO_VERSION=1:0:1
+TCMALLOC_SO_VERSION=2:0:2
+PROFILER_SO_VERSION=1:1:1
@@ -2979,7 +2983,7 @@ fi
# Define the identity of the package.
PACKAGE='google-perftools'
- VERSION='1.7'
+ VERSION='1.8'
cat >>confdefs.h <<_ACEOF
@@ -5609,13 +5613,13 @@ if test "${lt_cv_nm_interface+set}" = set; then :
else
lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
- (eval echo "\"\$as_me:5612: $ac_compile\"" >&5)
+ (eval echo "\"\$as_me:5616: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
- (eval echo "\"\$as_me:5615: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval echo "\"\$as_me:5619: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
- (eval echo "\"\$as_me:5618: output\"" >&5)
+ (eval echo "\"\$as_me:5622: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@@ -6820,7 +6824,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 6823 "configure"' > conftest.$ac_ext
+ echo '#line 6827 "configure"' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -8693,11 +8697,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:8696: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:8700: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:8700: \$? = $ac_status" >&5
+ echo "$as_me:8704: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -9032,11 +9036,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:9035: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:9039: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:9039: \$? = $ac_status" >&5
+ echo "$as_me:9043: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -9137,11 +9141,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:9140: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:9144: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:9144: \$? = $ac_status" >&5
+ echo "$as_me:9148: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -9192,11 +9196,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:9195: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:9199: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:9199: \$? = $ac_status" >&5
+ echo "$as_me:9203: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -11576,7 +11580,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11579 "configure"
+#line 11583 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11672,7 +11676,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11675 "configure"
+#line 11679 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -13628,11 +13632,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:13631: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:13635: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:13635: \$? = $ac_status" >&5
+ echo "$as_me:13639: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -13727,11 +13731,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:13730: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:13734: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:13734: \$? = $ac_status" >&5
+ echo "$as_me:13738: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -13779,11 +13783,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:13782: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:13786: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:13786: \$? = $ac_status" >&5
+ echo "$as_me:13790: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -15949,6 +15953,52 @@ fi
rm fp.s
CFLAGS="$OLD_CFLAGS"
+# See if the compiler supports -Wno-unused-result.
+# Newer ubuntu's turn on -D_FORTIFY_SOURCE=2, enabling
+# __attribute__((warn_unused_result)) for things like write(),
+# which we don't care about.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the compiler supports -Wno-unused-result" >&5
+$as_echo_n "checking if the compiler supports -Wno-unused-result... " >&6; }
+if test "${perftools_cv_w_no_unused_result+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ OLD_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -Wno-error -Wno-unused-result"
+ # gcc doesn't warn about unknown flags unless it's
+ # also warning for some other purpose, hence the
+ # divide-by-0. (We use -Wno-error to make sure the
+ # divide-by-0 doesn't cause this test to fail!)
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+return 1/0
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ perftools_cv_w_no_unused_result=yes
+else
+ perftools_cv_w_no_unused_result=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS="$OLD_CFLAGS"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $perftools_cv_w_no_unused_result" >&5
+$as_echo "$perftools_cv_w_no_unused_result" >&6; }
+
+
+if test "$perftools_cv_w_no_unused_result" = yes; then
+ HAVE_W_NO_UNUSED_RESULT_TRUE=
+ HAVE_W_NO_UNUSED_RESULT_FALSE='#'
+else
+ HAVE_W_NO_UNUSED_RESULT_TRUE='#'
+ HAVE_W_NO_UNUSED_RESULT_FALSE=
+fi
+
# Defines PRIuS
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking printf format code for printing a size_t and ssize_t" >&5
@@ -16115,6 +16165,35 @@ fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
+# glibc's __malloc_hook/etc were declared volatile starting in glibc 2.14
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if __malloc_hook is declared volatile" >&5
+$as_echo_n "checking if __malloc_hook is declared volatile... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <malloc.h>
+void* (* volatile __malloc_hook)(size_t, const void*) = 0;
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+$as_echo "#define MALLOC_HOOK_MAYBE_VOLATILE volatile" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ $as_echo "#define MALLOC_HOOK_MAYBE_VOLATILE /**/" >>confdefs.h
+,
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
# Nanosleep requires extra libraries on some architectures (solaris).
# This sets NANOSLEEP_LIBS. nanosleep doesn't exist on mingw, which
# is fine for us because we don't compile libspinlock, which uses it.
@@ -16977,10 +17056,15 @@ $as_echo "#define PERFTOOLS_DLL_DECL /**/" >>confdefs.h
# http://code.google.com/p/google-perftools/issues/detail?id=246
+
+
# MinGW uses autoconf, but also needs the windows shim routines
# (since it doesn't have its own support for, say, pthreads).
# This requires us to #include a special header file, and also to
# link in some windows versions of .o's instead of the unix versions.
+#
+# Also, manually mark systems where we have to be careful how early
+# we run pthreads. TODO(csilvers): turn this into an autoconf check.
@@ -16993,6 +17077,16 @@ else
fi
+
+if expr $host : '.*-apple-darwin.*' >/dev/null 2>&1; then
+ OSX_TRUE=
+ OSX_FALSE='#'
+else
+ OSX_TRUE='#'
+ OSX_FALSE=
+fi
+
+
# Redhat 7 (and below?) has sys/ucontext.h, but if you try to #include
# it directly, the compiler gets upset. So we pretend we don't have
# it.
@@ -17211,10 +17305,18 @@ if test -z "${X86_64_AND_NO_FP_BY_DEFAULT_TRUE}" && test -z "${X86_64_AND_NO_FP_
as_fn_error "conditional \"X86_64_AND_NO_FP_BY_DEFAULT\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${HAVE_W_NO_UNUSED_RESULT_TRUE}" && test -z "${HAVE_W_NO_UNUSED_RESULT_FALSE}"; then
+ as_fn_error "conditional \"HAVE_W_NO_UNUSED_RESULT\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${MINGW_TRUE}" && test -z "${MINGW_FALSE}"; then
as_fn_error "conditional \"MINGW\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${OSX_TRUE}" && test -z "${OSX_FALSE}"; then
+ as_fn_error "conditional \"OSX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${WITH_CPU_PROFILER_TRUE}" && test -z "${WITH_CPU_PROFILER_FALSE}"; then
as_fn_error "conditional \"WITH_CPU_PROFILER\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -17647,7 +17749,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by google-perftools $as_me 1.7, which was
+This file was extended by google-perftools $as_me 1.8, which was
generated by GNU Autoconf 2.65. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -17713,7 +17815,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-google-perftools config.status 1.7
+google-perftools config.status 1.8
configured by $0, generated by GNU Autoconf 2.65,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 87507ce..4eb8bf5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,11 +4,11 @@
# make sure we're interpreted by some minimal autoconf
AC_PREREQ(2.57)
-AC_INIT(google-perftools, 1.7, opensource@google.com)
+AC_INIT(google-perftools, 1.8, opensource@google.com)
# Update this value for every release! (A:B:C will map to foo.so.(A-C).C.B)
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
-TCMALLOC_SO_VERSION=1:0:1
-PROFILER_SO_VERSION=1:0:1
+TCMALLOC_SO_VERSION=2:0:2
+PROFILER_SO_VERSION=1:1:1
AC_SUBST(TCMALLOC_SO_VERSION)
AC_SUBST(PROFILER_SO_VERSION)
@@ -238,6 +238,24 @@ AM_CONDITIONAL(X86_64_AND_NO_FP_BY_DEFAULT,
rm fp.s
CFLAGS="$OLD_CFLAGS"
+# See if the compiler supports -Wno-unused-result.
+# Newer ubuntu's turn on -D_FORTIFY_SOURCE=2, enabling
+# __attribute__((warn_unused_result)) for things like write(),
+# which we don't care about.
+AC_CACHE_CHECK([if the compiler supports -Wno-unused-result],
+ perftools_cv_w_no_unused_result,
+ [OLD_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -Wno-error -Wno-unused-result"
+ # gcc doesn't warn about unknown flags unless it's
+ # also warning for some other purpose, hence the
+ # divide-by-0. (We use -Wno-error to make sure the
+ # divide-by-0 doesn't cause this test to fail!)
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM(, return 1/0)],
+ perftools_cv_w_no_unused_result=yes,
+ perftools_cv_w_no_unused_result=no)
+ CFLAGS="$OLD_CFLAGS"])
+AM_CONDITIONAL(HAVE_W_NO_UNUSED_RESULT,
+ test "$perftools_cv_w_no_unused_result" = yes)
# Defines PRIuS
AC_COMPILER_CHARACTERISTICS
@@ -276,10 +294,20 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([#if defined(__GNUC__) && (defined(__i386__) ||
#error gcc has this bug: http://gcc.gnu.org/ml/gcc-bugs/2006-09/msg02275.html
#endif], [static __thread int p = 0])],
[AC_DEFINE(HAVE_TLS, 1,
- Define to 1 if compiler supports __thread)
+ Define to 1 if compiler supports __thread)
AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])])
+# glibc's __malloc_hook/etc were declared volatile starting in glibc 2.14
+AC_MSG_CHECKING([if __malloc_hook is declared volatile])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <malloc.h>
+void* (* volatile __malloc_hook)(size_t, const void*) = 0;],)],
+ [AC_DEFINE(MALLOC_HOOK_MAYBE_VOLATILE, volatile,
+ Define to 'volatile' if __malloc_hook is declared volatile)
+ AC_MSG_RESULT([yes])],
+ [AC_DEFINE(MALLOC_HOOK_MAYBE_VOLATILE, ),
+ AC_MSG_RESULT([no])])
+
# Nanosleep requires extra libraries on some architectures (solaris).
# This sets NANOSLEEP_LIBS. nanosleep doesn't exist on mingw, which
# is fine for us because we don't compile libspinlock, which uses it.
@@ -334,10 +362,20 @@ AH_TOP([
#define GOOGLE_PERFTOOLS_CONFIG_H_
])
+AH_VERBATIM([PTHREADS_CRASHES_IF_RUN_TOO_EARLY],
+ [/* Mark the systems where we know it's bad if pthreads runs too
+ early before main (before threads are initialized, presumably). */
+#ifdef __FreeBSD__
+#define PTHREADS_CRASHES_IF_RUN_TOO_EARLY 1
+#endif])
+
# MinGW uses autoconf, but also needs the windows shim routines
# (since it doesn't have its own support for, say, pthreads).
# This requires us to #include a special header file, and also to
# link in some windows versions of .o's instead of the unix versions.
+#
+# Also, manually mark systems where we have to be careful how early
+# we run pthreads. TODO(csilvers): turn this into an autoconf check.
AH_BOTTOM([
#ifdef __MINGW32__
#include "windows/mingw.h"
@@ -346,6 +384,7 @@ AH_BOTTOM([
#endif /* #ifndef GOOGLE_PERFTOOLS_CONFIG_H_ */
])
AM_CONDITIONAL(MINGW, expr $host : '.*-mingw' >/dev/null 2>&1)
+AM_CONDITIONAL(OSX, expr $host : '.*-apple-darwin.*' >/dev/null 2>&1)
# Redhat 7 (and below?) has sys/ucontext.h, but if you try to #include
# it directly, the compiler gets upset. So we pretend we don't have
diff --git a/doc/heapprofile.html b/doc/heapprofile.html
index 709559d..22bfbec 100644
--- a/doc/heapprofile.html
+++ b/doc/heapprofile.html
@@ -366,11 +366,8 @@ interactive mode.</p>
</ul>
<hr>
-<address>Sanjay Ghemawat<br>
+<address>Sanjay Ghemawat
<!-- Created: Tue Dec 19 10:43:14 PST 2000 -->
-<!-- hhmts start -->
-Last modified: Sat Feb 24 14:33:15 PST 2007 (csilvers)
-<!-- hhmts end -->
</address>
</body>
</html>
diff --git a/doc/tcmalloc.html b/doc/tcmalloc.html
index 4578984..8d72c0c 100644
--- a/doc/tcmalloc.html
+++ b/doc/tcmalloc.html
@@ -503,7 +503,7 @@ environment variables.</p>
</tr>
<tr valign=top>
- <td><code>TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES=<i>x</i></code></td>
+ <td><code>TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES</code></td>
<td>default: 16777216</td>
<td>
Bound on the total amount of bytes allocated to thread caches. This
diff --git a/google-perftools.sln b/google-perftools.sln
index 4a2d630..f7d29a5 100755
--- a/google-perftools.sln
+++ b/google-perftools.sln
@@ -131,10 +131,18 @@ Global
{3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Debug.Build.0 = Debug|Win32
{3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.ActiveCfg = Release|Win32
{3765198D-5305-4AB0-9A21-A0CD8201EB2A}.Release.Build.0 = Release|Win32
+ {3765198D-AA05-4AB0-9A21-A0CD8201EB2A}.Debug.ActiveCfg = Debug|Win32
+ {3765198D-AA05-4AB0-9A21-A0CD8201EB2A}.Debug.Build.0 = Debug|Win32
+ {3765198D-AA05-4AB0-9A21-A0CD8201EB2A}.Release.ActiveCfg = Release|Win32
+ {3765198D-AA05-4AB0-9A21-A0CD8201EB2A}.Release.Build.0 = Release|Win32
{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Debug.ActiveCfg = Debug|Win32
{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Debug.Build.0 = Debug|Win32
{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Release.ActiveCfg = Release|Win32
{4AF7E21D-9D0A-410C-A7DB-7D21DA5166C0}.Release.Build.0 = Release|Win32
+ {4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}.Debug.ActiveCfg = Debug|Win32
+ {4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}.Debug.Build.0 = Debug|Win32
+ {4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}.Release.ActiveCfg = Release|Win32
+ {4AFFF21D-9D0A-410C-A7DB-7D21DA5166C0}.Release.Build.0 = Release|Win32
{605D3CED-B530-424E-B7D2-2A31F14FD570}.Debug.ActiveCfg = Debug|Win32
{605D3CED-B530-424E-B7D2-2A31F14FD570}.Debug.Build.0 = Debug|Win32
{605D3CED-B530-424E-B7D2-2A31F14FD570}.Release.ActiveCfg = Release|Win32
diff --git a/packages/deb/changelog b/packages/deb/changelog
index e9fd548..703500b 100644
--- a/packages/deb/changelog
+++ b/packages/deb/changelog
@@ -1,3 +1,9 @@
+google-perftools (1.8-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Google Inc. <opensource@google.com> Fri, 15 Jul 2011 16:10:51 -0700
+
google-perftools (1.7-1) unstable; urgency=low
* New upstream release.
@@ -140,7 +146,7 @@ google-perftools (0.5-1) unstable; urgency=low
* New upstream release.
- -- Google Inc. <opensource@google.com> Mon Nov 14 17:28:59 2005
+ -- Google Inc. <opensource@google.com> Mon Nov 14 17:28:59 2005 -0800
google-perftools (0.4-1) unstable; urgency=low
diff --git a/src/base/atomicops-internals-windows.h b/src/base/atomicops-internals-windows.h
index 58782a1..bd42c82 100644
--- a/src/base/atomicops-internals-windows.h
+++ b/src/base/atomicops-internals-windows.h
@@ -55,28 +55,74 @@ typedef int64 Atomic64;
// 32-bit low-level operations on any platform
+extern "C" {
+// We use windows intrinsics when we can (they seem to be supported
+// well on MSVC 8.0 and above). Unfortunately, in some
+// environments, <windows.h> and <intrin.h> have conflicting
+// declarations of some other intrinsics, breaking compilation:
+// http://connect.microsoft.com/VisualStudio/feedback/details/262047
+// Therefore, we simply declare the relevant intrinsics ourself.
+
// MinGW has a bug in the header files where it doesn't indicate the
// first argument is volatile -- they're not up to date. See
// http://readlist.com/lists/lists.sourceforge.net/mingw-users/0/3861.html
// We have to const_cast away the volatile to avoid compiler warnings.
// TODO(csilvers): remove this once MinGW has updated MinGW/include/winbase.h
-#ifdef __MINGW32__
-inline LONG InterlockedCompareExchange(volatile LONG* ptr,
- LONG newval, LONG oldval) {
+#if defined(__MINGW32__)
+inline LONG FastInterlockedCompareExchange(volatile LONG* ptr,
+ LONG newval, LONG oldval) {
return ::InterlockedCompareExchange(const_cast<LONG*>(ptr), newval, oldval);
}
-inline LONG InterlockedExchange(volatile LONG* ptr, LONG newval) {
+inline LONG FastInterlockedExchange(volatile LONG* ptr, LONG newval) {
return ::InterlockedExchange(const_cast<LONG*>(ptr), newval);
}
-inline LONG InterlockedExchangeAdd(volatile LONG* ptr, LONG increment) {
+inline LONG FastInterlockedExchangeAdd(volatile LONG* ptr, LONG increment) {
return ::InterlockedExchangeAdd(const_cast<LONG*>(ptr), increment);
}
+
+#elif _MSC_VER >= 1400 // intrinsics didn't work so well before MSVC 8.0
+// Unfortunately, in some environments, <windows.h> and <intrin.h>
+// have conflicting declarations of some intrinsics, breaking
+// compilation. So we declare the intrinsics we need ourselves. See
+// http://connect.microsoft.com/VisualStudio/feedback/details/262047
+LONG _InterlockedCompareExchange(volatile LONG* ptr, LONG newval, LONG oldval);
+#pragma intrinsic(_InterlockedCompareExchange)
+inline LONG FastInterlockedCompareExchange(volatile LONG* ptr,
+ LONG newval, LONG oldval) {
+ return _InterlockedCompareExchange(ptr, newval, oldval);
+}
+
+LONG _InterlockedExchange(volatile LONG* ptr, LONG newval);
+#pragma intrinsic(_InterlockedExchange)
+inline LONG FastInterlockedExchange(volatile LONG* ptr, LONG newval) {
+ return _InterlockedExchange(ptr, newval);
+}
+
+LONG _InterlockedExchangeAdd(volatile LONG* ptr, LONG increment);
+#pragma intrinsic(_InterlockedExchangeAdd)
+inline LONG FastInterlockedExchangeAdd(volatile LONG* ptr, LONG increment) {
+ return _InterlockedExchangeAdd(ptr, increment);
+}
+
+#else
+inline LONG FastInterlockedCompareExchange(volatile LONG* ptr,
+ LONG newval, LONG oldval) {
+ return ::InterlockedCompareExchange(ptr, newval, oldval);
+}
+inline LONG FastInterlockedExchange(volatile LONG* ptr, LONG newval) {
+ return ::InterlockedExchange(ptr, newval);
+}
+inline LONG FastInterlockedExchangeAdd(volatile LONG* ptr, LONG increment) {
+ return ::InterlockedExchangeAdd(ptr, increment);
+}
+
#endif // ifdef __MINGW32__
+} // extern "C"
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value,
Atomic32 new_value) {
- LONG result = InterlockedCompareExchange(
+ LONG result = FastInterlockedCompareExchange(
reinterpret_cast<volatile LONG*>(ptr),
static_cast<LONG>(new_value),
static_cast<LONG>(old_value));
@@ -85,7 +131,7 @@ inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
Atomic32 new_value) {
- LONG result = InterlockedExchange(
+ LONG result = FastInterlockedExchange(
reinterpret_cast<volatile LONG*>(ptr),
static_cast<LONG>(new_value));
return static_cast<Atomic32>(result);
@@ -93,7 +139,7 @@ inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
Atomic32 increment) {
- return InterlockedExchangeAdd(
+ return FastInterlockedExchangeAdd(
reinterpret_cast<volatile LONG*>(ptr),
static_cast<LONG>(increment)) + increment;
}
@@ -173,27 +219,68 @@ inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
COMPILE_ASSERT(sizeof(Atomic64) == sizeof(PVOID), atomic_word_is_atomic);
-// Like for the __MINGW32__ case above, this works around a header
-// error in mingw, where it's missing 'volatile'.
-#ifdef __MINGW64__
-inline PVOID InterlockedCompareExchangePointer(volatile PVOID* ptr,
- PVOID newval, PVOID oldval) {
+// These are the intrinsics needed for 64-bit operations. Similar to the
+// 32-bit case above.
+
+extern "C" {
+#if defined(__MINGW64__)
+inline PVOID FastInterlockedCompareExchangePointer(volatile PVOID* ptr,
+ PVOID newval, PVOID oldval) {
return ::InterlockedCompareExchangePointer(const_cast<PVOID*>(ptr),
newval, oldval);
}
-inline PVOID InterlockedExchangePointer(volatile PVOID* ptr, PVOID newval) {
+inline PVOID FastInterlockedExchangePointer(volatile PVOID* ptr, PVOID newval) {
return ::InterlockedExchangePointer(const_cast<PVOID*>(ptr), newval);
}
-inline LONGLONG InterlockedExchangeAdd64(volatile LONGLONG* ptr,
- LONGLONG increment) {
+inline LONGLONG FastInterlockedExchangeAdd64(volatile LONGLONG* ptr,
+ LONGLONG increment) {
return ::InterlockedExchangeAdd64(const_cast<LONGLONG*>(ptr), increment);
}
+
+#elif _MSC_VER >= 1400 // intrinsics didn't work so well before MSVC 8.0
+// Like above, we need to declare the intrinsics ourselves.
+PVOID _InterlockedCompareExchangePointer(volatile PVOID* ptr,
+ PVOID newval, PVOID oldval);
+#pragma intrinsic(_InterlockedCompareExchangePointer)
+inline PVOID FastInterlockedCompareExchangePointer(volatile PVOID* ptr,
+ PVOID newval, PVOID oldval) {
+ return _InterlockedCompareExchangePointer(const_cast<PVOID*>(ptr),
+ newval, oldval);
+}
+
+PVOID _InterlockedExchangePointer(volatile PVOID* ptr, PVOID newval);
+#pragma intrinsic(_InterlockedExchangePointer)
+inline PVOID FastInterlockedExchangePointer(volatile PVOID* ptr, PVOID newval) {
+ return _InterlockedExchangePointer(const_cast<PVOID*>(ptr), newval);
+}
+
+LONGLONG _InterlockedExchangeAdd64(volatile LONGLONG* ptr, LONGLONG increment);
+#pragma intrinsic(_InterlockedExchangeAdd64)
+inline LONGLONG FastInterlockedExchangeAdd64(volatile LONGLONG* ptr,
+ LONGLONG increment) {
+ return _InterlockedExchangeAdd64(const_cast<LONGLONG*>(ptr), increment);
+}
+
+#else
+inline PVOID FastInterlockedCompareExchangePointer(volatile PVOID* ptr,
+ PVOID newval, PVOID oldval) {
+ return ::InterlockedCompareExchangePointer(ptr, newval, oldval);
+}
+inline PVOID FastInterlockedExchangePointer(volatile PVOID* ptr, PVOID newval) {
+ return ::InterlockedExchangePointer(ptr, newval);
+}
+inline LONGLONG FastInterlockedExchangeAdd64(volatile LONGLONG* ptr,
+ LONGLONG increment) {
+ return ::InterlockedExchangeAdd64(ptr, increment);
+}
+
#endif // ifdef __MINGW64__
+} // extern "C"
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value,
Atomic64 new_value) {
- PVOID result = InterlockedCompareExchangePointer(
+ PVOID result = FastInterlockedCompareExchangePointer(
reinterpret_cast<volatile PVOID*>(ptr),
reinterpret_cast<PVOID>(new_value), reinterpret_cast<PVOID>(old_value));
return reinterpret_cast<Atomic64>(result);
@@ -201,7 +288,7 @@ inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
Atomic64 new_value) {
- PVOID result = InterlockedExchangePointer(
+ PVOID result = FastInterlockedExchangePointer(
reinterpret_cast<volatile PVOID*>(ptr),
reinterpret_cast<PVOID>(new_value));
return reinterpret_cast<Atomic64>(result);
@@ -209,7 +296,7 @@ inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
Atomic64 increment) {
- return InterlockedExchangeAdd64(
+ return FastInterlockedExchangeAdd64(
reinterpret_cast<volatile LONGLONG*>(ptr),
static_cast<LONGLONG>(increment)) + increment;
}
@@ -258,7 +345,7 @@ inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
// 64-bit low-level operations on 32-bit platform
// TODO(vchen): The GNU assembly below must be converted to MSVC inline
-// assembly. Then the file should be renamed to ...-x86-mscv.h, probably.
+// assembly. Then the file should be renamed to ...-x86-msvc.h, probably.
inline void NotImplementedFatalError(const char *function_name) {
fprintf(stderr, "64-bit %s() not implemented on this platform\n",
diff --git a/src/base/atomicops.h b/src/base/atomicops.h
index f36df5f..17e8a27 100644
--- a/src/base/atomicops.h
+++ b/src/base/atomicops.h
@@ -96,7 +96,7 @@
#elif defined(ARMV3)
#include "base/atomicops-internals-arm-generic.h"
#elif defined(_WIN32)
-#include "base/atomicops-internals-x86-windows.h"
+#include "base/atomicops-internals-windows.h"
#elif defined(__GNUC__) && (defined(__i386) || defined(__x86_64__))
#include "base/atomicops-internals-x86.h"
#elif defined(__linux__) && defined(__PPC__)
diff --git a/src/base/cycleclock.h b/src/base/cycleclock.h
index 11f9c9b..db5f49a 100644
--- a/src/base/cycleclock.h
+++ b/src/base/cycleclock.h
@@ -50,16 +50,20 @@
#if defined(__MACH__) && defined(__APPLE__)
# include <mach/mach_time.h>
#endif
-// For MSVC, we want the __rdtsc intrinsic, declared in <intrin.h>.
-// Unfortunately, in some environments, <windows.h> and <intrin.h> have
-// conflicting declarations of some other intrinsics, breaking compilation.
+// For MSVC, we want to use '_asm rdtsc' when possible (since it works
+// with even ancient MSVC compilers), and when not possible the
+// __rdtsc intrinsic, declared in <intrin.h>. Unfortunately, in some
+// environments, <windows.h> and <intrin.h> have conflicting
+// declarations of some other intrinsics, breaking compilation.
// Therefore, we simply declare __rdtsc ourselves. See also
// http://connect.microsoft.com/VisualStudio/feedback/details/262047
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(_M_IX86)
extern "C" uint64 __rdtsc();
#pragma intrinsic(__rdtsc)
#endif
+#ifdef ARMV3
#include <sys/time.h>
+#endif
// NOTE: only i386 and x86_64 have been well tested.
// PPC, sparc, alpha, and ia64 are based on
@@ -106,6 +110,12 @@ struct CycleClock {
int64 itc;
asm("mov %0 = ar.itc" : "=r" (itc));
return itc;
+#elif defined(_MSC_VER) && defined(_M_IX86)
+ // Older MSVC compilers (like 7.x) don't seem to support the
+ // __rdtsc intrinsic properly, so I prefer to use _asm instead
+ // when I know it will work. Otherwise, I'll use __rdtsc and hope
+ // the code is being compiled with a non-ancient compiler.
+ _asm rdtsc
#elif defined(_MSC_VER)
return __rdtsc();
#elif defined(ARMV3)
diff --git a/src/base/elf_mem_image.cc b/src/base/elf_mem_image.cc
new file mode 100644
index 0000000..d8b8090
--- /dev/null
+++ b/src/base/elf_mem_image.cc
@@ -0,0 +1,432 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Paul Pluzhnikov
+//
+// Allow dynamic symbol lookup in an in-memory Elf image.
+//
+
+#include "base/elf_mem_image.h"
+
+#ifdef HAVE_ELF_MEM_IMAGE // defined in elf_mem_image.h
+
+#include "base/logging.h"
+
+// From binutils/include/elf/common.h (this doesn't appear to be documented
+// anywhere else).
+//
+// /* This flag appears in a Versym structure. It means that the symbol
+// is hidden, and is only visible with an explicit version number.
+// This is a GNU extension. */
+// #define VERSYM_HIDDEN 0x8000
+//
+// /* This is the mask for the rest of the Versym information. */
+// #define VERSYM_VERSION 0x7fff
+
+#define VERSYM_VERSION 0x7fff
+
+namespace base {
+
+namespace {
+template <int N> class ElfClass {
+ public:
+ static const int kElfClass = -1;
+ static int ElfBind(const ElfW(Sym) *) {
+ CHECK(false); // << "Unexpected word size";
+ return 0;
+ }
+ static int ElfType(const ElfW(Sym) *) {
+ CHECK(false); // << "Unexpected word size";
+ return 0;
+ }
+};
+
+template <> class ElfClass<32> {
+ public:
+ static const int kElfClass = ELFCLASS32;
+ static int ElfBind(const ElfW(Sym) *symbol) {
+ return ELF32_ST_BIND(symbol->st_info);
+ }
+ static int ElfType(const ElfW(Sym) *symbol) {
+ return ELF32_ST_TYPE(symbol->st_info);
+ }
+};
+
+template <> class ElfClass<64> {
+ public:
+ static const int kElfClass = ELFCLASS64;
+ static int ElfBind(const ElfW(Sym) *symbol) {
+ return ELF64_ST_BIND(symbol->st_info);
+ }
+ static int ElfType(const ElfW(Sym) *symbol) {
+ return ELF64_ST_TYPE(symbol->st_info);
+ }
+};
+
+typedef ElfClass<__WORDSIZE> CurrentElfClass;
+
+// Extract an element from one of the ELF tables, cast it to desired type.
+// This is just a simple arithmetic and a glorified cast.
+// Callers are responsible for bounds checking.
+template <class T>
+const T* GetTableElement(const ElfW(Ehdr) *ehdr,
+ ElfW(Off) table_offset,
+ ElfW(Word) element_size,
+ size_t index) {
+ return reinterpret_cast<const T*>(reinterpret_cast<const char *>(ehdr)
+ + table_offset
+ + index * element_size);
+}
+} // namespace
+
+const void *const ElfMemImage::kInvalidBase =
+ reinterpret_cast<const void *>(~0L);
+
+ElfMemImage::ElfMemImage(const void *base) {
+ CHECK(base != kInvalidBase);
+ Init(base);
+}
+
+int ElfMemImage::GetNumSymbols() const {
+ if (!hash_) {
+ return 0;
+ }
+ // See http://www.caldera.com/developers/gabi/latest/ch5.dynamic.html#hash
+ return hash_[1];
+}
+
+const ElfW(Sym) *ElfMemImage::GetDynsym(int index) const {
+ CHECK_LT(index, GetNumSymbols());
+ return dynsym_ + index;
+}
+
+const ElfW(Versym) *ElfMemImage::GetVersym(int index) const {
+ CHECK_LT(index, GetNumSymbols());
+ return versym_ + index;
+}
+
+const ElfW(Phdr) *ElfMemImage::GetPhdr(int index) const {
+ CHECK_LT(index, ehdr_->e_phnum);
+ return GetTableElement<ElfW(Phdr)>(ehdr_,
+ ehdr_->e_phoff,
+ ehdr_->e_phentsize,
+ index);
+}
+
+const char *ElfMemImage::GetDynstr(ElfW(Word) offset) const {
+ CHECK_LT(offset, strsize_);
+ return dynstr_ + offset;
+}
+
+const void *ElfMemImage::GetSymAddr(const ElfW(Sym) *sym) const {
+ if (sym->st_shndx == SHN_UNDEF || sym->st_shndx >= SHN_LORESERVE) {
+ // Symbol corresponds to "special" (e.g. SHN_ABS) section.
+ return reinterpret_cast<const void *>(sym->st_value);
+ }
+ CHECK_LT(link_base_, sym->st_value);
+ return GetTableElement<char>(ehdr_, 0, 1, sym->st_value) - link_base_;
+}
+
+const ElfW(Verdef) *ElfMemImage::GetVerdef(int index) const {
+ CHECK_LE(index, verdefnum_);
+ const ElfW(Verdef) *version_definition = verdef_;
+ while (version_definition->vd_ndx < index && version_definition->vd_next) {
+ const char *const version_definition_as_char =
+ reinterpret_cast<const char *>(version_definition);
+ version_definition =
+ reinterpret_cast<const ElfW(Verdef) *>(version_definition_as_char +
+ version_definition->vd_next);
+ }
+ return version_definition->vd_ndx == index ? version_definition : NULL;
+}
+
+const ElfW(Verdaux) *ElfMemImage::GetVerdefAux(
+ const ElfW(Verdef) *verdef) const {
+ return reinterpret_cast<const ElfW(Verdaux) *>(verdef+1);
+}
+
+const char *ElfMemImage::GetVerstr(ElfW(Word) offset) const {
+ CHECK_LT(offset, strsize_);
+ return dynstr_ + offset;
+}
+
+void ElfMemImage::Init(const void *base) {
+ ehdr_ = NULL;
+ dynsym_ = NULL;
+ dynstr_ = NULL;
+ versym_ = NULL;
+ verdef_ = NULL;
+ hash_ = NULL;
+ strsize_ = 0;
+ verdefnum_ = 0;
+ link_base_ = ~0L; // Sentinel: PT_LOAD .p_vaddr can't possibly be this.
+ if (!base) {
+ return;
+ }
+ const intptr_t base_as_uintptr_t = reinterpret_cast<uintptr_t>(base);
+ // Fake VDSO has low bit set.
+ const bool fake_vdso = ((base_as_uintptr_t & 1) != 0);
+ base = reinterpret_cast<const void *>(base_as_uintptr_t & ~1);
+ const char *const base_as_char = reinterpret_cast<const char *>(base);
+ if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 ||
+ base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) {
+ RAW_DCHECK(false, "no ELF magic"); // at %p", base);
+ return;
+ }
+ int elf_class = base_as_char[EI_CLASS];
+ if (elf_class != CurrentElfClass::kElfClass) {
+ DCHECK_EQ(elf_class, CurrentElfClass::kElfClass);
+ return;
+ }
+ switch (base_as_char[EI_DATA]) {
+ case ELFDATA2LSB: {
+ if (__LITTLE_ENDIAN != __BYTE_ORDER) {
+ DCHECK_EQ(__LITTLE_ENDIAN, __BYTE_ORDER); // << ": wrong byte order";
+ return;
+ }
+ break;
+ }
+ case ELFDATA2MSB: {
+ if (__BIG_ENDIAN != __BYTE_ORDER) {
+ DCHECK_EQ(__BIG_ENDIAN, __BYTE_ORDER); // << ": wrong byte order";
+ return;
+ }
+ break;
+ }
+ default: {
+ RAW_DCHECK(false, "unexpected data encoding"); // << base_as_char[EI_DATA];
+ return;
+ }
+ }
+
+ ehdr_ = reinterpret_cast<const ElfW(Ehdr) *>(base);
+ const ElfW(Phdr) *dynamic_program_header = NULL;
+ for (int i = 0; i < ehdr_->e_phnum; ++i) {
+ const ElfW(Phdr) *const program_header = GetPhdr(i);
+ switch (program_header->p_type) {
+ case PT_LOAD:
+ if (link_base_ == ~0L) {
+ link_base_ = program_header->p_vaddr;
+ }
+ break;
+ case PT_DYNAMIC:
+ dynamic_program_header = program_header;
+ break;
+ }
+ }
+ if (link_base_ == ~0L || !dynamic_program_header) {
+ RAW_DCHECK(~0L != link_base_, "no PT_LOADs in VDSO");
+ RAW_DCHECK(dynamic_program_header, "no PT_DYNAMIC in VDSO");
+ // Mark this image as not present. Can not recur infinitely.
+ Init(0);
+ return;
+ }
+ ptrdiff_t relocation =
+ base_as_char - reinterpret_cast<const char *>(link_base_);
+ ElfW(Dyn) *dynamic_entry =
+ reinterpret_cast<ElfW(Dyn) *>(dynamic_program_header->p_vaddr +
+ relocation);
+ for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) {
+ ElfW(Xword) value = dynamic_entry->d_un.d_val;
+ if (fake_vdso) {
+ // A complication: in the real VDSO, dynamic entries are not relocated
+ // (it wasn't loaded by a dynamic loader). But when testing with a
+ // "fake" dlopen()ed vdso library, the loader relocates some (but
+ // not all!) of them before we get here.
+ if (dynamic_entry->d_tag == DT_VERDEF) {
+ // The only dynamic entry (of the ones we care about) libc-2.3.6
+ // loader doesn't relocate.
+ value += relocation;
+ }
+ } else {
+ // Real VDSO. Everything needs to be relocated.
+ value += relocation;
+ }
+ switch (dynamic_entry->d_tag) {
+ case DT_HASH:
+ hash_ = reinterpret_cast<ElfW(Word) *>(value);
+ break;
+ case DT_SYMTAB:
+ dynsym_ = reinterpret_cast<ElfW(Sym) *>(value);
+ break;
+ case DT_STRTAB:
+ dynstr_ = reinterpret_cast<const char *>(value);
+ break;
+ case DT_VERSYM:
+ versym_ = reinterpret_cast<ElfW(Versym) *>(value);
+ break;
+ case DT_VERDEF:
+ verdef_ = reinterpret_cast<ElfW(Verdef) *>(value);
+ break;
+ case DT_VERDEFNUM:
+ verdefnum_ = dynamic_entry->d_un.d_val;
+ break;
+ case DT_STRSZ:
+ strsize_ = dynamic_entry->d_un.d_val;
+ break;
+ default:
+ // Unrecognized entries explicitly ignored.
+ break;
+ }
+ }
+ if (!hash_ || !dynsym_ || !dynstr_ || !versym_ ||
+ !verdef_ || !verdefnum_ || !strsize_) {
+ RAW_DCHECK(hash_, "invalid VDSO (no DT_HASH)");
+ RAW_DCHECK(dynsym_, "invalid VDSO (no DT_SYMTAB)");
+ RAW_DCHECK(dynstr_, "invalid VDSO (no DT_STRTAB)");
+ RAW_DCHECK(versym_, "invalid VDSO (no DT_VERSYM)");
+ RAW_DCHECK(verdef_, "invalid VDSO (no DT_VERDEF)");
+ RAW_DCHECK(verdefnum_, "invalid VDSO (no DT_VERDEFNUM)");
+ RAW_DCHECK(strsize_, "invalid VDSO (no DT_STRSZ)");
+ // Mark this image as not present. Can not recur infinitely.
+ Init(0);
+ return;
+ }
+}
+
+bool ElfMemImage::LookupSymbol(const char *name,
+ const char *version,
+ int type,
+ SymbolInfo *info) const {
+ for (SymbolIterator it = begin(); it != end(); ++it) {
+ if (strcmp(it->name, name) == 0 && strcmp(it->version, version) == 0 &&
+ CurrentElfClass::ElfType(it->symbol) == type) {
+ if (info) {
+ *info = *it;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ElfMemImage::LookupSymbolByAddress(const void *address,
+ SymbolInfo *info_out) const {
+ for (SymbolIterator it = begin(); it != end(); ++it) {
+ const char *const symbol_start =
+ reinterpret_cast<const char *>(it->address);
+ const char *const symbol_end = symbol_start + it->symbol->st_size;
+ if (symbol_start <= address && address < symbol_end) {
+ if (info_out) {
+ // Client wants to know details for that symbol (the usual case).
+ if (CurrentElfClass::ElfBind(it->symbol) == STB_GLOBAL) {
+ // Strong symbol; just return it.
+ *info_out = *it;
+ return true;
+ } else {
+ // Weak or local. Record it, but keep looking for a strong one.
+ *info_out = *it;
+ }
+ } else {
+ // Client only cares if there is an overlapping symbol.
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+ElfMemImage::SymbolIterator::SymbolIterator(const void *const image, int index)
+ : index_(index), image_(image) {
+}
+
+const ElfMemImage::SymbolInfo *ElfMemImage::SymbolIterator::operator->() const {
+ return &info_;
+}
+
+const ElfMemImage::SymbolInfo& ElfMemImage::SymbolIterator::operator*() const {
+ return info_;
+}
+
+bool ElfMemImage::SymbolIterator::operator==(const SymbolIterator &rhs) const {
+ return this->image_ == rhs.image_ && this->index_ == rhs.index_;
+}
+
+bool ElfMemImage::SymbolIterator::operator!=(const SymbolIterator &rhs) const {
+ return !(*this == rhs);
+}
+
+ElfMemImage::SymbolIterator &ElfMemImage::SymbolIterator::operator++() {
+ this->Update(1);
+ return *this;
+}
+
+ElfMemImage::SymbolIterator ElfMemImage::begin() const {
+ SymbolIterator it(this, 0);
+ it.Update(0);
+ return it;
+}
+
+ElfMemImage::SymbolIterator ElfMemImage::end() const {
+ return SymbolIterator(this, GetNumSymbols());
+}
+
+void ElfMemImage::SymbolIterator::Update(int increment) {
+ const ElfMemImage *image = reinterpret_cast<const ElfMemImage *>(image_);
+ CHECK(image->IsPresent() || increment == 0);
+ if (!image->IsPresent()) {
+ return;
+ }
+ index_ += increment;
+ if (index_ >= image->GetNumSymbols()) {
+ index_ = image->GetNumSymbols();
+ return;
+ }
+ const ElfW(Sym) *symbol = image->GetDynsym(index_);
+ const ElfW(Versym) *version_symbol = image->GetVersym(index_);
+ CHECK(symbol && version_symbol);
+ const char *const symbol_name = image->GetDynstr(symbol->st_name);
+ const ElfW(Versym) version_index = version_symbol[0] & VERSYM_VERSION;
+ const ElfW(Verdef) *version_definition = NULL;
+ const char *version_name = "";
+ if (symbol->st_shndx == SHN_UNDEF) {
+ // Undefined symbols reference DT_VERNEED, not DT_VERDEF, and
+ // version_index could well be greater than verdefnum_, so calling
+ // GetVerdef(version_index) may trigger assertion.
+ } else {
+ version_definition = image->GetVerdef(version_index);
+ }
+ if (version_definition) {
+ // I am expecting 1 or 2 auxiliary entries: 1 for the version itself,
+ // optional 2nd if the version has a parent.
+ CHECK_LE(1, version_definition->vd_cnt);
+ CHECK_LE(version_definition->vd_cnt, 2);
+ const ElfW(Verdaux) *version_aux = image->GetVerdefAux(version_definition);
+ version_name = image->GetVerstr(version_aux->vda_name);
+ }
+ info_.name = symbol_name;
+ info_.version = version_name;
+ info_.address = image->GetSymAddr(symbol);
+ info_.symbol = symbol;
+}
+
+} // namespace base
+
+#endif // HAVE_ELF_MEM_IMAGE
diff --git a/src/base/elf_mem_image.h b/src/base/elf_mem_image.h
new file mode 100644
index 0000000..6f1f097
--- /dev/null
+++ b/src/base/elf_mem_image.h
@@ -0,0 +1,134 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Paul Pluzhnikov
+//
+// Allow dynamic symbol lookup for in-memory Elf images.
+
+#ifndef BASE_ELF_MEM_IMAGE_H_
+#define BASE_ELF_MEM_IMAGE_H_
+
+#include <config.h>
+#ifdef HAVE_FEATURES_H
+#include <features.h> // for __GLIBC__
+#endif
+
+// Maybe one day we can rewrite this file not to require the elf
+// symbol extensions in glibc, but for right now we need them.
+#if defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__)
+
+#define HAVE_ELF_MEM_IMAGE 1
+
+#include <stdlib.h>
+#include <link.h> // for ElfW
+
+namespace base {
+
+// An in-memory ELF image (may not exist on disk).
+class ElfMemImage {
+ public:
+ // Sentinel: there could never be an elf image at this address.
+ static const void *const kInvalidBase;
+
+ // Information about a single vdso symbol.
+ // All pointers are into .dynsym, .dynstr, or .text of the VDSO.
+ // Do not free() them or modify through them.
+ struct SymbolInfo {
+ const char *name; // E.g. "__vdso_getcpu"
+ const char *version; // E.g. "LINUX_2.6", could be ""
+ // for unversioned symbol.
+ const void *address; // Relocated symbol address.
+ const ElfW(Sym) *symbol; // Symbol in the dynamic symbol table.
+ };
+
+ // Supports iteration over all dynamic symbols.
+ class SymbolIterator {
+ public:
+ friend class ElfMemImage;
+ const SymbolInfo *operator->() const;
+ const SymbolInfo &operator*() const;
+ SymbolIterator& operator++();
+ bool operator!=(const SymbolIterator &rhs) const;
+ bool operator==(const SymbolIterator &rhs) const;
+ private:
+ SymbolIterator(const void *const image, int index);
+ void Update(int incr);
+ SymbolInfo info_;
+ int index_;
+ const void *const image_;
+ };
+
+
+ explicit ElfMemImage(const void *base);
+ void Init(const void *base);
+ bool IsPresent() const { return ehdr_ != NULL; }
+ const ElfW(Phdr)* GetPhdr(int index) const;
+ const ElfW(Sym)* GetDynsym(int index) const;
+ const ElfW(Versym)* GetVersym(int index) const;
+ const ElfW(Verdef)* GetVerdef(int index) const;
+ const ElfW(Verdaux)* GetVerdefAux(const ElfW(Verdef) *verdef) const;
+ const char* GetDynstr(ElfW(Word) offset) const;
+ const void* GetSymAddr(const ElfW(Sym) *sym) const;
+ const char* GetVerstr(ElfW(Word) offset) const;
+ int GetNumSymbols() const;
+
+ SymbolIterator begin() const;
+ SymbolIterator end() const;
+
+ // Look up versioned dynamic symbol in the image.
+ // Returns false if image is not present, or doesn't contain given
+ // symbol/version/type combination.
+ // If info_out != NULL, additional details are filled in.
+ bool LookupSymbol(const char *name, const char *version,
+ int symbol_type, SymbolInfo *info_out) const;
+
+ // Find info about symbol (if any) which overlaps given address.
+ // Returns true if symbol was found; false if image isn't present
+ // or doesn't have a symbol overlapping given address.
+ // If info_out != NULL, additional details are filled in.
+ bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const;
+
+ private:
+ const ElfW(Ehdr) *ehdr_;
+ const ElfW(Sym) *dynsym_;
+ const ElfW(Versym) *versym_;
+ const ElfW(Verdef) *verdef_;
+ const ElfW(Word) *hash_;
+ const char *dynstr_;
+ size_t strsize_;
+ size_t verdefnum_;
+ ElfW(Addr) link_base_; // Link-time base (p_vaddr of first PT_LOAD).
+};
+
+} // namespace base
+
+#endif // __ELF__ and __GLIBC__ and !__native_client__
+
+#endif // BASE_ELF_MEM_IMAGE_H_
diff --git a/src/base/low_level_alloc.cc b/src/base/low_level_alloc.cc
index 532c594..70f510d 100644
--- a/src/base/low_level_alloc.cc
+++ b/src/base/low_level_alloc.cc
@@ -233,7 +233,7 @@ namespace {
this->arena_->mu.Lock();
}
~ArenaLock() { RAW_CHECK(this->left_, "haven't left Arena region"); }
- void Leave() UNLOCK_FUNCTION() {
+ void Leave() /*UNLOCK_FUNCTION()*/ {
this->arena_->mu.Unlock();
#if 0
if (this->mask_valid_) {
diff --git a/src/base/spinlock_internal.cc b/src/base/spinlock_internal.cc
index b5b6ca4..7bd0e21 100644
--- a/src/base/spinlock_internal.cc
+++ b/src/base/spinlock_internal.cc
@@ -44,7 +44,7 @@
#if defined(_WIN32)
#include "base/spinlock_win32-inl.h"
-#elif defined(__linux__)
+#elif defined(__linux__) && !defined(__native_client__)
#include "base/spinlock_linux-inl.h"
#else
#include "base/spinlock_posix-inl.h"
diff --git a/src/base/vdso_support.cc b/src/base/vdso_support.cc
index 09288a5..767ee5f 100644
--- a/src/base/vdso_support.cc
+++ b/src/base/vdso_support.cc
@@ -54,285 +54,14 @@ using base::subtle::MemoryBarrier;
#define AT_SYSINFO_EHDR 33
#endif
-// From binutils/include/elf/common.h (this doesn't appear to be documented
-// anywhere else).
-//
-// /* This flag appears in a Versym structure. It means that the symbol
-// is hidden, and is only visible with an explicit version number.
-// This is a GNU extension. */
-// #define VERSYM_HIDDEN 0x8000
-//
-// /* This is the mask for the rest of the Versym information. */
-// #define VERSYM_VERSION 0x7fff
-
-#define VERSYM_VERSION 0x7fff
-
namespace base {
-namespace {
-template <int N> class ElfClass {
- public:
- static const int kElfClass = -1;
- static int ElfBind(const ElfW(Sym) *) {
- CHECK(false); // << "Unexpected word size";
- return 0;
- }
- static int ElfType(const ElfW(Sym) *) {
- CHECK(false); // << "Unexpected word size";
- return 0;
- }
-};
-
-template <> class ElfClass<32> {
- public:
- static const int kElfClass = ELFCLASS32;
- static int ElfBind(const ElfW(Sym) *symbol) {
- return ELF32_ST_BIND(symbol->st_info);
- }
- static int ElfType(const ElfW(Sym) *symbol) {
- return ELF32_ST_TYPE(symbol->st_info);
- }
-};
-
-template <> class ElfClass<64> {
- public:
- static const int kElfClass = ELFCLASS64;
- static int ElfBind(const ElfW(Sym) *symbol) {
- return ELF64_ST_BIND(symbol->st_info);
- }
- static int ElfType(const ElfW(Sym) *symbol) {
- return ELF64_ST_TYPE(symbol->st_info);
- }
-};
-
-typedef ElfClass<__WORDSIZE> CurrentElfClass;
-
-// Extract an element from one of the ELF tables, cast it to desired type.
-// This is just a simple arithmetic and a glorified cast.
-// Callers are responsible for bounds checking.
-template <class T>
-const T* GetTableElement(const ElfW(Ehdr) *ehdr,
- ElfW(Off) table_offset,
- ElfW(Word) element_size,
- size_t index) {
- return reinterpret_cast<const T*>(reinterpret_cast<const char *>(ehdr)
- + table_offset
- + index * element_size);
-}
-} // namespace
-
-const void *const VDSOSupport::kInvalidBase =
- reinterpret_cast<const void *>(~0L);
-
-const void *VDSOSupport::vdso_base_ = kInvalidBase;
+const void *VDSOSupport::vdso_base_ = ElfMemImage::kInvalidBase;
VDSOSupport::GetCpuFn VDSOSupport::getcpu_fn_ = &InitAndGetCPU;
-
-VDSOSupport::ElfMemImage::ElfMemImage(const void *base) {
- CHECK(base != kInvalidBase);
- Init(base);
-}
-
-int VDSOSupport::ElfMemImage::GetNumSymbols() const {
- if (!hash_) {
- return 0;
- }
- // See http://www.caldera.com/developers/gabi/latest/ch5.dynamic.html#hash
- return hash_[1];
-}
-
-const ElfW(Sym) *VDSOSupport::ElfMemImage::GetDynsym(int index) const {
- CHECK_LT(index, GetNumSymbols());
- return dynsym_ + index;
-}
-
-const ElfW(Versym) *VDSOSupport::ElfMemImage::GetVersym(int index) const {
- CHECK_LT(index, GetNumSymbols());
- return versym_ + index;
-}
-
-const ElfW(Phdr) *VDSOSupport::ElfMemImage::GetPhdr(int index) const {
- CHECK_LT(index, ehdr_->e_phnum);
- return GetTableElement<ElfW(Phdr)>(ehdr_,
- ehdr_->e_phoff,
- ehdr_->e_phentsize,
- index);
-}
-
-const char *VDSOSupport::ElfMemImage::GetDynstr(ElfW(Word) offset) const {
- CHECK_LT(offset, strsize_);
- return dynstr_ + offset;
-}
-
-const void *VDSOSupport::ElfMemImage::GetSymAddr(const ElfW(Sym) *sym) const {
- if (sym->st_shndx == SHN_UNDEF || sym->st_shndx >= SHN_LORESERVE) {
- // Symbol corresponds to "special" (e.g. SHN_ABS) section.
- return reinterpret_cast<const void *>(sym->st_value);
- }
- CHECK_LT(link_base_, sym->st_value);
- return GetTableElement<char>(ehdr_, 0, 1, sym->st_value) - link_base_;
-}
-
-const ElfW(Verdef) *VDSOSupport::ElfMemImage::GetVerdef(int index) const {
- CHECK_LE(index, verdefnum_);
- const ElfW(Verdef) *version_definition = verdef_;
- while (version_definition->vd_ndx < index && version_definition->vd_next) {
- const char *const version_definition_as_char =
- reinterpret_cast<const char *>(version_definition);
- version_definition =
- reinterpret_cast<const ElfW(Verdef) *>(version_definition_as_char +
- version_definition->vd_next);
- }
- return version_definition->vd_ndx == index ? version_definition : NULL;
-}
-
-const ElfW(Verdaux) *VDSOSupport::ElfMemImage::GetVerdefAux(
- const ElfW(Verdef) *verdef) const {
- return reinterpret_cast<const ElfW(Verdaux) *>(verdef+1);
-}
-
-const char *VDSOSupport::ElfMemImage::GetVerstr(ElfW(Word) offset) const {
- CHECK_LT(offset, strsize_);
- return dynstr_ + offset;
-}
-
-void VDSOSupport::ElfMemImage::Init(const void *base) {
- ehdr_ = NULL;
- dynsym_ = NULL;
- dynstr_ = NULL;
- versym_ = NULL;
- verdef_ = NULL;
- hash_ = NULL;
- strsize_ = 0;
- verdefnum_ = 0;
- link_base_ = ~0L; // Sentinel: PT_LOAD .p_vaddr can't possibly be this.
- if (!base) {
- return;
- }
- const intptr_t base_as_uintptr_t = reinterpret_cast<uintptr_t>(base);
- // Fake VDSO has low bit set.
- const bool fake_vdso = ((base_as_uintptr_t & 1) != 0);
- base = reinterpret_cast<const void *>(base_as_uintptr_t & ~1);
- const char *const base_as_char = reinterpret_cast<const char *>(base);
- if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 ||
- base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) {
- RAW_DCHECK(false, "no ELF magic"); // at %p", base);
- return;
- }
- int elf_class = base_as_char[EI_CLASS];
- if (elf_class != CurrentElfClass::kElfClass) {
- DCHECK_EQ(elf_class, CurrentElfClass::kElfClass);
- return;
- }
- switch (base_as_char[EI_DATA]) {
- case ELFDATA2LSB: {
- if (__LITTLE_ENDIAN != __BYTE_ORDER) {
- DCHECK_EQ(__LITTLE_ENDIAN, __BYTE_ORDER); // << ": wrong byte order";
- return;
- }
- break;
- }
- case ELFDATA2MSB: {
- if (__BIG_ENDIAN != __BYTE_ORDER) {
- DCHECK_EQ(__BIG_ENDIAN, __BYTE_ORDER); // << ": wrong byte order";
- return;
- }
- break;
- }
- default: {
- RAW_DCHECK(false, "unexpected data encoding"); // << base_as_char[EI_DATA];
- return;
- }
- }
-
- ehdr_ = reinterpret_cast<const ElfW(Ehdr) *>(base);
- const ElfW(Phdr) *dynamic_program_header = NULL;
- for (int i = 0; i < ehdr_->e_phnum; ++i) {
- const ElfW(Phdr) *const program_header = GetPhdr(i);
- switch (program_header->p_type) {
- case PT_LOAD:
- if (link_base_ == ~0L) {
- link_base_ = program_header->p_vaddr;
- }
- break;
- case PT_DYNAMIC:
- dynamic_program_header = program_header;
- break;
- }
- }
- if (link_base_ == ~0L || !dynamic_program_header) {
- RAW_DCHECK(~0L != link_base_, "no PT_LOADs in VDSO");
- RAW_DCHECK(dynamic_program_header, "no PT_DYNAMIC in VDSO");
- // Mark this image as not present. Can not recur infinitely.
- Init(0);
- return;
- }
- ptrdiff_t relocation =
- base_as_char - reinterpret_cast<const char *>(link_base_);
- ElfW(Dyn) *dynamic_entry =
- reinterpret_cast<ElfW(Dyn) *>(dynamic_program_header->p_vaddr +
- relocation);
- for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) {
- ElfW(Xword) value = dynamic_entry->d_un.d_val;
- if (fake_vdso) {
- // A complication: in the real VDSO, dynamic entries are not relocated
- // (it wasn't loaded by a dynamic loader). But when testing with a
- // "fake" dlopen()ed vdso library, the loader relocates some (but
- // not all!) of them before we get here.
- if (dynamic_entry->d_tag == DT_VERDEF) {
- // The only dynamic entry (of the ones we care about) libc-2.3.6
- // loader doesn't relocate.
- value += relocation;
- }
- } else {
- // Real VDSO. Everything needs to be relocated.
- value += relocation;
- }
- switch (dynamic_entry->d_tag) {
- case DT_HASH:
- hash_ = reinterpret_cast<ElfW(Word) *>(value);
- break;
- case DT_SYMTAB:
- dynsym_ = reinterpret_cast<ElfW(Sym) *>(value);
- break;
- case DT_STRTAB:
- dynstr_ = reinterpret_cast<const char *>(value);
- break;
- case DT_VERSYM:
- versym_ = reinterpret_cast<ElfW(Versym) *>(value);
- break;
- case DT_VERDEF:
- verdef_ = reinterpret_cast<ElfW(Verdef) *>(value);
- break;
- case DT_VERDEFNUM:
- verdefnum_ = dynamic_entry->d_un.d_val;
- break;
- case DT_STRSZ:
- strsize_ = dynamic_entry->d_un.d_val;
- break;
- default:
- // Unrecognized entries explicitly ignored.
- break;
- }
- }
- if (!hash_ || !dynsym_ || !dynstr_ || !versym_ ||
- !verdef_ || !verdefnum_ || !strsize_) {
- RAW_DCHECK(hash_, "invalid VDSO (no DT_HASH)");
- RAW_DCHECK(dynsym_, "invalid VDSO (no DT_SYMTAB)");
- RAW_DCHECK(dynstr_, "invalid VDSO (no DT_STRTAB)");
- RAW_DCHECK(versym_, "invalid VDSO (no DT_VERSYM)");
- RAW_DCHECK(verdef_, "invalid VDSO (no DT_VERDEF)");
- RAW_DCHECK(verdefnum_, "invalid VDSO (no DT_VERDEFNUM)");
- RAW_DCHECK(strsize_, "invalid VDSO (no DT_STRSZ)");
- // Mark this image as not present. Can not recur infinitely.
- Init(0);
- return;
- }
-}
-
VDSOSupport::VDSOSupport()
// If vdso_base_ is still set to kInvalidBase, we got here
// before VDSOSupport::Init has been called. Call it now.
- : image_(vdso_base_ == kInvalidBase ? Init() : vdso_base_) {
+ : image_(vdso_base_ == ElfMemImage::kInvalidBase ? Init() : vdso_base_) {
}
// NOTE: we can't use GoogleOnceInit() below, because we can be
@@ -345,7 +74,7 @@ VDSOSupport::VDSOSupport()
// Finally, even if there is a race here, it is harmless, because
// the operation should be idempotent.
const void *VDSOSupport::Init() {
- if (vdso_base_ == kInvalidBase) {
+ if (vdso_base_ == ElfMemImage::kInvalidBase) {
// Valgrind zaps AT_SYSINFO_EHDR and friends from the auxv[]
// on stack, and so glibc works as if VDSO was not present.
// But going directly to kernel via /proc/self/auxv below bypasses
@@ -372,7 +101,7 @@ const void *VDSOSupport::Init() {
}
}
close(fd);
- if (vdso_base_ == kInvalidBase) {
+ if (vdso_base_ == ElfMemImage::kInvalidBase) {
// Didn't find AT_SYSINFO_EHDR in auxv[].
vdso_base_ = NULL;
}
@@ -395,6 +124,7 @@ const void *VDSOSupport::Init() {
}
const void *VDSOSupport::SetBase(const void *base) {
+ CHECK(base != ElfMemImage::kInvalidBase);
const void *old_base = vdso_base_;
vdso_base_ = base;
image_.Init(base);
@@ -407,116 +137,12 @@ bool VDSOSupport::LookupSymbol(const char *name,
const char *version,
int type,
SymbolInfo *info) const {
- for (SymbolIterator it = begin(); it != end(); ++it) {
- if (strcmp(it->name, name) == 0 && strcmp(it->version, version) == 0 &&
- CurrentElfClass::ElfType(it->symbol) == type) {
- if (info) {
- *info = *it;
- }
- return true;
- }
- }
- return false;
+ return image_.LookupSymbol(name, version, type, info);
}
bool VDSOSupport::LookupSymbolByAddress(const void *address,
SymbolInfo *info_out) const {
- for (SymbolIterator it = begin(); it != end(); ++it) {
- const char *const symbol_start =
- reinterpret_cast<const char *>(it->address);
- const char *const symbol_end = symbol_start + it->symbol->st_size;
- if (symbol_start <= address && address < symbol_end) {
- if (info_out) {
- // Client wants to know details for that symbol (the usual case).
- if (CurrentElfClass::ElfBind(it->symbol) == STB_GLOBAL) {
- // Strong symbol; just return it.
- *info_out = *it;
- return true;
- } else {
- // Weak or local. Record it, but keep looking for a strong one.
- *info_out = *it;
- }
- } else {
- // Client only cares if there is an overlapping symbol.
- return true;
- }
- }
- }
- return false;
-}
-
-VDSOSupport::SymbolIterator::SymbolIterator(const void *const image, int index)
- : index_(index), image_(image) {
-}
-
-const VDSOSupport::SymbolInfo *VDSOSupport::SymbolIterator::operator->() const {
- return &info_;
-}
-
-const VDSOSupport::SymbolInfo& VDSOSupport::SymbolIterator::operator*() const {
- return info_;
-}
-
-bool VDSOSupport::SymbolIterator::operator==(const SymbolIterator &rhs) const {
- return this->image_ == rhs.image_ && this->index_ == rhs.index_;
-}
-
-bool VDSOSupport::SymbolIterator::operator!=(const SymbolIterator &rhs) const {
- return !(*this == rhs);
-}
-
-VDSOSupport::SymbolIterator &VDSOSupport::SymbolIterator::operator++() {
- this->Update(1);
- return *this;
-}
-
-VDSOSupport::SymbolIterator VDSOSupport::begin() const {
- SymbolIterator it(&image_, 0);
- it.Update(0);
- return it;
-}
-
-VDSOSupport::SymbolIterator VDSOSupport::end() const {
- return SymbolIterator(&image_, image_.GetNumSymbols());
-}
-
-void VDSOSupport::SymbolIterator::Update(int increment) {
- const ElfMemImage *image = reinterpret_cast<const ElfMemImage *>(image_);
- CHECK(image->IsPresent() || increment == 0);
- if (!image->IsPresent()) {
- return;
- }
- index_ += increment;
- if (index_ >= image->GetNumSymbols()) {
- index_ = image->GetNumSymbols();
- return;
- }
- const ElfW(Sym) *symbol = image->GetDynsym(index_);
- const ElfW(Versym) *version_symbol = image->GetVersym(index_);
- CHECK(symbol && version_symbol);
- const char *const symbol_name = image->GetDynstr(symbol->st_name);
- const ElfW(Versym) version_index = version_symbol[0] & VERSYM_VERSION;
- const ElfW(Verdef) *version_definition = NULL;
- const char *version_name = "";
- if (symbol->st_shndx == SHN_UNDEF) {
- // Undefined symbols reference DT_VERNEED, not DT_VERDEF, and
- // version_index could well be greater than verdefnum_, so calling
- // GetVerdef(version_index) may trigger assertion.
- } else {
- version_definition = image->GetVerdef(version_index);
- }
- if (version_definition) {
- // I am expecting 1 or 2 auxiliary entries: 1 for the version itself,
- // optional 2nd if the version has a parent.
- CHECK_LE(1, version_definition->vd_cnt);
- CHECK_LE(version_definition->vd_cnt, 2);
- const ElfW(Verdaux) *version_aux = image->GetVerdefAux(version_definition);
- version_name = image->GetVerstr(version_aux->vda_name);
- }
- info_.name = symbol_name;
- info_.version = version_name;
- info_.address = image->GetSymAddr(symbol);
- info_.symbol = symbol;
+ return image_.LookupSymbolByAddress(address, info_out);
}
// NOLINT on 'long' because this routine mimics kernel api.
diff --git a/src/base/vdso_support.h b/src/base/vdso_support.h
index 131646a..b97ab25 100644
--- a/src/base/vdso_support.h
+++ b/src/base/vdso_support.h
@@ -1,5 +1,34 @@
-// Copyright 2008 Google Inc. All Rights Reserved.
-// Author: ppluzhnikov@google.com (Paul Pluzhnikov)
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Paul Pluzhnikov
//
// Allow dynamic symbol lookup in the kernel VDSO page.
//
@@ -27,19 +56,14 @@
#define BASE_VDSO_SUPPORT_H_
#include <config.h>
-#ifdef HAVE_FEATURES_H
-#include <features.h> // for __GLIBC__
-#endif
#include "base/basictypes.h"
+#include "base/elf_mem_image.h"
-// Maybe one day we can rewrite this file not to require the elf
-// symbol extensions in glibc, but for right now we need them.
-#if defined(__ELF__) && defined(__GLIBC__)
+#ifdef HAVE_ELF_MEM_IMAGE
#define HAVE_VDSO_SUPPORT 1
#include <stdlib.h> // for NULL
-#include <link.h> // for ElfW
namespace base {
@@ -47,45 +71,17 @@ namespace base {
// use any memory allocation routines.
class VDSOSupport {
public:
- // Sentinel: there could never be a VDSO at this address.
- static const void *const kInvalidBase;
-
- // Information about a single vdso symbol.
- // All pointers are into .dynsym, .dynstr, or .text of the VDSO.
- // Do not free() them or modify through them.
- struct SymbolInfo {
- const char *name; // E.g. "__vdso_getcpu"
- const char *version; // E.g. "LINUX_2.6", could be ""
- // for unversioned symbol.
- const void *address; // Relocated symbol address.
- const ElfW(Sym) *symbol; // Symbol in the dynamic symbol table.
- };
-
- // Supports iteration over all dynamic symbols.
- class SymbolIterator {
- public:
- friend class VDSOSupport;
- const SymbolInfo *operator->() const;
- const SymbolInfo &operator*() const;
- SymbolIterator& operator++();
- bool operator!=(const SymbolIterator &rhs) const;
- bool operator==(const SymbolIterator &rhs) const;
- private:
- SymbolIterator(const void *const image, int index);
- void Update(int incr);
- SymbolInfo info_;
- int index_;
- const void *const image_;
- };
-
VDSOSupport();
+ typedef ElfMemImage::SymbolInfo SymbolInfo;
+ typedef ElfMemImage::SymbolIterator SymbolIterator;
+
// Answers whether we have a vdso at all.
bool IsPresent() const { return image_.IsPresent(); }
// Allow to iterate over all VDSO symbols.
- SymbolIterator begin() const;
- SymbolIterator end() const;
+ SymbolIterator begin() const { return image_.begin(); }
+ SymbolIterator end() const { return image_.end(); }
// Look up versioned dynamic symbol in the kernel VDSO.
// Returns false if VDSO is not present, or doesn't contain given
@@ -111,33 +107,6 @@ class VDSOSupport {
static const void *Init();
private:
- // An in-memory ELF image (may not exist on disk).
- class ElfMemImage {
- public:
- explicit ElfMemImage(const void *base);
- void Init(const void *base);
- bool IsPresent() const { return ehdr_ != NULL; }
- const ElfW(Phdr)* GetPhdr(int index) const;
- const ElfW(Sym)* GetDynsym(int index) const;
- const ElfW(Versym)* GetVersym(int index) const;
- const ElfW(Verdef)* GetVerdef(int index) const;
- const ElfW(Verdaux)* GetVerdefAux(const ElfW(Verdef) *verdef) const;
- const char* GetDynstr(ElfW(Word) offset) const;
- const void* GetSymAddr(const ElfW(Sym) *sym) const;
- const char* GetVerstr(ElfW(Word) offset) const;
- int GetNumSymbols() const;
- private:
- const ElfW(Ehdr) *ehdr_;
- const ElfW(Sym) *dynsym_;
- const ElfW(Versym) *versym_;
- const ElfW(Verdef) *verdef_;
- const ElfW(Word) *hash_;
- const char *dynstr_;
- size_t strsize_;
- size_t verdefnum_;
- ElfW(Addr) link_base_; // Link-time base (p_vaddr of first PT_LOAD).
- };
-
// image_ represents VDSO ELF image in memory.
// image_.ehdr_ == NULL implies there is no VDSO.
ElfMemImage image_;
@@ -181,6 +150,6 @@ class VDSOSupport {
int GetCPU();
} // namespace base
-#endif // __ELF__ and __GLIBC__
+#endif // HAVE_ELF_MEM_IMAGE
#endif // BASE_VDSO_SUPPORT_H_
diff --git a/src/central_freelist.cc b/src/central_freelist.cc
index 6b3be06..9b20cf8 100644
--- a/src/central_freelist.cc
+++ b/src/central_freelist.cc
@@ -31,29 +31,51 @@
// Author: Sanjay Ghemawat <opensource@google.com>
#include "config.h"
+#include <algorithm>
#include "central_freelist.h"
-
#include "internal_logging.h" // for ASSERT, MESSAGE
#include "linked_list.h" // for SLL_Next, SLL_Push, etc
#include "page_heap.h" // for PageHeap
#include "static_vars.h" // for Static
+using std::min;
+using std::max;
+
namespace tcmalloc {
void CentralFreeList::Init(size_t cl) {
size_class_ = cl;
tcmalloc::DLL_Init(&empty_);
tcmalloc::DLL_Init(&nonempty_);
+ num_spans_ = 0;
counter_ = 0;
+ max_cache_size_ = kMaxNumTransferEntries;
#ifdef TCMALLOC_SMALL_BUT_SLOW
// Disable the transfer cache for the small footprint case.
cache_size_ = 0;
#else
cache_size_ = 16;
#endif
+ if (cl > 0) {
+ // Limit the maximum size of the cache based on the size class. If this
+ // is not done, large size class objects will consume a lot of memory if
+ // they just sit in the transfer cache.
+ int32_t bytes = Static::sizemap()->ByteSizeForClass(cl);
+ int32_t objs_to_move = Static::sizemap()->num_objects_to_move(cl);
+
+ ASSERT(objs_to_move > 0 && bytes > 0);
+ // Limit each size class cache to at most 1MB of objects or one entry,
+ // whichever is greater. Total transfer cache memory used across all
+ // size classes then can't be greater than approximately
+ // 1MB * kMaxNumTransferEntries.
+ // min and max are in parens to avoid macro-expansion on windows.
+ max_cache_size_ = (min)(max_cache_size_,
+ (max)(1, (1024 * 1024) / (bytes * objs_to_move)));
+ cache_size_ = (min)(cache_size_, max_cache_size_);
+ }
used_slots_ = 0;
- ASSERT(cache_size_ <= kNumTransferEntries);
+ ASSERT(cache_size_ <= max_cache_size_);
}
void CentralFreeList::ReleaseListToSpans(void* start) {
@@ -110,6 +132,7 @@ void CentralFreeList::ReleaseToSpans(void* object) {
counter_ -= ((span->length<<kPageShift) /
Static::sizemap()->ByteSizeForClass(span->sizeclass));
tcmalloc::DLL_Remove(span);
+ --num_spans_;
// Release central list lock while operating on pageheap
lock_.Unlock();
@@ -144,7 +167,7 @@ bool CentralFreeList::MakeCacheSpace() {
// Is there room in the cache?
if (used_slots_ < cache_size_) return true;
// Check if we can expand this cache?
- if (cache_size_ == kNumTransferEntries) return false;
+ if (cache_size_ == max_cache_size_) return false;
// Ok, we'll try to grab an entry from some other size class.
if (EvictRandomSizeClass(size_class_, false) ||
EvictRandomSizeClass(size_class_, true)) {
@@ -153,7 +176,7 @@ bool CentralFreeList::MakeCacheSpace() {
// EvictRandomSizeClass (via ShrinkCache and the LockInverter), so the
// cache_size may have changed. Therefore, check and verify that it is
// still OK to increase the cache_size.
- if (cache_size_ < kNumTransferEntries) {
+ if (cache_size_ < max_cache_size_) {
cache_size_++;
return true;
}
@@ -210,7 +233,7 @@ void CentralFreeList::InsertRange(void *start, void *end, int N) {
MakeCacheSpace()) {
int slot = used_slots_++;
ASSERT(slot >=0);
- ASSERT(slot < kNumTransferEntries);
+ ASSERT(slot < max_cache_size_);
TCEntry *entry = &tc_slots_[slot];
entry->head = start;
entry->tail = end;
@@ -328,6 +351,7 @@ void CentralFreeList::Populate() {
// Add span to list of non-empty spans
lock_.Lock();
tcmalloc::DLL_Prepend(&nonempty_, span);
+ ++num_spans_;
counter_ += num;
}
@@ -336,4 +360,16 @@ int CentralFreeList::tc_length() {
return used_slots_ * Static::sizemap()->num_objects_to_move(size_class_);
}
+size_t CentralFreeList::OverheadBytes() {
+ SpinLockHolder h(&lock_);
+ if (size_class_ == 0) { // 0 holds the 0-sized allocations
+ return 0;
+ }
+ const size_t pages_per_span = Static::sizemap()->class_to_pages(size_class_);
+ const size_t object_size = Static::sizemap()->class_to_size(size_class_);
+ ASSERT(object_size > 0);
+ const size_t overhead_per_span = (pages_per_span * kPageSize) % object_size;
+ return num_spans_ * overhead_per_span;
+}
+
} // namespace tcmalloc
diff --git a/src/central_freelist.h b/src/central_freelist.h
index 69a09af..27e9d35 100644
--- a/src/central_freelist.h
+++ b/src/central_freelist.h
@@ -35,7 +35,9 @@
#include "config.h"
#include <stddef.h> // for size_t
+#ifdef HAVE_STDINT_H
#include <stdint.h> // for int32_t
+#endif
#include "base/spinlock.h"
#include "base/thread_annotations.h"
#include "common.h"
@@ -66,6 +68,12 @@ class CentralFreeList {
// Returns the number of free objects in the transfer cache.
int tc_length();
+ // Returns the memory overhead (internal fragmentation) attributable
+ // to the freelist. This is memory lost when the size of elements
+ // in a freelist doesn't exactly divide the page-size (an 8192-byte
+ // page full of 5-byte objects would have 2 bytes memory overhead).
+ size_t OverheadBytes();
+
private:
// TransferCache is used to cache transfers of
// sizemap.num_objects_to_move(size_class) back and forth between
@@ -75,16 +83,16 @@ class CentralFreeList {
void *tail; // Tail of chain of objects.
};
- // A central cache freelist can have anywhere from 0 to kNumTransferEntries
- // slots to put link list chains into. To keep memory usage bounded the total
- // number of TCEntries across size classes is fixed. Currently each size
- // class is initially given one TCEntry which also means that the maximum any
- // one class can have is kNumClasses.
+ // A central cache freelist can have anywhere from 0 to kMaxNumTransferEntries
+ // slots to put link list chains into.
#ifdef TCMALLOC_SMALL_BUT_SLOW
// For the small memory model, the transfer cache is not used.
- static const int kNumTransferEntries = 0;
+ static const int kMaxNumTransferEntries = 0;
#else
- static const int kNumTransferEntries = kNumClasses;
+ // Starting point for the the maximum number of entries in the transfer cache.
+ // This actual maximum for a given size class may be lower than this
+ // maximum value.
+ static const int kMaxNumTransferEntries = 64;
#endif
// REQUIRES: lock_ is held
@@ -143,12 +151,15 @@ class CentralFreeList {
size_t size_class_; // My size class
Span empty_; // Dummy header for list of empty spans
Span nonempty_; // Dummy header for list of non-empty spans
+ size_t num_spans_; // Number of spans in empty_ plus nonempty_
size_t counter_; // Number of free objects in cache entry
- // Here we reserve space for TCEntry cache slots. Since one size class can
- // end up getting all the TCEntries quota in the system we just preallocate
- // sufficient number of entries here.
- TCEntry tc_slots_[kNumTransferEntries];
+ // Here we reserve space for TCEntry cache slots. Space is preallocated
+ // for the largest possible number of entries than any one size class may
+ // accumulate. Not all size classes are allowed to accumulate
+ // kMaxNumTransferEntries, so there is some wasted space for those size
+ // classes.
+ TCEntry tc_slots_[kMaxNumTransferEntries];
// Number of currently used cached entries in tc_slots_. This variable is
// updated under a lock but can be read without one.
@@ -157,6 +168,8 @@ class CentralFreeList {
// adaptive value that is increased if there is lots of traffic
// on a given size class.
int32_t cache_size_;
+ // Maximum size of the cache for a given size class.
+ int32_t max_cache_size_;
};
// Pads each CentralCache object to multiple of 64 bytes. Since some
diff --git a/src/common.cc b/src/common.cc
index 8221b08..90e6626 100644
--- a/src/common.cc
+++ b/src/common.cc
@@ -54,9 +54,9 @@ static inline int LgFloor(size_t n) {
int AlignmentForSize(size_t size) {
int alignment = kAlignment;
- if (size >= 2048) {
- // Cap alignment at 256 for large sizes.
- alignment = 256;
+ if (size > kMaxSize) {
+ // Cap alignment at kPageSize for large sizes.
+ alignment = kPageSize;
} else if (size >= 128) {
// Space wasted due to alignment is at most 1/8, i.e., 12.5%.
alignment = (1 << LgFloor(size)) / 8;
@@ -65,6 +65,10 @@ int AlignmentForSize(size_t size) {
// requirements for some SSE types.
alignment = 16;
}
+ // Maximum alignment allowed is page size alignment.
+ if (alignment > kPageSize) {
+ alignment = kPageSize;
+ }
CHECK_CONDITION(size < 16 || alignment >= 16);
CHECK_CONDITION((alignment & (alignment - 1)) == 0);
return alignment;
@@ -105,22 +109,23 @@ void SizeMap::Init() {
int sc = 1; // Next size class to assign
int alignment = kAlignment;
CHECK_CONDITION(kAlignment <= 16);
- int last_lg = -1;
for (size_t size = kAlignment; size <= kMaxSize; size += alignment) {
- int lg = LgFloor(size);
- if (lg > last_lg) {
- // Increase alignment every so often to reduce number of size classes.
- alignment = AlignmentForSize(size);
- last_lg = lg;
- }
+ alignment = AlignmentForSize(size);
CHECK_CONDITION((size % alignment) == 0);
- // Allocate enough pages so leftover is less than 1/8 of total.
- // This bounds wasted space to at most 12.5%.
- size_t psize = kPageSize;
- while ((psize % size) > (psize >> 3)) {
+ int blocks_to_move = NumMoveSize(size) / 4;
+ size_t psize = 0;
+ do {
psize += kPageSize;
- }
+ // Allocate enough pages so leftover is less than 1/8 of total.
+ // This bounds wasted space to at most 12.5%.
+ while ((psize % size) > (psize >> 3)) {
+ psize += kPageSize;
+ }
+ // Continue to add pages until there are at least as many objects in
+ // the span as are needed when moving objects from the central
+ // freelists and spans to the thread caches.
+ } while ((psize / size) < (blocks_to_move));
const size_t my_pages = psize >> kPageShift;
if (sc > 1 && my_pages == class_to_pages_[sc-1]) {
diff --git a/src/common.h b/src/common.h
index e960c57..72725ca 100644
--- a/src/common.h
+++ b/src/common.h
@@ -63,16 +63,15 @@ typedef uintptr_t Length;
#if defined(TCMALLOC_LARGE_PAGES)
static const size_t kPageShift = 15;
-static const size_t kNumClasses = 95;
-static const size_t kMaxThreadCacheSize = 4 << 20;
+static const size_t kNumClasses = 78;
#else
-static const size_t kPageShift = 12;
-static const size_t kNumClasses = 61;
-static const size_t kMaxThreadCacheSize = 2 << 20;
+static const size_t kPageShift = 13;
+static const size_t kNumClasses = 86;
#endif
+static const size_t kMaxThreadCacheSize = 4 << 20;
static const size_t kPageSize = 1 << kPageShift;
-static const size_t kMaxSize = 8u * kPageSize;
+static const size_t kMaxSize = 256 * 1024;
static const size_t kAlignment = 8;
static const size_t kLargeSizeClass = 0;
// For all span-lengths < kMaxPages we keep an exact-size list.
@@ -166,7 +165,7 @@ class SizeMap {
// 32768 (32768 + 127 + (120<<7)) / 128 376
static const int kMaxSmallSize = 1024;
static const size_t kClassArraySize =
- (((1 << kPageShift) * 8u + 127 + (120 << 7)) >> 7) + 1;
+ ((kMaxSize + 127 + (120 << 7)) >> 7) + 1;
unsigned char class_array_[kClassArraySize];
// Compute index of the class_array[] entry for a given size
diff --git a/src/config.h.in b/src/config.h.in
index 9112951..64766ff 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -189,6 +189,9 @@
*/
#undef LT_OBJDIR
+/* Define to 'volatile' if __malloc_hook is declared volatile */
+#undef MALLOC_HOOK_MAYBE_VOLATILE
+
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
#undef NO_MINUS_C_MINUS_O
@@ -232,6 +235,12 @@
/* printf format code for printing a size_t and ssize_t */
#undef PRIxS
+/* Mark the systems where we know it's bad if pthreads runs too
+ early before main (before threads are initialized, presumably). */
+#ifdef __FreeBSD__
+#define PTHREADS_CRASHES_IF_RUN_TOO_EARLY 1
+#endif
+
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#undef PTHREAD_CREATE_JOINABLE
diff --git a/src/debugallocation.cc b/src/debugallocation.cc
index 9de927a..7cac751 100644
--- a/src/debugallocation.cc
+++ b/src/debugallocation.cc
@@ -134,13 +134,13 @@ static void TracePrintf(int fd, const char *fmt, ...)
// The do_* functions are defined in tcmalloc/tcmalloc.cc,
// which is included before this file
// when TCMALLOC_FOR_DEBUGALLOCATION is defined
-#define BASE_MALLOC_NEW(size) cpp_alloc(size, false)
+// TODO(csilvers): get rid of these now that we are tied to tcmalloc.
+#define BASE_MALLOC_NEW do_malloc
#define BASE_MALLOC do_malloc
#define BASE_FREE do_free
#define BASE_MALLOC_STATS do_malloc_stats
#define BASE_MALLOPT do_mallopt
#define BASE_MALLINFO do_mallinfo
-#define BASE_MALLOC_SIZE(ptr) GetSizeWithCallback(ptr, &InvalidGetAllocatedSize)
// ========================================================================= //
@@ -995,14 +995,25 @@ class DebugMallocImplementation : public TCMallocImplementation {
return MallocBlock::MemoryStats(blocks, total, histogram);
}
+ virtual size_t GetEstimatedAllocatedSize(size_t size) {
+ return size;
+ }
+
virtual size_t GetAllocatedSize(void* p) {
if (p) {
+ RAW_CHECK(GetOwnership(p) != MallocExtension::kNotOwned,
+ "ptr not allocated by tcmalloc");
return MallocBlock::FromRawPointer(p)->data_size();
}
return 0;
}
- virtual size_t GetEstimatedAllocatedSize(size_t size) {
- return size;
+
+ virtual MallocExtension::Ownership GetOwnership(const void* p) {
+ if (p) {
+ const MallocBlock* mb = MallocBlock::FromRawPointer(p);
+ return TCMallocImplementation::GetOwnership(mb);
+ }
+ return MallocExtension::kNotOwned; // nobody owns NULL
}
virtual void GetFreeListSizes(vector<MallocExtension::FreeListInfo>* v) {
@@ -1038,8 +1049,10 @@ REGISTER_MODULE_INITIALIZER(debugallocation, {
// ========================================================================= //
// This is mostly the same a cpp_alloc in tcmalloc.cc.
-// TODO(csilvers): write a wrapper for new-handler so we don't have to
-// copy this code so much.
+// TODO(csilvers): change Allocate() above to call cpp_alloc, so we
+// don't have to reproduce the logic here. To make tc_new_mode work
+// properly, I think we'll need to separate out the logic of throwing
+// from the logic of calling the new-handler.
inline void* debug_cpp_alloc(size_t size, int new_type, bool nothrow) {
for (;;) {
void* p = DebugAllocate(size, new_type);
@@ -1355,29 +1368,5 @@ extern "C" PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) __THROW {
#endif
extern "C" PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) __THROW {
- if (!ptr) {
- return 0;
- }
- MallocBlock* mb = MallocBlock::FromRawPointer(ptr);
- // This is just to make sure we actually own mb (and ptr). We don't
- // use the actual value, just the 'exception' it raises on error.
- (void)BASE_MALLOC_SIZE(mb);
- return mb->data_size();
-}
-
-// Override __libc_memalign in libc on linux boxes.
-// They have a bug in libc that causes them (very rarely) to allocate
-// with __libc_memalign() yet deallocate with free().
-// This function is an exception to the rule of calling MallocHook method
-// from the stack frame of the allocation function;
-// heap-checker handles this special case explicitly.
-static void *MemalignOverride(size_t align, size_t size, const void *caller)
- __THROW ATTRIBUTE_SECTION(google_malloc);
-
-static void *MemalignOverride(size_t align, size_t size, const void *caller)
- __THROW {
- void *p = do_debug_memalign_or_debug_cpp_memalign(align, size);
- MallocHook::InvokeNewHook(p, size);
- return p;
+ return MallocExtension::instance()->GetAllocatedSize(ptr);
}
-void *(*__memalign_hook)(size_t, size_t, const void *) = MemalignOverride;
diff --git a/src/google/heap-checker.h b/src/google/heap-checker.h
index f46f353..a431fe9 100644
--- a/src/google/heap-checker.h
+++ b/src/google/heap-checker.h
@@ -185,8 +185,7 @@ class PERFTOOLS_DLL_DECL HeapLeakChecker {
// for the purposes of heap leak checking.
// If 'ptr' does not point to an active allocated object
// at the time of this call, it is ignored;
- // but if it does, the object must not get deleted from the heap later on;
- // it must also be not already ignored at the time of this call.
+ // but if it does, the object must not get deleted from the heap later on.
//
// See also HiddenPointer, below, if you need to prevent a pointer from
// being traversed by the heap checker but do not wish to transitively
diff --git a/src/google/malloc_extension.h b/src/google/malloc_extension.h
index 0e15c04..4b06b2d 100644
--- a/src/google/malloc_extension.h
+++ b/src/google/malloc_extension.h
@@ -81,9 +81,6 @@ class SysAllocator {
// Returns NULL if failed. Otherwise, the returned pointer p up to and
// including (p + actual_size -1) have been allocated.
virtual void* Alloc(size_t size, size_t *actual_size, size_t alignment) = 0;
-
- // Notification that command-line flags have been initialized.
- virtual void FlagsInitialized() = 0;
};
// The default implementations of the following routines do nothing.
@@ -103,6 +100,7 @@ class PERFTOOLS_DLL_DECL MallocExtension {
// See "verify_memory.h" to see what these routines do
virtual bool VerifyAllMemory();
+ // TODO(csilvers): change these to const void*.
virtual bool VerifyNewMemory(void* p);
virtual bool VerifyArrayNewMemory(void* p);
virtual bool VerifyMallocMemory(void* p);
@@ -283,8 +281,27 @@ class PERFTOOLS_DLL_DECL MallocExtension {
// will return 0.)
// This is equivalent to malloc_size() in OS X, malloc_usable_size()
// in glibc, and _msize() for windows.
+ // TODO(csilvers): change to const void*.
virtual size_t GetAllocatedSize(void* p);
+ // Returns kOwned if this malloc implementation allocated the memory
+ // pointed to by p, or kNotOwned if some other malloc implementation
+ // allocated it or p is NULL. May also return kUnknownOwnership if
+ // the malloc implementation does not keep track of ownership.
+ // REQUIRES: p must be a value returned from a previous call to
+ // malloc(), calloc(), realloc(), memalign(), posix_memalign(),
+ // valloc(), pvalloc(), new, or new[], and must refer to memory that
+ // is currently allocated (so, for instance, you should not pass in
+ // a pointer after having called free() on it).
+ enum Ownership {
+ // NOTE: Enum values MUST be kept in sync with the version in
+ // malloc_extension_c.h
+ kUnknownOwnership = 0,
+ kOwned,
+ kNotOwned
+ };
+ virtual Ownership GetOwnership(const void* p);
+
// The current malloc implementation. Always non-NULL.
static MallocExtension* instance();
diff --git a/src/google/malloc_extension_c.h b/src/google/malloc_extension_c.h
index fcaa8cd..e3f7f79 100644
--- a/src/google/malloc_extension_c.h
+++ b/src/google/malloc_extension_c.h
@@ -80,6 +80,18 @@ PERFTOOLS_DLL_DECL void MallocExtension_ReleaseFreeMemory(void);
PERFTOOLS_DLL_DECL size_t MallocExtension_GetEstimatedAllocatedSize(size_t size);
PERFTOOLS_DLL_DECL size_t MallocExtension_GetAllocatedSize(void* p);
+/*
+ * NOTE: These enum values MUST be kept in sync with the version in
+ * malloc_extension.h
+ */
+typedef enum {
+ MallocExtension_kUnknownOwnership = 0,
+ MallocExtension_kOwned,
+ MallocExtension_kNotOwned
+} MallocExtension_Ownership;
+
+PERFTOOLS_DLL_DECL MallocExtension_Ownership MallocExtension_GetOwnership(const void* p);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/src/google/malloc_hook.h b/src/google/malloc_hook.h
index 3e2ef45..245d0e1 100644
--- a/src/google/malloc_hook.h
+++ b/src/google/malloc_hook.h
@@ -81,6 +81,14 @@ extern "C" {
# endif
#endif
+// The C++ methods below call the C version (MallocHook_*), and thus
+// convert between an int and a bool. Windows complains about this
+// (a "performance warning") which we don't care about, so we suppress.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4800)
+#endif
+
// Note: malloc_hook_c.h defines MallocHook_*Hook and
// MallocHook_{Add,Remove}*Hook. The version of these inside the MallocHook
// class are defined in terms of the malloc_hook_c version. See malloc_hook_c.h
@@ -342,4 +350,9 @@ class PERFTOOLS_DLL_DECL MallocHook {
static void InvokeSbrkHookSlow(const void* result, ptrdiff_t increment);
};
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+
#endif /* _MALLOC_HOOK_H_ */
diff --git a/src/heap-checker.cc b/src/heap-checker.cc
index 6fb2a62..8473739 100644
--- a/src/heap-checker.cc
+++ b/src/heap-checker.cc
@@ -52,7 +52,7 @@
#include <time.h>
#include <assert.h>
-#ifdef HAVE_LINUX_PTRACE_H
+#if defined(HAVE_LINUX_PTRACE_H) && !defined(__native_client__)
#include <linux/ptrace.h>
#endif
#ifdef HAVE_SYS_SYSCALL_H
@@ -278,10 +278,6 @@ static bool constructor_heap_profiling = false;
static const int heap_checker_info_level = 0;
//----------------------------------------------------------------------
-// Cancel our InitialMallocHook_* if present.
-static void CancelInitialMallocHooks(); // defined below
-
-//----------------------------------------------------------------------
// HeapLeakChecker's own memory allocator that is
// independent of the normal program allocator.
//----------------------------------------------------------------------
@@ -1473,7 +1469,7 @@ void HeapLeakChecker::IgnoreObject(const void* ptr) {
IgnoredObjectsMap;
}
if (!ignored_objects->insert(make_pair(AsInt(ptr), object_size)).second) {
- RAW_LOG(FATAL, "Object at %p is already being ignored", ptr);
+ RAW_LOG(WARNING, "Object at %p is already being ignored", ptr);
}
}
}
diff --git a/src/libc_override.h b/src/libc_override.h
new file mode 100644
index 0000000..c198e6a
--- /dev/null
+++ b/src/libc_override.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2011, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Craig Silverstein <opensource@google.com>
+//
+// This .h file imports the code that causes tcmalloc to override libc
+// versions of malloc/free/new/delete/etc. That is, it provides the
+// logic that makes it so calls to malloc(10) go through tcmalloc,
+// rather than the default (libc) malloc.
+//
+// This file also provides a method: ReplaceSystemAlloc(), that every
+// libc_override_*.h file it #includes is required to provide. This
+// is called when first setting up tcmalloc -- that is, when a global
+// constructor in tcmalloc.cc is executed -- to do any initialization
+// work that may be required for this OS. (Note we cannot entirely
+// control when tcmalloc is initialized, and the system may do some
+// mallocs and frees before this routine is called.) It may be a
+// noop.
+//
+// Every libc has its own way of doing this, and sometimes the compiler
+// matters too, so we have a different file for each libc, and often
+// for different compilers and OS's.
+
+#ifndef TCMALLOC_LIBC_OVERRIDE_INL_H_
+#define TCMALLOC_LIBC_OVERRIDE_INL_H_
+
+#include <config.h>
+#ifdef HAVE_FEATURES_H
+#include <features.h> // for __GLIBC__
+#endif
+#include <google/tcmalloc.h>
+
+static void ReplaceSystemAlloc(); // defined in the .h files below
+
+// For windows, there are two ways to get tcmalloc. If we're
+// patching, then src/windows/patch_function.cc will do the necessary
+// overriding here. Otherwise, we doing the 'redefine' trick, where
+// we remove malloc/new/etc from mscvcrt.dll, and just need to define
+// them now.
+#if defined(_WIN32) && defined(WIN32_DO_PATCHING)
+void PatchWindowsFunctions(); // in src/windows/patch_function.cc
+static void ReplaceSystemAlloc() { PatchWindowsFunctions(); }
+
+#elif defined(_WIN32) && !defined(WIN32_DO_PATCHING)
+#include "libc_override_redefine.h"
+
+#elif defined(__APPLE__)
+#include "libc_override_osx.h"
+
+#elif defined(__GLIBC__)
+#include "libc_override_glibc.h"
+
+// Not all gcc systems necessarily support weak symbols, but all the
+// ones I know of do, so for now just assume they all do.
+#elif defined(__GNUC__)
+#include "libc_override_gcc_and_weak.h"
+
+#else
+#error Need to add support for your libc/OS here
+
+#endif
+
+#endif // TCMALLOC_LIBC_OVERRIDE_INL_H_
diff --git a/src/libc_override_gcc_and_weak.h b/src/libc_override_gcc_and_weak.h
new file mode 100644
index 0000000..3d801d1
--- /dev/null
+++ b/src/libc_override_gcc_and_weak.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2011, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Craig Silverstein <opensource@google.com>
+//
+// Used to override malloc routines on systems that define the
+// memory allocation routines to be weak symbols in their libc
+// (almost all unix-based systems are like this), on gcc, which
+// suppports the 'alias' attribute.
+
+#ifndef TCMALLOC_LIBC_OVERRIDE_GCC_AND_WEAK_INL_H_
+#define TCMALLOC_LIBC_OVERRIDE_GCC_AND_WEAK_INL_H_
+
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h> // for __THROW
+#endif
+#include <google/tcmalloc.h>
+
+#ifndef __THROW // I guess we're not on a glibc-like system
+# define __THROW // __THROW is just an optimization, so ok to make it ""
+#endif
+
+#ifndef __GNUC__
+# error libc_override_gcc_and_weak.h is for gcc distributions only.
+#endif
+
+#define ALIAS(tc_fn) __attribute__ ((alias (#tc_fn)))
+
+void* operator new(size_t size) throw (std::bad_alloc)
+ ALIAS(tc_new);
+void operator delete(void* p) __THROW
+ ALIAS(tc_delete);
+void* operator new[](size_t size) throw (std::bad_alloc)
+ ALIAS(tc_newarray);
+void operator delete[](void* p) __THROW
+ ALIAS(tc_deletearray);
+void* operator new(size_t size, const std::nothrow_t& nt) __THROW
+ ALIAS(tc_new_nothrow);
+void* operator new[](size_t size, const std::nothrow_t& nt) __THROW
+ ALIAS(tc_newarray_nothrow);
+void operator delete(void* p, const std::nothrow_t& nt) __THROW
+ ALIAS(tc_delete_nothrow);
+void operator delete[](void* p, const std::nothrow_t& nt) __THROW
+ ALIAS(tc_deletearray_nothrow);
+
+extern "C" {
+ void* malloc(size_t size) __THROW ALIAS(tc_malloc);
+ void free(void* ptr) __THROW ALIAS(tc_free);
+ void* realloc(void* ptr, size_t size) __THROW ALIAS(tc_realloc);
+ void* calloc(size_t n, size_t size) __THROW ALIAS(tc_calloc);
+ void cfree(void* ptr) __THROW ALIAS(tc_cfree);
+ void* memalign(size_t align, size_t s) __THROW ALIAS(tc_memalign);
+ void* valloc(size_t size) __THROW ALIAS(tc_valloc);
+ void* pvalloc(size_t size) __THROW ALIAS(tc_pvalloc);
+ int posix_memalign(void** r, size_t a, size_t s) __THROW
+ ALIAS(tc_posix_memalign);
+ void malloc_stats(void) __THROW ALIAS(tc_malloc_stats);
+ int mallopt(int cmd, int value) __THROW ALIAS(tc_mallopt);
+#ifdef HAVE_STRUCT_MALLINFO
+ struct mallinfo mallinfo(void) __THROW ALIAS(tc_mallinfo);
+#endif
+ size_t malloc_size(void* p) __THROW ALIAS(tc_malloc_size);
+ size_t malloc_usable_size(void* p) __THROW ALIAS(tc_malloc_size);
+} // extern "C"
+
+#undef ALIAS
+
+// No need to do anything at tcmalloc-registration time: we do it all
+// via overriding weak symbols (at link time).
+static void ReplaceSystemAlloc() { }
+
+#endif // TCMALLOC_LIBC_OVERRIDE_GCC_AND_WEAK_INL_H_
diff --git a/src/libc_override_glibc.h b/src/libc_override_glibc.h
new file mode 100644
index 0000000..4490a7a
--- /dev/null
+++ b/src/libc_override_glibc.h
@@ -0,0 +1,148 @@
+// Copyright (c) 2011, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Craig Silverstein <opensource@google.com>
+//
+// Used to override malloc routines on systems that are using glibc.
+
+#ifndef TCMALLOC_LIBC_OVERRIDE_GLIBC_INL_H_
+#define TCMALLOC_LIBC_OVERRIDE_GLIBC_INL_H_
+
+#include <config.h>
+#include <features.h> // for __GLIBC__
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h> // for __THROW
+#endif
+#include <google/tcmalloc.h>
+
+#ifndef __GLIBC__
+# error libc_override_glibc.h is for glibc distributions only.
+#endif
+
+// In glibc, the memory-allocation methods are weak symbols, so we can
+// just override them with our own. If we're using gcc, we can use
+// __attribute__((alias)) to do the overriding easily (exception:
+// Mach-O, which doesn't support aliases). Otherwise we have to use a
+// function call.
+#if !defined(__GNUC__) || defined(__MACH__)
+
+// This also defines ReplaceSystemAlloc().
+# include "libc_override_redefine.h" // defines functions malloc()/etc
+
+#else // #if !defined(__GNUC__) || defined(__MACH__)
+
+// If we get here, we're a gcc system, so do all the overriding we do
+// with gcc. This does the overriding of all the 'normal' memory
+// allocation. This also defines ReplaceSystemAlloc().
+# include "libc_override_gcc_and_weak.h"
+
+// We also have to do some glibc-specific overriding. Some library
+// routines on RedHat 9 allocate memory using malloc() and free it
+// using __libc_free() (or vice-versa). Since we provide our own
+// implementations of malloc/free, we need to make sure that the
+// __libc_XXX variants (defined as part of glibc) also point to the
+// same implementations. Since it only matters for redhat, we
+// do it inside the gcc #ifdef, since redhat uses gcc.
+// TODO(csilvers): only do this if we detect we're an old enough glibc?
+
+#define ALIAS(tc_fn) __attribute__ ((alias (#tc_fn)))
+extern "C" {
+ void* __libc_malloc(size_t size) ALIAS(tc_malloc);
+ void __libc_free(void* ptr) ALIAS(tc_free);
+ void* __libc_realloc(void* ptr, size_t size) ALIAS(tc_realloc);
+ void* __libc_calloc(size_t n, size_t size) ALIAS(tc_calloc);
+ void __libc_cfree(void* ptr) ALIAS(tc_cfree);
+ void* __libc_memalign(size_t align, size_t s) ALIAS(tc_memalign);
+ void* __libc_valloc(size_t size) ALIAS(tc_valloc);
+ void* __libc_pvalloc(size_t size) ALIAS(tc_pvalloc);
+ int __posix_memalign(void** r, size_t a, size_t s) ALIAS(tc_posix_memalign);
+} // extern "C"
+#undef ALIAS
+
+#endif // #if defined(__GNUC__) && !defined(__MACH__)
+
+
+// We also have to hook libc malloc. While our work with weak symbols
+// should make sure libc malloc is never called in most situations, it
+// can be worked around by shared libraries with the DEEPBIND
+// environment variable set. The below hooks libc to call our malloc
+// routines even in that situation. In other situations, this hook
+// should never be called.
+extern "C" {
+static void* glibc_override_malloc(size_t size, const void *caller) {
+ return tc_malloc(size);
+}
+static void* glibc_override_realloc(void *ptr, size_t size,
+ const void *caller) {
+ return tc_realloc(ptr, size);
+}
+static void glibc_override_free(void *ptr, const void *caller) {
+ tc_free(ptr);
+}
+static void* glibc_override_memalign(size_t align, size_t size,
+ const void *caller) {
+ return tc_memalign(align, size);
+}
+
+// We should be using __malloc_initialize_hook here, like the #if 0
+// code below. (See http://swoolley.org/man.cgi/3/malloc_hook.)
+// However, this causes weird linker errors with programs that link
+// with -static, so instead we just assign the vars directly at
+// static-constructor time. That should serve the same effect of
+// making sure the hooks are set before the first malloc call the
+// program makes.
+#if 0
+#include <malloc.h> // for __malloc_hook, etc.
+void glibc_override_malloc_init_hook(void) {
+ __malloc_hook = glibc_override_malloc;
+ __realloc_hook = glibc_override_realloc;
+ __free_hook = glibc_override_free;
+ __memalign_hook = glibc_override_memalign;
+}
+
+void (* MALLOC_HOOK_MAYBE_VOLATILE __malloc_initialize_hook)(void)
+ = &glibc_override_malloc_init_hook;
+#endif
+
+void* (* MALLOC_HOOK_MAYBE_VOLATILE __malloc_hook)(size_t, const void*)
+ = &glibc_override_malloc;
+void* (* MALLOC_HOOK_MAYBE_VOLATILE __realloc_hook)(void*, size_t, const void*)
+ = &glibc_override_realloc;
+void (* MALLOC_HOOK_MAYBE_VOLATILE __free_hook)(void*, const void*)
+ = &glibc_override_free;
+void* (* MALLOC_HOOK_MAYBE_VOLATILE __memalign_hook)(size_t,size_t, const void*)
+ = &glibc_override_memalign;
+
+} // extern "C"
+
+// No need to write ReplaceSystemAlloc(); one of the #includes above
+// did it for us.
+
+#endif // TCMALLOC_LIBC_OVERRIDE_GLIBC_INL_H_
diff --git a/src/libc_override_osx.h b/src/libc_override_osx.h
new file mode 100644
index 0000000..0ccf9a3
--- /dev/null
+++ b/src/libc_override_osx.h
@@ -0,0 +1,257 @@
+// Copyright (c) 2011, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Craig Silverstein <opensource@google.com>
+//
+// Used to override malloc routines on OS X systems. We use the
+// malloc-zone functionality built into OS X to register our malloc
+// routine.
+//
+// 1) We used to use the normal 'override weak libc malloc/etc'
+// technique for OS X. This is not optimal because mach does not
+// support the 'alias' attribute, so we had to have forwarding
+// functions. It also does not work very well with OS X shared
+// libraries (dylibs) -- in general, the shared libs don't use
+// tcmalloc unless run with the DYLD_FORCE_FLAT_NAMESPACE envvar.
+//
+// 2) Another approach would be to use an interposition array:
+// static const interpose_t interposers[] __attribute__((section("__DATA, __interpose"))) = {
+// { (void *)tc_malloc, (void *)malloc },
+// { (void *)tc_free, (void *)free },
+// };
+// This requires the user to set the DYLD_INSERT_LIBRARIES envvar, so
+// is not much better.
+//
+// 3) Registering a new malloc zone avoids all these issues:
+// http://www.opensource.apple.com/source/Libc/Libc-583/include/malloc/malloc.h
+// http://www.opensource.apple.com/source/Libc/Libc-583/gen/malloc.c
+// If we make tcmalloc the default malloc zone (undocumented but
+// possible) then all new allocs use it, even those in shared
+// libraries. Allocs done before tcmalloc was installed, or in libs
+// that aren't using tcmalloc for some reason, will correctly go
+// through the malloc-zone interface when free-ing, and will pick up
+// the libc free rather than tcmalloc free. So it should "never"
+// cause a crash (famous last words).
+//
+// 4) The routines one must define for one's own malloc have changed
+// between OS X versions. This requires some hoops on our part, but
+// is only really annoying when it comes to posix_memalign. The right
+// behavior there depends on what OS version tcmalloc was compiled on,
+// but also what OS version the program is running on. For now, we
+// punt and don't implement our own posix_memalign. Apps that really
+// care can use tc_posix_memalign directly.
+
+#ifndef TCMALLOC_LIBC_OVERRIDE_OSX_INL_H_
+#define TCMALLOC_LIBC_OVERRIDE_OSX_INL_H_
+
+#include <config.h>
+#ifdef HAVE_FEATURES_H
+#include <features.h>
+#endif
+#include <google/tcmalloc.h>
+
+#if !defined(__APPLE__)
+# error libc_override_glibc-osx.h is for OS X distributions only.
+#endif
+
+#include <AvailabilityMacros.h>
+#include <malloc/malloc.h>
+
+// We need to provide wrappers around all the libc functions.
+namespace {
+size_t mz_size(malloc_zone_t* zone, const void* ptr) {
+ if (MallocExtension::instance()->GetOwnership(ptr) != MallocExtension::kOwned)
+ return 0; // malloc_zone semantics: return 0 if we don't own the memory
+
+ // TODO(csilvers): change this method to take a const void*, one day.
+ return MallocExtension::instance()->GetAllocatedSize(const_cast<void*>(ptr));
+}
+
+void* mz_malloc(malloc_zone_t* zone, size_t size) {
+ return tc_malloc(size);
+}
+
+void* mz_calloc(malloc_zone_t* zone, size_t num_items, size_t size) {
+ return tc_calloc(num_items, size);
+}
+
+void* mz_valloc(malloc_zone_t* zone, size_t size) {
+ return tc_valloc(size);
+}
+
+void mz_free(malloc_zone_t* zone, void* ptr) {
+ return tc_free(ptr);
+}
+
+void* mz_realloc(malloc_zone_t* zone, void* ptr, size_t size) {
+ return tc_realloc(ptr, size);
+}
+
+void* mz_memalign(malloc_zone_t* zone, size_t align, size_t size) {
+ return tc_memalign(align, size);
+}
+
+void mz_destroy(malloc_zone_t* zone) {
+ // A no-op -- we will not be destroyed!
+}
+
+// malloc_introspection callbacks. I'm not clear on what all of these do.
+kern_return_t mi_enumerator(task_t task, void *,
+ unsigned type_mask, vm_address_t zone_address,
+ memory_reader_t reader,
+ vm_range_recorder_t recorder) {
+ // Should enumerate all the pointers we have. Seems like a lot of work.
+ return KERN_FAILURE;
+}
+
+size_t mi_good_size(malloc_zone_t *zone, size_t size) {
+ // I think it's always safe to return size, but we maybe could do better.
+ return size;
+}
+
+boolean_t mi_check(malloc_zone_t *zone) {
+ return MallocExtension::instance()->VerifyAllMemory();
+}
+
+void mi_print(malloc_zone_t *zone, boolean_t verbose) {
+ int bufsize = 8192;
+ if (verbose)
+ bufsize = 102400; // I picked this size arbitrarily
+ char* buffer = new char[bufsize];
+ MallocExtension::instance()->GetStats(buffer, bufsize);
+ fprintf(stdout, "%s", buffer);
+ delete[] buffer;
+}
+
+void mi_log(malloc_zone_t *zone, void *address) {
+ // I don't think we support anything like this
+}
+
+void mi_force_lock(malloc_zone_t *zone) {
+ // Hopefully unneeded by us!
+}
+
+void mi_force_unlock(malloc_zone_t *zone) {
+ // Hopefully unneeded by us!
+}
+
+void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
+ // TODO(csilvers): figure out how to fill these out
+ stats->blocks_in_use = 0;
+ stats->size_in_use = 0;
+ stats->max_size_in_use = 0;
+ stats->size_allocated = 0;
+}
+
+boolean_t mi_zone_locked(malloc_zone_t *zone) {
+ return false; // Hopefully unneeded by us!
+}
+
+} // unnamed namespace
+
+// OS X doesn't have pvalloc, cfree, malloc_statc, etc, so we can just
+// define our own. :-) OS X supplies posix_memalign in some versions
+// but not others, either strongly or weakly linked, in a way that's
+// difficult enough to code to correctly, that I just don't try to
+// support either memalign() or posix_memalign(). If you need them
+// and are willing to code to tcmalloc, you can use tc_posix_memalign().
+extern "C" {
+ void cfree(void* p) { tc_cfree(p); }
+ void* pvalloc(size_t s) { return tc_pvalloc(s); }
+ void malloc_stats(void) { tc_malloc_stats(); }
+ int mallopt(int cmd, int v) { return tc_mallopt(cmd, v); }
+ // No struct mallinfo on OS X, so don't define mallinfo().
+ // An alias for malloc_size(), which OS X defines.
+ size_t malloc_usable_size(void* p) { return tc_malloc_size(p); }
+} // extern "C"
+
+static void ReplaceSystemAlloc() {
+ static malloc_introspection_t tcmalloc_introspection;
+ memset(&tcmalloc_introspection, 0, sizeof(tcmalloc_introspection));
+
+ tcmalloc_introspection.enumerator = &mi_enumerator;
+ tcmalloc_introspection.good_size = &mi_good_size;
+ tcmalloc_introspection.check = &mi_check;
+ tcmalloc_introspection.print = &mi_print;
+ tcmalloc_introspection.log = &mi_log;
+ tcmalloc_introspection.force_lock = &mi_force_lock;
+ tcmalloc_introspection.force_unlock = &mi_force_unlock;
+
+ static malloc_zone_t tcmalloc_zone;
+ memset(&tcmalloc_zone, 0, sizeof(malloc_zone_t));
+
+ // Start with a version 4 zone which is used for OS X 10.4 and 10.5.
+ tcmalloc_zone.version = 4;
+ tcmalloc_zone.zone_name = "tcmalloc";
+ tcmalloc_zone.size = &mz_size;
+ tcmalloc_zone.malloc = &mz_malloc;
+ tcmalloc_zone.calloc = &mz_calloc;
+ tcmalloc_zone.valloc = &mz_valloc;
+ tcmalloc_zone.free = &mz_free;
+ tcmalloc_zone.realloc = &mz_realloc;
+ tcmalloc_zone.destroy = &mz_destroy;
+ tcmalloc_zone.batch_malloc = NULL;
+ tcmalloc_zone.batch_free = NULL;
+ tcmalloc_zone.introspect = &tcmalloc_introspection;
+
+ // from AvailabilityMacros.h
+#if defined(MAC_OS_X_VERSION_10_6) && \
+ MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+ // Switch to version 6 on OSX 10.6 to support memalign.
+ tcmalloc_zone.version = 6;
+ tcmalloc_zone.free_definite_size = NULL;
+ tcmalloc_zone.memalign = &mz_memalign;
+ tcmalloc_introspection.zone_locked = &mi_zone_locked;
+
+ // Request the default purgable zone to force its creation. The
+ // current default zone is registered with the purgable zone for
+ // doing tiny and small allocs. Sadly, it assumes that the default
+ // zone is the szone implementation from OS X and will crash if it
+ // isn't. By creating the zone now, this will be true and changing
+ // the default zone won't cause a problem. (OS X 10.6 and higher.)
+ malloc_default_purgeable_zone();
+#endif
+
+ // Register the tcmalloc zone. At this point, it will not be the
+ // default zone.
+ malloc_zone_register(&tcmalloc_zone);
+
+ // Unregister and reregister the default zone. Unregistering swaps
+ // the specified zone with the last one registered which for the
+ // default zone makes the more recently registered zone the default
+ // zone. The default zone is then re-registered to ensure that
+ // allocations made from it earlier will be handled correctly.
+ // Things are not guaranteed to work that way, but it's how they work now.
+ malloc_zone_t *default_zone = malloc_default_zone();
+ malloc_zone_unregister(default_zone);
+ malloc_zone_register(default_zone);
+}
+
+#endif // TCMALLOC_LIBC_OVERRIDE_OSX_INL_H_
diff --git a/src/libc_override_redefine.h b/src/libc_override_redefine.h
new file mode 100644
index 0000000..d8d999c
--- /dev/null
+++ b/src/libc_override_redefine.h
@@ -0,0 +1,93 @@
+// Copyright (c) 2011, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Craig Silverstein <opensource@google.com>
+//
+// Used on systems that don't have their own definition of
+// malloc/new/etc. (Typically this will be a windows msvcrt.dll that
+// has been edited to remove the definitions.) We can just define our
+// own as normal functions.
+//
+// This should also work on systems were all the malloc routines are
+// defined as weak symbols, and there's no support for aliasing.
+
+#ifndef TCMALLOC_LIBC_OVERRIDE_REDEFINE_H_
+#define TCMALLOC_LIBC_OVERRIDE_REDEFINE_H_
+
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h> // for __THROW
+#endif
+
+#ifndef __THROW // I guess we're not on a glibc-like system
+# define __THROW // __THROW is just an optimization, so ok to make it ""
+#endif
+
+void* operator new(size_t size) { return tc_new(size); }
+void operator delete(void* p) __THROW { tc_delete(p); }
+void* operator new[](size_t size) { return tc_newarray(size); }
+void operator delete[](void* p) __THROW { tc_deletearray(p); }
+void* operator new(size_t size, const std::nothrow_t& nt) __THROW {
+ return tc_new_nothrow(size, nt);
+}
+void* operator new[](size_t size, const std::nothrow_t& nt) __THROW {
+ return tc_newarray_nothrow(size, nt);
+}
+void operator delete(void* ptr, const std::nothrow_t& nt) __THROW {
+ return tc_delete_nothrow(ptr, nt);
+}
+void operator delete[](void* ptr, const std::nothrow_t& nt) __THROW {
+ return tc_deletearray_nothrow(ptr, nt);
+}
+extern "C" {
+ void* malloc(size_t s) __THROW { return tc_malloc(s); }
+ void free(void* p) __THROW { tc_free(p); }
+ void* realloc(void* p, size_t s) __THROW { return tc_realloc(p, s); }
+ void* calloc(size_t n, size_t s) __THROW { return tc_calloc(n, s); }
+ void cfree(void* p) __THROW { tc_cfree(p); }
+ void* memalign(size_t a, size_t s) __THROW { return tc_memalign(a, s); }
+ void* valloc(size_t s) __THROW { return tc_valloc(s); }
+ void* pvalloc(size_t s) __THROW { return tc_pvalloc(s); }
+ int posix_memalign(void** r, size_t a, size_t s) __THROW {
+ return tc_posix_memalign(r, a, s);
+ }
+ void malloc_stats(void) __THROW { tc_malloc_stats(); }
+ int mallopt(int cmd, int v) __THROW { return tc_mallopt(cmd, v); }
+#ifdef HAVE_STRUCT_MALLINFO
+ struct mallinfo mallinfo(void) __THROW { return tc_mallinfo(); }
+#endif
+ size_t malloc_size(void* p) __THROW { return tc_malloc_size(p); }
+ size_t malloc_usable_size(void* p) __THROW { return tc_malloc_size(p); }
+} // extern "C"
+
+// No need to do anything at tcmalloc-registration time: we do it all
+// via overriding weak symbols (at link time).
+static void ReplaceSystemAlloc() { }
+
+#endif // TCMALLOC_LIBC_OVERRIDE_REDEFINE_H_
diff --git a/src/malloc_extension.cc b/src/malloc_extension.cc
index e9a0da7..bf946e6 100644
--- a/src/malloc_extension.cc
+++ b/src/malloc_extension.cc
@@ -48,6 +48,7 @@
#include "google/heap-checker.h"
#endif
#include "google/malloc_extension.h"
+#include "google/malloc_extension_c.h"
#include "maybe_threads.h"
using STL_NAMESPACE::string;
@@ -177,9 +178,14 @@ size_t MallocExtension::GetEstimatedAllocatedSize(size_t size) {
}
size_t MallocExtension::GetAllocatedSize(void* p) {
+ assert(GetOwnership(p) != kNotOwned);
return 0;
}
+MallocExtension::Ownership MallocExtension::GetOwnership(const void* p) {
+ return kUnknownOwnership;
+}
+
void MallocExtension::GetFreeListSizes(
vector<MallocExtension::FreeListInfo>* v) {
v->clear();
@@ -238,11 +244,11 @@ void PrintCountAndSize(MallocExtensionWriter* writer,
uintptr_t count, uintptr_t size) {
char buf[100];
snprintf(buf, sizeof(buf),
- "%6lld: %8lld [%6lld: %8lld] @",
- static_cast<long long>(count),
- static_cast<long long>(size),
- static_cast<long long>(count),
- static_cast<long long>(size));
+ "%6"PRIu64": %8"PRIu64" [%6"PRIu64": %8"PRIu64"] @",
+ static_cast<uint64>(count),
+ static_cast<uint64>(size),
+ static_cast<uint64>(count),
+ static_cast<uint64>(size));
writer->append(buf, strlen(buf));
}
@@ -357,3 +363,10 @@ C_SHIM(ReleaseFreeMemory, void, (void), ());
C_SHIM(ReleaseToSystem, void, (size_t num_bytes), (num_bytes));
C_SHIM(GetEstimatedAllocatedSize, size_t, (size_t size), (size));
C_SHIM(GetAllocatedSize, size_t, (void* p), (p));
+
+// Can't use the shim here because of the need to translate the enums.
+extern "C"
+MallocExtension_Ownership MallocExtension_GetOwnership(const void* p) {
+ return static_cast<MallocExtension_Ownership>(
+ MallocExtension::instance()->GetOwnership(p));
+}
diff --git a/src/malloc_hook-inl.h b/src/malloc_hook-inl.h
index b24b1c6..6210784 100644
--- a/src/malloc_hook-inl.h
+++ b/src/malloc_hook-inl.h
@@ -104,7 +104,7 @@ static const int kHookListMaxValues = 7;
// HookList: a class that provides synchronized insertions and removals and
// lockless traversal. Most of the implementation is in malloc_hook.cc.
template <typename T>
-struct HookList {
+struct PERFTOOLS_DLL_DECL HookList {
COMPILE_ASSERT(sizeof(T) <= sizeof(AtomicWord), T_should_fit_in_AtomicWord);
// Adds value to the list. Note that duplicates are allowed. Thread-safe and
diff --git a/src/malloc_hook.cc b/src/malloc_hook.cc
index 5a61362..dc4539c 100644
--- a/src/malloc_hook.cc
+++ b/src/malloc_hook.cc
@@ -283,7 +283,7 @@ int HookList<T>::Traverse(T* output_array, int n) const {
// Explicit instantiation for malloc_hook_test.cc. This ensures all the methods
// are instantiated.
-template class HookList<MallocHook::NewHook>;
+template struct HookList<MallocHook::NewHook>;
HookList<MallocHook::NewHook> new_hooks_ =
INIT_HOOK_LIST_WITH_VALUE(&InitialNewHook);
@@ -698,191 +698,19 @@ extern "C" int MallocHook_GetCallerStackTrace(void** result, int max_depth,
#endif
}
-// On Linux/x86, we override mmap/munmap/mremap/sbrk
-// and provide support for calling the related hooks.
-//
-// We define mmap() and mmap64(), which somewhat reimplements libc's mmap
-// syscall stubs. Unfortunately libc only exports the stubs via weak symbols
-// (which we're overriding with our mmap64() and mmap() wrappers) so we can't
-// just call through to them.
-
-
-#if defined(__linux) && \
- (defined(__i386__) || defined(__x86_64__) || defined(__PPC__))
-#include <unistd.h>
-#include <syscall.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include "base/linux_syscall_support.h"
-
-// The x86-32 case and the x86-64 case differ:
-// 32b has a mmap2() syscall, 64b does not.
-// 64b and 32b have different calling conventions for mmap().
-#if defined(__x86_64__) || defined(__PPC64__)
-
-static inline void* do_mmap64(void *start, size_t length,
- int prot, int flags,
- int fd, __off64_t offset) __THROW {
- return (void *)syscall(SYS_mmap, start, length, prot, flags, fd, offset);
-}
-
-#elif defined(__i386__) || defined(__PPC__)
-
-static inline void* do_mmap64(void *start, size_t length,
- int prot, int flags,
- int fd, __off64_t offset) __THROW {
- void *result;
-
- // Try mmap2() unless it's not supported
- static bool have_mmap2 = true;
- if (have_mmap2) {
- static int pagesize = 0;
- if (!pagesize) pagesize = getpagesize();
-
- // Check that the offset is page aligned
- if (offset & (pagesize - 1)) {
- result = MAP_FAILED;
- errno = EINVAL;
- goto out;
- }
-
- result = (void *)syscall(SYS_mmap2,
- start, length, prot, flags, fd,
- (off_t) (offset / pagesize));
- if (result != MAP_FAILED || errno != ENOSYS) goto out;
-
- // We don't have mmap2() after all - don't bother trying it in future
- have_mmap2 = false;
- }
-
- if (((off_t)offset) != offset) {
- // If we're trying to map a 64-bit offset, fail now since we don't
- // have 64-bit mmap() support.
- result = MAP_FAILED;
- errno = EINVAL;
- goto out;
- }
-
- {
- // Fall back to old 32-bit offset mmap() call
- // Old syscall interface cannot handle six args, so pass in an array
- int32 args[6] = { (int32) start, length, prot, flags, fd, (off_t) offset };
- result = (void *)syscall(SYS_mmap, args);
- }
- out:
- return result;
-}
-
-# endif // defined(__x86_64__)
-
-// We use do_mmap64 abstraction to put MallocHook::InvokeMmapHook
-// calls right into mmap and mmap64, so that the stack frames in the caller's
-// stack are at the same offsets for all the calls of memory allocating
-// functions.
-
-// Put all callers of MallocHook::Invoke* in this module into
-// malloc_hook section,
-// so that MallocHook::GetCallerStackTrace can function accurately:
-
-// Make sure mmap doesn't get #define'd away by <sys/mman.h>
-#undef mmap
-
-extern "C" {
- void* mmap64(void *start, size_t length, int prot, int flags,
- int fd, __off64_t offset ) __THROW
- ATTRIBUTE_SECTION(malloc_hook);
- void* mmap(void *start, size_t length,int prot, int flags,
- int fd, off_t offset) __THROW
- ATTRIBUTE_SECTION(malloc_hook);
- int munmap(void* start, size_t length) __THROW
- ATTRIBUTE_SECTION(malloc_hook);
- void* mremap(void* old_addr, size_t old_size, size_t new_size,
- int flags, ...) __THROW
- ATTRIBUTE_SECTION(malloc_hook);
- void* sbrk(ptrdiff_t increment) __THROW
- ATTRIBUTE_SECTION(malloc_hook);
-}
-
-extern "C" void* mmap64(void *start, size_t length, int prot, int flags,
- int fd, __off64_t offset) __THROW {
- MallocHook::InvokePreMmapHook(start, length, prot, flags, fd, offset);
- void *result;
- if (!MallocHook::InvokeMmapReplacement(
- start, length, prot, flags, fd, offset, &result)) {
- result = do_mmap64(start, length, prot, flags, fd, offset);
- }
- MallocHook::InvokeMmapHook(result, start, length, prot, flags, fd, offset);
- return result;
-}
-
-#if !defined(__USE_FILE_OFFSET64) || !defined(__REDIRECT_NTH)
-
-extern "C" void* mmap(void *start, size_t length, int prot, int flags,
- int fd, off_t offset) __THROW {
- MallocHook::InvokePreMmapHook(start, length, prot, flags, fd, offset);
- void *result;
- if (!MallocHook::InvokeMmapReplacement(
- start, length, prot, flags, fd, offset, &result)) {
- result = do_mmap64(start, length, prot, flags, fd,
- static_cast<size_t>(offset)); // avoid sign extension
- }
- MallocHook::InvokeMmapHook(result, start, length, prot, flags, fd, offset);
- return result;
-}
-
-#endif // !defined(__USE_FILE_OFFSET64) || !defined(__REDIRECT_NTH)
+// On systems where we know how, we override mmap/munmap/mremap/sbrk
+// to provide support for calling the related hooks (in addition,
+// of course, to doing what these functions normally do).
-extern "C" int munmap(void* start, size_t length) __THROW {
- MallocHook::InvokeMunmapHook(start, length);
- int result;
- if (!MallocHook::InvokeMunmapReplacement(start, length, &result)) {
- result = syscall(SYS_munmap, start, length);
- }
- return result;
-}
-
-extern "C" void* mremap(void* old_addr, size_t old_size, size_t new_size,
- int flags, ...) __THROW {
- va_list ap;
- va_start(ap, flags);
- void *new_address = va_arg(ap, void *);
- va_end(ap);
- void* result = sys_mremap(old_addr, old_size, new_size, flags, new_address);
- MallocHook::InvokeMremapHook(result, old_addr, old_size, new_size, flags,
- new_address);
- return result;
-}
-
-// libc's version:
-extern "C" void* __sbrk(ptrdiff_t increment);
-
-extern "C" void* sbrk(ptrdiff_t increment) __THROW {
- MallocHook::InvokePreSbrkHook(increment);
- void *result = __sbrk(increment);
- MallocHook::InvokeSbrkHook(result, increment);
- return result;
-}
-
-/*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot,
- int flags, int fd, off_t offset) {
- void* result;
- if (!MallocHook::InvokeMmapReplacement(
- start, length, prot, flags, fd, offset, &result)) {
- result = do_mmap64(start, length, prot, flags, fd, offset);
- }
- return result;
-}
+#if defined(__linux)
+# include "malloc_hook_mmap_linux.h"
-/*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) {
- int result;
- if (!MallocHook::InvokeMunmapReplacement(start, length, &result)) {
- result = sys_munmap(start, length);
- }
- return result;
-}
+// This code doesn't even compile on my freebsd 8.1 (x86_64) system,
+// so comment it out for now. TODO(csilvers): fix this!
+#elif 0 && defined(__FreeBSD__)
+# include "malloc_hook_mmap_freebsd.h"
-#else // defined(__linux) &&
- // (defined(__i386__) || defined(__x86_64__) || defined(__PPC__))
+#else
/*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot,
int flags, int fd, off_t offset) {
@@ -902,5 +730,4 @@ extern "C" void* sbrk(ptrdiff_t increment) __THROW {
return result;
}
-#endif // defined(__linux) &&
- // (defined(__i386__) || defined(__x86_64__) || defined(__PPC__))
+#endif
diff --git a/src/malloc_hook_mmap_freebsd.h b/src/malloc_hook_mmap_freebsd.h
new file mode 100644
index 0000000..4ac2bb3
--- /dev/null
+++ b/src/malloc_hook_mmap_freebsd.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2011, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Override mmap/munmap/mremap/sbrk to provide support for calling the
+// related hooks (in addition, of course, to doing what these
+// functions normally do).
+
+#ifndef __FreeBSD__
+# error Should only be including malloc_hook_mmap_freebsd.h on FreeBSD systems.
+#endif
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+static inline void* do_mmap(void *start, size_t length,
+ int prot, int flags,
+ int fd, off_t offset) __THROW {
+ return (void *)syscall(SYS_mmap, start, length, prot, flags, fd, offset);
+}
+
+// Make sure mmap doesn't get #define'd away by <sys/mman.h>
+#undef mmap
+
+extern "C" {
+ void* mmap(void *start, size_t length,int prot, int flags,
+ int fd, off_t offset) __THROW
+ ATTRIBUTE_SECTION(malloc_hook);
+ int munmap(void* start, size_t length) __THROW
+ ATTRIBUTE_SECTION(malloc_hook);
+ void* sbrk(intptr_t increment) __THROW
+ ATTRIBUTE_SECTION(malloc_hook);
+}
+
+static inline void* do_sbrk(intptr_t increment) {
+ void* curbrk;
+
+ __asm__ __volatile__(
+ "movl .curbrk, %%eax;"
+ "movl %%eax, %0"
+ : "=r" (curbrk)
+ :: "%eax");
+
+ char* prevbrk = static_cast<char*>(curbrk);
+ void* newbrk = prevbrk + increment;
+
+ if (brk(newbrk) == -1) {
+ assert(0);
+ return reinterpret_cast<void*>(static_cast<intptr_t>(-1));
+ }
+
+ return prevbrk;
+}
+
+
+extern "C" void* mmap(void *start, size_t length, int prot, int flags,
+ int fd, off_t offset) __THROW {
+ MallocHook::InvokePreMmapHook(start, length, prot, flags, fd, offset);
+ void *result = do_mmap(start, length, prot, flags, fd,
+ static_cast<size_t>(offset)); // avoid sign extension
+ MallocHook::InvokeMmapHook(result, start, length, prot, flags, fd, offset);
+ return result;
+}
+
+extern "C" int munmap(void* start, size_t length) __THROW {
+ MallocHook::InvokeMunmapHook(start, length);
+ return syscall(SYS_munmap, start, length);
+}
+
+extern "C" void* sbrk(intptr_t increment) __THROW {
+ MallocHook::InvokePreSbrkHook(increment);
+ void *result = do_sbrk(increment);
+ MallocHook::InvokeSbrkHook(result, increment);
+ return result;
+}
+
+/*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot,
+ int flags, int fd, off_t offset) {
+ return mmap(start, length, prot, flags, fd, offset);
+}
+
+/*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) {
+ return munmap(start, length);
+}
diff --git a/src/malloc_hook_mmap_linux.h b/src/malloc_hook_mmap_linux.h
new file mode 100644
index 0000000..0026589
--- /dev/null
+++ b/src/malloc_hook_mmap_linux.h
@@ -0,0 +1,223 @@
+// Copyright (c) 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Sanjay Ghemawat <opensource@google.com>
+
+// We define mmap() and mmap64(), which somewhat reimplements libc's mmap
+// syscall stubs. Unfortunately libc only exports the stubs via weak symbols
+// (which we're overriding with our mmap64() and mmap() wrappers) so we can't
+// just call through to them.
+
+#ifndef __linux
+# error Should only be including malloc_hook_mmap_linux.h on linux systems.
+#endif
+
+#include <unistd.h>
+#include <syscall.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include "base/linux_syscall_support.h"
+
+// The x86-32 case and the x86-64 case differ:
+// 32b has a mmap2() syscall, 64b does not.
+// 64b and 32b have different calling conventions for mmap().
+#if defined(__i386__) || defined(__PPC__)
+
+static inline void* do_mmap64(void *start, size_t length,
+ int prot, int flags,
+ int fd, __off64_t offset) __THROW {
+ void *result;
+
+ // Try mmap2() unless it's not supported
+ static bool have_mmap2 = true;
+ if (have_mmap2) {
+ static int pagesize = 0;
+ if (!pagesize) pagesize = getpagesize();
+
+ // Check that the offset is page aligned
+ if (offset & (pagesize - 1)) {
+ result = MAP_FAILED;
+ errno = EINVAL;
+ goto out;
+ }
+
+ result = (void *)syscall(SYS_mmap2,
+ start, length, prot, flags, fd,
+ (off_t) (offset / pagesize));
+ if (result != MAP_FAILED || errno != ENOSYS) goto out;
+
+ // We don't have mmap2() after all - don't bother trying it in future
+ have_mmap2 = false;
+ }
+
+ if (((off_t)offset) != offset) {
+ // If we're trying to map a 64-bit offset, fail now since we don't
+ // have 64-bit mmap() support.
+ result = MAP_FAILED;
+ errno = EINVAL;
+ goto out;
+ }
+
+ {
+ // Fall back to old 32-bit offset mmap() call
+ // Old syscall interface cannot handle six args, so pass in an array
+ int32 args[6] = { (int32) start, length, prot, flags, fd, (off_t) offset };
+ result = (void *)syscall(SYS_mmap, args);
+ }
+ out:
+ return result;
+}
+
+#define MALLOC_HOOK_HAVE_DO_MMAP64 1
+
+#elif defined(__x86_64__) || defined(__PPC64__) // #if defined(__i386__) || ...
+
+static inline void* do_mmap64(void *start, size_t length,
+ int prot, int flags,
+ int fd, __off64_t offset) __THROW {
+ return (void *)syscall(SYS_mmap, start, length, prot, flags, fd, offset);
+}
+
+#define MALLOC_HOOK_HAVE_DO_MMAP64 1
+
+#endif // #if defined(__i386__) || defined(__PPC__)
+
+
+#ifdef MALLOC_HOOK_HAVE_DO_MMAP64
+
+// We use do_mmap64 abstraction to put MallocHook::InvokeMmapHook
+// calls right into mmap and mmap64, so that the stack frames in the caller's
+// stack are at the same offsets for all the calls of memory allocating
+// functions.
+
+// Put all callers of MallocHook::Invoke* in this module into
+// malloc_hook section,
+// so that MallocHook::GetCallerStackTrace can function accurately:
+
+// Make sure mmap doesn't get #define'd away by <sys/mman.h>
+# undef mmap
+
+extern "C" {
+ void* mmap64(void *start, size_t length, int prot, int flags,
+ int fd, __off64_t offset ) __THROW
+ ATTRIBUTE_SECTION(malloc_hook);
+ void* mmap(void *start, size_t length,int prot, int flags,
+ int fd, off_t offset) __THROW
+ ATTRIBUTE_SECTION(malloc_hook);
+ int munmap(void* start, size_t length) __THROW
+ ATTRIBUTE_SECTION(malloc_hook);
+ void* mremap(void* old_addr, size_t old_size, size_t new_size,
+ int flags, ...) __THROW
+ ATTRIBUTE_SECTION(malloc_hook);
+ void* sbrk(ptrdiff_t increment) __THROW
+ ATTRIBUTE_SECTION(malloc_hook);
+}
+
+extern "C" void* mmap64(void *start, size_t length, int prot, int flags,
+ int fd, __off64_t offset) __THROW {
+ MallocHook::InvokePreMmapHook(start, length, prot, flags, fd, offset);
+ void *result;
+ if (!MallocHook::InvokeMmapReplacement(
+ start, length, prot, flags, fd, offset, &result)) {
+ result = do_mmap64(start, length, prot, flags, fd, offset);
+ }
+ MallocHook::InvokeMmapHook(result, start, length, prot, flags, fd, offset);
+ return result;
+}
+
+# if !defined(__USE_FILE_OFFSET64) || !defined(__REDIRECT_NTH)
+
+extern "C" void* mmap(void *start, size_t length, int prot, int flags,
+ int fd, off_t offset) __THROW {
+ MallocHook::InvokePreMmapHook(start, length, prot, flags, fd, offset);
+ void *result;
+ if (!MallocHook::InvokeMmapReplacement(
+ start, length, prot, flags, fd, offset, &result)) {
+ result = do_mmap64(start, length, prot, flags, fd,
+ static_cast<size_t>(offset)); // avoid sign extension
+ }
+ MallocHook::InvokeMmapHook(result, start, length, prot, flags, fd, offset);
+ return result;
+}
+
+# endif // !defined(__USE_FILE_OFFSET64) || !defined(__REDIRECT_NTH)
+
+extern "C" int munmap(void* start, size_t length) __THROW {
+ MallocHook::InvokeMunmapHook(start, length);
+ int result;
+ if (!MallocHook::InvokeMunmapReplacement(start, length, &result)) {
+ result = sys_munmap(start, length);
+ }
+ return result;
+}
+
+extern "C" void* mremap(void* old_addr, size_t old_size, size_t new_size,
+ int flags, ...) __THROW {
+ va_list ap;
+ va_start(ap, flags);
+ void *new_address = va_arg(ap, void *);
+ va_end(ap);
+ void* result = sys_mremap(old_addr, old_size, new_size, flags, new_address);
+ MallocHook::InvokeMremapHook(result, old_addr, old_size, new_size, flags,
+ new_address);
+ return result;
+}
+
+// libc's version:
+extern "C" void* __sbrk(ptrdiff_t increment);
+
+extern "C" void* sbrk(ptrdiff_t increment) __THROW {
+ MallocHook::InvokePreSbrkHook(increment);
+ void *result = __sbrk(increment);
+ MallocHook::InvokeSbrkHook(result, increment);
+ return result;
+}
+
+/*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot,
+ int flags, int fd, off_t offset) {
+ void* result;
+ if (!MallocHook::InvokeMmapReplacement(
+ start, length, prot, flags, fd, offset, &result)) {
+ result = do_mmap64(start, length, prot, flags, fd, offset);
+ }
+ return result;
+}
+
+/*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) {
+ int result;
+ if (!MallocHook::InvokeMunmapReplacement(start, length, &result)) {
+ result = syscall(SYS_munmap, start, length);
+ }
+ return result;
+}
+
+#undef MALLOC_HOOK_HAVE_DO_MMAP64
+
+#endif // #ifdef MALLOC_HOOK_HAVE_DO_MMAP64
diff --git a/src/maybe_threads.cc b/src/maybe_threads.cc
index cda1d63..15c8a23 100644
--- a/src/maybe_threads.cc
+++ b/src/maybe_threads.cc
@@ -39,6 +39,7 @@
#include "config.h"
#include <assert.h>
#include <string.h> // for memcmp
+#include <stdio.h> // for __isthreaded on FreeBSD
// We don't actually need strings. But including this header seems to
// stop the compiler trying to short-circuit our pthreads existence
// tests and claiming that the address of a function is always
@@ -98,9 +99,28 @@ int perftools_pthread_setspecific(pthread_key_t key, void *val) {
}
}
+
static pthread_once_t pthread_once_init = PTHREAD_ONCE_INIT;
int perftools_pthread_once(pthread_once_t *ctl,
void (*init_routine) (void)) {
+#ifdef __FreeBSD__
+ // On __FreeBSD__, calling pthread_once on a system that is not
+ // linked with -pthread is silently a noop. :-( Luckily, we have a
+ // workaround: FreeBSD exposes __isthreaded in <stdio.h>, which is
+ // set to 1 when the first thread is spawned. So on those systems,
+ // we can use our own separate pthreads-once mechanism, which is
+ // used until __isthreaded is 1 (which will never be true if the app
+ // is not linked with -pthread).
+ static bool pthread_once_ran_before_threads = false;
+ if (pthread_once_ran_before_threads) {
+ return 0;
+ }
+ if (!__isthreaded) {
+ init_routine();
+ pthread_once_ran_before_threads = true;
+ return 0;
+ }
+#endif
if (pthread_once) {
return pthread_once(ctl, init_routine);
} else {
diff --git a/src/memfs_malloc.cc b/src/memfs_malloc.cc
index 3fb55a4..0bb27d7 100644
--- a/src/memfs_malloc.cc
+++ b/src/memfs_malloc.cc
@@ -58,7 +58,6 @@
#include "base/basictypes.h"
#include "base/googleinit.h"
#include "base/sysinfo.h"
-#include "system-alloc.h"
#include "internal_logging.h"
using std::string;
@@ -86,7 +85,7 @@ DEFINE_bool(memfs_malloc_map_private,
class HugetlbSysAllocator: public SysAllocator {
public:
explicit HugetlbSysAllocator(SysAllocator* fallback)
- : failed_(true), // Unusable until FlagsInitialized() is called
+ : failed_(true), // To disable allocator until Initialize() is called.
big_page_size_(0),
hugetlb_fd_(-1),
hugetlb_base_(0),
@@ -94,10 +93,10 @@ public:
}
void* Alloc(size_t size, size_t *actual_size, size_t alignment);
-
- void FlagsInitialized();
+ bool Initialize();
bool failed_; // Whether failed to allocate memory.
+
private:
void* AllocInternal(size_t size, size_t *actual_size, size_t alignment);
@@ -212,49 +211,53 @@ void* HugetlbSysAllocator::AllocInternal(size_t size, size_t* actual_size,
return reinterpret_cast<void*>(ptr);
}
-void HugetlbSysAllocator::FlagsInitialized() {
- if (FLAGS_memfs_malloc_path.length()) {
- char path[PATH_MAX];
- int rc = snprintf(path, sizeof(path), "%s.XXXXXX",
- FLAGS_memfs_malloc_path.c_str());
- if (rc < 0 || rc >= sizeof(path)) {
- CRASH("XX fatal: memfs_malloc_path too long\n");
- }
-
- int hugetlb_fd = mkstemp(path);
- if (hugetlb_fd == -1) {
- TCMalloc_MESSAGE(__FILE__, __LINE__,
- "warning: unable to create memfs_malloc_path %s: %s\n",
- path, strerror(errno));
- return;
- }
+bool HugetlbSysAllocator::Initialize() {
+ char path[PATH_MAX];
+ int rc = snprintf(path, sizeof(path), "%s.XXXXXX",
+ FLAGS_memfs_malloc_path.c_str());
+ if (rc < 0 || rc >= sizeof(path)) {
+ CRASH("XX fatal: memfs_malloc_path too long\n");
+ return false;
+ }
- // Cleanup memory on process exit
- if (unlink(path) == -1) {
- CRASH("fatal: error unlinking memfs_malloc_path %s: %s\n",
- path, strerror(errno));
- }
+ int hugetlb_fd = mkstemp(path);
+ if (hugetlb_fd == -1) {
+ TCMalloc_MESSAGE(__FILE__, __LINE__,
+ "warning: unable to create memfs_malloc_path %s: %s\n",
+ path, strerror(errno));
+ return false;
+ }
- // Use fstatfs to figure out the default page size for memfs
- struct statfs sfs;
- if (fstatfs(hugetlb_fd, &sfs) == -1) {
- CRASH("fatal: error fstatfs of memfs_malloc_path: %s\n",
- strerror(errno));
- }
- int64 page_size = sfs.f_bsize;
+ // Cleanup memory on process exit
+ if (unlink(path) == -1) {
+ CRASH("fatal: error unlinking memfs_malloc_path %s: %s\n",
+ path, strerror(errno));
+ return false;
+ }
- hugetlb_fd_ = hugetlb_fd;
- big_page_size_ = page_size;
- failed_ = false;
+ // Use fstatfs to figure out the default page size for memfs
+ struct statfs sfs;
+ if (fstatfs(hugetlb_fd, &sfs) == -1) {
+ CRASH("fatal: error fstatfs of memfs_malloc_path: %s\n",
+ strerror(errno));
+ return false;
}
-}
+ int64 page_size = sfs.f_bsize;
-static void InitSystemAllocator() {
- SysAllocator *alloc = MallocExtension::instance()->GetSystemAllocator();
- HugetlbSysAllocator *hugetlb = new (hugetlb_space) HugetlbSysAllocator(alloc);
- MallocExtension::instance()->SetSystemAllocator(hugetlb);
+ hugetlb_fd_ = hugetlb_fd;
+ big_page_size_ = page_size;
+ failed_ = false;
+ return true;
}
-REGISTER_MODULE_INITIALIZER(memfs_malloc, { InitSystemAllocator(); });
+REGISTER_MODULE_INITIALIZER(memfs_malloc, {
+ if (FLAGS_memfs_malloc_path.length()) {
+ SysAllocator* alloc = MallocExtension::instance()->GetSystemAllocator();
+ HugetlbSysAllocator* hp = new (hugetlb_space) HugetlbSysAllocator(alloc);
+ if (hp->Initialize()) {
+ MallocExtension::instance()->SetSystemAllocator(hp);
+ }
+ }
+});
#endif /* ifdef __linux */
diff --git a/src/memory_region_map.cc b/src/memory_region_map.cc
index 3f17ac7..3bf8983 100644
--- a/src/memory_region_map.cc
+++ b/src/memory_region_map.cc
@@ -582,8 +582,8 @@ void MemoryRegionMap::MmapHook(const void* result,
int fd, off_t offset) {
// TODO(maxim): replace all 0x%"PRIxS" by %p when RAW_VLOG uses a safe
// snprintf reimplementation that does not malloc to pretty-print NULL
- RAW_VLOG(10, "MMap = 0x%"PRIxPTR" of %"PRIuS" at %llu "
- "prot %d flags %d fd %d offs %lld",
+ RAW_VLOG(10, "MMap = 0x%"PRIxPTR" of %"PRIuS" at %"PRIu64" "
+ "prot %d flags %d fd %d offs %"PRId64,
reinterpret_cast<uintptr_t>(result), size,
reinterpret_cast<uint64>(start), prot, flags, fd,
static_cast<int64>(offset));
diff --git a/src/pprof b/src/pprof
index 03bafa4..0ce5df3 100755
--- a/src/pprof
+++ b/src/pprof
@@ -72,7 +72,7 @@ use strict;
use warnings;
use Getopt::Long;
-my $PPROF_VERSION = "1.7";
+my $PPROF_VERSION = "1.8";
# These are the object tools we use which can come from a
# user-specified location using --tools, from the PPROF_TOOLS
@@ -156,7 +156,8 @@ pprof [options] <profile>
The /<service> can be $HEAP_PAGE, $PROFILE_PAGE, /pprof/pmuprofile,
$GROWTH_PAGE, $CONTENTION_PAGE, /pprof/wall,
$CENSUSPROFILE_PAGE, or /pprof/filteredprofile.
- For instance: "pprof http://myserver.com:80$HEAP_PAGE".
+ For instance:
+ pprof http://myserver.com:80$HEAP_PAGE
If /<service> is omitted, the service defaults to $PROFILE_PAGE (cpu profiling).
pprof --symbols <program>
Maps addresses to symbol names. In this mode, stdin should be a
@@ -545,7 +546,7 @@ sub Init() {
ConfigureObjTools($main::prog)
}
- # Break the opt_list_prefix into the prefix_list array
+ # Break the opt_lib_prefix into the prefix_list array
@prefix_list = split (',', $main::opt_lib_prefix);
# Remove trailing / from the prefixes, in the list to prevent
@@ -643,7 +644,7 @@ sub Main() {
if ($main::opt_disasm) {
PrintDisassembly($libs, $flat, $cumulative, $main::opt_disasm);
} elsif ($main::opt_list) {
- PrintListing($libs, $flat, $cumulative, $main::opt_list);
+ PrintListing($total, $libs, $flat, $cumulative, $main::opt_list, 0);
} elsif ($main::opt_text) {
# Make sure the output is empty when have nothing to report
# (only matters when --heapcheck is given but we must be
@@ -839,7 +840,7 @@ sub InteractiveCommand {
my $ignore;
($routine, $ignore) = ParseInteractiveArgs($3);
- my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore);
+ my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
my $reduced = ReduceProfile($symbols, $profile);
# Get derived profiles
@@ -866,21 +867,22 @@ sub InteractiveCommand {
return 1;
}
- if (m/^\s*list\s*(.+)/) {
+ if (m/^\s*(web)?list\s*(.+)/) {
+ my $html = (defined($1) && ($1 eq "web"));
$main::opt_list = 1;
my $routine;
my $ignore;
- ($routine, $ignore) = ParseInteractiveArgs($1);
+ ($routine, $ignore) = ParseInteractiveArgs($2);
- my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore);
+ my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
my $reduced = ReduceProfile($symbols, $profile);
# Get derived profiles
my $flat = FlatProfile($reduced);
my $cumulative = CumulativeProfile($reduced);
- PrintListing($libs, $flat, $cumulative, $routine);
+ PrintListing($total, $libs, $flat, $cumulative, $routine, $html);
return 1;
}
if (m/^\s*disasm\s*(.+)/) {
@@ -891,7 +893,7 @@ sub InteractiveCommand {
($routine, $ignore) = ParseInteractiveArgs($1);
# Process current profile to account for various settings
- my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore);
+ my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
my $reduced = ReduceProfile($symbols, $profile);
# Get derived profiles
@@ -918,7 +920,8 @@ sub InteractiveCommand {
($focus, $ignore) = ParseInteractiveArgs($2);
# Process current profile to account for various settings
- my $profile = ProcessProfile($orig_profile, $symbols, $focus, $ignore);
+ my $profile = ProcessProfile($total, $orig_profile, $symbols,
+ $focus, $ignore);
my $reduced = ReduceProfile($symbols, $profile);
# Get derived profiles
@@ -946,6 +949,7 @@ sub InteractiveCommand {
sub ProcessProfile {
+ my $total_count = shift;
my $orig_profile = shift;
my $symbols = shift;
my $focus = shift;
@@ -953,7 +957,6 @@ sub ProcessProfile {
# Process current profile to account for various settings
my $profile = $orig_profile;
- my $total_count = TotalProfile($profile);
printf("Total: %s %s\n", Unparse($total_count), Units());
if ($focus ne '') {
$profile = FocusProfile($symbols, $profile, $focus);
@@ -1000,6 +1003,11 @@ Commands:
list [routine_regexp] [-ignore1] [-ignore2]
Show source listing of routines whose names match "routine_regexp"
+ weblist [routine_regexp] [-ignore1] [-ignore2]
+ Displays a source listing of routines whose names match "routine_regexp"
+ in a web browser. You can click on source lines to view the
+ corresponding disassembly.
+
top [--cum] [-ignore1] [-ignore2]
top20 [--cum] [-ignore1] [-ignore2]
top37 [--cum] [-ignore1] [-ignore2]
@@ -1175,7 +1183,7 @@ sub PrintText {
$sym);
}
$lines++;
- last if ($line_limit >= 0 && $lines > $line_limit);
+ last if ($line_limit >= 0 && $lines >= $line_limit);
}
}
@@ -1322,13 +1330,33 @@ sub ByName {
return ShortFunctionName($a) cmp ShortFunctionName($b);
}
-# Print source-listing for all all routines that match $main::opt_list
+# Print source-listing for all all routines that match $list_opts
sub PrintListing {
+ my $total = shift;
my $libs = shift;
my $flat = shift;
my $cumulative = shift;
my $list_opts = shift;
+ my $html = shift;
+ my $output = \*STDOUT;
+ my $fname = "";
+
+ if ($html) {
+ # Arrange to write the output to a temporary file
+ $fname = TempName($main::next_tmpfile, "html");
+ $main::next_tmpfile++;
+ if (!open(TEMP, ">$fname")) {
+ print STDERR "$fname: $!\n";
+ return;
+ }
+ $output = \*TEMP;
+ print $output HtmlListingHeader();
+ printf $output ("<div class=\"legend\">%s<br>Total: %s %s</div>\n",
+ $main::prog, Unparse($total), Units());
+ }
+
+ my $listed = 0;
foreach my $lib (@{$libs}) {
my $symbol_table = GetProcedureBoundaries($lib->[0], $list_opts);
my $offset = AddressSub($lib->[1], $lib->[3]);
@@ -1340,15 +1368,113 @@ sub PrintListing {
my $addr = AddressAdd($start_addr, $offset);
for (my $i = 0; $i < $length; $i++) {
if (defined($cumulative->{$addr})) {
- PrintSource($lib->[0], $offset,
- $routine, $flat, $cumulative,
- $start_addr, $end_addr);
+ $listed += PrintSource(
+ $lib->[0], $offset,
+ $routine, $flat, $cumulative,
+ $start_addr, $end_addr,
+ $html,
+ $output);
last;
}
$addr = AddressInc($addr);
}
}
}
+
+ if ($html) {
+ if ($listed > 0) {
+ print $output HtmlListingFooter();
+ close($output);
+ RunWeb($fname);
+ } else {
+ close($output);
+ unlink($fname);
+ }
+ }
+}
+
+sub HtmlListingHeader {
+ return <<'EOF';
+<DOCTYPE html>
+<html>
+<head>
+<title>Pprof listing</title>
+<style type="text/css">
+body {
+ font-family: sans-serif;
+}
+h1 {
+ font-size: 1.5em;
+ margin-bottom: 4px;
+}
+.legend {
+ font-size: 1.25em;
+}
+.line {
+ color: #aaaaaa;
+}
+.nop {
+ color: #aaaaaa;
+}
+.unimportant {
+ color: #cccccc;
+}
+.disasmloc {
+ color: #000000;
+}
+.deadsrc {
+ cursor: pointer;
+}
+.deadsrc:hover {
+ background-color: #eeeeee;
+}
+.livesrc {
+ color: #0000ff;
+ cursor: pointer;
+}
+.livesrc:hover {
+ background-color: #eeeeee;
+}
+.asm {
+ color: #008800;
+ display: none;
+}
+</style>
+<script type="text/javascript">
+function pprof_toggle_asm(e) {
+ var target;
+ if (!e) e = window.event;
+ if (e.target) target = e.target;
+ else if (e.srcElement) target = e.srcElement;
+
+ if (target) {
+ var asm = target.nextSibling;
+ if (asm && asm.className == "asm") {
+ asm.style.display = (asm.style.display == "block" ? "" : "block");
+ e.preventDefault();
+ return false;
+ }
+ }
+}
+</script>
+</head>
+<body>
+EOF
+}
+
+sub HtmlListingFooter {
+ return <<'EOF';
+</body>
+</html>
+EOF
+}
+
+sub HtmlEscape {
+ my $text = shift;
+ $text =~ s/&/&amp;/g;
+ $text =~ s/</&lt;/g;
+ $text =~ s/>/&gt;/g;
+ return $text;
}
# Returns the indentation of the line, if it has any non-whitespace
@@ -1362,6 +1488,45 @@ sub Indentation {
}
}
+# If the symbol table contains inlining info, Disassemble() may tag an
+# instruction with a location inside an inlined function. But for
+# source listings, we prefer to use the location in the function we
+# are listing. So use MapToSymbols() to fetch full location
+# information for each instruction and then pick out the first
+# location from a location list (location list contains callers before
+# callees in case of inlining).
+#
+# After this routine has run, each entry in $instructions contains:
+# [0] start address
+# [1] filename for function we are listing
+# [2] line number for function we are listing
+# [3] disassembly
+# [4] limit address
+# [5] most specific filename (may be different from [1] due to inlining)
+# [6] most specific line number (may be different from [2] due to inlining)
+sub GetTopLevelLineNumbers {
+ my ($lib, $offset, $instructions) = @_;
+ my $pcs = [];
+ for (my $i = 0; $i <= $#{$instructions}; $i++) {
+ push(@{$pcs}, $instructions->[$i]->[0]);
+ }
+ my $symbols = {};
+ MapToSymbols($lib, $offset, $pcs, $symbols);
+ for (my $i = 0; $i <= $#{$instructions}; $i++) {
+ my $e = $instructions->[$i];
+ push(@{$e}, $e->[1]);
+ push(@{$e}, $e->[2]);
+ my $addr = $e->[0];
+ my $sym = $symbols->{$addr};
+ if (defined($sym)) {
+ if ($#{$sym} >= 2 && $sym->[1] =~ m/^(.*):(\d+)$/) {
+ $e->[1] = $1; # File name
+ $e->[2] = $2; # Line number
+ }
+ }
+ }
+}
+
# Print source-listing for one routine
sub PrintSource {
my $prog = shift;
@@ -1371,9 +1536,12 @@ sub PrintSource {
my $cumulative = shift;
my $start_addr = shift;
my $end_addr = shift;
+ my $html = shift;
+ my $output = shift;
# Disassemble all instructions (just to get line numbers)
my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
+ GetTopLevelLineNumbers($prog, $offset, \@instructions);
# Hack 1: assume that the first source file encountered in the
# disassembly contains the routine
@@ -1386,7 +1554,7 @@ sub PrintSource {
}
if (!defined($filename)) {
print STDERR "no filename found in $routine\n";
- return;
+ return 0;
}
# Hack 2: assume that the largest line number from $filename is the
@@ -1419,7 +1587,7 @@ sub PrintSource {
{
if (!open(FILE, "<$filename")) {
print STDERR "$filename: $!\n";
- return;
+ return 0;
}
my $l = 0;
my $first_indentation = -1;
@@ -1447,12 +1615,24 @@ sub PrintSource {
# Assign all samples to the range $firstline,$lastline,
# Hack 4: If an instruction does not occur in the range, its samples
# are moved to the next instruction that occurs in the range.
- my $samples1 = {};
- my $samples2 = {};
- my $running1 = 0; # Unassigned flat counts
- my $running2 = 0; # Unassigned cumulative counts
- my $total1 = 0; # Total flat counts
- my $total2 = 0; # Total cumulative counts
+ my $samples1 = {}; # Map from line number to flat count
+ my $samples2 = {}; # Map from line number to cumulative count
+ my $running1 = 0; # Unassigned flat counts
+ my $running2 = 0; # Unassigned cumulative counts
+ my $total1 = 0; # Total flat counts
+ my $total2 = 0; # Total cumulative counts
+ my %disasm = (); # Map from line number to disassembly
+ my $running_disasm = ""; # Unassigned disassembly
+ my $skip_marker = "---\n";
+ if ($html) {
+ $skip_marker = "";
+ for (my $l = $firstline; $l <= $lastline; $l++) {
+ $disasm{$l} = "";
+ }
+ }
+ my $last_dis_filename = '';
+ my $last_dis_linenum = -1;
+ my $last_touched_line = -1; # To detect gaps in disassembly for a line
foreach my $e (@instructions) {
# Add up counts for all address that fall inside this instruction
my $c1 = 0;
@@ -1461,6 +1641,38 @@ sub PrintSource {
$c1 += GetEntry($flat, $a);
$c2 += GetEntry($cumulative, $a);
}
+
+ if ($html) {
+ my $dis = sprintf(" %6s %6s \t\t%8s: %s ",
+ HtmlPrintNumber($c1),
+ HtmlPrintNumber($c2),
+ UnparseAddress($offset, $e->[0]),
+ CleanDisassembly($e->[3]));
+
+ # Append the most specific source line associated with this instruction
+ if (length($dis) < 80) { $dis .= (' ' x (80 - length($dis))) };
+ $dis = HtmlEscape($dis);
+ my $f = $e->[5];
+ my $l = $e->[6];
+ if ($f ne $last_dis_filename) {
+ $dis .= sprintf("<span class=disasmloc>%s:%d</span>",
+ HtmlEscape(CleanFileName($f)), $l);
+ } elsif ($l ne $last_dis_linenum) {
+ # De-emphasize the unchanged file name portion
+ $dis .= sprintf("<span class=unimportant>%s</span>" .
+ "<span class=disasmloc>:%d</span>",
+ HtmlEscape(CleanFileName($f)), $l);
+ } else {
+ # De-emphasize the entire location
+ $dis .= sprintf("<span class=unimportant>%s:%d</span>",
+ HtmlEscape(CleanFileName($f)), $l);
+ }
+ $last_dis_filename = $f;
+ $last_dis_linenum = $l;
+ $running_disasm .= $dis;
+ $running_disasm .= "\n";
+ }
+
$running1 += $c1;
$running2 += $c2;
$total1 += $c1;
@@ -1475,23 +1687,49 @@ sub PrintSource {
AddEntry($samples2, $line, $running2);
$running1 = 0;
$running2 = 0;
+ if ($html) {
+ if ($line != $last_touched_line && $disasm{$line} ne '') {
+ $disasm{$line} .= "\n";
+ }
+ $disasm{$line} .= $running_disasm;
+ $running_disasm = '';
+ $last_touched_line = $line;
+ }
}
}
# Assign any leftover samples to $lastline
AddEntry($samples1, $lastline, $running1);
AddEntry($samples2, $lastline, $running2);
-
- printf("ROUTINE ====================== %s in %s\n" .
- "%6s %6s Total %s (flat / cumulative)\n",
- ShortFunctionName($routine),
- $filename,
- Units(),
- Unparse($total1),
- Unparse($total2));
+ if ($html) {
+ if ($lastline != $last_touched_line && $disasm{$lastline} ne '') {
+ $disasm{$lastline} .= "\n";
+ }
+ $disasm{$lastline} .= $running_disasm;
+ }
+
+ if ($html) {
+ printf $output (
+ "<h1>%s</h1>%s\n<pre onClick=\"pprof_toggle_asm()\">\n" .
+ "Total:%6s %6s (flat / cumulative %s)\n",
+ HtmlEscape(ShortFunctionName($routine)),
+ HtmlEscape(CleanFileName($filename)),
+ Unparse($total1),
+ Unparse($total2),
+ Units());
+ } else {
+ printf $output (
+ "ROUTINE ====================== %s in %s\n" .
+ "%6s %6s Total %s (flat / cumulative)\n",
+ ShortFunctionName($routine),
+ CleanFileName($filename),
+ Unparse($total1),
+ Unparse($total2),
+ Units());
+ }
if (!open(FILE, "<$filename")) {
print STDERR "$filename: $!\n";
- return;
+ return 0;
}
my $l = 0;
while (<FILE>) {
@@ -1501,16 +1739,47 @@ sub PrintSource {
(($l <= $oldlastline + 5) || ($l <= $lastline))) {
chop;
my $text = $_;
- if ($l == $firstline) { printf("---\n"); }
- printf("%6s %6s %4d: %s\n",
- UnparseAlt(GetEntry($samples1, $l)),
- UnparseAlt(GetEntry($samples2, $l)),
- $l,
- $text);
- if ($l == $lastline) { printf("---\n"); }
+ if ($l == $firstline) { print $output $skip_marker; }
+ my $n1 = GetEntry($samples1, $l);
+ my $n2 = GetEntry($samples2, $l);
+ if ($html) {
+ # Emit a span that has one of the following classes:
+ # livesrc -- has samples
+ # deadsrc -- has disassembly, but with no samples
+ # nop -- has no matching disasembly
+ # Also emit an optional span containing disassembly.
+ my $dis = $disasm{$l};
+ my $asm = "";
+ if (defined($dis) && $dis ne '') {
+ $asm = "<span class=\"asm\">" . $dis . "</span>";
+ }
+ my $source_class = (($n1 + $n2 > 0)
+ ? "livesrc"
+ : (($asm ne "") ? "deadsrc" : "nop"));
+ printf $output (
+ "<span class=\"line\">%5d</span> " .
+ "<span class=\"%s\">%6s %6s %s</span>%s\n",
+ $l, $source_class,
+ HtmlPrintNumber($n1),
+ HtmlPrintNumber($n2),
+ HtmlEscape($text),
+ $asm);
+ } else {
+ printf $output(
+ "%6s %6s %4d: %s\n",
+ UnparseAlt($n1),
+ UnparseAlt($n2),
+ $l,
+ $text);
+ }
+ if ($l == $lastline) { print $output $skip_marker; }
};
}
close(FILE);
+ if ($html) {
+ print $output "</pre>\n";
+ }
+ return 1;
}
# Return the source line for the specified file/linenumber.
@@ -1653,21 +1922,11 @@ sub PrintDisassembledFunction {
# Print disassembly
for (my $x = $first_inst; $x <= $last_inst; $x++) {
my $e = $instructions[$x];
- my $address = $e->[0];
- $address = AddressSub($address, $offset); # Make relative to section
- $address =~ s/^0x//;
- $address =~ s/^0*//;
-
- # Trim symbols
- my $d = $e->[3];
- while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax)
- while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments
-
printf("%6s %6s %8s: %6s\n",
UnparseAlt($flat_count[$x]),
UnparseAlt($cum_count[$x]),
- $address,
- $d);
+ UnparseAddress($offset, $e->[0]),
+ CleanDisassembly($e->[3]));
}
}
}
@@ -2326,6 +2585,16 @@ sub UnparseAlt {
}
}
+# Alternate pretty-printed form: 0 maps to ""
+sub HtmlPrintNumber {
+ my $num = shift;
+ if ($num == 0) {
+ return "";
+ } else {
+ return Unparse($num);
+ }
+}
+
# Return output units
sub Units {
if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
@@ -2482,6 +2751,13 @@ sub RemoveUninterestingFrames {
'__builtin_vec_new',
'operator new',
'operator new[]',
+ # The entry to our memory-allocation routines on OS X
+ 'malloc_zone_malloc',
+ 'malloc_zone_calloc',
+ 'malloc_zone_valloc',
+ 'malloc_zone_realloc',
+ 'malloc_zone_memalign',
+ 'malloc_zone_free',
# These mark the beginning/end of our custom sections
'__start_google_malloc',
'__stop_google_malloc',
@@ -4414,6 +4690,31 @@ sub ShortFunctionName {
return $function;
}
+# Trim overly long symbols found in disassembler output
+sub CleanDisassembly {
+ my $d = shift;
+ while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax)
+ while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments
+ return $d;
+}
+
+# Clean file name for display
+sub CleanFileName {
+ my ($f) = @_;
+ $f =~ s|^/proc/self/cwd/||;
+ $f =~ s|^\./||;
+ return $f;
+}
+
+# Make address relative to section and clean up for display
+sub UnparseAddress {
+ my ($offset, $address) = @_;
+ $address = AddressSub($address, $offset);
+ $address =~ s/^0x//;
+ $address =~ s/^0*//;
+ return $address;
+}
+
##### Miscellaneous #####
# Find the right versions of the above object tools to use. The
diff --git a/src/profile-handler.cc b/src/profile-handler.cc
index 1946f7c..700b5c0 100644
--- a/src/profile-handler.cc
+++ b/src/profile-handler.cc
@@ -36,7 +36,7 @@
#include "config.h"
#include "profile-handler.h"
-#if !(defined(__CYGWIN__) || defined(__CYGWIN32__))
+#if !(defined(__CYGWIN__) || defined(__CYGWIN32__)) && !defined(__native_client__)
#include <stdio.h>
#include <errno.h>
@@ -478,12 +478,14 @@ extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) {
ProfileHandler::Instance()->GetState(state);
}
-#else // OS_CYGWIN
+#else // !defined(OS_CYGWIN) && !defined(__native_client__)
// ITIMER_PROF doesn't work under cygwin. ITIMER_REAL is available, but doesn't
// work as well for profiling, and also interferes with alarm(). Because of
// these issues, unless a specific need is identified, profiler support is
// disabled under Cygwin.
+//
+// Native Client runtime also does not have signals working.
extern "C" void ProfileHandlerRegisterThread() {
}
@@ -501,4 +503,4 @@ extern "C" void ProfileHandlerReset() {
extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) {
}
-#endif // OS_CYGWIN
+#endif // !defined(OS_CYGWIN) && !defined(__native_client__)
diff --git a/src/profiler.cc b/src/profiler.cc
index 38fbb93..a57953e 100644
--- a/src/profiler.cc
+++ b/src/profiler.cc
@@ -284,7 +284,7 @@ void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext,
}
}
-#if !(defined(__CYGWIN__) || defined(__CYGWIN32__))
+#if !(defined(__CYGWIN__) || defined(__CYGWIN32__)) && !defined(__native_client__)
extern "C" PERFTOOLS_DLL_DECL void ProfilerRegisterThread() {
ProfileHandlerRegisterThread();
@@ -316,12 +316,14 @@ extern "C" PERFTOOLS_DLL_DECL void ProfilerGetCurrentState(
CpuProfiler::instance_.GetCurrentState(state);
}
-#else // OS_CYGWIN
+#else // !defined(OS_CYGWIN) && !defined(__native_client__)
// ITIMER_PROF doesn't work under cygwin. ITIMER_REAL is available, but doesn't
// work as well for profiling, and also interferes with alarm(). Because of
// these issues, unless a specific need is identified, profiler support is
// disabled under Cygwin.
+//
+// Native Client runtime also does not have signals working.
extern "C" void ProfilerRegisterThread() { }
extern "C" void ProfilerFlush() { }
extern "C" int ProfilingIsEnabledForAllThreads() { return 0; }
@@ -335,7 +337,7 @@ extern "C" void ProfilerGetCurrentState(ProfilerState* state) {
memset(state, 0, sizeof(*state));
}
-#endif // OS_CYGWIN
+#endif // !defined(OS_CYGWIN) && !defined(__native_client__)
// DEPRECATED routines
extern "C" PERFTOOLS_DLL_DECL void ProfilerEnable() { }
diff --git a/src/stack_trace_table.h b/src/stack_trace_table.h
index e1d6a8a..26d21c1 100644
--- a/src/stack_trace_table.h
+++ b/src/stack_trace_table.h
@@ -36,7 +36,9 @@
#define TCMALLOC_STACK_TRACE_TABLE_H_
#include <config.h>
+#ifdef HAVE_STDINT_H
#include <stdint.h> // for uintptr_t
+#endif
#include "common.h"
namespace tcmalloc {
diff --git a/src/stacktrace.cc b/src/stacktrace.cc
index 68cb865..175cdf5 100644
--- a/src/stacktrace.cc
+++ b/src/stacktrace.cc
@@ -99,11 +99,12 @@
#elif 0
// This is for the benefit of code analysis tools that may have
// trouble with the computed #include above.
-# include "base/stacktrace_x86-inl.h"
-# include "base/stacktrace_libunwind-inl.h"
-# include "base/stacktrace_generic-inl.h"
-# include "base/stacktrace_powerpc-inl.h"
-# include "base/stacktrace_win32-inl.h"
+# include "stacktrace_x86-inl.h"
+# include "stacktrace_libunwind-inl.h"
+# include "stacktrace_generic-inl.h"
+# include "stacktrace_powerpc-inl.h"
+# include "stacktrace_nacl-inl.h"
+# include "stacktrace_win32-inl.h"
#else
# error Cannot calculate stack trace: will need to write for your environment
#endif
diff --git a/src/stacktrace_config.h b/src/stacktrace_config.h
index 18f16ab..b166ca2 100644
--- a/src/stacktrace_config.h
+++ b/src/stacktrace_config.h
@@ -46,8 +46,11 @@
#ifndef BASE_STACKTRACE_CONFIG_H_
#define BASE_STACKTRACE_CONFIG_H_
-// First, the i386 and x86_64 case.
-#if (defined(__i386__) || defined(__x86_64__)) && __GNUC__ >= 2
+#ifdef __native_client__
+# define STACKTRACE_INL_HEADER "base/stacktrace_nacl-inl.h"
+
+// i386 and x86_64 case.
+#elif (defined(__i386__) || defined(__x86_64__)) && __GNUC__ >= 2
# if !defined(NO_FRAME_POINTER)
# define STACKTRACE_INL_HEADER "stacktrace_x86-inl.h"
# define STACKTRACE_SKIP_CONTEXT_ROUTINES 1
diff --git a/src/stacktrace_nacl-inl.h b/src/stacktrace_nacl-inl.h
new file mode 100644
index 0000000..7467e75
--- /dev/null
+++ b/src/stacktrace_nacl-inl.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2011, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Author: Ivan Krasin
+//
+// Native Client stub for stacktrace.
+
+int GET_STACK_TRACE_OR_FRAMES {
+ return 0;
+}
diff --git a/src/symbolize.cc b/src/symbolize.cc
index ff45e3e..dfdfb7e 100644
--- a/src/symbolize.cc
+++ b/src/symbolize.cc
@@ -48,6 +48,13 @@
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
+#ifdef __MACH__
+#include <mach-o/dyld.h> // for GetProgramInvocationName()
+#include <limits.h> // for PATH_MAX
+#endif
+#if defined(__CYGWIN__) || defined(__CYGWIN32__)
+#include <io.h> // for get_osfhandle()
+#endif
#include <string>
#include "base/commandlineflags.h"
#include "base/sysinfo.h"
@@ -65,6 +72,27 @@ DEFINE_string(symbolize_pprof,
// a more-permanent copy that won't ever get destroyed.
static string* g_pprof_path = new string(FLAGS_symbolize_pprof);
+// Returns NULL if we're on an OS where we can't get the invocation name.
+// Using a static var is ok because we're not called from a thread.
+static char* GetProgramInvocationName() {
+#if defined(HAVE_PROGRAM_INVOCATION_NAME)
+ extern char* program_invocation_name; // gcc provides this
+ return program_invocation_name;
+#elif defined(__MACH__)
+ // We don't want to allocate memory for this since we may be
+ // calculating it when memory is corrupted.
+ static char program_invocation_name[PATH_MAX];
+ if (program_invocation_name[0] == '\0') { // first time calculating
+ uint32_t length = sizeof(program_invocation_name);
+ if (_NSGetExecutablePath(program_invocation_name, &length))
+ return NULL;
+ }
+ return program_invocation_name;
+#else
+ return NULL; // figure out a way to get argv[0]
+#endif
+}
+
void SymbolTable::Add(const void* addr) {
symbolization_table_[addr] = "";
}
@@ -82,11 +110,12 @@ const char* SymbolTable::GetSymbol(const void* addr) {
int SymbolTable::Symbolize() {
#if !defined(HAVE_UNISTD_H) || !defined(HAVE_SYS_SOCKET_H) || !defined(HAVE_SYS_WAIT_H)
return 0;
-#elif !defined(HAVE_PROGRAM_INVOCATION_NAME)
- return 0; // TODO(csilvers): get argv[0] somehow
#else
+ const char* argv0 = GetProgramInvocationName();
+ if (argv0 == NULL) // can't call symbolize if we can't figure out our name
+ return 0;
+
// All this work is to do two-way communication. ugh.
- extern char* program_invocation_name; // gcc provides this
int *child_in = NULL; // file descriptors
int *child_out = NULL; // for now, we don't worry about child_err
int child_fds[5][2]; // socketpair may be called up to five times below
@@ -142,7 +171,7 @@ int SymbolTable::Symbolize() {
unsetenv("HEAPCHECK");
unsetenv("PERFTOOLS_VERBOSE");
execlp(g_pprof_path->c_str(), g_pprof_path->c_str(),
- "--symbols", program_invocation_name, NULL);
+ "--symbols", argv0, NULL);
_exit(3); // if execvp fails, it's bad news for us
}
default: { // parent
@@ -159,7 +188,13 @@ int SymbolTable::Symbolize() {
return 0;
}
#endif
+#if defined(__CYGWIN__) || defined(__CYGWIN32__)
+ // On cygwin, DumpProcSelfMaps() takes a HANDLE, not an fd. Convert.
+ const HANDLE symbols_handle = (HANDLE) get_osfhandle(child_in[1]);
+ DumpProcSelfMaps(symbols_handle);
+#else
DumpProcSelfMaps(child_in[1]); // what pprof expects on stdin
+#endif
// Allocate 24 bytes = ("0x" + 8 bytes + "\n" + overhead) for each
// address to feed to pprof.
diff --git a/src/system-alloc.cc b/src/system-alloc.cc
index 690953d..a05060a 100644
--- a/src/system-alloc.cc
+++ b/src/system-alloc.cc
@@ -133,7 +133,6 @@ public:
SbrkSysAllocator() : SysAllocator() {
}
void* Alloc(size_t size, size_t *actual_size, size_t alignment);
- void FlagsInitialized() {}
};
static char sbrk_space[sizeof(SbrkSysAllocator)];
@@ -142,7 +141,6 @@ public:
MmapSysAllocator() : SysAllocator() {
}
void* Alloc(size_t size, size_t *actual_size, size_t alignment);
- void FlagsInitialized() {}
};
static char mmap_space[sizeof(MmapSysAllocator)];
@@ -151,7 +149,6 @@ public:
DevMemSysAllocator() : SysAllocator() {
}
void* Alloc(size_t size, size_t *actual_size, size_t alignment);
- void FlagsInitialized() {}
};
class DefaultSysAllocator : public SysAllocator {
@@ -160,6 +157,7 @@ class DefaultSysAllocator : public SysAllocator {
for (int i = 0; i < kMaxAllocators; i++) {
failed_[i] = true;
allocs_[i] = NULL;
+ names_[i] = NULL;
}
}
void SetChildAllocator(SysAllocator* alloc, unsigned int index,
@@ -167,10 +165,10 @@ class DefaultSysAllocator : public SysAllocator {
if (index < kMaxAllocators && alloc != NULL) {
allocs_[index] = alloc;
failed_[index] = false;
+ names_[index] = name;
}
}
void* Alloc(size_t size, size_t *actual_size, size_t alignment);
- void FlagsInitialized() {}
private:
static const int kMaxAllocators = 2;
diff --git a/src/system-alloc.h b/src/system-alloc.h
index 487a36b..814b556 100644
--- a/src/system-alloc.h
+++ b/src/system-alloc.h
@@ -74,4 +74,4 @@ extern void TCMalloc_SystemRelease(void* start, size_t length);
// The current system allocator.
extern PERFTOOLS_DLL_DECL SysAllocator* sys_alloc;
-#endif /* TCMALLOC_SYSTEM_ALLOC_H__ */
+#endif /* TCMALLOC_SYSTEM_ALLOC_H_ */
diff --git a/src/tcmalloc.cc b/src/tcmalloc.cc
index 97c366c..263db81 100644
--- a/src/tcmalloc.cc
+++ b/src/tcmalloc.cc
@@ -93,9 +93,6 @@
#ifdef HAVE_SYS_CDEFS_H
#include <sys/cdefs.h> // for __THROW
#endif
-#ifdef HAVE_FEATURES_H
-#include <features.h> // for __GLIBC__
-#endif
#if defined HAVE_STDINT_H
#include <stdint.h>
#elif defined HAVE_INTTYPES_H
@@ -153,6 +150,17 @@
using STL_NAMESPACE::max;
using STL_NAMESPACE::numeric_limits;
using STL_NAMESPACE::vector;
+
+#include "libc_override.h"
+
+// __THROW is defined in glibc (via <sys/cdefs.h>). It means,
+// counter-intuitively, "This function will never throw an exception."
+// It's an optional optimization tool, but we may need to use it to
+// match glibc prototypes.
+#ifndef __THROW // I guess we're not on a glibc system
+# define __THROW // __THROW is just an optimization, so ok to make it ""
+#endif
+
using tcmalloc::AlignmentForSize;
using tcmalloc::PageHeap;
using tcmalloc::PageHeapAllocator;
@@ -162,13 +170,6 @@ using tcmalloc::StackTrace;
using tcmalloc::Static;
using tcmalloc::ThreadCache;
-// __THROW is defined in glibc systems. It means, counter-intuitively,
-// "This function will never throw an exception." It's an optional
-// optimization tool, but we may need to use it to match glibc prototypes.
-#ifndef __THROW // I guess we're not on a glibc system
-# define __THROW // __THROW is just an optimization, so ok to make it ""
-#endif
-
DECLARE_int64(tcmalloc_sample_parameter);
DECLARE_double(tcmalloc_release_rate);
@@ -267,128 +268,6 @@ extern "C" {
} // extern "C"
#endif // #ifndef _WIN32
-// Override the libc functions to prefer our own instead. This comes
-// first so code in tcmalloc.cc can use the overridden versions. One
-// exception: in windows, by default, we patch our code into these
-// functions (via src/windows/patch_function.cc) rather than override
-// them. In that case, we don't want to do this overriding here.
-#if !defined(WIN32_DO_PATCHING)
-
-#if defined(__GNUC__) && !defined(__MACH__)
- // Potentially faster variants that use the gcc alias extension.
- // FreeBSD does support aliases, but apparently not correctly. :-(
- // NOTE: we make many of these symbols weak, but do so in the makefile
- // (via objcopy -W) and not here. That ends up being more portable.
-# define ALIAS(x) __attribute__ ((alias (x)))
-void* operator new(size_t size) throw (std::bad_alloc) ALIAS("tc_new");
-void operator delete(void* p) __THROW ALIAS("tc_delete");
-void* operator new[](size_t size) throw (std::bad_alloc) ALIAS("tc_newarray");
-void operator delete[](void* p) __THROW ALIAS("tc_deletearray");
-void* operator new(size_t size, const std::nothrow_t&) __THROW
- ALIAS("tc_new_nothrow");
-void* operator new[](size_t size, const std::nothrow_t&) __THROW
- ALIAS("tc_newarray_nothrow");
-void operator delete(void* size, const std::nothrow_t&) __THROW
- ALIAS("tc_delete_nothrow");
-void operator delete[](void* size, const std::nothrow_t&) __THROW
- ALIAS("tc_deletearray_nothrow");
-extern "C" {
- void* malloc(size_t size) __THROW ALIAS("tc_malloc");
- void free(void* ptr) __THROW ALIAS("tc_free");
- void* realloc(void* ptr, size_t size) __THROW ALIAS("tc_realloc");
- void* calloc(size_t n, size_t size) __THROW ALIAS("tc_calloc");
- void cfree(void* ptr) __THROW ALIAS("tc_cfree");
- void* memalign(size_t align, size_t s) __THROW ALIAS("tc_memalign");
- void* valloc(size_t size) __THROW ALIAS("tc_valloc");
- void* pvalloc(size_t size) __THROW ALIAS("tc_pvalloc");
- int posix_memalign(void** r, size_t a, size_t s) __THROW
- ALIAS("tc_posix_memalign");
- void malloc_stats(void) __THROW ALIAS("tc_malloc_stats");
- int mallopt(int cmd, int value) __THROW ALIAS("tc_mallopt");
-#ifdef HAVE_STRUCT_MALLINFO
- struct mallinfo mallinfo(void) __THROW ALIAS("tc_mallinfo");
-#endif
- size_t malloc_size(void* p) __THROW ALIAS("tc_malloc_size");
- size_t malloc_usable_size(void* p) __THROW ALIAS("tc_malloc_size");
-} // extern "C"
-#else // #if defined(__GNUC__) && !defined(__MACH__)
-// Portable wrappers
-void* operator new(size_t size) { return tc_new(size); }
-void operator delete(void* p) __THROW { tc_delete(p); }
-void* operator new[](size_t size) { return tc_newarray(size); }
-void operator delete[](void* p) __THROW { tc_deletearray(p); }
-void* operator new(size_t size, const std::nothrow_t& nt) __THROW {
- return tc_new_nothrow(size, nt);
-}
-void* operator new[](size_t size, const std::nothrow_t& nt) __THROW {
- return tc_newarray_nothrow(size, nt);
-}
-void operator delete(void* ptr, const std::nothrow_t& nt) __THROW {
- return tc_delete_nothrow(ptr, nt);
-}
-void operator delete[](void* ptr, const std::nothrow_t& nt) __THROW {
- return tc_deletearray_nothrow(ptr, nt);
-}
-extern "C" {
- void* malloc(size_t s) __THROW { return tc_malloc(s); }
- void free(void* p) __THROW { tc_free(p); }
- void* realloc(void* p, size_t s) __THROW { return tc_realloc(p, s); }
- void* calloc(size_t n, size_t s) __THROW { return tc_calloc(n, s); }
- void cfree(void* p) __THROW { tc_cfree(p); }
- void* memalign(size_t a, size_t s) __THROW { return tc_memalign(a, s); }
- void* valloc(size_t s) __THROW { return tc_valloc(s); }
- void* pvalloc(size_t s) __THROW { return tc_pvalloc(s); }
- int posix_memalign(void** r, size_t a, size_t s) __THROW {
- return tc_posix_memalign(r, a, s);
- }
- void malloc_stats(void) __THROW { tc_malloc_stats(); }
- int mallopt(int cmd, int v) __THROW { return tc_mallopt(cmd, v); }
-#ifdef HAVE_STRUCT_MALLINFO
- struct mallinfo mallinfo(void) __THROW { return tc_mallinfo(); }
-#endif
- size_t malloc_size(void* p) __THROW { return tc_malloc_size(p); }
- size_t malloc_usable_size(void* p) __THROW { return tc_malloc_size(p); }
-} // extern "C"
-#endif // #if defined(__GNUC__)
-
-// Some library routines on RedHat 9 allocate memory using malloc()
-// and free it using __libc_free() (or vice-versa). Since we provide
-// our own implementations of malloc/free, we need to make sure that
-// the __libc_XXX variants (defined as part of glibc) also point to
-// the same implementations.
-#ifdef __GLIBC__ // only glibc defines __libc_*
-extern "C" {
-#ifdef ALIAS
- void* __libc_malloc(size_t size) ALIAS("tc_malloc");
- void __libc_free(void* ptr) ALIAS("tc_free");
- void* __libc_realloc(void* ptr, size_t size) ALIAS("tc_realloc");
- void* __libc_calloc(size_t n, size_t size) ALIAS("tc_calloc");
- void __libc_cfree(void* ptr) ALIAS("tc_cfree");
- void* __libc_memalign(size_t align, size_t s) ALIAS("tc_memalign");
- void* __libc_valloc(size_t size) ALIAS("tc_valloc");
- void* __libc_pvalloc(size_t size) ALIAS("tc_pvalloc");
- int __posix_memalign(void** r, size_t a, size_t s) ALIAS("tc_posix_memalign");
-#else // #ifdef ALIAS
- void* __libc_malloc(size_t size) { return malloc(size); }
- void __libc_free(void* ptr) { free(ptr); }
- void* __libc_realloc(void* ptr, size_t size) { return realloc(ptr, size); }
- void* __libc_calloc(size_t n, size_t size) { return calloc(n, size); }
- void __libc_cfree(void* ptr) { cfree(ptr); }
- void* __libc_memalign(size_t align, size_t s) { return memalign(align, s); }
- void* __libc_valloc(size_t size) { return valloc(size); }
- void* __libc_pvalloc(size_t size) { return pvalloc(size); }
- int __posix_memalign(void** r, size_t a, size_t s) {
- return posix_memalign(r, a, s);
- }
-#endif // #ifdef ALIAS
-} // extern "C"
-#endif // ifdef __GLIBC__
-
-#undef ALIAS
-
-#endif // #ifndef(WIN32_DO_PATCHING)
-
-
// ----------------------- IMPLEMENTATION -------------------------------
static int tc_new_mode = 0; // See tc_set_new_mode().
@@ -430,9 +309,10 @@ static void ExtractStats(TCMallocStats* r, uint64_t* class_count) {
for (int cl = 0; cl < kNumClasses; ++cl) {
const int length = Static::central_cache()[cl].length();
const int tc_length = Static::central_cache()[cl].tc_length();
+ const size_t cache_overhead = Static::central_cache()[cl].OverheadBytes();
const size_t size = static_cast<uint64_t>(
Static::sizemap()->ByteSizeForClass(cl));
- r->central_bytes += (size * length);
+ r->central_bytes += (size * length) + cache_overhead;
r->transfer_bytes += (size * tc_length);
if (class_count) class_count[cl] = length + tc_length;
}
@@ -811,6 +691,25 @@ class TCMallocImplementation : public MallocExtension {
// file.
virtual size_t GetAllocatedSize(void* ptr);
+ // This duplicates some of the logic in GetSizeWithCallback, but is
+ // faster. This is important on OS X, where this function is called
+ // on every allocation operation.
+ virtual Ownership GetOwnership(const void* ptr) {
+ const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift;
+ // The rest of tcmalloc assumes that all allocated pointers use at
+ // most kAddressBits bits. If ptr doesn't, then it definitely
+ // wasn't alloacted by tcmalloc.
+ if ((p >> (kAddressBits - kPageShift)) > 0) {
+ return kNotOwned;
+ }
+ size_t cl = Static::pageheap()->GetSizeClassIfCached(p);
+ if (cl != 0) {
+ return kOwned;
+ }
+ const Span *span = Static::pageheap()->GetDescriptor(p);
+ return span ? kOwned : kNotOwned;
+ }
+
virtual void GetFreeListSizes(vector<MallocExtension::FreeListInfo>* v) {
static const char* kCentralCacheType = "tcmalloc.central";
static const char* kTransferCacheType = "tcmalloc.transfer";
@@ -924,9 +823,12 @@ TCMallocGuard::TCMallocGuard() {
// Check whether the kernel also supports TLS (needs to happen at runtime)
tcmalloc::CheckIfKernelSupportsTLS();
#endif
-#ifdef WIN32_DO_PATCHING
- // patch the windows VirtualAlloc, etc.
- PatchWindowsFunctions(); // defined in windows/patch_functions.cc
+ ReplaceSystemAlloc(); // defined in libc_override_*.h
+#if defined(__APPLE__)
+ // To break the recursive call of malloc, as malloc -> TCMALLOC_MESSAGE
+ // -> snprintf -> localeconv_l -> malloc, on MacOS.
+ char buf[32];
+ snprintf(buf, sizeof(buf), "%d", tcmallocguard_refcount);
#endif
tc_free(tc_malloc(1));
ThreadCache::InitTSD();
@@ -1023,8 +925,8 @@ static void ReportLargeAlloc(Length num_pages, void* result) {
static const int N = 1000;
char buffer[N];
TCMalloc_Printer printer(buffer, N);
- printer.printf("tcmalloc: large alloc %llu bytes == %p @ ",
- static_cast<unsigned long long>(num_pages) << kPageShift,
+ printer.printf("tcmalloc: large alloc %"PRIu64" bytes == %p @ ",
+ static_cast<uint64>(num_pages) << kPageShift,
result);
for (int i = 0; i < stack.depth; i++) {
printer.printf(" %p", stack.stack[i]);
@@ -1184,6 +1086,8 @@ inline void do_free(void* ptr) {
return do_free_with_callback(ptr, &InvalidFree);
}
+// NOTE: some logic here is duplicated in GetOwnership (above), for
+// speed. If you change this function, look at that one too.
inline size_t GetSizeWithCallback(void* ptr,
size_t (*invalid_getsize_fn)(void*)) {
if (ptr == NULL)
@@ -1193,7 +1097,7 @@ inline size_t GetSizeWithCallback(void* ptr,
if (cl != 0) {
return Static::sizemap()->ByteSizeForClass(cl);
} else {
- Span *span = Static::pageheap()->GetDescriptor(p);
+ const Span *span = Static::pageheap()->GetDescriptor(p);
if (span == NULL) { // means we do not own this memory
return (*invalid_getsize_fn)(ptr);
} else if (span->sizeclass != 0) {
@@ -1476,6 +1380,8 @@ void* cpp_memalign(size_t align, size_t size) {
// As promised, the definition of this function, declared above.
size_t TCMallocImplementation::GetAllocatedSize(void* ptr) {
+ ASSERT(TCMallocImplementation::GetOwnership(ptr)
+ != TCMallocImplementation::kNotOwned);
return GetSizeWithCallback(ptr, &InvalidGetAllocatedSize);
}
@@ -1673,26 +1579,7 @@ extern "C" PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) __THROW {
#endif
extern "C" PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) __THROW {
- return GetSizeWithCallback(ptr, &InvalidGetAllocatedSize);
-}
-
-
-// Override __libc_memalign in libc on linux boxes specially.
-// They have a bug in libc that causes them to (very rarely) allocate
-// with __libc_memalign() yet deallocate with free() and the
-// definitions above don't catch it.
-// This function is an exception to the rule of calling MallocHook method
-// from the stack frame of the allocation function;
-// heap-checker handles this special case explicitly.
-static void *MemalignOverride(size_t align, size_t size, const void *caller)
- __THROW ATTRIBUTE_SECTION(google_malloc);
-
-static void *MemalignOverride(size_t align, size_t size, const void *caller)
- __THROW {
- void* result = do_memalign_or_cpp_memalign(align, size);
- MallocHook::InvokeNewHook(result, size);
- return result;
+ return MallocExtension::instance()->GetAllocatedSize(ptr);
}
-void *(*__memalign_hook)(size_t, size_t, const void *) = MemalignOverride;
#endif // TCMALLOC_USING_DEBUGALLOCATION
diff --git a/src/tests/debugallocation_test.cc b/src/tests/debugallocation_test.cc
index 07b8604..cb458d4 100644
--- a/src/tests/debugallocation_test.cc
+++ b/src/tests/debugallocation_test.cc
@@ -75,7 +75,10 @@ static int test_counter = 0; // incremented every time the macro is called
// This flag won't be compiled in in opt mode.
DECLARE_int32(max_free_queue_size);
-// Test match as well as mismatch rules:
+// Test match as well as mismatch rules. But do not test on OS X; on
+// OS X the OS converts new/new[] to malloc before it gets to us, so
+// we are unable to catch these mismatch errors.
+#ifndef __APPLE__
TEST(DebugAllocationTest, DeallocMismatch) {
// malloc can be matched only by free
// new can be matched only by delete and delete(nothrow)
@@ -132,6 +135,7 @@ TEST(DebugAllocationTest, DeallocMismatch) {
::operator delete[](y, std::nothrow);
}
}
+#endif // #ifdef OS_MACOSX
TEST(DebugAllocationTest, DoubleFree) {
int* pint = new int;
diff --git a/src/tests/malloc_extension_c_test.c b/src/tests/malloc_extension_c_test.c
index e384b76..57cdbbd 100644
--- a/src/tests/malloc_extension_c_test.c
+++ b/src/tests/malloc_extension_c_test.c
@@ -126,6 +126,14 @@ void TestMallocExtension(void) {
if (MallocExtension_GetAllocatedSize(x) < 10) {
FAIL("GetEstimatedAllocatedSize returned a bad value (too small)");
}
+ if (MallocExtension_GetOwnership(x) != MallocExtension_kOwned) {
+ FAIL("DidAllocatePtr returned a bad value (kNotOwned)");
+ }
+ /* TODO(csilvers): this relies on undocumented behavior that
+ GetOwnership works on stack-allocated variables. Use a better test. */
+ if (MallocExtension_GetOwnership(hist) != MallocExtension_kNotOwned) {
+ FAIL("DidAllocatePtr returned a bad value (kOwned)");
+ }
free(x);
}
diff --git a/src/tests/malloc_extension_test.cc b/src/tests/malloc_extension_test.cc
index 0bd85ad..3e57765 100644
--- a/src/tests/malloc_extension_test.cc
+++ b/src/tests/malloc_extension_test.cc
@@ -55,6 +55,14 @@ int main(int argc, char** argv) {
ASSERT_TRUE(MallocExtension::instance()->VerifyAllMemory());
ASSERT_TRUE(MallocExtension_VerifyAllMemory());
+ ASSERT_EQ(MallocExtension::kOwned,
+ MallocExtension::instance()->GetOwnership(a));
+ // TODO(csilvers): this relies on undocumented behavior that
+ // GetOwnership works on stack-allocated variables. Use a better test.
+ ASSERT_EQ(MallocExtension::kNotOwned,
+ MallocExtension::instance()->GetOwnership(&cxx_bytes_used));
+ ASSERT_EQ(MallocExtension::kNotOwned,
+ MallocExtension::instance()->GetOwnership(NULL));
ASSERT_GE(MallocExtension::instance()->GetAllocatedSize(a), 1000);
// This is just a sanity check. If we allocated too much, tcmalloc is broken
ASSERT_LE(MallocExtension::instance()->GetAllocatedSize(a), 5000);
@@ -68,12 +76,24 @@ int main(int argc, char** argv) {
}
// Check the c-shim version too.
+ ASSERT_EQ(MallocExtension_kOwned, MallocExtension_GetOwnership(a));
+ ASSERT_EQ(MallocExtension_kNotOwned,
+ MallocExtension_GetOwnership(&cxx_bytes_used));
+ ASSERT_EQ(MallocExtension_kNotOwned, MallocExtension_GetOwnership(NULL));
ASSERT_GE(MallocExtension_GetAllocatedSize(a), 1000);
ASSERT_LE(MallocExtension_GetAllocatedSize(a), 5000);
ASSERT_GE(MallocExtension_GetEstimatedAllocatedSize(1000), 1000);
free(a);
+ // Verify that the .cc file and .h file have the same enum values.
+ ASSERT_EQ(static_cast<int>(MallocExtension::kUnknownOwnership),
+ static_cast<int>(MallocExtension_kUnknownOwnership));
+ ASSERT_EQ(static_cast<int>(MallocExtension::kOwned),
+ static_cast<int>(MallocExtension_kOwned));
+ ASSERT_EQ(static_cast<int>(MallocExtension::kNotOwned),
+ static_cast<int>(MallocExtension_kNotOwned));
+
printf("DONE\n");
return 0;
}
diff --git a/src/tests/malloc_hook_test.cc b/src/tests/malloc_hook_test.cc
index dc65b68..b46f6fd 100644
--- a/src/tests/malloc_hook_test.cc
+++ b/src/tests/malloc_hook_test.cc
@@ -36,16 +36,25 @@
#ifdef HAVE_MMAP
#include <sys/mman.h>
#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> // for sleep()
+#endif
#include <algorithm>
#include <string>
#include <vector>
#include <google/malloc_hook.h>
#include "malloc_hook-inl.h"
#include "base/logging.h"
-#include "base/spinlock.h"
+#include "base/simple_mutex.h"
#include "base/sysinfo.h"
#include "tests/testutil.h"
+// On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old
+// form of the name instead.
+#ifndef MAP_ANONYMOUS
+# define MAP_ANONYMOUS MAP_ANON
+#endif
+
namespace {
using std::string;
@@ -72,6 +81,15 @@ static int RUN_ALL_TESTS() {
return 0;
}
+void Sleep(int seconds) {
+#ifdef _MSC_VER
+ _sleep(seconds * 1000); // Windows's _sleep takes milliseconds argument
+#else
+ sleep(seconds);
+#endif
+}
+
+using std::min;
using base::internal::kHookListMaxValues;
// Since HookList is a template and is defined in malloc_hook.cc, we can only
@@ -81,7 +99,7 @@ typedef base::internal::HookList<MallocHook::NewHook> TestHookList;
int TestHookList_Traverse(const TestHookList& list, int* output_array, int n) {
MallocHook::NewHook values_as_hooks[kHookListMaxValues];
- int result = list.Traverse(values_as_hooks, std::min(n, kHookListMaxValues));
+ int result = list.Traverse(values_as_hooks, min(n, kHookListMaxValues));
for (int i = 0; i < result; ++i) {
output_array[i] = reinterpret_cast<const int&>(values_as_hooks[i]);
}
@@ -229,12 +247,12 @@ void MultithreadedTestThread(TestHookList* list, int shift,
static volatile int num_threads_remaining;
static TestHookList list = INIT_HOOK_LIST(69);
-static SpinLock threadcount_lock;
+static Mutex threadcount_lock;
void MultithreadedTestThreadRunner(int thread_num) {
// Wait for all threads to start running.
{
- SpinLockHolder h(&threadcount_lock);
+ MutexLock ml(&threadcount_lock);
assert(num_threads_remaining > 0);
--num_threads_remaining;
@@ -242,7 +260,7 @@ void MultithreadedTestThreadRunner(int thread_num) {
// go simple and busy-wait.
while (num_threads_remaining > 0) {
threadcount_lock.Unlock();
- SleepForMilliseconds(100);
+ Sleep(1);
threadcount_lock.Lock();
}
}
@@ -271,7 +289,10 @@ TEST(HookListTest, MultithreadedTest) {
EXPECT_EQ(0, list.priv_end);
}
-#ifdef HAVE_MMAP
+// We only do mmap-hooking on (some) linux systems.
+#if defined(HAVE_MMAP) && defined(__linux) && \
+ (defined(__i386__) || defined(__x86_64__) || defined(__PPC__))
+
int mmap_calls = 0;
int mmap_matching_calls = 0;
int munmap_calls = 0;
@@ -336,7 +357,7 @@ TEST(MallocMookTest, MmapReplacements) {
// whoever owns that memory now.
// EXPECT_DEATH(*ptr = 'a', "SIGSEGV");
}
-#endif // #ifdef HAVE_MMAN
+#endif // #ifdef HAVE_MMAP && linux && ...
} // namespace
diff --git a/src/tests/profiler_unittest.cc b/src/tests/profiler_unittest.cc
index 19371b7..fafc76f 100644
--- a/src/tests/profiler_unittest.cc
+++ b/src/tests/profiler_unittest.cc
@@ -61,7 +61,7 @@ static void test_other_thread() {
for (i = 0; i < g_iters; ++i ) {
result ^= i;
}
- snprintf(b, sizeof(b), "%d", result); // get some libc action
+ snprintf(b, sizeof(b), "other: %d", result); // get some libc action
}
#endif
}
@@ -74,7 +74,7 @@ static void test_main_thread() {
for (i = 0; i < g_iters; ++i ) {
result ^= i;
}
- snprintf(b, sizeof(b), "%d", result); // get some libc action
+ snprintf(b, sizeof(b), "same: %d", result); // get some libc action
}
}
diff --git a/src/tests/system-alloc_unittest.cc b/src/tests/system-alloc_unittest.cc
index c006425..8e4eb36 100644
--- a/src/tests/system-alloc_unittest.cc
+++ b/src/tests/system-alloc_unittest.cc
@@ -40,6 +40,7 @@
#endif
#include <sys/types.h>
#include <algorithm>
+#include <limits>
#include "base/logging.h" // for Check_GEImpl, Check_LTImpl, etc
#include <google/malloc_extension.h> // for MallocExtension::instance
#include "common.h" // for kAddressBits
@@ -83,7 +84,6 @@ public:
void DumpStats() {
}
- void FlagsInitialized() {}
private:
static const int kArraySize = 8 * 1024 * 1024;
@@ -115,14 +115,30 @@ TEST(AddressBits, CpuVirtualBits) {
const int kPointerBits = 8 * sizeof(void*);
const int kImplementedVirtualBits = NumImplementedVirtualBits();
- CHECK_GE(kAddressBits, min(kImplementedVirtualBits, kPointerBits));
+ CHECK_GE(kAddressBits, std::min(kImplementedVirtualBits, kPointerBits));
}
#endif
static void TestBasicRetryFailTest() {
// Check with the allocator still works after a failed allocation.
- void* p = malloc(1ULL << 50); // Asking for 1P ram
- CHECK(p == NULL);
+ //
+ // There is no way to call malloc and guarantee it will fail. malloc takes a
+ // size_t parameter and the C++ standard does not constrain the size of
+ // size_t. For example, consider an implementation where size_t is 32 bits
+ // and pointers are 64 bits.
+ //
+ // It is likely, though, that sizeof(size_t) == sizeof(void*). In that case,
+ // the first allocation here might succeed but the second allocation must
+ // fail.
+ //
+ // If the second allocation succeeds, you will have to rewrite or
+ // disable this test.
+ // The weird parens are to avoid macro-expansion of 'max' on windows.
+ const size_t kHugeSize = (std::numeric_limits<size_t>::max)() / 2;
+ void* p1 = malloc(kHugeSize);
+ void* p2 = malloc(kHugeSize);
+ CHECK(p2 == NULL);
+ if (p1 != NULL) free(p1);
char* q = new char[1024];
CHECK(q != NULL);
diff --git a/src/tests/tcmalloc_unittest.cc b/src/tests/tcmalloc_unittest.cc
index b430460..84a5889 100644
--- a/src/tests/tcmalloc_unittest.cc
+++ b/src/tests/tcmalloc_unittest.cc
@@ -96,16 +96,45 @@
// Windows doesn't define pvalloc and a few other obsolete unix
// functions; nor does it define posix_memalign (which is not obsolete).
-#if defined(_MSC_VER) || defined(__MINGW32__)
+#if defined(_WIN32)
# define cfree free // don't bother to try to test these obsolete fns
# define valloc malloc
# define pvalloc malloc
// I'd like to map posix_memalign to _aligned_malloc, but _aligned_malloc
// must be paired with _aligned_free (not normal free), which is too
// invasive a change to how we allocate memory here. So just bail
-# include <errno.h>
-# define memalign(alignment, size) malloc(size)
-# define posix_memalign(pptr, align, size) ((*(pptr)=malloc(size)) ? 0 : ENOMEM)
+static bool kOSSupportsMemalign = false;
+static inline void* Memalign(size_t align, size_t size) {
+ //LOG(FATAL) << "memalign not supported on windows";
+ exit(1);
+}
+static inline int PosixMemalign(void** ptr, size_t align, size_t size) {
+ //LOG(FATAL) << "posix_memalign not supported on windows";
+ exit(1);
+}
+
+// OS X defines posix_memalign in some OS versions but not others;
+// it's confusing enough to check that it's easiest to just not to test.
+#elif defined(__APPLE__)
+static bool kOSSupportsMemalign = false;
+static inline void* Memalign(size_t align, size_t size) {
+ //LOG(FATAL) << "memalign not supported on OS X";
+ exit(1);
+}
+static inline int PosixMemalign(void** ptr, size_t align, size_t size) {
+ //LOG(FATAL) << "posix_memalign not supported on OS X";
+ exit(1);
+}
+
+#else
+static bool kOSSupportsMemalign = true;
+static inline void* Memalign(size_t align, size_t size) {
+ return memalign(align, size);
+}
+static inline int PosixMemalign(void** ptr, size_t align, size_t size) {
+ return posix_memalign(ptr, align, size);
+}
+
#endif
// On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old
@@ -149,7 +178,12 @@ static const size_t kMaxSize = ~static_cast<size_t>(0);
static const size_t kMaxSignedSize = ((size_t(1) << (kSizeBits-1)) - 1);
static const size_t kNotTooBig = 100000;
-static const size_t kTooBig = kMaxSize;
+// We want an allocation that is definitely more than main memory. OS
+// X has special logic to discard very big allocs before even passing
+// the request along to the user-defined memory allocator; we're not
+// interested in testing their logic, so we have to make sure we're
+// not *too* big.
+static const size_t kTooBig = kMaxSize - 100000;
static int news_handled = 0;
@@ -246,16 +280,18 @@ int TestHarness::PickType() {
class AllocatorState : public TestHarness {
public:
- explicit AllocatorState(int seed) : TestHarness(seed) {
- CHECK_GE(FLAGS_memalign_max_fraction, 0);
- CHECK_LE(FLAGS_memalign_max_fraction, 1);
- CHECK_GE(FLAGS_memalign_min_fraction, 0);
- CHECK_LE(FLAGS_memalign_min_fraction, 1);
- double delta = FLAGS_memalign_max_fraction - FLAGS_memalign_min_fraction;
- CHECK_GE(delta, 0);
- memalign_fraction_ = (Uniform(10000)/10000.0 * delta +
- FLAGS_memalign_min_fraction);
- //fprintf(LOGSTREAM, "memalign fraction: %f\n", memalign_fraction_);
+ explicit AllocatorState(int seed) : TestHarness(seed), memalign_fraction_(0) {
+ if (kOSSupportsMemalign) {
+ CHECK_GE(FLAGS_memalign_max_fraction, 0);
+ CHECK_LE(FLAGS_memalign_max_fraction, 1);
+ CHECK_GE(FLAGS_memalign_min_fraction, 0);
+ CHECK_LE(FLAGS_memalign_min_fraction, 1);
+ double delta = FLAGS_memalign_max_fraction - FLAGS_memalign_min_fraction;
+ CHECK_GE(delta, 0);
+ memalign_fraction_ = (Uniform(10000)/10000.0 * delta +
+ FLAGS_memalign_min_fraction);
+ //fprintf(LOGSTREAM, "memalign fraction: %f\n", memalign_fraction_);
+ }
}
virtual ~AllocatorState() {}
@@ -269,7 +305,7 @@ class AllocatorState : public TestHarness {
(size < sizeof(intptr_t) ||
alignment < FLAGS_memalign_max_alignment_ratio * size)) {
void *result = reinterpret_cast<void*>(static_cast<intptr_t>(0x1234));
- int err = posix_memalign(&result, alignment, size);
+ int err = PosixMemalign(&result, alignment, size);
if (err != 0) {
CHECK_EQ(err, ENOMEM);
}
@@ -891,44 +927,42 @@ static void OnNoMemory() {
static void TestSetNewMode() {
int old_mode = tc_set_new_mode(1);
- // DebugAllocation will try to catch huge allocations. We need to avoid this
- // by requesting a smaller malloc block, that still can't be satisfied.
- const size_t kHugeRequest = kTooBig - 1024;
-
- g_old_handler = std::set_new_handler(&OnNoMemory);
- g_no_memory = false;
- void* ret = malloc(kHugeRequest);
- EXPECT_EQ(NULL, ret);
- EXPECT_TRUE(g_no_memory);
-
g_old_handler = std::set_new_handler(&OnNoMemory);
g_no_memory = false;
- ret = calloc(1, kHugeRequest);
+ void* ret = malloc(kTooBig);
EXPECT_EQ(NULL, ret);
EXPECT_TRUE(g_no_memory);
g_old_handler = std::set_new_handler(&OnNoMemory);
g_no_memory = false;
- ret = realloc(NULL, kHugeRequest);
+ ret = calloc(1, kTooBig);
EXPECT_EQ(NULL, ret);
EXPECT_TRUE(g_no_memory);
- // Not really important, but must be small enough such that kAlignment +
- // kHugeRequest does not overflow.
- const int kAlignment = 1 << 5;
-
g_old_handler = std::set_new_handler(&OnNoMemory);
g_no_memory = false;
- ret = memalign(kAlignment, kHugeRequest);
+ ret = realloc(NULL, kTooBig);
EXPECT_EQ(NULL, ret);
EXPECT_TRUE(g_no_memory);
- g_old_handler = std::set_new_handler(&OnNoMemory);
- g_no_memory = false;
- EXPECT_EQ(ENOMEM,
- posix_memalign(&ret, kAlignment, kHugeRequest));
- EXPECT_EQ(NULL, ret);
- EXPECT_TRUE(g_no_memory);
+ if (kOSSupportsMemalign) {
+ // Not really important, but must be small enough such that
+ // kAlignment + kTooBig does not overflow.
+ const int kAlignment = 1 << 5;
+
+ g_old_handler = std::set_new_handler(&OnNoMemory);
+ g_no_memory = false;
+ ret = Memalign(kAlignment, kTooBig);
+ EXPECT_EQ(NULL, ret);
+ EXPECT_TRUE(g_no_memory);
+
+ g_old_handler = std::set_new_handler(&OnNoMemory);
+ g_no_memory = false;
+ EXPECT_EQ(ENOMEM,
+ PosixMemalign(&ret, kAlignment, kTooBig));
+ EXPECT_EQ(NULL, ret);
+ EXPECT_TRUE(g_no_memory);
+ }
tc_set_new_mode(old_mode);
}
@@ -1032,17 +1066,19 @@ static int RunAllTests(int argc, char** argv) {
cfree(p1); // synonym for free
VerifyDeleteHookWasCalled();
- CHECK_EQ(posix_memalign(&p1, sizeof(p1), 40), 0);
- CHECK(p1 != NULL);
- VerifyNewHookWasCalled();
- free(p1);
- VerifyDeleteHookWasCalled();
-
- p1 = memalign(sizeof(p1) * 2, 50);
- CHECK(p1 != NULL);
- VerifyNewHookWasCalled();
- free(p1);
- VerifyDeleteHookWasCalled();
+ if (kOSSupportsMemalign) {
+ CHECK_EQ(PosixMemalign(&p1, sizeof(p1), 40), 0);
+ CHECK(p1 != NULL);
+ VerifyNewHookWasCalled();
+ free(p1);
+ VerifyDeleteHookWasCalled();
+
+ p1 = Memalign(sizeof(p1) * 2, 50);
+ CHECK(p1 != NULL);
+ VerifyNewHookWasCalled();
+ free(p1);
+ VerifyDeleteHookWasCalled();
+ }
// Windows has _aligned_malloc. Let's test that that's captured too.
#if (defined(_MSC_VER) || defined(__MINGW32__)) && !defined(PERFTOOLS_NO_ALIGNED_MALLOC)
diff --git a/src/thread_cache.cc b/src/thread_cache.cc
index b00e3b4..c228c0f 100644
--- a/src/thread_cache.cc
+++ b/src/thread_cache.cc
@@ -46,8 +46,9 @@ DEFINE_int64(tcmalloc_max_total_thread_cache_bytes,
EnvToInt64("TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES",
kDefaultOverallThreadCacheSize),
"Bound on the total amount of bytes allocated to "
- "thread caches. This bound is not strict, so it is possible "
- "for the cache to go over this bound in certain circumstances. ");
+ "thread caches. This bound is not strict, so it is possible "
+ "for the cache to go over this bound in certain circumstances. "
+ "Maximum value of this flag is capped to 1 GB.");
namespace tcmalloc {
@@ -72,7 +73,11 @@ pthread_key_t ThreadCache::heap_key_;
#if defined(HAVE_TLS)
bool kernel_supports_tls = false; // be conservative
-# if !HAVE_DECL_UNAME // if too old for uname, probably too old for TLS
+# if defined(_WIN32) // windows has supported TLS since winnt, I think.
+ void CheckIfKernelSupportsTLS() {
+ kernel_supports_tls = true;
+ }
+# elif !HAVE_DECL_UNAME // if too old for uname, probably too old for TLS
void CheckIfKernelSupportsTLS() {
kernel_supports_tls = false;
}
@@ -313,6 +318,18 @@ void ThreadCache::InitTSD() {
ASSERT(!tsd_inited_);
perftools_pthread_key_create(&heap_key_, DestroyThreadCache);
tsd_inited_ = true;
+
+#ifdef PTHREADS_CRASHES_IF_RUN_TOO_EARLY
+ // We may have used a fake pthread_t for the main thread. Fix it.
+ pthread_t zero;
+ memset(&zero, 0, sizeof(zero));
+ SpinLockHolder h(Static::pageheap_lock());
+ for (ThreadCache* h = thread_heaps_; h != NULL; h = h->next_) {
+ if (h->tid_ == zero) {
+ h->tid_ = pthread_self();
+ }
+ }
+#endif
}
ThreadCache* ThreadCache::CreateCacheIfNecessary() {
@@ -320,17 +337,23 @@ ThreadCache* ThreadCache::CreateCacheIfNecessary() {
ThreadCache* heap = NULL;
{
SpinLockHolder h(Static::pageheap_lock());
- // On very old libc's, this call may crash if it happens too
- // early. No libc using NPTL should be affected. If there
- // is a crash here, we could use code (on linux, at least)
- // to detect NPTL vs LinuxThreads:
- // http://www.redhat.com/archives/phil-list/2003-April/msg00038.html
- // If we detect not-NPTL, we could execute the old code from
- // http://google-perftools.googlecode.com/svn/tags/google-perftools-1.7/src/thread_cache.cc
- // that avoids calling pthread_self too early. The problem with
- // that code is it caused a race condition when tcmalloc is linked
- // in statically and other libraries spawn threads before main.
+ // On some old glibc's, and on freebsd's libc (as of freebsd 8.1),
+ // calling pthread routines (even pthread_self) too early could
+ // cause a segfault. Since we can call pthreads quite early, we
+ // have to protect against that in such situations by making a
+ // 'fake' pthread. This is not ideal since it doesn't work well
+ // when linking tcmalloc statically with apps that create threads
+ // before main, so we only do it if we have to.
+#ifdef PTHREADS_CRASHES_IF_RUN_TOO_EARLY
+ pthread_t me;
+ if (!tsd_inited_) {
+ memset(&me, 0, sizeof(me));
+ } else {
+ me = pthread_self();
+ }
+#else
const pthread_t me = pthread_self();
+#endif
// This may be a recursive malloc call from pthread_setspecific()
// In that case, the heap for this thread has already been created
@@ -474,7 +497,7 @@ void ThreadCache::PrintThreads(TCMalloc_Printer* out) {
h->Print(out);
actual_limit += h->max_size_;
}
- out->printf("ThreadCache overall: %"PRIuS ", unclaimed: %"PRIuS
+ out->printf("ThreadCache overall: %"PRIuS ", unclaimed: %"PRIdS
", actual: %"PRIuS"\n",
overall_thread_cache_size_, unclaimed_cache_space_, actual_limit);
}
diff --git a/src/windows/config.h b/src/windows/config.h
index 1d93c4f..7a7a8d7 100644
--- a/src/windows/config.h
+++ b/src/windows/config.h
@@ -94,6 +94,9 @@
/* Define to 1 if you have the <malloc.h> header file. */
#define HAVE_MALLOC_H 1
+/* Define to 1 if you have the <malloc/malloc.h> header file. */
+#undef HAVE_MALLOC_MALLOC_H
+
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
@@ -136,6 +139,12 @@
/* Define to 1 if the system has the type `struct mallinfo'. */
#undef HAVE_STRUCT_MALLINFO
+/* Define to 1 if you have the <sys/cdefs.h> header file. */
+#undef HAVE_SYS_CDEFS_H
+
+/* Define to 1 if you have the <sys/malloc.h> header file. */
+#undef HAVE_SYS_MALLOC_H
+
/* Define to 1 if you have the <sys/param.h> header file. */
#undef HAVE_SYS_PARAM_H
@@ -197,6 +206,9 @@
*/
#undef LT_OBJDIR
+/* Define to 'volatile' if __malloc_hook is declared volatile */
+#undef MALLOC_HOOK_MAYBE_VOLATILE
+
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
#undef NO_MINUS_C_MINUS_O
@@ -210,7 +222,7 @@
#define PACKAGE_NAME "google-perftools"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "google-perftools 1.7"
+#define PACKAGE_STRING "google-perftools 1.8"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "google-perftools"
@@ -219,7 +231,7 @@
#undef PACKAGE_URL
/* Define to the version of this package. */
-#define PACKAGE_VERSION "1.7"
+#define PACKAGE_VERSION "1.8"
/* How to access the PC from a struct ucontext */
#undef PC_FROM_UCONTEXT
@@ -244,6 +256,12 @@
/* printf format code for printing a size_t and ssize_t */
#define PRIxS "Ix"
+/* Mark the systems where we know it's bad if pthreads runs too
+ early before main (before threads are initialized, presumably). */
+#ifdef __FreeBSD__
+#define PTHREADS_CRASHES_IF_RUN_TOO_EARLY 1
+#endif
+
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#undef PTHREAD_CREATE_JOINABLE
diff --git a/src/windows/google/tcmalloc.h.in b/src/windows/google/tcmalloc.h.in
index a031b35..0b53e4e 100644
--- a/src/windows/google/tcmalloc.h.in
+++ b/src/windows/google/tcmalloc.h.in
@@ -35,6 +35,11 @@
#ifndef TCMALLOC_TCMALLOC_H_
#define TCMALLOC_TCMALLOC_H_
+#include <stddef.h> // for size_t
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h> // where glibc defines __THROW
+#endif
+
// __THROW is defined in glibc systems. It means, counter-intuitively,
// "This function will never throw an exception." It's an optional
// optimization tool, but we may need to use it to match glibc prototypes.
@@ -60,7 +65,9 @@
#endif
#ifdef __cplusplus
-#include <new> // for std::nothrow_t
+namespace std {
+struct nothrow_t;
+}
extern "C" {
#endif
diff --git a/src/windows/mingw.h b/src/windows/mingw.h
index 747b285..2aa5eb3 100644
--- a/src/windows/mingw.h
+++ b/src/windows/mingw.h
@@ -53,8 +53,6 @@
# define _WIN32_WINNT 0x0501
#endif
-#include "windows/port.h"
-
#define HAVE_SNPRINTF 1
// Some mingw distributions have a pthreads wrapper, but it doesn't
@@ -62,6 +60,8 @@
// pretend the pthreads wrapper doesn't exist, even when it does.
#undef HAVE_PTHREAD
+#include "windows/port.h"
+
#endif /* __MINGW32__ */
#endif /* GOOGLE_PERFTOOLS_WINDOWS_MINGW_H_ */
diff --git a/src/windows/port.cc b/src/windows/port.cc
index 1ecdace..e68de16 100644
--- a/src/windows/port.cc
+++ b/src/windows/port.cc
@@ -44,6 +44,7 @@
#include "port.h"
#include "base/logging.h"
#include "base/spinlock.h"
+#include "internal_logging.h"
#include "system-alloc.h"
// -----------------------------------------------------------------------
@@ -265,6 +266,9 @@ void DumpSystemAllocatorStats(TCMalloc_Printer* printer) {
// We don't dump stats on windows, right now
}
+// The current system allocator
+SysAllocator* sys_alloc = NULL;
+
// -----------------------------------------------------------------------
// These functions rework existing functions of the same name in the
diff --git a/src/windows/port.h b/src/windows/port.h
index 0faba01..300c72d 100644
--- a/src/windows/port.h
+++ b/src/windows/port.h
@@ -165,6 +165,10 @@ EXTERN_C int perftools_pthread_once(pthread_once_t *once_control,
#endif /* __cplusplus */
#endif /* HAVE_PTHREAD */
+inline void sched_yield(void) {
+ Sleep(0);
+}
+
/*
* __declspec(thread) isn't usable in a dll opened via LoadLibrary().
* But it doesn't work to LoadLibrary() us anyway, because of all the
@@ -260,7 +264,7 @@ class SpinLockHolder { // Acquires a spinlock for as long as the scope lasts
#define MAP_PRIVATE MEM_COMMIT
#define MAP_SHARED MEM_RESERVE /* value of this #define is 100% arbitrary */
-#if __STDC__
+#if __STDC__ && !defined(__MINGW32__)
typedef _off_t off_t;
#endif
@@ -372,7 +376,6 @@ inline char *getcwd(char *buf, size_t size) {
inline int mkdir(const char *pathname, int) {
return _mkdir(pathname);
}
-#endif
inline FILE *popen(const char *command, const char *type) {
return _popen(command, type);
@@ -380,13 +383,14 @@ inline FILE *popen(const char *command, const char *type) {
inline int pclose(FILE *stream) {
return _pclose(stream);
}
+#endif
EXTERN_C PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len);
/* ----------------------------------- SYSTEM/PROCESS */
typedef int pid_t;
-#if __STDC__
+#if __STDC__ && !defined(__MINGW32__)
inline pid_t getpid(void) { return _getpid(); }
#endif
inline pid_t getppid(void) { return 0; }
diff --git a/vsprojects/current_allocated_bytes_test/current_allocated_bytes_test.vcproj b/vsprojects/current_allocated_bytes_test/current_allocated_bytes_test.vcproj
index 1ec974d..679eaf2 100755
--- a/vsprojects/current_allocated_bytes_test/current_allocated_bytes_test.vcproj
+++ b/vsprojects/current_allocated_bytes_test/current_allocated_bytes_test.vcproj
@@ -129,6 +129,7 @@
RuntimeLibrary="2"/>
</FileConfiguration>
</File>
+ </Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
diff --git a/vsprojects/malloc_hook_test/malloc_hook_test.vcproj b/vsprojects/malloc_hook_test/malloc_hook_test.vcproj
index 4afe5b6..95be16b 100755
--- a/vsprojects/malloc_hook_test/malloc_hook_test.vcproj
+++ b/vsprojects/malloc_hook_test/malloc_hook_test.vcproj
@@ -127,7 +127,6 @@
RuntimeLibrary="2"/>
</FileConfiguration>
</File>
- </Filter>
<File
RelativePath="..\..\src\tests\testutil.cc">
<FileConfiguration