From: Milian Wolff Date: Tue, 9 Dec 2014 00:13:57 +0000 (+0100) Subject: Add -p/--pid option to attach heaptrack to a running process. X-Git-Tag: submit/tizen/20180620.112952^2~384^2~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2c3eb0da70a138971752e7424d5e82026445fe44;p=sdk%2Ftools%2Fheaptrack.git 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. --- 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 -#include -#include +#include +#include #include +#include #include @@ -155,7 +156,8 @@ struct hook { static_assert(sizeof(&Hook::hook) == sizeof(void*), "Mismatched pointer sizes"); static_assert(std::is_convertible::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 +#include #include #include #include @@ -31,7 +32,10 @@ #include #include + #include +#include +#include #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(".type") == "current") { + current = element.second.get(".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 + * + * 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 +#include +#include +#include + +#include +#include + +using namespace std; + +namespace { + +namespace hooks { + +template +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(ret); + } + + template + auto operator() (Args... args) const -> decltype(original(args...)) + { + return original(args...); + } + + explicit operator bool () const + { + return original; + } +}; + +hook malloc{"malloc"}; +hook free{"free"}; +hook calloc{"calloc"}; +hook cfree{"cfree"}; +hook realloc{"realloc"}; +hook posix_memalign{"posix_memalign"}; +hook valloc{"valloc"}; +hook aligned_alloc{"aligned_alloc"}; +hook dlopen{"dlopen"}; +hook 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 #include #include -#include #include #include @@ -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 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 -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(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"); - real_dlopen = findReal("dlopen"); - real_dlclose = findReal("dlclose"); - real_malloc = findReal("malloc"); - real_free = findReal("free"); - real_cfree = findReal("cfree"); - real_realloc = findReal("realloc"); - real_posix_memalign = findReal("posix_memalign"); - real_valloc = findReal("valloc"); - real_aligned_alloc = findReal("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 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);