[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [heaptrack/inject] /: Add -p/--pid option to attach heaptrack to a running process.
From: Milian Wolff <mail () milianw ! de>
Date: 2014-12-09 0:17:12
Message-ID: E1Xy8UK-0005KF-7W () scm ! kde ! org
[Download RAW message or body]
Git commit 2c3eb0da70a138971752e7424d5e82026445fe44 by Milian Wolff.
Committed on 09/12/2014 at 00:13.
Pushed by mwolff into branch 'inject'.
Add -p/--pid option to attach heaptrack to a running process.
We use gdb to attach to the process, then call dlopen there and
finally an initialization hook in the new libheaptrack_inject.so.
To prevent an underflow in the total memory consumption, we
call malloc_info and parse that in heaptrack_interpret to get a
baseline for the current total memory consumption at the point
where we attached to the process.
The code is refactored into a shared libheaptrack.cpp with common
code, and two libraries, libheaptrack_inject.so and the old
libheaptrack_preload.so. The heaptrack bash script is adapted to
support both versions.
M +7 -8 CMakeLists.txt
M +45 -10 heaptrack.sh.cmake
M +20 -11 heaptrack_inject.cpp
M +20 -0 heaptrack_interpret.cpp
A +277 -0 heaptrack_preload.cpp [License: LGPL (v2+)]
M +16 -2 heaptrack_print.cpp
M +20 -241 libheaptrack.cpp
M +2 -1 libheaptrack.h
http://commits.kde.org/heaptrack/2c3eb0da70a138971752e7424d5e82026445fe44
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 627ac80..4eba06b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -46,12 +46,10 @@ include_directories(
${LIBUNWIND_INCLUDE_DIR}
)
-add_library(libheaptrack SHARED libheaptrack.cpp)
-# the final .so should be named libheaptrack, not liblibheaptrack
-set_target_properties(libheaptrack PROPERTIES OUTPUT_NAME heaptrack)
-target_link_libraries(libheaptrack ${CMAKE_DL_LIBS} backtrace rt)
-add_library(heaptrackinject SHARED heaptrack_inject.cpp)
-target_link_libraries(heaptrackinject PRIVATE libheaptrack)
+add_library(heaptrack_preload MODULE heaptrack_preload.cpp libheaptrack.cpp)
+target_link_libraries(heaptrack_preload PRIVATE ${CMAKE_DL_LIBS} backtrace rt)
+add_library(heaptrack_inject MODULE heaptrack_inject.cpp libheaptrack.cpp)
+target_link_libraries(heaptrack_inject PRIVATE ${CMAKE_DL_LIBS} backtrace rt)
add_executable(heaptrack_interpret heaptrack_interpret.cpp)
target_link_libraries(heaptrack_interpret backtrace)
@@ -70,11 +68,12 @@ file(RELATIVE_PATH LIBEXEC_REL_PATH
file(RELATIVE_PATH LIB_REL_PATH
"${CMAKE_INSTALL_PREFIX}/${BIN_INSTALL_DIR}"
- "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}")
+ "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}/heaptrack")
configure_file(heaptrack.sh.cmake ${CMAKE_CURRENT_BINARY_DIR}/heaptrack @ONLY)
install(TARGETS heaptrack_print RUNTIME DESTINATION ${BIN_INSTALL_DIR})
install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/heaptrack DESTINATION \
${BIN_INSTALL_DIR})
-install(TARGETS libheaptrack LIBRARY DESTINATION ${LIB_INSTALL_DIR})
install(TARGETS heaptrack_interpret RUNTIME DESTINATION ${LIBEXEC_INSTALL_DIR})
+install(TARGETS heaptrack_inject LIBRARY DESTINATION ${LIB_INSTALL_DIR}/heaptrack/)
+install(TARGETS heaptrack_preload LIBRARY DESTINATION ${LIB_INSTALL_DIR}/heaptrack/)
diff --git a/heaptrack.sh.cmake b/heaptrack.sh.cmake
index 4ad5d76..789ddda 100755
--- a/heaptrack.sh.cmake
+++ b/heaptrack.sh.cmake
@@ -47,6 +47,7 @@ usage() {
}
debug=
+pid=
client=
clientargs=
@@ -62,6 +63,26 @@ while true; do
usage
exit 0
;;
+ "-p") ;&
+ "--pid")
+ pid=$2
+ if [ -z "$pid" ]; then
+ echo "Missing PID argument."
+ exit 1
+ fi
+ client=$(ps --no-headers -c -o comm -p $pid)
+ if [ -z "$client" ]; then
+ echo "Cannot attach to unknown process with PID $pid."
+ exit 1
+ fi
+ shift 2
+ echo $@
+ if [ ! -z "$@" ]; then
+ echo "You cannot specify a debuggee and a pid at the same time."
+ exit 1
+ fi
+ break
+ ;;
*)
if [ ! -x "$(which $1 2> /dev/null)" ]; then
echo "Error: Debuggee \"$1\" is not an executable."
@@ -72,7 +93,7 @@ while true; do
client="$1"
shift 1
clientargs="$@"
- break;
+ break
;;
esac
done
@@ -92,12 +113,19 @@ if [ ! -f "$INTERPRETER" ]; then
fi
INTERPRETER=$(readlink -f "$INTERPRETER")
-LIBHEAPTRACK="$EXE_PATH/$LIB_REL_PATH/libheaptrack.so"
-if [ ! -f "$LIBHEAPTRACK" ]; then
- echo "Could not find heaptrack preload library$LIBHEAPTRACK"
+LIBHEAPTRACK_PRELOAD="$EXE_PATH/$LIB_REL_PATH/libheaptrack_preload.so"
+if [ ! -f "$LIBHEAPTRACK_PRELOAD" ]; then
+ echo "Could not find heaptrack preload library $LIBHEAPTRACK_PRELOAD"
+ exit 1
+fi
+LIBHEAPTRACK_PRELOAD=$(readlink -f "$LIBHEAPTRACK_PRELOAD")
+
+LIBHEAPTRACK_INJECT="$EXE_PATH/$LIB_REL_PATH/libheaptrack_inject.so"
+if [ ! -f "$LIBHEAPTRACK_INJECT" ]; then
+ echo "Could not find heaptrack inject library $LIBHEAPTRACK_INJECT"
exit 1
fi
-LIBHEAPTRACK=$(readlink -f "$LIBHEAPTRACK")
+LIBHEAPTRACK_INJECT=$(readlink -f "$LIBHEAPTRACK_INJECT")
# setup named pipe to read data from
pipe=/tmp/heaptrack_fifo$$
@@ -112,12 +140,19 @@ debuggee=$!
echo "starting application, this might take some time..."
echo "output will be written to $output"
-if [ -z "$debug" ]; then
- LD_PRELOAD=$LIBHEAPTRACK DUMP_HEAPTRACK_OUTPUT="$pipe" $client $clientargs
+if [ -z "$debug" ] && [ -z "$pid" ]; then
+ LD_PRELOAD=$LIBHEAPTRACK_PRELOAD DUMP_HEAPTRACK_OUTPUT="$pipe" $client $clientargs
else
- gdb --eval-command="set environment LD_PRELOAD=$LIBHEAPTRACK" \
- --eval-command="set environment DUMP_HEAPTRACK_OUTPUT=$pipe" \
- --eval-command="run" --args $client $clientargs
+ if [ -z "$pid" ]; then
+ gdb --eval-command="set environment LD_PRELOAD=$LIBHEAPTRACK_PRELOAD" \
+ --eval-command="set environment DUMP_HEAPTRACK_OUTPUT=$pipe" \
+ --eval-command="run" --args $client $clientargs
+ else
+ gdb -p $pid \
+ --eval-command="call (void) dlopen(\"$LIBHEAPTRACK_INJECT\", 0x002)" \
+ --eval-command="call (void) init_heaptrack_inject(\"$pipe\")" \
+ --eval-command="detach" --eval-command="quit"
+ fi
fi
wait $debuggee
diff --git a/heaptrack_inject.cpp b/heaptrack_inject.cpp
index bccba2d..8f54613 100644
--- a/heaptrack_inject.cpp
+++ b/heaptrack_inject.cpp
@@ -20,9 +20,10 @@
#include "libheaptrack.h"
#include <link.h>
-#include <string.h>
-#include <stdlib.h>
+#include <cstring>
+#include <cstdlib>
#include <sys/mman.h>
+#include <malloc.h>
#include <type_traits>
@@ -155,7 +156,8 @@ struct hook
{
static_assert(sizeof(&Hook::hook) == sizeof(void*), "Mismatched pointer \
sizes");
static_assert(std::is_convertible<decltype(&Hook::hook), \
decltype(Hook::original)>::value,
- "hook is not compatible to original function");
+ "hook is not compatible to original function");
+ static_assert(&Hook::hook != Hook::original, "Recursion detected");
// TODO: why is (void*) cast allowed, but not reinterpret_cast?
return {Hook::name, (void*)(&Hook::hook)};
}
@@ -228,8 +230,8 @@ void try_overwrite_symbols(const ElfW(Dyn) *dyn, const ElfW(Addr) \
base)
int iterate_phdrs(dl_phdr_info *info, size_t /*size*/, void *data)
{
- if (strstr(info->dlpi_name, "/libheaptrackinject.so")) {
- // do not
+ if (strstr(info->dlpi_name, "/libheaptrack_inject.so")) {
+ // prevent infinite recursion: do not overwrite our own symbols
return 0;
}
@@ -242,13 +244,20 @@ int iterate_phdrs(dl_phdr_info *info, size_t /*size*/, void \
*data) return 0;
}
-struct InitializeInjection
+}
+
+extern "C" {
+
+void init_heaptrack_inject(const char *outputFileName)
{
- InitializeInjection()
- {
+ heaptrack_init(outputFileName, [] () {
dl_iterate_phdr(&iterate_phdrs, nullptr);
- heaptrack_init();
- }
-} initialize;
+ }, [] () {
+ auto out = heaptrack_output_file();
+ fprintf(out, "A BEGIN_MALLOC_INFO\n");
+ malloc_info(0, out);
+ fprintf(out, "\nA END_MALLOC_INFO\n");
+ });
+}
}
diff --git a/heaptrack_interpret.cpp b/heaptrack_interpret.cpp
index 3a4a8e4..fde77ec 100644
--- a/heaptrack_interpret.cpp
+++ b/heaptrack_interpret.cpp
@@ -24,6 +24,7 @@
*/
#include <iostream>
+#include <sstream>
#include <unordered_map>
#include <vector>
#include <tuple>
@@ -31,7 +32,10 @@
#include <stdio_ext.h>
#include <cxxabi.h>
+
#include <boost/algorithm/string/predicate.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+#include <boost/property_tree/ptree.hpp>
#include "libbacktrace/backtrace.h"
#include "linereader.h"
@@ -378,6 +382,22 @@ int main(int /*argc*/, char** /*argv*/)
const auto ipId = data.addIp(instructionPointer);
// trace point, map current output index to parent index
fprintf(stdout, "t %lx %lx\n", ipId, parentIndex);
+ } else if (reader.mode() == 'A') {
+ // we attached, and now have to parse the malloc_info to get some \
baseline + stringstream xml;
+ while (reader.getLine(cin) && reader.mode() != 'A') {
+ xml << reader.line();
+ }
+ boost::property_tree::ptree pt;
+ boost::property_tree::read_xml(xml, pt);
+ size_t current = 0;
+ for (const auto& element : pt.get_child("malloc")) {
+ if (element.first == "system" && \
element.second.get<string>("<xmlattr>.type") == "current") { + \
current = element.second.get<size_t>("<xmlattr>.size"); + break;
+ }
+ }
+ fprintf(stdout, "A %lx\n", current);
} else {
fputs(reader.line().c_str(), stdout);
fputc('\n', stdout);
diff --git a/heaptrack_preload.cpp b/heaptrack_preload.cpp
new file mode 100644
index 0000000..d151d11
--- /dev/null
+++ b/heaptrack_preload.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2014 Milian Wolff <mail@milianw.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "libheaptrack.h"
+
+#include <dlfcn.h>
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+
+#include <type_traits>
+#include <atomic>
+
+using namespace std;
+
+namespace {
+
+namespace hooks {
+
+template<typename SignatureT>
+struct hook
+{
+ hook(const char* const name)
+ : name(name)
+ {}
+
+ using Signature = SignatureT*;
+ Signature original = nullptr;
+
+ const char * const name;
+ void init()
+ {
+ auto ret = dlsym(RTLD_NEXT, name);
+ if (!ret) {
+ fprintf(stderr, "Could not find original function %s\n", name);
+ abort();
+ }
+ original = reinterpret_cast<Signature>(ret);
+ }
+
+ template<typename... Args>
+ auto operator() (Args... args) const -> decltype(original(args...))
+ {
+ return original(args...);
+ }
+
+ explicit operator bool () const
+ {
+ return original;
+ }
+};
+
+hook<decltype(::malloc)> malloc{"malloc"};
+hook<decltype(::free)> free{"free"};
+hook<decltype(::calloc)> calloc{"calloc"};
+hook<decltype(::cfree)> cfree{"cfree"};
+hook<decltype(::realloc)> realloc{"realloc"};
+hook<decltype(::posix_memalign)> posix_memalign{"posix_memalign"};
+hook<decltype(::valloc)> valloc{"valloc"};
+hook<decltype(::aligned_alloc)> aligned_alloc{"aligned_alloc"};
+hook<decltype(::dlopen)> dlopen{"dlopen"};
+hook<decltype(::dlclose)> dlclose{"dlclose"};
+
+/**
+ * Dummy implementation, since the call to dlsym from findReal triggers a call to \
calloc. + *
+ * This is only called at startup and will eventually be replaced by the "proper" \
calloc implementation. + */
+void* dummy_calloc(size_t num, size_t size)
+{
+ const size_t MAX_SIZE = 1024;
+ static char* buf[MAX_SIZE];
+ static size_t offset = 0;
+ if (!offset) {
+ memset(buf, 0, MAX_SIZE);
+ }
+ size_t oldOffset = offset;
+ offset += num * size;
+ if (offset >= MAX_SIZE) {
+ fprintf(stderr, "failed to initialize, dummy calloc buf size exhausted: %lu \
requested, %lu available\n", offset, MAX_SIZE); + abort();
+ }
+ return buf + oldOffset;
+}
+
+void init()
+{
+ heaptrack_init(getenv("DUMP_HEAPTRACK_OUTPUT"), [] {
+ hooks::calloc.original = &dummy_calloc;
+ hooks::calloc.init();
+ hooks::dlopen.init();
+ hooks::dlclose.init();
+ hooks::malloc.init();
+ hooks::free.init();
+ hooks::calloc.init();
+ hooks::cfree.init();
+ hooks::realloc.init();
+ hooks::posix_memalign.init();
+ hooks::valloc.init();
+ hooks::aligned_alloc.init();
+
+ // cleanup environment to prevent tracing of child apps
+ unsetenv("LD_PRELOAD");
+ }, nullptr);
+}
+
+}
+
+}
+
+extern "C" {
+
+/// TODO: memalign, pvalloc, ...?
+
+void* malloc(size_t size)
+{
+ if (!hooks::malloc) {
+ hooks::init();
+ }
+
+ void* ptr = hooks::malloc(size);
+ heaptrack_malloc(ptr, size);
+ return ptr;
+}
+
+void free(void* ptr)
+{
+ if (!hooks::free) {
+ hooks::init();
+ }
+
+ // call handler before handing over the real free implementation
+ // to ensure the ptr is not reused in-between and thus the output
+ // stays consistent
+ heaptrack_free(ptr);
+
+ hooks::free(ptr);
+}
+
+void* realloc(void* ptr, size_t size)
+{
+ if (!hooks::realloc) {
+ hooks::init();
+ }
+
+ void* ret = hooks::realloc(ptr, size);
+
+ if (ret) {
+ heaptrack_realloc(ptr, size, ret);
+ }
+
+ return ret;
+}
+
+void* calloc(size_t num, size_t size)
+{
+ if (!hooks::calloc) {
+ hooks::init();
+ }
+
+ void* ret = hooks::calloc(num, size);
+
+ if (ret) {
+ heaptrack_malloc(ret, num * size);
+ }
+
+ return ret;
+}
+
+void cfree(void* ptr)
+{
+ if (!hooks::cfree) {
+ hooks::init();
+ }
+
+ // call handler before handing over the real free implementation
+ // to ensure the ptr is not reused in-between and thus the output
+ // stays consistent
+ if (ptr) {
+ heaptrack_free(ptr);
+ }
+
+ hooks::cfree(ptr);
+}
+
+int posix_memalign(void **memptr, size_t alignment, size_t size)
+{
+ if (!hooks::posix_memalign) {
+ hooks::init();
+ }
+
+ int ret = hooks::posix_memalign(memptr, alignment, size);
+
+ if (!ret) {
+ heaptrack_malloc(*memptr, size);
+ }
+
+ return ret;
+}
+
+void* aligned_alloc(size_t alignment, size_t size)
+{
+ if (!hooks::aligned_alloc) {
+ hooks::init();
+ }
+
+ void* ret = hooks::aligned_alloc(alignment, size);
+
+ if (ret) {
+ heaptrack_malloc(ret, size);
+ }
+
+ return ret;
+}
+
+void* valloc(size_t size)
+{
+ if (!hooks::valloc) {
+ hooks::init();
+ }
+
+ void* ret = hooks::valloc(size);
+
+ if (ret) {
+ heaptrack_malloc(ret, size);
+ }
+
+ return ret;
+}
+
+void *dlopen(const char *filename, int flag)
+{
+ if (!hooks::dlopen) {
+ hooks::init();
+ }
+
+ void* ret = hooks::dlopen(filename, flag);
+
+ if (ret) {
+ heaptrack_invalidate_module_cache();
+ }
+
+ return ret;
+}
+
+int dlclose(void *handle)
+{
+ if (!hooks::dlclose) {
+ hooks::init();
+ }
+
+ int ret = hooks::dlclose(handle);
+
+ if (!ret) {
+ heaptrack_invalidate_module_cache();
+ }
+
+ return ret;
+}
+
+}
diff --git a/heaptrack_print.cpp b/heaptrack_print.cpp
index d91ba74..4d3d33b 100644
--- a/heaptrack_print.cpp
+++ b/heaptrack_print.cpp
@@ -503,7 +503,9 @@ struct AccumulatedTraceData
}
auto ip = activeAllocations.find(ptr);
if (ip == activeAllocations.end()) {
- cerr << "unknown pointer in line: " << reader.line() << endl;
+ if (!fromAttached) {
+ cerr << "unknown pointer in line: " << reader.line() << \
endl; + }
continue;
}
const auto info = ip->second;
@@ -511,7 +513,9 @@ struct AccumulatedTraceData
auto& allocation = findAllocation(info.traceIndex);
if (!allocation.allocations || allocation.leaked < info.size) {
- cerr << "inconsistent allocation info, underflowed allocations \
of " << info.traceIndex << endl; + if (!fromAttached) {
+ cerr << "inconsistent allocation info, underflowed \
allocations of " << info.traceIndex << endl; + }
allocation.leaked = 0;
allocation.allocations = 0;
} else {
@@ -537,6 +541,15 @@ struct AccumulatedTraceData
if (massifOut.is_open()) {
writeMassifHeader(reader.line().c_str() + 2);
}
+ } else if (reader.mode() == 'A') {
+ size_t current = 0;
+ if (!(reader >> current)) {
+ cerr << "Failed to read current size after attaching." << endl;
+ continue;
+ }
+ leaked = current;
+ peak = current;
+ fromAttached = true;
} else {
cerr << "failed to parse line: " << reader.line() << endl;
}
@@ -557,6 +570,7 @@ struct AccumulatedTraceData
bool shortenTemplates = false;
bool mergeBacktraces = true;
bool printHistogram = false;
+ bool fromAttached = false;
ofstream massifOut;
double massifThreshold = 1;
size_t massifDetailedFreq = 1;
diff --git a/libheaptrack.cpp b/libheaptrack.cpp
index 2c4e3be..c6f8c9c 100644
--- a/libheaptrack.cpp
+++ b/libheaptrack.cpp
@@ -29,7 +29,6 @@
#include <cstdlib>
#include <stdio_ext.h>
#include <fcntl.h>
-#include <dlfcn.h>
#include <link.h>
#include <atomic>
@@ -54,28 +53,6 @@ using namespace std;
namespace {
-using malloc_t = void* (*) (size_t);
-using free_t = void (*) (void*);
-using cfree_t = void (*) (void*);
-using realloc_t = void* (*) (void*, size_t);
-using calloc_t = void* (*) (size_t, size_t);
-using posix_memalign_t = int (*) (void **, size_t, size_t);
-using valloc_t = void* (*) (size_t);
-using aligned_alloc_t = void* (*) (size_t, size_t);
-using dlopen_t = void* (*) (const char*, int);
-using dlclose_t = int (*) (void*);
-
-malloc_t real_malloc = nullptr;
-free_t real_free = nullptr;
-cfree_t real_cfree = nullptr;
-realloc_t real_realloc = nullptr;
-calloc_t real_calloc = nullptr;
-posix_memalign_t real_posix_memalign = nullptr;
-valloc_t real_valloc = nullptr;
-aligned_alloc_t real_aligned_alloc = nullptr;
-dlopen_t real_dlopen = nullptr;
-dlclose_t real_dlclose = nullptr;
-
// threadsafe stuff
atomic<bool> moduleCacheDirty(true);
@@ -119,12 +96,6 @@ private:
thread_local bool HandleGuard::inHandler = false;
-string env(const char* variable)
-{
- const char* value = getenv(variable);
- return value ? string(value) : string();
-}
-
void writeExe(FILE* out)
{
const int BUF_SIZE = 1023;
@@ -160,11 +131,14 @@ void child_fork();
struct Data
{
- Data()
+ Data(const char *outputFileName_)
{
pthread_atfork(&prepare_fork, &parent_fork, &child_fork);
- string outputFileName = env("DUMP_HEAPTRACK_OUTPUT");
+ string outputFileName;
+ if (outputFileName_) {
+ outputFileName.assign(outputFileName_);
+ }
if (outputFileName.empty()) {
// env var might not be set when linked directly into an executable
outputFileName = "heaptrack.$$";
@@ -192,7 +166,6 @@ struct Data
// cleanup environment to prevent tracing of child apps
unsetenv("DUMP_HEAPTRACK_OUTPUT");
- unsetenv("LD_PRELOAD");
// print a backtrace in every interval
timer.setInterval(0, 1000 * 1000 * 10);
@@ -314,61 +287,23 @@ void child_fork()
HandleGuard::inHandler = true;
}
-template<typename T>
-T findReal(const char* name)
-{
- auto ret = dlsym(RTLD_NEXT, name);
- if (!ret) {
- fprintf(stderr, "Could not find original function %s\n", name);
- abort();
- }
- return reinterpret_cast<T>(ret);
}
+extern "C" {
-/**
- * Dummy implementation, since the call to dlsym from findReal triggers a call to \
calloc.
- *
- * This is only called at startup and will eventually be replaced by the "proper" \
calloc implementation.
- */
-void* dummy_calloc(size_t num, size_t size)
+void heaptrack_init(const char *outputFileName, void (*initCallbackBefore) (), void \
(*initCallbackAfter) ()) {
- const size_t MAX_SIZE = 1024;
- static char* buf[MAX_SIZE];
- static size_t offset = 0;
- if (!offset) {
- memset(buf, 0, MAX_SIZE);
- }
- size_t oldOffset = offset;
- offset += num * size;
- if (offset >= MAX_SIZE) {
- fprintf(stderr, "failed to initialize, dummy calloc buf size exhausted: %lu \
requested, %lu available\n", offset, MAX_SIZE);
- abort();
- }
- return buf + oldOffset;
-}
+ HandleGuard guard;
-void init()
-{
static once_flag once;
- call_once(once, [] {
- if (data || HandleGuard::inHandler) {
+ call_once(once, [=] {
+ if (data) {
fprintf(stderr, "initialization recursion detected\n");
abort();
}
- HandleGuard guard;
-
- real_calloc = &dummy_calloc;
- real_calloc = findReal<calloc_t>("calloc");
- real_dlopen = findReal<dlopen_t>("dlopen");
- real_dlclose = findReal<dlclose_t>("dlclose");
- real_malloc = findReal<malloc_t>("malloc");
- real_free = findReal<free_t>("free");
- real_cfree = findReal<cfree_t>("cfree");
- real_realloc = findReal<realloc_t>("realloc");
- real_posix_memalign = findReal<posix_memalign_t>("posix_memalign");
- real_valloc = findReal<valloc_t>("valloc");
- real_aligned_alloc = findReal<aligned_alloc_t>("aligned_alloc");
+ if (initCallbackBefore) {
+ initCallbackBefore();
+ }
if (unw_set_caching_policy(unw_local_addr_space, UNW_CACHE_PER_THREAD)) {
fprintf(stderr, "Failed to enable per-thread libunwind caching.\n");
@@ -377,16 +312,17 @@ void init()
fprintf(stderr, "Failed to set libunwind cache size.\n");
}
- data.reset(new Data);
- });
-}
+ data.reset(new Data(outputFileName));
+ if (initCallbackAfter) {
+ initCallbackAfter();
+ }
+ });
}
-extern "C" {
-void heaptrack_init()
+FILE* heaptrack_output_file()
{
- init();
+ return data ? data->out : nullptr;
}
void heaptrack_malloc(void* ptr, size_t size)
@@ -421,161 +357,4 @@ void heaptrack_invalidate_module_cache()
moduleCacheDirty = true;
}
-/// TODO: memalign, pvalloc, ...?
-
-void* malloc(size_t size)
-{
- if (!real_malloc) {
- init();
- }
-
- void* ptr = real_malloc(size);
- heaptrack_malloc(ptr, size);
- return ptr;
-}
-
-void free(void* ptr)
-{
- if (!real_free) {
- init();
- }
-
- // call handler before handing over the real free implementation
- // to ensure the ptr is not reused in-between and thus the output
- // stays consistent
- heaptrack_free(ptr);
-
- real_free(ptr);
-}
-
-void* realloc(void* ptr, size_t size)
-{
- if (!real_realloc) {
- init();
- }
-
- void* ret = real_realloc(ptr, size);
-
- if (ret && !HandleGuard::inHandler && data) {
- HandleGuard guard;
- if (ptr) {
- data->handleFree(ptr);
- }
- data->handleMalloc(ret, size);
- }
-
- return ret;
-}
-
-void* calloc(size_t num, size_t size)
-{
- if (!real_calloc) {
- init();
- }
-
- void* ret = real_calloc(num, size);
-
- if (ret && !HandleGuard::inHandler && data) {
- HandleGuard guard;
- data->handleMalloc(ret, num*size);
- }
-
- return ret;
-}
-
-void cfree(void* ptr)
-{
- if (!real_cfree) {
- init();
- }
-
- // call handler before handing over the real free implementation
- // to ensure the ptr is not reused in-between and thus the output
- // stays consistent
- if (ptr && !HandleGuard::inHandler && data) {
- HandleGuard guard;
- data->handleFree(ptr);
- }
-
- real_cfree(ptr);
-}
-
-int posix_memalign(void **memptr, size_t alignment, size_t size)
-{
- if (!real_posix_memalign) {
- init();
- }
-
- int ret = real_posix_memalign(memptr, alignment, size);
-
- if (!ret && !HandleGuard::inHandler && data) {
- HandleGuard guard;
- data->handleMalloc(*memptr, size);
- }
-
- return ret;
-}
-
-void* aligned_alloc(size_t alignment, size_t size)
-{
- if (!real_aligned_alloc) {
- init();
- }
-
- void* ret = real_aligned_alloc(alignment, size);
-
- if (ret && !HandleGuard::inHandler && data) {
- HandleGuard guard;
- data->handleMalloc(ret, size);
- }
-
- return ret;
-}
-
-void* valloc(size_t size)
-{
- if (!real_valloc) {
- init();
- }
-
- void* ret = real_valloc(size);
-
- if (ret && !HandleGuard::inHandler && data) {
- HandleGuard guard;
- data->handleMalloc(ret, size);
- }
-
- return ret;
-}
-
-void *dlopen(const char *filename, int flag)
-{
- if (!real_dlopen) {
- init();
- }
-
- void* ret = real_dlopen(filename, flag);
-
- if (ret) {
- moduleCacheDirty = true;
- }
-
- return ret;
-}
-
-int dlclose(void *handle)
-{
- if (!real_dlclose) {
- init();
- }
-
- int ret = real_dlclose(handle);
-
- if (!ret) {
- moduleCacheDirty = true;
- }
-
- return ret;
-}
-
}
diff --git a/libheaptrack.h b/libheaptrack.h
index 15075b0..605b23f 100644
--- a/libheaptrack.h
+++ b/libheaptrack.h
@@ -20,7 +20,8 @@
#include <cstdio>
extern "C" {
-void heaptrack_init();
+void heaptrack_init(const char *outputFileName, void (*initCallbackBefore) (), void \
(*initCallbackAfter) ()); +FILE* heaptrack_output_file();
void heaptrack_malloc(void *ptr, size_t size);
void heaptrack_free(void *ptr);
void heaptrack_realloc(void *ptr_in, size_t size, void *ptr_out);
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic