From kde-commits Tue Dec 09 00:17:12 2014 From: Milian Wolff Date: Tue, 09 Dec 2014 00:17:12 +0000 To: kde-commits Subject: [heaptrack/inject] /: Add -p/--pid option to attach heaptrack to a running process. Message-Id: X-MARC-Message: https://marc.info/?l=kde-commits&m=141808424531368 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.cp= p) +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 @O= NLY) = install(TARGETS heaptrack_print RUNTIME DESTINATION ${BIN_INSTALL_DIR}) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/heaptrack DESTINATION ${BIN_I= NSTALL_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}/he= aptrack/) +install(TARGETS heaptrack_preload LIBRARY DESTINATION ${LIB_INSTALL_DIR}/h= eaptrack/) 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=3D +pid=3D client=3D clientargs=3D = @@ -62,6 +63,26 @@ while true; do usage exit 0 ;; + "-p") ;& + "--pid") + pid=3D$2 + if [ -z "$pid" ]; then + echo "Missing PID argument." + exit 1 + fi + client=3D$(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=3D"$1" shift 1 clientargs=3D"$@" - break; + break ;; esac done @@ -92,12 +113,19 @@ if [ ! -f "$INTERPRETER" ]; then fi INTERPRETER=3D$(readlink -f "$INTERPRETER") = -LIBHEAPTRACK=3D"$EXE_PATH/$LIB_REL_PATH/libheaptrack.so" -if [ ! -f "$LIBHEAPTRACK" ]; then - echo "Could not find heaptrack preload library$LIBHEAPTRACK" +LIBHEAPTRACK_PRELOAD=3D"$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=3D$(readlink -f "$LIBHEAPTRACK_PRELOAD") + +LIBHEAPTRACK_INJECT=3D"$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=3D$(readlink -f "$LIBHEAPTRACK") +LIBHEAPTRACK_INJECT=3D$(readlink -f "$LIBHEAPTRACK_INJECT") = # setup named pipe to read data from pipe=3D/tmp/heaptrack_fifo$$ @@ -112,12 +140,19 @@ debuggee=3D$! echo "starting application, this might take some time..." echo "output will be written to $output" = -if [ -z "$debug" ]; then - LD_PRELOAD=3D$LIBHEAPTRACK DUMP_HEAPTRACK_OUTPUT=3D"$pipe" $client $clie= ntargs +if [ -z "$debug" ] && [ -z "$pid" ]; then + LD_PRELOAD=3D$LIBHEAPTRACK_PRELOAD DUMP_HEAPTRACK_OUTPUT=3D"$pipe" $clie= nt $clientargs else - gdb --eval-command=3D"set environment LD_PRELOAD=3D$LIBHEAPTRACK" \ - --eval-command=3D"set environment DUMP_HEAPTRACK_OUTPUT=3D$pipe" \ - --eval-command=3D"run" --args $client $clientargs + if [ -z "$pid" ]; then + gdb --eval-command=3D"set environment LD_PRELOAD=3D$LIBHEAPTRACK_PRELO= AD" \ + --eval-command=3D"set environment DUMP_HEAPTRACK_OUTPUT=3D$pipe" \ + --eval-command=3D"run" --args $client $clientargs + else + gdb -p $pid \ + --eval-command=3D"call (void) dlopen(\"$LIBHEAPTRACK_INJECT\", 0x0= 02)" \ + --eval-command=3D"call (void) init_heaptrack_inject(\"$pipe\")" \ + --eval-command=3D"detach" --eval-command=3D"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) =3D=3D sizeof(void*), "Mismatche= d 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 !=3D 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 =3D 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 =3D data.addIp(instructionPointer); // trace point, map current output index to parent index fprintf(stdout, "t %lx %lx\n", ipId, parentIndex); + } else if (reader.mode() =3D=3D 'A') { + // we attached, and now have to parse the malloc_info to get s= ome baseline + stringstream xml; + while (reader.getLine(cin) && reader.mode() !=3D 'A') { + xml << reader.line(); + } + boost::property_tree::ptree pt; + boost::property_tree::read_xml(xml, pt); + size_t current =3D 0; + for (const auto& element : pt.get_child("malloc")) { + if (element.first =3D=3D "system" && element.second.get(".type") =3D=3D "current") { + current =3D 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 =3D SignatureT*; + Signature original =3D nullptr; + + const char * const name; + void init() + { + auto ret =3D dlsym(RTLD_NEXT, name); + if (!ret) { + fprintf(stderr, "Could not find original function %s\n", name); + abort(); + } + original =3D 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 =3D 1024; + static char* buf[MAX_SIZE]; + static size_t offset =3D 0; + if (!offset) { + memset(buf, 0, MAX_SIZE); + } + size_t oldOffset =3D offset; + offset +=3D num * size; + if (offset >=3D MAX_SIZE) { + fprintf(stderr, "failed to initialize, dummy calloc buf size exhau= sted: %lu requested, %lu available\n", offset, MAX_SIZE); + abort(); + } + return buf + oldOffset; +} + +void init() +{ + heaptrack_init(getenv("DUMP_HEAPTRACK_OUTPUT"), [] { + hooks::calloc.original =3D &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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D hooks::dlopen(filename, flag); + + if (ret) { + heaptrack_invalidate_module_cache(); + } + + return ret; +} + +int dlclose(void *handle) +{ + if (!hooks::dlclose) { + hooks::init(); + } + + int ret =3D 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 =3D activeAllocations.find(ptr); if (ip =3D=3D activeAllocations.end()) { - cerr << "unknown pointer in line: " << reader.line() <= < endl; + if (!fromAttached) { + cerr << "unknown pointer in line: " << reader.line= () << endl; + } continue; } const auto info =3D ip->second; @@ -511,7 +513,9 @@ struct AccumulatedTraceData = auto& allocation =3D findAllocation(info.traceIndex); if (!allocation.allocations || allocation.leaked < info.si= ze) { - cerr << "inconsistent allocation info, underflowed all= ocations of " << info.traceIndex << endl; + if (!fromAttached) { + cerr << "inconsistent allocation info, underflowed= allocations of " << info.traceIndex << endl; + } allocation.leaked =3D 0; allocation.allocations =3D 0; } else { @@ -537,6 +541,15 @@ struct AccumulatedTraceData if (massifOut.is_open()) { writeMassifHeader(reader.line().c_str() + 2); } + } else if (reader.mode() =3D=3D 'A') { + size_t current =3D 0; + if (!(reader >> current)) { + cerr << "Failed to read current size after attaching."= << endl; + continue; + } + leaked =3D current; + peak =3D current; + fromAttached =3D true; } else { cerr << "failed to parse line: " << reader.line() << endl; } @@ -557,6 +570,7 @@ struct AccumulatedTraceData bool shortenTemplates =3D false; bool mergeBacktraces =3D true; bool printHistogram =3D false; + bool fromAttached =3D false; ofstream massifOut; double massifThreshold =3D 1; size_t massifDetailedFreq =3D 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 =3D void* (*) (size_t); -using free_t =3D void (*) (void*); -using cfree_t =3D void (*) (void*); -using realloc_t =3D void* (*) (void*, size_t); -using calloc_t =3D void* (*) (size_t, size_t); -using posix_memalign_t =3D int (*) (void **, size_t, size_t); -using valloc_t =3D void* (*) (size_t); -using aligned_alloc_t =3D void* (*) (size_t, size_t); -using dlopen_t =3D void* (*) (const char*, int); -using dlclose_t =3D int (*) (void*); - -malloc_t real_malloc =3D nullptr; -free_t real_free =3D nullptr; -cfree_t real_cfree =3D nullptr; -realloc_t real_realloc =3D nullptr; -calloc_t real_calloc =3D nullptr; -posix_memalign_t real_posix_memalign =3D nullptr; -valloc_t real_valloc =3D nullptr; -aligned_alloc_t real_aligned_alloc =3D nullptr; -dlopen_t real_dlopen =3D nullptr; -dlclose_t real_dlclose =3D nullptr; - // threadsafe stuff atomic moduleCacheDirty(true); = @@ -119,12 +96,6 @@ private: = thread_local bool HandleGuard::inHandler =3D false; = -string env(const char* variable) -{ - const char* value =3D getenv(variable); - return value ? string(value) : string(); -} - void writeExe(FILE* out) { const int BUF_SIZE =3D 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 =3D 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 execu= table outputFileName =3D "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 =3D true; } = -template -T findReal(const char* name) -{ - auto ret =3D 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 =3D 1024; - static char* buf[MAX_SIZE]; - static size_t offset =3D 0; - if (!offset) { - memset(buf, 0, MAX_SIZE); - } - size_t oldOffset =3D offset; - offset +=3D num * size; - if (offset >=3D MAX_SIZE) { - fprintf(stderr, "failed to initialize, dummy calloc buf size exhau= sted: %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, [=3D] { + if (data) { fprintf(stderr, "initialization recursion detected\n"); abort(); } = - HandleGuard guard; - - real_calloc =3D &dummy_calloc; - real_calloc =3D findReal("calloc"); - real_dlopen =3D findReal("dlopen"); - real_dlclose =3D findReal("dlclose"); - real_malloc =3D findReal("malloc"); - real_free =3D findReal("free"); - real_cfree =3D findReal("cfree"); - real_realloc =3D findReal("realloc"); - real_posix_memalign =3D findReal("posix_memalign= "); - real_valloc =3D findReal("valloc"); - real_aligned_alloc =3D findReal("aligned_alloc"); + if (initCallbackBefore) { + initCallbackBefore(); + } = if (unw_set_caching_policy(unw_local_addr_space, UNW_CACHE_PER_THR= EAD)) { 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 =3D true; } = -/// TODO: memalign, pvalloc, ...? - -void* malloc(size_t size) -{ - if (!real_malloc) { - init(); - } - - void* ptr =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D real_dlopen(filename, flag); - - if (ret) { - moduleCacheDirty =3D true; - } - - return ret; -} - -int dlclose(void *handle) -{ - if (!real_dlclose) { - init(); - } - - int ret =3D real_dlclose(handle); - - if (!ret) { - moduleCacheDirty =3D 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);